PageSourceSearch

https://www.backsplash.com/wp-content/plugins/woocommerce-tm-extra…/assets/js/nouislider.js?ver=13.1.1

js backsplash.com collected 2026-09-25 23:40:56 UTC 86,263 bytes, 2,341 lines download raw bytes

vendor: 14,666 bytes, lines 1-417
1/*! nouislider - 15.7.1 - 6/14/2023 */
2// reformatted code by ThemeComplete
3( function( global, factory ) {
4	'use strict';
5
6	factory( global.noUiSlider = {} );
7}( this, ( function( exports ) {
8	'use strict';
9
10	var nouislider;
11	//region Defaults
12	var defaultFormatter = {
13		to: function( value ) {
14			return value === undefined ? '' : value.toFixed( 2 );
15		},
16		from: Number
17	};
18	var cssClasses = {
19		target: 'target',
20		base: 'base',
21		origin: 'origin',
22		handle: 'handle',
23		handleLower: 'handle-lower',
24		handleUpper: 'handle-upper',
25		touchArea: 'touch-area',
26		horizontal: 'horizontal',
27		vertical: 'vertical',
28		background: 'background',
29		connect: 'connect',
30		connects: 'connects',
31		ltr: 'ltr',
32		rtl: 'rtl',
33		textDirectionLtr: 'txt-dir-ltr',
34		textDirectionRtl: 'txt-dir-rtl',
35		draggable: 'draggable',
36		drag: 'state-drag',
37		tap: 'state-tap',
38		active: 'active',
39		tooltip: 'tooltip',
40		pips: 'pips',
41		pipsHorizontal: 'pips-horizontal',
42		pipsVertical: 'pips-vertical',
43		marker: 'marker',
44		markerHorizontal: 'marker-horizontal',
45		markerVertical: 'marker-vertical',
46		markerNormal: 'marker-normal',
47		markerLarge: 'marker-large',
48		markerSub: 'marker-sub',
49		value: 'value',
50		valueHorizontal: 'value-horizontal',
51		valueVertical: 'value-vertical',
52		valueNormal: 'value-normal',
53		valueLarge: 'value-large',
54		valueSub: 'value-sub'
55	};
56	// Namespaces of internal event listeners
57	var INTERNAL_EVENT_NS = {
58		tooltips: '.__tooltips',
59		aria: '.__aria'
60	};
61	//endregion
62	//region Spectrum
63	var Spectrum = /** @class */ ( function() {
64		function Spectrumc( entry, snap, singleStep ) {
65			var index;
66			var ordered = [];
67			this.xPct = [];
68			this.xVal = [];
69			this.xSteps = [];
70			this.xNumSteps = [];
71			this.xHighestCompleteStep = [];
72			this.xSteps = [ singleStep || false ];
73			this.xNumSteps = [ false ];
74			this.snap = snap;
75			// Map the object keys to an array.
76			Object.keys( entry ).forEach( function( iindex ) {
77				ordered.push( [ asArray( entry[ iindex ] ), iindex ] );
78			} );
79			// Sort all entries by value (numeric sort).
80			ordered.sort( function( a, b ) {
81				return a[ 0 ][ 0 ] - b[ 0 ][ 0 ];
82			} );
83			// Convert all entries to subranges.
84			for ( index = 0; index < ordered.length; index++ ) {
85				this.handleEntryPoint( ordered[ index ][ 1 ], ordered[ index ][ 0 ] );
86			}
87			// Store the actual step values.
88			// xSteps is sorted in the same order as xPct and xVal.
89			this.xNumSteps = this.xSteps.slice( 0 );
90			// Convert all numeric steps to the percentage of the subrange they represent.
91			for ( index = 0; index < this.xNumSteps.length; index++ ) {
92				this.handleStepPoint( index, this.xNumSteps[ index ] );
93			}
94		}
95		Spectrumc.prototype.getDistance = function( value ) {
96			var index;
97			var distances = [];
98			for ( index = 0; index < this.xNumSteps.length - 1; index++ ) {
99				distances[ index ] = fromPercentage( this.xVal, value, index );
100			}
101			return distances;
102		};
103		// Calculate the percentual distance over the whole scale of ranges.
104		// direction: 0 = backwards / 1 = forwards
105		Spectrumc.prototype.getAbsoluteDistance = function( value, distances, direction ) {
106			var xPct_index = 0;
107			var start_factor;
108			var rest_factor = 1;
109			var rest_rel_distance;
110			var range_pct = 0;
111			var rel_range_distance = 0;
112			var abs_distance_counter = 0;
113			var range_counter = 0;
114
115			// Calculate range where to start calculation
116			if ( value < this.xPct[ this.xPct.length - 1 ] ) {
117				while ( value > this.xPct[ xPct_index + 1 ] ) {
118					xPct_index++;
119				}
120			} else if ( value === this.xPct[ this.xPct.length - 1 ] ) {
121				xPct_index = this.xPct.length - 2;
122			}
123			// If looking backwards and the value is exactly at a range separator then look one range further
124			if ( ! direction && value === this.xPct[ xPct_index + 1 ] ) {
125				xPct_index++;
126			}
127			if ( distances === null ) {
128				distances = [];
129			}
130			rest_rel_distance = distances[ xPct_index ];
131
132			// Calculate what part of the start range the value is
133			if ( direction ) {
134				start_factor = ( value - this.xPct[ xPct_index ] ) / ( this.xPct[ xPct_index + 1 ] - this.xPct[ xPct_index ] );
135			} else {
136				start_factor = ( this.xPct[ xPct_index + 1 ] - value ) / ( this.xPct[ xPct_index + 1 ] - this.xPct[ xPct_index ] );
137			}
138			// Do until the complete distance across ranges is calculated
139			while ( rest_rel_distance > 0 ) {
140				// Calculate the percentage of total range
141				range_pct = this.xPct[ xPct_index + 1 + range_counter ] - this.xPct[ xPct_index + range_counter ];
142				// Detect if the margin, padding or limit is larger then the current range and calculate
143				if ( ( distances[ xPct_index + range_counter ] * rest_factor ) + 100 - ( start_factor * 100 ) > 100 ) {
144					// If larger then take the percentual distance of the whole range
145					rel_range_distance = range_pct * start_factor;
146					// Rest factor of relative percentual distance still to be calculated
147					rest_factor = ( rest_rel_distance - ( 100 * start_factor ) ) / distances[ xPct_index + range_counter ];
148					// Set start factor to 1 as for next range it does not apply.
149					start_factor = 1;
150				} else {
151					// If smaller or equal then take the percentual distance of the calculate percentual part of that range
152					rel_range_distance = ( ( distances[ xPct_index + range_counter ] * range_pct ) / 100 ) * rest_factor;
153					// No rest left as the rest fits in current range
154					rest_factor = 0;
155				}
156				if ( direction ) {
157					abs_distance_counter = abs_distance_counter - rel_range_distance;
158					// Limit range to first range when distance becomes outside of minimum range
159					if ( this.xPct.length + range_counter >= 1 ) {
160						range_counter--;
161					}
162				} else {
163					abs_distance_counter = abs_distance_counter + rel_range_distance;
164					// Limit range to last range when distance becomes outside of maximum range
165					if ( this.xPct.length - range_counter >= 1 ) {
166						range_counter++;
167					}
168				}
169				// Rest of relative percentual distance still to be calculated
170				rest_rel_distance = distances[ xPct_index + range_counter ] * rest_factor;
171			}
172			return value + abs_distance_counter;
173		};
174		Spectrumc.prototype.toStepping = function( value ) {
175			value = toStepping( this.xVal, this.xPct, value );
176			return value;
177		};
178		Spectrumc.prototype.fromStepping = function( value ) {
179			return fromStepping( this.xVal, this.xPct, value );
180		};
181		Spectrumc.prototype.getStep = function( value ) {
182			value = getStep( this.xPct, this.xSteps, this.snap, value );
183			return value;
184		};
185		Spectrumc.prototype.getDefaultStep = function( value, isDown, size ) {
186			var j = getJ( value, this.xPct );
187			// When at the top or stepping down, look at the previous sub-range
188			if ( value === 100 || ( isDown && value === this.xPct[ j - 1 ] ) ) {
189				j = Math.max( j - 1, 1 );
190			}
191			return ( this.xVal[ j ] - this.xVal[ j - 1 ] ) / size;
192		};
193		Spectrumc.prototype.getNearbySteps = function( value ) {
194			var j = getJ( value, this.xPct );
195			return {
196				stepBefore: {
197					startValue: this.xVal[ j - 2 ],
198					step: this.xNumSteps[ j - 2 ],
199					highestStep: this.xHighestCompleteStep[ j - 2 ]
200				},
201				thisStep: {
202					startValue: this.xVal[ j - 1 ],
203					step: this.xNumSteps[ j - 1 ],
204					highestStep: this.xHighestCompleteStep[ j - 1 ]
205				},
206				stepAfter: {
207					startValue: this.xVal[ j ],
208					step: this.xNumSteps[ j ],
209					highestStep: this.xHighestCompleteStep[ j ]
210				}
211			};
212		};
213		Spectrumc.prototype.countStepDecimals = function() {
214			var stepDecimals = this.xNumSteps.map( countDecimals );
215			return Math.max.apply( null, stepDecimals );
216		};
217		Spectrumc.prototype.hasNoSize = function() {
218			return this.xVal[ 0 ] === this.xVal[ this.xVal.length - 1 ];
219		};
220		// Outside testing
221		Spectrumc.prototype.convert = function( value ) {
222			return this.getStep( this.toStepping( value ) );
223		};
224		Spectrumc.prototype.handleEntryPoint = function( index, value ) {
225			var percentage;
226			var value1;
227			// Covert min/max syntax to 0 and 100.
228			if ( index === 'min' ) {
229				percentage = 0;
230			} else if ( index === 'max' ) {
231				percentage = 100;
232			} else {
233				percentage = parseFloat( index );
234			}
235			// Check for correct input.
236			if ( ! isNumeric( percentage ) || ! isNumeric( value[ 0 ] ) ) {
237				throw new Error( "noUiSlider: 'range' value isn't numeric." );
238			}
239			// Store values.
240			this.xPct.push( percentage );
241			this.xVal.push( value[ 0 ] );
242			value1 = Number( value[ 1 ] );
243			// NaN will evaluate to false too, but to keep
244			// logging clear, set step explicitly. Make sure
245			// not to override the 'step' setting with false.
246			if ( ! percentage ) {
247				if ( ! isNaN( value1 ) ) {
248					this.xSteps[ 0 ] = value1;
249				}
250			} else {
251				this.xSteps.push( isNaN( value1 ) ? false : value1 );
252			}
253			this.xHighestCompleteStep.push( 0 );
254		};
255		Spectrumc.prototype.handleStepPoint = function( i, n ) {
256			var totalSteps;
257			var highestStep;
258			var step;
259			// Ignore 'false' stepping.
260			if ( ! n ) {
261				return;
262			}
263			// Step over zero-length ranges (#948);
264			if ( this.xVal[ i ] === this.xVal[ i + 1 ] ) {
265				this.xSteps[ i ] = this.xHighestCompleteStep[ i ] = this.xVal[ i ];
266				return;
267			}
268			// Factor to range ratio
269			this.xSteps[ i ] =
270                fromPercentage( [ this.xVal[ i ], this.xVal[ i + 1 ] ], n, 0 ) / subRangeRatio( this.xPct[ i ], this.xPct[ i + 1 ] );
271			totalSteps = ( this.xVal[ i + 1 ] - this.xVal[ i ] ) / this.xNumSteps[ i ];
272			highestStep = Math.ceil( Number( totalSteps.toFixed( 3 ) ) - 1 );
273			step = this.xVal[ i ] + ( this.xNumSteps[ i ] * highestStep );
274			this.xHighestCompleteStep[ i ] = step;
275		};
276		return Spectrumc;
277	}() );
278	//endregion
279	exports.PipsMode = void 0;
280	( function( PipsMode ) {
281		PipsMode.Range = 'range';
282		PipsMode.Steps = 'steps';
283		PipsMode.Positions = 'positions';
284		PipsMode.Count = 'count';
285		PipsMode.Values = 'values';
286	}( exports.PipsMode || ( exports.PipsMode = {} ) ) );
287	exports.PipsType = void 0;
288	( function( PipsType ) {
289		PipsType[ PipsType.None = -1 ] = 'None';
290		PipsType[ PipsType.NoValue = 0 ] = 'NoValue';
291		PipsType[ PipsType.LargeValue = 1 ] = 'LargeValue';
292		PipsType[ PipsType.SmallValue = 2 ] = 'SmallValue';
293	}( exports.PipsType || ( exports.PipsType = {} ) ) );
294	//region Helper Methods
295	function isValidFormatter( entry ) {
296		return isValidPartialFormatter( entry ) && typeof entry.from === 'function';
297	}
298	function isValidPartialFormatter( entry ) {
299		// partial formatters only need a to function and not a from function
300		return typeof entry === 'object' && typeof entry.to === 'function';
301	}
302	function removeElement( el ) {
303		el.parentElement.removeChild( el );
304	}
305	function isSet( value ) {
306		return value !== null && value !== undefined;
307	}
308	// Bindable version
309	function preventDefault( e ) {
310		e.preventDefault();
311	}
312	// Removes duplicates from an array.
313	function unique( array ) {
314		return array.filter( function( a ) {
315			return ! this[ a ] ? ( this[ a ] = true ) : false;
316		}, {} );
317	}
318	// Round a value to the closest 'to'.
319	function closest( value, to ) {
320		return Math.round( value / to ) * to;
321	}
322	// Current position of an element relative to the document.
323	function offset( elem, orientation ) {
324		var rect = elem.getBoundingClientRect();
325		var doc = elem.ownerDocument;
326		var docElem = doc.documentElement;
327		var pageOffset = getPageOffset( doc );
328		// getBoundingClientRect contains left scroll in Chrome on Android.
329		// I haven't found a feature detection that proves this. Worst case
330		// scenario on mis-match: the 'tap' feature on horizontal sliders breaks.
331		if ( /webkit.*Chrome.*Mobile/i.test( navigator.userAgent ) ) {
332			pageOffset.x = 0;
333		}
334		return orientation ? rect.top + pageOffset.y - docElem.clientTop : rect.left + pageOffset.x - docElem.clientLeft;
335	}
336	// Checks whether a value is numerical.
337	function isNumeric( a ) {
338		return typeof a === 'number' && ! isNaN( a ) && isFinite( a );
339	}
340	// Sets a class and removes it after [duration] ms.
341	function addClassFor( element, className, duration ) {
342		if ( duration > 0 ) {
343			addClass( element, className );
344			setTimeout( function() {
345				removeClass( element, className );
346			}, duration );
347		}
348	}
349	// Limits a value to 0 - 100
350	function limit( a ) {
351		return Math.max( Math.min( a, 100 ), 0 );
352	}
353	// Wraps a variable as an array, if it isn't one yet.
354	// Note that an input array is returned by reference!
355	function asArray( a ) {
356		return Array.isArray( a ) ? a : [ a ];
357	}
358	// Counts decimals
359	function countDecimals( numStr ) {
360		var pieces;
361		numStr = String( numStr );
362		pieces = numStr.split( '.' );
363		return pieces.length > 1 ? pieces[ 1 ].length : 0;
364	}
365	// http://youmightnotneedjquery.com/#add_class
366	function addClass( el, className ) {
367		if ( el.classList && ! /\s/.test( className ) ) {
368			el.classList.add( className );
369		} else {
370			el.className += ' ' + className;
371		}
372	}
373	// http://youmightnotneedjquery.com/#remove_class
374	function removeClass( el, className ) {
375		if ( el.classList && ! /\s/.test( className ) ) {
376			el.classList.remove( className );
377		} else {
378			el.className = el.className.replace( new RegExp( '(^|\\b)' + className.split( ' ' ).join( '|' ) + '(\\b|$)', 'gi' ), ' ' );
379		}
380	}
381	// https://plainjs.com/javascript/attributes/adding-removing-and-testing-for-classes-9/
382	function hasClass( el, className ) {
383		return el.classList ? el.classList.contains( className ) : new RegExp( '\\b' + className + '\\b' ).test( el.className );
384	}
385	// https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollY#Notes
386	function getPageOffset( doc ) {
387		var supportPageOffset = window.pageXOffset !== undefined;
388		var isCSS1Compat = ( doc.compatMode || '' ) === 'CSS1Compat';
389		var x = supportPageOffset ? window.pageXOffset : isCSS1Compat ? doc.documentElement.scrollLeft : doc.body.scrollLeft;
390		var y = supportPageOffset ? window.pageYOffset : isCSS1Compat ? doc.documentElement.scrollTop : doc.body.scrollTop;
391		return {
392			x: x,
393			y: y
394		};
395	}
396	// we provide a function to compute constants instead
397	// of accessing window.* as soon as the module needs it
398	// so that we do not compute anything if not needed
399	function getActions() {
400		// Determine the events to bind. IE11 implements pointerEvents without
401		// a prefix, which breaks compatibility with the IE10 implementation.
402		return window.navigator.pointerEnabled ? {
403			start: 'pointerdown',
404			move: 'pointermove',
405			end: 'pointerup'
406		} : window.navigator.msPointerEnabled ? {
407			start: 'MSPointerDown',
408			move: 'MSPointerMove',
409			end: 'MSPointerUp'
410		} : {
411			start: 'mousedown touchstart',
412			move: 'mousemove touchmove',
413			end: 'mouseup touchend'
414		};
415	}
416	// https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md
417	// Issue #785
418	function getSupportsPassive() {
419		var supportsPassive = false;
420		/* eslint-disable */
421        try {
422            var opts = Object.defineProperty({}, "passive", {
423                get: function () {
424                    supportsPassive = true;
425                },
426            });
427            // @ts-ignore
428            window.addEventListener("test", null, opts);
429        }
430        catch (e) { }
431        /* eslint-enable */
432		return supportsPassive;
433	}
434	function getSupportsTouchActionNone() {
435		return window.CSS && CSS.supports && CSS.supports( 'touch-action', 'none' );
436	}
437	//endregion
438	//region Range Calculation
439	// Determine the size of a sub-range in relation to a full range.
440	function subRangeRatio( pa, pb ) {
441		return 100 / ( pb - pa );
442	}
443	// (percentage) How many percent is this value of this range?
444	function fromPercentage( range, value, startRange ) {
445		return ( value * 100 ) / ( range[ startRange + 1 ] - range[ startRange ] );
446	}
447	// (percentage) Where is this value on this range?
448	function toPercentage( range, value ) {
449		return fromPercentage( range, range[ 0 ] < 0 ? value + Math.abs( range[ 0 ] ) : value - range[ 0 ], 0 );
450	}
451	// (value) How much is this percentage on this range?
452	function isPercentage( range, value ) {
453		return ( ( value * ( range[ 1 ] - range[ 0 ] ) ) / 100 ) + range[ 0 ];
454	}
455	function getJ( value, arr ) {
456		var j = 1;
457		while ( value >= arr[ j ] ) {
458			j += 1;
459		}
460		return j;
461	}
462	// (percentage) Input a value, find where, on a scale of 0-100, it applies.
463	function toStepping( xVal, xPct, value ) {
464		var j;
465		var va;
466		var vb;
467		var pa;
468		var pb;
469		if ( value >= xVal.slice( -1 )[ 0 ] ) {
470			return 100;
471		}
472		j = getJ( value, xVal );
473		va = xVal[ j - 1 ];
474		vb = xVal[ j ];
475		pa = xPct[ j - 1 ];
476		pb = xPct[ j ];
477		return pa + ( toPercentage( [ va, vb ], value ) / subRangeRatio( pa, pb ) );
478	}
479	// (value) Input a percentage, find where it is on the specified range.
480	function fromStepping( xVal, xPct, value ) {
481		var j;
482		var va;
483		var vb;
484		var pa;
485		var pb;
486		// There is no range group that fits 100
487		if ( value >= 100 ) {
488			return xVal.slice( -1 )[ 0 ];
489		}
490		j = getJ( value, xPct );
491		va = xVal[ j - 1 ];
492		vb = xVal[ j ];
493		pa = xPct[ j - 1 ];
494		pb = xPct[ j ];
495		return isPercentage( [ va, vb ], ( value - pa ) * subRangeRatio( pa, pb ) );
496	}
497	// (percentage) Get the step that applies at a certain value.
498	function getStep( xPct, xSteps, snap, value ) {
499		var j;
500		var a;
501		var b;
502		if ( value === 100 ) {
503			return value;
504		}
505		j = getJ( value, xPct );
506		a = xPct[ j - 1 ];
507		b = xPct[ j ];
508		// If 'snap' is set, steps are used as fixed points on the slider.
509		if ( snap ) {
510			// Find the closest position, a or b.
511			if ( value - a > ( b - a ) / 2 ) {
512				return b;
513			}
514			return a;
515		}
516		if ( ! xSteps[ j - 1 ] ) {
517			return value;
518		}
519		return xPct[ j - 1 ] + closest( value - xPct[ j - 1 ], xSteps[ j - 1 ] );
520	}
521	//endregion
522	//region Options
523	/*	Every input option is tested and parsed. This will prevent
524        endless validation in internal methods. These tests are
525        structured with an item for every option available. An
526        option can be marked as required by setting the 'r' flag.
527        The testing function is provided with three arguments:
528            - The provided value for the option;
529            - A reference to the options object;
530            - The name for the option;
531
532        The testing function returns false when an error is detected,
533        or true when everything is OK. It can also modify the option
534        object, to make sure all values can be correctly looped elsewhere. */
535
536	function testStep( parsed, entry ) {
537		if ( ! isNumeric( entry ) ) {
538			throw new Error( "noUiSlider: 'step' is not numeric." );
539		}
540		// The step option can still be used to set stepping
541		// for linear sliders. Overwritten if set in 'range'.
542		parsed.singleStep = entry;
543	}
544	function testKeyboardPageMultiplier( parsed, entry ) {
545		if ( ! isNumeric( entry ) ) {
546			throw new Error( "noUiSlider: 'keyboardPageMultiplier' is not numeric." );
547		}
548		parsed.keyboardPageMultiplier = entry;
549	}
550	function testKeyboardMultiplier( parsed, entry ) {
551		if ( ! isNumeric( entry ) ) {
552			throw new Error( "noUiSlider: 'keyboardMultiplier' is not numeric." );
553		}
554		parsed.keyboardMultiplier = entry;
555	}
556	function testKeyboardDefaultStep( parsed, entry ) {
557		if ( ! isNumeric( entry ) ) {
558			throw new Error( "noUiSlider: 'keyboardDefaultStep' is not numeric." );
559		}
560		parsed.keyboardDefaultStep = entry;
561	}
562	function testRange( parsed, entry ) {
563		// Filter incorrect input.
564		if ( typeof entry !== 'object' || Array.isArray( entry ) ) {
565			throw new Error( "noUiSlider: 'range' is not an object." );
566		}
567		// Catch missing start or end.
568		if ( entry.min === undefined || entry.max === undefined ) {
569			throw new Error( "noUiSlider: Missing 'min' or 'max' in 'range'." );
570		}
571		parsed.spectrum = new Spectrum( entry, parsed.snap || false, parsed.singleStep );
572	}
573	function testStart( parsed, entry ) {
574		entry = asArray( entry );
575		// Validate input. Values aren't tested, as the public .val method
576		// will always provide a valid location.
577		if ( ! Array.isArray( entry ) || ! entry.length ) {
578			throw new Error( "noUiSlider: 'start' option is incorrect." );
579		}
580		// Store the number of handles.
581		parsed.handles = entry.length;
vendor: 7,473 bytes, lines 582-808
582		// When the slider is initialized, the .val method will
583		// be called with the start options.
584		parsed.start = entry;
585	}
586	function testSnap( parsed, entry ) {
587		if ( typeof entry !== 'boolean' ) {
588			throw new Error( "noUiSlider: 'snap' option must be a boolean." );
589		}
590		// Enforce 100% stepping within subranges.
591		parsed.snap = entry;
592	}
593	function testAnimate( parsed, entry ) {
594		if ( typeof entry !== 'boolean' ) {
595			throw new Error( "noUiSlider: 'animate' option must be a boolean." );
596		}
597		// Enforce 100% stepping within subranges.
598		parsed.animate = entry;
599	}
600	function testAnimationDuration( parsed, entry ) {
601		if ( typeof entry !== 'number' ) {
602			throw new Error( "noUiSlider: 'animationDuration' option must be a number." );
603		}
604		parsed.animationDuration = entry;
605	}
606	function testConnect( parsed, entry ) {
607		var connect = [ false ];
608		var i;
609		// Map legacy options
610		if ( entry === 'lower' ) {
611			entry = [ true, false ];
612		} else if ( entry === 'upper' ) {
613			entry = [ false, true ];
614		}
615		// Handle boolean options
616		if ( entry === true || entry === false ) {
617			for ( i = 1; i < parsed.handles; i++ ) {
618				connect.push( entry );
619			}
620			connect.push( false );
621		} else if ( ! Array.isArray( entry ) || ! entry.length || entry.length !== parsed.handles + 1 ) { // Reject invalid input
622			throw new Error( "noUiSlider: 'connect' option doesn't match handle count." );
623		} else {
624			connect = entry;
625		}
626		parsed.connect = connect;
627	}
628	function testOrientation( parsed, entry ) {
629		// Set orientation to an a numerical value for easy
630		// array selection.
631		switch ( entry ) {
632			case 'horizontal':
633				parsed.ort = 0;
634				break;
635			case 'vertical':
636				parsed.ort = 1;
637				break;
638			default:
639				throw new Error( "noUiSlider: 'orientation' option is invalid." );
640		}
641	}
642	function testMargin( parsed, entry ) {
643		if ( ! isNumeric( entry ) ) {
644			throw new Error( "noUiSlider: 'margin' option must be numeric." );
645		}
646		// Issue #582
647		if ( entry === 0 ) {
648			return;
649		}
650		parsed.margin = parsed.spectrum.getDistance( entry );
651	}
652	function testLimit( parsed, entry ) {
653		if ( ! isNumeric( entry ) ) {
654			throw new Error( "noUiSlider: 'limit' option must be numeric." );
655		}
656		parsed.limit = parsed.spectrum.getDistance( entry );
657		if ( ! parsed.limit || parsed.handles < 2 ) {
658			throw new Error( "noUiSlider: 'limit' option is only supported on linear sliders with 2 or more handles." );
659		}
660	}
661	function testPadding( parsed, entry ) {
662		var index;
663		var totalPadding;
664		var firstValue;
665		var lastValue;
666		if ( ! isNumeric( entry ) && ! Array.isArray( entry ) ) {
667			throw new Error( "noUiSlider: 'padding' option must be numeric or array of exactly 2 numbers." );
668		}
669		if ( Array.isArray( entry ) && ! ( entry.length === 2 || isNumeric( entry[ 0 ] ) || isNumeric( entry[ 1 ] ) ) ) {
670			throw new Error( "noUiSlider: 'padding' option must be numeric or array of exactly 2 numbers." );
671		}
672		if ( entry === 0 ) {
673			return;
674		}
675		if ( ! Array.isArray( entry ) ) {
676			entry = [ entry, entry ];
677		}
678		// 'getDistance' returns false for invalid values.
679		parsed.padding = [ parsed.spectrum.getDistance( entry[ 0 ] ), parsed.spectrum.getDistance( entry[ 1 ] ) ];
680		for ( index = 0; index < parsed.spectrum.xNumSteps.length - 1; index++ ) {
681			// last "range" can't contain step size as it is purely an endpoint.
682			if ( parsed.padding[ 0 ][ index ] < 0 || parsed.padding[ 1 ][ index ] < 0 ) {
683				throw new Error( "noUiSlider: 'padding' option must be a positive number(s)." );
684			}
685		}
686		totalPadding = entry[ 0 ] + entry[ 1 ];
687		firstValue = parsed.spectrum.xVal[ 0 ];
688		lastValue = parsed.spectrum.xVal[ parsed.spectrum.xVal.length - 1 ];
689		if ( totalPadding / ( lastValue - firstValue ) > 1 ) {
690			throw new Error( "noUiSlider: 'padding' option must not exceed 100% of the range." );
691		}
692	}
693	function testDirection( parsed, entry ) {
694		// Set direction as a numerical value for easy parsing.
695		// Invert connection for RTL sliders, so that the proper
696		// handles get the connect/background classes.
697		switch ( entry ) {
698			case 'ltr':
699				parsed.dir = 0;
700				break;
701			case 'rtl':
702				parsed.dir = 1;
703				break;
704			default:
705				throw new Error( "noUiSlider: 'direction' option was not recognized." );
706		}
707	}
708	function testBehaviour( parsed, entry ) {
709		var tap;
710		var drag;
711		var fixed;
712		var snap;
713		var hover;
714		var unconstrained;
715		var dragAll;
716		var smoothSteps;
717		// Make sure the input is a string.
718		if ( typeof entry !== 'string' ) {
719			throw new Error( "noUiSlider: 'behaviour' must be a string containing options." );
720		}
721		// Check if the string contains any keywords.
722		// None are required.
723		tap = entry.indexOf( 'tap' ) >= 0;
724		drag = entry.indexOf( 'drag' ) >= 0;
725		fixed = entry.indexOf( 'fixed' ) >= 0;
726		snap = entry.indexOf( 'snap' ) >= 0;
727		hover = entry.indexOf( 'hover' ) >= 0;
728		unconstrained = entry.indexOf( 'unconstrained' ) >= 0;
729		dragAll = entry.indexOf( 'drag-all' ) >= 0;
730		smoothSteps = entry.indexOf( 'smooth-steps' ) >= 0;
731		if ( fixed ) {
732			if ( parsed.handles !== 2 ) {
733				throw new Error( "noUiSlider: 'fixed' behaviour must be used with 2 handles" );
734			}
735			// Use margin to enforce fixed state
736			testMargin( parsed, parsed.start[ 1 ] - parsed.start[ 0 ] );
737		}
738		if ( unconstrained && ( parsed.margin || parsed.limit ) ) {
739			throw new Error( "noUiSlider: 'unconstrained' behaviour cannot be used with margin or limit" );
740		}
741		parsed.events = {
742			tap: tap || snap,
743			drag: drag,
744			dragAll: dragAll,
745			smoothSteps: smoothSteps,
746			fixed: fixed,
747			snap: snap,
748			hover: hover,
749			unconstrained: unconstrained
750		};
751	}
752	function testTooltips( parsed, entry ) {
753		var i;
754		if ( entry === false ) {
755			return;
756		}
757		if ( entry === true || isValidPartialFormatter( entry ) ) {
758			parsed.tooltips = [];
759			for ( i = 0; i < parsed.handles; i++ ) {
760				parsed.tooltips.push( entry );
761			}
762		} else {
763			entry = asArray( entry );
764			if ( entry.length !== parsed.handles ) {
765				throw new Error( 'noUiSlider: must pass a formatter for all handles.' );
766			}
767			entry.forEach( function( formatter ) {
768				if ( typeof formatter !== 'boolean' && ! isValidPartialFormatter( formatter ) ) {
769					throw new Error( "noUiSlider: 'tooltips' must be passed a formatter or 'false'." );
770				}
771			} );
772			parsed.tooltips = entry;
773		}
774	}
775	function testHandleAttributes( parsed, entry ) {
776		if ( entry.length !== parsed.handles ) {
777			throw new Error( 'noUiSlider: must pass a attributes for all handles.' );
778		}
779		parsed.handleAttributes = entry;
780	}
781	function testAriaFormat( parsed, entry ) {
782		if ( ! isValidPartialFormatter( entry ) ) {
783			throw new Error( "noUiSlider: 'ariaFormat' requires 'to' method." );
784		}
785		parsed.ariaFormat = entry;
786	}
787	function testFormat( parsed, entry ) {
788		if ( ! isValidFormatter( entry ) ) {
789			throw new Error( "noUiSlider: 'format' requires 'to' and 'from' methods." );
790		}
791		parsed.format = entry;
792	}
793	function testKeyboardSupport( parsed, entry ) {
794		if ( typeof entry !== 'boolean' ) {
795			throw new Error( "noUiSlider: 'keyboardSupport' option must be a boolean." );
796		}
797		parsed.keyboardSupport = entry;
798	}
799	function testDocumentElement( parsed, entry ) {
800		// This is an advanced option. Passed values are used without validation.
801		parsed.documentElement = entry;
802	}
803	function testCssPrefix( parsed, entry ) {
804		if ( typeof entry !== 'string' && entry !== false ) {
805			throw new Error( "noUiSlider: 'cssPrefix' must be a string or `false`." );
806		}
807		parsed.cssPrefix = entry;
808	}
809	function testCssClasses( parsed, entry ) {
810		if ( typeof entry !== 'object' ) {
811			throw new Error( "noUiSlider: 'cssClasses' must be an object." );
812		}
813		if ( typeof parsed.cssPrefix === 'string' ) {
814			parsed.cssClasses = {};
815			Object.keys( entry ).forEach( function( key ) {
816				parsed.cssClasses[ key ] = parsed.cssPrefix + entry[ key ];
817			} );
818		} else {
819			parsed.cssClasses = entry;
820		}
821	}
822	// Test all developer settings and parse to assumption-safe values.
823	function testOptions( options ) {
824		// To prove a fix for #537, freeze options here.
825		// If the object is modified, an error will be thrown.
826		// Object.freeze(options);
827		var parsed = {
828			margin: null,
829			limit: null,
830			padding: null,
831			animate: true,
832			animationDuration: 300,
833			ariaFormat: defaultFormatter,
834			format: defaultFormatter
835		};
836		// Tests are executed in the order they are presented here.
837		var tests = {
838			step: { r: false, t: testStep },
839			keyboardPageMultiplier: { r: false, t: testKeyboardPageMultiplier },
840			keyboardMultiplier: { r: false, t: testKeyboardMultiplier },
841			keyboardDefaultStep: { r: false, t: testKeyboardDefaultStep },
842			start: { r: true, t: testStart },
843			connect: { r: true, t: testConnect },
844			direction: { r: true, t: testDirection },
845			snap: { r: false, t: testSnap },
846			animate: { r: false, t: testAnimate },
847			animationDuration: { r: false, t: testAnimationDuration },
848			range: { r: true, t: testRange },
849			orientation: { r: false, t: testOrientation },
850			margin: { r: false, t: testMargin },
851			limit: { r: false, t: testLimit },
852			padding: { r: false, t: testPadding },
853			behaviour: { r: true, t: testBehaviour },
854			ariaFormat: { r: false, t: testAriaFormat },
855			format: { r: false, t: testFormat },
856			tooltips: { r: false, t: testTooltips },
857			keyboardSupport: { r: true, t: testKeyboardSupport },
858			documentElement: { r: false, t: testDocumentElement },
859			cssPrefix: { r: true, t: testCssPrefix },
860			cssClasses: { r: true, t: testCssClasses },
861			handleAttributes: { r: false, t: testHandleAttributes }
862		};
863		var defaults = {
864			connect: false,
865			direction: 'ltr',
866			behaviour: 'tap',
867			orientation: 'horizontal',
868			keyboardSupport: true,
869			cssPrefix: 'noui-',
870			cssClasses: cssClasses,
871			keyboardPageMultiplier: 5,
872			keyboardMultiplier: 1,
873			keyboardDefaultStep: 10
874		};
875		var d;
876		var msPrefix;
877		var noPrefix;
878		var styles;
879		// AriaFormat defaults to regular format, if any.
880		if ( options.format && ! options.ariaFormat ) {
881			options.ariaFormat = options.format;
882		}
883		// Run all options through a testing mechanism to ensure correct
884		// input. It should be noted that options might get modified to
885		// be handled properly. E.g. wrapping integers in arrays.
886		Object.keys( tests ).forEach( function( name ) {
887			// If the option isn't set, but it is required, throw an error.
888			if ( ! isSet( options[ name ] ) && defaults[ name ] === undefined ) {
889				if ( tests[ name ].r ) {
890					throw new Error( "noUiSlider: '" + name + "' is required." );
891				}
892				return;
893			}
894			tests[ name ].t( parsed, ! isSet( options[ name ] ) ? defaults[ name ] : options[ name ] );
895		} );
896		// Forward pips options
897		parsed.pips = options.pips;
898		// All recent browsers accept unprefixed transform.
899		// We need -ms- for IE9 and -webkit- for older Android;
900		// Assume use of -webkit- if unprefixed and -ms- are not supported.
901		// https://caniuse.com/#feat=transforms2d
902		d = document.createElement( 'div' );
903		msPrefix = d.style.msTransform !== undefined;
904		noPrefix = d.style.transform !== undefined;
905		parsed.transformRule = noPrefix ? 'transform' : msPrefix ? 'msTransform' : 'webkitTransform';
906		// Pips don't move, so we can place them using left/top.
907		styles = [
908			[ 'left', 'top' ],
909			[ 'right', 'bottom' ]
910		];
911		parsed.style = styles[ parsed.dir ][ parsed.ort ];
912		return parsed;
913	}
914	//endregion
915	function scope( target, options, originalOptions ) {
916		var actions = getActions();
917		var supportsTouchActionNone = getSupportsTouchActionNone();
918		var supportsPassive = supportsTouchActionNone && getSupportsPassive();
919		// All variables local to 'scope' are prefixed with 'scope_'
920		// Slider DOM Nodes
921		var scope_Target = target;
922		var scope_Base;
923		var scope_Handles;
924		var scope_Connects;
925		var scope_Pips;
926		var scope_Tooltips;
927		// Slider state values
928		var scope_Spectrum = options.spectrum;
929		var scope_Values = [];
930		var scope_Locations = [];
931		var scope_HandleNumbers = [];
932		var scope_ActiveHandlesCount = 0;
933		var scope_Events = {};
934		// Document Nodes
935		var scope_Document = target.ownerDocument;
936		var scope_DocumentElement = options.documentElement || scope_Document.documentElement;
937		var scope_Body = scope_Document.body;
938		// For horizontal sliders in standard ltr documents,
939		// make .noUi-origin overflow to the left so the document doesn't scroll.
940		var scope_DirOffset = scope_Document.dir === 'rtl' || options.ort === 1 ? 0 : 100;
941		var scope_Self;
942		// Creates a node, adds it to target, returns the new node.
943		function addNodeTo( addTarget, className ) {
944			var div = scope_Document.createElement( 'div' );
945			if ( className ) {
946				addClass( div, className );
947			}
948			addTarget.appendChild( div );
949			return div;
950		}
951		// Append a origin to the base
952		function addOrigin( base, handleNumber ) {
953			var origin = addNodeTo( base, options.cssClasses.origin );
954			var handle = addNodeTo( origin, options.cssClasses.handle );
955			var attributes_1;
956			addNodeTo( handle, options.cssClasses.touchArea );
957			handle.setAttribute( 'data-handle', String( handleNumber ) );
958			if ( options.keyboardSupport ) {
959				// https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex
960				// 0 = focusable and reachable
961				handle.setAttribute( 'tabindex', '0' );
962				handle.addEventListener( 'keydown', function( event ) {
vendor: 19,677 bytes, lines 963-1460
963					return eventKeydown( event, handleNumber );
964				} );
965			}
966			if ( options.handleAttributes !== undefined ) {
967				attributes_1 = options.handleAttributes[ handleNumber ];
968				Object.keys( attributes_1 ).forEach( function( attribute ) {
969					handle.setAttribute( attribute, attributes_1[ attribute ] );
970				} );
971			}
972			handle.setAttribute( 'role', 'slider' );
973			handle.setAttribute( 'aria-orientation', options.ort ? 'vertical' : 'horizontal' );
974			if ( handleNumber === 0 ) {
975				addClass( handle, options.cssClasses.handleLower );
976			} else if ( handleNumber === options.handles - 1 ) {
977				addClass( handle, options.cssClasses.handleUpper );
978			}
979			origin.handle = handle;
980			return origin;
981		}
982		// Insert nodes for connect elements
983		function addConnect( base, add ) {
984			if ( ! add ) {
985				return false;
986			}
987			return addNodeTo( base, options.cssClasses.connect );
988		}
989		// Add handles to the slider base.
990		function addElements( connectOptions, base ) {
991			var connectBase = addNodeTo( base, options.cssClasses.connects );
992			var i;
993			scope_Handles = [];
994			scope_Connects = [];
995			scope_Connects.push( addConnect( connectBase, connectOptions[ 0 ] ) );
996			// [::::O====O====O====]
997			// connectOptions = [0, 1, 1, 1]
998			for ( i = 0; i < options.handles; i++ ) {
999				// Keep a list of all added handles.
1000				scope_Handles.push( addOrigin( base, i ) );
1001				scope_HandleNumbers[ i ] = i;
1002				scope_Connects.push( addConnect( connectBase, connectOptions[ i + 1 ] ) );
1003			}
1004		}
1005		// Initialize a single slider.
1006		function addSlider( addTarget ) {
1007			var textDirection;
1008			// Apply classes and data to the target.
1009			addClass( addTarget, options.cssClasses.target );
1010			if ( options.dir === 0 ) {
1011				addClass( addTarget, options.cssClasses.ltr );
1012			} else {
1013				addClass( addTarget, options.cssClasses.rtl );
1014			}
1015			if ( options.ort === 0 ) {
1016				addClass( addTarget, options.cssClasses.horizontal );
1017			} else {
1018				addClass( addTarget, options.cssClasses.vertical );
1019			}
1020			textDirection = getComputedStyle( addTarget ).direction;
1021			if ( textDirection === 'rtl' ) {
1022				addClass( addTarget, options.cssClasses.textDirectionRtl );
1023			} else {
1024				addClass( addTarget, options.cssClasses.textDirectionLtr );
1025			}
1026			return addNodeTo( addTarget, options.cssClasses.base );
1027		}
1028		function addTooltip( handle, handleNumber ) {
1029			if ( ! options.tooltips || ! options.tooltips[ handleNumber ] ) {
1030				return false;
1031			}
1032			return addNodeTo( handle.firstChild, options.cssClasses.tooltip );
1033		}
1034		function isSliderDisabled() {
1035			return scope_Target.hasAttribute( 'disabled' );
1036		}
1037		// Disable the slider dragging if any handle is disabled
1038		function isHandleDisabled( handleNumber ) {
1039			var handleOrigin = scope_Handles[ handleNumber ];
1040			return handleOrigin.hasAttribute( 'disabled' );
1041		}
1042		function disable( handleNumber ) {
1043			if ( handleNumber !== null && handleNumber !== undefined ) {
1044				scope_Handles[ handleNumber ].setAttribute( 'disabled', '' );
1045				scope_Handles[ handleNumber ].handle.removeAttribute( 'tabindex' );
1046			} else {
1047				scope_Target.setAttribute( 'disabled', '' );
1048				scope_Handles.forEach( function( handle ) {
1049					handle.handle.removeAttribute( 'tabindex' );
1050				} );
1051			}
1052		}
1053		function enable( handleNumber ) {
1054			if ( handleNumber !== null && handleNumber !== undefined ) {
1055				scope_Handles[ handleNumber ].removeAttribute( 'disabled' );
1056				scope_Handles[ handleNumber ].handle.setAttribute( 'tabindex', '0' );
1057			} else {
1058				scope_Target.removeAttribute( 'disabled' );
1059				scope_Handles.forEach( function( handle ) {
1060					handle.removeAttribute( 'disabled' );
1061					handle.handle.setAttribute( 'tabindex', '0' );
1062				} );
1063			}
1064		}
1065		function removeTooltips() {
1066			if ( scope_Tooltips ) {
1067				removeEvent( 'update' + INTERNAL_EVENT_NS.tooltips );
1068				scope_Tooltips.forEach( function( tooltip ) {
1069					if ( tooltip ) {
1070						removeElement( tooltip );
1071					}
1072				} );
1073				scope_Tooltips = null;
1074			}
1075		}
1076		// The tooltips option is a shorthand for using the 'update' event.
1077		function tooltips() {
1078			var formattedValue;
1079			removeTooltips();
1080			// Tooltips are added with options.tooltips in original order.
1081			scope_Tooltips = scope_Handles.map( addTooltip );
1082			bindEvent( 'update' + INTERNAL_EVENT_NS.tooltips, function( values, handleNumber, unencoded ) {
1083				if ( ! scope_Tooltips || ! options.tooltips ) {
1084					return;
1085				}
1086				if ( scope_Tooltips[ handleNumber ] === false ) {
1087					return;
1088				}
1089				formattedValue = values[ handleNumber ];
1090				if ( options.tooltips[ handleNumber ] !== true ) {
1091					formattedValue = options.tooltips[ handleNumber ].to( unencoded[ handleNumber ] );
1092				}
1093				scope_Tooltips[ handleNumber ].innerHTML = formattedValue;
1094			} );
1095		}
1096		function aria() {
1097			removeEvent( 'update' + INTERNAL_EVENT_NS.aria );
1098			bindEvent( 'update' + INTERNAL_EVENT_NS.aria, function( values, handleNumber, unencoded, tap, positions ) {
1099				// Update Aria Values for all handles, as a change in one changes min and max values for the next.
1100				scope_HandleNumbers.forEach( function( index ) {
1101					var handle = scope_Handles[ index ];
1102					var min = checkHandlePosition( scope_Locations, index, 0, true, true, true );
1103					var max = checkHandlePosition( scope_Locations, index, 100, true, true, true );
1104					var now = positions[ index ];
1105					// Formatted value for display
1106					var text = String( options.ariaFormat.to( unencoded[ index ] ) );
1107					// Map to slider range values
1108					min = scope_Spectrum.fromStepping( min ).toFixed( 1 );
1109					max = scope_Spectrum.fromStepping( max ).toFixed( 1 );
1110					now = scope_Spectrum.fromStepping( now ).toFixed( 1 );
1111					handle.children[ 0 ].setAttribute( 'aria-valuemin', min );
1112					handle.children[ 0 ].setAttribute( 'aria-valuemax', max );
1113					handle.children[ 0 ].setAttribute( 'aria-valuenow', now );
1114					handle.children[ 0 ].setAttribute( 'aria-valuetext', text );
1115				} );
1116			} );
1117		}
1118		function getGroup( ipips ) {
1119			var interval;
1120			var spread;
1121			var values;
1122			// Use the range.
1123			if ( ipips.mode === exports.PipsMode.Range || ipips.mode === exports.PipsMode.Steps ) {
1124				return scope_Spectrum.xVal;
1125			}
1126			if ( ipips.mode === exports.PipsMode.Count ) {
1127				if ( ipips.values < 2 ) {
1128					throw new Error( "noUiSlider: 'values' (>= 2) required for mode 'count'." );
1129				}
1130				// Divide 0 - 100 in 'count' parts.
1131				interval = ipips.values - 1;
1132				spread = 100 / interval;
1133				values = [];
1134				// List these parts and have them handled as 'positions'.
1135				while ( interval-- ) {
1136					values[ interval ] = interval * spread;
1137				}
1138				values.push( 100 );
1139				return mapToRange( values, ipips.stepped );
1140			}
1141			if ( ipips.mode === exports.PipsMode.Positions ) {
1142				// Map all percentages to on-range values.
1143				return mapToRange( ipips.values, ipips.stepped );
1144			}
1145			if ( ipips.mode === exports.PipsMode.Values ) {
1146				// If the value must be stepped, it needs to be converted to a percentage first.
1147				if ( ipips.stepped ) {
1148					return ipips.values.map( function( value ) {
1149						// Convert to percentage, apply step, return to value.
1150						return scope_Spectrum.fromStepping( scope_Spectrum.getStep( scope_Spectrum.toStepping( value ) ) );
1151					} );
1152				}
1153				// Otherwise, we can simply use the values.
1154				return ipips.values;
1155			}
1156			return []; // ipips.mode = never
1157		}
1158		function mapToRange( values, stepped ) {
1159			return values.map( function( value ) {
1160				return scope_Spectrum.fromStepping( stepped ? scope_Spectrum.getStep( value ) : value );
1161			} );
1162		}
1163		function generateSpread( ipips ) {
1164			var group = getGroup( ipips );
1165			var indexes = {};
1166			var firstInRange = scope_Spectrum.xVal[ 0 ];
1167			var lastInRange = scope_Spectrum.xVal[ scope_Spectrum.xVal.length - 1 ];
1168			var ignoreFirst = false;
1169			var ignoreLast = false;
1170			var prevPct = 0;
1171			function safeIncrement( value, increment ) {
1172				// Avoid floating point variance by dropping the smallest decimal places.
1173				return Number( ( value + increment ).toFixed( 7 ) );
1174			}
1175			// Create a copy of the group, sort it and filter away all duplicates.
1176			group = unique( group.slice().sort( function( a, b ) {
1177				return a - b;
1178			} ) );
1179			// Make sure the range starts with the first element.
1180			if ( group[ 0 ] !== firstInRange ) {
1181				group.unshift( firstInRange );
1182				ignoreFirst = true;
1183			}
1184			// Likewise for the last one.
1185			if ( group[ group.length - 1 ] !== lastInRange ) {
1186				group.push( lastInRange );
1187				ignoreLast = true;
1188			}
1189			group.forEach( function( current, index ) {
1190				// Get the current step and the lower + upper positions.
1191				var step;
1192				var i;
1193				var q;
1194				var low = current;
1195				var high = group[ index + 1 ];
1196				var newPct;
1197				var pctDifference;
1198				var pctPos;
1199				var type;
1200				var steps;
1201				var realSteps;
1202				var stepSize;
1203				var isSteps = ipips.mode === exports.PipsMode.Steps;
1204				// When using 'steps' mode, use the provided steps.
1205				// Otherwise, we'll step on to the next subrange.
1206				if ( isSteps ) {
1207					step = scope_Spectrum.xNumSteps[ index ];
1208				}
1209				// Default to a 'full' step.
1210				if ( ! step ) {
1211					step = high - low;
1212				}
1213				// If high is undefined we are at the last subrange. Make sure it iterates once (#1088)
1214				if ( high === undefined ) {
1215					high = low;
1216				}
1217				// Make sure step isn't 0, which would cause an infinite loop (#654)
1218				step = Math.max( step, 0.0000001 );
1219				// Find all steps in the subrange.
1220				for ( i = low; i <= high; i = safeIncrement( i, step ) ) {
1221					// Get the percentage value for the current step,
1222					// calculate the size for the subrange.
1223					newPct = scope_Spectrum.toStepping( i );
1224					pctDifference = newPct - prevPct;
1225					steps = pctDifference / ( ipips.density || 1 );
1226					realSteps = Math.round( steps );
1227					// This ratio represents the amount of percentage-space a point indicates.
1228					// For a density 1 the points/percentage = 1. For density 2, that percentage needs to be re-divided.
1229					// Round the percentage offset to an even number, then divide by two
1230					// to spread the offset on both sides of the range.
1231					stepSize = pctDifference / realSteps;
1232					// Divide all points evenly, adding the correct number to this subrange.
1233					// Run up to <= so that 100% gets a point, event if ignoreLast is set.
1234					for ( q = 1; q <= realSteps; q += 1 ) {
1235						// The ratio between the rounded value and the actual size might be ~1% off.
1236						// Correct the percentage offset by the number of points
1237						// per subrange. density = 1 will result in 100 points on the
1238						// full range, 2 for 50, 4 for 25, etc.
1239						pctPos = prevPct + ( q * stepSize );
1240						indexes[ pctPos.toFixed( 5 ) ] = [ scope_Spectrum.fromStepping( pctPos ), 0 ];
1241					}
1242					// Determine the point type.
1243					type = group.indexOf( i ) > -1 ? exports.PipsType.LargeValue : isSteps ? exports.PipsType.SmallValue : exports.PipsType.NoValue;
1244					// Enforce the 'ignoreFirst' option by overwriting the type for 0.
1245					if ( ! index && ignoreFirst && i !== high ) {
1246						type = 0;
1247					}
1248					if ( ! ( i === high && ignoreLast ) ) {
1249						// Mark the 'type' of this point. 0 = plain, 1 = real value, 2 = step value.
1250						indexes[ newPct.toFixed( 5 ) ] = [ i, type ];
1251					}
1252					// Update the percentage count.
1253					prevPct = newPct;
1254				}
1255			} );
1256			return indexes;
1257		}
1258		function addMarking( spread, filterFunc, formatter ) {
1259			var _a, _b;
1260			var element = scope_Document.createElement( 'div' );
1261			var valueSizeClasses = ( _a = {},
1262			_a[ exports.PipsType.None ] = '',
1263			_a[ exports.PipsType.NoValue ] = options.cssClasses.valueNormal,
1264			_a[ exports.PipsType.LargeValue ] = options.cssClasses.valueLarge,
1265			_a[ exports.PipsType.SmallValue ] = options.cssClasses.valueSub,
1266			_a );
1267			var markerSizeClasses = ( _b = {},
1268			_b[ exports.PipsType.None ] = '',
1269			_b[ exports.PipsType.NoValue ] = options.cssClasses.markerNormal,
1270			_b[ exports.PipsType.LargeValue ] = options.cssClasses.markerLarge,
1271			_b[ exports.PipsType.SmallValue ] = options.cssClasses.markerSub,
1272			_b );
1273			var valueOrientationClasses = [ options.cssClasses.valueHorizontal, options.cssClasses.valueVertical ];
1274			var markerOrientationClasses = [ options.cssClasses.markerHorizontal, options.cssClasses.markerVertical ];
1275			addClass( element, options.cssClasses.pips );
1276			addClass( element, options.ort === 0 ? options.cssClasses.pipsHorizontal : options.cssClasses.pipsVertical );
1277			function getClasses( type, source ) {
1278				var a = source === options.cssClasses.value;
1279				var orientationClasses = a ? valueOrientationClasses : markerOrientationClasses;
1280				var sizeClasses = a ? valueSizeClasses : markerSizeClasses;
1281				return source + ' ' + orientationClasses[ options.ort ] + ' ' + sizeClasses[ type ];
1282			}
1283			function addSpread( key, value, type ) {
1284				var node;
1285				// Apply the filter function, if it is set.
1286				type = filterFunc ? filterFunc( value, type ) : type;
1287				if ( type === exports.PipsType.None ) {
1288					return;
1289				}
1290				// Add a marker for every point
1291				node = addNodeTo( element, false );
1292				node.className = getClasses( type, options.cssClasses.marker );
1293				node.style[ options.style ] = key + '%';
1294				// Values are only appended for points marked '1' or '2'.
1295				if ( type > exports.PipsType.NoValue ) {
1296					node = addNodeTo( element, false );
1297					node.className = getClasses( type, options.cssClasses.value );
1298					node.setAttribute( 'data-value', String( value ) );
1299					node.style[ options.style ] = key + '%';
1300					node.innerHTML = String( formatter.to( value ) );
1301				}
1302			}
1303			// Append all points.
1304			Object.keys( spread ).forEach( function( key ) {
1305				addSpread( key, spread[ key ][ 0 ], spread[ key ][ 1 ] );
1306			} );
1307			return element;
1308		}
1309		function removePips() {
1310			if ( scope_Pips ) {
1311				removeElement( scope_Pips );
1312				scope_Pips = null;
1313			}
1314		}
1315		function pips( ipips ) {
1316			var filter;
1317			var spread;
1318			var format;
1319			// Fix #669
1320			removePips();
1321			spread = generateSpread( ipips );
1322			filter = ipips.filter;
1323			format = ipips.format || {
1324				to: function( value ) {
1325					return String( Math.round( value ) );
1326				}
1327			};
1328			scope_Pips = scope_Target.appendChild( addMarking( spread, filter, format ) );
1329			return scope_Pips;
1330		}
1331		// Shorthand for base dimensions.
1332		function baseSize() {
1333			var rect = scope_Base.getBoundingClientRect();
1334			var alt = ( 'offset' + [ 'Width', 'Height' ][ options.ort ] );
1335			return options.ort === 0 ? rect.width || scope_Base[ alt ] : rect.height || scope_Base[ alt ];
1336		}
1337		// Handler for attaching events trough a proxy.
1338		function attachEvent( events, element, callback, data ) {
1339			// This function can be used to 'filter' events to the slider.
1340			// element is a node, not a nodeList
1341			var method = function( event ) {
1342				var e = fixEvent( event, data.pageOffset, data.target || element );
1343				// fixEvent returns false if this event has a different target
1344				// when handling (multi-) touch events;
1345				if ( ! e ) {
1346					return false;
1347				}
1348				// doNotReject is passed by all end events to make sure released touches
1349				// are not rejected, leaving the slider "stuck" to the cursor;
1350				if ( isSliderDisabled() && ! data.doNotReject ) {
1351					return false;
1352				}
1353				// Stop if an active 'tap' transition is taking place.
1354				if ( hasClass( scope_Target, options.cssClasses.tap ) && ! data.doNotReject ) {
1355					return false;
1356				}
1357				// Ignore right or middle clicks on start #454
1358				if ( events === actions.start && e.buttons !== undefined && e.buttons > 1 ) {
1359					return false;
1360				}
1361				// Ignore right or middle clicks on start #454
1362				if ( data.hover && e.buttons ) {
1363					return false;
1364				}
1365				// 'supportsPassive' is only true if a browser also supports touch-action: none in CSS.
1366				// iOS safari does not, so it doesn't get to benefit from passive scrolling. iOS does support
1367				// touch-action: manipulation, but that allows panning, which breaks
1368				// sliders after zooming/on non-responsive pages.
1369				// See: https://bugs.webkit.org/show_bug.cgi?id=133112
1370				if ( ! supportsPassive ) {
1371					e.preventDefault();
1372				}
1373				e.calcPoint = e.points[ options.ort ];
1374				// Call the event handler with the event [ and additional data ].
1375				callback( e, data );
1376			};
1377			var methods = [];
1378			// Bind a closure on the target for every event type.
1379			events.split( ' ' ).forEach( function( eventName ) {
1380				element.addEventListener( eventName, method, supportsPassive ? { passive: true } : false );
1381				methods.push( [ eventName, method ] );
1382			} );
1383			return methods;
1384		}
1385		// Provide a clean event with standardized offset values.
1386		function fixEvent( e, pageOffset, eventTarget ) {
1387			// Filter the event to register the type, which can be
1388			// touch, mouse or pointer. Offset changes need to be
1389			// made on an event specific basis.
1390			var touch = e.type.indexOf( 'touch' ) === 0;
1391			var mouse = e.type.indexOf( 'mouse' ) === 0;
1392			var pointer = e.type.indexOf( 'pointer' ) === 0;
1393			var x = 0;
1394			var y = 0;
1395			var isTouchOnTarget;
1396			var targetTouches;
1397			var targetTouch;
1398			// IE10 implemented pointer events with a prefix;
1399			if ( e.type.indexOf( 'MSPointer' ) === 0 ) {
1400				pointer = true;
1401			}
1402			// Erroneous events seem to be passed in occasionally on iOS/iPadOS after user finishes interacting with
1403			// the slider. They appear to be of type MouseEvent, yet they don't have usual properties set. Ignore
1404			// events that have no touches or buttons associated with them. (#1057, #1079, #1095)
1405			if ( e.type === 'mousedown' && ! e.buttons && ! e.touches ) {
1406				return false;
1407			}
1408			// The only thing one handle should be concerned about is the touches that originated on top of it.
1409			if ( touch ) {
1410				// Returns true if a touch originated on the target.
1411				isTouchOnTarget = function( checkTouch ) {
1412					return ( checkTouch.target === eventTarget ||
1413                        eventTarget.contains( checkTouch.target ) ||
1414                        ( e.composed && e.composedPath().shift() === eventTarget ) );
1415				};
1416				// In the case of touchstart events, we need to make sure there is still no more than one
1417				// touch on the target so we look amongst all touches.
1418				if ( e.type === 'touchstart' ) {
1419					targetTouches = Array.prototype.filter.call( e.touches, isTouchOnTarget );
1420					// Do not support more than one touch per handle.
1421					if ( targetTouches.length > 1 ) {
1422						return false;
1423					}
1424					x = targetTouches[ 0 ].pageX;
1425					y = targetTouches[ 0 ].pageY;
1426				} else {
1427					// In the other cases, find on changedTouches is enough.
1428					targetTouch = Array.prototype.find.call( e.changedTouches, isTouchOnTarget );
1429					// Cancel if the target touch has not moved.
1430					if ( ! targetTouch ) {
1431						return false;
1432					}
1433					x = targetTouch.pageX;
1434					y = targetTouch.pageY;
1435				}
1436			}
1437			pageOffset = pageOffset || getPageOffset( scope_Document );
1438			if ( mouse || pointer ) {
1439				x = e.clientX + pageOffset.x;
1440				y = e.clientY + pageOffset.y;
1441			}
1442			e.pageOffset = pageOffset;
1443			e.points = [ x, y ];
1444			e.cursor = mouse || pointer; // Fix #435
1445			return e;
1446		}
1447		// Translate a coordinate in the document to a percentage on the slider
1448		function calcPointToPercentage( calcPoint ) {
1449			var location = calcPoint - offset( scope_Base, options.ort );
1450			var proposal = ( location * 100 ) / baseSize();
1451			// Clamp proposal between 0% and 100%
1452			// Out-of-bound coordinates may occur when .noUi-base pseudo-elements
1453			// are used (e.g. contained handles feature)
1454			proposal = limit( proposal );
1455			return options.dir ? 100 - proposal : proposal;
1456		}
1457		// Find handle closest to a certain percentage on the slider
1458		function getClosestHandle( clickedPosition ) {
1459			var smallestDifference = 100;
1460			var handleNumber = false;
1461			scope_Handles.forEach( function( handle, index ) {
1462				var handlePosition;
1463				var differenceWithThisHandle;
1464				var clickAtEdge;
1465				var isCloser;
1466				var isCloserAfter;
1467				// Disabled handles are ignored
1468				if ( isHandleDisabled( index ) ) {
1469					return;
1470				}
1471				handlePosition = scope_Locations[ index ];
1472				differenceWithThisHandle = Math.abs( handlePosition - clickedPosition );
1473				// Initial state
1474				clickAtEdge = differenceWithThisHandle === 100 && smallestDifference === 100;
1475				// Difference with this handle is smaller than the previously checked handle
1476				isCloser = differenceWithThisHandle < smallestDifference;
1477				isCloserAfter = differenceWithThisHandle <= smallestDifference && clickedPosition > handlePosition;
1478				if ( isCloser || isCloserAfter || clickAtEdge ) {
1479					handleNumber = index;
1480					smallestDifference = differenceWithThisHandle;
1481				}
1482			} );
1483			return handleNumber;
1484		}
1485		// Fire 'end' when a mouse or pen leaves the document.
1486		function documentLeave( event, data ) {
1487			if ( event.type === 'mouseout' &&
1488                event.target.nodeName === 'HTML' &&
1489                event.relatedTarget === null ) {
1490				eventEnd( event, data );
1491			}
1492		}
1493		// Handle movement on document for handle and range drag.
1494		function eventMove( event, data ) {
1495			var movement;
1496			var proposal;
1497			// Fix #498
1498			// Check value of .buttons in 'start' to work around a bug in IE10 mobile (data.buttonsProperty).
1499			// https://connect.microsoft.com/IE/feedback/details/927005/mobile-ie10-windows-phone-buttons-property-of-pointermove-event-always-zero
1500			// IE9 has .buttons and .which zero on mousemove.
1501			// Firefox breaks the spec MDN defines.
1502			if ( navigator.appVersion.indexOf( 'MSIE 9' ) === -1 && event.buttons === 0 && data.buttonsProperty !== 0 ) {
1503				return eventEnd( event, data );
1504			}
1505			// Check if we are moving up or down
1506			movement = ( options.dir ? -1 : 1 ) * ( event.calcPoint - data.startCalcPoint );
1507			// Convert the movement into a percentage of the slider width/height
1508			proposal = ( movement * 100 ) / data.baseSize;
1509			moveHandles( movement > 0, proposal, data.locations, data.handleNumbers, data.connect );
1510		}
1511		// Unbind move events on document, call callbacks.
1512		function eventEnd( event, data ) {
1513			// The handle is no longer active, so remove the class.
1514			if ( data.handle ) {
1515				removeClass( data.handle, options.cssClasses.active );
1516				scope_ActiveHandlesCount -= 1;
1517			}
1518			// Unbind the move and end events, which are added on 'start'.
1519			data.listeners.forEach( function( c ) {
1520				scope_DocumentElement.removeEventListener( c[ 0 ], c[ 1 ] );
1521			} );
1522			if ( scope_ActiveHandlesCount === 0 ) {
1523				// Remove dragging class.
1524				removeClass( scope_Target, options.cssClasses.drag );
1525				setZindex();
1526				// Remove cursor styles and text-selection events bound to the body.
1527				if ( event.cursor ) {
1528					scope_Body.style.cursor = '';
1529					scope_Body.removeEventListener( 'selectstart', preventDefault );
1530				}
1531			}
1532			if ( options.events.smoothSteps ) {
1533				data.handleNumbers.forEach( function( handleNumber ) {
1534					setHandle( handleNumber, scope_Locations[ handleNumber ], true, true, false, false );
1535				} );
1536				data.handleNumbers.forEach( function( handleNumber ) {
1537					fireEvent( 'update', handleNumber );
1538				} );
1539			}
1540			data.handleNumbers.forEach( function( handleNumber ) {
1541				fireEvent( 'change', handleNumber );
1542				fireEvent( 'set', handleNumber );
1543				fireEvent( 'end', handleNumber );
1544			} );
1545		}
1546		// Bind move events on document.
1547		function eventStart( event, data ) {
1548			var handle;
1549			var handleOrigin;
1550			var listeners;
1551			var moveEvent;
1552			var endEvent;
1553			var outEvent;
1554			// Ignore event if any handle is disabled
1555			if ( data.handleNumbers.some( isHandleDisabled ) ) {
1556				return;
1557			}
1558			if ( data.handleNumbers.length === 1 ) {
1559				handleOrigin = scope_Handles[ data.handleNumbers[ 0 ] ];
1560				handle = handleOrigin.children[ 0 ];
1561				scope_ActiveHandlesCount += 1;
1562				// Mark the handle as 'active' so it can be styled.
1563				addClass( handle, options.cssClasses.active );
1564			}
1565			// A drag should never propagate up to the 'tap' event.
1566			event.stopPropagation();
1567			// Record the event listeners.
1568			listeners = [];
1569			// Attach the move and end events.
1570			moveEvent = attachEvent( actions.move, scope_DocumentElement, eventMove, {
1571				// The event target has changed so we need to propagate the original one so that we keep
1572				// relying on it to extract target touches.
1573				target: event.target,
1574				handle: handle,
1575				connect: data.connect,
1576				listeners: listeners,
1577				startCalcPoint: event.calcPoint,
1578				baseSize: baseSize(),
1579				pageOffset: event.pageOffset,
1580				handleNumbers: data.handleNumbers,
1581				buttonsProperty: event.buttons,
1582				locations: scope_Locations.slice()
1583			} );
1584			endEvent = attachEvent( actions.end, scope_DocumentElement, eventEnd, {
1585				target: event.target,
1586				handle: handle,
1587				listeners: listeners,
1588				doNotReject: true,
1589				handleNumbers: data.handleNumbers
1590			} );
1591			outEvent = attachEvent( 'mouseout', scope_DocumentElement, documentLeave, {
1592				target: event.target,
1593				handle: handle,
1594				listeners: listeners,
1595				doNotReject: true,
1596				handleNumbers: data.handleNumbers
1597			} );
1598			// We want to make sure we pushed the listeners in the listener list rather than creating
1599			// a new one as it has already been passed to the event handlers.
1600			listeners.push.apply( listeners, moveEvent.concat( endEvent, outEvent ) );
1601			// Text selection isn't an issue on touch devices,
1602			// so adding cursor styles can be skipped.
1603			if ( event.cursor ) {
1604				// Prevent the 'I' cursor and extend the range-drag cursor.
1605				scope_Body.style.cursor = getComputedStyle( event.target ).cursor;
1606				// Mark the target with a dragging state.
1607				if ( scope_Handles.length > 1 ) {
1608					addClass( scope_Target, options.cssClasses.drag );
1609				}
1610				// Prevent text selection when dragging the handles.
1611				// In noUiSlider <= 9.2.0, this was handled by calling preventDefault on mouse/touch start/move,
1612				// which is scroll blocking. The selectstart event is supported by FireFox starting from version 52,
1613				// meaning the only holdout is iOS Safari. This doesn't matter: text selection isn't triggered there.
1614				// The 'cursor' flag is false.
1615				// See: http://caniuse.com/#search=selectstart
1616				scope_Body.addEventListener( 'selectstart', preventDefault, false );
1617			}
1618			data.handleNumbers.forEach( function( handleNumber ) {
1619				fireEvent( 'start', handleNumber );
1620			} );
1621		}
1622		// Move closest handle to tapped location.
1623		function eventTap( event ) {
1624			var proposal;
1625			var handleNumber;
1626			// The tap event shouldn't propagate up
1627			event.stopPropagation();
1628			proposal = calcPointToPercentage( event.calcPoint );
1629			handleNumber = getClosestHandle( proposal );
1630			// Tackle the case that all handles are 'disabled'.
1631			if ( handleNumber === false ) {
1632				return;
1633			}
1634			// Flag the slider as it is now in a transitional state.
1635			// Transition takes a configurable amount of ms (default 300). Re-enable the slider after that.
1636			if ( ! options.events.snap ) {
1637				addClassFor( scope_Target, options.cssClasses.tap, options.animationDuration );
1638			}
1639			setHandle( handleNumber, proposal, true, true );
1640			setZindex();
1641			fireEvent( 'slide', handleNumber, true );
1642			fireEvent( 'update', handleNumber, true );
1643			if ( ! options.events.snap ) {
1644				fireEvent( 'change', handleNumber, true );
1645				fireEvent( 'set', handleNumber, true );
1646			} else {
1647				eventStart( event, { handleNumbers: [ handleNumber ] } );
1648			}
1649		}
1650		// Fires a 'hover' event for a hovered mouse/pen position.
1651		function eventHover( event ) {
1652			var proposal = calcPointToPercentage( event.calcPoint );
1653			var to = scope_Spectrum.getStep( proposal );
1654			var value = scope_Spectrum.fromStepping( to );
1655			Object.keys( scope_Events ).forEach( function( targetEvent ) {
1656				if ( 'hover' === targetEvent.split( '.' )[ 0 ] ) {
1657					scope_Events[ targetEvent ].forEach( function( callback ) {
1658						callback.call( scope_Self, value );
1659					} );
1660				}
1661			} );
1662		}
1663		// Handles keydown on focused handles
1664		// Don't move the document when pressing arrow keys on focused handles
1665		function eventKeydown( event, handleNumber ) {
1666			var horizontalKeys;
1667			var verticalKeys;
1668			var largeStepKeys;
1669			var edgeKeys;
1670			var key;
1671			var isLargeDown;
1672			var isLargeUp;
1673			var isDown;
1674			var isUp;
1675			var isMin;
1676			var isMax;
1677			var to;
1678			var direction;
1679			var steps;
1680			var step;
1681			if ( isSliderDisabled() || isHandleDisabled( handleNumber ) ) {
1682				return false;
1683			}
1684			horizontalKeys = [ 'Left', 'Right' ];
1685			verticalKeys = [ 'Down', 'Up' ];
1686			largeStepKeys = [ 'PageDown', 'PageUp' ];
1687			edgeKeys = [ 'Home', 'End' ];
1688			if ( options.dir && ! options.ort ) {
1689				// On an right-to-left slider, the left and right keys act inverted
1690				horizontalKeys.reverse();
1691			} else if ( options.ort && ! options.dir ) {
1692				// On a top-to-bottom slider, the up and down keys act inverted
1693				verticalKeys.reverse();
1694				largeStepKeys.reverse();
1695			}
1696			// Strip "Arrow" for IE compatibility. https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key
1697			key = event.key.replace( 'Arrow', '' );
1698			isLargeDown = key === largeStepKeys[ 0 ];
1699			isLargeUp = key === largeStepKeys[ 1 ];
1700			isDown = key === verticalKeys[ 0 ] || key === horizontalKeys[ 0 ] || isLargeDown;
1701			isUp = key === verticalKeys[ 1 ] || key === horizontalKeys[ 1 ] || isLargeUp;
1702			isMin = key === edgeKeys[ 0 ];
1703			isMax = key === edgeKeys[ 1 ];
1704			if ( ! isDown && ! isUp && ! isMin && ! isMax ) {
1705				return true;
1706			}
1707			event.preventDefault();
1708			if ( isUp || isDown ) {
1709				direction = isDown ? 0 : 1;
1710				steps = getNextStepsForHandle( handleNumber );
1711				step = steps[ direction ];
1712				// At the edge of a slider, do nothing
1713				if ( step === null ) {
1714					return false;
1715				}
1716				// No step set, use the default of 10% of the sub-range
1717				if ( step === false ) {
1718					step = scope_Spectrum.getDefaultStep( scope_Locations[ handleNumber ], isDown, options.keyboardDefaultStep );
1719				}
1720				if ( isLargeUp || isLargeDown ) {
1721					step *= options.keyboardPageMultiplier;
1722				} else {
1723					step *= options.keyboardMultiplier;
1724				}
1725				// Step over zero-length ranges (#948);
1726				step = Math.max( step, 0.0000001 );
1727				// Decrement for down steps
1728				step = ( isDown ? -1 : 1 ) * step;
1729				to = scope_Values[ handleNumber ] + step;
1730			} else if ( isMax ) {
1731				// End key
1732				to = options.spectrum.xVal[ options.spectrum.xVal.length - 1 ];
1733			} else {
1734				// Home key
1735				to = options.spectrum.xVal[ 0 ];
1736			}
1737			setHandle( handleNumber, scope_Spectrum.toStepping( to ), true, true );
1738			fireEvent( 'slide', handleNumber );
1739			fireEvent( 'update', handleNumber );
1740			fireEvent( 'change', handleNumber );
1741			fireEvent( 'set', handleNumber );
1742			return false;
vendor: 6,566 bytes, lines 1743-1906
1743		}
1744		// Attach events to several slider parts.
1745		function bindSliderEvents( behaviour ) {
1746			var handleBefore;
1747			var handleAfter;
1748			var eventHolders;
1749			var handlesToDrag;
1750			var handleNumbersToDrag;
1751			// Attach the standard drag event to the handles.
1752			if ( ! behaviour.fixed ) {
1753				scope_Handles.forEach( function( handle, index ) {
1754					// These events are only bound to the visual handle
1755					// element, not the 'real' origin element.
1756					attachEvent( actions.start, handle.children[ 0 ], eventStart, {
1757						handleNumbers: [ index ]
1758					} );
1759				} );
1760			}
1761			// Attach the tap event to the slider base.
1762			if ( behaviour.tap ) {
1763				attachEvent( actions.start, scope_Base, eventTap, {} );
1764			}
1765			// Fire hover events
1766			if ( behaviour.hover ) {
1767				attachEvent( actions.move, scope_Base, eventHover, {
1768					hover: true
1769				} );
1770			}
1771			// Make the range draggable.
1772			if ( behaviour.drag ) {
1773				scope_Connects.forEach( function( connect, index ) {
1774					if ( connect === false || index === 0 || index === scope_Connects.length - 1 ) {
1775						return;
1776					}
1777					handleBefore = scope_Handles[ index - 1 ];
1778					handleAfter = scope_Handles[ index ];
1779					eventHolders = [ connect ];
1780					handlesToDrag = [ handleBefore, handleAfter ];
1781					handleNumbersToDrag = [ index - 1, index ];
1782					addClass( connect, options.cssClasses.draggable );
1783					// When the range is fixed, the entire range can
1784					// be dragged by the handles. The handle in the first
1785					// origin will propagate the start event upward,
1786					// but it needs to be bound manually on the other.
1787					if ( behaviour.fixed ) {
1788						eventHolders.push( handleBefore.children[ 0 ] );
1789						eventHolders.push( handleAfter.children[ 0 ] );
1790					}
1791					if ( behaviour.dragAll ) {
1792						handlesToDrag = scope_Handles;
1793						handleNumbersToDrag = scope_HandleNumbers;
1794					}
1795					eventHolders.forEach( function( eventHolder ) {
1796						attachEvent( actions.start, eventHolder, eventStart, {
1797							handles: handlesToDrag,
1798							handleNumbers: handleNumbersToDrag,
1799							connect: connect
1800						} );
1801					} );
1802				} );
1803			}
1804		}
1805		// Attach an event to this slider, possibly including a namespace
1806		function bindEvent( namespacedEvent, callback ) {
1807			scope_Events[ namespacedEvent ] = scope_Events[ namespacedEvent ] || [];
1808			scope_Events[ namespacedEvent ].push( callback );
1809			// If the event bound is 'update,' fire it immediately for all handles.
1810			if ( namespacedEvent.split( '.' )[ 0 ] === 'update' ) {
1811				scope_Handles.forEach( function( a, index ) {
1812					fireEvent( 'update', index );
1813				} );
1814			}
1815		}
1816		function isInternalNamespace( namespace ) {
1817			return namespace === INTERNAL_EVENT_NS.aria || namespace === INTERNAL_EVENT_NS.tooltips;
1818		}
1819		// Undo attachment of event
1820		function removeEvent( namespacedEvent ) {
1821			var event = namespacedEvent && namespacedEvent.split( '.' )[ 0 ];
1822			var namespace = event ? namespacedEvent.substring( event.length ) : namespacedEvent;
1823			Object.keys( scope_Events ).forEach( function( bind ) {
1824				var tEvent = bind.split( '.' )[ 0 ];
1825				var tNamespace = bind.substring( tEvent.length );
1826				if ( ( ! event || event === tEvent ) && ( ! namespace || namespace === tNamespace ) ) {
1827					// only delete protected internal event if intentional
1828					if ( ! isInternalNamespace( tNamespace ) || namespace === tNamespace ) {
1829						delete scope_Events[ bind ];
1830					}
1831				}
1832			} );
1833		}
1834		// External event handling
1835		function fireEvent( eventName, handleNumber, tap ) {
1836			Object.keys( scope_Events ).forEach( function( targetEvent ) {
1837				var eventType = targetEvent.split( '.' )[ 0 ];
1838				if ( eventName === eventType ) {
1839					scope_Events[ targetEvent ].forEach( function( callback ) {
1840						callback.call(
1841							// Use the slider public API as the scope ('this')
1842							scope_Self,
1843							// Return values as array, so arg_1[arg_2] is always valid.
1844							scope_Values.map( options.format.to ),
1845							// Handle index, 0 or 1
1846							handleNumber,
1847							// Un-formatted slider values
1848							scope_Values.slice(),
1849							// Event is fired by tap, true or false
1850							tap || false,
1851							// Left offset of the handle, in relation to the slider
1852							scope_Locations.slice(),
1853							// add the slider public API to an accessible parameter when this is unavailable
1854							scope_Self );
1855					} );
1856				}
1857			} );
1858		}
1859		// Split out the handle positioning logic so the Move event can use it, too
1860		function checkHandlePosition( reference, handleNumber, to, lookBackward, lookForward, getValue, smoothSteps ) {
1861			var distance;
1862			// For sliders with multiple handles, limit movement to the other handle.
1863			// Apply the margin option by adding it to the handle positions.
1864			if ( scope_Handles.length > 1 && ! options.events.unconstrained ) {
1865				if ( lookBackward && handleNumber > 0 ) {
1866					distance = scope_Spectrum.getAbsoluteDistance( reference[ handleNumber - 1 ], options.margin, false );
1867					to = Math.max( to, distance );
1868				}
1869				if ( lookForward && handleNumber < scope_Handles.length - 1 ) {
1870					distance = scope_Spectrum.getAbsoluteDistance( reference[ handleNumber + 1 ], options.margin, true );
1871					to = Math.min( to, distance );
1872				}
1873			}
1874			// The limit option has the opposite effect, limiting handles to a
1875			// maximum distance from another. Limit must be > 0, as otherwise
1876			// handles would be unmovable.
1877			if ( scope_Handles.length > 1 && options.limit ) {
1878				if ( lookBackward && handleNumber > 0 ) {
1879					distance = scope_Spectrum.getAbsoluteDistance( reference[ handleNumber - 1 ], options.limit, false );
1880					to = Math.min( to, distance );
1881				}
1882				if ( lookForward && handleNumber < scope_Handles.length - 1 ) {
1883					distance = scope_Spectrum.getAbsoluteDistance( reference[ handleNumber + 1 ], options.limit, true );
1884					to = Math.max( to, distance );
1885				}
1886			}
1887			// The padding option keeps the handles a certain distance from the
1888			// edges of the slider. Padding must be > 0.
1889			if ( options.padding ) {
1890				if ( handleNumber === 0 ) {
1891					distance = scope_Spectrum.getAbsoluteDistance( 0, options.padding[ 0 ], false );
1892					to = Math.max( to, distance );
1893				}
1894				if ( handleNumber === scope_Handles.length - 1 ) {
1895					distance = scope_Spectrum.getAbsoluteDistance( 100, options.padding[ 1 ], true );
1896					to = Math.min( to, distance );
1897				}
1898			}
1899			if ( ! smoothSteps ) {
1900				to = scope_Spectrum.getStep( to );
1901			}
1902			// Limit percentage to the 0 - 100 range
1903			to = limit( to );
1904			// Return false if handle can't move
1905			if ( to === reference[ handleNumber ] && ! getValue ) {
1906				return false;
1907			}
1908			return to;
1909		}
1910		// Uses slider orientation to create CSS rules. a = base value;
1911		function inRuleOrder( v, a ) {
1912			var o = options.ort;
1913			return ( o ? a : v ) + ', ' + ( o ? v : a );
1914		}
1915		// Moves handle(s) by a percentage
1916		// (bool, % to move, [% where handle started, ...], [index in scope_Handles, ...])
1917		function moveHandles( upward, proposal, locations, handleNumbers, connect ) {
1918			var proposals = locations.slice();
1919			// Store first handle now, so we still have it in case handleNumbers is reversed
1920			var firstHandle = handleNumbers[ 0 ];
1921			var smoothSteps = options.events.smoothSteps;
1922			var b = [ ! upward, upward ];
1923			var f = [ upward, ! upward ];
1924			var state = false;
1925			// Copy handleNumbers so we don't change the dataset
1926			handleNumbers = handleNumbers.slice();
1927			// Check to see which handle is 'leading'.
1928			// If that one can't move the second can't either.
1929			if ( upward ) {
1930				handleNumbers.reverse();
1931			}
1932			// Step 1: get the maximum percentage that any of the handles can move
1933			if ( handleNumbers.length > 1 ) {
1934				handleNumbers.forEach( function( handleNumber, o ) {
1935					var to = checkHandlePosition( proposals, handleNumber, proposals[ handleNumber ] + proposal, b[ o ], f[ o ], false, smoothSteps );
1936					// Stop if one of the handles can't move.
1937					if ( to === false ) {
1938						proposal = 0;
1939					} else {
1940						proposal = to - proposals[ handleNumber ];
1941						proposals[ handleNumber ] = to;
1942					}
1943				} );
1944			} else { // If using one handle, check backward AND forward
1945				b = f = [ true ];
1946			}
1947			// Step 2: Try to set the handles with the found percentage
1948			handleNumbers.forEach( function( handleNumber, o ) {
1949				state =
1950                    setHandle( handleNumber, locations[ handleNumber ] + proposal, b[ o ], f[ o ], false, smoothSteps ) || state;
1951			} );
1952			// Step 3: If a handle moved, fire events
1953			if ( state ) {
1954				handleNumbers.forEach( function( handleNumber ) {
1955					fireEvent( 'update', handleNumber );
1956					fireEvent( 'slide', handleNumber );
1957				} );
1958				// If target is a connect, then fire drag event
1959				if ( connect !== undefined ) {
1960					fireEvent( 'drag', firstHandle );
1961				}
1962			}
1963		}
1964		// Takes a base value and an offset. This offset is used for the connect bar size.
1965		// In the initial design for this feature, the origin element was 1% wide.
1966		// Unfortunately, a rounding bug in Chrome makes it impossible to implement this feature
1967		// in this manner: https://bugs.chromium.org/p/chromium/issues/detail?id=798223
1968		function transformDirection( a, b ) {
1969			return options.dir ? 100 - a - b : a;
1970		}
1971		// Updates scope_Locations and scope_Values, updates visual state
1972		function updateHandlePosition( handleNumber, to ) {
1973			var translation;
1974			var translateRule;
1975			// Update locations.
1976			scope_Locations[ handleNumber ] = to;
1977			// Convert the value to the slider stepping/range.
1978			scope_Values[ handleNumber ] = scope_Spectrum.fromStepping( to );
1979			translation = transformDirection( to, 0 ) - scope_DirOffset;
1980			translateRule = 'translate(' + inRuleOrder( translation + '%', '0' ) + ')';
1981			scope_Handles[ handleNumber ].style[ options.transformRule ] = translateRule;
1982			updateConnect( handleNumber );
1983			updateConnect( handleNumber + 1 );
1984		}
1985		// Handles before the slider middle are stacked later = higher,
1986		// Handles after the middle later is lower
1987		// [[7] [8] .......... | .......... [5] [4]
1988		function setZindex() {
1989			scope_HandleNumbers.forEach( function( handleNumber ) {
1990				var dir = scope_Locations[ handleNumber ] > 50 ? -1 : 1;
1991				var zIndex = 3 + ( scope_Handles.length + ( dir * handleNumber ) );
1992				scope_Handles[ handleNumber ].style.zIndex = String( zIndex );
1993			} );
1994		}
1995		// Test suggested values and apply margin, step.
1996		// if exactInput is true, don't run checkHandlePosition, then the handle can be placed in between steps (#436)
1997		function setHandle( handleNumber, to, lookBackward, lookForward, exactInput, smoothSteps ) {
1998			if ( ! exactInput ) {
1999				to = checkHandlePosition( scope_Locations, handleNumber, to, lookBackward, lookForward, false, smoothSteps );
2000			}
2001			if ( to === false ) {
2002				return false;
2003			}
2004			updateHandlePosition( handleNumber, to );
2005			return true;
2006		}
2007		// Updates style attribute for connect nodes
2008		function updateConnect( index ) {
2009			var l;
2010			var h;
2011			var connectWidth;
2012			var translateRule;
2013			var scaleRule;
2014			// Skip connects set to false
2015			if ( ! scope_Connects[ index ] ) {
2016				return;
2017			}
2018			l = 0;
2019			h = 100;
2020			if ( index !== 0 ) {
2021				l = scope_Locations[ index - 1 ];
2022			}
2023			if ( index !== scope_Connects.length - 1 ) {
2024				h = scope_Locations[ index ];
2025			}
2026			// We use two rules:
2027			// 'translate' to change the left/top offset;
2028			// 'scale' to change the width of the element;
2029			// As the element has a width of 100%, a translation of 100% is equal to 100% of the parent (.noUi-base)
2030			connectWidth = h - l;
2031			translateRule = 'translate(' + inRuleOrder( transformDirection( l, connectWidth ) + '%', '0' ) + ')';
2032			scaleRule = 'scale(' + inRuleOrder( connectWidth / 100, '1' ) + ')';
2033			scope_Connects[ index ].style[ options.transformRule ] =
2034                translateRule + ' ' + scaleRule;
2035		}
2036		// Parses value passed to .set method. Returns current value if not parse-able.
2037		function resolveToValue( to, handleNumber ) {
2038			// Setting with null indicates an 'ignore'.
2039			// Inputting 'false' is invalid.
2040			if ( to === null || to === false || to === undefined ) {
2041				return scope_Locations[ handleNumber ];
2042			}
2043			// If a formatted number was passed, attempt to decode it.
2044			if ( typeof to === 'number' ) {
2045				to = String( to );
2046			}
2047			to = options.format.from( to );
2048			if ( to !== false ) {
2049				to = scope_Spectrum.toStepping( to );
2050			}
2051			// If parsing the number failed, use the current value.
2052			if ( to === false || isNaN( to ) ) {
2053				return scope_Locations[ handleNumber ];
2054			}
2055			return to;
2056		}
2057		function scope_HandleNumbersCallback( exactInput ) {
2058			return function( handleNumber ) {
2059				setHandle( handleNumber, scope_Locations[ handleNumber ], true, true, exactInput );
2060			};
2061		}
2062		// Set the slider value.
2063		function valueSet( input, fireSetEvent, exactInput ) {
2064			var values = asArray( input );
2065			var isInit = scope_Locations[ 0 ] === undefined;
2066			var i;
2067			var space_1;
2068			// Event fires by default
2069			fireSetEvent = fireSetEvent === undefined ? true : fireSetEvent;
2070			// Animation is optional.
2071			// Make sure the initial values were set before using animated placement.
2072			if ( options.animate && ! isInit ) {
2073				addClassFor( scope_Target, options.cssClasses.tap, options.animationDuration );
2074			}
2075			// First pass, without lookAhead but with lookBackward. Values are set from left to right.
2076			scope_HandleNumbers.forEach( function( handleNumber ) {
2077				setHandle( handleNumber, resolveToValue( values[ handleNumber ], handleNumber ), true, false, exactInput );
2078			} );
2079			i = scope_HandleNumbers.length === 1 ? 0 : 1;
2080			// Spread handles evenly across the slider if the range has no size (min=max)
2081			if ( isInit && scope_Spectrum.hasNoSize() ) {
2082				exactInput = true;
2083				scope_Locations[ 0 ] = 0;
2084				if ( scope_HandleNumbers.length > 1 ) {
2085					space_1 = 100 / ( scope_HandleNumbers.length - 1 );
2086					scope_HandleNumbers.forEach( function( handleNumber ) {
2087						scope_Locations[ handleNumber ] = handleNumber * space_1;
2088					} );
2089				}
2090			}
2091			// Secondary passes. Now that all base values are set, apply constraints.
2092			// Iterate all handles to ensure constraints are applied for the entire slider (Issue #1009)
2093			for ( ; i < scope_HandleNumbers.length; ++i ) {
2094				scope_HandleNumbers.forEach( scope_HandleNumbersCallback( exactInput ) );
2095			}
2096			setZindex();
2097			scope_HandleNumbers.forEach( function( handleNumber ) {
2098				fireEvent( 'update', handleNumber );
2099				// Fire the event only for handles that received a new value, as per #579
2100				if ( values[ handleNumber ] !== null && fireSetEvent ) {
2101					fireEvent( 'set', handleNumber );
2102				}
2103			} );
2104		}
2105		// Reset slider to initial values
2106		function valueReset( fireSetEvent ) {
2107			valueSet( options.start, fireSetEvent );
2108		}
2109		// Set value for a single handle
2110		function valueSetHandle( handleNumber, value, fireSetEvent, exactInput ) {
2111			// Ensure numeric input
2112			handleNumber = Number( handleNumber );
2113			if ( ! ( handleNumber >= 0 && handleNumber < scope_HandleNumbers.length ) ) {
2114				throw new Error( 'noUiSlider: invalid handle number, got: ' + handleNumber );
2115			}
2116			// Look both backward and forward, since we don't want this handle to "push" other handles (#960);
2117			// The exactInput argument can be used to ignore slider stepping (#436)
2118			setHandle( handleNumber, resolveToValue( value, handleNumber ), true, true, exactInput );
2119			fireEvent( 'update', handleNumber );
2120			if ( fireSetEvent ) {
2121				fireEvent( 'set', handleNumber );
2122			}
2123		}
2124		// Get the slider value.
2125		function valueGet( unencoded ) {
2126			var values;
2127			if ( unencoded === void 0 ) {
2128				unencoded = false;
vendor: 6,568 bytes, lines 2129-2328
2129			}
2130			if ( unencoded ) {
2131				// return a copy of the raw values
2132				return scope_Values.length === 1 ? scope_Values[ 0 ] : scope_Values.slice( 0 );
2133			}
2134			values = scope_Values.map( options.format.to );
2135			// If only one handle is used, return a single value.
2136			if ( values.length === 1 ) {
2137				return values[ 0 ];
2138			}
2139			return values;
2140		}
2141		// Removes classes from the root and empties it.
2142		function destroy() {
2143			// remove protected internal listeners
2144			removeEvent( INTERNAL_EVENT_NS.aria );
2145			removeEvent( INTERNAL_EVENT_NS.tooltips );
2146			Object.keys( options.cssClasses ).forEach( function( key ) {
2147				removeClass( scope_Target, options.cssClasses[ key ] );
2148			} );
2149			while ( scope_Target.firstChild ) {
2150				scope_Target.removeChild( scope_Target.firstChild );
2151			}
2152			delete scope_Target.noUiSlider;
2153		}
2154		function getNextStepsForHandle( handleNumber ) {
2155			var location = scope_Locations[ handleNumber ];
2156			var nearbySteps = scope_Spectrum.getNearbySteps( location );
2157			var value = scope_Values[ handleNumber ];
2158			var increment = nearbySteps.thisStep.step;
2159			var decrement = null;
2160			var stepDecimals;
2161			// If snapped, directly use defined step value
2162			if ( options.snap ) {
2163				return [
2164					value - nearbySteps.stepBefore.startValue || null,
2165					nearbySteps.stepAfter.startValue - value || null
2166				];
2167			}
2168			// If the next value in this step moves into the next step,
2169			// the increment is the start of the next step - the current value
2170			if ( increment !== false ) {
2171				if ( value + increment > nearbySteps.stepAfter.startValue ) {
2172					increment = nearbySteps.stepAfter.startValue - value;
2173				}
2174			}
2175			// If the value is beyond the starting point
2176			if ( value > nearbySteps.thisStep.startValue ) {
2177				decrement = nearbySteps.thisStep.step;
2178			} else if ( nearbySteps.stepBefore.step === false ) {
2179				decrement = false;
2180			} else { // If a handle is at the start of a step, it always steps back into the previous step first
2181				decrement = value - nearbySteps.stepBefore.highestStep;
2182			}
2183			// Now, if at the slider edges, there is no in/decrement
2184			if ( location === 100 ) {
2185				increment = null;
2186			} else if ( location === 0 ) {
2187				decrement = null;
2188			}
2189			// As per #391, the comparison for the decrement step can have some rounding issues.
2190			stepDecimals = scope_Spectrum.countStepDecimals();
2191			// Round per #391
2192			if ( increment !== null && increment !== false ) {
2193				increment = Number( increment.toFixed( stepDecimals ) );
2194			}
2195			if ( decrement !== null && decrement !== false ) {
2196				decrement = Number( decrement.toFixed( stepDecimals ) );
2197			}
2198			return [ decrement, increment ];
2199		}
2200		// Get the current step size for the slider.
2201		function getNextSteps() {
2202			return scope_HandleNumbers.map( getNextStepsForHandle );
2203		}
2204		// Updatable: margin, limit, padding, step, range, animate, snap
2205		function updateOptions( optionsToUpdate, fireSetEvent ) {
2206			// Spectrum is created using the range, snap, direction and step options.
2207			// 'snap' and 'step' can be updated.
2208			// If 'snap' and 'step' are not passed, they should remain unchanged.
2209			var v = valueGet();
2210			var updateAble = [
2211				'margin',
2212				'limit',
2213				'padding',
2214				'range',
2215				'animate',
2216				'snap',
2217				'step',
2218				'format',
2219				'pips',
2220				'tooltips'
2221			];
2222			var newOptions;
2223			// Only change options that we're actually passed to update.
2224			updateAble.forEach( function( name ) {
2225				// Check for undefined. null removes the value.
2226				if ( optionsToUpdate[ name ] !== undefined ) {
2227					originalOptions[ name ] = optionsToUpdate[ name ];
2228				}
2229			} );
2230			newOptions = testOptions( originalOptions );
2231			// Load new options into the slider state
2232			updateAble.forEach( function( name ) {
2233				if ( optionsToUpdate[ name ] !== undefined ) {
2234					options[ name ] = newOptions[ name ];
2235				}
2236			} );
2237			scope_Spectrum = newOptions.spectrum;
2238			// Limit, margin and padding depend on the spectrum but are stored outside of it. (#677)
2239			options.margin = newOptions.margin;
2240			options.limit = newOptions.limit;
2241			options.padding = newOptions.padding;
2242			// Update pips, removes existing.
2243			if ( options.pips ) {
2244				pips( options.pips );
2245			} else {
2246				removePips();
2247			}
2248			// Update tooltips, removes existing.
2249			if ( options.tooltips ) {
2250				tooltips();
2251			} else {
2252				removeTooltips();
2253			}
2254			// Invalidate the current positioning so valueSet forces an update.
2255			scope_Locations = [];
2256			valueSet( isSet( optionsToUpdate.start ) ? optionsToUpdate.start : v, fireSetEvent );
2257		}
2258		// Initialization steps
2259		function setupSlider() {
2260			// Create the base element, initialize HTML and set classes.
2261			// Add handles and connect elements.
2262			scope_Base = addSlider( scope_Target );
2263			addElements( options.connect, scope_Base );
2264			// Attach user events.
2265			bindSliderEvents( options.events );
2266			// Use the public value method to set the start values.
2267			valueSet( options.start );
2268			if ( options.pips ) {
2269				pips( options.pips );
2270			}
2271			if ( options.tooltips ) {
2272				tooltips();
2273			}
2274			aria();
2275		}
2276		setupSlider();
2277		scope_Self = {
2278			destroy: destroy,
2279			steps: getNextSteps,
2280			on: bindEvent,
2281			off: removeEvent,
2282			get: valueGet,
2283			set: valueSet,
2284			setHandle: valueSetHandle,
2285			reset: valueReset,
2286			disable: disable,
2287			enable: enable,
2288			// Exposed for unit testing, don't use this in your application.
2289			__moveHandles: function( upward, proposal, handleNumbers ) {
2290				moveHandles( upward, proposal, scope_Locations, handleNumbers );
2291			},
2292			options: originalOptions,
2293			updateOptions: updateOptions,
2294			target: scope_Target,
2295			removePips: removePips,
2296			removeTooltips: removeTooltips,
2297			getPositions: function() {
2298				return scope_Locations.slice();
2299			},
2300			getTooltips: function() {
2301				return scope_Tooltips;
2302			},
2303			getOrigins: function() {
2304				return scope_Handles;
2305			},
2306			pips: pips // Issue #594
2307		};
2308		return scope_Self;
2309	}
2310	// Run the standard initializer
2311	function initialize( target, originalOptions ) {
2312		var options;
2313		var api;
2314		if ( ! target || ! target.nodeName ) {
2315			throw new Error( 'noUiSlider: create requires a single element, got: ' + target );
2316		}
2317		// Throw an error if the slider was already initialized.
2318		if ( target.noUiSlider ) {
2319			throw new Error( 'noUiSlider: Slider was already initialized.' );
2320		}
2321		// Test the options and create the slider environment;
2322		options = testOptions( originalOptions );
2323		api = scope( target, options, originalOptions );
2324		target.noUiSlider = api;
2325		return api;
2326	}
2327	nouislider = {
2328		// Exposed for unit testing, don't use this in your application.
2329		__spectrum: Spectrum,
2330		// A reference to the default classes, allows global changes.
2331		// Use the cssClasses option for changes to one slider.
2332		cssClasses: cssClasses,
2333		create: initialize
2334	};
2335
2336	exports.create = initialize;
2337	exports.cssClasses = cssClasses;
2338	exports.default = nouislider;
2339
2340	Object.defineProperty( exports, '__esModule', { value: true } );
2341} ) ) );

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.