PageSourceSearch

https://burlingtonbooks.es/wp-content/plugins/b2b/user-registratio…/front/js/afreg_color_spectrum.js?ver=1.0

js burlingtonbooks.es collected 2026-10-01 23:48:58 UTC 63,959 bytes, 2,332 lines download raw bytes

vendor: 26,050 bytes, lines 1-964
1// Spectrum Colorpicker v1.8.0
2// https://github.com/bgrins/spectrum
3// Author: Brian Grinstead
4// License: MIT
5
6(function (factory) {
7	"use strict";
8
9	if (typeof define === 'function' && define.amd) { // AMD
10		define(['jquery'], factory);
11	} else if (typeof exports == "object" && typeof module == "object") { // CommonJS
12		module.exports = factory(require('jquery'));
13	} else { // Browser
14		factory(jQuery);
15	}
16})(function ($, undefined) {
17	"use strict";
18
19	var defaultOpts = {
20
21		// Callbacks
22		beforeShow: noop,
23		move: noop,
24		change: noop,
25		show: noop,
26		hide: noop,
27
28		// Options
29		color: false,
30		flat: false,
31		showInput: false,
32		allowEmpty: false,
33		showButtons: true,
34		clickoutFiresChange: true,
35		showInitial: false,
36		showPalette: false,
37		showPaletteOnly: false,
38		hideAfterPaletteSelect: false,
39		togglePaletteOnly: false,
40		showSelectionPalette: true,
41		localStorageKey: false,
42		appendTo: "body",
43		maxSelectionSize: 7,
44		cancelText: "cancel",
45		chooseText: "choose",
46		togglePaletteMoreText: "more",
47		togglePaletteLessText: "less",
48		clearText: "Clear Color Selection",
49		noColorSelectedText: "No Color Selected",
50		preferredFormat: false,
51		className: "", // Deprecated - use containerClassName and replacerClassName instead.
52		containerClassName: "",
53		replacerClassName: "",
54		showAlpha: false,
55		theme: "sp-light",
56		palette: [["#ffffff", "#000000", "#ff0000", "#ff8000", "#ffff00", "#008000", "#0000ff", "#4b0082", "#9400d3"]],
57		selectionPalette: [],
58		disabled: false,
59		offset: null
60	},
61		spectrums = [],
62		IE = !!/msie/i.exec(window.navigator.userAgent),
63		rgbaSupport = (function () {
64			function contains(str, substr) {
65				return !!~('' + str).indexOf(substr);
66			}
67
68			var elem = document.createElement('div');
69			var style = elem.style;
70			style.cssText = 'background-color:rgba(0,0,0,.5)';
71			return contains(style.backgroundColor, 'rgba') || contains(style.backgroundColor, 'hsla');
72		})(),
73		replaceInput = [
74			"<div class='sp-replacer'>",
75			"<div class='sp-preview'><div class='sp-preview-inner'></div></div>",
76			"<div class='sp-dd'>&#9660;</div>",
77			"</div>"
78		].join(''),
79		markup = (function () {
80
81			// IE does not support gradients with multiple stops, so we need to simulate
82			//  that for the rainbow slider with 8 divs that each have a single gradient
83			var gradientFix = "";
84			if (IE) {
85				for (var i = 1; i <= 6; i++) {
86					gradientFix += "<div class='sp-" + i + "'></div>";
87				}
88			}
89
90			return [
91				"<div class='sp-container sp-hidden'>",
92				"<div class='sp-palette-container'>",
93				"<div class='sp-palette sp-thumb sp-cf'></div>",
94				"<div class='sp-palette-button-container sp-cf'>",
95				"<button type='button' class='sp-palette-toggle'></button>",
96				"</div>",
97				"</div>",
98				"<div class='sp-picker-container'>",
99				"<div class='sp-top sp-cf'>",
100				"<div class='sp-fill'></div>",
101				"<div class='sp-top-inner'>",
102				"<div class='sp-color'>",
103				"<div class='sp-sat'>",
104				"<div class='sp-val'>",
105				"<div class='sp-dragger'></div>",
106				"</div>",
107				"</div>",
108				"</div>",
109				"<div class='sp-clear sp-clear-display'>",
110				"</div>",
111				"<div class='sp-hue'>",
112				"<div class='sp-slider'></div>",
113				gradientFix,
114				"</div>",
115				"</div>",
116				"<div class='sp-alpha'><div class='sp-alpha-inner'><div class='sp-alpha-handle'></div></div></div>",
117				"</div>",
118				"<div class='sp-input-container sp-cf'>",
119				"<input class='sp-input' type='text' spellcheck='false'  />",
120				"</div>",
121				"<div class='sp-initial sp-thumb sp-cf'></div>",
122				"<div class='sp-button-container sp-cf'>",
123				"<a class='sp-cancel' href='#'></a>",
124				"<button type='button' class='sp-choose'></button>",
125				"</div>",
126				"</div>",
127				"</div>"
128			].join("");
129		})();
130
131	function paletteTemplate(p, color, className, opts) {
132		var html = [];
133		for (var i = 0; i < p.length; i++) {
134			var current = p[i];
135			if (current) {
136				var tiny = tinycolor(current);
137				var c = tiny.toHsl().l < 0.5 ? "sp-thumb-el sp-thumb-dark" : "sp-thumb-el sp-thumb-light";
138				c += (tinycolor.equals(color, current)) ? " sp-thumb-active" : "";
139				var formattedString = tiny.toString(opts.preferredFormat || "rgb");
140				var swatchStyle = rgbaSupport ? ("background-color:" + tiny.toRgbString()) : "filter:" + tiny.toFilter();
141				html.push('<span title="' + formattedString + '" data-color="' + tiny.toRgbString() + '" class="' + c + '"><span class="sp-thumb-inner" style="' + swatchStyle + ';" /></span>');
142			} else {
143				var cls = 'sp-clear-display';
144				html.push($('<div />')
145					.append($('<span data-color="" style="background-color:transparent;" class="' + cls + '"></span>')
146						.attr('title', opts.noColorSelectedText)
147					)
148					.html()
149				);
150			}
151		}
152		return "<div class='sp-cf " + className + "'>" + html.join('') + "</div>";
153	}
154
155	function hideAll() {
156		for (var i = 0; i < spectrums.length; i++) {
157			if (spectrums[i]) {
158				spectrums[i].hide();
159			}
160		}
161	}
162
163	function instanceOptions(o, callbackContext) {
164		var opts = $.extend({}, defaultOpts, o);
165		opts.callbacks = {
166			'move': bind(opts.move, callbackContext),
167			'change': bind(opts.change, callbackContext),
168			'show': bind(opts.show, callbackContext),
169			'hide': bind(opts.hide, callbackContext),
170			'beforeShow': bind(opts.beforeShow, callbackContext)
171		};
172
173		return opts;
174	}
175
176	function spectrum(element, o) {
177
178		var opts = instanceOptions(o, element),
179			flat = opts.flat,
180			showSelectionPalette = opts.showSelectionPalette,
181			localStorageKey = opts.localStorageKey,
182			theme = opts.theme,
183			callbacks = opts.callbacks,
184			resize = throttle(reflow, 10),
185			visible = false,
186			isDragging = false,
187			dragWidth = 0,
188			dragHeight = 0,
189			dragHelperHeight = 0,
190			slideHeight = 0,
191			slideWidth = 0,
192			alphaWidth = 0,
193			alphaSlideHelperWidth = 0,
194			slideHelperHeight = 0,
195			currentHue = 0,
196			currentSaturation = 0,
197			currentValue = 0,
198			currentAlpha = 1,
199			palette = [],
200			paletteArray = [],
201			paletteLookup = {},
202			selectionPalette = opts.selectionPalette.slice(0),
203			maxSelectionSize = opts.maxSelectionSize,
204			draggingClass = "sp-dragging",
205			shiftMovementDirection = null;
206
207		var doc = element.ownerDocument,
208			body = doc.body,
209			boundElement = $(element),
210			disabled = false,
211			container = $(markup, doc).addClass(theme),
212			pickerContainer = container.find(".sp-picker-container"),
213			dragger = container.find(".sp-color"),
214			dragHelper = container.find(".sp-dragger"),
215			slider = container.find(".sp-hue"),
216			slideHelper = container.find(".sp-slider"),
217			alphaSliderInner = container.find(".sp-alpha-inner"),
218			alphaSlider = container.find(".sp-alpha"),
219			alphaSlideHelper = container.find(".sp-alpha-handle"),
220			textInput = container.find(".sp-input"),
221			paletteContainer = container.find(".sp-palette"),
222			initialColorContainer = container.find(".sp-initial"),
223			cancelButton = container.find(".sp-cancel"),
224			clearButton = container.find(".sp-clear"),
225			chooseButton = container.find(".sp-choose"),
226			toggleButton = container.find(".sp-palette-toggle"),
227			isInput = boundElement.is("input"),
228			isInputTypeColor = isInput && boundElement.attr("type") === "color" && inputTypeColorSupport(),
229			shouldReplace = isInput && !flat,
230			replacer = (shouldReplace) ? $(replaceInput).addClass(theme).addClass(opts.className).addClass(opts.replacerClassName) : $([]),
231			offsetElement = (shouldReplace) ? replacer : boundElement,
232			previewElement = replacer.find(".sp-preview-inner"),
233			initialColor = opts.color || (isInput && boundElement.val()),
234			colorOnShow = false,
235			currentPreferredFormat = opts.preferredFormat,
236			clickoutFiresChange = !opts.showButtons || opts.clickoutFiresChange,
237			isEmpty = !initialColor,
238			allowEmpty = opts.allowEmpty && !isInputTypeColor;
239
240		function applyOptions() {
241
242			if (opts.showPaletteOnly) {
243				opts.showPalette = true;
244			}
245
246			toggleButton.text(opts.showPaletteOnly ? opts.togglePaletteMoreText : opts.togglePaletteLessText);
247
248			if (opts.palette) {
249				palette = opts.palette.slice(0);
250				paletteArray = $.isArray(palette[0]) ? palette : [palette];
251				paletteLookup = {};
252				for (var i = 0; i < paletteArray.length; i++) {
253					for (var j = 0; j < paletteArray[i].length; j++) {
254						var rgb = tinycolor(paletteArray[i][j]).toRgbString();
255						paletteLookup[rgb] = true;
256					}
257				}
258			}
259
260			container.toggleClass("sp-flat", flat);
261			container.toggleClass("sp-input-disabled", !opts.showInput);
262			container.toggleClass("sp-alpha-enabled", opts.showAlpha);
263			container.toggleClass("sp-clear-enabled", allowEmpty);
264			container.toggleClass("sp-buttons-disabled", !opts.showButtons);
265			container.toggleClass("sp-palette-buttons-disabled", !opts.togglePaletteOnly);
266			container.toggleClass("sp-palette-disabled", !opts.showPalette);
267			container.toggleClass("sp-palette-only", opts.showPaletteOnly);
268			container.toggleClass("sp-initial-disabled", !opts.showInitial);
269			container.addClass(opts.className).addClass(opts.containerClassName);
270
271			reflow();
272		}
273
274		function initialize() {
275
276			if (IE) {
277				container.find("*:not(input)").attr("unselectable", "on");
278			}
279
280			applyOptions();
281
282			if (shouldReplace) {
283				boundElement.after(replacer).hide();
284			}
285
286			if (!allowEmpty) {
287				clearButton.hide();
288			}
289
290			if (flat) {
291				boundElement.after(container).hide();
292			} else {
293
294				var appendTo = opts.appendTo === "parent" ? boundElement.parent() : $(opts.appendTo);
295				if (appendTo.length !== 1) {
296					appendTo = $("body");
297				}
298
299				appendTo.append(container);
300			}
301
302			updateSelectionPaletteFromStorage();
303
304			offsetElement.bind("click.spectrum touchstart.spectrum", function (e) {
305				if (!disabled) {
306					toggle();
307				}
308
309				e.stopPropagation();
310
311				if (!$(e.target).is("input")) {
312					e.preventDefault();
313				}
314			});
315
316			if (boundElement.is(":disabled") || (opts.disabled === true)) {
317				disable();
318			}
319
320			// Prevent clicks from bubbling up to document.  This would cause it to be hidden.
321			container.click(stopPropagation);
322
323			// Handle user typed input
324			textInput.change(setFromTextInput);
325			textInput.bind("paste", function () {
326				setTimeout(setFromTextInput, 1);
327			});
328			textInput.keydown(function (e) {
329				if (e.keyCode == 13) {
330					setFromTextInput();
331				}
332			});
333
334			cancelButton.text(opts.cancelText);
335			cancelButton.bind("click.spectrum", function (e) {
336				e.stopPropagation();
337				e.preventDefault();
338				revert();
339				hide();
340			});
341
342			clearButton.attr("title", opts.clearText);
343			clearButton.bind("click.spectrum", function (e) {
344				e.stopPropagation();
345				e.preventDefault();
346				isEmpty = true;
347				move();
348
349				if (flat) {
350					//for the flat style, this is a change event
351					updateOriginalInput(true);
352				}
353			});
354
355			chooseButton.text(opts.chooseText);
356			chooseButton.bind("click.spectrum", function (e) {
357				e.stopPropagation();
358				e.preventDefault();
359
360				if (IE && textInput.is(":focus")) {
361					textInput.trigger('change');
362				}
363
364				if (isValid()) {
365					updateOriginalInput(true);
366					hide();
367				}
368			});
369
370			toggleButton.text(opts.showPaletteOnly ? opts.togglePaletteMoreText : opts.togglePaletteLessText);
371			toggleButton.bind("click.spectrum", function (e) {
372				e.stopPropagation();
373				e.preventDefault();
374
375				opts.showPaletteOnly = !opts.showPaletteOnly;
376
377				// To make sure the Picker area is drawn on the right, next to the
378				// Palette area (and not below the palette), first move the Palette
379				// to the left to make space for the picker, plus 5px extra.
380				// The 'applyOptions' function puts the whole container back into place
381				// and takes care of the button-text and the sp-palette-only CSS class.
382				if (!opts.showPaletteOnly && !flat) {
383					container.css('left', '-=' + (pickerContainer.outerWidth(true) + 5));
384				}
385				applyOptions();
386			});
387
388			draggable(alphaSlider, function (dragX, dragY, e) {
389				currentAlpha = (dragX / alphaWidth);
390				isEmpty = false;
391				if (e.shiftKey) {
392					currentAlpha = Math.round(currentAlpha * 10) / 10;
393				}
394
395				move();
396			}, dragStart, dragStop);
397
398			draggable(slider, function (dragX, dragY) {
399				currentHue = parseFloat(dragY / slideHeight);
400				isEmpty = false;
401				if (!opts.showAlpha) {
402					currentAlpha = 1;
403				}
404				move();
405			}, dragStart, dragStop);
406
407			draggable(dragger, function (dragX, dragY, e) {
408
409				// shift+drag should snap the movement to either the x or y axis.
410				if (!e.shiftKey) {
411					shiftMovementDirection = null;
412				} else if (!shiftMovementDirection) {
413					var oldDragX = currentSaturation * dragWidth;
414					var oldDragY = dragHeight - (currentValue * dragHeight);
415					var furtherFromX = Math.abs(dragX - oldDragX) > Math.abs(dragY - oldDragY);
416
417					shiftMovementDirection = furtherFromX ? "x" : "y";
418				}
419
420				var setSaturation = !shiftMovementDirection || shiftMovementDirection === "x";
421				var setValue = !shiftMovementDirection || shiftMovementDirection === "y";
422
423				if (setSaturation) {
424					currentSaturation = parseFloat(dragX / dragWidth);
425				}
426				if (setValue) {
427					currentValue = parseFloat((dragHeight - dragY) / dragHeight);
428				}
429
430				isEmpty = false;
431				if (!opts.showAlpha) {
432					currentAlpha = 1;
433				}
434
435				move();
436
437			}, dragStart, dragStop);
438
439			if (!!initialColor) {
440				set(initialColor);
441
442				// In case color was black - update the preview UI and set the format
443				// since the set function will not run (default color is black).
444				updateUI();
445				currentPreferredFormat = opts.preferredFormat || tinycolor(initialColor).format;
446
447				addColorToSelectionPalette(initialColor);
448			} else {
449				updateUI();
450			}
451
452			if (flat) {
453				show();
454			}
455
456			function paletteElementClick(e) {
457				if (e.data && e.data.ignore) {
458					set($(e.target).closest(".sp-thumb-el").data("color"));
459					move();
460				} else {
461					set($(e.target).closest(".sp-thumb-el").data("color"));
462					move();
463					updateOriginalInput(true);
464					if (opts.hideAfterPaletteSelect) {
465						hide();
466					}
467				}
468
469				return false;
470			}
471
472			var paletteEvent = IE ? "mousedown.spectrum" : "click.spectrum touchstart.spectrum";
473			paletteContainer.delegate(".sp-thumb-el", paletteEvent, paletteElementClick);
474			initialColorContainer.delegate(".sp-thumb-el:nth-child(1)", paletteEvent, { ignore: true }, paletteElementClick);
475		}
476
477		function updateSelectionPaletteFromStorage() {
478
479			if (localStorageKey && window.localStorage) {
480
481				// Migrate old palettes over to new format.  May want to remove this eventually.
482				try {
483					var oldPalette = window.localStorage[localStorageKey].split(",#");
484					if (oldPalette.length > 1) {
485						delete window.localStorage[localStorageKey];
486						$.each(oldPalette, function (i, c) {
487							addColorToSelectionPalette(c);
488						});
489					}
490				} catch (e) {
491				}
492
493				try {
494					selectionPalette = window.localStorage[localStorageKey].split(";");
495				} catch (e) {
496				}
497			}
498		}
499
500		function addColorToSelectionPalette(color) {
501			if (showSelectionPalette) {
502				var rgb = tinycolor(color).toRgbString();
503				if (!paletteLookup[rgb] && $.inArray(rgb, selectionPalette) === -1) {
504					selectionPalette.push(rgb);
505					while (selectionPalette.length > maxSelectionSize) {
506						selectionPalette.shift();
507					}
508				}
509
510				if (localStorageKey && window.localStorage) {
511					try {
512						window.localStorage[localStorageKey] = selectionPalette.join(";");
513					} catch (e) {
514					}
515				}
516			}
517		}
518
519		function getUniqueSelectionPalette() {
520			var unique = [];
521			if (opts.showPalette) {
522				for (var i = 0; i < selectionPalette.length; i++) {
523					var rgb = tinycolor(selectionPalette[i]).toRgbString();
524
525					if (!paletteLookup[rgb]) {
526						unique.push(selectionPalette[i]);
527					}
528				}
529			}
530
531			return unique.reverse().slice(0, opts.maxSelectionSize);
532		}
533
534		function drawPalette() {
535
536			var currentColor = get();
537
538			var html = $.map(paletteArray, function (palette, i) {
539				return paletteTemplate(palette, currentColor, "sp-palette-row sp-palette-row-" + i, opts);
540			});
541
542			updateSelectionPaletteFromStorage();
543
544			if (selectionPalette) {
545				html.push(paletteTemplate(getUniqueSelectionPalette(), currentColor, "sp-palette-row sp-palette-row-selection", opts));
546			}
547
548			paletteContainer.html(html.join(""));
549		}
550
551		function drawInitial() {
552			if (opts.showInitial) {
553				var initial = colorOnShow;
554				var current = get();
555				initialColorContainer.html(paletteTemplate([initial, current], current, "sp-palette-row-initial", opts));
556			}
557		}
558
559		function dragStart() {
560			if (dragHeight <= 0 || dragWidth <= 0 || slideHeight <= 0) {
561				reflow();
562			}
563			isDragging = true;
564			container.addClass(draggingClass);
565			shiftMovementDirection = null;
566			boundElement.trigger('dragstart.spectrum', [get()]);
567		}
568
569		function dragStop() {
570			isDragging = false;
571			container.removeClass(draggingClass);
572			boundElement.trigger('dragstop.spectrum', [get()]);
573		}
574
575		function setFromTextInput() {
576
577			var value = textInput.val();
578
579			if ((value === null || value === "") && allowEmpty) {
580				set(null);
581				updateOriginalInput(true);
582			} else {
583				var tiny = tinycolor(value);
584				if (tiny.isValid()) {
585					set(tiny);
586					updateOriginalInput(true);
587				} else {
588					textInput.addClass("sp-validation-error");
589				}
590			}
591		}
592
593		function toggle() {
594			if (visible) {
595				hide();
596			} else {
597				show();
598			}
599		}
600
601		function show() {
602			var event = $.Event('beforeShow.spectrum');
603
604			if (visible) {
605				reflow();
606				return;
607			}
608
609			boundElement.trigger(event, [get()]);
610
611			if (callbacks.beforeShow(get()) === false || event.isDefaultPrevented()) {
612				return;
613			}
614
615			hideAll();
616			visible = true;
617
618			$(doc).bind("keydown.spectrum", onkeydown);
619			$(doc).bind("click.spectrum", clickout);
620			$(window).bind("resize.spectrum", resize);
621			replacer.addClass("sp-active");
622			container.removeClass("sp-hidden");
623
624			reflow();
625			updateUI();
626
627			colorOnShow = get();
628
629			drawInitial();
630			callbacks.show(colorOnShow);
631			boundElement.trigger('show.spectrum', [colorOnShow]);
632		}
633
634		function onkeydown(e) {
635			// Close on ESC
636			if (e.keyCode === 27) {
637				hide();
638			}
639		}
640
641		function clickout(e) {
642			// Return on right click.
643			if (e.button == 2) {
644				return;
645			}
646
647			// If a drag event was happening during the mouseup, don't hide
648			// on click.
649			if (isDragging) {
650				return;
651			}
652
653			if (clickoutFiresChange) {
654				updateOriginalInput(true);
655			} else {
656				revert();
657			}
658			hide();
659		}
660
661		function hide() {
662			// Return if hiding is unnecessary
663			if (!visible || flat) {
664				return;
665			}
666			visible = false;
667
668			$(doc).unbind("keydown.spectrum", onkeydown);
669			$(doc).unbind("click.spectrum", clickout);
670			$(window).unbind("resize.spectrum", resize);
671
672			replacer.removeClass("sp-active");
673			container.addClass("sp-hidden");
674
675			callbacks.hide(get());
676			boundElement.trigger('hide.spectrum', [get()]);
677		}
678
679		function revert() {
680			set(colorOnShow, true);
681		}
682
683		function set(color, ignoreFormatChange) {
684			if (tinycolor.equals(color, get())) {
685				// Update UI just in case a validation error needs
686				// to be cleared.
687				updateUI();
688				return;
689			}
690
691			var newColor, newHsv;
692			if (!color && allowEmpty) {
693				isEmpty = true;
694			} else {
695				isEmpty = false;
696				newColor = tinycolor(color);
697				newHsv = newColor.toHsv();
698
699				currentHue = (newHsv.h % 360) / 360;
700				currentSaturation = newHsv.s;
701				currentValue = newHsv.v;
702				currentAlpha = newHsv.a;
703			}
704			updateUI();
705
706			if (newColor && newColor.isValid() && !ignoreFormatChange) {
707				currentPreferredFormat = opts.preferredFormat || newColor.getFormat();
708			}
709		}
710
711		function get(opts) {
712			opts = opts || {};
713
714			if (allowEmpty && isEmpty) {
715				return null;
716			}
717
718			return tinycolor.fromRatio({
719				h: currentHue,
720				s: currentSaturation,
721				v: currentValue,
722				a: Math.round(currentAlpha * 100) / 100
723			}, { format: opts.format || currentPreferredFormat });
724		}
725
726		function isValid() {
727			return !textInput.hasClass("sp-validation-error");
728		}
729
730		function move() {
731			updateUI();
732
733			callbacks.move(get());
734			boundElement.trigger('move.spectrum', [get()]);
735		}
736
737		function updateUI() {
738
739			textInput.removeClass("sp-validation-error");
740
741			updateHelperLocations();
742
743			// Update dragger background color (gradients take care of saturation and value).
744			var flatColor = tinycolor.fromRatio({ h: currentHue, s: 1, v: 1 });
745			dragger.css("background-color", flatColor.toHexString());
746
747			// Get a format that alpha will be included in (hex and names ignore alpha)
748			var format = currentPreferredFormat;
749			if (currentAlpha < 1 && !(currentAlpha === 0 && format === "name")) {
750				if (format === "hex" || format === "hex3" || format === "hex6" || format === "name") {
751					format = "rgb";
752				}
753			}
754
755			var realColor = get({ format: format }),
756				displayColor = '';
757
758			//reset background info for preview element
759			previewElement.removeClass("sp-clear-display");
760			previewElement.css('background-color', 'transparent');
761
762			if (!realColor && allowEmpty) {
763				// Update the replaced elements background with icon indicating no color selection
764				previewElement.addClass("sp-clear-display");
765			} else {
766				var realHex = realColor.toHexString(),
767					realRgb = realColor.toRgbString();
768
769				// Update the replaced elements background color (with actual selected color)
770				if (rgbaSupport || realColor.alpha === 1) {
771					previewElement.css("background-color", realRgb);
772				} else {
773					previewElement.css("background-color", "transparent");
774					previewElement.css("filter", realColor.toFilter());
775				}
776
777				if (opts.showAlpha) {
778					var rgb = realColor.toRgb();
779					rgb.a = 0;
780					var realAlpha = tinycolor(rgb).toRgbString();
781					var gradient = "linear-gradient(left, " + realAlpha + ", " + realHex + ")";
782
783					if (IE) {
784						alphaSliderInner.css("filter", tinycolor(realAlpha).toFilter({ gradientType: 1 }, realHex));
785					} else {
786						alphaSliderInner.css("background", "-webkit-" + gradient);
787						alphaSliderInner.css("background", "-moz-" + gradient);
788						alphaSliderInner.css("background", "-ms-" + gradient);
789						// Use current syntax gradient on unprefixed property.
790						alphaSliderInner.css("background",
791							"linear-gradient(to right, " + realAlpha + ", " + realHex + ")");
792					}
793				}
794
795				displayColor = realColor.toString(format);
796			}
797
798			// Update the text entry input as it changes happen
799			if (opts.showInput) {
800				textInput.val(displayColor);
801			}
802
803			if (opts.showPalette) {
804				drawPalette();
805			}
806
807			drawInitial();
808		}
809
810		function updateHelperLocations() {
811			var s = currentSaturation;
812			var v = currentValue;
813
814			if (allowEmpty && isEmpty) {
815				//if selected color is empty, hide the helpers
816				alphaSlideHelper.hide();
817				slideHelper.hide();
818				dragHelper.hide();
819			} else {
820				//make sure helpers are visible
821				alphaSlideHelper.show();
822				slideHelper.show();
823				dragHelper.show();
824
825				// Where to show the little circle in that displays your current selected color
826				var dragX = s * dragWidth;
827				var dragY = dragHeight - (v * dragHeight);
828				dragX = Math.max(
829					-dragHelperHeight,
830					Math.min(dragWidth - dragHelperHeight, dragX - dragHelperHeight)
831				);
832				dragY = Math.max(
833					-dragHelperHeight,
834					Math.min(dragHeight - dragHelperHeight, dragY - dragHelperHeight)
835				);
836				dragHelper.css({
837					"top": dragY + "px",
838					"left": dragX + "px"
839				});
840
841				var alphaX = currentAlpha * alphaWidth;
842				alphaSlideHelper.css({
843					"left": (alphaX - (alphaSlideHelperWidth / 2)) + "px"
844				});
845
846				// Where to show the bar that displays your current selected hue
847				var slideY = (currentHue) * slideHeight;
848				slideHelper.css({
849					"top": (slideY - slideHelperHeight) + "px"
850				});
851			}
852		}
853
854		function updateOriginalInput(fireCallback) {
855			var color = get(),
856				displayColor = '',
857				hasChanged = !tinycolor.equals(color, colorOnShow);
858
859			if (color) {
860				displayColor = color.toString(currentPreferredFormat);
861				// Update the selection palette with the current color
862				addColorToSelectionPalette(color);
863			}
864
865			if (isInput) {
866				boundElement.val(displayColor);
867			}
868
869			if (fireCallback && hasChanged) {
870				callbacks.change(color);
871				boundElement.trigger('change', [color]);
872			}
873		}
874
875		function reflow() {
876			if (!visible) {
877				return; // Calculations would be useless and wouldn't be reliable anyways
878			}
879			dragWidth = dragger.width();
880			dragHeight = dragger.height();
881			dragHelperHeight = dragHelper.height();
882			slideWidth = slider.width();
883			slideHeight = slider.height();
884			slideHelperHeight = slideHelper.height();
885			alphaWidth = alphaSlider.width();
886			alphaSlideHelperWidth = alphaSlideHelper.width();
887
888			if (!flat) {
889				container.css("position", "absolute");
890				if (opts.offset) {
891					container.offset(opts.offset);
892				} else {
893					container.offset(getOffset(container, offsetElement));
894				}
895			}
896
897			updateHelperLocations();
898
899			if (opts.showPalette) {
900				drawPalette();
901			}
902
903			boundElement.trigger('reflow.spectrum');
904		}
905
906		function destroy() {
907			boundElement.show();
908			offsetElement.unbind("click.spectrum touchstart.spectrum");
909			container.remove();
910			replacer.remove();
911			spectrums[spect.id] = null;
912		}
913
914		function option(optionName, optionValue) {
915			if (optionName === undefined) {
916				return $.extend({}, opts);
917			}
918			if (optionValue === undefined) {
919				return opts[optionName];
920			}
921
922			opts[optionName] = optionValue;
923
924			if (optionName === "preferredFormat") {
925				currentPreferredFormat = opts.preferredFormat;
926			}
927			applyOptions();
928		}
929
930		function enable() {
931			disabled = false;
932			boundElement.attr("disabled", false);
933			offsetElement.removeClass("sp-disabled");
934		}
935
936		function disable() {
937			hide();
938			disabled = true;
939			boundElement.attr("disabled", true);
940			offsetElement.addClass("sp-disabled");
941		}
942
943		function setOffset(coord) {
944			opts.offset = coord;
945			reflow();
946		}
947
948		initialize();
949
950		var spect = {
951			show: show,
952			hide: hide,
953			toggle: toggle,
954			reflow: reflow,
955			option: option,
956			enable: enable,
957			disable: disable,
958			offset: setOffset,
959			set: function (c) {
960				set(c);
961				updateOriginalInput();
962			},
963			get: get,
964			destroy: destroy,
965			container: container
966		};
967
968		spect.id = spectrums.push(spect) - 1;
969
970		return spect;
971	}
972
973	/**
974	* checkOffset - get the offset below/above and left/right element depending on screen position
975	* Thanks https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.datepicker.js
976	*/
977	function getOffset(picker, input) {
978		var extraY = 0;
979		var dpWidth = picker.outerWidth();
980		var dpHeight = picker.outerHeight();
981		var inputHeight = input.outerHeight();
982		var doc = picker[0].ownerDocument;
983		var docElem = doc.documentElement;
984		var viewWidth = docElem.clientWidth + $(doc).scrollLeft();
985		var viewHeight = docElem.clientHeight + $(doc).scrollTop();
986		var offset = input.offset();
987		offset.top += inputHeight;
988
989		offset.left -=
990			Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
991				Math.abs(offset.left + dpWidth - viewWidth) : 0);
992
993		offset.top -=
994			Math.min(offset.top, ((offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
995				Math.abs(dpHeight + inputHeight - extraY) : extraY));
996
997		return offset;
998	}
999
1000	/**
1001	* noop - do nothing
1002	*/
1003	function noop() {
1004
1005	}
1006
vendor: 36,801 bytes, lines 1007-2332
1007	/**
1008	* stopPropagation - makes the code only doing this a little easier to read in line
1009	*/
1010	function stopPropagation(e) {
1011		e.stopPropagation();
1012	}
1013
1014	/**
1015	* Create a function bound to a given object
1016	* Thanks to underscore.js
1017	*/
1018	function bind(func, obj) {
1019		var slice = Array.prototype.slice;
1020		var args = slice.call(arguments, 2);
1021		return function () {
1022			return func.apply(obj, args.concat(slice.call(arguments)));
1023		};
1024	}
1025
1026	/**
1027	* Lightweight drag helper.  Handles containment within the element, so that
1028	* when dragging, the x is within [0,element.width] and y is within [0,element.height]
1029	*/
1030	function draggable(element, onmove, onstart, onstop) {
1031		onmove = onmove || function () { };
1032		onstart = onstart || function () { };
1033		onstop = onstop || function () { };
1034		var doc = document;
1035		var dragging = false;
1036		var offset = {};
1037		var maxHeight = 0;
1038		var maxWidth = 0;
1039		var hasTouch = ('ontouchstart' in window);
1040
1041		var duringDragEvents = {};
1042		duringDragEvents["selectstart"] = prevent;
1043		duringDragEvents["dragstart"] = prevent;
1044		duringDragEvents["touchmove mousemove"] = move;
1045		duringDragEvents["touchend mouseup"] = stop;
1046
1047		function prevent(e) {
1048			if (e.stopPropagation) {
1049				e.stopPropagation();
1050			}
1051			if (e.preventDefault) {
1052				e.preventDefault();
1053			}
1054			e.returnValue = false;
1055		}
1056
1057		function move(e) {
1058			if (dragging) {
1059				// Mouseup happened outside of window
1060				if (IE && doc.documentMode < 9 && !e.button) {
1061					return stop();
1062				}
1063
1064				var t0 = e.originalEvent && e.originalEvent.touches && e.originalEvent.touches[0];
1065				var pageX = t0 && t0.pageX || e.pageX;
1066				var pageY = t0 && t0.pageY || e.pageY;
1067
1068				var dragX = Math.max(0, Math.min(pageX - offset.left, maxWidth));
1069				var dragY = Math.max(0, Math.min(pageY - offset.top, maxHeight));
1070
1071				if (hasTouch) {
1072					// Stop scrolling in iOS
1073					prevent(e);
1074				}
1075
1076				onmove.apply(element, [dragX, dragY, e]);
1077			}
1078		}
1079
1080		function start(e) {
1081			var rightclick = (e.which) ? (e.which == 3) : (e.button == 2);
1082
1083			if (!rightclick && !dragging) {
1084				if (onstart.apply(element, arguments) !== false) {
1085					dragging = true;
1086					maxHeight = $(element).height();
1087					maxWidth = $(element).width();
1088					offset = $(element).offset();
1089
1090					$(doc).bind(duringDragEvents);
1091					$(doc.body).addClass("sp-dragging");
1092
1093					move(e);
1094
1095					prevent(e);
1096				}
1097			}
1098		}
1099
1100		function stop() {
1101			if (dragging) {
1102				$(doc).unbind(duringDragEvents);
1103				$(doc.body).removeClass("sp-dragging");
1104
1105				// Wait a tick before notifying observers to allow the click event
1106				// to fire in Chrome.
1107				setTimeout(function () {
1108					onstop.apply(element, arguments);
1109				}, 0);
1110			}
1111			dragging = false;
1112		}
1113
1114		$(element).bind("touchstart mousedown", start);
1115	}
1116
1117	function throttle(func, wait, debounce) {
1118		var timeout;
1119		return function () {
1120			var context = this, args = arguments;
1121			var throttler = function () {
1122				timeout = null;
1123				func.apply(context, args);
1124			};
1125			if (debounce) {
1126				clearTimeout(timeout);
1127			}
1128			if (debounce || !timeout) {
1129				timeout = setTimeout(throttler, wait);
1130			}
1131		};
1132	}
1133
1134	function inputTypeColorSupport() {
1135		return $.fn.spectrum.inputTypeColorSupport();
1136	}
1137
1138	/**
1139	* Define a jQuery plugin
1140	*/
1141	var dataID = "spectrum.id";
1142	$.fn.spectrum = function (opts, extra) {
1143
1144		if (typeof opts == "string") {
1145
1146			var returnValue = this;
1147			var args = Array.prototype.slice.call(arguments, 1);
1148
1149			this.each(function () {
1150				var spect = spectrums[$(this).data(dataID)];
1151				if (spect) {
1152					var method = spect[opts];
1153					if (!method) {
1154						throw new Error("Spectrum: no such method: '" + opts + "'");
1155					}
1156
1157					if (opts == "get") {
1158						returnValue = spect.get();
1159					} else if (opts == "container") {
1160						returnValue = spect.container;
1161					} else if (opts == "option") {
1162						returnValue = spect.option.apply(spect, args);
1163					} else if (opts == "destroy") {
1164						spect.destroy();
1165						$(this).removeData(dataID);
1166					} else {
1167						method.apply(spect, args);
1168					}
1169				}
1170			});
1171
1172			return returnValue;
1173		}
1174
1175		// Initializing a new instance of spectrum
1176		return this.spectrum("destroy").each(function () {
1177			var options = $.extend({}, opts, $(this).data());
1178			var spect = spectrum(this, options);
1179			$(this).data(dataID, spect.id);
1180		});
1181	};
1182
1183	$.fn.spectrum.load = true;
1184	$.fn.spectrum.loadOpts = {};
1185	$.fn.spectrum.draggable = draggable;
1186	$.fn.spectrum.defaults = defaultOpts;
1187	$.fn.spectrum.inputTypeColorSupport = function inputTypeColorSupport() {
1188		if (typeof inputTypeColorSupport._cachedResult === "undefined") {
1189			var colorInput = $("<input type='color'/>")[0]; // if color element is supported, value will default to not null
1190			inputTypeColorSupport._cachedResult = colorInput.type === "color" && colorInput.value !== "";
1191		}
1192		return inputTypeColorSupport._cachedResult;
1193	};
1194
1195	$.spectrum = {};
1196	$.spectrum.localization = {};
1197	$.spectrum.palettes = {};
1198
1199	$.fn.spectrum.processNativeColorInputs = function () {
1200		var colorInputs = $("input[type=color]");
1201		if (colorInputs.length && !inputTypeColorSupport()) {
1202			colorInputs.spectrum({
1203				preferredFormat: "hex6"
1204			});
1205		}
1206	};
1207
1208	// TinyColor v1.1.2
1209	// https://github.com/bgrins/TinyColor
1210	// Brian Grinstead, MIT License
1211
1212	(function () {
1213
1214		var trimLeft = /^[\s,#]+/,
1215			trimRight = /\s+$/,
1216			tinyCounter = 0,
1217			math = Math,
1218			mathRound = math.round,
1219			mathMin = math.min,
1220			mathMax = math.max,
1221			mathRandom = math.random;
1222
1223		var tinycolor = function (color, opts) {
1224
1225			color = (color) ? color : '';
1226			opts = opts || {};
1227
1228			// If input is already a tinycolor, return itself
1229			if (color instanceof tinycolor) {
1230				return color;
1231			}
1232			// If we are called as a function, call using new instead
1233			if (!(this instanceof tinycolor)) {
1234				return new tinycolor(color, opts);
1235			}
1236
1237			var rgb = inputToRGB(color);
1238			this._originalInput = color,
1239				this._r = rgb.r,
1240				this._g = rgb.g,
1241				this._b = rgb.b,
1242				this._a = rgb.a,
1243				this._roundA = mathRound(100 * this._a) / 100,
1244				this._format = opts.format || rgb.format;
1245			this._gradientType = opts.gradientType;
1246
1247			// Don't let the range of [0,255] come back in [0,1].
1248			// Potentially lose a little bit of precision here, but will fix issues where
1249			// .5 gets interpreted as half of the total, instead of half of 1
1250			// If it was supposed to be 128, this was already taken care of by `inputToRgb`
1251			if (this._r < 1) {
1252				this._r = mathRound(this._r);
1253			}
1254			if (this._g < 1) {
1255				this._g = mathRound(this._g);
1256			}
1257			if (this._b < 1) {
1258				this._b = mathRound(this._b);
1259			}
1260
1261			this._ok = rgb.ok;
1262			this._tc_id = tinyCounter++;
1263		};
1264
1265		tinycolor.prototype = {
1266			isDark: function () {
1267				return this.getBrightness() < 128;
1268			},
1269			isLight: function () {
1270				return !this.isDark();
1271			},
1272			isValid: function () {
1273				return this._ok;
1274			},
1275			getOriginalInput: function () {
1276				return this._originalInput;
1277			},
1278			getFormat: function () {
1279				return this._format;
1280			},
1281			getAlpha: function () {
1282				return this._a;
1283			},
1284			getBrightness: function () {
1285				var rgb = this.toRgb();
1286				return (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000;
1287			},
1288			setAlpha: function (value) {
1289				this._a = boundAlpha(value);
1290				this._roundA = mathRound(100 * this._a) / 100;
1291				return this;
1292			},
1293			toHsv: function () {
1294				var hsv = rgbToHsv(this._r, this._g, this._b);
1295				return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: this._a };
1296			},
1297			toHsvString: function () {
1298				var hsv = rgbToHsv(this._r, this._g, this._b);
1299				var h = mathRound(hsv.h * 360), s = mathRound(hsv.s * 100), v = mathRound(hsv.v * 100);
1300				return (this._a == 1) ?
1301					"hsv(" + h + ", " + s + "%, " + v + "%)" :
1302					"hsva(" + h + ", " + s + "%, " + v + "%, " + this._roundA + ")";
1303			},
1304			toHsl: function () {
1305				var hsl = rgbToHsl(this._r, this._g, this._b);
1306				return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: this._a };
1307			},
1308			toHslString: function () {
1309				var hsl = rgbToHsl(this._r, this._g, this._b);
1310				var h = mathRound(hsl.h * 360), s = mathRound(hsl.s * 100), l = mathRound(hsl.l * 100);
1311				return (this._a == 1) ?
1312					"hsl(" + h + ", " + s + "%, " + l + "%)" :
1313					"hsla(" + h + ", " + s + "%, " + l + "%, " + this._roundA + ")";
1314			},
1315			toHex: function (allow3Char) {
1316				return rgbToHex(this._r, this._g, this._b, allow3Char);
1317			},
1318			toHexString: function (allow3Char) {
1319				return '#' + this.toHex(allow3Char);
1320			},
1321			toHex8: function () {
1322				return rgbaToHex(this._r, this._g, this._b, this._a);
1323			},
1324			toHex8String: function () {
1325				return '#' + this.toHex8();
1326			},
1327			toRgb: function () {
1328				return { r: mathRound(this._r), g: mathRound(this._g), b: mathRound(this._b), a: this._a };
1329			},
1330			toRgbString: function () {
1331				return (this._a == 1) ?
1332					"rgb(" + mathRound(this._r) + ", " + mathRound(this._g) + ", " + mathRound(this._b) + ")" :
1333					"rgba(" + mathRound(this._r) + ", " + mathRound(this._g) + ", " + mathRound(this._b) + ", " + this._roundA + ")";
1334			},
1335			toPercentageRgb: function () {
1336				return { r: mathRound(bound01(this._r, 255) * 100) + "%", g: mathRound(bound01(this._g, 255) * 100) + "%", b: mathRound(bound01(this._b, 255) * 100) + "%", a: this._a };
1337			},
1338			toPercentageRgbString: function () {
1339				return (this._a == 1) ?
1340					"rgb(" + mathRound(bound01(this._r, 255) * 100) + "%, " + mathRound(bound01(this._g, 255) * 100) + "%, " + mathRound(bound01(this._b, 255) * 100) + "%)" :
1341					"rgba(" + mathRound(bound01(this._r, 255) * 100) + "%, " + mathRound(bound01(this._g, 255) * 100) + "%, " + mathRound(bound01(this._b, 255) * 100) + "%, " + this._roundA + ")";
1342			},
1343			toName: function () {
1344				if (this._a === 0) {
1345					return "transparent";
1346				}
1347
1348				if (this._a < 1) {
1349					return false;
1350				}
1351
1352				return hexNames[rgbToHex(this._r, this._g, this._b, true)] || false;
1353			},
1354			toFilter: function (secondColor) {
1355				var hex8String = '#' + rgbaToHex(this._r, this._g, this._b, this._a);
1356				var secondHex8String = hex8String;
1357				var gradientType = this._gradientType ? "GradientType = 1, " : "";
1358
1359				if (secondColor) {
1360					var s = tinycolor(secondColor);
1361					secondHex8String = s.toHex8String();
1362				}
1363
1364				return "progid:DXImageTransform.Microsoft.gradient(" + gradientType + "startColorstr=" + hex8String + ",endColorstr=" + secondHex8String + ")";
1365			},
1366			toString: function (format) {
1367				var formatSet = !!format;
1368				format = format || this._format;
1369
1370				var formattedString = false;
1371				var hasAlpha = this._a < 1 && this._a >= 0;
1372				var needsAlphaFormat = !formatSet && hasAlpha && (format === "hex" || format === "hex6" || format === "hex3" || format === "name");
1373
1374				if (needsAlphaFormat) {
1375					// Special case for "transparent", all other non-alpha formats
1376					// will return rgba when there is transparency.
1377					if (format === "name" && this._a === 0) {
1378						return this.toName();
1379					}
1380					return this.toRgbString();
1381				}
1382				if (format === "rgb") {
1383					formattedString = this.toRgbString();
1384				}
1385				if (format === "prgb") {
1386					formattedString = this.toPercentageRgbString();
1387				}
1388				if (format === "hex" || format === "hex6") {
1389					formattedString = this.toHexString();
1390				}
1391				if (format === "hex3") {
1392					formattedString = this.toHexString(true);
1393				}
1394				if (format === "hex8") {
1395					formattedString = this.toHex8String();
1396				}
1397				if (format === "name") {
1398					formattedString = this.toName();
1399				}
1400				if (format === "hsl") {
1401					formattedString = this.toHslString();
1402				}
1403				if (format === "hsv") {
1404					formattedString = this.toHsvString();
1405				}
1406
1407				return formattedString || this.toHexString();
1408			},
1409
1410			_applyModification: function (fn, args) {
1411				var color = fn.apply(null, [this].concat([].slice.call(args)));
1412				this._r = color._r;
1413				this._g = color._g;
1414				this._b = color._b;
1415				this.setAlpha(color._a);
1416				return this;
1417			},
1418			lighten: function () {
1419				return this._applyModification(lighten, arguments);
1420			},
1421			brighten: function () {
1422				return this._applyModification(brighten, arguments);
1423			},
1424			darken: function () {
1425				return this._applyModification(darken, arguments);
1426			},
1427			desaturate: function () {
1428				return this._applyModification(desaturate, arguments);
1429			},
1430			saturate: function () {
1431				return this._applyModification(saturate, arguments);
1432			},
1433			greyscale: function () {
1434				return this._applyModification(greyscale, arguments);
1435			},
1436			spin: function () {
1437				return this._applyModification(spin, arguments);
1438			},
1439
1440			_applyCombination: function (fn, args) {
1441				return fn.apply(null, [this].concat([].slice.call(args)));
1442			},
1443			analogous: function () {
1444				return this._applyCombination(analogous, arguments);
1445			},
1446			complement: function () {
1447				return this._applyCombination(complement, arguments);
1448			},
1449			monochromatic: function () {
1450				return this._applyCombination(monochromatic, arguments);
1451			},
1452			splitcomplement: function () {
1453				return this._applyCombination(splitcomplement, arguments);
1454			},
1455			triad: function () {
1456				return this._applyCombination(triad, arguments);
1457			},
1458			tetrad: function () {
1459				return this._applyCombination(tetrad, arguments);
1460			}
1461		};
1462
1463		// If input is an object, force 1 into "1.0" to handle ratios properly
1464		// String input requires "1.0" as input, so 1 will be treated as 1
1465		tinycolor.fromRatio = function (color, opts) {
1466			if (typeof color == "object") {
1467				var newColor = {};
1468				for (var i in color) {
1469					if (color.hasOwnProperty(i)) {
1470						if (i === "a") {
1471							newColor[i] = color[i];
1472						} else {
1473							newColor[i] = convertToPercentage(color[i]);
1474						}
1475					}
1476				}
1477				color = newColor;
1478			}
1479
1480			return tinycolor(color, opts);
1481		};
1482
1483		// Given a string or object, convert that input to RGB
1484		// Possible string inputs:
1485		//
1486		//     "red"
1487		//     "#f00" or "f00"
1488		//     "#ff0000" or "ff0000"
1489		//     "#ff000000" or "ff000000"
1490		//     "rgb 255 0 0" or "rgb (255, 0, 0)"
1491		//     "rgb 1.0 0 0" or "rgb (1, 0, 0)"
1492		//     "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1"
1493		//     "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1"
1494		//     "hsl(0, 100%, 50%)" or "hsl 0 100% 50%"
1495		//     "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1"
1496		//     "hsv(0, 100%, 100%)" or "hsv 0 100% 100%"
1497		//
1498		function inputToRGB(color) {
1499
1500			var rgb = { r: 0, g: 0, b: 0 };
1501			var a = 1;
1502			var ok = false;
1503			var format = false;
1504
1505			if (typeof color == "string") {
1506				color = stringInputToObject(color);
1507			}
1508
1509			if (typeof color == "object") {
1510				if (color.hasOwnProperty("r") && color.hasOwnProperty("g") && color.hasOwnProperty("b")) {
1511					rgb = rgbToRgb(color.r, color.g, color.b);
1512					ok = true;
1513					format = String(color.r).substr(-1) === "%" ? "prgb" : "rgb";
1514				} else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("v")) {
1515					color.s = convertToPercentage(color.s);
1516					color.v = convertToPercentage(color.v);
1517					rgb = hsvToRgb(color.h, color.s, color.v);
1518					ok = true;
1519					format = "hsv";
1520				} else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("l")) {
1521					color.s = convertToPercentage(color.s);
1522					color.l = convertToPercentage(color.l);
1523					rgb = hslToRgb(color.h, color.s, color.l);
1524					ok = true;
1525					format = "hsl";
1526				}
1527
1528				if (color.hasOwnProperty("a")) {
1529					a = color.a;
1530				}
1531			}
1532
1533			a = boundAlpha(a);
1534
1535			return {
1536				ok: ok,
1537				format: color.format || format,
1538				r: mathMin(255, mathMax(rgb.r, 0)),
1539				g: mathMin(255, mathMax(rgb.g, 0)),
1540				b: mathMin(255, mathMax(rgb.b, 0)),
1541				a: a
1542			};
1543		}
1544
1545
1546		// Conversion Functions
1547		// --------------------
1548
1549		// `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from:
1550		// <http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript>
1551
1552		// `rgbToRgb`
1553		// Handle bounds / percentage checking to conform to CSS color spec
1554		// <http://www.w3.org/TR/css3-color/>
1555		// *Assumes:* r, g, b in [0, 255] or [0, 1]
1556		// *Returns:* { r, g, b } in [0, 255]
1557		function rgbToRgb(r, g, b) {
1558			return {
1559				r: bound01(r, 255) * 255,
1560				g: bound01(g, 255) * 255,
1561				b: bound01(b, 255) * 255
1562			};
1563		}
1564
1565		// `rgbToHsl`
1566		// Converts an RGB color value to HSL.
1567		// *Assumes:* r, g, and b are contained in [0, 255] or [0, 1]
1568		// *Returns:* { h, s, l } in [0,1]
1569		function rgbToHsl(r, g, b) {
1570
1571			r = bound01(r, 255);
1572			g = bound01(g, 255);
1573			b = bound01(b, 255);
1574
1575			var max = mathMax(r, g, b), min = mathMin(r, g, b);
1576			var h, s, l = (max + min) / 2;
1577
1578			if (max == min) {
1579				h = s = 0; // achromatic
1580			} else {
1581				var d = max - min;
1582				s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
1583				switch (max) {
1584					case r: h = (g - b) / d + (g < b ? 6 : 0); break;
1585					case g: h = (b - r) / d + 2; break;
1586					case b: h = (r - g) / d + 4; break;
1587				}
1588
1589				h /= 6;
1590			}
1591
1592			return { h: h, s: s, l: l };
1593		}
1594
1595		// `hslToRgb`
1596		// Converts an HSL color value to RGB.
1597		// *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100]
1598		// *Returns:* { r, g, b } in the set [0, 255]
1599		function hslToRgb(h, s, l) {
1600			var r, g, b;
1601
1602			h = bound01(h, 360);
1603			s = bound01(s, 100);
1604			l = bound01(l, 100);
1605
1606			function hue2rgb(p, q, t) {
1607				if (t < 0) {
1608					t += 1;
1609				}
1610				if (t > 1) {
1611					t -= 1;
1612				}
1613				if (t < 1 / 6) {
1614					return p + (q - p) * 6 * t;
1615				}
1616				if (t < 1 / 2) {
1617					return q;
1618				}
1619				if (t < 2 / 3) {
1620					return p + (q - p) * (2 / 3 - t) * 6;
1621				}
1622				return p;
1623			}
1624
1625			if (s === 0) {
1626				r = g = b = l; // achromatic
1627			} else {
1628				var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
1629				var p = 2 * l - q;
1630				r = hue2rgb(p, q, h + 1 / 3);
1631				g = hue2rgb(p, q, h);
1632				b = hue2rgb(p, q, h - 1 / 3);
1633			}
1634
1635			return { r: r * 255, g: g * 255, b: b * 255 };
1636		}
1637
1638		// `rgbToHsv`
1639		// Converts an RGB color value to HSV
1640		// *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1]
1641		// *Returns:* { h, s, v } in [0,1]
1642		function rgbToHsv(r, g, b) {
1643
1644			r = bound01(r, 255);
1645			g = bound01(g, 255);
1646			b = bound01(b, 255);
1647
1648			var max = mathMax(r, g, b), min = mathMin(r, g, b);
1649			var h, s, v = max;
1650
1651			var d = max - min;
1652			s = max === 0 ? 0 : d / max;
1653
1654			if (max == min) {
1655				h = 0; // achromatic
1656			} else {
1657				switch (max) {
1658					case r: h = (g - b) / d + (g < b ? 6 : 0); break;
1659					case g: h = (b - r) / d + 2; break;
1660					case b: h = (r - g) / d + 4; break;
1661				}
1662				h /= 6;
1663			}
1664			return { h: h, s: s, v: v };
1665		}
1666
1667		// `hsvToRgb`
1668		// Converts an HSV color value to RGB.
1669		// *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100]
1670		// *Returns:* { r, g, b } in the set [0, 255]
1671		function hsvToRgb(h, s, v) {
1672
1673			h = bound01(h, 360) * 6;
1674			s = bound01(s, 100);
1675			v = bound01(v, 100);
1676
1677			var i = math.floor(h),
1678				f = h - i,
1679				p = v * (1 - s),
1680				q = v * (1 - f * s),
1681				t = v * (1 - (1 - f) * s),
1682				mod = i % 6,
1683				r = [v, q, p, p, t, v][mod],
1684				g = [t, v, v, q, p, p][mod],
1685				b = [p, p, t, v, v, q][mod];
1686
1687			return { r: r * 255, g: g * 255, b: b * 255 };
1688		}
1689
1690		// `rgbToHex`
1691		// Converts an RGB color to hex
1692		// Assumes r, g, and b are contained in the set [0, 255]
1693		// Returns a 3 or 6 character hex
1694		function rgbToHex(r, g, b, allow3Char) {
1695
1696			var hex = [
1697				pad2(mathRound(r).toString(16)),
1698				pad2(mathRound(g).toString(16)),
1699				pad2(mathRound(b).toString(16))
1700			];
1701
1702			// Return a 3 character hex if possible
1703			if (allow3Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1)) {
1704				return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0);
1705			}
1706
1707			return hex.join("");
1708		}
1709		// `rgbaToHex`
1710		// Converts an RGBA color plus alpha transparency to hex
1711		// Assumes r, g, b and a are contained in the set [0, 255]
1712		// Returns an 8 character hex
1713		function rgbaToHex(r, g, b, a) {
1714
1715			var hex = [
1716				pad2(convertDecimalToHex(a)),
1717				pad2(mathRound(r).toString(16)),
1718				pad2(mathRound(g).toString(16)),
1719				pad2(mathRound(b).toString(16))
1720			];
1721
1722			return hex.join("");
1723		}
1724
1725		// `equals`
1726		// Can be called with any tinycolor input
1727		tinycolor.equals = function (color1, color2) {
1728			if (!color1 || !color2) {
1729				return false;
1730			}
1731			return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString();
1732		};
1733		tinycolor.random = function () {
1734			return tinycolor.fromRatio({
1735				r: mathRandom(),
1736				g: mathRandom(),
1737				b: mathRandom()
1738			});
1739		};
1740
1741
1742		// Modification Functions
1743		// ----------------------
1744		// Thanks to less.js for some of the basics here
1745		// <https://github.com/cloudhead/less.js/blob/master/lib/less/functions.js>
1746
1747		function desaturate(color, amount) {
1748			amount = (amount === 0) ? 0 : (amount || 10);
1749			var hsl = tinycolor(color).toHsl();
1750			hsl.s -= amount / 100;
1751			hsl.s = clamp01(hsl.s);
1752			return tinycolor(hsl);
1753		}
1754
1755		function saturate(color, amount) {
1756			amount = (amount === 0) ? 0 : (amount || 10);
1757			var hsl = tinycolor(color).toHsl();
1758			hsl.s += amount / 100;
1759			hsl.s = clamp01(hsl.s);
1760			return tinycolor(hsl);
1761		}
1762
1763		function greyscale(color) {
1764			return tinycolor(color).desaturate(100);
1765		}
1766
1767		function lighten(color, amount) {
1768			amount = (amount === 0) ? 0 : (amount || 10);
1769			var hsl = tinycolor(color).toHsl();
1770			hsl.l += amount / 100;
1771			hsl.l = clamp01(hsl.l);
1772			return tinycolor(hsl);
1773		}
1774
1775		function brighten(color, amount) {
1776			amount = (amount === 0) ? 0 : (amount || 10);
1777			var rgb = tinycolor(color).toRgb();
1778			rgb.r = mathMax(0, mathMin(255, rgb.r - mathRound(255 * - (amount / 100))));
1779			rgb.g = mathMax(0, mathMin(255, rgb.g - mathRound(255 * - (amount / 100))));
1780			rgb.b = mathMax(0, mathMin(255, rgb.b - mathRound(255 * - (amount / 100))));
1781			return tinycolor(rgb);
1782		}
1783
1784		function darken(color, amount) {
1785			amount = (amount === 0) ? 0 : (amount || 10);
1786			var hsl = tinycolor(color).toHsl();
1787			hsl.l -= amount / 100;
1788			hsl.l = clamp01(hsl.l);
1789			return tinycolor(hsl);
1790		}
1791
1792		// Spin takes a positive or negative amount within [-360, 360] indicating the change of hue.
1793		// Values outside of this range will be wrapped into this range.
1794		function spin(color, amount) {
1795			var hsl = tinycolor(color).toHsl();
1796			var hue = (mathRound(hsl.h) + amount) % 360;
1797			hsl.h = hue < 0 ? 360 + hue : hue;
1798			return tinycolor(hsl);
1799		}
1800
1801		// Combination Functions
1802		// ---------------------
1803		// Thanks to jQuery xColor for some of the ideas behind these
1804		// <https://github.com/infusion/jQuery-xcolor/blob/master/jquery.xcolor.js>
1805
1806		function complement(color) {
1807			var hsl = tinycolor(color).toHsl();
1808			hsl.h = (hsl.h + 180) % 360;
1809			return tinycolor(hsl);
1810		}
1811
1812		function triad(color) {
1813			var hsl = tinycolor(color).toHsl();
1814			var h = hsl.h;
1815			return [
1816				tinycolor(color),
1817				tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }),
1818				tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l })
1819			];
1820		}
1821
1822		function tetrad(color) {
1823			var hsl = tinycolor(color).toHsl();
1824			var h = hsl.h;
1825			return [
1826				tinycolor(color),
1827				tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }),
1828				tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }),
1829				tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l })
1830			];
1831		}
1832
1833		function splitcomplement(color) {
1834			var hsl = tinycolor(color).toHsl();
1835			var h = hsl.h;
1836			return [
1837				tinycolor(color),
1838				tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l }),
1839				tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l })
1840			];
1841		}
1842
1843		function analogous(color, results, slices) {
1844			results = results || 6;
1845			slices = slices || 30;
1846
1847			var hsl = tinycolor(color).toHsl();
1848			var part = 360 / slices;
1849			var ret = [tinycolor(color)];
1850
1851			for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results;) {
1852				hsl.h = (hsl.h + part) % 360;
1853				ret.push(tinycolor(hsl));
1854			}
1855			return ret;
1856		}
1857
1858		function monochromatic(color, results) {
1859			results = results || 6;
1860			var hsv = tinycolor(color).toHsv();
1861			var h = hsv.h, s = hsv.s, v = hsv.v;
1862			var ret = [];
1863			var modification = 1 / results;
1864
1865			while (results--) {
1866				ret.push(tinycolor({ h: h, s: s, v: v }));
1867				v = (v + modification) % 1;
1868			}
1869
1870			return ret;
1871		}
1872
1873		// Utility Functions
1874		// ---------------------
1875
1876		tinycolor.mix = function (color1, color2, amount) {
1877			amount = (amount === 0) ? 0 : (amount || 50);
1878
1879			var rgb1 = tinycolor(color1).toRgb();
1880			var rgb2 = tinycolor(color2).toRgb();
1881
1882			var p = amount / 100;
1883			var w = p * 2 - 1;
1884			var a = rgb2.a - rgb1.a;
1885
1886			var w1;
1887
1888			if (w * a == -1) {
1889				w1 = w;
1890			} else {
1891				w1 = (w + a) / (1 + w * a);
1892			}
1893
1894			w1 = (w1 + 1) / 2;
1895
1896			var w2 = 1 - w1;
1897
1898			var rgba = {
1899				r: rgb2.r * w1 + rgb1.r * w2,
1900				g: rgb2.g * w1 + rgb1.g * w2,
1901				b: rgb2.b * w1 + rgb1.b * w2,
1902				a: rgb2.a * p + rgb1.a * (1 - p)
1903			};
1904
1905			return tinycolor(rgba);
1906		};
1907
1908
1909		// Readability Functions
1910		// ---------------------
1911		// <http://www.w3.org/TR/AERT#color-contrast>
1912
1913		// `readability`
1914		// Analyze the 2 colors and returns an object with the following properties:
1915		//    `brightness`: difference in brightness between the two colors
1916		//    `color`: difference in color/hue between the two colors
1917		tinycolor.readability = function (color1, color2) {
1918			var c1 = tinycolor(color1);
1919			var c2 = tinycolor(color2);
1920			var rgb1 = c1.toRgb();
1921			var rgb2 = c2.toRgb();
1922			var brightnessA = c1.getBrightness();
1923			var brightnessB = c2.getBrightness();
1924			var colorDiff = (
1925				Math.max(rgb1.r, rgb2.r) - Math.min(rgb1.r, rgb2.r) +
1926				Math.max(rgb1.g, rgb2.g) - Math.min(rgb1.g, rgb2.g) +
1927				Math.max(rgb1.b, rgb2.b) - Math.min(rgb1.b, rgb2.b)
1928			);
1929
1930			return {
1931				brightness: Math.abs(brightnessA - brightnessB),
1932				color: colorDiff
1933			};
1934		};
1935
1936		// `readable`
1937		// http://www.w3.org/TR/AERT#color-contrast
1938		// Ensure that foreground and background color combinations provide sufficient contrast.
1939		// *Example*
1940		//    tinycolor.isReadable("#000", "#111") => false
1941		tinycolor.isReadable = function (color1, color2) {
1942			var readability = tinycolor.readability(color1, color2);
1943			return readability.brightness > 125 && readability.color > 500;
1944		};
1945
1946		// `mostReadable`
1947		// Given a base color and a list of possible foreground or background
1948		// colors for that base, returns the most readable color.
1949		// *Example*
1950		//    tinycolor.mostReadable("#123", ["#fff", "#000"]) => "#000"
1951		tinycolor.mostReadable = function (baseColor, colorList) {
1952			var bestColor = null;
1953			var bestScore = 0;
1954			var bestIsReadable = false;
1955			for (var i = 0; i < colorList.length; i++) {
1956
1957				// We normalize both around the "acceptable" breaking point,
1958				// but rank brightness constrast higher than hue.
1959
1960				var readability = tinycolor.readability(baseColor, colorList[i]);
1961				var readable = readability.brightness > 125 && readability.color > 500;
1962				var score = 3 * (readability.brightness / 125) + (readability.color / 500);
1963
1964				if ((readable && !bestIsReadable) ||
1965					(readable && bestIsReadable && score > bestScore) ||
1966					((!readable) && (!bestIsReadable) && score > bestScore)) {
1967					bestIsReadable = readable;
1968					bestScore = score;
1969					bestColor = tinycolor(colorList[i]);
1970				}
1971			}
1972			return bestColor;
1973		};
1974
1975
1976		// Big List of Colors
1977		// ------------------
1978		// <http://www.w3.org/TR/css3-color/#svg-color>
1979		var names = tinycolor.names = {
1980			aliceblue: "f0f8ff",
1981			antiquewhite: "faebd7",
1982			aqua: "0ff",
1983			aquamarine: "7fffd4",
1984			azure: "f0ffff",
1985			beige: "f5f5dc",
1986			bisque: "ffe4c4",
1987			black: "000",
1988			blanchedalmond: "ffebcd",
1989			blue: "00f",
1990			blueviolet: "8a2be2",
1991			brown: "a52a2a",
1992			burlywood: "deb887",
1993			burntsienna: "ea7e5d",
1994			cadetblue: "5f9ea0",
1995			chartreuse: "7fff00",
1996			chocolate: "d2691e",
1997			coral: "ff7f50",
1998			cornflowerblue: "6495ed",
1999			cornsilk: "fff8dc",
2000			crimson: "dc143c",
2001			cyan: "0ff",
2002			darkblue: "00008b",
2003			darkcyan: "008b8b",
2004			darkgoldenrod: "b8860b",
2005			darkgray: "a9a9a9",
2006			darkgreen: "006400",
2007			darkgrey: "a9a9a9",
2008			darkkhaki: "bdb76b",
2009			darkmagenta: "8b008b",
2010			darkolivegreen: "556b2f",
2011			darkorange: "ff8c00",
2012			darkorchid: "9932cc",
2013			darkred: "8b0000",
2014			darksalmon: "e9967a",
2015			darkseagreen: "8fbc8f",
2016			darkslateblue: "483d8b",
2017			darkslategray: "2f4f4f",
2018			darkslategrey: "2f4f4f",
2019			darkturquoise: "00ced1",
2020			darkviolet: "9400d3",
2021			deeppink: "ff1493",
2022			deepskyblue: "00bfff",
2023			dimgray: "696969",
2024			dimgrey: "696969",
2025			dodgerblue: "1e90ff",
2026			firebrick: "b22222",
2027			floralwhite: "fffaf0",
2028			forestgreen: "228b22",
2029			fuchsia: "f0f",
2030			gainsboro: "dcdcdc",
2031			ghostwhite: "f8f8ff",
2032			gold: "ffd700",
2033			goldenrod: "daa520",
2034			gray: "808080",
2035			green: "008000",
2036			greenyellow: "adff2f",
2037			grey: "808080",
2038			honeydew: "f0fff0",
2039			hotpink: "ff69b4",
2040			indianred: "cd5c5c",
2041			indigo: "4b0082",
2042			ivory: "fffff0",
2043			khaki: "f0e68c",
2044			lavender: "e6e6fa",
2045			lavenderblush: "fff0f5",
2046			lawngreen: "7cfc00",
2047			lemonchiffon: "fffacd",
2048			lightblue: "add8e6",
2049			lightcoral: "f08080",
2050			lightcyan: "e0ffff",
2051			lightgoldenrodyellow: "fafad2",
2052			lightgray: "d3d3d3",
2053			lightgreen: "90ee90",
2054			lightgrey: "d3d3d3",
2055			lightpink: "ffb6c1",
2056			lightsalmon: "ffa07a",
2057			lightseagreen: "20b2aa",
2058			lightskyblue: "87cefa",
2059			lightslategray: "789",
2060			lightslategrey: "789",
2061			lightsteelblue: "b0c4de",
2062			lightyellow: "ffffe0",
2063			lime: "0f0",
2064			limegreen: "32cd32",
2065			linen: "faf0e6",
2066			magenta: "f0f",
2067			maroon: "800000",
2068			mediumaquamarine: "66cdaa",
2069			mediumblue: "0000cd",
2070			mediumorchid: "ba55d3",
2071			mediumpurple: "9370db",
2072			mediumseagreen: "3cb371",
2073			mediumslateblue: "7b68ee",
2074			mediumspringgreen: "00fa9a",
2075			mediumturquoise: "48d1cc",
2076			mediumvioletred: "c71585",
2077			midnightblue: "191970",
2078			mintcream: "f5fffa",
2079			mistyrose: "ffe4e1",
2080			moccasin: "ffe4b5",
2081			navajowhite: "ffdead",
2082			navy: "000080",
2083			oldlace: "fdf5e6",
2084			olive: "808000",
2085			olivedrab: "6b8e23",
2086			orange: "ffa500",
2087			orangered: "ff4500",
2088			orchid: "da70d6",
2089			palegoldenrod: "eee8aa",
2090			palegreen: "98fb98",
2091			paleturquoise: "afeeee",
2092			palevioletred: "db7093",
2093			papayawhip: "ffefd5",
2094			peachpuff: "ffdab9",
2095			peru: "cd853f",
2096			pink: "ffc0cb",
2097			plum: "dda0dd",
2098			powderblue: "b0e0e6",
2099			purple: "800080",
2100			rebeccapurple: "663399",
2101			red: "f00",
2102			rosybrown: "bc8f8f",
2103			royalblue: "4169e1",
2104			saddlebrown: "8b4513",
2105			salmon: "fa8072",
2106			sandybrown: "f4a460",
2107			seagreen: "2e8b57",
2108			seashell: "fff5ee",
2109			sienna: "a0522d",
2110			silver: "c0c0c0",
2111			skyblue: "87ceeb",
2112			slateblue: "6a5acd",
2113			slategray: "708090",
2114			slategrey: "708090",
2115			snow: "fffafa",
2116			springgreen: "00ff7f",
2117			steelblue: "4682b4",
2118			tan: "d2b48c",
2119			teal: "008080",
2120			thistle: "d8bfd8",
2121			tomato: "ff6347",
2122			turquoise: "40e0d0",
2123			violet: "ee82ee",
2124			wheat: "f5deb3",
2125			white: "fff",
2126			whitesmoke: "f5f5f5",
2127			yellow: "ff0",
2128			yellowgreen: "9acd32"
2129		};
2130
2131		// Make it easy to access colors via `hexNames[hex]`
2132		var hexNames = tinycolor.hexNames = flip(names);
2133
2134
2135		// Utilities
2136		// ---------
2137
2138		// `{ 'name1': 'val1' }` becomes `{ 'val1': 'name1' }`
2139		function flip(o) {
2140			var flipped = {};
2141			for (var i in o) {
2142				if (o.hasOwnProperty(i)) {
2143					flipped[o[i]] = i;
2144				}
2145			}
2146			return flipped;
2147		}
2148
2149		// Return a valid alpha value [0,1] with all invalid values being set to 1
2150		function boundAlpha(a) {
2151			a = parseFloat(a);
2152
2153			if (isNaN(a) || a < 0 || a > 1) {
2154				a = 1;
2155			}
2156
2157			return a;
2158		}
2159
2160		// Take input from [0, n] and return it as [0, 1]
2161		function bound01(n, max) {
2162			if (isOnePointZero(n)) {
2163				n = "100%";
2164			}
2165
2166			var processPercent = isPercentage(n);
2167			n = mathMin(max, mathMax(0, parseFloat(n)));
2168
2169			// Automatically convert percentage into number
2170			if (processPercent) {
2171				n = parseInt(n * max, 10) / 100;
2172			}
2173
2174			// Handle floating point rounding errors
2175			if ((math.abs(n - max) < 0.000001)) {
2176				return 1;
2177			}
2178
2179			// Convert into [0, 1] range if it isn't already
2180			return (n % max) / parseFloat(max);
2181		}
2182
2183		// Force a number between 0 and 1
2184		function clamp01(val) {
2185			return mathMin(1, mathMax(0, val));
2186		}
2187
2188		// Parse a base-16 hex value into a base-10 integer
2189		function parseIntFromHex(val) {
2190			return parseInt(val, 16);
2191		}
2192
2193		// Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1
2194		// <http://stackoverflow.com/questions/7422072/javascript-how-to-detect-number-as-a-decimal-including-1-0>
2195		function isOnePointZero(n) {
2196			return typeof n == "string" && n.indexOf('.') != -1 && parseFloat(n) === 1;
2197		}
2198
2199		// Check to see if string passed in is a percentage
2200		function isPercentage(n) {
2201			return typeof n === "string" && n.indexOf('%') != -1;
2202		}
2203
2204		// Force a hex value to have 2 characters
2205		function pad2(c) {
2206			return c.length == 1 ? '0' + c : '' + c;
2207		}
2208
2209		// Replace a decimal with it's percentage value
2210		function convertToPercentage(n) {
2211			if (n <= 1) {
2212				n = (n * 100) + "%";
2213			}
2214
2215			return n;
2216		}
2217
2218		// Converts a decimal to a hex value
2219		function convertDecimalToHex(d) {
2220			return Math.round(parseFloat(d) * 255).toString(16);
2221		}
2222		// Converts a hex value to a decimal
2223		function convertHexToDecimal(h) {
2224			return (parseIntFromHex(h) / 255);
2225		}
2226
2227		var matchers = (function () {
2228
2229			// <http://www.w3.org/TR/css3-values/#integers>
2230			var CSS_INTEGER = "[-\\+]?\\d+%?";
2231
2232			// <http://www.w3.org/TR/css3-values/#number-value>
2233			var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?";
2234
2235			// Allow positive/negative integer/number.  Don't capture the either/or, just the entire outcome.
2236			var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")";
2237
2238			// Actual matching.
2239			// Parentheses and commas are optional, but not required.
2240			// Whitespace can take the place of commas or opening paren
2241			var PERMISSIVE_MATCH3 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?";
2242			var PERMISSIVE_MATCH4 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?";
2243
2244			return {
2245				rgb: new RegExp("rgb" + PERMISSIVE_MATCH3),
2246				rgba: new RegExp("rgba" + PERMISSIVE_MATCH4),
2247				hsl: new RegExp("hsl" + PERMISSIVE_MATCH3),
2248				hsla: new RegExp("hsla" + PERMISSIVE_MATCH4),
2249				hsv: new RegExp("hsv" + PERMISSIVE_MATCH3),
2250				hsva: new RegExp("hsva" + PERMISSIVE_MATCH4),
2251				hex3: /^([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
2252				hex6: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,
2253				hex8: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/
2254			};
2255		})();
2256
2257		// `stringInputToObject`
2258		// Permissive string parsing.  Take in a number of formats, and output an object
2259		// based on detected format.  Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}`
2260		function stringInputToObject(color) {
2261
2262			color = color.replace(trimLeft, '').replace(trimRight, '').toLowerCase();
2263			var named = false;
2264			if (names[color]) {
2265				color = names[color];
2266				named = true;
2267			} else if (color == 'transparent') {
2268				return { r: 0, g: 0, b: 0, a: 0, format: "name" };
2269			}
2270
2271			// Try to match string input using regular expressions.
2272			// Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360]
2273			// Just return an object and let the conversion functions handle that.
2274			// This way the result will be the same whether the tinycolor is initialized with string or object.
2275			var match;
2276			if ((match = matchers.rgb.exec(color))) {
2277				return { r: match[1], g: match[2], b: match[3] };
2278			}
2279			if ((match = matchers.rgba.exec(color))) {
2280				return { r: match[1], g: match[2], b: match[3], a: match[4] };
2281			}
2282			if ((match = matchers.hsl.exec(color))) {
2283				return { h: match[1], s: match[2], l: match[3] };
2284			}
2285			if ((match = matchers.hsla.exec(color))) {
2286				return { h: match[1], s: match[2], l: match[3], a: match[4] };
2287			}
2288			if ((match = matchers.hsv.exec(color))) {
2289				return { h: match[1], s: match[2], v: match[3] };
2290			}
2291			if ((match = matchers.hsva.exec(color))) {
2292				return { h: match[1], s: match[2], v: match[3], a: match[4] };
2293			}
2294			if ((match = matchers.hex8.exec(color))) {
2295				return {
2296					a: convertHexToDecimal(match[1]),
2297					r: parseIntFromHex(match[2]),
2298					g: parseIntFromHex(match[3]),
2299					b: parseIntFromHex(match[4]),
2300					format: named ? "name" : "hex8"
2301				};
2302			}
2303			if ((match = matchers.hex6.exec(color))) {
2304				return {
2305					r: parseIntFromHex(match[1]),
2306					g: parseIntFromHex(match[2]),
2307					b: parseIntFromHex(match[3]),
2308					format: named ? "name" : "hex"
2309				};
2310			}
2311			if ((match = matchers.hex3.exec(color))) {
2312				return {
2313					r: parseIntFromHex(match[1] + '' + match[1]),
2314					g: parseIntFromHex(match[2] + '' + match[2]),
2315					b: parseIntFromHex(match[3] + '' + match[3]),
2316					format: named ? "name" : "hex"
2317				};
2318			}
2319
2320			return false;
2321		}
2322
2323		window.tinycolor = tinycolor;
2324	})();
2325
2326	$(function () {
2327		if ($.fn.spectrum.load) {
2328			$.fn.spectrum.processNativeColorInputs();
2329		}
2330	});
2331
2332});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.