function () {
    var childClusters = this._childClusters.slice(),
      map = this._group._map,
      boundsZoom = map.getBoundsZoom(this._bounds),
      zoom = this._zoom + 1,
      mapZoom = map.getZoom(),
      i;

    //calculate how far we need to zoom down to see all of the markers
    while (childClusters.length > 0 && boundsZoom > zoom) {
      zoom++;
      var newClusters = [];
      for (i = 0; i < childClusters.length; i++) {
        newClusters = newClusters.concat(childClusters[i]._childClusters);
      }
      childClusters = newClusters;
    }

    if (boundsZoom > zoom) {
      this._group._map.setView(this._latlng, zoom);
    } else if (boundsZoom <= mapZoom) { //If fitBounds wouldn't zoom us down, zoom us down instead
      this._group._map.setView(this._latlng, mapZoom + 1);
    } else {
      this._group._map.fitBounds(this._bounds);
    }
  }

function ( ) { var childClusters = this . _childClusters . slice ( ) , map = this . _group . _map , boundsZoom = map . getBoundsZoom ( this . _bounds ) , zoom = this . _zoom + 1 , mapZoom = map . getZoom ( ) , i ; while ( childClusters . length > 0 && boundsZoom > zoom ) { zoom ++ ; var newClusters = [ ] ; for ( i = 0 ; i < childClusters . length ; i ++ ) { newClusters = newClusters . concat ( childClusters [ i ] . _childClusters ) ; } childClusters = newClusters ; } if ( boundsZoom > zoom ) { this . _group . _map . setView ( this . _latlng , zoom ) ; } else if ( boundsZoom <= mapZoom ) { this . _group . _map . setView ( this . _latlng , mapZoom + 1 ) ; } else { this . _group . _map . fitBounds ( this . _bounds ) ; } }

Zoom to the minimum of showing all of the child markers, or the extents of this cluster

Zoom to the minimum of showing all of the child markers or the extents of this cluster


function (marker) {
    var addedCount,
        addedLatLng = marker._wLatLng || marker._latlng;

    if (marker instanceof L.MarkerCluster) {
      this._bounds.extend(marker._bounds);
      addedCount = marker._childCount;
    } else {
      this._bounds.extend(addedLatLng);
      addedCount = 1;
    }

    if (!this._cLatLng) {
      // when clustering, take position of the first point as the cluster center
      this._cLatLng = marker._cLatLng || addedLatLng;
    }

    // when showing clusters, take weighted average of all points as cluster center
    var totalCount = this._childCount + addedCount;

    //Calculate weighted latlng for display
    if (!this._wLatLng) {
      this._latlng = this._wLatLng = new L.LatLng(addedLatLng.lat, addedLatLng.lng);
    } else {
      this._wLatLng.lat = (addedLatLng.lat * addedCount + this._wLatLng.lat * this._childCount) / totalCount;
      this._wLatLng.lng = (addedLatLng.lng * addedCount + this._wLatLng.lng * this._childCount) / totalCount;
    }
  }

function ( marker ) { var addedCount , addedLatLng = marker . _wLatLng || marker . _latlng ; if ( marker instanceof L . MarkerCluster ) { this . _bounds . extend ( marker . _bounds ) ; addedCount = marker . _childCount ; } else { this . _bounds . extend ( addedLatLng ) ; addedCount = 1 ; } if ( ! this . _cLatLng ) { this . _cLatLng = marker . _cLatLng || addedLatLng ; } var totalCount = this . _childCount + addedCount ; if ( ! this . _wLatLng ) { this . _latlng = this . _wLatLng = new L . LatLng ( addedLatLng . lat , addedLatLng . lng ) ; } else { this . _wLatLng . lat = ( addedLatLng . lat * addedCount + this . _wLatLng . lat * this . _childCount ) / totalCount ; this . _wLatLng . lng = ( addedLatLng . lng * addedCount + this . _wLatLng . lng * this . _childCount ) / totalCount ; } }

Expand our bounds and tell our parent to


function () {
    if (this._group._spiderfied === this || this._group._inZoomAnimation) {
      return;
    }

    var childMarkers = this.getAllChildMarkers(),
      group = this._group,
      map = group._map,
      center = map.latLngToLayerPoint(this._latlng),
      positions;

    this._group._unspiderfy();
    this._group._spiderfied = this;

    //TODO Maybe: childMarkers order by distance to center

    if (childMarkers.length >= this._circleSpiralSwitchover) {
      positions = this._generatePointsSpiral(childMarkers.length, center);
    } else {
      center.y += 10; //Otherwise circles look wrong
      positions = this._generatePointsCircle(childMarkers.length, center);
    }

    this._animationSpiderfy(childMarkers, positions);
  }

function ( ) { if ( this . _group . _spiderfied === this || this . _group . _inZoomAnimation ) { return ; } var childMarkers = this . getAllChildMarkers ( ) , group = this . _group , map = group . _map , center = map . latLngToLayerPoint ( this . _latlng ) , positions ; this . _group . _unspiderfy ( ) ; this . _group . _spiderfied = this ; if ( childMarkers . length >= this . _circleSpiralSwitchover ) { positions = this . _generatePointsSpiral ( childMarkers . length , center ) ; } else { center . y += 10 ; positions = this . _generatePointsCircle ( childMarkers . length , center ) ; } this . _animationSpiderfy ( childMarkers , positions ) ; }

show spiral instead of circle from this marker count upwards. 0 -> always spiral; Infinity -> always circle

show spiral instead of circle from this marker count upwards . 0 - > always spiral ; Infinity - > always circle


function (childMarkers, positions) {
    var group = this._group,
      map = group._map,
      fg = group._featureGroup,
      i, m, leg, newPos;

    for (i = childMarkers.length - 1; i >= 0; i--) {
      newPos = map.layerPointToLatLng(positions[i]);
      m = childMarkers[i];

      m._preSpiderfyLatlng = m._latlng;
      m.setLatLng(newPos);
      if (m.setZIndexOffset) {
        m.setZIndexOffset(1000000); //Make these appear on top of EVERYTHING
      }

      fg.addLayer(m);

      leg = new L.Polyline([this._latlng, newPos], { weight: 1.5, color: '#222' });
      map.addLayer(leg);
      m._spiderLeg = leg;
    }
    this.setOpacity(0.3);
    group.fire('spiderfied');
  }

function ( childMarkers , positions ) { var group = this . _group , map = group . _map , fg = group . _featureGroup , i , m , leg , newPos ; for ( i = childMarkers . length - 1 ; i >= 0 ; i -- ) { newPos = map . layerPointToLatLng ( positions [ i ] ) ; m = childMarkers [ i ] ; m . _preSpiderfyLatlng = m . _latlng ; m . setLatLng ( newPos ) ; if ( m . setZIndexOffset ) { m . setZIndexOffset ( 1000000 ) ; } fg . addLayer ( m ) ; leg = new L . Polyline ( [ this . _latlng , newPos ] , { weight : 1.5 , color : '#222' } ) ; map . addLayer ( leg ) ; m . _spiderLeg = leg ; } this . setOpacity ( 0.3 ) ; group . fire ( 'spiderfied' ) ; }


function (layer) {
    if (layer._spiderLeg) {
      this._featureGroup.removeLayer(layer);

      layer.setOpacity(1);
      //Position will be fixed up immediately in _animationUnspiderfy
      layer.setZIndexOffset(0);

      this._map.removeLayer(layer._spiderLeg);
      delete layer._spiderLeg;
    }
  }

function ( layer ) { if ( layer . _spiderLeg ) { this . _featureGroup . removeLayer ( layer ) ; layer . setOpacity ( 1 ) ; layer . setZIndexOffset ( 0 ) ; this . _map . removeLayer ( layer . _spiderLeg ) ; delete layer . _spiderLeg ; } }

If the given layer is currently being spiderfied then we unspiderfy it so it isn't on the map anymore etc

If the given layer is currently being spiderfied then we unspiderfy it so it isn t on the map anymore etc


function addToMap(location, map) {
    var marker = L.marker(location.coordinates);
    marker.addTo(map);
  }

function addToMap ( location , map ) { var marker = L . marker ( location . coordinates ) ; marker . addTo ( map ) ; }

Have to create a separate marker for each map else weirdness happens


function interpolate (path, data) {
  return path.replace(/:(\w+)/g, function (match, param) {
    return data[param]
  })
}

function interpolate ( path , data ) { return path . replace ( / :(\w+) / g , function ( match , param ) { return data [ param ] } ) }

Interpolate the page path with pagination variables.

@param  {String} path
@param  {Object} data
@return {String}

Interpolate the page path with pagination variables .


function createPagesUtility (pages, index) {
  return function getPages (number) {
    var offset = Math.floor(number / 2)
    var start, end

    if (index + offset >= pages.length) {
      start = Math.max(0, pages.length - number)
      end = pages.length
    } else {
      start = Math.max(0, index - offset)
      end = Math.min(start + number, pages.length)
    }

    return pages.slice(start, end)
  }
}

function createPagesUtility ( pages , index ) { return function getPages ( number ) { var offset = Math . floor ( number / 2 ) var start , end if ( index + offset >= pages . length ) { start = Math . max ( 0 , pages . length - number ) end = pages . length } else { start = Math . max ( 0 , index - offset ) end = Math . min ( start + number , pages . length ) } return pages . slice ( start , end ) } }

Create a "get pages" utility for people to use when rendering.

@param  {Array}    pages
@param  {number}   index
@return {Function}

Create a get pages utility for people to use when rendering .


function() {
        var templates = { data: {} };

        var stringTemplateSource = function(template) {
            this.text = function(value) {
                if (arguments.length === 0) {
                    return templates[template];
                }
                templates[template] = value;
            };
        };

        var templateEngine = new ko.nativeTemplateEngine();
        templateEngine.makeTemplateSource = function(template) {
            return new stringTemplateSource(template);
        };

        templateEngine.addTemplate = function(key, value) {
            templates[key] = value;
        };

        return templateEngine;
    }

function ( ) { var templates = { data : { } } ; var stringTemplateSource = function ( template ) { this . text = function ( value ) { if ( arguments . length === 0 ) { return templates [ template ] ; } templates [ template ] = value ; } ; } ; var templateEngine = new ko . nativeTemplateEngine ( ) ; templateEngine . makeTemplateSource = function ( template ) { return new stringTemplateSource ( template ) ; } ; templateEngine . addTemplate = function ( key , value ) { templates [ key ] = value ; } ; return templateEngine ; }

helper engine that can use a template from a string


function Job(collection, data) {
    this.collection = collection;

    if (data) {
        // Convert plain object to JobData type
        data.__proto__ = JobData.prototype;
        this.data = data;
    } else {
        this.data = new JobData();
    }
}

function Job ( collection , data ) { this . collection = collection ; if ( data ) { data . __proto__ = JobData . prototype ; this . data = data ; } else { this . data = new JobData ( ) ; } }

Job retry specification
@typedef {Object} Job~Attempts
@property {string} strategy - Name of {@link Worker~strategyCallback} to use on retry
@property {number} count - total number of attempts so far
@property {number} delay - a delay constant for use in determining a delay.  In default linear strategy, this will be the delay between attempts

@constructor
@param {string} collection - The collection to save the job to
@param {Object} data - The Job data


function Worker(queues, options) {
    options || (options = {});

    this.empty = 0;
    this.queues = queues || [];
    this.interval = options.interval || 5000;

    this.callbacks = options.callbacks || {};
    this.strategies = options.strategies || {};
    this.universal = options.universal || false;

    // Default retry strategies
    this.strategies.linear || (this.strategies.linear = linear);
    this.strategies.exponential || (this.strategies.exponential = exponential);

    // This worker will only process jobs of this priority or higher
    this.minPriority = options.minPriority;

}

function Worker ( queues , options ) { options || ( options = { } ) ; this . empty = 0 ; this . queues = queues || [ ] ; this . interval = options . interval || 5000 ; this . callbacks = options . callbacks || { } ; this . strategies = options . strategies || { } ; this . universal = options . universal || false ; this . strategies . linear || ( this . strategies . linear = linear ) ; this . strategies . exponential || ( this . strategies . exponential = exponential ) ; this . minPriority = options . minPriority ; }

Options for a new worker
@typedef {Object} Worker~Options
@property {Number} interval - the polling interval for the worker. Note: The worker will process jobs, one at a time, as fast as possible while queues have waiting jobs
@property {Worker~Strategies} strategies - {@link Worker~Strategies} for retrying jobs
@property {Worker~Callbacks} callbacks - Map of {@link Worker~Callback} for processing jobs
@property {Number} minPriority - The lowest job priority the worker will process

@constructor
@param {string[]} queues - an array of queue names that this worker will listen for
@param {Worker~Options} options - {@link Worker~Options} Options object


function handleDragEvents(e) {
    e.stopPropagation();
    e.preventDefault();
    return this.emit(e.type, e);
  }

function handleDragEvents ( e ) { e . stopPropagation ( ) ; e . preventDefault ( ) ; return this . emit ( e . type , e ) ; }


function(value) {
            if(value != value || value === 0) {
                for(var i = this.length; i-- && !is(this[i], value);){}
            } else {
                i = [].indexOf.call(this, value);
            }
            return i;
        }

function ( value ) { if ( value != value || value === 0 ) { for ( var i = this . length ; i -- && ! is ( this [ i ] , value ) ; ) { } } else { i = [ ] . indexOf . call ( this , value ) ; } return i ; }

More reliable indexOf, courtesy of @WebReflection


function Tor(child, port, dir) {
  this.process = child;
  this.port    = port;
  this.dir     = dir;
}

function Tor ( child , port , dir ) { this . process = child ; this . port = port ; this . dir = dir ; }

A wrapper for the tor process containing its ChildProcess, port number
and data directory.

@param {ChildProcess} child
@param {int}          port
@param {string}       dir

A wrapper for the tor process containing its ChildProcess port number and data directory .


function getIncluded() {
  var args = config.files().included || getDefaultArgs() ||
              getPackageJsonArgs() || getBowerJsonArgs() || [];
  return _expandGlobs(args);
}

function getIncluded ( ) { var args = config . files ( ) . included || getDefaultArgs ( ) || getPackageJsonArgs ( ) || getBowerJsonArgs ( ) || [ ] ; return _expandGlobs ( args ) ; }

Returns an Array containing the included locations.

Returns an Array containing the included locations .


function getDefaultArgs() {
  var results = [];
  DEFAULT_PATHS.forEach(function(dir) {
    if( fs.existsSync(dir) ) results.push(dir);
  });
  return results.length == 0 ? null : results;
}

function getDefaultArgs ( ) { var results = [ ] ; DEFAULT_PATHS . forEach ( function ( dir ) { if ( fs . existsSync ( dir ) ) results . push ( dir ) ; } ) ; return results . length == 0 ? null : results ; }


function getPackageJsonArgs() {
  var results = [];
  var config = _loadJson('package.json');
  if( config.main ) results = results.concat(getMainFieldAsArray(config.main));
  if( config.files ) results = results.concat(config.files);
  return results.length == 0 ? null : results.filter(_uniqfilter);
}

function getPackageJsonArgs ( ) { var results = [ ] ; var config = _loadJson ( 'package.json' ) ; if ( config . main ) results = results . concat ( getMainFieldAsArray ( config . main ) ) ; if ( config . files ) results = results . concat ( config . files ) ; return results . length == 0 ? null : results . filter ( _uniqfilter ) ; }

Checks package . json for possible paths


function getBowerJsonArgs() {
  var results = [];
  var config = _loadJson('bower.json');
  if( config.main ) results = results.concat(getMainFieldAsArray(config.main));
  return results.length == 0 ? null : results.filter(_uniqfilter);
}

function getBowerJsonArgs ( ) { var results = [ ] ; var config = _loadJson ( 'bower.json' ) ; if ( config . main ) results = results . concat ( getMainFieldAsArray ( config . main ) ) ; return results . length == 0 ? null : results . filter ( _uniqfilter ) ; }


function getMainFieldAsArray(main) {
  if( main.constructor === Array ) {
    return main;
  } else {
    if( fs.existsSync(main) ) {
      return [main];
    } else if( fs.existsSync(main+'.js') ) {
      return [main+'.js'];
    } else {
      return [];
    }
  }
}

function getMainFieldAsArray ( main ) { if ( main . constructor === Array ) { return main ; } else { if ( fs . existsSync ( main ) ) { return [ main ] ; } else if ( fs . existsSync ( main + '.js' ) ) { return [ main + '.js' ] ; } else { return [ ] ; } } }

Returns an Array of the files mentioned in a 'main' field
If the value is noted without '.js' at the end, it is appended.

Returns an Array of the files mentioned in a main field If the value is noted without . js at the end it is appended .


function TorAgent(opts) {
  if (!(this instanceof TorAgent)) {
    return new TorAgent();
  }

  http.Agent.call(this, opts);

  this.socksHost   = opts.socksHost || 'localhost';
  this.socksPort   = opts.socksPort || 9050;
  this.defaultPort = 80;

  // Used when invoking TorAgent.create
  this.tor = opts.tor;

  // Prevent protocol check, wrap destroy
  this.protocol = null;
  this.defaultDestroy = this.destroy;
  this.destroy = this.destroyWrapper;
}

function TorAgent ( opts ) { if ( ! ( this instanceof TorAgent ) ) { return new TorAgent ( ) ; } http . Agent . call ( this , opts ) ; this . socksHost = opts . socksHost || 'localhost' ; this . socksPort = opts . socksPort || 9050 ; this . defaultPort = 80 ; this . tor = opts . tor ; this . protocol = null ; this . defaultDestroy = this . destroy ; this . destroy = this . destroyWrapper ; }

An HTTP Agent for proxying requests through Tor using SOCKS5.

@param {object} opts

An HTTP Agent for proxying requests through Tor using SOCKS5 .


function run(inch_args, options) {
  var callback = function(filename) {
      LocalInch.run(inch_args || ['suggest'], filename, noop);
    }

  if( options.dry_run ) callback = noop;
  retriever.run(PathExtractor.extractPaths(inch_args), callback);
}

function run ( inch_args , options ) { var callback = function ( filename ) { LocalInch . run ( inch_args || [ 'suggest' ] , filename , noop ) ; } if ( options . dry_run ) callback = noop ; retriever . run ( PathExtractor . extractPaths ( inch_args ) , callback ) ; }


function shutdown(addr, b) {
	    if(addr<0 || addr>=maxDevices)
			throw 'address out of range';

	    if(b)
			spiTransfer(addr, OP_SHUTDOWN,0);
	    else
			spiTransfer(addr, OP_SHUTDOWN,1);
	}

function
shutdown
(
addr
,
b
)
{
if
(
addr
<
0
||
addr
>=
maxDevices
)
throw
'address out of range'
;
if
(
b
)
spiTransfer
(
addr
,
OP_SHUTDOWN
,
0
)
;
else
spiTransfer
(
addr
,
OP_SHUTDOWN
,
1
)
;
}

shutdown puts it into power saving sleep mode. call with false to wake it up.

shutdown puts it into power saving sleep mode . call with false to wake it up .


function setScanLimit(addr, limit) {
	    if(addr<0 || addr>=maxDevices)
			return;

		//console.log("OP_SCANLIMIT");
	    if(limit>=0 && limit<8)
	    	spiTransfer(addr, OP_SCANLIMIT,limit);
	}

function setScanLimit ( addr , limit ) { if ( addr < 0 || addr >= maxDevices ) return ; if ( limit >= 0 && limit < 8 ) spiTransfer ( addr , OP_SCANLIMIT , limit ) ; }

sets the number of pixels per row, pretty much always 8 for most devices.

sets the number of pixels per row pretty much always 8 for most devices .


function setBrightness(addr, intensity) {
	    if(addr<0 || addr>=maxDevices)
			return;
	 	if (typeof intensity == 'undefined') return;

		intensity = constrain(intensity, 0, 15);

		spiTransfer(addr, OP_INTENSITY,intensity);

	}

function setBrightness ( addr , intensity ) { if ( addr < 0 || addr >= maxDevices ) return ; if ( typeof intensity == 'undefined' ) return ; intensity = constrain ( intensity , 0 , 15 ) ; spiTransfer ( addr , OP_INTENSITY , intensity ) ; }

sets the brightness of the LEDs, 0 to 15


function clearDisplay(addr) {
	    if(addr<0 || addr>=maxDevices)
			throw 'address out of range';

	    var offset;

	    offset=addr*8;
	    for(var i=0;i<8;i++) {
			status[offset+i]=0;
			spiTransfer(addr, i+1,status[offset+i]);
	    }
	}

function
clearDisplay
(
addr
)
{
if
(
addr
<
0
||
addr
>=
maxDevices
)
throw
'address out of range'
;
var
offset
;
offset
=
addr
*
8
;
for
(
var
i
=
0
;
i
<
8
;
i
++
)
{
status
[
offset
+
i
]
=
0
;
spiTransfer
(
addr
,
i
+
1
,
status
[
offset
+
i
]
)
;
}
}


function showNumber(addr, num, decimalplaces, mindigits, leftjustified, pos, dontclear) {

	    if(addr<0 || addr>=maxDevices)
			throw 'address out of range';

		num = formatNumber(num, decimalplaces, mindigits);

		// internally, pos is 0 on the right, so we set defaults, and convert
		if(typeof pos === 'undefined') {
			if(leftjustified) {
				pos = 7;
			} else {
				pos = 0;
			}
		} else pos = 7-pos;

		// get rid of the decimal place but remember where it was
		var decimalplace;
		if(num.indexOf('.')<0) decimalplace = -1;
		else {
			decimalplace = num.length - num.indexOf('.') -1;
			num = num.split('.').join('');
		}
		if(leftjustified) {
			pos-=(num.length-1);
		}

		for(var i = 0; i<8; i++) {
			var offset = i+pos;
			var char = num.charAt(num.length-1-i);

			if((offset<8 && offset>=0) && (!dontclear || char!=''))
			{
				if(char=='-') setChar(addr, offset, char, i>0 && i==decimalplace);
				else setDigit(addr, offset, parseInt(char), i>0 && i==decimalplace);
			}
		}

	}

function
showNumber
(
addr
,
num
,
decimalplaces
,
mindigits
,
leftjustified
,
pos
,
dontclear
)
{
if
(
addr
<
0
||
addr
>=
maxDevices
)
throw
'address out of range'
;
num
=
formatNumber
(
num
,
decimalplaces
,
mindigits
)
;
if
(
typeof
pos
===
'undefined'
)
{
if
(
leftjustified
)
{
pos
=
7
;
}
else
{
pos
=
0
;
}
}
else
pos
=
7
pos
;
var
decimalplace
;
if
(
num
.
indexOf
(
'.'
)
<
0
)
decimalplace
=
1
;
else
{
decimalplace
=
num
.
length
num
.
indexOf
(
'.'
)
1
;
num
=
num
.
split
(
'.'
)
.
join
(
''
)
;
}
if
(
leftjustified
)
{
pos
-=
(
num
.
length
1
)
;
}
for
(
var
i
=
0
;
i
<
8
;
i
++
)
{
var
offset
=
i
+
pos
;
var
char
=
num
.
charAt
(
num
.
length
1
i
)
;
if
(
(
offset
<
8
&&
offset
>=
0
)
&&
(
!
dontclear
||
char
!=
''
)
)
{
if
(
char
==
'-'
)
setChar
(
addr
,
offset
,
char
,
i
>
0
&&
i
==
decimalplace
)
;
else
setDigit
(
addr
,
offset
,
parseInt
(
char
)
,
i
>
0
&&
i
==
decimalplace
)
;
}
}
}

pos is passed in as 0 to 7, 0 on the left, 7 on the right

pos is passed in as 0 to 7 0 on the left 7 on the right


function getExampleCode(comment) {
  var expectedResult = comment.expectedResult;
  var isAsync = comment.isAsync;
  var testCase = comment.testCase;

  if(isAsync) {
    return '\nfunction cb(err, result) {' +
      'if(err) return done(err);' +
      'result.should.eql(' + expectedResult + ');' +
      'done();' +
    '}\n' +
    'var returnValue = ' + testCase + ';' +
    'if(returnValue && returnValue.then && typeof returnValue.then === \'function\') {' +
      'returnValue.then(cb.bind(null, null), cb);' +
    '}';
  } else {
    return '(' + testCase + ').should.eql(' + expectedResult + ');';
  }
}

Compiles down an `example`. Async examples call an imaginary `done` function
once they're done.

@param {Object} comment
@param {String} comment.testCase
@param {String} comment.expectedResult
@param {Boolean} comment.isAsync
@return {String}

Compiles down an example . Async examples call an imaginary done function once they re done .


function (options) {
    "use strict";
    if ((options.setter && options.setter.indexOf('.') > -1) || (options.getter && options.getter.indexOf('.') > -1)) {
        throw new Error('Getter (' + options.getter + ') and setter (' + options.setter + ') methods cannot be nested, so they cannot contain dot(.)');
    }

    this.options = Joi.attempt(options, optionsSchema);
    this.locales = this.getAvailableLocales();
    this.default = this.options.default || this.locales[0];
    //this.callback   = this.getCallback(this.options.callback);
}

Class to implement inner working of plugin.
@param {PluginOptions} options     - Plugin configuration options.
@constructor
@private

Class to implement inner working of plugin .


function fileExists(path, shouldBeDir) {
    "use strict";
    try {
        var lstat = fs.lstatSync(path);
        if (shouldBeDir && lstat.isDirectory()) {
            return true;
        }
        if (!shouldBeDir && lstat.isFile()) {
            return true;
        }
    } catch (err) {
        return false;
    }
    return false;
}

function
fileExists
(
path
,
shouldBeDir
)
{
"use strict"
;
try
{
var
lstat
=
fs
.
lstatSync
(
path
)
;
if
(
shouldBeDir
&&
lstat
.
isDirectory
(
)
)
{
return
true
;
}
if
(
!
shouldBeDir
&&
lstat
.
isFile
(
)
)
{
return
true
;
}
}
catch
(
err
)
{
return
false
;
}
return
false
;
}

Checks synchroniously if given file or directory exists. Returns true or false.
@param {string}  path        - Path of the file or directory.
@param {boolean} shouldBeDir - Whether given path should be directory.
@returns {boolean}
@private

Checks synchroniously if given file or directory exists . Returns true or false .


async function (server, options) {
        try {
            var internal = new Internal(options);
        } catch (err) {
            throw new Boom(err);
        }

        /**
         * @module exposed
         * @description
         * Exposed functions and attributes are listed under exposed name.
         * To access those attributes `request.server.plugins['hapi-locale']` can be used.
         * @example
         * var locales = request.server.plugins['hapi-locale'].getLocales(); // ['tr_TR', 'en_US'] etc.
         */

        /**
         * Returns all available locales as an array.
         * @name getLocales
         * @function
         * @returns {Array.<string>}    - Array of locales.
         * @example
         * var locales = request.server.plugins['hapi-locale'].getLocales(); // ['tr_TR', 'en_US'] etc.
         */
        server.expose('getLocales', function getLocales() {
            return internal.locales;
        });

        /**
         * Returns default locale.
         * @name getDefaultLocale
         * @function
         * @returns {string}    - Default locale
         */
        server.expose('getDefaultLocale', function getDefaultLocale() {
            return internal.default;
        });

        /**
         * Returns requested language.
         * @name getLocale
         * @function
         * @param {Object}      request - Hapi.js request object
         * @returns {string}    Locale
         */
        server.expose('getLocale', function getLocale(request) {
            try {
                return lodash.get(request, internal.options.getter)();
            } catch (err) {
                return null;
            }
        });

        server.ext(internal.options.onEvent, internal.processRequest, {bind: internal});
    }

async function ( server , options ) { try { var internal = new Internal ( options ) ; } catch ( err ) { throw new Boom ( err ) ; } server . expose ( 'getLocales' , function getLocales ( ) { return internal . locales ; } ) ; server . expose ( 'getDefaultLocale' , function getDefaultLocale ( ) { return internal . default ; } ) ; server . expose ( 'getLocale' , function getLocale ( request ) { try { return lodash . get ( request , internal . options . getter ) ( ) ; } catch ( err ) { return null ; } } ) ; server . ext ( internal . options . onEvent , internal . processRequest , { bind : internal } ) ; }

Hapi plugin function which adds i18n support to request and response objects.
@param {Object}          server      - Hapi server object
@param {PluginOptions}   options     - Plugin configuration options.

Hapi plugin function which adds i18n support to request and response objects .


function (currDeps, loc) {
      loc.deps = loc.deps || [];
      var covered = []; // only cover unique paths once to avoid stack overflow
      currDeps.forEach(function (obj) {
        if (covered.indexOf(obj.path) < 0) {
          covered.push(obj.path); // cover unique paths only once per level

          var key = obj.name
            , isRelative = (['\\', '/', '.'].indexOf(key[0]) >= 0)
            , notCovered = notCoveredInArray(loc.deps, key)
            , isRecorded = (!isRelative || opts.showLocal) && notCovered
            , res = isRecorded ? { name: key } : loc;

          if (isRecorded) {
            // NB: !isRecorded => only inspect the file for recorded deps
            res.path = obj.path;
            loc.deps.push(res);
          }

          // recurse (!isRecorded => keep adding to previous location)
          traverse(lookup[obj.path] || [], res);
        }
      });
    }

function ( currDeps , loc ) { loc . deps = loc . deps || [ ] ; var covered = [ ] ; currDeps . forEach ( function ( obj ) { if ( covered . indexOf ( obj . path ) < 0 ) { covered . push ( obj . path ) ; var key = obj . name , isRelative = ( [ '\\' , \\ , '/' ] . '.' indexOf >= ( key [ 0 ] ) ) , 0 , notCovered = notCoveredInArray ( loc . deps , key ) , isRecorded = ( ! isRelative || opts . showLocal ) && notCovered ; res = isRecorded ? { name : key } : loc if ( isRecorded ) { res . path = obj . path ; loc . deps . push ( res ) ; } } } ) ; }

build a dependency tree from the flat mdeps list by recursing


function (ms, cycles) {
  var removed = {};

  cycles.forEach(function (c) {
    var last = c[c.length-1]; // last id in cycle
    //console.log('will try to trim from', last, ms[last]);

    // need to find a dependency in the cycle
    var depsInCycle = ms[last].filter(function (deps) {
      return deps.path && c.indexOf(deps.path) >= 0;
    });
    if (!depsInCycle.length) {
      throw new Error("logic fail2"); // last thing in a cycle should have deps
    }
    var depToRemove = depsInCycle[0].path;
    //console.log('deps in cycle', depsInCycle);

    for (var i = 0; i < ms[last].length; i += 1) {
      var dep = ms[last][i];
      if (dep.path && dep.path === depToRemove) {
        //console.log('removing', depToRemove);
        removed[last] = dep.name;
        ms[last].splice(i, 1);
      }
    }
    //console.log('after remove', ms[last]);
  });

  return removed;
}

function
(
ms
,
cycles
)
{
var
removed
=
{
}
;
cycles
.
forEach
(
function
(
c
)
{
var
last
=
c
[
c
.
length
1
]
;
var
depsInCycle
=
ms
[
last
]
.
filter
(
function
(
deps
)
{
return
deps
.
path
&&
c
.
indexOf
(
deps
.
path
)
>=
0
;
}
)
;
if
(
!
depsInCycle
.
length
)
{
throw
new
Error
(
"logic fail2"
)
;
}
var
depToRemove
=
depsInCycle
[
0
]
.
path
;
for
(
var
i
=
0
;
i
<
ms
[
last
]
.
length
;
i
+=
1
)
{
var
dep
=
ms
[
last
]
[
i
]
;
if
(
dep
.
path
&&
dep
.
path
===
depToRemove
)
{
removed
[
last
]
=
dep
.
name
;
ms
[
last
]
.
splice
(
i
,
1
)
;
}
}
}
)
;
return
removed
;
}

given a modules array with cycles - trim dependencies in each cycle


function(options) {
  // Validate options
  assert(options,         "options are required");
  assert(options.name,    "Series must be named");
  options = _.defaults({}, options, {
    columns:              {},
    additionalColumns:    null
  });

  // Store options
  this._options = options;
}

function
(
options
)
{
assert
(
options
,
"options are required"
)
;
assert
(
options
.
name
,
"Series must be named"
)
;
options
=
_
.
defaults
(
{
}
,
options
,
{
columns
:
{
}
,
additionalColumns
:
}
)
;
this
.
_options
=
options
;
}

Create a times series that you can report to.

options:
{
// Name of the series in influxdb
name:               'ResponseTimes',

// Required columns
columns: {
method:           stats.types.String,
duration:         stats.types.Number,
custom:           stats.types.Any
},

// Type of additional columns if they are allowed (defaults `null`)
additionalColumns:  stats.types.String
}

Create a times series that you can report to .


function whenRead (args) {
    let value = getValue(args)
    if (value && typeof value.then === 'function') {
      value.then((val) => whenTest(args, val)).catch((error) => {
        console.error(`${action.displayName} caught an error whilst getting a value to test`, error)
      })
    } else {
      whenTest(args, value)
    }
  }

function whenRead ( args ) { let value = getValue ( args ) if ( value && typeof value . then === 'function' ) { value . then ( ( val ) => whenTest ( args , val ) ) . catch ( ( error ) => { console . error ( ` ${ action . displayName } ` , error ) } ) } else { whenTest ( args , value ) } }


function findAndDelete(target, value) {
    if (!isIterable(target))
        return false;
    if (isArray(target)) {
        for (let i = 0; i < target.length; i++) {
            if (deep_equal_1.default(target[i], value)) {
                target.splice(i, 1);
                return true;
            }
        }
    }
    else if (isObject(target)) {
        const keys = Object.keys(target);
        for (let i = 0; i < keys.length; i++) {
            if (deep_equal_1.default(target[keys[i]], value)) {
                delete target[keys[i]];
                return true;
            }
        }
    }
    return false;
}

function findAndDelete ( target , value ) { if ( ! isIterable ( target ) ) return false ; if ( isArray ( target ) ) { for ( let i = 0 ; i < target . length ; i ++ ) { if ( deep_equal_1 . default ( target [ i ] , value ) ) { target . splice ( i , 1 ) ; return true ; } } } else if ( isObject ( target ) ) { const keys = Object . keys ( target ) ; for ( let i = 0 ; i < keys . length ; i ++ ) { if ( deep_equal_1 . default ( target [ keys [ i ] ] , value ) ) { delete target [ keys [ i ] ] ; return true ; } } } return false ; }

Finds and deletes first encounter of value in target
@param target
@param value
@returns true if an element has been deleted, otherwise - false


function findAndDeleteAll(target, value) {
    let flag = false;
    while (findAndDelete(target, value)) {
        flag = true;
    }
    return flag;
}

function findAndDeleteAll ( target , value ) { let flag = false ; while ( findAndDelete ( target , value ) ) { flag = true ; } return flag ; }

Finds and deletes all encounters of value in target
@param target
@param value
@returns true if anything has been deleted, otherwise - false


function(options) {
  assert(options,                   "options are required");
  assert(options.connectionString,  "options.connectionString is missing");
  assert(url.parse(options.connectionString).protocol === 'https:' ||
         options.allowHTTP, "InfluxDB connectionString must use HTTPS!");
  options = _.defaults({}, options, {
    maxDelay:             60 * 5,
    maxPendingPoints:     250
  });
  this._options           = options;
  this._pendingPoints     = {};
  this._nbPendingPoints   = 0;
  this._flushTimeout = setTimeout(
    this.flush.bind(this, true),
    options.maxDelay * 1000
  );
}

Create an Influx Database Connection

options:
{
// Connection string for
connectionString:  '<protocol>://<user>:<pwd>@<host>:<port>/db/<database>',

// Max submission delay
maxDelay:          60 * 5, // 5 minutes

// Maximum number of pending points before writing
maxPendingPoints:  250,

// Allow the connection string to use HTTP instead of HTTPS, this option
// is just to prevent accidental deployments with HTTP instead of HTTPS
// (there is no reason not to use HTTPS).
allowHTTP:         false
}


function(handler, options) {
  assert(handler instanceof Function, "A handler must be provided");
  assert(options,                     "options required");
  assert(options.drain,               "options.drain is required");
  assert(options.component,           "options.component is required");

  // Create a reporter
  var reporter = series.HandlerReports.reporter(options.drain);

  // Wrap handler and let that be it
  return function(message) {
    // Create most of the point
    var point = {
      component:      options.component,
      duration:       undefined,
      exchange:       message.exchange || '',
      redelivered:    (message.redelivered ? 'true' : 'false'),
      error:          'false'
    };

    // Start timer
    var start = process.hrtime();

    // Handle the message
    return Promise.resolve(handler(message)).then(function() {
      // Get duration
      var d = process.hrtime(start);

      // Convert to milliseconds
      point.duration = d[0] * 1000 + (d[1] / 1000000);

      // Send point to reporter
      reporter(point);
    }, function(err) {
      // Get duration
      var d = process.hrtime(start);

      // Convert to milliseconds
      point.duration = d[0] * 1000 + (d[1] / 1000000);

      // Flag and error
      point.error = 'true';

      // Send point to reporter
      reporter(point);

      // Re-throw the error
      throw err;
    });
  };
}

function
(
handler
,
options
)
{
assert
(
handler
instanceof
Function
,
"A handler must be provided"
)
;
assert
(
options
,
"options required"
)
;
assert
(
options
.
drain
,
"options.drain is required"
)
;
assert
(
options
.
component
,
"options.component is required"
)
;
var
reporter
=
series
.
HandlerReports
.
reporter
(
options
.
drain
)
;
return
function
(
message
)
{
var
point
=
{
component
:
options
.
component
,
duration
:
undefined
,
exchange
:
message
.
exchange
||
''
,
redelivered
:
(
message
.
redelivered
'true'
:
'false'
)
,
error
:
'false'
}
;
var
start
=
process
.
hrtime
(
)
;
return
Promise
.
resolve
(
handler
(
message
)
)
.
then
(
function
(
)
{
var
d
=
process
.
hrtime
(
start
)
;
point
.
duration
=
d
[
0
]
*
1000
+
(
d
[
1
]
/
1000000
)
;
reporter
(
point
)
;
}
,
function
(
err
)
{
var
d
=
process
.
hrtime
(
start
)
;
point
.
duration
=
d
[
0
]
*
1000
+
(
d
[
1
]
/
1000000
)
;
point
.
error
=
'true'
;
reporter
(
point
)
;
throw
err
;
}
)
;
}
;
}

Create a handler timer for AMQP messages received through
taskcluster-client. Please note, that this relies on that messages format.

options:
{
drain:        new Influx(...),  // Place to send events
component:    'queue'           // Identifier for taskcluster component
}

Create a handler timer for AMQP messages received through taskcluster - client . Please note that this relies on that messages format .


function(options) {
  // Validate options
  assert(options,           "Options are required");
  assert(options.drain,     "A drain for the measurements must be provided!");
  assert(options.component, "A component must be specified");
  assert(options.process,   "A process name must be specified");

  // Provide default options
  options = _.defaults({}, options, {
    interval:         60
  });

  // Clear reporting if already started
  if (_processUsageReportingInterval) {
    debug("WARNING: startProcessUsageReporting() already started!");
    clearInterval(_processUsageReportingInterval);
    _processUsageReportingInterval = null;
  }

  // Lazy load the usage monitor module
  var usage = require('usage');

  // Create reporter
  var reporter = series.UsageReports.reporter(options.drain);

  // Set interval to report usage at interval
  _processUsageReportingInterval = setInterval(function() {
    // Lookup usage for the current process
    usage.lookup(process.pid, {keepHistory: true}, function(err, result) {
      // Check for error
      if (err) {
        debug("Failed to get usage statistics, err: %s, %j",
              err, err, err.stack);
        return;
      }

      // Report usage
      reporter({
        component:      options.component,
        process:        options.process,
        cpu:            result.cpu,
        memory:         result.memory
      });
    });
  }, options.interval * 1000);
}

Monitor CPU and memory for this instance.

options: {
drain:        new Influx(...), // Place to send the pings
interval:     60,              // Report every 1 minute
component:    'queue',         // Identifier for the taskcluster component
process:      'server'         // Process name
}

Note, this is global in the current process.

Monitor CPU and memory for this instance .


function(options) {
  options = _.defaults({}, options || {}, {
    tags:   {},
    drain:  undefined
  });
  assert(options.drain,                     "options.drain is required");
  assert(typeof options.tags === 'object',  "options.tags is required");
  assert(_.intersection(
    _.keys(options.tags), series.APIClientCalls.columns()
  ).length === 0, "Can't used reserved tag names!");

  // Create a reporter
  return series.APIClientCalls.reporter(options.drain, options.tags);
}

function
(
options
)
{
options
=
_
.
defaults
(
{
}
,
options
||
{
}
,
{
tags
:
{
}
,
drain
:
undefined
}
)
;
assert
(
options
.
drain
,
"options.drain is required"
)
;
assert
(
typeof
options
.
tags
===
'object'
,
"options.tags is required"
)
;
assert
(
_
.
intersection
(
_
.
keys
(
options
.
tags
)
,
series
.
APIClientCalls
.
columns
(
)
)
.
length
===
0
,
"Can't used reserved tag names!"
)
;
return
series
.
APIClientCalls
.
reporter
(
options
.
drain
,
options
.
tags
)
;
}

Create a stats handler for taskcluster-client clients which takes an option
`stats` as function that will be call after an API call.

options:
{
tags: {                         // Tags as key/value (both strings)
component: 'queue',           // Component identifier
process:   'web'              // Process identifier
// Common tags that are good to use includes:
//     component, process, provisionerId, workerType
},
drain:        new Influx(...),  // Place to send events
}

Create a stats handler for taskcluster - client clients which takes an option stats as function that will be call after an API call .


function buildOptions (options) {
  var result = [];

  var keys = Object.keys(options);

  keys.forEach(function (key) {
    var props = options[key];

    // convert short to long form
    if (is.string(props)) {
      props = {
        type: props
      };
    }

    // all names of an option
    // aliases come first
    // full name comes last
    var name = [
      format('--%s', dasherize(key))
    ];

    // accept both string and array
    var aliases = props.alias || props.aliases || [];

    if (is.not.array(aliases)) {
      aliases = [aliases];
    }

    // aliases are prefixed with "-"
    aliases.forEach(function (alias) {
      alias = format('-%s', alias);

      name.unshift(alias);
    });

    result.push([
      name.join(', '),
      props.desc || ''
    ]);
  });

  return table(result);
}

function
buildOptions
(
options
)
{
var
result
=
[
]
;
var
keys
=
Object
.
keys
(
options
)
;
keys
.
forEach
(
function
(
key
)
{
var
props
=
options
[
key
]
;
if
(
is
.
string
(
props
)
)
{
props
=
{
type
:
props
}
;
}
var
name
=
[
format
(
'--%s'
,
dasherize
(
key
)
)
]
;
var
aliases
=
props
.
alias
||
props
.
aliases
||
[
]
;
if
(
is
.
not
.
array
(
aliases
)
)
{
aliases
=
[
aliases
]
;
}
aliases
.
forEach
(
function
(
alias
)
{
alias
=
format
(
'-%s'
,
alias
)
;
name
.
unshift
(
alias
)
;
}
)
;
result
.
push
(
[
name
.
join
(
', '
)
,
props
.
desc
||
''
]
)
;
}
)
;
return
table
(
result
)
;
}


function buildCommands (commands) {
  var result = [];

  commands.forEach(function (command) {
    result.push([
      command.name,
      command.desc || ''
    ]);
  });

  return table(result);
}

function buildCommands ( commands ) { var result = [ ] ; commands . forEach ( function ( command ) { result . push ( [ command . name , command . desc || '' ] ) ; } ) ; return table ( result ) ; }


function Router(options) {
	const logPrefix = topLogPrefix + 'Router() - ';
	const that      = this;

	let defaultRouteFound = false;

	that.options = options || {};

	if (! that.options.paths) {
		that.options.paths = {
			'controller': {
				'path': 'controllers',
				'exts': 'js'
			},
			'static': {
				'path': 'public',
				'exts': false
			},
			'template': {
				'path': 'public/templates',
				'exts': ['tmpl', 'tmp', 'ejs', 'pug']
			}
		};
	}

	if (! that.options.routes)   that.options.routes   = [];
	if (! that.options.basePath) that.options.basePath = process.cwd();

	if (! that.options.log) {
		const lUtils = new LUtils();

		that.options.log = new lUtils.Log();
	}

	for (const key of Object.keys(that.options.paths)) {
		if (! Array.isArray(that.options.paths[key].exts) && that.options.paths[key].exts !== false) {
			that.options.paths[key].exts = [that.options.paths[key].exts];
		}
	}

	if (! that.options.lfs) {
		that.options.lfs = new Lfs({'basePath': that.options.basePath, 'log': that.options.log});
	}

	for (let i = 0; that.options.routes[i] !== undefined; i ++) {
		if (that.options.routes[i].regex === '^/$') {
			defaultRouteFound = true;
			break;
		}
	}

	// We should always have a default route, so if none exists, create one
	if (defaultRouteFound === false) {
		that.options.routes.push({
			'regex':          '^/$',
			'controllerPath': 'default.js',
			'templatePath':   'default.tmpl'
		});
	}

	for (const key of Object.keys(that.options)) {
		that[key] = that.options[key];
	}

	that.log.debug(logPrefix + 'Instantiated with options: ' + JSON.stringify(that.options));
}

function
Router
(
options
)
{
const
logPrefix
=
topLogPrefix
+
'Router() - '
;
const
that
=
this
;
let
defaultRouteFound
=
false
;
that
.
options
=
options
||
{
}
;
if
(
!
that
.
options
.
paths
)
{
that
.
options
.
paths
=
{
'controller'
:
{
'path'
:
'controllers'
,
'exts'
:
'js'
}
,
'static'
:
{
'path'
:
'public'
,
'exts'
:
false
}
,
'template'
:
{
'path'
:
'public/templates'
,
'exts'
:
[
'tmpl'
,
'tmp'
,
'ejs'
,
'pug'
]
}
}
;
}
if
(
!
that
.
options
.
routes
)
that
.
options
.
routes
=
[
]
;
if
(
!
that
.
options
.
basePath
)
that
.
options
.
basePath
=
process
.
cwd
(
)
;
if
(
!
that
.
options
.
log
)
{
const
lUtils
=
new
LUtils
(
)
;
that
.
options
.
log
=
new
lUtils
.
Log
(
)
;
}
for
(
const
key
of
Object
.
keys
(
that
.
options
.
paths
)
)
{
if
(
!
Array
.
isArray
(
that
.
options
.
paths
[
key
]
.
exts
)
&&
that
.
options
.
paths
[
key
]
.
exts
!==
false
)
{
that
.
options
.
paths
[
key
]
.
exts
=
[
that
.
options
.
paths
[
key
]
.
exts
]
;
}
}
if
(
!
that
.
options
.
lfs
)
{
that
.
options
.
lfs
=
new
Lfs
(
{
'basePath'
:
that
.
options
.
basePath
,
'log'
:
that
.
options
.
log
}
)
;
}
for
(
let
i
=
0
;
that
.
options
.
routes
[
i
]
!==
undefined
;
i
++
)
{
if
(
that
.
options
.
routes
[
i
]
.
regex
===
'^/$'
)
{
defaultRouteFound
=
true
;
break
;
}
}
if
(
defaultRouteFound
===
false
)
{
that
.
options
.
routes
.
push
(
{
'regex'
:
'^/$'
,
'controllerPath'
:
'default.js'
,
'templatePath'
:
'default.tmpl'
}
)
;
}
for
(
const
key
of
Object
.
keys
(
that
.
options
)
)
{
that
[
key
]
=
that
.
options
[
key
]
;
}
that
.
log
.
debug
(
logPrefix
+
'Instantiated with options: '
+
JSON
.
stringify
(
that
.
options
)
)
;
}

Module main constructor

@param {obj} options - {
'paths':           {
'controller': {
'path': 'controllers',
'exts': 'js'
},
'static': {
'path': 'public',
'exts': false
},
'template': {
'path': 'public/templates',
'exts': ['tmpl', 'tmp', 'ejs', 'pug']
}
},
'routes':   [],
'basePath': process.cwd(),
'log':      log object,
'lfs':      larvitfs instance
}


function getDefaultPortByProtocol (rawProtocol) {
  // port-numbers expect no trailing colon
  const protocol = rawProtocol.endsWith(':')
    ? rawProtocol.slice(0, -1)
    : rawProtocol

  // e.g. mailto has no port associated
  // example return value:
  // { port: 80, protocol: 'tcp', description: 'World Wide Web HTTP' }
  const portByProtocol = portNumbers.getPort(protocol)

  return portByProtocol
    ? Promise.resolve(String(portByProtocol.port))
    : Promise.reject(new Error('Has no port'))
}

function
getDefaultPortByProtocol
(
rawProtocol
)
{
const
protocol
=
rawProtocol
.
endsWith
(
':'
)
rawProtocol
.
slice
(
0
,
1
)
:
rawProtocol
const
portByProtocol
=
portNumbers
.
getPort
(
protocol
)
return
portByProtocol
Promise
.
resolve
(
String
(
portByProtocol
.
port
)
)
:
Promise
.
reject
(
new
Error
(
'Has no port'
)
)
}

Helper method to look up port by protocol.

@private
@param {string} rawProtocol - Protocol as returned by url, i.e. with :
@returns {Promise<string|Error>}
Associated port with protocol.
Or an Error if the validation failed (e.g. mailto:).

Helper method to look up port by protocol .


function clearScripts(node){
      var rslt = {};
      for(var key in node){
        var val = node[key];
        if(_.isString(val)){
          if(val.trim()) rslt[key] = "...";
        }
        else{
          var childScripts = clearScripts(val);
          if(!_.isEmpty(childScripts)) rslt[key] = childScripts;
        }
      }
      return rslt;
    }

function clearScripts ( node ) { var rslt = { } ; for ( var key in node ) { var val = node [ key ] ; if ( _ . isString ( val ) ) { if ( val . trim ( ) ) rslt [ key ] = "..." ; } else { var childScripts = clearScripts ( val ) ; if ( ! _ . isEmpty ( childScripts ) ) rslt [ key ] = childScripts ; } } return rslt ; }

Replace scripts with "..." and prune empty scripts

Replace scripts with ... and prune empty scripts


function(obj, array){
    if(!Array.prototype.indexOf){
      for(var i=0; i<array.length; i++){
          if(array[i]===obj){
              return i;
          }
      }
      return -1;
    }
    else {
      return array.indexOf(obj);
    }
  }

function ( obj , array ) { if ( ! Array . prototype . indexOf ) { for ( var i = 0 ; i < array . length ; i ++ ) { if ( array [ i ] === obj ) { return i ; } } return - 1 ; } else { return array . indexOf ( obj ) ; } }


function getElementValues(nodeList, initialScope) {
    const valueList = []

    for (let i = 0; i < nodeList.length; ++i) {
        const elementNode = nodeList[i]

        if (elementNode == null) {
            valueList.length = i + 1
        } else if (elementNode.type === "SpreadElement") {
            const argument = getStaticValueR(elementNode.argument, initialScope)
            if (argument == null) {
                return null
            }
            valueList.push(...argument.value)
        } else {
            const element = getStaticValueR(elementNode, initialScope)
            if (element == null) {
                return null
            }
            valueList.push(element.value)
        }
    }

    return valueList
}

function getElementValues ( nodeList , initialScope ) { const valueList = [ ] for ( let i = 0 ; i < nodeList . length ; ++ i ) { const elementNode = nodeList [ i ] if ( elementNode == null ) { valueList . length = i + 1 } else if ( elementNode . type === "SpreadElement" ) { const argument = getStaticValueR ( elementNode . argument , initialScope ) if ( argument == null ) { return null } valueList . push ( ... argument . value ) } else { const element = getStaticValueR ( elementNode , initialScope ) if ( element == null ) { return null } valueList . push ( element . value ) } } return valueList }

Get the element values of a given node list.
@param {Node[]} nodeList The node list to get values.
@param {Scope|undefined} initialScope The initial scope to find variables.
@returns {any[]|null} The value list if all nodes are constant. Otherwise, null.

Get the element values of a given node list .


function getStaticValueR(node, initialScope) {
    if (node != null && Object.hasOwnProperty.call(operations, node.type)) {
        return operations[node.type](node, initialScope)
    }
    return null
}

function getStaticValueR ( node , initialScope ) { if ( node != null && Object . hasOwnProperty . call ( operations , node . type ) ) { return operations [ node . type ] ( node , initialScope ) } return null }

Get the value of a given node if it's a static value.
@param {Node} node The node to get.
@param {Scope|undefined} initialScope The scope to start finding variable.
@returns {{value:any}|null} The static value of the node, or `null`.

Get the value of a given node if it s a static value .


function isModifiedGlobal(variable) {
    return (
        variable == null ||
        variable.defs.length !== 0 ||
        variable.references.some(r => r.isWrite())
    )
}

function isModifiedGlobal ( variable ) { return ( variable == null || variable . defs . length !== 0 || variable . references . some ( r => r . isWrite ( ) ) ) }

Check whether a given variable is modified or not.
@param {Variable} variable The variable to check.
@returns {boolean} `true` if the variable is modified.

Check whether a given variable is modified or not .


function config(ext) {
    return {
        input: "src/index.js",
        output: {
            file: `index${ext}`,
            format: ext === ".mjs" ? "es" : "cjs",
            sourcemap: true,
            sourcemapFile: `index${ext}.map`,
            strict: true,
            banner: `/*! @author Toru Nagashima <https://github.com/mysticatea> */`,
        },
        plugins: [sourcemaps()],
        external: Object.keys(require("./package.json").dependencies),
    }
}

function config ( ext ) { return { input : "src/index.js" , output : { file : ` ${ ext } ` , format : ext === ".mjs" ? "es" : "cjs" , sourcemap : true , sourcemapFile : ` ${ ext } ` , strict : true , banner : ` ` , } , plugins : [ sourcemaps ( ) ] , external : Object . keys ( require ( "./package.json" ) . dependencies ) , } }

Define the output configuration.
@param {string} ext The extension for generated files.
@returns {object} The output configuration


function isEscaped(str, index) {
    let escaped = false
    for (let i = index - 1; i >= 0 && str.charCodeAt(i) === 0x5c; --i) {
        escaped = !escaped
    }
    return escaped
}

function isEscaped ( str , index ) { let escaped = false for ( let i = index - 1 ; i >= 0 && str . charCodeAt ( i ) === 0x5c ; -- i ) { escaped = ! escaped } return escaped }

Check whether a given character is escaped or not.
@param {string} str The string to check.
@param {number} index The location of the character to check.
@returns {boolean} `true` if the character is escaped.

Check whether a given character is escaped or not .


function replaceS(matcher, str, replacement) {
    const chunks = []
    let index = 0

    /** @type {RegExpExecArray} */
    let match = null

    /**
     * @param {string} key The placeholder.
     * @returns {string} The replaced string.
     */
    function replacer(key) {
        switch (key) {
            case "$$":
                return "$"
            case "$&":
                return match[0]
            case "$`":
                return str.slice(0, match.index)
            case "$'":
                return str.slice(match.index + match[0].length)
            default: {
                const i = key.slice(1)
                if (i in match) {
                    return match[i]
                }
                return key
            }
        }
    }

    for (match of matcher.execAll(str)) {
        chunks.push(str.slice(index, match.index))
        chunks.push(replacement.replace(placeholder, replacer))
        index = match.index + match[0].length
    }
    chunks.push(str.slice(index))

    return chunks.join("")
}

function replaceS ( matcher , str , replacement ) { const chunks = [ ] let index = 0 let match = null function replacer ( key ) { switch ( key ) { case "$$" : return "$" case "$&" : return match [ 0 ] case "$`" : return str . slice ( 0 , match . index ) case "$'" : return str . slice ( match . index + match [ 0 ] . length ) default : { const i = key . slice ( 1 ) if ( i in match ) { return match [ i ] } return key } } } for ( match of matcher . execAll ( str ) ) { chunks . push ( str . slice ( index , match . index ) ) chunks . push ( replacement . replace ( placeholder , replacer ) ) index = match . index + match [ 0 ] . length } chunks . push ( str . slice ( index ) ) return chunks . join ( "" ) }

Replace a given string by a given matcher.
@param {PatternMatcher} matcher The pattern matcher.
@param {string} str The string to be replaced.
@param {string} replacement The new substring to replace each matched part.
@returns {string} The replaced string.

Replace a given string by a given matcher .


function replaceF(matcher, str, replace) {
    const chunks = []
    let index = 0

    for (const match of matcher.execAll(str)) {
        chunks.push(str.slice(index, match.index))
        chunks.push(String(replace(...match, match.index, match.input)))
        index = match.index + match[0].length
    }
    chunks.push(str.slice(index))

    return chunks.join("")
}

function replaceF ( matcher , str , replace ) { const chunks = [ ] let index = 0 for ( const match of matcher . execAll ( str ) ) { chunks . push ( str . slice ( index , match . index ) ) chunks . push ( String ( replace ( ... match , match . index , match . input ) ) ) index = match . index + match [ 0 ] . length } chunks . push ( str . slice ( index ) ) return chunks . join ( "" ) }

eslint-disable-next-line valid-jsdoc
Replace a given string by a given matcher.
@param {PatternMatcher} matcher The pattern matcher.
@param {string} str The string to be replaced.
@param {(...strs[])=>string} replace The function to replace each matched part.
@returns {string} The replaced string.

eslint - disable - next - line valid - jsdoc Replace a given string by a given matcher .


function send(msg) {
    switch(ps.readyState) {
      case 0: // CONNECTING
        setTimeout(function () { send(msg); }, 1000);
        break;
      case 2: // CLOSING
      case 3: // CLOSED
        _event('dev', 'pubsub - reconnect: send() - closing/closed state');
        connect();
        setTimeout(function () { send(msg); }, 2000);
        break;
      case 1: // OPEN
        try {
          ps.send(msg);
        } catch (err) {
          console.error(err);
          setTimeout(function () { send(msg); }, 1500);
        }
        break;
      default:
        break;
		}
  }

this provides some preventative error handling because the pubsub edge seems to be unstable


function parseMessage(data) {
    switch (data.topic) {
      // https://dev.twitch.tv/docs/v5/guides/PubSub/
      case 'channel-bits-events-v1.' + state.channel_id:
        bits();
        break;
      // https://discuss.dev.twitch.tv/t/in-line-broadcaster-chat-mod-logs/7281/12
      case 'chat_moderator_actions.' + state.id + '.' + state.id:
        moderation();
        break;
      case 'whispers.' + state.id:
        whisper();
        break;
      // case 'channel-subscribe-events-v1.' + state.channel_id:
      //   sub();
      //   break;
      default:
        break;
    }

    function bits() {
      let bits = JSON.parse(data.message);
      _event('bits', bits);
    }

    function moderation() {
      let moderation = JSON.parse(data.message).data;
      _event('moderation', moderation);
    }

    function whisper() {
      let message = JSON.parse(data.message).data_object;
      // TODO: figure out why some whispers are dropped...
      // _event('whisper', message);
    }

    // function sub() {
    //   // TODO: https://discuss.dev.twitch.tv/t/subscriptions-beta-changes/10023
    // }

  }

function parseMessage ( data ) { switch ( data . topic ) { case 'channel-bits-events-v1.' + state . channel_id : bits ( ) ; break ; case 'chat_moderator_actions.' + state . id + '.' + state . id : moderation ( ) ; break ; case 'whispers.' + state . id : whisper ( ) ; break ; default : break ; } function bits ( ) { let bits = JSON . parse ( data . message ) ; _event ( 'bits' , bits ) ; } function moderation ( ) { let moderation = JSON . parse ( data . message ) . data ; _event ( 'moderation' , moderation ) ; } function whisper ( ) { let message = JSON . parse ( data . message ) . data_object ; } }

data is message.data, so it should have msg.topic and msg.message

data is message . data so it should have msg . topic and msg . message


function JWT(secret, options) {
    this.token = '';
    this.payload = {};
    this.secret = secret;
    this.options = options;
    this.valid = false;
    this.expired = false;
    this.stale = true;
}

function JWT ( secret , options ) { this . token = '' ; this . payload = { } ; this . secret = secret ; this . options = options ; this . valid = false ; this . expired = false ; this . stale = true ; }

JWT - Class representing a JSON Web Token, it's payload, and it's status
@param string secret The secret to sign / verify with
@param object options The jwt-express options

JWT - Class representing a JSON Web Token it s payload and it s status


function(payload) {
        payload.stales = Date.now() + this.options.stales;

        this.payload = payload;
        this.token = utils.sign(this.payload, this.secret, this.options.signOptions);
        this.valid = true;
        this.expired = false;
        this.stale = false;

        return this;
    }

function ( payload ) { payload . stales = Date . now ( ) + this . options . stales ; this . payload = payload ; this . token = utils . sign ( this . payload , this . secret , this . options . signOptions ) ; this . valid = true ; this . expired = false ; this . stale = false ; return this ; }

sign - generate a new token from the payload
@param object payload The payload to sign
@return this


function(res) {
        if (this.options.cookies) {
            res.cookie(this.options.cookie, this.token, this.options.cookieOptions);
        }

        return this;
    }

function ( res ) { if ( this . options . cookies ) { res . cookie ( this . options . cookie , this . token , this . options . cookieOptions ) ; } return this ; }

store - stores the JWT in the cookie
@param object res The Express HTTP Response object
@return this


function() {
        return {
            token: this.token,
            payload: this.payload,
            valid: this.valid,
            expired: this.expired,
            stale: this.stale
        };
    }

function ( ) { return { token : this . token , payload : this . payload , valid : this . valid , expired : this . expired , stale : this . stale } ; }

toJSON - this function is called when the jwt is passed through JSON.stringify
we don't want the secret or options to be stringified
@return object

toJSON - this function is called when the jwt is passed through JSON . stringify we don t want the secret or options to be stringified


function(token) {
        this.token = token || '';

        try {
            this.payload = utils.verify(this.token, this.secret, this.options.verifyOptions);
            this.valid = true;
        } catch (err) {
            this.payload = utils.decode(this.token) || {};
            if (err.name == 'TokenExpiredError') {
                this.expired = true;
            }
        }

        if (this.valid && !this.options.verify(this)) {
            this.valid = false;
        }

        if (this.payload.stales && Date.now() <= this.payload.stales) {
            this.stale = false;
        }

        return this;
    }

function ( token ) { this . token = token || '' ; try { this . payload = utils . verify ( this . token , this . secret , this . options . verifyOptions ) ; this . valid = true ; } catch ( err ) { this . payload = utils . decode ( this . token ) || { } ; if ( err . name == 'TokenExpiredError' ) { this . expired = true ; } } if ( this . valid && ! this . options . verify ( this ) ) { this . valid = false ; } if ( this . payload . stales && Date . now ( ) <= this . payload . stales ) { this . stale = false ; } return this ; }

verify - verifies the JWT's token
@param string token The token to verify
@return this


function(secret, options) {
        if (!secret) {
            throw new ReferenceError('secret must be defined');
        }

        if (typeof secret == 'string') {
            var _secret = secret;
            secret = function(req) {return _secret};
        }

        options = options || {};
        var defaults = {
            cookie: 'jwt-express',
            cookieOptions: {
                httpOnly: true
            },
            cookies: true,
            refresh: true,
            reqProperty: 'jwt',
            revoke: function(jwt) {},
            signOptions: {},
            stales: 900000,
            verify: function(jwt) {return true},
            verifyOptions: {}
        };

        for (var key in defaults) {
            this.options[key] = options[key] !== undefined? options[key]: defaults[key];
        }

        return function(req, res, next) {
            var token;
            if (this.options.cookies) {
                token = req.cookies[this.options.cookie];
            } else if (req.headers.authorization) {
                // Authorization: Bearer abc.abc.abc
                token = req.headers.authorization.split(' ')[1];
            }

            var jwt = new JWT(secret(req), this.options);
            req[this.options.reqProperty] = jwt.verify(token);

            if (jwt.valid && !jwt.stale && jwt.options.refresh) {
                jwt.resign().store(res);
            }

            /**
             * jwt - Creates and signs a new JWT. If cookies are in use, it stores
             *     the JWT in the cookie as well.
             * @param object payload The payload of the JWT
             * @return JWT
             */
            res.jwt = function(payload) {
                var jwt = new JWT(secret(req), this.options);
                return jwt.sign(payload).store(res);
            }.bind(this);

            this.clear = function() {
                if (this.options.cookies) {
                    res.clearCookie(this.options.cookie);
                }
            }.bind(this);

            next();
        }.bind(this);
    }

function
(
secret
,
options
)
{
if
(
!
secret
)
{
throw
new
ReferenceError
(
'secret must be defined'
)
;
}
if
(
typeof
secret
==
'string'
)
{
var
_secret
=
secret
;
secret
=
function
(
req
)
{
return
_secret
}
;
}
options
=
options
||
{
}
;
var
defaults
=
{
cookie
:
'jwt-express'
,
cookieOptions
:
{
httpOnly
:
true
}
,
cookies
:
true
,
refresh
:
true
,
reqProperty
:
'jwt'
,
revoke
:
function
(
jwt
)
{
}
,
signOptions
:
{
}
,
stales
:
900000
,
verify
:
function
(
jwt
)
{
return
true
}
,
verifyOptions
:
{
}
}
;
for
(
var
key
in
defaults
)
{
this
.
options
[
key
]
=
options
[
key
]
!==
undefined
options
[
key
]
:
defaults
[
key
]
;
}
return
function
(
req
,
res
,
next
)
{
var
token
;
if
(
this
.
options
.
cookies
)
{
token
=
req
.
cookies
[
this
.
options
.
cookie
]
;
}
else
if
(
req
.
headers
.
authorization
)
{
token
=
req
.
headers
.
authorization
.
split
(
' '
)
[
1
]
;
}
var
jwt
=
new
JWT
(
secret
(
req
)
,
this
.
options
)
;
req
[
this
.
options
.
reqProperty
]
=
jwt
.
verify
(
token
)
;
if
(
jwt
.
valid
&&
!
jwt
.
stale
&&
jwt
.
options
.
refresh
)
{
jwt
.
resign
(
)
.
store
(
res
)
;
}
res
.
jwt
=
function
(
payload
)
{
var
jwt
=
new
JWT
(
secret
(
req
)
,
this
.
options
)
;
return
jwt
.
sign
(
payload
)
.
store
(
res
)
;
}
.
bind
(
this
)
;
this
.
clear
=
function
(
)
{
if
(
this
.
options
.
cookies
)
{
res
.
clearCookie
(
this
.
options
.
cookie
)
;
}
}
.
bind
(
this
)
;
next
(
)
;
}
.
bind
(
this
)
;
}

init - initialize jwt-express
@param string|function secret If secret is a string, that will be used
to verify / sign with. If secret is a function, that function will be
called with the Express HTTP Request as it's first parameter, and must
return a string which will be used to verify / sign with.
@param object options (Optional) The options of jwt-express
cookie:        The name of the cookie (default: 'jwt-express')
cookieOptions: Options to use when storing the cookie
(default: {httpOnly: true})
cookies:       Boolean indicating to use cookies to look for / save the JWTs
or to use the Authorization header to look for the JWTs (default: true)
refresh:       Boolean indicating if the JWT should be refreshed and stored every request
reqProperty:   The property of req to populate (default: 'jwt')
revoke:        The function to call when jwt.revoke() is called
(default: function(jwt) {})
signOptions:   Options to use when signing the JWT (default: {})
stales:        Milliseconds when the jwt will go stale
verify:        Additional function to call when verifying a JWT
(default: function(jwt) {return true})
verifyOptions: Options to use when verifying the JWT (default: {})
@return function middleware


function() {
        return function(req, res, next) {
            var jwt = req[this.options.reqProperty] || {};

            if (!jwt.valid) {
                next(new JWTExpressError('JWT is invalid'));
            } else {
                next();
            }
        }.bind(this);
    }

function
(
)
{
return
function
(
req
,
res
,
next
)
{
var
jwt
=
req
[
this
.
options
.
reqProperty
]
||
{
}
;
if
(
!
jwt
.
valid
)
{
next
(
new
JWTExpressError
(
'JWT is invalid'
)
)
;
}
else
{
next
(
)
;
}
}
.
bind
(
this
)
;
}

valid - requires that a JWT is valid
@return function middleware


function setupComponent (fixture, options) {
    // tear down any existing component instance
    if (this.component) {
      this.component.teardown();
      this.$node.remove();
    }

    if (fixture instanceof jQuery || typeof fixture === 'string') {
      // use the fixture to create component root node
      this.$node = $(fixture).addClass('component-root');
    } else {
      // create an empty component root node
      this.$node = $('<div class="component-root" />');
      options = fixture;
      fixture = null;
    }

    // append component root node to body
    $('body').append(this.$node);

    // normalize options
    options = options === undefined ? {} : options;

    // instantiate component on component root node
    this.component = (new this.Component()).initialize(this.$node, options);
  }

function
setupComponent
(
fixture
,
options
)
{
if
(
this
.
component
)
{
this
.
component
.
teardown
(
)
;
this
.
$node
.
remove
(
)
;
}
if
(
fixture
instanceof
jQuery
||
typeof
fixture
===
'string'
)
{
this
.
$node
=
$
(
fixture
)
.
addClass
(
'component-root'
)
;
}
else
{
this
.
$node
=
$
(
'<div class="component-root" />'
)
;
options
=
fixture
;
fixture
=
;
}
$
(
'body'
)
.
append
(
this
.
$node
)
;
options
=
options
===
undefined
{
}
:
options
;
this
.
component
=
(
new
this
.
Component
(
)
)
.
initialize
(
this
.
$node
,
options
)
;
}

setupComponent
- Assumes it has been called in the context of a jasmine spec.
- Creates a new HTML element and attaches to it an instance of this.Component
- If a fixture is provided, the fixture will serve as the component root.

@param fixture: HTML or jQuery fixture
@param options: component initialization options

setupComponent - Assumes it has been called in the context of a jasmine spec . - Creates a new HTML element and attaches to it an instance of this . Component - If a fixture is provided the fixture will serve as the component root .


function describeModuleFactory (modulePath, specDefinitions) {
    return function () {
      beforeEach(function (done) {
        this.module = null;

        var requireCallback = function (module) {
          this.module = module;
          done();
        }.bind(this);

        require([modulePath], requireCallback);
      });

      specDefinitions.apply(this);
    };
  }

function describeModuleFactory ( modulePath , specDefinitions ) { return function ( ) { beforeEach ( function ( done ) { this . module = null ; var requireCallback = function ( module ) { this . module = module ; done ( ) ; } . bind ( this ) ; require ( [ modulePath ] , requireCallback ) ; } ) ; specDefinitions . apply ( this ) ; } ; }

Load amd module before executing specDefinitions


function consul (options, resilient) {
      defineResilientOptions(params, options)

      return {
        // Incoming traffic middleware
        'in': function inHandler (err, res, next) {
          if (err) return next()

          // resilient.js sometimes calls the middleware function more than once, with the output
          // of the previous invokation; checking here the type of the items in the response to
          // only call `mapServers` with service objects, not URLs (strings)
          if (Array.isArray(res.data) && Object(res.data[0]) === res.data[0]) {
            res.data = mapServers(res.data)
          }

          next()
        },
        // Outgoing traffic middleware
        'out': function outHandler (options, next) {
          options.params = options.params || {}

          if (params.datacenter) {
            options.params.dc = params.datacenter
          }

          if (params.onlyHealthy) {
            options.params.passing = true
          }

          if (params.tag) {
            options.params.tag = params.tag
          }

          next()
        }
      }
    }

function consul ( options , resilient ) { defineResilientOptions ( params , options ) return { 'in' : function inHandler ( err , res , next ) { if ( err ) return next ( ) if ( Array . isArray ( res . data ) && Object ( res . data [ 0 ] ) === res . data [ 0 ] ) { res . data = mapServers ( res . data ) } next ( ) } , 'out' : function outHandler ( options , next ) { options . params = options . params || { } if ( params . datacenter ) { options . params . dc = params . datacenter } if ( params . onlyHealthy ) { options . params . passing = true } if ( params . tag ) { options . params . tag = params . tag } next ( ) } } }


function inHandler (err, res, next) {
          if (err) return next()

          // resilient.js sometimes calls the middleware function more than once, with the output
          // of the previous invokation; checking here the type of the items in the response to
          // only call `mapServers` with service objects, not URLs (strings)
          if (Array.isArray(res.data) && Object(res.data[0]) === res.data[0]) {
            res.data = mapServers(res.data)
          }

          next()
        }

function inHandler ( err , res , next ) { if ( err ) return next ( ) if ( Array . isArray ( res . data ) && Object ( res . data [ 0 ] ) === res . data [ 0 ] ) { res . data = mapServers ( res . data ) } next ( ) }


function outHandler (options, next) {
          options.params = options.params || {}

          if (params.datacenter) {
            options.params.dc = params.datacenter
          }

          if (params.onlyHealthy) {
            options.params.passing = true
          }

          if (params.tag) {
            options.params.tag = params.tag
          }

          next()
        }

function outHandler ( options , next ) { options . params = options . params || { } if ( params . datacenter ) { options . params . dc = params . datacenter } if ( params . onlyHealthy ) { options . params . passing = true } if ( params . tag ) { options . params . tag = params . tag } next ( ) }


function(categoryId, event) {
    event.preventDefault();
    this.refs.scroller.prepareAnimationSync();
    this.setState({
      mode: 'single',
      selected: categoryId,
      previousScrollPosition: this.refs.scroller.scrollTop,
    }, function() {
      this.refs.scroller.animateAndResetScroll(0, 0);
    });
  }

function ( categoryId , event ) { event . preventDefault ( ) ; this . refs . scroller . prepareAnimationSync ( ) ; this . setState ( { mode : 'single' , selected : categoryId , previousScrollPosition : this . refs . scroller . scrollTop , } , function ( ) { this . refs . scroller . animateAndResetScroll ( 0 , 0 ) ; } ) ; }

When listing all categories and user taps on a given category


function(event) {
    event.preventDefault();
    this.setState({
      mode: 'all',
      selected: null,
    }, function() {
      this.refs.scroller.animateAndResetScroll(0, this.state.previousScrollPosition);
    });
  }

function ( event ) { event . preventDefault ( ) ; this . setState ( { mode : 'all' , selected : null , } , function ( ) { this . refs . scroller . animateAndResetScroll ( 0 , this . state . previousScrollPosition ) ; } ) ; }

When showing a single category and user taps the stack


function Service(displayName, UUID, subtype) {

  if (!UUID) throw new Error("Services must be created with a valid UUID.");

  this.displayName = displayName;
  this.UUID = UUID;
  this.subtype = subtype;
  this.iid = null; // assigned later by our containing Accessory
  this.characteristics = [];
  this.optionalCharacteristics = [];

  // every service has an optional Characteristic.Name property - we'll set it to our displayName
  // if one was given
  // if you don't provide a display name, some HomeKit apps may choose to hide the device.
  if (displayName) {
    // create the characteristic if necessary
    var nameCharacteristic =
      this.getCharacteristic(Characteristic.Name) ||
      this.addCharacteristic(Characteristic.Name);

    nameCharacteristic.setValue(displayName);
  }
}

Service represents a set of grouped values necessary to provide a logical function. For instance, a
"Door Lock Mechanism" service might contain two values, one for the "desired lock state" and one for the
"current lock state". A particular Service is distinguished from others by its "type", which is a UUID.
HomeKit provides a set of known Service UUIDs defined in HomeKitTypes.js along with a corresponding
concrete subclass that you can instantiate directly to setup the necessary values. These natively-supported
Services are expected to contain a particular set of Characteristics.

Unlike Characteristics, where you cannot have two Characteristics with the same UUID in the same Service,
you can actually have multiple Services with the same UUID in a single Accessory. For instance, imagine
a Garage Door Opener with both a "security light" and a "backlight" for the display. Each light could be
a "Lightbulb" Service with the same UUID. To account for this situation, we define an extra "subtype"
property on Service, that can be a string or other string-convertible object that uniquely identifies the
Service among its peers in an Accessory. For instance, you might have `service1.subtype = 'security_light'`
for one and `service2.subtype = 'backlight'` for the other.

You can also define custom Services by providing your own UUID for the type that you generate yourself.
Custom Services can contain an arbitrary set of Characteristics, but Siri will likely not be able to
work with these.

@event 'characteristic-change' => function({characteristic, oldValue, newValue, context}) { }
Emitted after a change in the value of one of our Characteristics has occurred.

Service represents a set of grouped values necessary to provide a logical function . For instance a Door Lock Mechanism service might contain two values one for the desired lock state and one for the current lock state . A particular Service is distinguished from others by its type which is a UUID . HomeKit provides a set of known Service UUIDs defined in HomeKitTypes . js along with a corresponding concrete subclass that you can instantiate directly to setup the necessary values . These natively - supported Services are expected to contain a particular set of Characteristics .


function Characteristic(displayName, UUID, props) {
  this.displayName = displayName;
  this.UUID  = UUID;
  this.iid   = null; // assigned by our containing Service
  this.value = null;
  this.props = props || {
    format  : null,
    unit    : null,
    minValue: null,
    maxValue: null,
    minStep : null,
    perms   : []
  };
}

function Characteristic ( displayName , UUID , props ) { this . displayName = displayName ; this . UUID = UUID ; this . iid = null ; this . value = null ; this . props = props || { format : null , unit : null , minValue : null , maxValue : null , minStep : null , perms : [ ] } ; }

Characteristic represents a particular typed variable that can be assigned to a Service. For instance, a
"Hue" Characteristic might store a 'float' value of type 'arcdegrees'. You could add the Hue Characteristic
to a Service in order to store that value. A particular Characteristic is distinguished from others by its
UUID. HomeKit provides a set of known Characteristic UUIDs defined in HomeKitTypes.js along with a
corresponding concrete subclass.

You can also define custom Characteristics by providing your own UUID. Custom Characteristics can be added
to any native or custom Services, but Siri will likely not be able to work with these.

Note that you can get the "value" of a Characteristic by accessing the "value" property directly, but this
is really a "cached value". If you want to fetch the latest value, which may involve doing some work, then
call getValue().

@event 'get' => function(callback(err, newValue), context) { }
Emitted when someone calls getValue() on this Characteristic and desires the latest non-cached
value. If there are any listeners to this event, one of them MUST call the callback in order
for the value to ever be delivered. The `context` object is whatever was passed in by the initiator
of this event (for instance whomever called `getValue`).

@event 'set' => function(newValue, callback(err), context) { }
Emitted when someone calls setValue() on this Characteristic with a desired new value. If there
are any listeners to this event, one of them MUST call the callback in order for this.value to
actually be set. The `context` object is whatever was passed in by the initiator of this change
(for instance, whomever called `setValue`).

@event 'change' => function({ oldValue, newValue, context }) { }
Emitted after a change in our value has occurred. The new value will also be immediately accessible
in this.value. The event object contains the new value as well as the context object originally
passed in by the initiator of this change (if known).

Characteristic represents a particular typed variable that can be assigned to a Service . For instance a Hue Characteristic might store a float value of type arcdegrees . You could add the Hue Characteristic to a Service in order to store that value . A particular Characteristic is distinguished from others by its UUID . HomeKit provides a set of known Characteristic UUIDs defined in HomeKitTypes . js along with a corresponding concrete subclass .


function migrateDatabase(nativeDatabase, nativeTransaction, schemaDescriptors,
    currentVersion) {
  let descriptorsToProcess = schemaDescriptors.filter((descriptor) => {
    return descriptor.version > currentVersion
  })

  if (!descriptorsToProcess.length) {
    return PromiseSync.resolve(undefined)
  }

  return migrateDatabaseVersion(
    nativeDatabase,
    nativeTransaction,
    descriptorsToProcess[0]
  ).then(() => {
    return migrateDatabase(
      nativeDatabase,
      nativeTransaction,
      descriptorsToProcess,
      descriptorsToProcess[0].version
    )
  })
}

function migrateDatabase ( nativeDatabase , nativeTransaction , schemaDescriptors , currentVersion ) { let descriptorsToProcess = schemaDescriptors . filter ( ( descriptor ) => { return descriptor . version > currentVersion } ) if ( ! descriptorsToProcess . length ) { return PromiseSync . resolve ( undefined ) } return migrateDatabaseVersion ( nativeDatabase , nativeTransaction , descriptorsToProcess [ 0 ] ) . then ( ( ) => { return migrateDatabase ( nativeDatabase , nativeTransaction , descriptorsToProcess , descriptorsToProcess [ 0 ] . version ) } ) }

Processes the schema descriptors to upgrade the database schema to the
greatest version specified.

@param {IDBDatabase} nativeDatabase The native Indexed DB database being
migrated to a higher version.
@param {IDBTransaction} nativeTransaction The native Indexed DB
{@code versionchange} transaction to use to manipulate the data.
@param {(DatabaseSchema|UpgradedDatabaseSchema)[]} schemaDescriptors Schema
descriptors of the database schemas for various versions, sorted in
ascending order by the version number.
@param {number} currentVersion The current version of the database schema.
@return {PromiseSync<undefined>} A promise that resolves when the schema is
upgraded to the greatest version specified in the schema
descriptors.

Processes the schema descriptors to upgrade the database schema to the greatest version specified .


function migrateDatabaseVersion(nativeDatabase, nativeTransaction,
    descriptor) {
  let fetchPromise
  if (descriptor.fetchBefore && descriptor.fetchBefore.length) {
    let fetcher = new RecordFetcher()
    let objectStores = normalizeFetchBeforeObjectStores(descriptor.fetchBefore)
    fetchPromise = fetcher.fetchRecords(nativeTransaction, objectStores)
  } else {
    fetchPromise = PromiseSync.resolve({})
  }

  return fetchPromise.then((recordsMap) => {
    let versionMigrator = new DatabaseVersionMigrator(
      nativeDatabase,
      nativeTransaction,
      descriptor.objectStores
    )

    return versionMigrator.executeMigration(
      descriptor.after || (() => {}),
      recordsMap
    )
  })
}

function migrateDatabaseVersion ( nativeDatabase , nativeTransaction , descriptor ) { let fetchPromise if ( descriptor . fetchBefore && descriptor . fetchBefore . length ) { let fetcher = new RecordFetcher ( ) let objectStores = normalizeFetchBeforeObjectStores ( descriptor . fetchBefore ) fetchPromise = fetcher . fetchRecords ( nativeTransaction , objectStores ) } else { fetchPromise = PromiseSync . resolve ( { } ) } return fetchPromise . then ( ( recordsMap ) => { let versionMigrator = new DatabaseVersionMigrator ( nativeDatabase , nativeTransaction , descriptor . objectStores ) return versionMigrator . executeMigration ( descriptor . after || ( ( ) => { } ) , recordsMap ) } ) }

Performs a single-version database migration to the schema described by the
provided database schema descriptor.

@param {IDBDatabase} nativeDatabase The native Indexed DB database being
migrated to a higher version.
@param {IDBTransaction} nativeTransaction The native Indexed DB
{@code versionchange} transaction to use to manipulate the data.
@param {(DatabaseSchema|UpgradedDatabaseSchema)} descriptor Schema
descriptor of the version to which the database is to be upgraded.
@return {PromiseSync<undefined>} A promise that resolves once the database
has been upgraded to the schema described by the provided schema
descriptor.

Performs a single - version database migration to the schema described by the provided database schema descriptor .


function normalizeFetchBeforeObjectStores(objectStores) {
  return objectStores.map((objectStore) => {
    if (typeof objectStore === "string") {
      return {
        objectStore,
        preprocessor: record => record
      }
    } else if (!objectStore.preprocessor) {
      return {
        objectStore: objectStore.objectStore,
        preprocessor: record => record
      }
    } else {
      return objectStore
    }
  })
}

function normalizeFetchBeforeObjectStores ( objectStores ) { return objectStores . map ( ( objectStore ) => { if ( typeof objectStore === "string" ) { return { objectStore , preprocessor : record => record } } else if ( ! objectStore . preprocessor ) { return { objectStore : objectStore . objectStore , preprocessor : record => record } } else { return objectStore } } ) }

Normalizes the provided array of object store fetch descriptors to process
before upgrading the database schema.

@param {(string|{objectStore: string, preprocessor: function(*, (number|string|Date|Array)): (*|UpgradedDatabaseSchema.SKIP_RECORD|UpgradedDatabaseSchema.DELETE_RECORD)=})[]} objectStores
The names of object stores that should have their records fetch or
(possibly partially filled) object store fetch descriptors, mixed in
an array.
@return {{objectStore: string, preprocessor: function(*, (number|string|Date|Array)): (*|UpgradedDatabaseSchema.SKIP_RECORD|UpgradedDatabaseSchema.DELETE_RECORD)}[]}
Normalized object store fetch descriptors.

Normalizes the provided array of object store fetch descriptors to process before upgrading the database schema .


function checkSchemaDescriptorTypes(schemaDescriptors) {
  let onlyPlainObjects = schemaDescriptors.every((descriptor) => {
    return descriptor.constructor === Object
  })
  if (onlyPlainObjects) {
    return
  }

  if (!(schemaDescriptors[0] instanceof DatabaseSchema)) {
    throw new TypeError("The schema descriptor of the lowest described " +
        `database version (${schemaDescriptors[0].version}) must be a ` +
        "DatabaseSchema instance, or all schema descriptors must be plain " +
        "objects")
  }
  schemaDescriptors.slice(1).forEach((descriptor) => {
    if (!(descriptor instanceof UpgradedDatabaseSchema)) {
      throw new TypeError("The schema descriptors of the upgraded database " +
          "versions must be UpgradedDatabaseSchema instances, but the " +
          `provided descriptor of version ${descriptor.version} was not an ` +
          "UpgradedDatabaseSchema instance, or all schema descriptors must " +
          "be plain objects")
    }
  })
}

Validates the types of the provided schema descriptors.

@param {((DatabaseSchema|UpgradedDatabaseSchema)[]|Object[])} schemaDescriptors
The database schemas for database versions to validate, sorted by
version number in the ascending order.
@throws {TypeError} Thrown if the schema descriptors are of invalid type.

Validates the types of the provided schema descriptors .


function list(storage, keyRange, filter, direction, unique, pageSize,
    storageFactory) {
  return new Promise((resolve, reject) => {
    let items = []

    storage.createCursorFactory(keyRange, direction)((cursor) => {
      if (!filter || filter(cursor.record, cursor.primaryKey, cursor.key)) {
        if (items.length === pageSize) {
          finalize(true, cursor.key, cursor.primaryKey)
          return
        } else {
          items.push(cursor.record)
        }
      }

      cursor.continue()
    }).then(() => finalize(false, null, null)).catch(error => reject(error))

    function finalize(hasNextPage, nextKey, nextPrimaryKey) {
      resolve(new RecordList(items, storageFactory, nextKey, nextPrimaryKey,
          direction, unique, filter, pageSize, hasNextPage))
    }
  })
}

function list ( storage , keyRange , filter , direction , unique , pageSize , storageFactory ) { return new Promise ( ( resolve , reject ) => { let items = [ ] storage . createCursorFactory ( keyRange , direction ) ( ( cursor ) => { if ( ! filter || filter ( cursor . record , cursor . primaryKey , cursor . key ) ) { if ( items . length === pageSize ) { finalize ( true , cursor . key , cursor . primaryKey ) return } else { items . push ( cursor . record ) } } cursor . continue ( ) } ) . then ( ( ) => finalize ( false , null , null ) ) . catch ( error => reject ( error ) ) function finalize ( hasNextPage , nextKey , nextPrimaryKey ) { resolve ( new RecordList ( items , storageFactory , nextKey , nextPrimaryKey , direction , unique , filter , pageSize , hasNextPage ) ) } } ) }

Creates a promise that resolves to a record list containing the first page
of records matching the provided filter.

@param {AbstractReadOnlyStorage} storage The current storage accessor - will
be used to fetch the first page of records.
@param {(undefined|IDBKeyRange)} keyRange The key range to use for the first
page or records.
@param {(undefined|function(*, (number|string|Date|Array), (number|string|Date|Array)): boolean)} filter
The filter function restricting the records that will be listed.
If a function is provided, the first argument will be set to the
record, the second argument will be set to the primary key of the
record, and the third argument will be set to the key referencing the
record (the primary key if traversing an object store).
@param {CursorDirection} direction The direction in which the records in the
storage should be listed.
@param {boolean} unique When {@code true}, the keys by which the records are
organized in the store are always unique for each record.
@param {number} pageSize The maximum number of records per page. Must be a
positive integer.
@param {function(): AbstractReadOnlyStorage} storageFactory A function that
creates a new read-only transaction and returns this storage accessor
each time it is invoked.
@return {Promise<RecordList<*>>} A promise that resolves to a record list of
the fetched records matching the filter.

Creates a promise that resolves to a record list containing the first page of records matching the provided filter .


function normalizeCompoundObjectKey(keyPaths, key) {
  let normalizedKey = []

  keyPaths.forEach((keyPath) => {
    let keyValue = key

    keyPath.split(".").forEach((fieldName) => {
      if (!keyValue.hasOwnProperty(fieldName)) {
        throw new Error(`The ${keyPath} key path is not defined in the ` +
            "provided compound key")
      }

      keyValue = keyValue[fieldName]
    })

    normalizedKey.push(keyValue)
  })

  return normalizedKey
}

function
normalizeCompoundObjectKey
(
keyPaths
,
key
)
{
let
normalizedKey
=
[
]
keyPaths
.
forEach
(
(
keyPath
)
=>
{
let
keyValue
=
key
keyPath
.
split
(
"."
)
.
forEach
(
(
fieldName
)
=>
{
if
(
!
keyValue
.
hasOwnProperty
(
fieldName
)
)
{
throw
new
Error
(
`
${
keyPath
}
`
+
"provided compound key"
)
}
keyValue
=
keyValue
[
fieldName
]
}
)
normalizedKey
.
push
(
keyValue
)
}
)
return
normalizedKey
}

Normalizes the provided compound key represented as an object into a
compound key representation compatible with the Indexed DB.

@param {string[]} keyPaths The key paths of this storage.
@param {Object} key The compound key to normalize for use with the Indexed
DB.
@return {Array<(number|string|Date|Array)>} Normalized compound key.

Normalizes the provided compound key represented as an object into a compound key representation compatible with the Indexed DB .


function iterateCursor(request, cursorConstructor, recordCallback) {
  return new PromiseSync((resolve, reject) => {
    let traversedRecords = 0
    let canIterate = true

    request.onerror = () => reject(request.error)
    request.onsuccess = () => {
      if (!canIterate) {
        console.warn("Cursor iteration was requested asynchronously, " +
            "ignoring the new cursor position")
        return
      }

      if (!request.result) {
        resolve(traversedRecords)
        return
      }

      traversedRecords++

      let iterationRequested = handleCursorIteration(
        request,
        cursorConstructor,
        recordCallback,
        reject
      )

      if (!iterationRequested) {
        canIterate = false
        resolve(traversedRecords)
      }
    }
  })
}

Iterates the cursor to which the provided Indexed DB request resolves. The
method will iterate the cursor over the records in this storage within the
range specified when the cursor was opened until the provided callback does
not request iterating to the next record or the last matching record is
reached.

@param {IDBRequest} request Indexed DB request that resolves to a cursor
every time the cursor iterates to a record.
@param {function(new: ReadOnlyCursor, IDBRequest, function(), function(IDBRequest): PromiseSync)} cursorConstructor
Constructor of the cursor class to use to wrap the native IDBRequest
producing the native IndexedDB cursor.
@param {function(ReadOnlyCursor)} recordCallback The callback to execute,
passing a high-level cursor instance pointing to the current record
in each iteration of the cursor.
@return {PromiseSync<number>} A promise that resolves to the number of
records the cursor traversed.

Iterates the cursor to which the provided Indexed DB request resolves . The method will iterate the cursor over the records in this storage within the range specified when the cursor was opened until the provided callback does not request iterating to the next record or the last matching record is reached .


function handleCursorIteration(request, cursorConstructor, recordCallback,
    reject) {
  let iterationRequested = false
  let cursor = new cursorConstructor(request, () => {
    iterationRequested = true
  }, (subRequest) => {
    return PromiseSync.resolve(subRequest).catch((error) => {
      reject(error)
      throw error
    })
  })

  try {
    recordCallback(cursor)
  } catch (error) {
    iterationRequested = false
    reject(error)
  }

  return iterationRequested
}

function handleCursorIteration ( request , cursorConstructor , recordCallback , reject ) { let iterationRequested = false let cursor = new cursorConstructor ( request , ( ) => { iterationRequested = true } , ( subRequest ) => { return PromiseSync . resolve ( subRequest ) . catch ( ( error ) => { reject ( error ) throw error } ) } ) try { recordCallback ( cursor ) } catch ( error ) { iterationRequested = false reject ( error ) } return iterationRequested }

Handles a single iteration of a Indexed DB cursor iterating the records in
the storage.

@param {IDBRequest} request Indexed DB request resolved to a cursor.
@param {function(new: ReadOnlyCursor, IDBRequest, function(), function(IDBRequest): PromiseSync)} cursorConstructor
Constructor of the high-level cursor implementation to use.
@param {function(ReadOnlyCursor)} recordCallback The callback to execute,
passing a high-level cursor instance pointing to the current record.
@param {function(Error)} reject Callback to call if any sub-operation
triggered by the callback results in an error.
@return {boolean} {@code true} if the cursor should iterate to the next
record.

Handles a single iteration of a Indexed DB cursor iterating the records in the storage .


function fetchAllRecords(transaction, objectStores) {
  return PromiseSync.all(objectStores.map((descriptor) => {
    return fetchRecords(
      transaction.getObjectStore(descriptor.objectStore),
      descriptor.preprocessor
    )
  })).then((fetchedRecords) => {
    let recordsMap = {}

    for (let i = 0; i < objectStores.length; i++) {
      recordsMap[objectStores[i].objectStore] = fetchedRecords[i]
    }

    return recordsMap
  })
}

function fetchAllRecords ( transaction , objectStores ) { return PromiseSync . all ( objectStores . map ( ( descriptor ) => { return fetchRecords ( transaction . getObjectStore ( descriptor . objectStore ) , descriptor . preprocessor ) } ) ) . then ( ( fetchedRecords ) => { let recordsMap = { } for ( let i = 0 ; i < objectStores . length ; i ++ ) { recordsMap [ objectStores [ i ] . objectStore ] = fetchedRecords [ i ] } return recordsMap } ) }

Fetches all records from the specified object stores using the provided
read-write transaction.

@param {Transaction} transaction The read-write transaction to use to access
the object stores.
@param {(string|{objectStore: string, preprocessor: function(*, (number|string|Date|Array)): (*|UpgradedDatabaseSchema.SKIP_RECORD|UpgradedDatabaseSchema.DELETE_RECORD)=})[]} objectStores
The names of object stores that should have their records fetch or
(possibly partially filled) object store fetch descriptors, mixed in
an array.
@return {PromiseSync<Object<string, {key: (number|string|Date|Array), record: *}[]>>}
A promise that resolves once all the records have been fetched and
the records marked for deletion were deleted.
The promise resolves to a map of object store names to the records
fetched from the object store, except for the records marked for
skipping or deletion.

Fetches all records from the specified object stores using the provided read - write transaction .