<commit_before>/* ===========================================================
 * bootstrap-modal.js v2.1
 * ===========================================================
 * Copyright 2012 Jordan Schroter
 *
 * 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.
 * ========================================================== */

!function ($) {

	"use strict"; // jshint ;_;

	/* MODAL CLASS DEFINITION
	* ====================== */

	var Modal = function (element, options) {
		this.init(element, options);
	};

	Modal.prototype = {

		constructor: Modal,

		init: function (element, options) {
			this.options = options;

			this.$element = $(element)
				.delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this));

			this.options.remote && this.$element.find('.modal-body').load(this.options.remote);

			var manager = typeof this.options.manager === 'function' ?
				this.options.manager.call(this) : this.options.manager;

			manager = manager.appendModal ?
				manager : $(manager).modalmanager().data('modalmanager');

			manager.appendModal(this);
		},

		toggle: function () {
			return this[!this.isShown ? 'show' : 'hide']();
		},

		show: function () {
			var e = $.Event('show');

			if (this.isShown) return;

			this.$element.trigger(e);

			if (e.isDefaultPrevented()) return;

			this.escape();

			this.tab();

			this.options.loading && this.loading();
		},

		hide: function (e) {
			e && e.preventDefault();

			e = $.Event('hide');

			this.$element.trigger(e);

			if (!this.isShown || e.isDefaultPrevented()) return (this.isShown = false);

			this.isShown = false;

			this.escape();

			this.tab();

			this.isLoading && this.loading();

			$(document).off('focusin.modal');

			this.$element
				.removeClass('in')
				.removeClass('animated')
				.removeClass(this.options.attentionAnimation)
				.removeClass('modal-overflow')
				.attr('aria-hidden', true);

			$.support.transition && this.$element.hasClass('fade') ?
				this.hideWithTransition() :
				this.hideModal();
		},

		layout: function () {
			var prop = this.options.height ? 'height' : 'max-height',
				value = this.options.height || this.options.maxHeight;

			if (this.options.width){
				this.$element.css('width', this.options.width);

				var that = this;
				this.$element.css('margin-left', function () {
					if (/%/ig.test(that.options.width)){
						return -(parseInt(that.options.width) / 2) + '%';
					} else {
						return -($(this).width() / 2) + 'px';
					}
				});
			} else {
				this.$element.css('width', '');
				this.$element.css('margin-left', '');
			}

			this.$element.find('.modal-body')
				.css('overflow', '')
				.css(prop, '');

			if (value){
				this.$element.find('.modal-body')
					.css('overflow', 'auto')
					.css(prop, value);
			}

			var modalOverflow = $(window).height() - 10 < this.$element.height();

			if (modalOverflow || this.options.modalOverflow) {
				this.$element
					.css('margin-top', 0)
					.addClass('modal-overflow');
			} else {
				this.$element
					.css('margin-top', 0 - this.$element.height() / 2)
					.removeClass('modal-overflow');
			}
		},

		tab: function () {
			var that = this;

			if (this.isShown && this.options.consumeTab) {
				this.$element.on('keydown.tabindex.modal', '[data-tabindex]', function (e) {
			    	if (e.keyCode && e.keyCode == 9){
						var elements = [],
							tabindex = Number($(this).data('tabindex'));

						that.$element.find('[data-tabindex]:enabled:not([readonly])').each(function (ev) {
							elements.push(Number($(this).data('tabindex')));
						});
						elements.sort(function(a,b){return a-b});

						var arrayPos = $.inArray(tabindex, elements);
						if (!e.shiftKey){
						 		arrayPos < elements.length-1 ?
									that.$element.find('[data-tabindex='+elements[arrayPos+1]+']').focus() :
									that.$element.find('[data-tabindex='+elements[0]+']').focus();
							} else {
								arrayPos == 0 ?
									that.$element.find('[data-tabindex='+elements[elements.length-1]+']').focus() :
									that.$element.find('[data-tabindex='+elements[arrayPos-1]+']').focus();
							}

						e.preventDefault();
					}
				});
			} else if (!this.isShown) {
				this.$element.off('keydown.tabindex.modal');
			}
		},

		escape: function () {
			var that = this;
			if (this.isShown && this.options.keyboard) {
				if (!this.$element.attr('tabindex')) this.$element.attr('tabindex', -1);

				this.$element.on('keyup.dismiss.modal', function (e) {
					e.which == 27 && that.hide();
				});
			} else if (!this.isShown) {
				this.$element.off('keyup.dismiss.modal')
			}
		},

		hideWithTransition: function () {
			var that = this
				, timeout = setTimeout(function () {
					that.$element.off($.support.transition.end);
					that.hideModal();
				}, 500);

			this.$element.one($.support.transition.end, function () {
				clearTimeout(timeout);
				that.hideModal();
			});
		},

		hideModal: function () {
			var prop = this.options.height ? 'height' : 'max-height';
			var value = this.options.height || this.options.maxHeight;

			if (value){
				this.$element.find('.modal-body')
					.css('overflow', '')
					.css(prop, '');
			}

			this.$element
				.hide()
				.trigger('hidden');
		},

		removeLoading: function () {
			this.$loading.remove();
			this.$loading = null;
			this.isLoading = false;
		},

		loading: function (callback) {
			callback = callback || function () {};

			var animate = this.$element.hasClass('fade') ? 'fade' : '';

			if (!this.isLoading) {
				var doAnimate = $.support.transition && animate;

				this.$loading = $('
')
					.append(this.options.spinner)
					.appendTo(this.$element);

				if (doAnimate) this.$loading[0].offsetWidth; // force reflow

				this.$loading.addClass('in');

				this.isLoading = true;

				doAnimate ?
					this.$loading.one($.support.transition.end, callback) :
					callback();

			} else if (this.isLoading && this.$loading) {
				this.$loading.removeClass('in');

				var that = this;
				$.support.transition && this.$element.hasClass('fade')?
					this.$loading.one($.support.transition.end, function () { that.removeLoading() }) :
					that.removeLoading();

			} else if (callback) {
				callback(this.isLoading);
			}
		},

		focus: function () {
			var $focusElem = this.$element.find(this.options.focusOn);

			$focusElem = $focusElem.length ? $focusElem : this.$element;

			$focusElem.focus();
		},

		attention: function (){
			// NOTE: transitionEnd with keyframes causes odd behaviour

			if (this.options.attentionAnimation){
				this.$element
					.removeClass('animated')
					.removeClass(this.options.attentionAnimation);

				var that = this;

				setTimeout(function () {
					that.$element
						.addClass('animated')
						.addClass(that.options.attentionAnimation);
				}, 0);
			}

			this.focus();
		},

		destroy: function () {
			var e = $.Event('destroy');
			this.$element.trigger(e);
			if (e.isDefaultPrevented()) return;

			this.teardown();
		},

		teardown: function () {
			if (!this.$parent.length){
				this.$element.remove();
				this.$element = null;
				return;
			}

			if (this.$parent !== this.$element.parent()){
				this.$element.appendTo(this.$parent);
			}

			this.$element.off('.modal');
			this.$element.removeData('modal');
			this.$element
				.removeClass('in')
				.attr('aria-hidden', true);
		}
	};

	/* MODAL PLUGIN DEFINITION
	* ======================= */

	$.fn.modal = function (option, args) {
		return this.each(function () {
			var $this = $(this),
				data = $this.data('modal'),
				options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option);

			if (!data) $this.data('modal', (data = new Modal(this, options)));
			if (typeof option == 'string') data[option].apply(data, [].concat(args));
			else if (options.show) data.show()
		})
	};

	$.fn.modal.defaults = {
		keyboard: true,
		backdrop: true,
		loading: false,
		show: true,
		width: null,
		height: null,
		maxHeight: null,
		modalOverflow: false,
		consumeTab: true,
		focusOn: null,
		replace: false,
		resize: false,
		attentionAnimation: 'shake',
		manager: 'body',
		spinner: '

'
	};

	$.fn.modal.Constructor = Modal;

	/* MODAL DATA-API
	* ============== */

	$(function () {
		$(document).off('click.modal').on('click.modal.data-api', '[data-toggle="modal"]', function ( e ) {
			var $this = $(this),
				href = $this.attr('href'),
				$target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))), //strip for ie7
				option = $target.data('modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data());

			e.preventDefault();
			$target
				.modal(option)
				.one('hide', function () {
					$this.focus();
				})
		});
	});

}(window.jQuery);
<commit_msg>add visibility condition<commit_after>/* ===========================================================
 * bootstrap-modal.js v2.1
 * ===========================================================
 * Copyright 2012 Jordan Schroter
 *
 * 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.
 * ========================================================== */

!function ($) {

	"use strict"; // jshint ;_;

	/* MODAL CLASS DEFINITION
	* ====================== */

	var Modal = function (element, options) {
		this.init(element, options);
	};

	Modal.prototype = {

		constructor: Modal,

		init: function (element, options) {
			this.options = options;

			this.$element = $(element)
				.delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this));

			this.options.remote && this.$element.find('.modal-body').load(this.options.remote);

			var manager = typeof this.options.manager === 'function' ?
				this.options.manager.call(this) : this.options.manager;

			manager = manager.appendModal ?
				manager : $(manager).modalmanager().data('modalmanager');

			manager.appendModal(this);
		},

		toggle: function () {
			return this[!this.isShown ? 'show' : 'hide']();
		},

		show: function () {
			var e = $.Event('show');

			if (this.isShown) return;

			this.$element.trigger(e);

			if (e.isDefaultPrevented()) return;

			this.escape();

			this.tab();

			this.options.loading && this.loading();
		},

		hide: function (e) {
			e && e.preventDefault();

			e = $.Event('hide');

			this.$element.trigger(e);

			if (!this.isShown || e.isDefaultPrevented()) return (this.isShown = false);

			this.isShown = false;

			this.escape();

			this.tab();

			this.isLoading && this.loading();

			$(document).off('focusin.modal');

			this.$element
				.removeClass('in')
				.removeClass('animated')
				.removeClass(this.options.attentionAnimation)
				.removeClass('modal-overflow')
				.attr('aria-hidden', true);

			$.support.transition && this.$element.hasClass('fade') ?
				this.hideWithTransition() :
				this.hideModal();
		},

		layout: function () {
			var prop = this.options.height ? 'height' : 'max-height',
				value = this.options.height || this.options.maxHeight;

			if (this.options.width){
				this.$element.css('width', this.options.width);

				var that = this;
				this.$element.css('margin-left', function () {
					if (/%/ig.test(that.options.width)){
						return -(parseInt(that.options.width) / 2) + '%';
					} else {
						return -($(this).width() / 2) + 'px';
					}
				});
			} else {
				this.$element.css('width', '');
				this.$element.css('margin-left', '');
			}

			this.$element.find('.modal-body')
				.css('overflow', '')
				.css(prop, '');

			if (value){
				this.$element.find('.modal-body')
					.css('overflow', 'auto')
					.css(prop, value);
			}

			var modalOverflow = $(window).height() - 10 < this.$element.height();

			if (modalOverflow || this.options.modalOverflow) {
				this.$element
					.css('margin-top', 0)
					.addClass('modal-overflow');
			} else {
				this.$element
					.css('margin-top', 0 - this.$element.height() / 2)
					.removeClass('modal-overflow');
			}
		},

		tab: function () {
			var that = this;

			if (this.isShown && this.options.consumeTab) {
				this.$element.on('keydown.tabindex.modal', '[data-tabindex]', function (e) {
			    	if (e.keyCode && e.keyCode == 9){
						var elements = [],
							tabindex = Number($(this).data('tabindex'));

						that.$element.find('[data-tabindex]:enabled:visible:not([readonly])').each(function (ev) {
							elements.push(Number($(this).data('tabindex')));
						});
						elements.sort(function(a,b){return a-b});

						var arrayPos = $.inArray(tabindex, elements);
						if (!e.shiftKey){
						 		arrayPos < elements.length-1 ?
									that.$element.find('[data-tabindex='+elements[arrayPos+1]+']').focus() :
									that.$element.find('[data-tabindex='+elements[0]+']').focus();
							} else {
								arrayPos == 0 ?
									that.$element.find('[data-tabindex='+elements[elements.length-1]+']').focus() :
									that.$element.find('[data-tabindex='+elements[arrayPos-1]+']').focus();
							}

						e.preventDefault();
					}
				});
			} else if (!this.isShown) {
				this.$element.off('keydown.tabindex.modal');
			}
		},

		escape: function () {
			var that = this;
			if (this.isShown && this.options.keyboard) {
				if (!this.$element.attr('tabindex')) this.$element.attr('tabindex', -1);

				this.$element.on('keyup.dismiss.modal', function (e) {
					e.which == 27 && that.hide();
				});
			} else if (!this.isShown) {
				this.$element.off('keyup.dismiss.modal')
			}
		},

		hideWithTransition: function () {
			var that = this
				, timeout = setTimeout(function () {
					that.$element.off($.support.transition.end);
					that.hideModal();
				}, 500);

			this.$element.one($.support.transition.end, function () {
				clearTimeout(timeout);
				that.hideModal();
			});
		},

		hideModal: function () {
			var prop = this.options.height ? 'height' : 'max-height';
			var value = this.options.height || this.options.maxHeight;

			if (value){
				this.$element.find('.modal-body')
					.css('overflow', '')
					.css(prop, '');
			}

			this.$element
				.hide()
				.trigger('hidden');
		},

		removeLoading: function () {
			this.$loading.remove();
			this.$loading = null;
			this.isLoading = false;
		},

		loading: function (callback) {
			callback = callback || function () {};

			var animate = this.$element.hasClass('fade') ? 'fade' : '';

			if (!this.isLoading) {
				var doAnimate = $.support.transition && animate;

				this.$loading = $('
')
					.append(this.options.spinner)
					.appendTo(this.$element);

				if (doAnimate) this.$loading[0].offsetWidth; // force reflow

				this.$loading.addClass('in');

				this.isLoading = true;

				doAnimate ?
					this.$loading.one($.support.transition.end, callback) :
					callback();

			} else if (this.isLoading && this.$loading) {
				this.$loading.removeClass('in');

				var that = this;
				$.support.transition && this.$element.hasClass('fade')?
					this.$loading.one($.support.transition.end, function () { that.removeLoading() }) :
					that.removeLoading();

			} else if (callback) {
				callback(this.isLoading);
			}
		},

		focus: function () {
			var $focusElem = this.$element.find(this.options.focusOn);

			$focusElem = $focusElem.length ? $focusElem : this.$element;

			$focusElem.focus();
		},

		attention: function (){
			// NOTE: transitionEnd with keyframes causes odd behaviour

			if (this.options.attentionAnimation){
				this.$element
					.removeClass('animated')
					.removeClass(this.options.attentionAnimation);

				var that = this;

				setTimeout(function () {
					that.$element
						.addClass('animated')
						.addClass(that.options.attentionAnimation);
				}, 0);
			}

			this.focus();
		},

		destroy: function () {
			var e = $.Event('destroy');
			this.$element.trigger(e);
			if (e.isDefaultPrevented()) return;

			this.teardown();
		},

		teardown: function () {
			if (!this.$parent.length){
				this.$element.remove();
				this.$element = null;
				return;
			}

			if (this.$parent !== this.$element.parent()){
				this.$element.appendTo(this.$parent);
			}

			this.$element.off('.modal');
			this.$element.removeData('modal');
			this.$element
				.removeClass('in')
				.attr('aria-hidden', true);
		}
	};

	/* MODAL PLUGIN DEFINITION
	* ======================= */

	$.fn.modal = function (option, args) {
		return this.each(function () {
			var $this = $(this),
				data = $this.data('modal'),
				options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option);

			if (!data) $this.data('modal', (data = new Modal(this, options)));
			if (typeof option == 'string') data[option].apply(data, [].concat(args));
			else if (options.show) data.show()
		})
	};

	$.fn.modal.defaults = {
		keyboard: true,
		backdrop: true,
		loading: false,
		show: true,
		width: null,
		height: null,
		maxHeight: null,
		modalOverflow: false,
		consumeTab: true,
		focusOn: null,
		replace: false,
		resize: false,
		attentionAnimation: 'shake',
		manager: 'body',
		spinner: '

'
	};

	$.fn.modal.Constructor = Modal;

	/* MODAL DATA-API
	* ============== */

	$(function () {
		$(document).off('click.modal').on('click.modal.data-api', '[data-toggle="modal"]', function ( e ) {
			var $this = $(this),
				href = $this.attr('href'),
				$target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))), //strip for ie7
				option = $target.data('modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data());

			e.preventDefault();
			$target
				.modal(option)
				.one('hide', function () {
					$this.focus();
				})
		});
	});

}(window.jQuery);
<|endoftext|>


<commit_before>/* ===========================================================
 * bootstrap-modal.js v2.2.4
 * ===========================================================
 * Copyright 2012 Jordan Schroter
 *
 * 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.
 * ========================================================== */

!function ($) {

	"use strict"; // jshint ;_;

	/* MODAL CLASS DEFINITION
	* ====================== */

	var Modal = function (element, options) {
		this.init(element, options);
	};

	Modal.prototype = {

		constructor: Modal,

		init: function (element, options) {
			var that = this;

			this.options = options;

			this.$element = $(element)
				.delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this));

			this.options.remote && this.$element.find('.modal-body').load(this.options.remote, function () {
				var e = $.Event('loaded');
				that.$element.trigger(e);
			});

			var manager = typeof this.options.manager === 'function' ?
				this.options.manager.call(this) : this.options.manager;

			manager = manager.appendModal ?
				manager : $(manager).modalmanager().data('modalmanager');

			manager.appendModal(this);
		},

		toggle: function () {
			return this[!this.isShown ? 'show' : 'hide']();
		},

		show: function () {
			var e = $.Event('show');

			if (this.isShown) return;

			this.$element.trigger(e);

			if (e.isDefaultPrevented()) return;

			this.escape();

			this.tab();

			this.options.loading && this.loading();
		},

		hide: function (e) {
			e && e.preventDefault();

			e = $.Event('hide');

			this.$element.trigger(e);

			if (!this.isShown || e.isDefaultPrevented()) return (this.isShown = false);

			this.isShown = false;

			this.escape();

			this.tab();

			this.isLoading && this.loading();

			$(document).off('focusin.modal');

			this.$element
				.removeClass('in')
				.removeClass('animated')
				.removeClass(this.options.attentionAnimation)
				.removeClass('modal-overflow')
				.attr('aria-hidden', true);

			$.support.transition && this.$element.hasClass('fade') ?
				this.hideWithTransition() :
				this.hideModal();
		},

		layout: function () {
			var prop = this.options.height ? 'height' : 'max-height',
				value = this.options.height || this.options.maxHeight;

			if (this.options.width){
				this.$element.css('width', this.options.width);

				var that = this;
				this.$element.css('margin-left', function () {
					if (/%/ig.test(that.options.width)){
						return -(parseInt(that.options.width) / 2) + '%';
					} else {
						return -($(this).width() / 2) + 'px';
					}
				});
			} else {
				this.$element.css('width', '');
				this.$element.css('margin-left', '');
			}

			this.$element.find('.modal-body')
				.css('overflow', '')
				.css(prop, '');

			if (value){
				this.$element.find('.modal-body')
					.css('overflow', 'auto')
					.css(prop, value);
			}

			var modalOverflow = $(window).height() - 10 < this.$element.height();

			if (modalOverflow || this.options.modalOverflow) {
				this.$element
					.css('margin-top', 0)
					.addClass('modal-overflow');
			} else {
				this.$element
					.css('margin-top', 0 - this.$element.height() / 2)
					.removeClass('modal-overflow');
			}
		},

		tab: function () {
			var that = this;

			if (this.isShown && this.options.consumeTab) {
				this.$element.on('keydown.tabindex.modal', '[data-tabindex]', function (e) {
			    	if (e.keyCode && e.keyCode == 9){
						var $next = $(this),
							$rollover = $(this);

						that.$element.find('[data-tabindex]:enabled:not([readonly])').each(function (e) {
							if (!e.shiftKey){
						 		$next = $next.data('tabindex') < $(this).data('tabindex') ?
									$next = $(this) :
									$rollover = $(this);
							} else {
								$next = $next.data('tabindex') > $(this).data('tabindex') ?
									$next = $(this) :
									$rollover = $(this);
							}
						});

						$next[0] !== $(this)[0] ?
							$next.focus() : $rollover.focus();

						e.preventDefault();
					}
				});
			} else if (!this.isShown) {
				this.$element.off('keydown.tabindex.modal');
			}
		},

		escape: function () {
			var that = this;
			if (this.isShown && this.options.keyboard) {
				if (!this.$element.attr('tabindex')) this.$element.attr('tabindex', -1);

				this.$element.on('keyup.dismiss.modal', function (e) {
					e.which == 27 && that.hide();
				});
			} else if (!this.isShown) {
				this.$element.off('keyup.dismiss.modal')
			}
		},

		hideWithTransition: function () {
			var that = this
				, timeout = setTimeout(function () {
					that.$element.off($.support.transition.end);
					that.hideModal();
				}, 500);

			this.$element.one($.support.transition.end, function () {
				clearTimeout(timeout);
				that.hideModal();
			});
		},

		hideModal: function () {
			var prop = this.options.height ? 'height' : 'max-height';
			var value = this.options.height || this.options.maxHeight;

			if (value){
				this.$element.find('.modal-body')
					.css('overflow', '')
					.css(prop, '');
			}

			this.$element
				.hide()
				.trigger('hidden');
		},

		removeLoading: function () {
			this.$loading.remove();
			this.$loading = null;
			this.isLoading = false;
		},

		loading: function (callback) {
			callback = callback || function () {};

			var animate = this.$element.hasClass('fade') ? 'fade' : '';

			if (!this.isLoading) {
				var doAnimate = $.support.transition && animate;

				this.$loading = $('
')
					.append(this.options.spinner)
					.appendTo(this.$element);

				if (doAnimate) this.$loading[0].offsetWidth; // force reflow

				this.$loading.addClass('in');

				this.isLoading = true;

				doAnimate ?
					this.$loading.one($.support.transition.end, callback) :
					callback();

			} else if (this.isLoading && this.$loading) {
				this.$loading.removeClass('in');

				var that = this;
				$.support.transition && this.$element.hasClass('fade')?
					this.$loading.one($.support.transition.end, function () { that.removeLoading() }) :
					that.removeLoading();

			} else if (callback) {
				callback(this.isLoading);
			}
		},

		focus: function () {
			var $focusElem = this.$element.find(this.options.focusOn);

			$focusElem = $focusElem.length ? $focusElem : this.$element;

			$focusElem.focus();
		},

		attention: function (){
			// NOTE: transitionEnd with keyframes causes odd behaviour

			if (this.options.attentionAnimation){
				this.$element
					.removeClass('animated')
					.removeClass(this.options.attentionAnimation);

				var that = this;

				setTimeout(function () {
					that.$element
						.addClass('animated')
						.addClass(that.options.attentionAnimation);
				}, 0);
			}

			this.focus();
		},

		destroy: function () {
			var e = $.Event('destroy');
			this.$element.trigger(e);
			if (e.isDefaultPrevented()) return;

			this.teardown();
		},

		teardown: function () {
			if (!this.$parent.length){
				this.$element.remove();
				this.$element = null;
				return;
			}

			if (this.$parent !== this.$element.parent()){
				this.$element.appendTo(this.$parent);
			}

			this.$element.off('.modal');
			this.$element.removeData('modal');
			this.$element
				.removeClass('in')
				.attr('aria-hidden', true)
				.trigger('destroyed');
		}
	};

	/* MODAL PLUGIN DEFINITION
	* ======================= */

	$.fn.modal = function (option, args) {
		return this.each(function () {
			var $this = $(this),
				data = $this.data('modal'),
				options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option);

			if (!data) $this.data('modal', (data = new Modal(this, options)));
			if (typeof option == 'string') data[option].apply(data, [].concat(args));
			else if (options.show) data.show()
		})
	};

	$.fn.modal.defaults = {
		keyboard: true,
		backdrop: true,
		loading: false,
		show: true,
		width: null,
		height: null,
		maxHeight: null,
		modalOverflow: false,
		consumeTab: true,
		focusOn: null,
		replace: false,
		resize: false,
		attentionAnimation: 'shake',
		manager: 'body',
		spinner: '

',
		backdropTemplate: '
'
	};

	$.fn.modal.Constructor = Modal;

	/* MODAL DATA-API
	* ============== */

	$(function () {
		$(document).off('click.modal').on('click.modal.data-api', '[data-toggle="modal"]', function ( e ) {
			var $this = $(this),
				href = $this.attr('href'),
				$target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))), //strip for ie7
				option = $target.data('modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data());

			e.preventDefault();
			$target
				.modal(option)
				.one('hide', function () {
					$this.focus();
				})
		});
	});

}(window.jQuery);
<commit_msg>Refactored destory method, make sure destoyed event is always called<commit_after>/* ===========================================================
 * bootstrap-modal.js v2.2.4
 * ===========================================================
 * Copyright 2012 Jordan Schroter
 *
 * 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.
 * ========================================================== */

!function ($) {

	"use strict"; // jshint ;_;

	/* MODAL CLASS DEFINITION
	* ====================== */

	var Modal = function (element, options) {
		this.init(element, options);
	};

	Modal.prototype = {

		constructor: Modal,

		init: function (element, options) {
			var that = this;

			this.options = options;

			this.$element = $(element)
				.delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this));

			this.options.remote && this.$element.find('.modal-body').load(this.options.remote, function () {
				var e = $.Event('loaded');
				that.$element.trigger(e);
			});

			var manager = typeof this.options.manager === 'function' ?
				this.options.manager.call(this) : this.options.manager;

			manager = manager.appendModal ?
				manager : $(manager).modalmanager().data('modalmanager');

			manager.appendModal(this);
		},

		toggle: function () {
			return this[!this.isShown ? 'show' : 'hide']();
		},

		show: function () {
			var e = $.Event('show');

			if (this.isShown) return;

			this.$element.trigger(e);

			if (e.isDefaultPrevented()) return;

			this.escape();

			this.tab();

			this.options.loading && this.loading();
		},

		hide: function (e) {
			e && e.preventDefault();

			e = $.Event('hide');

			this.$element.trigger(e);

			if (!this.isShown || e.isDefaultPrevented()) return (this.isShown = false);

			this.isShown = false;

			this.escape();

			this.tab();

			this.isLoading && this.loading();

			$(document).off('focusin.modal');

			this.$element
				.removeClass('in')
				.removeClass('animated')
				.removeClass(this.options.attentionAnimation)
				.removeClass('modal-overflow')
				.attr('aria-hidden', true);

			$.support.transition && this.$element.hasClass('fade') ?
				this.hideWithTransition() :
				this.hideModal();
		},

		layout: function () {
			var prop = this.options.height ? 'height' : 'max-height',
				value = this.options.height || this.options.maxHeight;

			if (this.options.width){
				this.$element.css('width', this.options.width);

				var that = this;
				this.$element.css('margin-left', function () {
					if (/%/ig.test(that.options.width)){
						return -(parseInt(that.options.width) / 2) + '%';
					} else {
						return -($(this).width() / 2) + 'px';
					}
				});
			} else {
				this.$element.css('width', '');
				this.$element.css('margin-left', '');
			}

			this.$element.find('.modal-body')
				.css('overflow', '')
				.css(prop, '');

			if (value){
				this.$element.find('.modal-body')
					.css('overflow', 'auto')
					.css(prop, value);
			}

			var modalOverflow = $(window).height() - 10 < this.$element.height();

			if (modalOverflow || this.options.modalOverflow) {
				this.$element
					.css('margin-top', 0)
					.addClass('modal-overflow');
			} else {
				this.$element
					.css('margin-top', 0 - this.$element.height() / 2)
					.removeClass('modal-overflow');
			}
		},

		tab: function () {
			var that = this;

			if (this.isShown && this.options.consumeTab) {
				this.$element.on('keydown.tabindex.modal', '[data-tabindex]', function (e) {
			    	if (e.keyCode && e.keyCode == 9){
						var $next = $(this),
							$rollover = $(this);

						that.$element.find('[data-tabindex]:enabled:not([readonly])').each(function (e) {
							if (!e.shiftKey){
						 		$next = $next.data('tabindex') < $(this).data('tabindex') ?
									$next = $(this) :
									$rollover = $(this);
							} else {
								$next = $next.data('tabindex') > $(this).data('tabindex') ?
									$next = $(this) :
									$rollover = $(this);
							}
						});

						$next[0] !== $(this)[0] ?
							$next.focus() : $rollover.focus();

						e.preventDefault();
					}
				});
			} else if (!this.isShown) {
				this.$element.off('keydown.tabindex.modal');
			}
		},

		escape: function () {
			var that = this;
			if (this.isShown && this.options.keyboard) {
				if (!this.$element.attr('tabindex')) this.$element.attr('tabindex', -1);

				this.$element.on('keyup.dismiss.modal', function (e) {
					e.which == 27 && that.hide();
				});
			} else if (!this.isShown) {
				this.$element.off('keyup.dismiss.modal')
			}
		},

		hideWithTransition: function () {
			var that = this
				, timeout = setTimeout(function () {
					that.$element.off($.support.transition.end);
					that.hideModal();
				}, 500);

			this.$element.one($.support.transition.end, function () {
				clearTimeout(timeout);
				that.hideModal();
			});
		},

		hideModal: function () {
			var prop = this.options.height ? 'height' : 'max-height';
			var value = this.options.height || this.options.maxHeight;

			if (value){
				this.$element.find('.modal-body')
					.css('overflow', '')
					.css(prop, '');
			}

			this.$element
				.hide()
				.trigger('hidden');
		},

		removeLoading: function () {
			this.$loading.remove();
			this.$loading = null;
			this.isLoading = false;
		},

		loading: function (callback) {
			callback = callback || function () {};

			var animate = this.$element.hasClass('fade') ? 'fade' : '';

			if (!this.isLoading) {
				var doAnimate = $.support.transition && animate;

				this.$loading = $('
')
					.append(this.options.spinner)
					.appendTo(this.$element);

				if (doAnimate) this.$loading[0].offsetWidth; // force reflow

				this.$loading.addClass('in');

				this.isLoading = true;

				doAnimate ?
					this.$loading.one($.support.transition.end, callback) :
					callback();

			} else if (this.isLoading && this.$loading) {
				this.$loading.removeClass('in');

				var that = this;
				$.support.transition && this.$element.hasClass('fade')?
					this.$loading.one($.support.transition.end, function () { that.removeLoading() }) :
					that.removeLoading();

			} else if (callback) {
				callback(this.isLoading);
			}
		},

		focus: function () {
			var $focusElem = this.$element.find(this.options.focusOn);

			$focusElem = $focusElem.length ? $focusElem : this.$element;

			$focusElem.focus();
		},

		attention: function (){
			// NOTE: transitionEnd with keyframes causes odd behaviour

			if (this.options.attentionAnimation){
				this.$element
					.removeClass('animated')
					.removeClass(this.options.attentionAnimation);

				var that = this;

				setTimeout(function () {
					that.$element
						.addClass('animated')
						.addClass(that.options.attentionAnimation);
				}, 0);
			}

			this.focus();
		},

		destroy: function () {
			var e = $.Event('destroy');

			this.$element.trigger(e);

			if (e.isDefaultPrevented()) return;

			this.$element
				.off('.modal')
				.removeData('modal')
				.removeClass('in')
				.attr('aria-hidden', true);

			if (this.$parent !== this.$element.parent()) {
				this.$element.appendTo(this.$parent);
			} else if (!this.$parent.length) {
				// modal is not part of the DOM so remove it.
				this.$element.remove();
				this.$element = null;
			}

			this.$element.trigger('destroyed');
		}
	};

	/* MODAL PLUGIN DEFINITION
	* ======================= */

	$.fn.modal = function (option, args) {
		return this.each(function () {
			var $this = $(this),
				data = $this.data('modal'),
				options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option);

			if (!data) $this.data('modal', (data = new Modal(this, options)));
			if (typeof option == 'string') data[option].apply(data, [].concat(args));
			else if (options.show) data.show()
		})
	};

	$.fn.modal.defaults = {
		keyboard: true,
		backdrop: true,
		loading: false,
		show: true,
		width: null,
		height: null,
		maxHeight: null,
		modalOverflow: false,
		consumeTab: true,
		focusOn: null,
		replace: false,
		resize: false,
		attentionAnimation: 'shake',
		manager: 'body',
		spinner: '

',
		backdropTemplate: '
'
	};

	$.fn.modal.Constructor = Modal;

	/* MODAL DATA-API
	* ============== */

	$(function () {
		$(document).off('click.modal').on('click.modal.data-api', '[data-toggle="modal"]', function ( e ) {
			var $this = $(this),
				href = $this.attr('href'),
				$target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))), //strip for ie7
				option = $target.data('modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data());

			e.preventDefault();
			$target
				.modal(option)
				.one('hide', function () {
					$this.focus();
				})
		});
	});

}(window.jQuery);
<|endoftext|>


<commit_before>var CharacterFinder = function( canvas, width, height ){

    this.img = document.createElement("img");
    this.img.style.display = 'none';

    document.body.appendChild( this.img );

    this.canvas = canvas;
    //this.canvas.style.display = 'none';
    //document.body.appendChild( this.canvas );

    this.context = canvas.getContext('2d');
    this.width = width;
    this.height = height;
    this.ypos = 185;
    this.contrastLimit = 140;

    this.canvas.width = this.width;
    this.canvas.height = this.height;

    this.onCompleteCallbacks = [];

    this.img.onload = this.onImgload.bind(this);
};

CharacterFinder.prototype.setImg = function( src ){
    this.img.src = src;
};

CharacterFinder.prototype.onImgload = function(){

    var correct = 0;
    var numberShapes = [];
    var resultingNumbers = [];

    this.context.drawImage( this.img, 0, this.img.height - this.ypos, this.width, this.height, 0, 0, this.width, this.height );

    var tracedShapes = this.traceAll( { r: 221, g: 216, b: 136, a: 1 } );

    for(var i = 0, l = tracedShapes.length; i < l; i++ ){
        if( tracedShapes[ i ].length < 90 || tracedShapes[ i ].length > 400 ){
            this.drawPixels( this.context, tracedShapes[ i ], '#000' );
        } else {
            numberShapes.push( tracedShapes[ i ] );
        }
    }

    this.context.drawImage( this.img, 0, this.img.height - this.ypos, this.width, this.height, 0, 0, this.width, this.height );

    for( var i = 0, l = numberShapes.length; i < l; i++ ){

        var boundaries = findBoundaries( numberShapes[ i ] );

        // Compensate bounding box for narrow 1's, since they match too many numbers.
        if( (boundaries.xmax - boundaries.xmin) / ( boundaries.ymax - boundaries.ymin ) < 0.5 ){
            boundaries.xmax += 4;
            boundaries.xmin -= 4;
        }

        if( boundaries.ymin != 0 && boundaries.xmax - boundaries.xmin < 25 ){

            this.drawRect( boundaries.xmin - 2, boundaries.ymin - 2, boundaries.xmax + 2, boundaries.ymax + 2, '#f00' );
            correct++;

            this.drawPixels( numberShapes[ i ], '#0f0' );

            var bestAnswer = null;
            var bestAnswerValue = null;

            for( var j = 0; j < 10; j++ ){

                var sum = 0;

                var curve = getNumberAsNurb( j, boundaries.xmin + 1 , boundaries.ymin + 1, boundaries.xmax - boundaries.xmin - 2, boundaries.ymax - boundaries.ymin - 2 );

                for(var k = 0, len = curve.length; k < len; k++ ){

                    var pixelColor = this.getPixelColor( Math.round(curve[ k ].x), Math.round(curve[ k ].y) );
                    var diff = colorDiff( pixelColor, { r: 0, g: 255, b: 0 } ) / 255;

                    sum += colorDiff( pixelColor, { r: 0, g: 255, b: 0 } ) / 255;
                }

                if( bestAnswer == null || bestAnswerValue > sum ){
                    bestAnswer = j;
                    bestAnswerValue = sum;
                }

            }

            resultingNumbers.push( bestAnswer );

            this.drawPixels( getNumberAsNurb( bestAnswer, boundaries.xmin + 1 , boundaries.ymin + 1, boundaries.xmax - boundaries.xmin - 2, boundaries.ymax - boundaries.ymin - 2 ), '#00f' );
        }
    }

    // Fallback to 0 if we match nothing
    if( resultingNumbers.length === 0 ){
        resultingNumbers = false;
    }

    for( var i = 0, l = this.onCompleteCallbacks.length; i < l; i++){
        if( resultingNumbers ){
            this.onCompleteCallbacks[ i ].bind( this )( this.img.src.split(/\//).pop(), parseInt(resultingNumbers.join('')) );
        } else {
            this.onCompleteCallbacks[ i ].bind( this )( this.img.src.split(/\//).pop(), resultingNumbers );
        }
    }

}

CharacterFinder.prototype.contrast = function(){
    var self = this;

    this.onPixels( function( x, y, r, g, b, a ){
        if( intensity( r, g, b ) < self.contrastLimit ){
            self.drawPixel( x, y, '#000' );
        } else if( intensity( r, g, b ) > self.contrastLimit ){
            self.drawPixel( x, y, '#FFF' );
        }
    });

};

CharacterFinder.prototype.drawPixel = function( x, y, color ){
    this.context.fillStyle = color || '#FFF';
    this.context.fillRect(x,y,1,1);
}

CharacterFinder.prototype.traceAll = function( byColor ){
    var tracedShapes = [];
    var traceIndex = [];
    var value = byColor;

    this.onPixels( ( function( x, y ){
        var tracedShape = this.traceArea( x, y, value, traceIndex, byColor );

        if(tracedShape.length){
            tracedShapes.push( tracedShape );
        }
    }).bind( this ));

    return tracedShapes;

}

CharacterFinder.prototype.traceArea = function ( startx, starty, value, index, byColor ){
    var traceIndex = index || [];
    return this.traceAreaStepColor( startx, starty, value, traceIndex );
}

CharacterFinder.prototype.traceAreaStepColor = function( startx, starty, color, index ){

    var result = [];

    if( colorDiff( color, this.getPixelColor( startx, starty ) ) < 50 && index.indexOf( startx + ',' + starty ) == -1 ){
        index.push( startx + ',' + starty );

        result.push( { x: startx, y: starty } );

        if( index.indexOf( ( startx + 1 ) + ',' + ( starty ) ) == -1 )
            result = result.concat( this.traceAreaStepColor( startx + 1, starty, color, index ) );
        if( index.indexOf( ( startx ) + ',' + ( starty + 1 ) ) == -1 )
            result = result.concat( this.traceAreaStepColor( startx, starty + 1, color, index ) );

        if( index.indexOf( ( startx - 1 ) + ',' + ( starty ) ) == -1 )
            result = result.concat( this.traceAreaStepColor( startx - 1, starty, color, index ) );
        if( index.indexOf( ( startx ) + ',' + ( starty - 1 ) ) == -1 )
            result = result.concat( this.traceAreaStepColor( startx, starty - 1, color, index ) );
    }

    return result;
}

CharacterFinder.prototype.onPixels = function( fn ){
    var data = this.context.getImageData( 0, 0, this.width, this.height ).data;

    for(var x = 0; x < this.width; x++) {
        for(var y = 0; y < this.height; y++) {
            var red = data[((this.width * y) + x) * 4];
            var green = data[((this.width * y) + x) * 4 + 1];
            var blue = data[((this.width * y) + x) * 4 + 2];
            var alpha = data[((this.width * y) + x) * 4 + 3];

            fn( x, y, red, green, blue, alpha );
        }
    }
}

CharacterFinder.prototype.getPixelColor = function( x, y, canvas ){

    canvas = canvas || this.canvas;

    var data = canvas.getContext('2d').getImageData( 0, 0, this.width, this.height ).data;

    return {
        r: data[ ( ( canvas.width * y ) + x ) * 4 ],
        g: data[ ( ( canvas.width * y ) + x ) * 4 + 1 ],
        b: data[ ( ( canvas.width * y ) + x ) * 4 + 2 ],
        a: data[ ( ( canvas.width * y ) + x ) * 4 + 3 ]
    };
}

CharacterFinder.prototype.drawPixel = function( x, y, color ){
    this.context.fillStyle = color || '#FFF';
    this.context.fillRect( x, y, 1, 1 );        }

CharacterFinder.prototype.drawPixels = function( arr, color ){
    for( var i = 0, l = arr.length; i < l; i++ ){
        this.drawPixel( arr[ i ].x, arr[ i ].y, color || '#FFF' );
    }
}

CharacterFinder.prototype.drawRect = function( x1, y1, x2, y2, color ){
    color = color || '#f00';

    this.context.strokeStyle = color;

    this.context.strokeRect( x1, y1, x2 - x1, y2 - y1 );
}

CharacterFinder.prototype.getPixelIntensity = function( x, y ){
    var color = this.getPixelColor( x, y );
    return intensity( color.r, color.g, color.b );
}

CharacterFinder.prototype.diff = function( refcanvas ){
    var sum = 0;
    var num = 0;

    this.onPixels( function( x, y, r, g, b, a ){
        var refcolor = this.getPixelColor( x, y, refcanvas );
        sum += ( intensity( r, g, b ) == intensity( refcolor.r, refcolor.g, refcolor.b ) ) ? 0 : 1;
        //sum += colorDiff( {r:r,g:g,b:b}, refcolor );
        num++;
    });

    return sum;
}

CharacterFinder.prototype.onComplete = function( fn ){
    this.onCompleteCallbacks.push( fn );
}

// Helper functions
function intensity( r, g, b ){
    return Math.sqrt( ( r * r + g * g + b * b ) / 3 );
}

function colorDiff( c1, c2 ){

    return Math.sqrt(
        (
            Math.pow( c1.r - c2.r, 2 ) +
            Math.pow( c1.g - c2.g, 2 ) +
            Math.pow( c1.b - c2.b, 2 )
        ) / 3
    );
}

function findBoundaries( shape ){
    var ret = {
        xmin: shape[0].x,
        xmax: shape[0].x,
        ymin: shape[0].y,
        ymax: shape[0].y
    };

    for(var i = 1, l = shape.length; i < l; i++){
        ret.xmin = Math.min( ret.xmin, shape[i].x );
        ret.xmax = Math.max( ret.xmax, shape[i].x );
        ret.ymin = Math.min( ret.ymin, shape[i].y );
        ret.ymax = Math.max( ret.ymax, shape[i].y );
    }

    return ret;
}

function nurbPlotToXY( arr, sx, sy ){
    var ret = [];
    sx = sx || 0;
    sy = sy || 0;

    for( var i = 0, l = arr.length; i < l; i++ ){
        ret.push({
            x: arr[ i ][ 0 ] + sx,
            y: arr[ i ][ 1 ] + sy
        });
    }

    return ret;
}

function getNumberAsNurb( n, sx, sy, width, height ){

    var interpCurve = getNumCurve( n, width, height );

    return nurbPlotToXY( verb.eval.Tess.rationalCurveRegularSample(interpCurve.asNurbs(), 100, false), sx, sy );

}

function getNumCurve( n, w, h ){

    w = w || 10;
    h = h || 10;

    var numbers = [

        // 0
        [
            [ 3, 0 ],
            [ 9, 5 ],
            [ 7, 10 ],
            [ 1, 5 ],
            [ 4, 0 ]
        ],

        //1
        [
            [ 4, 0 ],
            [ 5, 2.5 ],
            [ 5, 5 ],
            [ 5, 7.5 ],
            [ 5, 10 ]
        ],

        //2
        [
            [ 1, 3.5 ],
            [ 3, 0 ],
            [ 8.5, 1 ],
            [ 6, 6.3 ],
            [ 2.5, 9.5 ],
            [ 3, 9.5 ],
            [ 9, 9.6 ]
        ],

        //3
        [
            [ 1, 0.5 ],
            [ 4, 0.5 ],
            [ 7.7, 0.5 ],
            [ 7.8, 0.5 ],
            [ 5, 4.4 ],
            //[ 5, 4 ],
            [ 6, 4.6],
            [ 9, 6.5 ],
            [ 1, 9.5 ]
        ],

        //4
        [
            [ 10, 7.4 ],
            [ 5, 7.4 ],
            [ 3.5, 7.4 ],
            [ 2, 7.4 ],
            [ 0.6, 7.4 ],
            [ 0.6, 7.0 ],
            [ 7.5, 2 ],
            [ 7.5, 2.5 ],
            [ 7.5, 7.5 ],
            [ 7.5, 10 ]
        ],

        //5
        [
            // [ 1, 0.5 ],
            // [ 4, 0.5 ],
            // [ 7.7, 0.5 ],
            // [ 7.8, 0.5 ],
            [ 9, 0.5 ],
            [ 3.6, 0.7 ],
            [ 3.5, 0.7 ],
            [ 1, 4.2 ],
            [ 1, 4.4 ],
            [ 5, 4.2 ],
            [ 7.2, 4.2],
            [ 9.2, 5.4 ],
            [ 1, 8.5 ]
        ],

        //6
        [
            [ 8, 0 ],
            [ 2, 1 ],
            [ 2, 8 ],
            [ 5, 10 ],
            [ 8.9, 8 ],
            [ 2, 4.5 ]
        ],

        //7
        [
            [ 0, 1 ],
            [1,1],
            [ 5, 1 ],
            [ 9, 1 ],
            [ 9, 2 ],
            [ 6.5, 5 ],
            [ 4, 10 ]
        ],

        //8
        [
            [ 5, -0.5 ],
            [ 0.5, 2.4 ],
            [ 5, 4.5 ],
            [ 9.5, 7.5 ],
            [ 5, 10 ],
            [ 0, 7.3 ],
            [ 5, 4.5 ],
            [ 9.4, 2.4 ],
            [ 5, -0.5 ]
        ],

        //9
        [

            [ 2, 10 ],
            [ 7.5, 9 ],
            [ 8, 2 ],
            [ 3, 0 ],
            [ 0.5, 2 ],
            [ 8, 5.5 ]
        ]

    ];

    var number = [];

    for( var i = 0, l = numbers[ n ].length; i < l; i++ ){
        number.push([ numbers[ n ][ i ][ 0 ] * w / 10, numbers[ n ][ i ][ 1 ] * h / 10 ]);
    }

    return verb.geom.NurbsCurve.byPoints( number, 3 );

}

<commit_msg>Only match boxes that have at least an aspect ratio of 1.1<commit_after>var CharacterFinder = function( canvas, width, height ){

    this.img = document.createElement("img");
    this.img.style.display = 'none';

    document.body.appendChild( this.img );

    this.canvas = canvas;
    //this.canvas.style.display = 'none';
    //document.body.appendChild( this.canvas );

    this.context = canvas.getContext('2d');
    this.width = width;
    this.height = height;
    this.ypos = 185;
    this.contrastLimit = 140;

    this.canvas.width = this.width;
    this.canvas.height = this.height;

    this.onCompleteCallbacks = [];

    this.img.onload = this.onImgload.bind(this);
};

CharacterFinder.prototype.setImg = function( src ){
    this.img.src = src;
};

CharacterFinder.prototype.onImgload = function(){

    var correct = 0;
    var numberShapes = [];
    var resultingNumbers = [];

    this.context.drawImage( this.img, 0, this.img.height - this.ypos, this.width, this.height, 0, 0, this.width, this.height );

    var tracedShapes = this.traceAll( { r: 221, g: 216, b: 136, a: 1 } );

    for(var i = 0, l = tracedShapes.length; i < l; i++ ){
        if( tracedShapes[ i ].length < 90 || tracedShapes[ i ].length > 400 ){
            this.drawPixels( this.context, tracedShapes[ i ], '#000' );
        } else {
            numberShapes.push( tracedShapes[ i ] );
        }
    }

    this.context.drawImage( this.img, 0, this.img.height - this.ypos, this.width, this.height, 0, 0, this.width, this.height );

    for( var i = 0, l = numberShapes.length; i < l; i++ ){

        var boundaries = findBoundaries( numberShapes[ i ] );

        // Compensate bounding box for narrow 1's, since they match too many numbers.
        if( (boundaries.xmax - boundaries.xmin) / ( boundaries.ymax - boundaries.ymin ) < 0.5 ){
            boundaries.xmax += 4;
            boundaries.xmin -= 4;
        }

        if( boundaries.xmax - boundaries.xmin < 25 && ( boundaries.ymax - boundaries.ymin ) / ( boundaries.xmax - boundaries.xmin ) > 1.1 ){

            this.drawRect( boundaries.xmin - 2, boundaries.ymin - 2, boundaries.xmax + 2, boundaries.ymax + 2, '#f00' );
            correct++;

            this.drawPixels( numberShapes[ i ], '#0f0' );

            var bestAnswer = null;
            var bestAnswerValue = null;

            for( var j = 0; j < 10; j++ ){

                var sum = 0;

                var curve = getNumberAsNurb( j, boundaries.xmin + 1 , boundaries.ymin + 1, boundaries.xmax - boundaries.xmin - 2, boundaries.ymax - boundaries.ymin - 2 );

                for(var k = 0, len = curve.length; k < len; k++ ){

                    var pixelColor = this.getPixelColor( Math.round(curve[ k ].x), Math.round(curve[ k ].y) );
                    var diff = colorDiff( pixelColor, { r: 0, g: 255, b: 0 } ) / 255;

                    sum += colorDiff( pixelColor, { r: 0, g: 255, b: 0 } ) / 255;
                }

                if( bestAnswer == null || bestAnswerValue > sum ){
                    bestAnswer = j;
                    bestAnswerValue = sum;
                }

            }

            resultingNumbers.push( bestAnswer );

            this.drawPixels( getNumberAsNurb( bestAnswer, boundaries.xmin + 1 , boundaries.ymin + 1, boundaries.xmax - boundaries.xmin - 2, boundaries.ymax - boundaries.ymin - 2 ), '#00f' );
        }
    }

    // Fallback to 0 if we match nothing
    if( resultingNumbers.length === 0 ){
        resultingNumbers = false;
    }

    for( var i = 0, l = this.onCompleteCallbacks.length; i < l; i++){
        if( resultingNumbers ){
            this.onCompleteCallbacks[ i ].bind( this )( this.img.src.split(/\//).pop(), parseInt(resultingNumbers.join('')) );
        } else {
            this.onCompleteCallbacks[ i ].bind( this )( this.img.src.split(/\//).pop(), resultingNumbers );
        }
    }

}

CharacterFinder.prototype.contrast = function(){
    var self = this;

    this.onPixels( function( x, y, r, g, b, a ){
        if( intensity( r, g, b ) < self.contrastLimit ){
            self.drawPixel( x, y, '#000' );
        } else if( intensity( r, g, b ) > self.contrastLimit ){
            self.drawPixel( x, y, '#FFF' );
        }
    });

};

CharacterFinder.prototype.drawPixel = function( x, y, color ){
    this.context.fillStyle = color || '#FFF';
    this.context.fillRect(x,y,1,1);
}

CharacterFinder.prototype.traceAll = function( byColor ){
    var tracedShapes = [];
    var traceIndex = [];
    var value = byColor;

    this.onPixels( ( function( x, y ){
        var tracedShape = this.traceArea( x, y, value, traceIndex, byColor );

        if(tracedShape.length){
            tracedShapes.push( tracedShape );
        }
    }).bind( this ));

    return tracedShapes;

}

CharacterFinder.prototype.traceArea = function ( startx, starty, value, index, byColor ){
    var traceIndex = index || [];
    return this.traceAreaStepColor( startx, starty, value, traceIndex );
}

CharacterFinder.prototype.traceAreaStepColor = function( startx, starty, color, index ){

    var result = [];

    if( colorDiff( color, this.getPixelColor( startx, starty ) ) < 50 && index.indexOf( startx + ',' + starty ) == -1 ){
        index.push( startx + ',' + starty );

        result.push( { x: startx, y: starty } );

        if( index.indexOf( ( startx + 1 ) + ',' + ( starty ) ) == -1 )
            result = result.concat( this.traceAreaStepColor( startx + 1, starty, color, index ) );
        if( index.indexOf( ( startx ) + ',' + ( starty + 1 ) ) == -1 )
            result = result.concat( this.traceAreaStepColor( startx, starty + 1, color, index ) );

        if( index.indexOf( ( startx - 1 ) + ',' + ( starty ) ) == -1 )
            result = result.concat( this.traceAreaStepColor( startx - 1, starty, color, index ) );
        if( index.indexOf( ( startx ) + ',' + ( starty - 1 ) ) == -1 )
            result = result.concat( this.traceAreaStepColor( startx, starty - 1, color, index ) );
    }

    return result;
}

CharacterFinder.prototype.onPixels = function( fn ){
    var data = this.context.getImageData( 0, 0, this.width, this.height ).data;

    for(var x = 0; x < this.width; x++) {
        for(var y = 0; y < this.height; y++) {
            var red = data[((this.width * y) + x) * 4];
            var green = data[((this.width * y) + x) * 4 + 1];
            var blue = data[((this.width * y) + x) * 4 + 2];
            var alpha = data[((this.width * y) + x) * 4 + 3];

            fn( x, y, red, green, blue, alpha );
        }
    }
}

CharacterFinder.prototype.getPixelColor = function( x, y, canvas ){

    canvas = canvas || this.canvas;

    var data = canvas.getContext('2d').getImageData( 0, 0, this.width, this.height ).data;

    return {
        r: data[ ( ( canvas.width * y ) + x ) * 4 ],
        g: data[ ( ( canvas.width * y ) + x ) * 4 + 1 ],
        b: data[ ( ( canvas.width * y ) + x ) * 4 + 2 ],
        a: data[ ( ( canvas.width * y ) + x ) * 4 + 3 ]
    };
}

CharacterFinder.prototype.drawPixel = function( x, y, color ){
    this.context.fillStyle = color || '#FFF';
    this.context.fillRect( x, y, 1, 1 );        }

CharacterFinder.prototype.drawPixels = function( arr, color ){
    for( var i = 0, l = arr.length; i < l; i++ ){
        this.drawPixel( arr[ i ].x, arr[ i ].y, color || '#FFF' );
    }
}

CharacterFinder.prototype.drawRect = function( x1, y1, x2, y2, color ){
    color = color || '#f00';

    this.context.strokeStyle = color;

    this.context.strokeRect( x1, y1, x2 - x1, y2 - y1 );
}

CharacterFinder.prototype.getPixelIntensity = function( x, y ){
    var color = this.getPixelColor( x, y );
    return intensity( color.r, color.g, color.b );
}

CharacterFinder.prototype.diff = function( refcanvas ){
    var sum = 0;
    var num = 0;

    this.onPixels( function( x, y, r, g, b, a ){
        var refcolor = this.getPixelColor( x, y, refcanvas );
        sum += ( intensity( r, g, b ) == intensity( refcolor.r, refcolor.g, refcolor.b ) ) ? 0 : 1;
        //sum += colorDiff( {r:r,g:g,b:b}, refcolor );
        num++;
    });

    return sum;
}

CharacterFinder.prototype.onComplete = function( fn ){
    this.onCompleteCallbacks.push( fn );
}

// Helper functions
function intensity( r, g, b ){
    return Math.sqrt( ( r * r + g * g + b * b ) / 3 );
}

function colorDiff( c1, c2 ){

    return Math.sqrt(
        (
            Math.pow( c1.r - c2.r, 2 ) +
            Math.pow( c1.g - c2.g, 2 ) +
            Math.pow( c1.b - c2.b, 2 )
        ) / 3
    );
}

function findBoundaries( shape ){
    var ret = {
        xmin: shape[0].x,
        xmax: shape[0].x,
        ymin: shape[0].y,
        ymax: shape[0].y
    };

    for(var i = 1, l = shape.length; i < l; i++){
        ret.xmin = Math.min( ret.xmin, shape[i].x );
        ret.xmax = Math.max( ret.xmax, shape[i].x );
        ret.ymin = Math.min( ret.ymin, shape[i].y );
        ret.ymax = Math.max( ret.ymax, shape[i].y );
    }

    return ret;
}

function nurbPlotToXY( arr, sx, sy ){
    var ret = [];
    sx = sx || 0;
    sy = sy || 0;

    for( var i = 0, l = arr.length; i < l; i++ ){
        ret.push({
            x: arr[ i ][ 0 ] + sx,
            y: arr[ i ][ 1 ] + sy
        });
    }

    return ret;
}

function getNumberAsNurb( n, sx, sy, width, height ){

    var interpCurve = getNumCurve( n, width, height );

    return nurbPlotToXY( verb.eval.Tess.rationalCurveRegularSample(interpCurve.asNurbs(), 100, false), sx, sy );

}

function getNumCurve( n, w, h ){

    w = w || 10;
    h = h || 10;

    var numbers = [

        // 0
        [
            [ 3, 0 ],
            [ 9, 5 ],
            [ 7, 10 ],
            [ 1, 5 ],
            [ 4, 0 ]
        ],

        //1
        [
            [ 4, 0 ],
            [ 5, 2.5 ],
            [ 5, 5 ],
            [ 5, 7.5 ],
            [ 5, 10 ]
        ],

        //2
        [
            [ 1, 3.5 ],
            [ 3, 0 ],
            [ 8.5, 1 ],
            [ 6, 6.3 ],
            [ 2.5, 9.5 ],
            [ 3, 9.5 ],
            [ 9, 9.6 ]
        ],

        //3
        [
            [ 1, 0.5 ],
            [ 4, 0.5 ],
            [ 7.7, 0.5 ],
            [ 7.8, 0.5 ],
            [ 5, 4.4 ],
            //[ 5, 4 ],
            [ 6, 4.6],
            [ 9, 6.5 ],
            [ 1, 9.5 ]
        ],

        //4
        [
            [ 10, 7.4 ],
            [ 5, 7.4 ],
            [ 3.5, 7.4 ],
            [ 2, 7.4 ],
            [ 0.6, 7.4 ],
            [ 0.6, 7.0 ],
            [ 7.5, 2 ],
            [ 7.5, 2.5 ],
            [ 7.5, 7.5 ],
            [ 7.5, 10 ]
        ],

        //5
        [
            // [ 1, 0.5 ],
            // [ 4, 0.5 ],
            // [ 7.7, 0.5 ],
            // [ 7.8, 0.5 ],
            [ 9, 0.5 ],
            [ 3.6, 0.7 ],
            [ 3.5, 0.7 ],
            [ 1, 4.2 ],
            [ 1, 4.4 ],
            [ 5, 4.2 ],
            [ 7.2, 4.2],
            [ 9.2, 5.4 ],
            [ 1, 8.5 ]
        ],

        //6
        [
            [ 8, 0 ],
            [ 2, 1 ],
            [ 2, 8 ],
            [ 5, 10 ],
            [ 8.9, 8 ],
            [ 2, 4.5 ]
        ],

        //7
        [
            [ 0, 1 ],
            [1,1],
            [ 5, 1 ],
            [ 9, 1 ],
            [ 9, 2 ],
            [ 6.5, 5 ],
            [ 4, 10 ]
        ],

        //8
        [
            [ 5, -0.5 ],
            [ 0.5, 2.4 ],
            [ 5, 4.5 ],
            [ 9.5, 7.5 ],
            [ 5, 10 ],
            [ 0, 7.3 ],
            [ 5, 4.5 ],
            [ 9.4, 2.4 ],
            [ 5, -0.5 ]
        ],

        //9
        [

            [ 2, 10 ],
            [ 7.5, 9 ],
            [ 8, 2 ],
            [ 3, 0 ],
            [ 0.5, 2 ],
            [ 8, 5.5 ]
        ]

    ];

    var number = [];

    for( var i = 0, l = numbers[ n ].length; i < l; i++ ){
        number.push([ numbers[ n ][ i ][ 0 ] * w / 10, numbers[ n ][ i ][ 1 ] * h / 10 ]);
    }

    return verb.geom.NurbsCurve.byPoints( number, 3 );

}

<|endoftext|>


<commit_before>// Dynamically set the css background images for all the sprites
import React from "react";
import { createPortal } from "react-dom";
import { connect } from "react-redux";

import { LETTERS } from "../constants";
import { imageSelectors, cursorSelectors } from "../skinSelectors";

const CSS_PREFIX = "#webamp";

const mapRegionNamesToIds = {
  normal: "mainWindowClipPath",
  windowshade: "shadeMainWindowClipPath",
  equalizer: "equalizerWindowClipPath",
  equalizerws: "shadeEqualizerWindowClipPath"
};

const mapRegionNamesToMatcher = {
  normal: "#main-window:not(.shade)",
  windowshade: "#main-window.shade",
  equalizer: "#equalizer-window:not(.shade)",
  equalizerws: "#equalizer-window.shade"
};

const numExIsUsed = skinImages => !!skinImages.DIGIT_0_EX;

class Css extends React.Component {
  componentWillMount() {
    const style = document.createElement("style");
    style.type = "text/css";
    style.id = "webamp-skin";
    document.head.appendChild(style);
    this.style = style;
  }

  componentWillUnmount() {
    this.style.remove();
    this.style = null;
  }

  render() {
    return createPortal(this.props.children, this.style);
  }
}

class ClipPaths extends React.Component {
  componentWillMount() {
    const paths = document.createElement("div");
    document.body.appendChild(paths);
    this.paths = paths;
  }

  componentWillUnmount() {
    this.paths.remove();
    this.paths = null;
  }

  render() {
    // this.props.children should be an object containing arrays of strings. The
    // keys are ids, and the arrays are arrays of polygon point strings
    const { children } = this.props;

    return createPortal(
      <svg height={0} width={0}>
        <defs>
          {Object.keys(children).map(id => (
            <clipPath id={id} key={id}>
              {children[id].map((points, i) => (
                <polygon points={points} key={i} />
              ))}
            </clipPath>
          ))}
        </defs>
      </svg>,
      this.paths
    );
  }
}

const Skin = props => {
  const { skinImages, skinCursors, skinGenLetterWidths } = props;
  if (!skinImages || !skinCursors) {
    return null;
  }
  const cssRules = [];
  Object.keys(imageSelectors).forEach(imageName => {
    const imageUrl = skinImages[imageName];
    if (imageUrl) {
      imageSelectors[imageName].forEach(selector => {
        cssRules.push(
          `${CSS_PREFIX} ${selector} {background-image: url(${imageUrl})}`
        );
      });
    }
  });

  if (skinGenLetterWidths != null) {
    LETTERS.forEach(letter => {
      const width = skinGenLetterWidths[`GEN_TEXT_${letter}`];
      const selectedWidth = skinGenLetterWidths[`GEN_TEXT_SELECTED_${letter}`];
      cssRules.push(
        `${CSS_PREFIX} .gen-text-${letter.toLowerCase()} {width: ${width}px;}`
      );
      cssRules.push(
        `${CSS_PREFIX} .selected .gen-text-${letter.toLowerCase()} {width: ${selectedWidth}px;}`
      );
    });
  }
  Object.keys(cursorSelectors).forEach(cursorName => {
    const cursorUrl = skinCursors[cursorName];
    if (cursorUrl) {
      cursorSelectors[cursorName].forEach(selector => {
        cssRules.push(
          `${CSS_PREFIX} ${selector} {cursor: url(${cursorUrl}), auto}`
        );
      });
    }
  });

  if (numExIsUsed(skinImages)) {
    // This alternate number file requires that the minus sign be
    // formatted differently.
    cssRules.push(
      `${CSS_PREFIX} .status #time #minus-sign { top: 0px; left: -1px; width: 9px; height: 13px; }`
    );
  }

  const clipPaths = {};
  for (const [regionName, polygons] of Object.entries(props.skinRegion)) {
    if (polygons) {
      const matcher = mapRegionNamesToMatcher[regionName];
      const id = mapRegionNamesToIds[regionName];
      clipPaths[id] = polygons;
      cssRules.push(`${CSS_PREFIX} ${matcher} { clip-path: url(#${id}); }`);
    }
  }
  return (

      <Css>{cssRules.join("\n")}</Css>
      <ClipPaths>{clipPaths}</ClipPaths>

  );
};

export default connect(state => ({
  skinImages: state.display.skinImages,
  skinCursors: state.display.skinCursors,
  skinRegion: state.display.skinRegion,
  skinGenLetterWidths: state.display.skinGenLetterWidths
}))(Skin);
<commit_msg>Use the volume slider if no balance exists<commit_after>// Dynamically set the css background images for all the sprites
import React from "react";
import { createPortal } from "react-dom";
import { connect } from "react-redux";

import { LETTERS } from "../constants";
import { imageSelectors, cursorSelectors } from "../skinSelectors";

const CSS_PREFIX = "#webamp";

const mapRegionNamesToIds = {
  normal: "mainWindowClipPath",
  windowshade: "shadeMainWindowClipPath",
  equalizer: "equalizerWindowClipPath",
  equalizerws: "shadeEqualizerWindowClipPath"
};

const mapRegionNamesToMatcher = {
  normal: "#main-window:not(.shade)",
  windowshade: "#main-window.shade",
  equalizer: "#equalizer-window:not(.shade)",
  equalizerws: "#equalizer-window.shade"
};

const numExIsUsed = skinImages => !!skinImages.DIGIT_0_EX;

class Css extends React.Component {
  componentWillMount() {
    const style = document.createElement("style");
    style.type = "text/css";
    style.id = "webamp-skin";
    document.head.appendChild(style);
    this.style = style;
  }

  componentWillUnmount() {
    this.style.remove();
    this.style = null;
  }

  render() {
    return createPortal(this.props.children, this.style);
  }
}

class ClipPaths extends React.Component {
  componentWillMount() {
    const paths = document.createElement("div");
    document.body.appendChild(paths);
    this.paths = paths;
  }

  componentWillUnmount() {
    this.paths.remove();
    this.paths = null;
  }

  render() {
    // this.props.children should be an object containing arrays of strings. The
    // keys are ids, and the arrays are arrays of polygon point strings
    const { children } = this.props;

    return createPortal(
      <svg height={0} width={0}>
        <defs>
          {Object.keys(children).map(id => (
            <clipPath id={id} key={id}>
              {children[id].map((points, i) => (
                <polygon points={points} key={i} />
              ))}
            </clipPath>
          ))}
        </defs>
      </svg>,
      this.paths
    );
  }
}

const FALLBACKS = {
  MAIN_BALANCE_BACKGROUND: "MAIN_VOLUME_BACKGROUND",
  MAIN_BALANCE_THUMB: "MAIN_VOLUME_THUMB",
  MAIN_BALANCE_THUMB_ACTIVE: "MAIN_VOLUME_THUMB_SELECTED"
};

const Skin = props => {
  const { skinImages, skinCursors, skinGenLetterWidths } = props;
  if (!skinImages || !skinCursors) {
    return null;
  }
  const cssRules = [];
  Object.keys(imageSelectors).forEach(imageName => {
    const imageUrl = skinImages[imageName] || skinImages[FALLBACKS[imageName]];
    if (imageUrl) {
      imageSelectors[imageName].forEach(selector => {
        cssRules.push(
          `${CSS_PREFIX} ${selector} {background-image: url(${imageUrl})}`
        );
      });
    }
  });

  if (skinGenLetterWidths != null) {
    LETTERS.forEach(letter => {
      const width = skinGenLetterWidths[`GEN_TEXT_${letter}`];
      const selectedWidth = skinGenLetterWidths[`GEN_TEXT_SELECTED_${letter}`];
      cssRules.push(
        `${CSS_PREFIX} .gen-text-${letter.toLowerCase()} {width: ${width}px;}`
      );
      cssRules.push(
        `${CSS_PREFIX} .selected .gen-text-${letter.toLowerCase()} {width: ${selectedWidth}px;}`
      );
    });
  }
  Object.keys(cursorSelectors).forEach(cursorName => {
    const cursorUrl = skinCursors[cursorName];
    if (cursorUrl) {
      cursorSelectors[cursorName].forEach(selector => {
        cssRules.push(
          `${CSS_PREFIX} ${selector} {cursor: url(${cursorUrl}), auto}`
        );
      });
    }
  });

  if (numExIsUsed(skinImages)) {
    // This alternate number file requires that the minus sign be
    // formatted differently.
    cssRules.push(
      `${CSS_PREFIX} .status #time #minus-sign { top: 0px; left: -1px; width: 9px; height: 13px; }`
    );
  }

  const clipPaths = {};
  for (const [regionName, polygons] of Object.entries(props.skinRegion)) {
    if (polygons) {
      const matcher = mapRegionNamesToMatcher[regionName];
      const id = mapRegionNamesToIds[regionName];
      clipPaths[id] = polygons;
      cssRules.push(`${CSS_PREFIX} ${matcher} { clip-path: url(#${id}); }`);
    }
  }
  return (

      <Css>{cssRules.join("\n")}</Css>
      <ClipPaths>{clipPaths}</ClipPaths>

  );
};

export default connect(state => ({
  skinImages: state.display.skinImages,
  skinCursors: state.display.skinCursors,
  skinRegion: state.display.skinRegion,
  skinGenLetterWidths: state.display.skinGenLetterWidths
}))(Skin);
<|endoftext|>


<commit_before>// Dynamically set the css background images for all the sprites
import React from "react";
import { connect } from "react-redux";

import { FONT_LOOKUP, imageConstFromChar } from "../skinSprites";

const imageSelectors = {
  MAIN_BALANCE_BACKGROUND: ["#balance"],
  MAIN_BALANCE_THUMB: [
    "#balance::-webkit-slider-thumb",
    "#balance::-moz-range-thumb"
  ],
  MAIN_BALANCE_THUMB_ACTIVE: [
    "#balance::-webkit-slider-thumb:active",
    "#balance::-moz-range-thumb:active"
  ],
  MAIN_PREVIOUS_BUTTON: [".actions #previous"],
  MAIN_PREVIOUS_BUTTON_ACTIVE: [".actions #previous:active"],
  MAIN_PLAY_BUTTON: [".actions #play"],
  MAIN_PLAY_BUTTON_ACTIVE: [".actions #play:active"],
  MAIN_PAUSE_BUTTON: [".actions #pause"],
  MAIN_PAUSE_BUTTON_ACTIVE: [".actions #pause:active"],
  MAIN_STOP_BUTTON: [".actions #stop"],
  MAIN_STOP_BUTTON_ACTIVE: [".actions #stop:active"],
  MAIN_NEXT_BUTTON: [".actions #next"],
  MAIN_NEXT_BUTTON_ACTIVE: [".actions #next:active"],
  MAIN_EJECT_BUTTON: ["#eject"],
  MAIN_EJECT_BUTTON_ACTIVE: ["#eject:active"],
  MAIN_WINDOW_BACKGROUND: ["#main-window"],
  MAIN_STEREO: [".media-info #stereo", ".stop .media-info #stereo.selected"],
  MAIN_STEREO_SELECTED: [".media-info #stereo.selected"],
  MAIN_MONO: [".media-info #mono", ".stop .media-info #mono.selected"],
  MAIN_MONO_SELECTED: [".media-info #mono.selected"],
  NO_MINUS_SIGN: ["#time #minus-sign"],
  MINUS_SIGN: ["#time.countdown #minus-sign"],
  DIGIT_0: [".digit-0"],
  DIGIT_1: [".digit-1"],
  DIGIT_2: [".digit-2"],
  DIGIT_3: [".digit-3"],
  DIGIT_4: [".digit-4"],
  DIGIT_5: [".digit-5"],
  DIGIT_6: [".digit-6"],
  DIGIT_7: [".digit-7"],
  DIGIT_8: [".digit-8"],
  DIGIT_9: [".digit-9"],
  NO_MINUS_SIGN_EX: ["#time #minus-sign"],
  MINUS_SIGN_EX: ["#time.countdown #minus-sign"],
  DIGIT_0_EX: [".digit-0"],
  DIGIT_1_EX: [".digit-1"],
  DIGIT_2_EX: [".digit-2"],
  DIGIT_3_EX: [".digit-3"],
  DIGIT_4_EX: [".digit-4"],
  DIGIT_5_EX: [".digit-5"],
  DIGIT_6_EX: [".digit-6"],
  DIGIT_7_EX: [".digit-7"],
  DIGIT_8_EX: [".digit-8"],
  DIGIT_9_EX: [".digit-9"],
  MAIN_PLAYING_INDICATOR: [".play #play-pause"],
  MAIN_PAUSED_INDICATOR: [".pause #play-pause"],
  MAIN_STOPPED_INDICATOR: [".stop #play-pause"],
  MAIN_NOT_WORKING_INDICATOR: [".play #work-indicator"],
  MAIN_WORKING_INDICATOR: [".play #work-indicator.selected"],
  PLAYLIST_TOP_TILE: [".playlist-top"],
  PLAYLIST_TOP_LEFT_CORNER: [".playlist-top-left"],
  PLAYLIST_TITLE_BAR: [".playlist-top-title"],
  PLAYLIST_TOP_RIGHT_CORNER: [".playlist-top-right"],
  PLAYLIST_TOP_TILE_SELECTED: [".selected .playlist-top"],
  PLAYLIST_TOP_LEFT_SELECTED: [".selected .playlist-top-left"],
  PLAYLIST_TITLE_BAR_SELECTED: [".selected .playlist-top-title"],
  PLAYLIST_TOP_RIGHT_CORNER_SELECTED: [".selected .playlist-top-right"],
  PLAYLIST_LEFT_TILE: [".playlist-left"],
  PLAYLIST_RIGHT_TILE: [".playlist-right"],
  PLAYLIST_BOTTOM_TILE: [".playlist-bottom"],
  PLAYLIST_BOTTOM_LEFT_CORNER: [".playlist-bottom-left"],
  PLAYLIST_BOTTOM_RIGHT_CORNER: [".playlist-bottom-right"],
  PLAYLIST_VISUALIZER_BACKGROUND: [".playlist-visualizer"],
  PLAYLIST_SHADE_BACKGROUND: ["#playlist.shade"],
  EQ_WINDOW_BACKGROUND: ["#equalizer-window:not(.shade)"],
  EQ_TITLE_BAR: [".equalizer-top"],
  EQ_TITLE_BAR_SELECTED: [".selected .equalizer-top"],
  EQ_SLIDER_BACKGROUND: [".band"],
  EQ_SLIDER_THUMB: [".band .rc-slider-handle"],
  EQ_SLIDER_THUMB_SELECTED: [".band .rc-slider-handle:active"],
  EQ_ON_BUTTON: ["#on"],
  EQ_ON_BUTTON_DEPRESSED: ["#on:active"],
  EQ_ON_BUTTON_SELECTED: ["#on.selected"],
  EQ_ON_BUTTON_SELECTED_DEPRESSED: ["#on.selected:active"],
  EQ_AUTO_BUTTON: ["#auto"],
  EQ_AUTO_BUTTON_DEPRESSED: ["#auto:active"],
  EQ_AUTO_BUTTON_SELECTED: ["#auto.selected"],
  EQ_AUTO_BUTTON_SELECTED_DEPRESSED: ["#auto.selected:active"],
  EQ_GRAPH_BACKGROUND: ["#eqGraph"],
  EQ_PRESETS_BUTTON: ["#presets"],
  EQ_PRESETS_BUTTON_SELECTED: ["#presets:active"],
  EQ_PREAMP_LINE: ["#preamp-line"],
  EQ_SHADE_BACKGROUND: ["#equalizer-window.shade"],
  EQ_SHADE_BACKGROUND_SELECTED: ["#equalizer-window.shade.selected"],
  EQ_SHADE_VOLUME_SLIDER_LEFT: [
    "#equalizer-volume.left::-webkit-slider-thumb",
    "#equalizer-volume.left::-moz-range-thumb"
  ],
  EQ_SHADE_VOLUME_SLIDER_CENTER: [
    "#equalizer-volume.center::-webkit-slider-thumb",
    "#equalizer-volume.center::-moz-range-thumb"
  ],
  EQ_SHADE_VOLUME_SLIDER_RIGHT: [
    "#equalizer-volume.right::-webkit-slider-thumb",
    "#equalizer-volume.right::-moz-range-thumb"
  ],
  EQ_SHADE_BALANCE_SLIDER_LEFT: [
    "#equalizer-balance.left::-webkit-slider-thumb",
    "#equalizer-balance.left::-moz-range-thumb"
  ],
  EQ_SHADE_BALANCE_SLIDER_CENTER: [
    "#equalizer-balance.center::-webkit-slider-thumb",
    "#equalizer-balance.center::-moz-range-thumb"
  ],
  EQ_SHADE_BALANCE_SLIDER_RIGHT: [
    "#equalizer-balance.right::-webkit-slider-thumb",
    "#equalizer-balance.right::-moz-range-thumb"
  ],
  EQ_MAXIMIZE_BUTTON_ACTIVE: ["#equalizer-shade:active"],
  EQ_MINIMIZE_BUTTON_ACTIVE: [
    "#equalizer-window.shade #equalizer-shade:active"
  ],
  EQ_CLOSE_BUTTON: ["#equalizer-window.selected #equalizer-close"],
  EQ_CLOSE_BUTTON_ACTIVE: ["#equalizer-window #equalizer-close:active"],
  MAIN_POSITION_SLIDER_BACKGROUND: ["#position"],
  MAIN_POSITION_SLIDER_THUMB: [
    "#position::-webkit-slider-thumb",
    "#position::-moz-range-thumb"
  ],
  MAIN_POSITION_SLIDER_THUMB_SELECTED: [
    "#position:active::-webkit-slider-thumb",
    "#position:active::-moz-range-thumb"
  ],
  MAIN_SHUFFLE_BUTTON: ["#shuffle"],
  MAIN_SHUFFLE_BUTTON_DEPRESSED: ["#shuffle:active"],
  MAIN_SHUFFLE_BUTTON_SELECTED: ["#shuffle.selected"],
  MAIN_SHUFFLE_BUTTON_SELECTED_DEPRESSED: ["#shuffle.selected:active"],
  MAIN_REPEAT_BUTTON: ["#repeat"],
  MAIN_REPEAT_BUTTON_DEPRESSED: ["#repeat:active"],
  MAIN_REPEAT_BUTTON_SELECTED: ["#repeat.selected"],
  MAIN_REPEAT_BUTTON_SELECTED_DEPRESSED: ["#repeat.selected:active"],
  MAIN_EQ_BUTTON: ["#equalizer-button"],
  MAIN_EQ_BUTTON_SELECTED: ["#equalizer-button.selected"],
  MAIN_EQ_BUTTON_DEPRESSED: ["#equalizer-button:active"],
  MAIN_EQ_BUTTON_DEPRESSED_SELECTED: ["#equalizer-button.selected:active"],
  MAIN_PLAYLIST_BUTTON: ["#playlist-button"],
  MAIN_PLAYLIST_BUTTON_SELECTED: ["#playlist-button.selected"],
  MAIN_PLAYLIST_BUTTON_DEPRESSED: ["#playlist-button:active"],
  MAIN_PLAYLIST_BUTTON_DEPRESSED_SELECTED: ["#playlist-button.selected:active"],
  MAIN_TITLE_BAR: ["#title-bar"],
  MAIN_TITLE_BAR_SELECTED: [".selected #title-bar"],
  MAIN_EASTER_EGG_TITLE_BAR: [".llama #title-bar"],
  MAIN_EASTER_EGG_TITLE_BAR_SELECTED: [".llama.selected #title-bar"],
  MAIN_OPTIONS_BUTTON: ["#title-bar #option"],
  MAIN_OPTIONS_BUTTON_DEPRESSED: [
    "#title-bar #option:active",
    "#title-bar #option:selected"
  ],
  MAIN_MINIMIZE_BUTTON: ["#title-bar #minimize"],
  MAIN_MINIMIZE_BUTTON_DEPRESSED: ["#title-bar #minimize:active"],
  MAIN_SHADE_BUTTON: ["#title-bar #shade"],
  MAIN_SHADE_BUTTON_DEPRESSED: ["#title-bar #shade:active"],
  MAIN_CLOSE_BUTTON: ["#title-bar #close"],
  MAIN_CLOSE_BUTTON_DEPRESSED: ["#title-bar #close:active"],
  MAIN_CLUTTER_BAR_BACKGROUND: ["#clutter-bar"],
  MAIN_CLUTTER_BAR_BACKGROUND_DISABLED: ["#clutter-bar.disabled"],
  MAIN_CLUTTER_BAR_BUTTON_O_SELECTED: [
    "#button-o:active",
    "#button-0:selected"
  ],
  MAIN_CLUTTER_BAR_BUTTON_A_SELECTED: [
    "#button-a:active",
    "#button-a.selected"
  ],
  MAIN_CLUTTER_BAR_BUTTON_I_SELECTED: [
    "#button-i:active",
    "#button-i.selected"
  ],
  MAIN_CLUTTER_BAR_BUTTON_D_SELECTED: [
    "#button-d:active",
    "#button-d.selected"
  ],
  MAIN_CLUTTER_BAR_BUTTON_V_SELECTED: [
    "#button-v:active",
    "#button-v.selected"
  ],
  MAIN_SHADE_BACKGROUND: [".shade #title-bar"],
  MAIN_SHADE_BACKGROUND_SELECTED: [".shade.selected #title-bar"],
  MAIN_SHADE_BUTTON_SELECTED: [".shade #title-bar #shade"],
  MAIN_SHADE_BUTTON_SELECTED_DEPRESSED: [".shade #title-bar #shade:active"],
  MAIN_SHADE_POSITION_BACKGROUND: [".shade #position"],
  MAIN_SHADE_POSITION_THUMB: [
    ".shade #position::-moz-range-thumb",
    ".shade #position::-webkit-slider-thumb"
  ],
  MAIN_SHADE_POSITION_THUMB_LEFT: [
    ".shade #position.left::-moz-range-thumb",
    ".shade #position.left::-webkit-slider-thumb"
  ],
  MAIN_SHADE_POSITION_THUMB_RIGHT: [
    ".shade #position.right::-moz-range-thumb",
    ".shade #position.right::-webkit-slider-thumb"
  ],
  MAIN_VOLUME_BACKGROUND: ["#volume"],
  MAIN_VOLUME_THUMB: [
    "#volume::-webkit-slider-thumb",
    "#volume::-moz-range-thumb"
  ],
  MAIN_VOLUME_THUMB_SELECTED: [
    "#volume::-webkit-slider-thumb:active",
    "#volume::-moz-range-thumb:active"
  ]
};

Object.keys(FONT_LOOKUP).forEach(character => {
  const key = imageConstFromChar(character);
  const code = character.charCodeAt(0);
  imageSelectors[key] = [`.character-${code}`];
});

const numExIsUsed = skinImages => !!skinImages.DIGIT_0_EX;

const Skin = props => {
  if (!props.skinImages) {
    return null;
  }
  const cssRules = [];
  Object.keys(imageSelectors).map(imageName => {
    const imageUrl = props.skinImages[imageName];
    if (imageUrl) {
      imageSelectors[imageName].forEach(selector => {
        cssRules.push(
          `#winamp2-js ${selector} {background-image: url(${imageUrl})}`
        );
      });
    }
  });
  if (numExIsUsed(props.skinImages)) {
    // This alternate number file requires that the minus sign be
    // formatted differently.
    cssRules.push(
      "#winamp2-js .status #time #minus-sign { top: 0px; left: -1px; width: 9px; height: 13px; }"
    );
  }
  return <style type="text/css">{cssRules.join("\n")}</style>;
};

export default connect(state => ({ skinImages: state.display.skinImages }))(
  Skin
);
<commit_msg>Use dimmed top buttons when main window not focused.<commit_after>// Dynamically set the css background images for all the sprites
import React from "react";
import { connect } from "react-redux";

import { FONT_LOOKUP, imageConstFromChar } from "../skinSprites";

const imageSelectors = {
  MAIN_BALANCE_BACKGROUND: ["#balance"],
  MAIN_BALANCE_THUMB: [
    "#balance::-webkit-slider-thumb",
    "#balance::-moz-range-thumb"
  ],
  MAIN_BALANCE_THUMB_ACTIVE: [
    "#balance::-webkit-slider-thumb:active",
    "#balance::-moz-range-thumb:active"
  ],
  MAIN_PREVIOUS_BUTTON: [".actions #previous"],
  MAIN_PREVIOUS_BUTTON_ACTIVE: [".actions #previous:active"],
  MAIN_PLAY_BUTTON: [".actions #play"],
  MAIN_PLAY_BUTTON_ACTIVE: [".actions #play:active"],
  MAIN_PAUSE_BUTTON: [".actions #pause"],
  MAIN_PAUSE_BUTTON_ACTIVE: [".actions #pause:active"],
  MAIN_STOP_BUTTON: [".actions #stop"],
  MAIN_STOP_BUTTON_ACTIVE: [".actions #stop:active"],
  MAIN_NEXT_BUTTON: [".actions #next"],
  MAIN_NEXT_BUTTON_ACTIVE: [".actions #next:active"],
  MAIN_EJECT_BUTTON: ["#eject"],
  MAIN_EJECT_BUTTON_ACTIVE: ["#eject:active"],
  MAIN_WINDOW_BACKGROUND: ["#main-window"],
  MAIN_STEREO: [".media-info #stereo", ".stop .media-info #stereo.selected"],
  MAIN_STEREO_SELECTED: [".media-info #stereo.selected"],
  MAIN_MONO: [".media-info #mono", ".stop .media-info #mono.selected"],
  MAIN_MONO_SELECTED: [".media-info #mono.selected"],
  NO_MINUS_SIGN: ["#time #minus-sign"],
  MINUS_SIGN: ["#time.countdown #minus-sign"],
  DIGIT_0: [".digit-0"],
  DIGIT_1: [".digit-1"],
  DIGIT_2: [".digit-2"],
  DIGIT_3: [".digit-3"],
  DIGIT_4: [".digit-4"],
  DIGIT_5: [".digit-5"],
  DIGIT_6: [".digit-6"],
  DIGIT_7: [".digit-7"],
  DIGIT_8: [".digit-8"],
  DIGIT_9: [".digit-9"],
  NO_MINUS_SIGN_EX: ["#time #minus-sign"],
  MINUS_SIGN_EX: ["#time.countdown #minus-sign"],
  DIGIT_0_EX: [".digit-0"],
  DIGIT_1_EX: [".digit-1"],
  DIGIT_2_EX: [".digit-2"],
  DIGIT_3_EX: [".digit-3"],
  DIGIT_4_EX: [".digit-4"],
  DIGIT_5_EX: [".digit-5"],
  DIGIT_6_EX: [".digit-6"],
  DIGIT_7_EX: [".digit-7"],
  DIGIT_8_EX: [".digit-8"],
  DIGIT_9_EX: [".digit-9"],
  MAIN_PLAYING_INDICATOR: [".play #play-pause"],
  MAIN_PAUSED_INDICATOR: [".pause #play-pause"],
  MAIN_STOPPED_INDICATOR: [".stop #play-pause"],
  MAIN_NOT_WORKING_INDICATOR: [".play #work-indicator"],
  MAIN_WORKING_INDICATOR: [".play #work-indicator.selected"],
  PLAYLIST_TOP_TILE: [".playlist-top"],
  PLAYLIST_TOP_LEFT_CORNER: [".playlist-top-left"],
  PLAYLIST_TITLE_BAR: [".playlist-top-title"],
  PLAYLIST_TOP_RIGHT_CORNER: [".playlist-top-right"],
  PLAYLIST_TOP_TILE_SELECTED: [".selected .playlist-top"],
  PLAYLIST_TOP_LEFT_SELECTED: [".selected .playlist-top-left"],
  PLAYLIST_TITLE_BAR_SELECTED: [".selected .playlist-top-title"],
  PLAYLIST_TOP_RIGHT_CORNER_SELECTED: [".selected .playlist-top-right"],
  PLAYLIST_LEFT_TILE: [".playlist-left"],
  PLAYLIST_RIGHT_TILE: [".playlist-right"],
  PLAYLIST_BOTTOM_TILE: [".playlist-bottom"],
  PLAYLIST_BOTTOM_LEFT_CORNER: [".playlist-bottom-left"],
  PLAYLIST_BOTTOM_RIGHT_CORNER: [".playlist-bottom-right"],
  PLAYLIST_VISUALIZER_BACKGROUND: [".playlist-visualizer"],
  PLAYLIST_SHADE_BACKGROUND: ["#playlist.shade"],
  EQ_WINDOW_BACKGROUND: ["#equalizer-window:not(.shade)"],
  EQ_TITLE_BAR: [".equalizer-top"],
  EQ_TITLE_BAR_SELECTED: [".selected .equalizer-top"],
  EQ_SLIDER_BACKGROUND: [".band"],
  EQ_SLIDER_THUMB: [".band .rc-slider-handle"],
  EQ_SLIDER_THUMB_SELECTED: [".band .rc-slider-handle:active"],
  EQ_ON_BUTTON: ["#on"],
  EQ_ON_BUTTON_DEPRESSED: ["#on:active"],
  EQ_ON_BUTTON_SELECTED: ["#on.selected"],
  EQ_ON_BUTTON_SELECTED_DEPRESSED: ["#on.selected:active"],
  EQ_AUTO_BUTTON: ["#auto"],
  EQ_AUTO_BUTTON_DEPRESSED: ["#auto:active"],
  EQ_AUTO_BUTTON_SELECTED: ["#auto.selected"],
  EQ_AUTO_BUTTON_SELECTED_DEPRESSED: ["#auto.selected:active"],
  EQ_GRAPH_BACKGROUND: ["#eqGraph"],
  EQ_PRESETS_BUTTON: ["#presets"],
  EQ_PRESETS_BUTTON_SELECTED: ["#presets:active"],
  EQ_PREAMP_LINE: ["#preamp-line"],
  EQ_SHADE_BACKGROUND: ["#equalizer-window.shade"],
  EQ_SHADE_BACKGROUND_SELECTED: ["#equalizer-window.shade.selected"],
  EQ_SHADE_VOLUME_SLIDER_LEFT: [
    "#equalizer-volume.left::-webkit-slider-thumb",
    "#equalizer-volume.left::-moz-range-thumb"
  ],
  EQ_SHADE_VOLUME_SLIDER_CENTER: [
    "#equalizer-volume.center::-webkit-slider-thumb",
    "#equalizer-volume.center::-moz-range-thumb"
  ],
  EQ_SHADE_VOLUME_SLIDER_RIGHT: [
    "#equalizer-volume.right::-webkit-slider-thumb",
    "#equalizer-volume.right::-moz-range-thumb"
  ],
  EQ_SHADE_BALANCE_SLIDER_LEFT: [
    "#equalizer-balance.left::-webkit-slider-thumb",
    "#equalizer-balance.left::-moz-range-thumb"
  ],
  EQ_SHADE_BALANCE_SLIDER_CENTER: [
    "#equalizer-balance.center::-webkit-slider-thumb",
    "#equalizer-balance.center::-moz-range-thumb"
  ],
  EQ_SHADE_BALANCE_SLIDER_RIGHT: [
    "#equalizer-balance.right::-webkit-slider-thumb",
    "#equalizer-balance.right::-moz-range-thumb"
  ],
  EQ_MAXIMIZE_BUTTON_ACTIVE: ["#equalizer-shade:active"],
  EQ_MINIMIZE_BUTTON_ACTIVE: [
    "#equalizer-window.shade #equalizer-shade:active"
  ],
  EQ_CLOSE_BUTTON: ["#equalizer-window.selected #equalizer-close"],
  EQ_CLOSE_BUTTON_ACTIVE: ["#equalizer-window #equalizer-close:active"],
  MAIN_POSITION_SLIDER_BACKGROUND: ["#position"],
  MAIN_POSITION_SLIDER_THUMB: [
    "#position::-webkit-slider-thumb",
    "#position::-moz-range-thumb"
  ],
  MAIN_POSITION_SLIDER_THUMB_SELECTED: [
    "#position:active::-webkit-slider-thumb",
    "#position:active::-moz-range-thumb"
  ],
  MAIN_SHUFFLE_BUTTON: ["#shuffle"],
  MAIN_SHUFFLE_BUTTON_DEPRESSED: ["#shuffle:active"],
  MAIN_SHUFFLE_BUTTON_SELECTED: ["#shuffle.selected"],
  MAIN_SHUFFLE_BUTTON_SELECTED_DEPRESSED: ["#shuffle.selected:active"],
  MAIN_REPEAT_BUTTON: ["#repeat"],
  MAIN_REPEAT_BUTTON_DEPRESSED: ["#repeat:active"],
  MAIN_REPEAT_BUTTON_SELECTED: ["#repeat.selected"],
  MAIN_REPEAT_BUTTON_SELECTED_DEPRESSED: ["#repeat.selected:active"],
  MAIN_EQ_BUTTON: ["#equalizer-button"],
  MAIN_EQ_BUTTON_SELECTED: ["#equalizer-button.selected"],
  MAIN_EQ_BUTTON_DEPRESSED: ["#equalizer-button:active"],
  MAIN_EQ_BUTTON_DEPRESSED_SELECTED: ["#equalizer-button.selected:active"],
  MAIN_PLAYLIST_BUTTON: ["#playlist-button"],
  MAIN_PLAYLIST_BUTTON_SELECTED: ["#playlist-button.selected"],
  MAIN_PLAYLIST_BUTTON_DEPRESSED: ["#playlist-button:active"],
  MAIN_PLAYLIST_BUTTON_DEPRESSED_SELECTED: ["#playlist-button.selected:active"],
  MAIN_TITLE_BAR: ["#title-bar"],
  MAIN_TITLE_BAR_SELECTED: [".selected #title-bar"],
  MAIN_EASTER_EGG_TITLE_BAR: [".llama #title-bar"],
  MAIN_EASTER_EGG_TITLE_BAR_SELECTED: [".llama.selected #title-bar"],
  MAIN_OPTIONS_BUTTON: ["#title-bar #option"],
  MAIN_OPTIONS_BUTTON_DEPRESSED: [
    "#title-bar #option:active",
    "#title-bar #option:selected"
  ],
  MAIN_MINIMIZE_BUTTON: [".selected #title-bar #minimize"],
  MAIN_MINIMIZE_BUTTON_DEPRESSED: ["#title-bar #minimize:active"],
  MAIN_SHADE_BUTTON: [".selected #title-bar #shade"],
  MAIN_SHADE_BUTTON_DEPRESSED: ["#title-bar #shade:active"],
  MAIN_CLOSE_BUTTON: [".selected #title-bar #close"],
  MAIN_CLOSE_BUTTON_DEPRESSED: ["#title-bar #close:active"],
  MAIN_CLUTTER_BAR_BACKGROUND: ["#clutter-bar"],
  MAIN_CLUTTER_BAR_BACKGROUND_DISABLED: ["#clutter-bar.disabled"],
  MAIN_CLUTTER_BAR_BUTTON_O_SELECTED: [
    "#button-o:active",
    "#button-0:selected"
  ],
  MAIN_CLUTTER_BAR_BUTTON_A_SELECTED: [
    "#button-a:active",
    "#button-a.selected"
  ],
  MAIN_CLUTTER_BAR_BUTTON_I_SELECTED: [
    "#button-i:active",
    "#button-i.selected"
  ],
  MAIN_CLUTTER_BAR_BUTTON_D_SELECTED: [
    "#button-d:active",
    "#button-d.selected"
  ],
  MAIN_CLUTTER_BAR_BUTTON_V_SELECTED: [
    "#button-v:active",
    "#button-v.selected"
  ],
  MAIN_SHADE_BACKGROUND: [".shade #title-bar"],
  MAIN_SHADE_BACKGROUND_SELECTED: [".shade.selected #title-bar"],
  MAIN_SHADE_BUTTON_SELECTED: [".shade.selected #title-bar #shade"],
  MAIN_SHADE_BUTTON_SELECTED_DEPRESSED: [".shade #title-bar #shade:active"],
  MAIN_SHADE_POSITION_BACKGROUND: [".shade #position"],
  MAIN_SHADE_POSITION_THUMB: [
    ".shade #position::-moz-range-thumb",
    ".shade #position::-webkit-slider-thumb"
  ],
  MAIN_SHADE_POSITION_THUMB_LEFT: [
    ".shade #position.left::-moz-range-thumb",
    ".shade #position.left::-webkit-slider-thumb"
  ],
  MAIN_SHADE_POSITION_THUMB_RIGHT: [
    ".shade #position.right::-moz-range-thumb",
    ".shade #position.right::-webkit-slider-thumb"
  ],
  MAIN_VOLUME_BACKGROUND: ["#volume"],
  MAIN_VOLUME_THUMB: [
    "#volume::-webkit-slider-thumb",
    "#volume::-moz-range-thumb"
  ],
  MAIN_VOLUME_THUMB_SELECTED: [
    "#volume::-webkit-slider-thumb:active",
    "#volume::-moz-range-thumb:active"
  ]
};

Object.keys(FONT_LOOKUP).forEach(character => {
  const key = imageConstFromChar(character);
  const code = character.charCodeAt(0);
  imageSelectors[key] = [`.character-${code}`];
});

const numExIsUsed = skinImages => !!skinImages.DIGIT_0_EX;

const Skin = props => {
  if (!props.skinImages) {
    return null;
  }
  const cssRules = [];
  Object.keys(imageSelectors).map(imageName => {
    const imageUrl = props.skinImages[imageName];
    if (imageUrl) {
      imageSelectors[imageName].forEach(selector => {
        cssRules.push(
          `#winamp2-js ${selector} {background-image: url(${imageUrl})}`
        );
      });
    }
  });
  if (numExIsUsed(props.skinImages)) {
    // This alternate number file requires that the minus sign be
    // formatted differently.
    cssRules.push(
      "#winamp2-js .status #time #minus-sign { top: 0px; left: -1px; width: 9px; height: 13px; }"
    );
  }
  return <style type="text/css">{cssRules.join("\n")}</style>;
};

export default connect(state => ({ skinImages: state.display.skinImages }))(
  Skin
);
<|endoftext|>


<commit_before>import Config from '../constants/Config';
import authenticationStore from '../stores/AuthenticationStore';

const Buffer = require('buffer').Buffer;

const requestLocation = `${Config.SERVER}${Config.API_PATH}`;

export default class DataLoader {
  static _getQueryParametersString(queryParameters) {
    let queryParametersString;
    queryParametersString = queryParameters[0];
    for (let i = 1; i < queryParameters.length; i++) {
      queryParametersString += `,${queryParameters[i]}`;
    }
    return queryParametersString;
  }

  static _getParametersString(parameters) {
    let parametersString;
    parametersString = `?${parameters[0]}`;
    for (let i = 1; i < parameters.length; i++) {
      parametersString += `&${parameters[i]}`;
    }
    return parametersString;
  }

  static _createAuthorizationHash() {
    const userLoggedIn = authenticationStore.isLoggedIn();
    if (!userLoggedIn) {
      return null;
    }

    const authenticatedUser = authenticationStore.getUserCredential();
    const userId = authenticatedUser.userId;
    const secret = authenticatedUser.secret;
    const hash = new Buffer(`${userId}:${secret}`).toString('base64');
    return hash;
  }

  static _createHeaders(requestMethod) {
    const authorizationHash = DataLoader._createAuthorizationHash();

    if (requestMethod === 'GET') {
      return { Authorization: `Basic ${authorizationHash}` };
    } else if (requestMethod === 'POST' || requestMethod === 'PUT') {
      return {
        Authorization: `Basic ${authorizationHash}`,
        Accept: 'application/json',
        'Content-Type': 'application/json',
      };
    }

    return null;
  }

  static createRequestUrl(apiUrl, queryParameters, parameters) {
    let requestUrl = requestLocation;

    if (!apiUrl.startsWith('/')) requestUrl += '/';
    requestUrl = requestUrl + apiUrl;

    if (queryParameters !== null && queryParameters.length !== 0 && queryParameters[0] !== null) {
      if (!requestUrl.endsWith('/')) requestUrl += '/';
      requestUrl += DataLoader._getQueryParametersString(queryParameters);
    }

    if (parameters !== null && parameters.length !== 0 && parameters[0] !== null) {
      requestUrl += DataLoader._getParametersString(parameters);
    }

    return requestUrl;
  }

  static makeGetRequest(requestUrl, authorized, onSuccess, onError) {
    let authorizationHeader = {};
    if (authorized === true) {
      authorizationHeader = this._createHeaders('GET');
    }

    fetch(requestUrl, { headers: authorizationHeader })
      .then((response) => response.json())
      .then((responseData) => responseData)
      .then((data) => onSuccess(data))
      .catch((error) => {
        if (onError != null) {
          onError(error);
        } else {
          console.log(`url: ${requestUrl}, error: ${error}`);
        }
      })
      .done();
  }

  static _makePutOrPostRequest(requestUrl, jsonBody, onSuccess, onError, requestMethod) {
    if (requestMethod !== 'PUT' || requestMethod !== 'POST') {
      throw new Error('Request method needs to be of type \'PUT\' or \'POST\'.');
    }

    const headers = this._createHeaders(requestMethod);

    fetch(requestUrl, {
      headers,
      requestMethod,
      body: jsonBody,
    })
      .then((response) => response.json())
      .then((responseData) => responseData)
      .then((data) => onSuccess(data))
      .catch((error) => {
        if (onError != null) {
          onError(error);
        } else {
          console.log(error);
        }
      })
      .done();
  }

  static makePostRequest(requestUrl, jsonBody, onSuccess, onError) {
    const requestMethod = 'POST';
    DataLoader._makePutOrPostRequest(requestUrl, jsonBody, onSuccess, onError, requestMethod);
  }

  static makePutRequest(requestUrl, jsonBody, onSuccess, onError) {
    const requestMethod = 'PUT';
    DataLoader._makePutOrPostRequest(requestUrl, jsonBody, onSuccess, onError, requestMethod);
  }
}
<commit_msg>fix if condition<commit_after>import Config from '../constants/Config';
import authenticationStore from '../stores/AuthenticationStore';

const Buffer = require('buffer').Buffer;

const requestLocation = `${Config.SERVER}${Config.API_PATH}`;

export default class DataLoader {
  static _getQueryParametersString(queryParameters) {
    let queryParametersString;
    queryParametersString = queryParameters[0];
    for (let i = 1; i < queryParameters.length; i++) {
      queryParametersString += `,${queryParameters[i]}`;
    }
    return queryParametersString;
  }

  static _getParametersString(parameters) {
    let parametersString;
    parametersString = `?${parameters[0]}`;
    for (let i = 1; i < parameters.length; i++) {
      parametersString += `&${parameters[i]}`;
    }
    return parametersString;
  }

  static _createAuthorizationHash() {
    const userLoggedIn = authenticationStore.isLoggedIn();
    if (!userLoggedIn) {
      return null;
    }

    const authenticatedUser = authenticationStore.getUserCredential();
    const userId = authenticatedUser.userId;
    const secret = authenticatedUser.secret;
    const hash = new Buffer(`${userId}:${secret}`).toString('base64');
    return hash;
  }

  static _createHeaders(requestMethod) {
    const authorizationHash = DataLoader._createAuthorizationHash();

    if (requestMethod === 'GET') {
      return { Authorization: `Basic ${authorizationHash}` };
    } else if (requestMethod === 'POST' || requestMethod === 'PUT') {
      return {
        Authorization: `Basic ${authorizationHash}`,
        Accept: 'application/json',
        'Content-Type': 'application/json',
      };
    }

    return null;
  }

  static createRequestUrl(apiUrl, queryParameters, parameters) {
    let requestUrl = requestLocation;

    if (!apiUrl.startsWith('/')) requestUrl += '/';
    requestUrl = requestUrl + apiUrl;

    if (queryParameters !== null && queryParameters.length !== 0 && queryParameters[0] !== null) {
      if (!requestUrl.endsWith('/')) requestUrl += '/';
      requestUrl += DataLoader._getQueryParametersString(queryParameters);
    }

    if (parameters !== null && parameters.length !== 0 && parameters[0] !== null) {
      requestUrl += DataLoader._getParametersString(parameters);
    }

    return requestUrl;
  }

  static makeGetRequest(requestUrl, authorized, onSuccess, onError) {
    let authorizationHeader = {};
    if (authorized === true) {
      authorizationHeader = this._createHeaders('GET');
    }

    fetch(requestUrl, { headers: authorizationHeader })
      .then((response) => response.json())
      .then((responseData) => responseData)
      .then((data) => onSuccess(data))
      .catch((error) => {
        if (onError != null) {
          onError(error);
        } else {
          console.log(`url: ${requestUrl}, error: ${error}`);
        }
      })
      .done();
  }

  static _makePutOrPostRequest(requestUrl, jsonBody, onSuccess, onError, requestMethod) {
    if (requestMethod !== 'PUT' && requestMethod !== 'POST') {
      throw new Error('Request method needs to be of type \'PUT\' or \'POST\'.');
    }

    const headers = this._createHeaders(requestMethod);
    console.log('POST MISSION', 'requestUrl', requestUrl);
    fetch(requestUrl, {
      headers,
      method: requestMethod,
      body: jsonBody,
    })
      .then((response) => response.json())
      .then((responseData) => responseData)
      .then((data) => onSuccess(data))
      .catch((error) => {
        if (onError != null) {
          onError(error);
        } else {
          console.log(error);
        }
      })
      .done();
  }

  static makePostRequest(requestUrl, jsonBody, onSuccess, onError) {
    const requestMethod = 'POST';
    DataLoader._makePutOrPostRequest(requestUrl, jsonBody, onSuccess, onError, requestMethod);
  }

  static makePutRequest(requestUrl, jsonBody, onSuccess, onError) {
    const requestMethod = 'PUT';
    DataLoader._makePutOrPostRequest(requestUrl, jsonBody, onSuccess, onError, requestMethod);
  }
}
<|endoftext|>