PageSourceSearch

https://www.realescuela.org/wp-content/plugins/user-registration-p…/front/js/afreg_color_spectrum.js?ver=1.0

js realescuela.org collected 2026-09-24 19:03:39 UTC 65,382 bytes, 2,321 lines download raw bytes

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

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.