<commit_before>/*!
 * jQuery Mobile
 * http://jquerymobile.com/
 *
 * Copyright 2010, jQuery Project
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 */
(function( jQuery, window, undefined ) {
	// if we're missing support for any of these, then we're a C-grade browser
	if ( !jQuery.support.display || !jQuery.support.position || !jQuery.support.overflow || !jQuery.support.floatclear ) {
		return;
	}

	//these properties should be made easy to override externally
	jQuery.mobile = {};

	jQuery.extend(jQuery.mobile, {
		subPageUrlKey: 'ui-page' //define the key used in urls for sub-pages. Defaults to &ui-page=
	});
	jQuery.mobile.subPageUrlKey = 'ui-page';

	var $window = jQuery(window),
		$html = jQuery('html'),
		$head = jQuery('head'),
		$body,
		$loader = jQuery('

loading.

'),
		startPage,
		startPageId = 'ui-page-start',
		activePageClass = 'ui-page-active',
		pageTransition,
		transitions = 'slide slideup slidedown pop flip fade dissolve swap',
		transitionDuration = 350,
		backBtnText = "Back",
		urlStack = [ {
			url: location.hash.replace( /^#/, "" ),
			transition: "slide"
		} ],
		nextPageRole = null,
		noCache = '.ui-dialog';

	// hide address bar
	function hideBrowserChrome() {
		// prevent scrollstart and scrollstop events
		jQuery.event.special.scrollstart.enabled = false;
		window.scrollTo( 0, 0 );
		setTimeout(function() {
			jQuery.event.special.scrollstart.enabled = true;
		}, 150 );
	}

	function manageGlobalNav(activePage){
		if(activePage.is('.ui-globalnav-expanded')){
			jQuery('[data-role="globalnav"]').addClass('ui-globalnav-disable');
		}
		else{
			jQuery('[data-role="globalnav"]').removeClass('ui-globalnav-disable');
		}
	}

	// send a link through hash tracking
	jQuery.fn.ajaxClick = function() {
		var href = jQuery( this ).attr( "href" );
		pageTransition = jQuery( this ).attr( "data-transition" ) || "slide";
		nextPageRole = jQuery( this ).attr( "data-rel" );

		// let the hashchange event handler take care of everything else
		location.hash = href;

		// note: if it's a non-local-anchor and Ajax is not supported, go to page
		if ( href.match( /^[^#]/ ) && !jQuery.support.ajax ) {
			window.location = href;
		}

		return this;
	};

	// ajaxify all navigable links
	jQuery( "a:not([href=#]):not([target=_blank]):not([rel=external])" ).live( "click", function() {
		jQuery( this ).ajaxClick();
		return false;
	});

	// turn on/off page loading message.. also hides the ui-content div
	function pageLoading( done ) {
		if ( done ) {
			$html.removeClass( "ui-loading" );
			//fade in page content, remove loading msg
			jQuery('.ui-page-active .ui-content').addClass('dissolve in');
		} else {
			$html.addClass( "ui-loading" );
			$loader.appendTo( $body ).addClass( "dissolve in" );
		}
	};

	// transition between pages - based on transitions from jQtouch
	function changePage( from, to, transition, back ) {
		hideBrowserChrome();

		// kill keyboard (thx jQtouch :) )
		jQuery( document.activeElement ).blur();

		// animate in / out
		from.addClass( transition + " out " + ( back ? "reverse" : "" ) );
		to.appendTo($body).addClass( activePageClass + " " + transition +
			" in " + ( back ? "reverse" : "" ) );
		//make sure globalnav is on top
		jQuery('[data-role="globalnav"]').appendTo($body);
		manageGlobalNav(to);

		// callback - remove classes, etc
		to.animationComplete(function() {
			from.add( to ).removeClass(" out in reverse " + transitions );
			from.removeClass( activePageClass );
			pageLoading( true );
			jQuery.fixedToolbars.show();
		});
	};

	jQuery(function() {
		$body = jQuery( "body" );
		pageLoading();

		// needs to be bound at domready (for IE6)
		// find or load content, make it active
		$window.bind( "hashchange", function(e) {
			var url = location.hash.replace( /^#/, "" ),
				stackLength = urlStack.length,
				// pageTransition only exists if the user clicked a link
				back = !pageTransition && stackLength > 1 &&
					urlStack[ stackLength - 2 ].url === url,
				transition = pageTransition || "slide",
				fileUrl = url;
			pageTransition = undefined;

			// if the new href is the same as the previous one
			if ( back ) {
				transition = urlStack.pop().transition;
			} else {
				urlStack.push({ url: url, transition: transition });
			}

			//remove any pages that shouldn't cache
			jQuery(noCache).remove();

			//function for setting role of next page
			function setPageRole( newPage ) {
				if ( nextPageRole ) {
					newPage.attr( "data-role", nextPageRole );
					nextPageRole = undefined;
				}
			}

			if ( url ) {
				// see if content is present already
				var localDiv = jQuery( "[id='" + url + "']" );
				if ( localDiv.length ) {
					if ( localDiv.is( "[data-role]" ) ) {
						setPageRole( localDiv );
					}
					mobilize( localDiv );
					changePage( jQuery( ".ui-page-active" ), localDiv, transition, back );
				} else { //ajax it in
					pageLoading();
					if(url.match( '&' + jQuery.mobile.subPageUrlKey )){
						fileUrl = url.split( '&' + jQuery.mobile.subPageUrlKey )[0];
					}
					var newPage = jQuery( "
" )
						.appendTo( $body )
						.load( fileUrl + ' [data-role="page"]', function() {
							// TODO: test this (avoids querying the dom for new element):
//							var newPage = jQuery( this ).find( ".ui-page" ).eq( 0 )
//								.attr( "id", url );
//							jQuery( this ).replaceWith( newPage );
//							setPageRole( newPage );
//							mobilize( newPage );
//							changePage( jQuery( ".ui-page-active" ), newPage, transition, back );
							jQuery( this ).replaceWith(
								jQuery( this ).find( '[data-role="page"]' ).eq( 0 ).attr( "id", fileUrl ) );
							var newPage = jQuery( "[id='" + fileUrl + "']" );
							setPageRole( newPage );
							mobilize( newPage );
							newPage = jQuery( "[id='" + url + "']" );
							changePage( jQuery( ".ui-page-active" ), newPage, transition, back );
						});
				}
			} else {
				// either we've backed up to the root page url
				// or it's the first page load with no hash present
				var currentPage = jQuery( ".ui-page-active" );
				if ( currentPage.length && !startPage.is( ".ui-page-active" ) ) {
					changePage( currentPage, startPage, transition, back );
				} else {
					startPage.addClass( activePageClass );
					manageGlobalNav(startPage);
					jQuery.fixedToolbars.show();
					pageLoading( true );
				}
			}
		});

		hideBrowserChrome();
	});

	//add orientation class on flip/resize.
	$window.bind( "orientationchange", function( event, data ) {
		$html.removeClass( "portrait landscape" ).addClass( data.orientation );
	});

	//add mobile, loading classes to doc
	$html.addClass('ui-mobile');

	//insert mobile meta - these will need to be configurable somehow.
	$head.append('<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0" />'+
		'<link rel="apple-touch-icon" href="images/homeicon.png" />'+
		'<link rel="apple-touch-startup-image" href="images/startscreen.png" />'+
		'<meta name="apple-mobile-web-app-capable" content="yes" />' +
        '<meta name="apple-mobile-web-app-status-bar-style" content="default" />');

	//potential (probably incomplete) fallback to workaround lack of animation callbacks.
	//should this be extended into a full special event?
	// note: Expects CSS animations use transitionDuration (350ms)
	jQuery.fn.animationComplete = function(callback){
		if(jQuery.support.WebKitAnimationEvent){
			return jQuery(this).one('webkitAnimationEnd', callback); //check out transitionEnd (opera per Paul's request)
		}
		else{
			setTimeout(callback, transitionDuration);
		}
	};

	//markup-driven enhancements, to be called on any ui-page upon loading
	function mobilize($el){
		//to-do: make sure this only runs one time on a page (or maybe per component)
		return $el.not('[data-mobilized]').each(function(){

			//hide no-js content
			$el.find('[data-role="nojs"]').addClass('ui-nojs');

			//pre-find data els
			var $dataEls = $el.find('[data-role]').andSelf().each(function() {
				var $this = $(this),
					role = $this.attr("data-role");
				switch(role) {
				case 'page':
				case 'header':
				case 'content':
				case 'footer':
					$this.addClass('ui-' + role);
					break;
				case 'collapsible':
				case 'fieldcontain':
				case 'globalnav':
				case 'listview':
				case 'dialog':
				case 'ajaxform':
					$this[role]();
					break;
				}
			});

			//fix toolbars
			$el.fixHeaderFooter();

			//form elements
			var checksradios = 'input[type=radio],input[type=checkbox]',
				buttonInputs = 'button, input[type=submit], input[type=reset], input[type=image]',
				textInputs = 'input[type=text],input[type=number],input[type=date],input[type=password],textarea',
				dateInputs = 'input[type=date]',
				sliders = '[data-role="slider"]',
				selects = 'select';

			$formEls = $el.find( [checksradios, buttonInputs, textInputs, dateInputs, sliders, selects].join(',') ).not('.ui-nojs');

			$formEls.filter(checksradios).customCheckboxRadio();
			//custom buttons
			$formEls.filter(buttonInputs).customButton();
			//custom text inputs
			$formEls.filter(textInputs).customTextInput();

			/*temporary datepicker workaround */
			$formEls.filter(dateInputs).hide().after( $('
').datepicker() );

			$('.ui-datepicker');//.addClass('ui-shadow');
			$('.ui-datepicker-header').addClass('ui-body-c ui-corner-top').removeClass('ui-corner-all');
			$('.ui-datepicker-prev').buttonMarkup({iconPos: 'notext', icon: 'arrow-l', shadow: true, corners: true});
			$('.ui-datepicker-next').buttonMarkup({iconPos: 'notext', icon: 'arrow-r', shadow: true, corners: true});
			$('.ui-datepicker-calendar thead').remove();
			$('.ui-datepicker-calendar td').addClass('ui-btn-up-c');
			$('.ui-datepicker-calendar a').buttonMarkup({corners: false, shadow: false});
			/* //temporary datepicker workaround */

			//sliders
			$formEls.filter(sliders).slider();
			//selects
			$formEls.filter(selects).not('[data-role="slider"]').customSelect();

			//vertical controlgroups
			$dataEls.filter('[data-role="controlgroup"]:not([data-type="horizontal"])').controlgroup();
			//horizontal controlgroups
			$dataEls.filter('[data-role="controlgroup"][data-type="horizontal"]').controlgroup({direction: 'horizontal'});

			//add back buttons to headers that don't have them
			var backBtn = $el.find('.ui-header a.ui-back');
			if(!backBtn.length){
				backBtn = jQuery('').appendTo($el.find('.ui-header'));
			}

			//buttons from links in headers,footers,bars, or with data-role
			$dataEls.filter('[data-role="button"]').add('.ui-header a, .ui-footer a, .ui-bar a').not('.ui-btn').buttonMarkup();
			//links within content areas
			$el.find('.ui-body a:not(.ui-btn):not(.ui-link-inherit)').addClass('ui-link');
			//make all back buttons mimic the back button (pre-js, these links are usually "home" links)
			backBtn
				.click(function(){
					history.go(-1);
					return false;
				})
				.find('.ui-btn-text').text(backBtnText);

			$el.attr('data-mobilized',true);
		});
	};

	jQuery.extend({
		mobilize: mobilize,
		pageLoading: pageLoading,
		changePage: changePage,
		hideBrowserChrome: hideBrowserChrome
	});

	//dom-ready
	jQuery(function(){

		//set up active page - mobilize it!
		startPage = jQuery('[data-role="page"]:first');

		//make sure it has an ID - for finding it later
		if(!startPage.attr('id')){
			startPage.attr('id', startPageId);
		}

		//mobilize all pages present
		mobilize(jQuery('[data-role="page"]'));

		//trigger a new hashchange, hash or not
		$window.trigger( "hashchange" );

		//update orientation
		$html.addClass( jQuery.event.special.orientationchange.orientation( $window ) );

		//some debug stuff for the events pages
		jQuery('body').bind('scrollstart scrollstop swipe swipeleft swiperight tap taphold turn',function(e){
			jQuery('#eventlogger').prepend('
Event fired: '+ e.type +'
');
		});
	});
})( jQuery, this );
<commit_msg>unused selector<commit_after>/*!
 * jQuery Mobile
 * http://jquerymobile.com/
 *
 * Copyright 2010, jQuery Project
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 */
(function( jQuery, window, undefined ) {
	// if we're missing support for any of these, then we're a C-grade browser
	if ( !jQuery.support.display || !jQuery.support.position || !jQuery.support.overflow || !jQuery.support.floatclear ) {
		return;
	}

	//these properties should be made easy to override externally
	jQuery.mobile = {};

	jQuery.extend(jQuery.mobile, {
		subPageUrlKey: 'ui-page' //define the key used in urls for sub-pages. Defaults to &ui-page=
	});
	jQuery.mobile.subPageUrlKey = 'ui-page';

	var $window = jQuery(window),
		$html = jQuery('html'),
		$head = jQuery('head'),
		$body,
		$loader = jQuery('

loading.

'),
		startPage,
		startPageId = 'ui-page-start',
		activePageClass = 'ui-page-active',
		pageTransition,
		transitions = 'slide slideup slidedown pop flip fade dissolve swap',
		transitionDuration = 350,
		backBtnText = "Back",
		urlStack = [ {
			url: location.hash.replace( /^#/, "" ),
			transition: "slide"
		} ],
		nextPageRole = null,
		noCache = '.ui-dialog';

	// hide address bar
	function hideBrowserChrome() {
		// prevent scrollstart and scrollstop events
		jQuery.event.special.scrollstart.enabled = false;
		window.scrollTo( 0, 0 );
		setTimeout(function() {
			jQuery.event.special.scrollstart.enabled = true;
		}, 150 );
	}

	function manageGlobalNav(activePage){
		if(activePage.is('.ui-globalnav-expanded')){
			jQuery('[data-role="globalnav"]').addClass('ui-globalnav-disable');
		}
		else{
			jQuery('[data-role="globalnav"]').removeClass('ui-globalnav-disable');
		}
	}

	// send a link through hash tracking
	jQuery.fn.ajaxClick = function() {
		var href = jQuery( this ).attr( "href" );
		pageTransition = jQuery( this ).attr( "data-transition" ) || "slide";
		nextPageRole = jQuery( this ).attr( "data-rel" );

		// let the hashchange event handler take care of everything else
		location.hash = href;

		// note: if it's a non-local-anchor and Ajax is not supported, go to page
		if ( href.match( /^[^#]/ ) && !jQuery.support.ajax ) {
			window.location = href;
		}

		return this;
	};

	// ajaxify all navigable links
	jQuery( "a:not([href=#]):not([target=_blank]):not([rel=external])" ).live( "click", function() {
		jQuery( this ).ajaxClick();
		return false;
	});

	// turn on/off page loading message.. also hides the ui-content div
	function pageLoading( done ) {
		if ( done ) {
			$html.removeClass( "ui-loading" );
			//fade in page content, remove loading msg
			jQuery('.ui-page-active .ui-content').addClass('dissolve in');
		} else {
			$html.addClass( "ui-loading" );
			$loader.appendTo( $body ).addClass( "dissolve in" );
		}
	};

	// transition between pages - based on transitions from jQtouch
	function changePage( from, to, transition, back ) {
		hideBrowserChrome();

		// kill keyboard (thx jQtouch :) )
		jQuery( document.activeElement ).blur();

		// animate in / out
		from.addClass( transition + " out " + ( back ? "reverse" : "" ) );
		to.appendTo($body).addClass( activePageClass + " " + transition +
			" in " + ( back ? "reverse" : "" ) );
		//make sure globalnav is on top
		jQuery('[data-role="globalnav"]').appendTo($body);
		manageGlobalNav(to);

		// callback - remove classes, etc
		to.animationComplete(function() {
			from.add( to ).removeClass(" out in reverse " + transitions );
			from.removeClass( activePageClass );
			pageLoading( true );
			jQuery.fixedToolbars.show();
		});
	};

	jQuery(function() {
		$body = jQuery( "body" );
		pageLoading();

		// needs to be bound at domready (for IE6)
		// find or load content, make it active
		$window.bind( "hashchange", function(e) {
			var url = location.hash.replace( /^#/, "" ),
				stackLength = urlStack.length,
				// pageTransition only exists if the user clicked a link
				back = !pageTransition && stackLength > 1 &&
					urlStack[ stackLength - 2 ].url === url,
				transition = pageTransition || "slide",
				fileUrl = url;
			pageTransition = undefined;

			// if the new href is the same as the previous one
			if ( back ) {
				transition = urlStack.pop().transition;
			} else {
				urlStack.push({ url: url, transition: transition });
			}

			//remove any pages that shouldn't cache
			jQuery(noCache).remove();

			//function for setting role of next page
			function setPageRole( newPage ) {
				if ( nextPageRole ) {
					newPage.attr( "data-role", nextPageRole );
					nextPageRole = undefined;
				}
			}

			if ( url ) {
				// see if content is present already
				var localDiv = jQuery( "[id='" + url + "']" );
				if ( localDiv.length ) {
					if ( localDiv.is( "[data-role]" ) ) {
						setPageRole( localDiv );
					}
					mobilize( localDiv );
					changePage( jQuery( ".ui-page-active" ), localDiv, transition, back );
				} else { //ajax it in
					pageLoading();
					if(url.match( '&' + jQuery.mobile.subPageUrlKey )){
						fileUrl = url.split( '&' + jQuery.mobile.subPageUrlKey )[0];
					}
					var newPage = jQuery( "
" )
						.appendTo( $body )
						.load( fileUrl + ' [data-role="page"]', function() {
							// TODO: test this (avoids querying the dom for new element):
//							var newPage = jQuery( this ).find( ".ui-page" ).eq( 0 )
//								.attr( "id", url );
//							jQuery( this ).replaceWith( newPage );
//							setPageRole( newPage );
//							mobilize( newPage );
//							changePage( jQuery( ".ui-page-active" ), newPage, transition, back );
							jQuery( this ).replaceWith(
								jQuery( this ).find( '[data-role="page"]' ).eq( 0 ).attr( "id", fileUrl ) );
							var newPage = jQuery( "[id='" + fileUrl + "']" );
							setPageRole( newPage );
							mobilize( newPage );
							newPage = jQuery( "[id='" + url + "']" );
							changePage( jQuery( ".ui-page-active" ), newPage, transition, back );
						});
				}
			} else {
				// either we've backed up to the root page url
				// or it's the first page load with no hash present
				var currentPage = jQuery( ".ui-page-active" );
				if ( currentPage.length && !startPage.is( ".ui-page-active" ) ) {
					changePage( currentPage, startPage, transition, back );
				} else {
					startPage.addClass( activePageClass );
					manageGlobalNav(startPage);
					jQuery.fixedToolbars.show();
					pageLoading( true );
				}
			}
		});

		hideBrowserChrome();
	});

	//add orientation class on flip/resize.
	$window.bind( "orientationchange", function( event, data ) {
		$html.removeClass( "portrait landscape" ).addClass( data.orientation );
	});

	//add mobile, loading classes to doc
	$html.addClass('ui-mobile');

	//insert mobile meta - these will need to be configurable somehow.
	$head.append('<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0" />'+
		'<link rel="apple-touch-icon" href="images/homeicon.png" />'+
		'<link rel="apple-touch-startup-image" href="images/startscreen.png" />'+
		'<meta name="apple-mobile-web-app-capable" content="yes" />' +
        '<meta name="apple-mobile-web-app-status-bar-style" content="default" />');

	//potential (probably incomplete) fallback to workaround lack of animation callbacks.
	//should this be extended into a full special event?
	// note: Expects CSS animations use transitionDuration (350ms)
	jQuery.fn.animationComplete = function(callback){
		if(jQuery.support.WebKitAnimationEvent){
			return jQuery(this).one('webkitAnimationEnd', callback); //check out transitionEnd (opera per Paul's request)
		}
		else{
			setTimeout(callback, transitionDuration);
		}
	};

	//markup-driven enhancements, to be called on any ui-page upon loading
	function mobilize($el){
		//to-do: make sure this only runs one time on a page (or maybe per component)
		return $el.not('[data-mobilized]').each(function(){

			//hide no-js content
			$el.find('[data-role="nojs"]').addClass('ui-nojs');

			//pre-find data els
			var $dataEls = $el.find('[data-role]').andSelf().each(function() {
				var $this = $(this),
					role = $this.attr("data-role");
				switch(role) {
				case 'page':
				case 'header':
				case 'content':
				case 'footer':
					$this.addClass('ui-' + role);
					break;
				case 'collapsible':
				case 'fieldcontain':
				case 'globalnav':
				case 'listview':
				case 'dialog':
				case 'ajaxform':
					$this[role]();
					break;
				}
			});

			//fix toolbars
			$el.fixHeaderFooter();

			//form elements
			var checksradios = 'input[type=radio],input[type=checkbox]',
				buttonInputs = 'button, input[type=submit], input[type=reset], input[type=image]',
				textInputs = 'input[type=text],input[type=number],input[type=date],input[type=password],textarea',
				dateInputs = 'input[type=date]',
				sliders = '[data-role="slider"]',
				selects = 'select';

			$formEls = $el.find( [checksradios, buttonInputs, textInputs, dateInputs, sliders, selects].join(',') ).not('.ui-nojs');

			$formEls.filter(checksradios).customCheckboxRadio();
			//custom buttons
			$formEls.filter(buttonInputs).customButton();
			//custom text inputs
			$formEls.filter(textInputs).customTextInput();

			/*temporary datepicker workaround */
			$formEls.filter(dateInputs).hide().after( $('
').datepicker() );
			$('.ui-datepicker-header').addClass('ui-body-c ui-corner-top').removeClass('ui-corner-all');
			$('.ui-datepicker-prev').buttonMarkup({iconPos: 'notext', icon: 'arrow-l', shadow: true, corners: true});
			$('.ui-datepicker-next').buttonMarkup({iconPos: 'notext', icon: 'arrow-r', shadow: true, corners: true});
			$('.ui-datepicker-calendar thead').remove();
			$('.ui-datepicker-calendar td').addClass('ui-btn-up-c');
			$('.ui-datepicker-calendar a').buttonMarkup({corners: false, shadow: false});
			/* //temporary datepicker workaround */

			//sliders
			$formEls.filter(sliders).slider();
			//selects
			$formEls.filter(selects).not('[data-role="slider"]').customSelect();

			//vertical controlgroups
			$dataEls.filter('[data-role="controlgroup"]:not([data-type="horizontal"])').controlgroup();
			//horizontal controlgroups
			$dataEls.filter('[data-role="controlgroup"][data-type="horizontal"]').controlgroup({direction: 'horizontal'});

			//add back buttons to headers that don't have them
			var backBtn = $el.find('.ui-header a.ui-back');
			if(!backBtn.length){
				backBtn = jQuery('').appendTo($el.find('.ui-header'));
			}

			//buttons from links in headers,footers,bars, or with data-role
			$dataEls.filter('[data-role="button"]').add('.ui-header a, .ui-footer a, .ui-bar a').not('.ui-btn').buttonMarkup();
			//links within content areas
			$el.find('.ui-body a:not(.ui-btn):not(.ui-link-inherit)').addClass('ui-link');
			//make all back buttons mimic the back button (pre-js, these links are usually "home" links)
			backBtn
				.click(function(){
					history.go(-1);
					return false;
				})
				.find('.ui-btn-text').text(backBtnText);

			$el.attr('data-mobilized',true);
		});
	};

	jQuery.extend({
		mobilize: mobilize,
		pageLoading: pageLoading,
		changePage: changePage,
		hideBrowserChrome: hideBrowserChrome
	});

	//dom-ready
	jQuery(function(){

		//set up active page - mobilize it!
		startPage = jQuery('[data-role="page"]:first');

		//make sure it has an ID - for finding it later
		if(!startPage.attr('id')){
			startPage.attr('id', startPageId);
		}

		//mobilize all pages present
		mobilize(jQuery('[data-role="page"]'));

		//trigger a new hashchange, hash or not
		$window.trigger( "hashchange" );

		//update orientation
		$html.addClass( jQuery.event.special.orientationchange.orientation( $window ) );

		//some debug stuff for the events pages
		jQuery('body').bind('scrollstart scrollstop swipe swipeleft swiperight tap taphold turn',function(e){
			jQuery('#eventlogger').prepend('
Event fired: '+ e.type +'
');
		});
	});
})( jQuery, this );
<|endoftext|>


<commit_before>/*
File:           slidegrid.js
Description:    for more information see http://www.zackgrossbart.com/hackito/slidegrid/

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

slidegrid = {
	hasDrawn: false,
	windowWidth: 0,
	cellWidth: 250,
	cellHeight: 150,
	padding: 30,
	gridOffset: 0,

	/**
	 * Adds a specific cell to the set of used cells.  Used cells are skipped
	 * when laying cells out in the future.
	 *
	 * @param usedCells the array of used cells
	 * @param col       the column of the used cell
	 * @param row       the row of the used cell
	 */
	setUsed: function(/*array*/ usedCells, /*int*/col, /*int*/row) {
	    var index = usedCells.length;

	    usedCells[index] = { left: col, top: row};
	},

	/**
	 * Lets you know if a specific column and row index has already been used.
	 *
	 * @param usedCells the array of used cells
	 * @param col       the column of the cell to check
	 * @param row       the row of the cell to check
	 */
	isUsed: function(/*array*/ usedCells, /*int*/ col, /*int*/ row) {
	    for (var i = 0; i < usedCells.length; i++) {
	        if (usedCells[i].left === col &&
	            usedCells[i].top === row) {
	            return true;
	        }
	    }

	    return false;
	},

	/**
	 * Applies the styling to a specific cell.
	 *
	 * @param cell       The JQuery object representing the cell to style
	 * @param x          the left position of the cell in EMs
	 * @param y          the top position of the cell in EMs
	 * @param cellWidth  the width of the cell in EMs
	 * @param cellHeight the height of the cell in EMs
	 * @param animate    true if this style should be animated and false otherwise
	 */
	styleCell: function(cell, x, y, cellWidth, cellHeight, /*boolean*/animate) {
	    if (animate) {
	        cell.animate({
	            left: x + "px",
	            top: y + "px"
	            }, 500, "swing" );
	    } else {
	        cell.css({
	            width: cellWidth + "px",
	            height: cellHeight + "px",
	            position: "absolute",
	            left: x + "px",
	            top: y + "px"
	        });
	    }
	},

	/**
	 * Aligns a set of elements in a resizable grid.
	 *
	 * @param cellWidth  the width of each cell in px
	 * @param cellHeight the height of each cell in px
	 * @param padding    the padding between each cell in px
	 * @param gridOffset the offset width of the grid in px
	 */
	alignGrid: function(/*int*/ cellWidth, /*int*/ cellHeight, /*int*/ padding, /*int*/ gridOffset) {
		slidegrid.cellWidth = cellWidth;
		slidegrid.cellHeight = cellHeight;
		slidegrid.padding = padding;
		slidegrid.gridOffset = gridOffset;

	    var x = padding / 2;
	    var y = 0;
	    var count = 1;

	    /*
	     * When we add a "bigcell" to the grid it takes up four cells instead of one.
	     * That makes we need to not add any other cells to those areas or the cells
	     * will overlap.  These three variables are used to remember the cells used
	     * by big cells.
	     */
	    var curCol = 0;
	    var curRow = 0;
	    var usedCells = [];

	    $(".slidegrid").each(function() {

	        var hasTallCell = false;

	        var cols = Math.floor(($(window).width() - gridOffset) / ((cellWidth + padding)));

	        $(this).css("position", "relative");

	        var children = $(this).children("div");

	        for (var i = 0; i < children.length; i++) {
	            if (children.eq(i).hasClass("bigcell")) {
	                if (curCol === cols - 1) {
	                    /*
	                     * This means it is time to bump down to the next row
	                     */
	                    curCol = 0;
	                    curRow++;
	                    x = padding / 2;
	                    y += cellHeight + padding;
	                    count++;

	                }

	                if (slidegrid.isUsed(usedCells, curCol, curRow) ||
	                    slidegrid.isUsed(usedCells, curCol + 1, curRow) ||
	                    slidegrid.isUsed(usedCells, curCol + 1, curRow + 1) ||
	                    slidegrid.isUsed(usedCells, curCol, curRow + 1)) {
	                    /*
	                     * If the current cell is used we
	                     * just want to try the next column.
	                     * However, we also want to bump to
	                     * the next row if needed so we are
	                     * calling the column logic and then
	                     * backing up the counter.
	                     */
	                    i--;
	                } else {

	                    slidegrid.styleCell(children.eq(i), x, y, (cellWidth * 2) + padding, (cellHeight * 2) + padding, slidegrid.hasDrawn);
	                    /*
	                     * Big cells are twice as large as normal cells.  That means they
	                     * use up the cell to the right, the cell below, and the cell to
	                     * the right and below.
	                     */

	                    slidegrid.setUsed(usedCells, curCol, curRow);
	                    slidegrid.setUsed(usedCells, curCol + 1, curRow);
	                    slidegrid.setUsed(usedCells, curCol, curRow + 1);
	                    slidegrid.setUsed(usedCells, curCol + 1, curRow + 1);
	                }

	                hasTallCell = true;

	            } else if (children.eq(i).hasClass("widecell")) {
	                if (slidegrid.isUsed(usedCells, curCol, curRow) ||
	                    slidegrid.isUsed(usedCells, curCol + 1, curRow)) {
	                    /*
	                     * If the current cell is used we
	                     * just want to try the next column.
	                     * However, we also want to bump to
	                     * the next row if needed so we are
	                     * calling the column logic and then
	                     * backing up the counter.
	                     */
	                    i--;

	                } else {
	                    slidegrid.styleCell(children.eq(i), x, y, (cellWidth * 2) + padding, cellHeight, slidegrid.hasDrawn);
	                    /*
	                     * Wide cells are twice as wide, but the same height
	                     */

	                    slidegrid.setUsed(usedCells, curCol, curRow);
	                    slidegrid.setUsed(usedCells, curCol + 1, curRow);
	                }
	            } else if (children.eq(i).hasClass("tallcell")) {
	                if (slidegrid.isUsed(usedCells, curCol, curRow) ||
	                    slidegrid.isUsed(usedCells, curCol, curRow + 1)) {
	                    /*
	                     * If the current cell is used we
	                     * just want to try the next column.
	                     * However, we also want to bump to
	                     * the next row if needed so we are
	                     * calling the column logic and then
	                     * backing up the counter.
	                     */
	                    i--;

	                } else {
	                    slidegrid.styleCell(children.eq(i), x, y, cellWidth, (cellHeight * 2) + padding, slidegrid.hasDrawn);
	                    /*
	                     * Tall cells are twice as tall, but the same width
	                     */

	                    slidegrid.setUsed(usedCells, curCol, curRow);
	                    slidegrid.setUsed(usedCells, curCol, curRow + 1);
	                }

	                hasTallCell = true;

	            } else {
	                if (slidegrid.isUsed(usedCells, curCol, curRow)) {
	                    /*
	                     * If the current cell is used we
	                     * just want to try the next column.
	                     * However, we also want to bump to
	                     * the next row if needed so we are
	                     * calling the column logic and then
	                     * backing up the counter.
	                     */
	                    i--;

	                } else {
	                    slidegrid.styleCell(children.eq(i), x, y, cellWidth, cellHeight, slidegrid.hasDrawn);
	                }
	            }

	            if ((count % cols) === 0) {
	                /*
	                 * This means it is time to bump down to the next row
	                 */
	                curCol = 0;
	                curRow++;
	                x = padding / 2;
	                y += cellHeight + padding;
	            } else if ((count % cols) === 0) {
	                hasTallCell = false;
	            } else {
	                x += cellWidth + padding;
	                curCol++;
	            }

	            count++;
	        }

	        /*
	         * We need to set a height of the slidegrid div since it only has absolute
	         * height tags within it.
	         */
	        var height = 0;
	        if ((count % cols) !== 1) {
	            height = y + cellHeight + padding;
	        } else {
	            height = y + padding;
	        }

	        if (hasTallCell) {
	            height += cellHeight + padding;
	        }

	        $(this).css('height', height + "px");

	        /*
	         * Now we reset the variables for the next grid.
	         */
	        x = padding / 2;
	        y = 0;
	        count = 1;
	    });

	    slidegrid.hasDrawn = true;
	},

	resizeWindow: function(e) {
        if (slidegrid.windowWidth != $(window).width()) {
            slidegrid.alignGrid(slidegrid.cellWidth, slidegrid.cellHeight, slidegrid.padding, slidegrid.gridOffset);
            slidegrid.windowWidth = $(window).width();
        }
    }
}

$(document).ready(function() {
    /*
     * When the user resizes the window we need to redraw the grid.
     * This works well in Firefox and Chrome, but IE and Safari fire
     * the resize events a little more often than they need to.  We
     * remember the last window width so we can only repaint the grid
     * when we need to.
     */
    $(window).bind("resize", slidegrid.resizeWindow);
});
<commit_msg>Changed the sliding grid so wide cells won't hang over the right-side edge.<commit_after>/*
File:           slidegrid.js
Description:    for more information see http://www.zackgrossbart.com/hackito/slidegrid/

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

slidegrid = {
	hasDrawn: false,
	windowWidth: 0,
	cellWidth: 250,
	cellHeight: 150,
	padding: 30,
	gridOffset: 0,

	/**
	 * Adds a specific cell to the set of used cells.  Used cells are skipped
	 * when laying cells out in the future.
	 *
	 * @param usedCells the array of used cells
	 * @param col       the column of the used cell
	 * @param row       the row of the used cell
	 */
	setUsed: function(/*array*/ usedCells, /*int*/col, /*int*/row) {
	    var index = usedCells.length;

	    usedCells[index] = { left: col, top: row};
	},

	/**
	 * Lets you know if a specific column and row index has already been used.
	 *
	 * @param usedCells the array of used cells
	 * @param col       the column of the cell to check
	 * @param row       the row of the cell to check
	 */
	isUsed: function(/*array*/ usedCells, /*int*/ col, /*int*/ row) {
	    for (var i = 0; i < usedCells.length; i++) {
	        if (usedCells[i].left === col &&
	            usedCells[i].top === row) {
	            return true;
	        }
	    }

	    return false;
	},

	/**
	 * Applies the styling to a specific cell.
	 *
	 * @param cell       The JQuery object representing the cell to style
	 * @param x          the left position of the cell in EMs
	 * @param y          the top position of the cell in EMs
	 * @param cellWidth  the width of the cell in EMs
	 * @param cellHeight the height of the cell in EMs
	 * @param animate    true if this style should be animated and false otherwise
	 */
	styleCell: function(cell, x, y, cellWidth, cellHeight, /*boolean*/animate) {
	    if (animate) {
	        cell.animate({
	            left: x + "px",
	            top: y + "px"
	            }, 500, "swing" );
	    } else {
	        cell.css({
	            width: cellWidth + "px",
	            height: cellHeight + "px",
	            position: "absolute",
	            left: x + "px",
	            top: y + "px"
	        });
	    }
	},

	/**
	 * Aligns a set of elements in a resizable grid.
	 *
	 * @param cellWidth  the width of each cell in px
	 * @param cellHeight the height of each cell in px
	 * @param padding    the padding between each cell in px
	 * @param gridOffset the offset width of the grid in px
	 */
	alignGrid: function(/*int*/ cellWidth, /*int*/ cellHeight, /*int*/ padding, /*int*/ gridOffset) {
		slidegrid.cellWidth = cellWidth;
		slidegrid.cellHeight = cellHeight;
		slidegrid.padding = padding;
		slidegrid.gridOffset = gridOffset;

	    var x = padding / 2;
	    var y = 0;
	    var count = 1;

	    /*
	     * When we add a "bigcell" to the grid it takes up four cells instead of one.
	     * That makes we need to not add any other cells to those areas or the cells
	     * will overlap.  These three variables are used to remember the cells used
	     * by big cells.
	     */
	    var curCol = 0;
	    var curRow = 0;
	    var usedCells = [];

	    $(".slidegrid").each(function() {

	        var hasTallCell = false;

	        var cols = Math.floor(($(window).width() - gridOffset) / ((cellWidth + padding)));

	        $(this).css("position", "relative");

	        var children = $(this).children("div");

	        for (var i = 0; i < children.length; i++) {
	            if (children.eq(i).hasClass("bigcell")) {
	                if (curCol === cols - 1) {
	                    /*
	                     * This means it is time to bump down to the next row
	                     */
	                    curCol = 0;
	                    curRow++;
	                    x = padding / 2;
	                    y += cellHeight + padding;
	                    count++;

	                }

	                if (slidegrid.isUsed(usedCells, curCol, curRow) ||
	                    slidegrid.isUsed(usedCells, curCol + 1, curRow) ||
	                    slidegrid.isUsed(usedCells, curCol + 1, curRow + 1) ||
	                    slidegrid.isUsed(usedCells, curCol, curRow + 1)) {
	                    /*
	                     * If the current cell is used we
	                     * just want to try the next column.
	                     * However, we also want to bump to
	                     * the next row if needed so we are
	                     * calling the column logic and then
	                     * backing up the counter.
	                     */
	                    i--;
	                } else {

	                    slidegrid.styleCell(children.eq(i), x, y, (cellWidth * 2) + padding, (cellHeight * 2) + padding, slidegrid.hasDrawn);
	                    /*
	                     * Big cells are twice as large as normal cells.  That means they
	                     * use up the cell to the right, the cell below, and the cell to
	                     * the right and below.
	                     */

	                    slidegrid.setUsed(usedCells, curCol, curRow);
	                    slidegrid.setUsed(usedCells, curCol + 1, curRow);
	                    slidegrid.setUsed(usedCells, curCol, curRow + 1);
	                    slidegrid.setUsed(usedCells, curCol + 1, curRow + 1);
	                }

	                hasTallCell = true;

	            } else if (children.eq(i).hasClass("widecell")) {
					if (slidegrid.isUsed(usedCells, curCol, curRow) ||
	                    slidegrid.isUsed(usedCells, curCol + 1, curRow) ||
						curCol === cols - 1) {
	                    /*
	                     * If the current cell is used we
	                     * just want to try the next column.
	                     * However, we also want to bump to
	                     * the next row if needed so we are
	                     * calling the column logic and then
	                     * backing up the counter.
	                     */
	                    i--;

	                } else {
	                    slidegrid.styleCell(children.eq(i), x, y, (cellWidth * 2) + padding, cellHeight, slidegrid.hasDrawn);
	                    /*
	                     * Wide cells are twice as wide, but the same height
	                     */

	                    slidegrid.setUsed(usedCells, curCol, curRow);
	                    slidegrid.setUsed(usedCells, curCol + 1, curRow);
	                }
	            } else if (children.eq(i).hasClass("tallcell")) {
	                if (slidegrid.isUsed(usedCells, curCol, curRow) ||
	                    slidegrid.isUsed(usedCells, curCol, curRow + 1)) {
	                    /*
	                     * If the current cell is used we
	                     * just want to try the next column.
	                     * However, we also want to bump to
	                     * the next row if needed so we are
	                     * calling the column logic and then
	                     * backing up the counter.
	                     */
	                    i--;

	                } else {
	                    slidegrid.styleCell(children.eq(i), x, y, cellWidth, (cellHeight * 2) + padding, slidegrid.hasDrawn);
	                    /*
	                     * Tall cells are twice as tall, but the same width
	                     */

	                    slidegrid.setUsed(usedCells, curCol, curRow);
	                    slidegrid.setUsed(usedCells, curCol, curRow + 1);
	                }

	                hasTallCell = true;

	            } else {
	                if (slidegrid.isUsed(usedCells, curCol, curRow)) {
	                    /*
	                     * If the current cell is used we
	                     * just want to try the next column.
	                     * However, we also want to bump to
	                     * the next row if needed so we are
	                     * calling the column logic and then
	                     * backing up the counter.
	                     */
	                    i--;

	                } else {
	                    slidegrid.styleCell(children.eq(i), x, y, cellWidth, cellHeight, slidegrid.hasDrawn);
	                }
	            }

	            if ((count % cols) === 0) {
	                /*
	                 * This means it is time to bump down to the next row
	                 */
	                curCol = 0;
	                curRow++;
	                x = padding / 2;
	                y += cellHeight + padding;
	            } else if ((count % cols) === 0) {
	                hasTallCell = false;
	            } else {
	                x += cellWidth + padding;
	                curCol++;
	            }

	            count++;
	        }

	        /*
	         * We need to set a height of the slidegrid div since it only has absolute
	         * height tags within it.
	         */
	        var height = 0;
	        if ((count % cols) !== 1) {
	            height = y + cellHeight + padding;
	        } else {
	            height = y + padding;
	        }

	        if (hasTallCell) {
	            height += cellHeight + padding;
	        }

	        $(this).css('height', height + "px");

	        /*
	         * Now we reset the variables for the next grid.
	         */
	        x = padding / 2;
	        y = 0;
	        count = 1;
	    });

	    slidegrid.hasDrawn = true;
	},

	resizeWindow: function(e) {
        if (slidegrid.windowWidth != $(window).width()) {
            slidegrid.alignGrid(slidegrid.cellWidth, slidegrid.cellHeight, slidegrid.padding, slidegrid.gridOffset);
            slidegrid.windowWidth = $(window).width();
        }
    }
}

$(document).ready(function() {
    /*
     * When the user resizes the window we need to redraw the grid.
     * This works well in Firefox and Chrome, but IE and Safari fire
     * the resize events a little more often than they need to.  We
     * remember the last window width so we can only repaint the grid
     * when we need to.
     */
    $(window).bind("resize", slidegrid.resizeWindow);
});
<|endoftext|>


<commit_before>var addic7edApi = require('addic7ed-api');
var fs = require('fs');
var Common = require('../common.js');
var Mongoose = require('mongoose');
var Mongo = require('../db/mongo.js');
var ScheduleManager = require('../schedule/scheduleManager.js');
var TvMaze = require('../libs/tvMaze.js');
var Logger = require('../log/logger.js');

exports.addic7edGetSubtitle = function (session, languages, bot, chat, sessionsList) {
    if(session.choosenEpisode.indexOf('-')===-1){
        getSingleEpisodeSubs(session, languages, bot, chat, sessionsList, session.choosenEpisode, true)
    }else{
        var start = +session.choosenEpisode.substr(0, session.choosenEpisode.indexOf('-'));
        var end = +session.choosenEpisode.substr(session.choosenEpisode.indexOf('-') + 1, session.choosenEpisode.length);
        while (start <= end){
            getSingleEpisodeSubs(session, languages, bot, chat, sessionsList, start, start == end),
            start++;
        }
    }
}

function getSingleEpisodeSubs (session, languages = [], bot, chat, sessionsList, episode, sendAmbiguousMessage) {
    //Logger.logEvent("get", languages, session);
    addic7edApi.search(session.choosenSeries.show.name, session.choosenSeason,
        episode, languages).then(function (subtitlesList) {
            var subInfo = subtitlesList[0];
            if (subInfo != undefined) {
                var filename = session.choosenSeries.show.name + '_S' + session.choosenSeason + '_E' + episode + '.srt';
                addic7edApi.download(subInfo, filename).then(function () {
                    fs.exists(filename, function (exists) {
                        if (exists) {
                            console.log('Subtitles file saved.');
                            Common.removeSession(sessionsList, session);
                            bot.sendMessage(chat, Common.buildLinkMessage(subInfo.link));
                            bot.sendDocument(chat, filename).then(function () {
                                fs.unlinkSync(filename);
                            });
                            if (sendAmbiguousMessage && session.choosenSeries.show.name.indexOf("(") > -1 && session.choosenSeries.show.name.indexOf(")") > -1) {
                                bot.sendMessage(chat, Common.ambigousSubtitleMessage);
                            }
                        }
                    });
                 }).catch(function (err) {
                    console.log("error downloading subs");
                });
            }
            else
                bot.sendMessage(chat, Common.subtitleNotFoundInAddic7edMessage);
         }).catch(function (err) {
            console.log("error searching subs - ", session);
        });
}

exports.addic7edGetSubtitleAlert = function (alert, job, bot, doneJobInterval) {
    addic7edApi.search(alert.show_name, alert.nextepisode_season, alert.nextepisode_episode, alert.language).then(function (subtitlesList) {
        var subInfo = subtitlesList[0];
        if (subInfo != undefined) {
            var filename = alert.show_name + '_S' + alert.nextepisode_season + '_E' + alert.nextepisode_episode + '.srt';
            addic7edApi.download(subInfo, filename).then(function () {
                fs.exists(filename, function (exists) {
                    if (exists) {
                        console.log('Subtitles file saved.');
                        Mongo.User.find({ alerts: alert._id.toString() }, function (err, users) {
                            users.forEach(function (user) {
                                var userDoc = user._doc;
                                bot.sendMessage(userDoc.chatId, Common.newEpisodeAlertMessage(userDoc.first_name, alert.show_name));
                                bot.sendMessage(userDoc.chatId, Common.buildLinkMessage(subInfo.link));
                                bot.sendDocument(userDoc.chatId, filename).then(function () {
                                    console.log("File sent to user " + userDoc.first_name);
                                });
                                if (Common.isAmbiguousTitle(alert.show_name)) {
                                    bot.sendMessage(userDoc.chatId, Common.ambigousSubtitleMessage);
                                }
                            });
                            job.attrs.data.hasToBeRemoved = true;
                            fs.unlinkSync(filename);
                            doneJobInterval();
                        });
                    }
                });
             }).catch(function (err) {
                console.log("error download subs - ", alert);
            });
        } else {
            job.attrs.data.hasToBeRemoved = false;
            doneJobInterval();
        }
     }).catch(function (err) {
        console.log("error searching subs - ", alert);
    });
}<commit_msg>fixed _doc bug in alert<commit_after>var addic7edApi = require('addic7ed-api');
var fs = require('fs');
var Common = require('../common.js');
var Mongoose = require('mongoose');
var Mongo = require('../db/mongo.js');
var ScheduleManager = require('../schedule/scheduleManager.js');
var TvMaze = require('../libs/tvMaze.js');
var Logger = require('../log/logger.js');

exports.addic7edGetSubtitle = function (session, languages, bot, chat, sessionsList) {
    if(session.choosenEpisode.indexOf('-')===-1){
        getSingleEpisodeSubs(session, languages, bot, chat, sessionsList, session.choosenEpisode, true)
    }else{
        var start = +session.choosenEpisode.substr(0, session.choosenEpisode.indexOf('-'));
        var end = +session.choosenEpisode.substr(session.choosenEpisode.indexOf('-') + 1, session.choosenEpisode.length);
        while (start <= end){
            getSingleEpisodeSubs(session, languages, bot, chat, sessionsList, start, start == end),
            start++;
        }
    }
}

function getSingleEpisodeSubs (session, languages = [], bot, chat, sessionsList, episode, sendAmbiguousMessage) {
    //Logger.logEvent("get", languages, session);
    addic7edApi.search(session.choosenSeries.show.name, session.choosenSeason,
        episode, languages).then(function (subtitlesList) {
            var subInfo = subtitlesList[0];
            if (subInfo != undefined) {
                var filename = session.choosenSeries.show.name + '_S' + session.choosenSeason + '_E' + episode + '.srt';
                addic7edApi.download(subInfo, filename).then(function () {
                    fs.exists(filename, function (exists) {
                        if (exists) {
                            console.log('Subtitles file saved.');
                            Common.removeSession(sessionsList, session);
                            bot.sendMessage(chat, Common.buildLinkMessage(subInfo.link));
                            bot.sendDocument(chat, filename).then(function () {
                                fs.unlinkSync(filename);
                            });
                            if (sendAmbiguousMessage && session.choosenSeries.show.name.indexOf("(") > -1 && session.choosenSeries.show.name.indexOf(")") > -1) {
                                bot.sendMessage(chat, Common.ambigousSubtitleMessage);
                            }
                        }
                    });
                 }).catch(function (err) {
                    console.log("error downloading subs");
                });
            }
            else
                bot.sendMessage(chat, Common.subtitleNotFoundInAddic7edMessage);
         }).catch(function (err) {
            console.log("error searching subs - ", session);
        });
}

exports.addic7edGetSubtitleAlert = function (alert, job, bot, doneJobInterval) {
    addic7edApi.search(alert.show_name, alert.nextepisode_season, alert.nextepisode_episode, alert.language).then(function (subtitlesList) {
        var subInfo = subtitlesList[0];
        if (subInfo != undefined) {
            var filename = alert.show_name + '_S' + alert.nextepisode_season + '_E' + alert.nextepisode_episode + '.srt';
            addic7edApi.download(subInfo, filename).then(function () {
                fs.exists(filename, function (exists) {
                    if (exists) {
                        console.log('Subtitles file saved.');
                        Mongo.User.find({ alerts: alert._doc._id.toString() }, function (err, users) {
                            users.forEach(function (user) {
                                var userDoc = user._doc;
                                bot.sendMessage(userDoc.chatId, Common.newEpisodeAlertMessage(userDoc.first_name, alert._doc.show_name));
                                bot.sendMessage(userDoc.chatId, Common.buildLinkMessage(subInfo.link));
                                bot.sendDocument(userDoc.chatId, filename).then(function () {
                                    console.log("File sent to user " + userDoc.first_name);
                                });
                                if (Common.isAmbiguousTitle(alert._doc.show_name)) {
                                    bot.sendMessage(userDoc.chatId, Common.ambigousSubtitleMessage);
                                }
                            });
                            job.attrs.data.hasToBeRemoved = true;
                            fs.unlinkSync(filename);
                            doneJobInterval();
                        });
                    }
                });
             }).catch(function (err) {
                console.log("error download subs - ", alert);
            });
        } else {
            job.attrs.data.hasToBeRemoved = false;
            doneJobInterval();
        }
     }).catch(function (err) {
        console.log("error searching subs - ", alert);
    });
}<|endoftext|>


<commit_before>	$().ready(function() {
	    // Retreive URL Hash data

	    var rootUrl = "https://cryptamatic.com"
	    var decryptUrlBits = "#d/"
		var decryptUrlBitsMail = "%23d/"
	    var hashTag = window.location.hash
	    var splitHashTag = hashTag.split('/')
	    var mode = splitHashTag[0]
	    var payload = splitHashTag[1]
	    var clipboard = new Clipboard('.clipboard-btn');
	    //alert(hashTag);
	    //alert(mode);
	    //define functions

	    function EncryptTheStuff() {
	        triplesec.encrypt({

	            data: new triplesec.Buffer($('#text').val()),
	            key: new triplesec.Buffer($('#key').val()),
	            progress_hook: function(obj) {

	            }

	        }, function(err, buff) {

	            if (!err) {
	                var ciphertext = buff.toString('hex');
	                //Create the nice shareable URL
	                var assembleShareLink = rootUrl.concat(decryptUrlBits);
	                var shareLink = assembleShareLink.concat(ciphertext);
					var outputPassword = $('#key').val();
	                $('#text').val(shareLink);
	                //$('#loading').html('ALL DONE!');
	                $('#loading').html('');
					$('#encryption-output-div').show();
	                $('#output-password').html(outputPassword);
					$('#output-title').show();
	                var NatoOptions = {
	                    'decode': $('#key').val(),
	                    'includeCase': true
	                };
	                var phoneticString = $.NatoCallout(NatoOptions);
	                $('#phonetic-key').html(phoneticString)
					var emailAssembleShareLink = rootUrl.concat(decryptUrlBitsMail);
	                var emailShareLink = emailAssembleShareLink.concat(ciphertext);
					var beforeEmailContent = "mailto:?subject=A%20secret%20has%20been%20shared%20with%20you%20via%20cryptamatic.com&body="
					var afterEmailContent = "%0A%0AWhat%20is%20this%20link%3F%0AThe%20URL%20above%20actually%20contains%20the%20encrypted%20data%20-%20no%20data%20is%20stored%20on%20cryptamatic%27s%20servers.%20When%20you%20click%20on%20it%2C%20it%20will%20load%20our%20site%20and%20automaticaly%20auto-fill%20the%20encrypted%20message%20into%20the%20browser%20window.%0A%0AFind%20out%20more%3A%0Ahttps%3A%2F%2Fcryptamatic.com"
					var partAssembledMailLink = beforeEmailContent.concat(emailShareLink);
					var fullAssembledMailLink = partAssembledMailLink.concat(afterEmailContent);
					$('#mailto-button').attr('href',fullAssembledMailLink);

	            } else {
	                alert('hmm that didnt work!');
	                $('#encrypt-button').show();
	                $('#loading').hide();
	            }

	        });
	    }

	    function setRandomPasswordandEncrypt(passwordOptionBool) {
	        if (!$("#AutogenPasswordOptionsBool").prop('checked')) { //if bool is false dont autogen password stuff
	            EncryptTheStuff();
	        } else if (!$("#PasswordOptionsBool").prop('checked')) { //if bool is false dont use random.org seed
	            var my_chance = new Chance();
	            $('#key').val(my_chance.string({
	                length: 15,
	                pool: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
	            }));
	            EncryptTheStuff();
	        } else {
	            var mySeed;
	            $.get("https://www.random.org/integers/", {
	                num: "1",
	                col: "1",
	                min: "1",
	                max: "1000000000",
	                base: "10",
	                format: "plain",
	                rnd: "new"
	            }, function(randNum) {
	                mySeed = randNum;
	                //debugger;
	                // Instantiate Chance with this truly random number as the seed
	                var my_seeded_chance = new Chance(mySeed);
	                $('#key').val(my_seeded_chance.string({
	                    length: 15,
	                    pool: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
	                }));
	                EncryptTheStuff();
	            });
	        }
	    }
	    $('#text').focus();
	    //$('#text').html('Type your secret here');
	    $('#encrypt-button').on('click', function() {

	        //	        if ( $(this).parsley().isValid() ) {
	        //fill in the key section with a random key created by the Chance library (and Random.org)
	        setRandomPasswordandEncrypt();

	        //function call back (to make sure that the get succeeds before trying to encrypt

	        $('#encrypt-button, #loading').hide();
	        $('#text').height('160px');
	        $('#loading').show();
			$('#OptionsModalLink').hide();

	        // Start encryption

	        //	        }
	    });
	    //DECRYPTING THE STUFF
	    $('#decrypt-button').on('click', function() {
	        $('#decrypt-button, #loading').hide();
	        $('#text').height('160px');
	        $('#loading').show();
	        triplesec.decrypt({

	            data: new triplesec.Buffer($('#text').val(), "hex"),
	            key: new triplesec.Buffer($('#key').val()),
	            progress_hook: function(obj) { /* ... */ }

	        }, function(err, buff) {

	            if (!err) {
	                $('#text').val(buff.toString());
	                $('#loading').html('');
					$('#clipboarddecrypted').show();
	                $('#password-row').hide();

	            } else {
	                alert('Your message could not be decrypted. Check your password.');
	                $('#decrypt-button').show();
	                $('#loading').hide();
	            }

	        });
	    });
	    //Show Encrypt Button if someone click the decrypt link (TBA)

	    $('#encrypt-view').on('click', function() {
	        $('#decrypt-button-div').hide();
	        $('#encrypt-button-div').show();
	        $('#encrypt-view').hide();
	        $('#decrypt-view').show();
	        $('#OptionsModalLink').show();
	        var a = document.getElementById("key");
	        a.value = a.defaultValue;
	    });

	    //Show Decrypt Button if someone click the decrypt link (TBA)

	    $('#decrypt-view').on('click', function() {
	        $('#decrypt-button-div').show();
	        $('#encrypt-button-div').hide()
	        $('#encrypt-view').show();
	        $('#decrypt-view').hide();
	        $('#OptionsModalLink').hide();
	        $('#key').show();
	        var a = document.getElementById("key");
	        a.value = a.defaultValue;
	    });
	    //Show Decrypt Button if #d exist
	    if (mode.includes('#d')) {
	        $('#text').html(payload);
	        $('#decrypt-button-div').show();
	        $('#encrypt-button-div').hide();
	        $('#encrypt-view').show();
	        $('#key').show();
	        $('#OptionsModalLink').hide();
	    } else {
	        $('#decrypt-button-div').hide();
	        $('#encrypt-button-div').show();
	        $('#decrypt-view').show();

	    }

	    //Show password field if option checked
	    $('#AutogenPasswordOptionsBool').change(function() {
	        if (!$("#AutogenPasswordOptionsBool").prop('checked')) { //if bool is false dont autogen password stuff
	            $('#key').show();
	        } else {
	            $('#key').hide();
	        }
	    });
	});<commit_msg>added basic click track<commit_after>	$().ready(function() {
	    // Retreive URL Hash data

	    var rootUrl = "https://cryptamatic.com"
	    var decryptUrlBits = "#d/"
		var decryptUrlBitsMail = "%23d/"
	    var hashTag = window.location.hash
	    var splitHashTag = hashTag.split('/')
	    var mode = splitHashTag[0]
	    var payload = splitHashTag[1]
	    var clipboard = new Clipboard('.clipboard-btn');
	    //alert(hashTag);
	    //alert(mode);
	    //define functions

	    function EncryptTheStuff() {
	        triplesec.encrypt({

	            data: new triplesec.Buffer($('#text').val()),
	            key: new triplesec.Buffer($('#key').val()),
	            progress_hook: function(obj) {

	            }

	        }, function(err, buff) {

	            if (!err) {
	                var ciphertext = buff.toString('hex');
	                //Create the nice shareable URL
	                var assembleShareLink = rootUrl.concat(decryptUrlBits);
	                var shareLink = assembleShareLink.concat(ciphertext);
					var outputPassword = $('#key').val();
	                $('#text').val(shareLink);
	                //$('#loading').html('ALL DONE!');
	                $('#loading').html('');
					$('#encryption-output-div').show();
	                $('#output-password').html(outputPassword);
					$('#output-title').show();
	                var NatoOptions = {
	                    'decode': $('#key').val(),
	                    'includeCase': true
	                };
	                var phoneticString = $.NatoCallout(NatoOptions);
	                $('#phonetic-key').html(phoneticString)
					var emailAssembleShareLink = rootUrl.concat(decryptUrlBitsMail);
	                var emailShareLink = emailAssembleShareLink.concat(ciphertext);
					var beforeEmailContent = "mailto:?subject=A%20secret%20has%20been%20shared%20with%20you%20via%20cryptamatic.com&body="
					var afterEmailContent = "%0A%0AWhat%20is%20this%20link%3F%0AThe%20URL%20above%20actually%20contains%20the%20encrypted%20data%20-%20no%20data%20is%20stored%20on%20cryptamatic%27s%20servers.%20When%20you%20click%20on%20it%2C%20it%20will%20load%20our%20site%20and%20automaticaly%20auto-fill%20the%20encrypted%20message%20into%20the%20browser%20window.%0A%0AFind%20out%20more%3A%0Ahttps%3A%2F%2Fcryptamatic.com"
					var partAssembledMailLink = beforeEmailContent.concat(emailShareLink);
					var fullAssembledMailLink = partAssembledMailLink.concat(afterEmailContent);
					$('#mailto-button').attr('href',fullAssembledMailLink);

	            } else {
	                alert('hmm that didnt work!');
	                $('#encrypt-button').show();
	                $('#loading').hide();
	            }

	        });
	    }

	    function setRandomPasswordandEncrypt(passwordOptionBool) {
	        if (!$("#AutogenPasswordOptionsBool").prop('checked')) { //if bool is false dont autogen password stuff
	            EncryptTheStuff();
	        } else if (!$("#PasswordOptionsBool").prop('checked')) { //if bool is false dont use random.org seed
	            var my_chance = new Chance();
	            $('#key').val(my_chance.string({
	                length: 15,
	                pool: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
	            }));
	            EncryptTheStuff();
	        } else {
	            var mySeed;
	            $.get("https://www.random.org/integers/", {
	                num: "1",
	                col: "1",
	                min: "1",
	                max: "1000000000",
	                base: "10",
	                format: "plain",
	                rnd: "new"
	            }, function(randNum) {
	                mySeed = randNum;
	                //debugger;
	                // Instantiate Chance with this truly random number as the seed
	                var my_seeded_chance = new Chance(mySeed);
	                $('#key').val(my_seeded_chance.string({
	                    length: 15,
	                    pool: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
	                }));
	                EncryptTheStuff();
	            });
	        }
	    }
	    $('#text').focus();
	    //$('#text').html('Type your secret here');
	    $('#encrypt-button').on('click', function() {

	        //	        if ( $(this).parsley().isValid() ) {
	        //fill in the key section with a random key created by the Chance library (and Random.org)
	        setRandomPasswordandEncrypt();

	        //function call back (to make sure that the get succeeds before trying to encrypt
			//basic click tracking
			$('track_click').attr('src','https://s3-us-west-2.amazonaws.com/cryptamatic-clicktrack/enc-click.gif');

	        $('#encrypt-button, #loading').hide();
	        $('#text').height('160px');
	        $('#loading').show();
			$('#OptionsModalLink').hide();

	        // Start encryption

	        //	        }
	    });
	    //DECRYPTING THE STUFF
	    $('#decrypt-button').on('click', function() {
	        $('#decrypt-button, #loading').hide();
	        $('#text').height('160px');
	        $('#loading').show();
			//basic click tracking
			$('track_click').attr('src','https://s3-us-west-2.amazonaws.com/cryptamatic-clicktrack/dec-click.gif');
			triplesec.decrypt({

	            data: new triplesec.Buffer($('#text').val(), "hex"),
	            key: new triplesec.Buffer($('#key').val()),
	            progress_hook: function(obj) { /* ... */ }

	        }, function(err, buff) {

	            if (!err) {
	                $('#text').val(buff.toString());
	                $('#loading').html('');
					$('#clipboarddecrypted').show();
	                $('#password-row').hide();

	            } else {
	                alert('Your message could not be decrypted. Check your password.');
	                $('#decrypt-button').show();
	                $('#loading').hide();
	            }

	        });
	    });
	    //Show Encrypt Button if someone click the decrypt link (TBA)

	    $('#encrypt-view').on('click', function() {
	        $('#decrypt-button-div').hide();
	        $('#encrypt-button-div').show();
	        $('#encrypt-view').hide();
	        $('#decrypt-view').show();
	        $('#OptionsModalLink').show();
	        var a = document.getElementById("key");
	        a.value = a.defaultValue;
	    });

	    //Show Decrypt Button if someone click the decrypt link (TBA)

	    $('#decrypt-view').on('click', function() {
	        $('#decrypt-button-div').show();
	        $('#encrypt-button-div').hide()
	        $('#encrypt-view').show();
	        $('#decrypt-view').hide();
	        $('#OptionsModalLink').hide();
	        $('#key').show();
	        var a = document.getElementById("key");
	        a.value = a.defaultValue;
	    });
	    //Show Decrypt Button if #d exist
	    if (mode.includes('#d')) {
	        $('#text').html(payload);
	        $('#decrypt-button-div').show();
	        $('#encrypt-button-div').hide();
	        $('#encrypt-view').show();
	        $('#key').show();
	        $('#OptionsModalLink').hide();
	    } else {
	        $('#decrypt-button-div').hide();
	        $('#encrypt-button-div').show();
	        $('#decrypt-view').show();

	    }

	    //Show password field if option checked
	    $('#AutogenPasswordOptionsBool').change(function() {
	        if (!$("#AutogenPasswordOptionsBool").prop('checked')) { //if bool is false dont autogen password stuff
	            $('#key').show();
	        } else {
	            $('#key').hide();
	        }
	    });
	});<|endoftext|>


<commit_before>var matpanel = React.createClass({displayName: "matpanel",
  render: function(){
    return(
      React.createElement("div",{className: 'col-xs-12 col-sm-12 col-md-12 col-lg-12'},
       React.createElement("div",{className: 'box'},
        React.createElement("div",{className: 'box-icon'},
         React.createElement("span",{className: this.props.icon},null)
        ),
        React.createElement("div",{className: 'info'},
         React.createElement("h4",{className: 'text-center'},this.props.head),
         React.createElement("p",null,this.props.children),
        React.createElement("a",{href: this.props.btnlink, className: 'btn'},this.props.btnlabel)
        )
       )
      )
    );

  }

});

var mpanelgrp = React.createClass({displayName: "mpanelgrp",
  render: function(){
    return(
      React.createElement("div",{className: 'row'},
       React.createElement("div",{onChange: this.onChange ,className: this.props.colsize},
       this.props.options.map(function(option){return(
         React.createElement(matpanel,{icon: option.icon,head: option.head,btnlabel: option.btnlabel,btnlink: option.btnlink, key: option.head},option.content)
         );
       })
       )
      )
    );
  }
});
<commit_msg>qoute icon<commit_after>var matpanel = React.createClass({displayName: "matpanel",
  render: function(){
    return(
      React.createElement("div",{className: 'col-xs-12 col-sm-12 col-md-12 col-lg-12'},
       React.createElement("div",{className: 'box'},
        React.createElement("div",{className: 'box-icon'},
         React.createElement("span",{className: this.props.icon},null)
        ),
        React.createElement("div",{className: 'info'},
         React.createElement("h4",{className: 'text-center'},this.props.head),
         React.createElement("p",null,React.createElement("i",{className: 'fa fa-2x fa-qoute-left'},null),this.props.children,React.createElement("i",{className: 'fa fa-qoute-right'},null)),
        React.createElement("a",{href: this.props.btnlink, className: 'btn'},this.props.btnlabel)
        )
       )
      )
    );

  }

});

var mpanelgrp = React.createClass({displayName: "mpanelgrp",
  render: function(){
    return(
      React.createElement("div",{className: 'row'},
       React.createElement("div",{onChange: this.onChange ,className: this.props.colsize},
       this.props.options.map(function(option){return(
         React.createElement(matpanel,{icon: option.icon,head: option.head,btnlabel: option.btnlabel,btnlink: option.btnlink, key: option.head},option.content)
         );
       })
       )
      )
    );
  }
});
<|endoftext|>


<commit_before>//The Utils module contains all the functions that are used by,
//but do not directly affect the MapController or Palette

define(["modules/color-thief.min", "modules/rainbowvis"], function() {

    //Function to convert image URLs to base64
    var imageToBase64 = function(url, callback){
        var xhr = new XMLHttpRequest();
        xhr.onload = function () {
            var reader = new FileReader();
            reader.onloadend = function () {
                callback(reader.result);
            }
            reader.readAsDataURL(xhr.response);
        };
        xhr.open('GET', url);
        xhr.responseType = 'blob';
        xhr.send();
    }

    var imageToColours = function(image, numberOfColours){
        var dfd = $.Deferred();
        if (image.startsWith("data:image")) {

            var img = document.createElement('img');
            img.setAttribute("src", image);
            img.addEventListener('load', function () {
                //Update the canvas to display the image preview
                updateCanvas($(img).attr('src'));
                var colorThief = new ColorThief();
                //Request ColorThief to return a palette of five colours from the image that we can use to update the map's style
                var colorThiefColors = colorThief.getPalette(img, numberOfColours);
                for (var colors in colorThiefColors) {
                    colorThiefColors[colors] = rgbToHex(colorThiefColors[colors][0], colorThiefColors[colors][1], colorThiefColors[colors][2]);
                }
                dfd.resolve(colorThiefColors);
            });
        }
        else {
            dfd.resolve("error");
        }
        return dfd.promise();
    }

    var updateCanvas = function (imagesrc) {
        var canvas = document.getElementById("c");
        var cardContent = document.getElementsByClassName("card-content")[0];
        canvas.width = cardContent.clientWidth;
        canvas.height = cardContent.clientHeight;
        var ctx	= canvas.getContext("2d");
        var image = new Image();
        image.onload = function () {
            ctx.clearRect(0, 0, cardContent.clientWidth, cardContent.clientHeight);
            var wrh = image.width / image.height;
            var newWidth = cardContent.clientWidth;
            var newHeight = newWidth / wrh;
            if (newHeight > cardContent.clientHeight) {
                newHeight = cardContent.clientHeight;
                newWidth = newHeight * wrh;
            }
            offset = 0;
            if (newWidth < cardContent.clientWidth) {
                offset = (cardContent.clientWidth/2) - (newWidth/2);
            }
            if (newWidth > newHeight){
            }
            ctx.drawImage(image, offset, 0, newWidth, newHeight);
        };
        image.src = imagesrc;
    }

    //Function for converting component colour values to hex
    var componentToHex = function (c) {
        var hex = c.toString(16);
        return hex.length == 1 ? "0" + hex : hex;
    }

    //Function to convert RGB colour value to hex
    var rgbToHex = function (r, g, b) {
        return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
    }

    //Function to do a find and replace in the style JSON to replace original colour values with new ones
    function stringReplace(str, replaceWhat, replaceTo) {
        replaceWhat = replaceWhat.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
        var re = new RegExp(replaceWhat, 'gi');
        return str.replace(re, replaceTo);
    }

    //Generate a colour ramp between two colours using RainbowVIS-JS - https://github.com/anomal/RainbowVis-JS
    function getColourRamp(first, last) {
        var array = getBaseColourArray();
        //Use the number of colours in the dark gray canvas vector tile colour array to define how many colours in the generated colour ramp
        var numberOfItems = array.length;
        var rainbow = new Rainbow();
        rainbow.setNumberRange(1, numberOfItems);
        rainbow.setSpectrum(first, last);
        var dict = [];
        for (var i = 1; i <= numberOfItems; i++) {
            dict[array[i - 1]] = "#" + rainbow.colourAt(i).toUpperCase();
        }
        return dict;
    }

    function getBaseColourArray(){
        var array = ["#222326", "#222426", "#2d2c2e", "#323133", "#373638", "#3b3a3c", "#3f3e40",
           "#414042", "#424143", "#464748", "#474648", "#4a494b", "#494b4a", "#49484a", "#4e4d4f",
           "#59585a", "#5a595b", "#5b5a5c", "#5d5c5e", "#5f5e60", "#666666", "#6e6d6f", "#787779",
           "#828282", "#808781", "#868587", "#939294", "#969696", "#99989a", "#9c9c9c", "#a2a2a6",
           "#abaaac", "#aeadaf", "#cfcfd4", "#dddcde", "#f5f2dc", "#fdfdfd", "#ffffff"
        ];
        return array;
    }

    //Stuff to make public
    return {
        imageToBase64: imageToBase64,
        imageToColours: imageToColours,
        componentToHex: componentToHex,
        rgbToHex: rgbToHex,
        stringReplace: stringReplace,
        getColourRamp: getColourRamp,
        getBaseColourArray: getBaseColourArray,
        updateCanvas: updateCanvas
    };

});<commit_msg>Don't update canvas if image is invalid<commit_after>//The Utils module contains all the functions that are used by,
//but do not directly affect the MapController or Palette

define(["modules/color-thief.min", "modules/rainbowvis"], function() {

    //Function to convert image URLs to base64
    var imageToBase64 = function(url, callback){
        var xhr = new XMLHttpRequest();
        xhr.onload = function () {
            var reader = new FileReader();
            reader.onloadend = function () {
                callback(reader.result);
            }
            reader.readAsDataURL(xhr.response);
        };
        xhr.open('GET', url);
        xhr.responseType = 'blob';
        xhr.send();
    }

    var imageToColours = function(image, numberOfColours){
        var dfd = $.Deferred();
        if (image.startsWith("data:image")) {

            var img = document.createElement('img');
            img.setAttribute("src", image);
            img.addEventListener('load', function () {
                var colorThief = new ColorThief();
                //Request ColorThief to return a palette of five colours from the image that we can use to update the map's style
                var colorThiefColors = colorThief.getPalette(img, numberOfColours);
                if (colorThiefColors != null){
                    //Update the canvas to display the image preview
                    updateCanvas($(img).attr('src'));
                }
                for (var colors in colorThiefColors) {
                    colorThiefColors[colors] = rgbToHex(colorThiefColors[colors][0], colorThiefColors[colors][1], colorThiefColors[colors][2]);
                }
                dfd.resolve(colorThiefColors);
            });
        }
        else {
            dfd.resolve("error");
        }
        return dfd.promise();
    }

    var updateCanvas = function (imagesrc) {
        var canvas = document.getElementById("c");
        var cardContent = document.getElementsByClassName("card-content")[0];
        canvas.width = cardContent.clientWidth;
        canvas.height = cardContent.clientHeight;
        var ctx	= canvas.getContext("2d");
        var image = new Image();
        image.onload = function () {
            ctx.clearRect(0, 0, cardContent.clientWidth, cardContent.clientHeight);
            var wrh = image.width / image.height;
            var newWidth = cardContent.clientWidth;
            var newHeight = newWidth / wrh;
            if (newHeight > cardContent.clientHeight) {
                newHeight = cardContent.clientHeight;
                newWidth = newHeight * wrh;
            }
            offset = 0;
            if (newWidth < cardContent.clientWidth) {
                offset = (cardContent.clientWidth/2) - (newWidth/2);
            }
            if (newWidth > newHeight){
            }
            ctx.drawImage(image, offset, 0, newWidth, newHeight);
        };
        image.src = imagesrc;
    }

    //Function for converting component colour values to hex
    var componentToHex = function (c) {
        var hex = c.toString(16);
        return hex.length == 1 ? "0" + hex : hex;
    }

    //Function to convert RGB colour value to hex
    var rgbToHex = function (r, g, b) {
        return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
    }

    //Function to do a find and replace in the style JSON to replace original colour values with new ones
    function stringReplace(str, replaceWhat, replaceTo) {
        replaceWhat = replaceWhat.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
        var re = new RegExp(replaceWhat, 'gi');
        return str.replace(re, replaceTo);
    }

    //Generate a colour ramp between two colours using RainbowVIS-JS - https://github.com/anomal/RainbowVis-JS
    function getColourRamp(first, last) {
        var array = getBaseColourArray();
        //Use the number of colours in the dark gray canvas vector tile colour array to define how many colours in the generated colour ramp
        var numberOfItems = array.length;
        var rainbow = new Rainbow();
        rainbow.setNumberRange(1, numberOfItems);
        rainbow.setSpectrum(first, last);
        var dict = [];
        for (var i = 1; i <= numberOfItems; i++) {
            dict[array[i - 1]] = "#" + rainbow.colourAt(i).toUpperCase();
        }
        return dict;
    }

    function getBaseColourArray(){
        var array = ["#222326", "#222426", "#2d2c2e", "#323133", "#373638", "#3b3a3c", "#3f3e40",
           "#414042", "#424143", "#464748", "#474648", "#4a494b", "#494b4a", "#49484a", "#4e4d4f",
           "#59585a", "#5a595b", "#5b5a5c", "#5d5c5e", "#5f5e60", "#666666", "#6e6d6f", "#787779",
           "#828282", "#808781", "#868587", "#939294", "#969696", "#99989a", "#9c9c9c", "#a2a2a6",
           "#abaaac", "#aeadaf", "#cfcfd4", "#dddcde", "#f5f2dc", "#fdfdfd", "#ffffff"
        ];
        return array;
    }

    //Stuff to make public
    return {
        imageToBase64: imageToBase64,
        imageToColours: imageToColours,
        componentToHex: componentToHex,
        rgbToHex: rgbToHex,
        stringReplace: stringReplace,
        getColourRamp: getColourRamp,
        getBaseColourArray: getBaseColourArray,
        updateCanvas: updateCanvas
    };

});<|endoftext|>


<commit_before>//Responsibilities.
/*
*** Incomplete.

Listing notifications
adding notifications
removing notifications
updating notifications

searches
list searches
retreive search info
create notification from search
*/

  'use strict';

  /**
   * @ngdoc function
   * @name clientApp.controller:ConfigfilesCtrl
   * @description
   * # ConfigfilesCtrl
   * Controller of the clientApp
   */
  angular.module('clientApp')
    .controller('NotificationsCtrl', function ($scope,$http,$location) {
      var selectedSearch=null
        $scope.searchList= [
          {ID:"1",Title:"Search Example",SearchString:"searchstring"},
          {ID:"2",Title:"Another Search",SearchString:"searchstring"},
          {ID:"3",Title:"Another Example",SearchString:"searchstring"},
        ];
        $scope.NotificationList = [
          {NotifyID:"1",SearchID:"1",Threshold:"2",Period:""},//Period in minutes.
          {NotifyID:"2",SearchID:"1",Threshold:"2",Period:""},
          {NotifyID:"3",SearchID:"2",Threshold:"2",Period:""},
          {NotifyID:"4",SearchID:"3",Threshold:"2",Period:""},
        ];
        $scope.notification = {};
        $scope.notification.thresholdType          = "Max";
        $scope.notification.notificationName       = "Notification Name";
        //$scope.selectedSearch         =
        $scope.notification.thresholdCount         = 10;
        $scope.notification.timeValue              = 10;
        $scope.notification.timeFrame              = "m";
        $scope.notification.enabled                = false;
        $scope.notification.notificationDescription= "Notification Description";
        $scope.notification.notifyEmail            = "example@domain.com";

        servicelocation = "https://" + $location.$$host + "/api/Notification";

      //  servicelocation = "https://" + $location.$$host + "/api/";
        var data = {};
        var config = {headers:{
          "Content-type": "application/x-www-form-urlencoded; charset=utf-8"
          }};

          $http.post(servicelocation+"/GetNotifications",data,config)
            .success(function(data)
              {
                console.log(data);
                 $scope.notificationFiles=data;
              });

        $scope.refreshScreen = function()
        {
          servicelocation = "https://" + $location.$$host + "/api/Notification";
          var data = {};
          var config = {headers:{
            "Content-type": "application/x-www-form-urlencoded; charset=utf-8"
            }};
          // $http.post(servicelocation+"/GetNotifications",data,config)
          //   .success(function(data)
          //     {
          //       console.log(data);
          //        $scope.notifications=data;
          //     });

          servicelocation = "https://" + $location.$$host + "/api/Notification";
          var data = {};
          var config = {headers:{
            "Content-type": "application/x-www-form-urlencoded; charset=utf-8"
            }};
          $http.post(servicelocation+"/ListSearches",data,config)
            .success(function(data)
              {
                console.log(data);
                 $scope.avalibleSearches=data;
              });
        }

        $scope.refreshScreen();

        $scope.deleteFile = function(configuration){
          $scope.filelocation = "";
          $scope.conffilename = configuration;

          var retVal = prompt("You must confirm to delete this file enter DELETE in the box below \n\n are you sure you want to continue?", "WARNING");

          if(retVal=="DELETE")
          {
            var data = "conffilename="+ encodeURIComponent(configuration);
            var config = {headers:{
              "Content-type": "application/x-www-form-urlencoded; charset=utf-8"
            }};

            var result = $http.post(servicelocation+"Notification/DeleteNotification",data,config)
              .success(function(data)
                {
                  console.log(data);
                  $scope.configuration = data;
                });
          }
          $scope.refreshScreen();
        }

      $scope.updateTextArea = function(configuration){

        $scope.filelocation = "";
        $scope.filename = configuration;

        var data = "configfile="+ encodeURIComponent(configuration);
        var config = {headers:{
          "Content-type": "application/x-www-form-urlencoded; charset=utf-8"
        }};

        var result = $http.post(servicelocation+"Notification/GetNotification",data,config)
          .success(function(data)
            {
              console.log(data);
              //$scope.configuration = data;
              $scope.notification = data;

            });
      };

$scope.saveNotification = function()
{

  if($scope.notification.notificationName=="")
  {
    alert('you must supply a notification name!');
    return;
  }
  if($scope.notification.selectedSearch=="")
  {
    alert('you must select a search name!');
    return;
  }

  var data = "notificationName="
  + encodeURIComponent($scope.notification.notificationName);
  data+= "&selectedSearch="
  + encodeURIComponent($scope.notification.selectedSearch);
  data+= "&thresholdType="
  + encodeURIComponent($scope.notification.thresholdType);
  data+= "&thresholdCount="
  + encodeURIComponent($scope.notification.thresholdCount);
  data+= "&timeValue="
  + encodeURIComponent($scope.notification.timeValue);
  data+= "&timeFrame="
  + encodeURIComponent($scope.notification.timeFrame);
  data+= "&enabled="
  + encodeURIComponent($scope.notification.enabled);
  data+= "&notificationDescription="
  + encodeURIComponent($scope.notification.notificationDescription);
  data+= "&notifyEmail="
  + encodeURIComponent(notification.notifyEmail);

  var config = {headers:{
    "Content-type": "application/x-www-form-urlencoded; charset=utf-8"
  }};

  var result = $http.post(servicelocation+"/Notification/UpdateNotification",data,config)
    .success(function(data)
      {
        console.log(data);
        //$scope.configuration = data;
      });

  };
      $scope.testNotifyService = function(){
        console.log("test notfiy");
        servicelocation = "https://" + $location.$$host + "/api/Notification";
        var data = {};
        var config = {headers:{
          "Content-type": "application/x-www-form-urlencoded; charset=utf-8"
          }};

        $http.post(servicelocation+"/PingCluster",data,config)
          .success(function(data)
            {
              console.log(data);
               $scope.searchList=data;
            });
      };

      $scope.testRegister(){

      }

      $scope.testUnregister(){

      }

      //Clear form
      $scope.createNotification= function(){
        $scope.notification.notificationName = "";
        $scope.notification.selectedSearch = {};
        $scope.notification.thresholdType = 'Max';
        $scope.notification.thresholdCount = 0;
        $scope.notification.timeValue = 0;
        $scope.notification.timeFrame = 'm';
        $scope.notification.enabled = false;
        $scope.notification.notificationDescription = "";
        $scope.notification.notifyEmail = "";
      };

    });
<commit_msg>update controller<commit_after>//Responsibilities.
/*
*** Incomplete.

Listing notifications
adding notifications
removing notifications
updating notifications

searches
list searches
retreive search info
create notification from search
*/

  'use strict';

  /**
   * @ngdoc function
   * @name clientApp.controller:ConfigfilesCtrl
   * @description
   * # ConfigfilesCtrl
   * Controller of the clientApp
   */
  angular.module('clientApp')
    .controller('NotificationsCtrl', function ($scope,$http,$location) {
      var selectedSearch=null
        $scope.searchList= [
          {ID:"1",Title:"Search Example",SearchString:"searchstring"},
          {ID:"2",Title:"Another Search",SearchString:"searchstring"},
          {ID:"3",Title:"Another Example",SearchString:"searchstring"},
        ];
        $scope.NotificationList = [
          {NotifyID:"1",SearchID:"1",Threshold:"2",Period:""},//Period in minutes.
          {NotifyID:"2",SearchID:"1",Threshold:"2",Period:""},
          {NotifyID:"3",SearchID:"2",Threshold:"2",Period:""},
          {NotifyID:"4",SearchID:"3",Threshold:"2",Period:""},
        ];
        $scope.notification = {};
        $scope.notification.thresholdType          = "Max";
        $scope.notification.notificationName       = "Notification Name";
        //$scope.selectedSearch         =
        $scope.notification.thresholdCount         = 10;
        $scope.notification.timeValue              = 10;
        $scope.notification.timeFrame              = "m";
        $scope.notification.enabled                = false;
        $scope.notification.notificationDescription= "Notification Description";
        $scope.notification.notifyEmail            = "example@domain.com";

        servicelocation = "https://" + $location.$$host + "/api/Notification";

      //  servicelocation = "https://" + $location.$$host + "/api/";
        var data = {};
        var config = {headers:{
          "Content-type": "application/x-www-form-urlencoded; charset=utf-8"
          }};

          $http.post(servicelocation+"/GetNotifications",data,config)
            .success(function(data)
              {
                console.log(data);
                 $scope.notificationFiles=data;
              });

        $scope.refreshScreen = function()
        {
          servicelocation = "https://" + $location.$$host + "/api/Notification";
          var data = {};
          var config = {headers:{
            "Content-type": "application/x-www-form-urlencoded; charset=utf-8"
            }};
          // $http.post(servicelocation+"/GetNotifications",data,config)
          //   .success(function(data)
          //     {
          //       console.log(data);
          //        $scope.notifications=data;
          //     });

          servicelocation = "https://" + $location.$$host + "/api/Notification";
          var data = {};
          var config = {headers:{
            "Content-type": "application/x-www-form-urlencoded; charset=utf-8"
            }};
          $http.post(servicelocation+"/ListSearches",data,config)
            .success(function(data)
              {
                console.log(data);
                 $scope.avalibleSearches=data;
              });
        }

        $scope.refreshScreen();

        $scope.deleteFile = function(configuration){
          $scope.filelocation = "";
          $scope.conffilename = configuration;

          var retVal = prompt("You must confirm to delete this file enter DELETE in the box below \n\n are you sure you want to continue?", "WARNING");

          if(retVal=="DELETE")
          {
            var data = "conffilename="+ encodeURIComponent(configuration);
            var config = {headers:{
              "Content-type": "application/x-www-form-urlencoded; charset=utf-8"
            }};

            var result = $http.post(servicelocation+"Notification/DeleteNotification",data,config)
              .success(function(data)
                {
                  console.log(data);
                  $scope.configuration = data;
                });
          }
          $scope.refreshScreen();
        }

      $scope.updateTextArea = function(configuration){

        $scope.filelocation = "";
        $scope.filename = configuration;

        var data = "configfile="+ encodeURIComponent(configuration);
        var config = {headers:{
          "Content-type": "application/x-www-form-urlencoded; charset=utf-8"
        }};

        var result = $http.post(servicelocation+"Notification/GetNotification",data,config)
          .success(function(data)
            {
              console.log(data);
              //$scope.configuration = data;
              $scope.notification = data;
            });
      };

$scope.saveNotification = function()
{

  if($scope.notification.notificationName=="")
  {
    alert('you must supply a notification name!');
    return;
  }
  if($scope.notification.selectedSearch=="")
  {
    alert('you must select a search name!');
    return;
  }

  var data = "notificationName="
  + encodeURIComponent($scope.notification.notificationName);
  data+= "&selectedSearch="
  + encodeURIComponent($scope.notification.selectedSearch);
  data+= "&thresholdType="
  + encodeURIComponent($scope.notification.thresholdType);
  data+= "&thresholdCount="
  + encodeURIComponent($scope.notification.thresholdCount);
  data+= "&timeValue="
  + encodeURIComponent($scope.notification.timeValue);
  data+= "&timeFrame="
  + encodeURIComponent($scope.notification.timeFrame);
  data+= "&enabled="
  + encodeURIComponent($scope.notification.enabled);
  data+= "&notificationDescription="
  + encodeURIComponent($scope.notification.notificationDescription);
  data+= "&notifyEmail="
  + encodeURIComponent(notification.notifyEmail);

  var config = {headers:{
    "Content-type": "application/x-www-form-urlencoded; charset=utf-8"
  }};

  var result = $http.post(servicelocation+"/Notification/UpdateNotification",data,config)
    .success(function(data)
      {
        console.log(data);
        //$scope.configuration = data;
      });

  };
      $scope.testNotifyService = function(){
        console.log("test notfiy");
        servicelocation = "https://" + $location.$$host + "/api/Notification";
        var data = {};
        var config = {headers:{
          "Content-type": "application/x-www-form-urlencoded; charset=utf-8"
          }};

        $http.post(servicelocation+"/PingCluster",data,config)
          .success(function(data)
            {
              console.log(data);
               $scope.searchList=data;
            });
      };

      //Clear form
      $scope.createNotification= function(){
        $scope.notification.notificationName = "";
        $scope.notification.selectedSearch = {};
        $scope.notification.thresholdType = 'Max';
        $scope.notification.thresholdCount = 0;
        $scope.notification.timeValue = 0;
        $scope.notification.timeFrame = 'm';
        $scope.notification.enabled = false;
        $scope.notification.notificationDescription = "";
        $scope.notification.notifyEmail = "";
      };

    });
<|endoftext|>