function(args) {
    var opts = {
      auth: null,
      headers: {},
    };
    if (args.length > 0) {
      var arg = args[args.length - 1];
      if (utils.isAuthKey(arg)) {
        opts.auth = args.pop();
      } else if (utils.isOptionsHash(arg)) {
        var params = args.pop();

        var extraKeys = Object.keys(params).filter(function(key) {
          return OPTIONS_KEYS.indexOf(key) == -1;
        });

        if (extraKeys.length) {
          emitWarning('Invalid options found (' + extraKeys.join(', ') + '); ignoring.');
        }

        if (params.api_key) {
          opts.auth = params.api_key;
        }
        if (params.idempotency_key) {
          opts.headers['Idempotency-Key'] = params.idempotency_key;
        }
        if (params.stripe_account) {
          opts.headers['Stripe-Account'] = params.stripe_account;
        }
        if (params.stripe_version) {
          opts.headers['Stripe-Version'] = params.stripe_version;
        }
      }
    }
    return opts;
  }

function
(
args
)
{
var
opts
=
{
auth
:
,
headers
:
{
}
,
}
;
if
(
args
.
length
>
0
)
{
var
arg
=
args
[
args
.
length
1
]
;
if
(
utils
.
isAuthKey
(
arg
)
)
{
opts
.
auth
=
args
.
pop
(
)
;
}
else
if
(
utils
.
isOptionsHash
(
arg
)
)
{
var
params
=
args
.
pop
(
)
;
var
extraKeys
=
Object
.
keys
(
params
)
.
filter
(
function
(
key
)
{
return
OPTIONS_KEYS
.
indexOf
(
key
)
==
1
;
}
)
;
if
(
extraKeys
.
length
)
{
emitWarning
(
'Invalid options found ('
+
extraKeys
.
join
(
', '
)
+
'); ignoring.'
)
;
}
if
(
params
.
api_key
)
{
opts
.
auth
=
params
.
api_key
;
}
if
(
params
.
idempotency_key
)
{
opts
.
headers
[
'Idempotency-Key'
]
=
params
.
idempotency_key
;
}
if
(
params
.
stripe_account
)
{
opts
.
headers
[
'Stripe-Account'
]
=
params
.
stripe_account
;
}
if
(
params
.
stripe_version
)
{
opts
.
headers
[
'Stripe-Version'
]
=
params
.
stripe_version
;
}
}
}
return
opts
;
}

Return the options hash from a list of arguments


function(sub) {
    var Super = this;
    var Constructor = hasOwn.call(sub, 'constructor') ? sub.constructor : function() {
      Super.apply(this, arguments);
    };

    // This initialization logic is somewhat sensitive to be compatible with
    // divergent JS implementations like the one found in Qt. See here for more
    // context:
    //
    // https://github.com/stripe/stripe-node/pull/334
    Object.assign(Constructor, Super);
    Constructor.prototype = Object.create(Super.prototype);
    Object.assign(Constructor.prototype, sub);

    return Constructor;
  }

Provide simple "Class" extension mechanism

Provide simple Class extension mechanism


function(obj) {
    if (typeof obj !== 'object') {
      throw new Error('Argument must be an object');
    }

    Object.keys(obj).forEach(function(key) {
      if (obj[key] === null || obj[key] === undefined) {
        delete obj[key];
      }
    });

    return obj;
  }

function
(
obj
)
{
if
(
typeof
obj
!==
'object'
)
{
throw
new
Error
(
'Argument must be an object'
)
;
}
Object
.
keys
(
obj
)
.
forEach
(
function
(
key
)
{
if
(
obj
[
key
]
===
||
obj
[
key
]
===
undefined
)
{
delete
obj
[
key
]
;
}
}
)
;
return
obj
;
}


function safeExec(cmd, cb) {
    try {
      utils._exec(cmd, cb);
    } catch (e) {
      cb(e, null);
    }
  }

function safeExec ( cmd , cb ) { try { utils . _exec ( cmd , cb ) ; } catch ( e ) { cb ( e , null ) ; } }

Node's built in `exec` function sometimes throws outright,
and sometimes has a callback with an error,
depending on the type of error.

This unifies that interface.

Node s built in exec function sometimes throws outright and sometimes has a callback with an error depending on the type of error .


function(opts) {
    if (!opts) {
      throw new Error.StripeError({
        message: 'Options are required',
      });
    }

    opts.timestamp = Math.floor(opts.timestamp) || Math.floor(Date.now() / 1000);
    opts.scheme = opts.scheme || signature.EXPECTED_SCHEME;

    opts.signature = opts.signature ||
      signature._computeSignature(opts.timestamp + '.' + opts.payload, opts.secret);

    var generatedHeader = [
      't=' + opts.timestamp,
      opts.scheme + '=' + opts.signature,
    ].join(',');

    return generatedHeader;
  }

function
(
opts
)
{
if
(
!
opts
)
{
throw
new
Error
.
StripeError
(
{
message
:
'Options are required'
,
}
)
;
}
opts
.
timestamp
=
Math
.
floor
(
opts
.
timestamp
)
||
Math
.
floor
(
Date
.
now
(
)
/
1000
)
;
opts
.
scheme
=
opts
.
scheme
||
signature
.
EXPECTED_SCHEME
;
opts
.
signature
=
opts
.
signature
||
signature
.
_computeSignature
(
opts
.
timestamp
+
'.'
+
opts
.
payload
,
opts
.
secret
)
;
var
generatedHeader
=
[
't='
+
opts
.
timestamp
,
opts
.
scheme
+
'='
+
opts
.
signature
,
]
.
join
(
','
)
;
return
generatedHeader
;
}

Generates a header to be used for webhook mocking

@typedef {object} opts
@property {number} timestamp - Timestamp of the header. Defaults to Date.now()
@property {string} payload - JSON stringified payload object, containing the 'id' and 'object' parameters
@property {string} secret - Stripe webhook secret 'whsec_...'
@property {string} scheme - Version of API to hit. Defaults to 'v1'.
@property {string} signature - Computed webhook signature


function StripeResource(stripe, urlData) {
  this._stripe = stripe;
  this._urlData = urlData || {};

  this.basePath = utils.makeURLInterpolator(this.basePath || stripe.getApiField('basePath'));
  this.resourcePath = this.path;
  this.path = utils.makeURLInterpolator(this.path);

  if (this.includeBasic) {
    this.includeBasic.forEach(function(methodName) {
      this[methodName] = StripeResource.BASIC_METHODS[methodName];
    }, this);
  }

  this.initialize.apply(this, arguments);
}

function StripeResource ( stripe , urlData ) { this . _stripe = stripe ; this . _urlData = urlData || { } ; this . basePath = utils . makeURLInterpolator ( this . basePath || stripe . getApiField ( 'basePath' ) ) ; this . resourcePath = this . path ; this . path = utils . makeURLInterpolator ( this . path ) ; if ( this . includeBasic ) { this . includeBasic . forEach ( function ( methodName ) { this [ methodName ] = StripeResource . BASIC_METHODS [ methodName ] ; } , this ) ; } this . initialize . apply ( this , arguments ) ; }

Encapsulates request logic for a Stripe Resource


function stripeMethod(spec) {
  return function() {
    var self = this;
    var args = [].slice.call(arguments);

    var callback = typeof args[args.length - 1] == 'function' && args.pop();

    var requestPromise = utils.callbackifyPromiseWithTimeout(makeRequest(self, args, spec, {}), callback)

    if (spec.methodType === 'list') {
      var autoPaginationMethods = makeAutoPaginationMethods(self, args, spec, requestPromise);
      Object.assign(requestPromise, autoPaginationMethods);
    }

    return requestPromise;
  };
}

function stripeMethod ( spec ) { return function ( ) { var self = this ; var args = [ ] . slice . call ( arguments ) ; var callback = typeof args [ args . length - 1 ] == 'function' && args . pop ( ) ; var requestPromise = utils . callbackifyPromiseWithTimeout ( makeRequest ( self , args , spec , { } ) , callback ) if ( spec . methodType === 'list' ) { var autoPaginationMethods = makeAutoPaginationMethods ( self , args , spec , requestPromise ) ; Object . assign ( requestPromise , autoPaginationMethods ) ; } return requestPromise ; } ; }

Create an API method from the declared spec.

@param [spec.method='GET'] Request Method (POST, GET, DELETE, PUT)
@param [spec.path=''] Path to be appended to the API BASE_PATH, joined with
the instance's path (e.g. 'charges' or 'customers')
@param [spec.urlParams=[]] Array of required arguments in the order that they
must be passed by the consumer of the API. Subsequent optional arguments are
optionally passed through a hash (Object) as the penultimate argument
(preceding the also-optional callback argument
@param [spec.encode] Function for mutating input parameters to a method.
Usefully for applying transforms to data on a per-method basis.
@param [spec.host] Hostname for the request.

Create an API method from the declared spec .


function(cb) {
    if (Stripe.USER_AGENT_SERIALIZED) {
      return cb(Stripe.USER_AGENT_SERIALIZED);
    }
    this.getClientUserAgentSeeded(Stripe.USER_AGENT, function(cua) {
      Stripe.USER_AGENT_SERIALIZED = cua;
      cb(Stripe.USER_AGENT_SERIALIZED);
    })
  }

function ( cb ) { if ( Stripe . USER_AGENT_SERIALIZED ) { return cb ( Stripe . USER_AGENT_SERIALIZED ) ; } this . getClientUserAgentSeeded ( Stripe . USER_AGENT , function ( cua ) { Stripe . USER_AGENT_SERIALIZED = cua ; cb ( Stripe . USER_AGENT_SERIALIZED ) ; } ) }

Gets a JSON version of a User-Agent and uses a cached version for a slight speed advantage.

Gets a JSON version of a User - Agent and uses a cached version for a slight speed advantage .


function(seed, cb) {
    var self = this;

    utils.safeExec('uname -a', function(err, uname) {
      var userAgent = {};
      for (var field in seed) {
        userAgent[field] = encodeURIComponent(seed[field]);
      }

      // URI-encode in case there are unusual characters in the system's uname.
      userAgent.uname = encodeURIComponent(uname || 'UNKNOWN');

      if (self._appInfo) {
        userAgent.application = self._appInfo;
      }

      cb(JSON.stringify(userAgent))
    });
  }

Gets a JSON version of a User-Agent by encoding a seeded object and fetching a uname from the system.

Gets a JSON version of a User - Agent by encoding a seeded object and fetching a uname from the system .


function createSharingUrl (network) {
      return this.baseNetworks[network].sharer
        .replace(/@url/g, encodeURIComponent(this.url))
        .replace(/@title/g, encodeURIComponent(this.title))
        .replace(/@description/g, encodeURIComponent(this.description))
        .replace(/@quote/g, encodeURIComponent(this.quote))
        .replace(/@hashtags/g, this.generateHashtags(network, this.hashtags))
        .replace(/@media/g, this.media)
        .replace(/@twitteruser/g, this.twitterUser ? '&via=' + this.twitterUser : '');
    }

function createSharingUrl ( network ) { return this . baseNetworks [ network ] . sharer . replace ( / @url / g , encodeURIComponent ( this . url ) ) . replace ( / @title / g , encodeURIComponent ( this . title ) ) . replace ( / @description / g , encodeURIComponent ( this . description ) ) . replace ( / @quote / g , encodeURIComponent ( this . quote ) ) . replace ( / @hashtags / g , this . generateHashtags ( network , this . hashtags ) ) . replace ( / @media / g , this . media ) . replace ( / @twitteruser / g , this . twitterUser ? '&via=' + this . twitterUser : '' ) ; }

Returns generated sharer url.

@param network Social network key.


function share (network) {
      this.openSharer(network, this.createSharingUrl(network));

      this.$root.$emit('social_shares_open', network, this.url);
      this.$emit('open', network, this.url);
    }

function share ( network ) { this . openSharer ( network , this . createSharingUrl ( network ) ) ; this . $root . $emit ( 'social_shares_open' , network , this . url ) ; this . $emit ( 'open' , network , this . url ) ; }

Shares URL in specified network.

@param network Social network key.


function touch (network) {
      window.open(this.createSharingUrl(network), '_self');

      this.$root.$emit('social_shares_open', network, this.url);
      this.$emit('open', network, this.url);
    }

function touch ( network ) { window . open ( this . createSharingUrl ( network ) , '_self' ) ; this . $root . $emit ( 'social_shares_open' , network , this . url ) ; this . $emit ( 'open' , network , this . url ) ; }

Touches network and emits click event.

@param network Social network key.


function openSharer (network, url) {
      var this$1 = this;

      // If a popup window already exist it will be replaced, trigger a close event.
      var popupWindow = null;
      if (popupWindow && this.popup.interval) {
        clearInterval(this.popup.interval);

        popupWindow.close();// Force close (for Facebook)

        this.$root.$emit('social_shares_change', network, this.url);
        this.$emit('change', network, this.url);
      }

      popupWindow = window.open(
        url,
        'sharer',
        'status=' + (this.popup.status ? 'yes' : 'no') +
        ',height=' + this.popup.height +
        ',width=' + this.popup.width +
        ',resizable=' + (this.popup.resizable ? 'yes' : 'no') +
        ',left=' + this.popup.left +
        ',top=' + this.popup.top +
        ',screenX=' + this.popup.left +
        ',screenY=' + this.popup.top +
        ',toolbar=' + (this.popup.toolbar ? 'yes' : 'no') +
        ',menubar=' + (this.popup.menubar ? 'yes' : 'no') +
        ',scrollbars=' + (this.popup.scrollbars ? 'yes' : 'no') +
        ',location=' + (this.popup.location ? 'yes' : 'no') +
        ',directories=' + (this.popup.directories ? 'yes' : 'no')
      );

      popupWindow.focus();

      // Create an interval to detect popup closing event
      this.popup.interval = setInterval(function () {
        if (popupWindow.closed) {
          clearInterval(this$1.popup.interval);

          popupWindow = undefined;

          this$1.$root.$emit('social_shares_close', network, this$1.url);
          this$1.$emit('close', network, this$1.url);
        }
      }, 500);
    }

Opens sharer popup.

@param network Social network key
@param url Url to share.


function mounted () {
    if (!inBrowser) {
      return;
    }

    /**
     * Center the popup on dual screens
     * http://stackoverflow.com/questions/4068373/center-a-popup-window-on-screen/32261263
     */
    var dualScreenLeft = $window.screenLeft !== undefined ? $window.screenLeft : screen.left;
    var dualScreenTop = $window.screenTop !== undefined ? $window.screenTop : screen.top;

    var width = $window.innerWidth ? $window.innerWidth : (document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width);
    var height = $window.innerHeight ? $window.innerHeight : (document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height);

    this.popup.left = ((width / 2) - (this.popup.width / 2)) + dualScreenLeft;
    this.popup.top = ((height / 2) - (this.popup.height / 2)) + dualScreenTop;
  }


function loadAndParseFile(filename, settings, nextFile) {

        if (settings.debug) {
            debug('loadAndParseFile(\'' + filename +'\')');
            debug('totalFiles: ' + settings.totalFiles);
            debug('filesLoaded: ' + settings.filesLoaded);
        }

  	    if (filename !== null && typeof filename !== 'undefined') {
            $.ajax({
                url: filename,
                async: settings.async,
                cache: settings.cache,
                dataType: 'text',
                success: function (data, status) {

                    if (settings.debug) {
                        debug('Succeeded in downloading ' + filename + '.');
                        debug(data);
                    }

                    parseData(data, settings);
                    nextFile();
                },
                error: function (jqXHR, textStatus, errorThrown) {

                    if (settings.debug) {
                        debug('Failed to download or parse ' + filename + '. errorThrown: ' + errorThrown);
                    }
                    if (jqXHR.status === 404) {
                        settings.totalFiles -= 1;
                    }
                    nextFile();
                }
            });
        }
    }

function
loadAndParseFile
(
filename
,
settings
,
nextFile
)
{
if
(
settings
.
debug
)
{
debug
(
'loadAndParseFile(\''
+
filename
+
'\')'
)
;
debug
(
'totalFiles: '
+
settings
.
totalFiles
)
;
debug
(
'filesLoaded: '
+
settings
.
filesLoaded
)
;
}
if
(
filename
!==
&&
typeof
filename
!==
'undefined'
)
{
$
.
ajax
(
{
url
:
filename
,
async
:
settings
.
async
,
cache
:
settings
.
cache
,
dataType
:
'text'
,
success
:
function
(
data
,
status
)
{
if
(
settings
.
debug
)
{
debug
(
'Succeeded in downloading '
+
filename
+
'.'
)
;
debug
(
data
)
;
}
parseData
(
data
,
settings
)
;
nextFile
(
)
;
}
,
error
:
function
(
jqXHR
,
textStatus
,
errorThrown
)
{
if
(
settings
.
debug
)
{
debug
(
'Failed to download or parse '
+
filename
+
'. errorThrown: '
+
errorThrown
)
;
}
if
(
jqXHR
.
status
===
404
)
{
settings
.
totalFiles
-=
1
;
}
nextFile
(
)
;
}
}
)
;
}
}


function(event, g) {
  var chartPos = utils.findPos(g.canvas_);
  var box = {
    left: chartPos.x,
    right: chartPos.x + g.canvas_.offsetWidth,
    top: chartPos.y,
    bottom: chartPos.y + g.canvas_.offsetHeight
  };

  var pt = {
    x: utils.pageX(event),
    y: utils.pageY(event)
  };

  var dx = distanceFromInterval(pt.x, box.left, box.right),
      dy = distanceFromInterval(pt.y, box.top, box.bottom);
  return Math.max(dx, dy);
}

function ( event , g ) { var chartPos = utils . findPos ( g . canvas_ ) ; var box = { left : chartPos . x , right : chartPos . x + g . canvas_ . offsetWidth , top : chartPos . y , bottom : chartPos . y + g . canvas_ . offsetHeight } ; var pt = { x : utils . pageX ( event ) , y : utils . pageY ( event ) } ; var dx = distanceFromInterval ( pt . x , box . left , box . right ) , dy = distanceFromInterval ( pt . y , box . top , box . bottom ) ; return Math . max ( dx , dy ) ; }

Returns the number of pixels by which the event happens from the nearest
edge of the chart. For events in the interior of the chart, this returns zero.

Returns the number of pixels by which the event happens from the nearest edge of the chart . For events in the interior of the chart this returns zero .


function(event, g, context) {
    // Right-click should not initiate a zoom.
    if (event.button && event.button == 2) return;

    context.initializeMouseDown(event, g, context);

    if (event.altKey || event.shiftKey) {
      DygraphInteraction.startPan(event, g, context);
    } else {
      DygraphInteraction.startZoom(event, g, context);
    }

    // Note: we register mousemove/mouseup on document to allow some leeway for
    // events to move outside of the chart. Interaction model events get
    // registered on the canvas, which is too small to allow this.
    var mousemove = function(event) {
      if (context.isZooming) {
        // When the mouse moves >200px from the chart edge, cancel the zoom.
        var d = distanceFromChart(event, g);
        if (d < DRAG_EDGE_MARGIN) {
          DygraphInteraction.moveZoom(event, g, context);
        } else {
          if (context.dragEndX !== null) {
            context.dragEndX = null;
            context.dragEndY = null;
            g.clearZoomRect_();
          }
        }
      } else if (context.isPanning) {
        DygraphInteraction.movePan(event, g, context);
      }
    };
    var mouseup = function(event) {
      if (context.isZooming) {
        if (context.dragEndX !== null) {
          DygraphInteraction.endZoom(event, g, context);
        } else {
          DygraphInteraction.maybeTreatMouseOpAsClick(event, g, context);
        }
      } else if (context.isPanning) {
        DygraphInteraction.endPan(event, g, context);
      }

      utils.removeEvent(document, 'mousemove', mousemove);
      utils.removeEvent(document, 'mouseup', mouseup);
      context.destroy();
    };

    g.addAndTrackEvent(document, 'mousemove', mousemove);
    g.addAndTrackEvent(document, 'mouseup', mouseup);
  }


function(event, g, context) {
    if (context.cancelNextDblclick) {
      context.cancelNextDblclick = false;
      return;
    }

    // Give plugins a chance to grab this event.
    var e = {
      canvasx: context.dragEndX,
      canvasy: context.dragEndY,
      cancelable: true,
    };
    if (g.cascadeEvents_('dblclick', e)) {
      return;
    }

    if (event.altKey || event.shiftKey) {
      return;
    }
    g.resetZoom();
  }


function getControlPoints(p0, p1, p2, opt_alpha, opt_allowFalseExtrema) {
  var alpha = (opt_alpha !== undefined) ? opt_alpha : 1/3;  // 0=no smoothing, 1=crazy smoothing
  var allowFalseExtrema = opt_allowFalseExtrema || false;

  if (!p2) {
    return [p1.x, p1.y, null, null];
  }

  // Step 1: Position the control points along each line segment.
  var l1x = (1 - alpha) * p1.x + alpha * p0.x,
      l1y = (1 - alpha) * p1.y + alpha * p0.y,
      r1x = (1 - alpha) * p1.x + alpha * p2.x,
      r1y = (1 - alpha) * p1.y + alpha * p2.y;

  // Step 2: shift the points up so that p1 is on the l1–r1 line.
  if (l1x != r1x) {
    // This can be derived w/ some basic algebra.
    var deltaY = p1.y - r1y - (p1.x - r1x) * (l1y - r1y) / (l1x - r1x);
    l1y += deltaY;
    r1y += deltaY;
  }

  // Step 3: correct to avoid false extrema.
  if (!allowFalseExtrema) {
    if (l1y > p0.y && l1y > p1.y) {
      l1y = Math.max(p0.y, p1.y);
      r1y = 2 * p1.y - l1y;
    } else if (l1y < p0.y && l1y < p1.y) {
      l1y = Math.min(p0.y, p1.y);
      r1y = 2 * p1.y - l1y;
    }

    if (r1y > p1.y && r1y > p2.y) {
      r1y = Math.max(p1.y, p2.y);
      l1y = 2 * p1.y - r1y;
    } else if (r1y < p1.y && r1y < p2.y) {
      r1y = Math.min(p1.y, p2.y);
      l1y = 2 * p1.y - r1y;
    }
  }

  return [l1x, l1y, r1x, r1y];
}

Given three sequential points, p0, p1 and p2, find the left and right
control points for p1.

The three points are expected to have x and y properties.

The alpha parameter controls the amount of smoothing.
If α=0, then both control points will be the same as p1 (i.e. no smoothing).

Returns [l1x, l1y, r1x, r1y]

It's guaranteed that the line from (l1x, l1y)-(r1x, r1y) passes through p1.
Unless allowFalseExtrema is set, then it's also guaranteed that:
l1y ∈ [p0.y, p1.y]
r1y ∈ [p1.y, p2.y]

The basic algorithm is:
1. Put the control points l1 and r1 α of the way down (p0, p1) and (p1, p2).
2. Shift l1 and r2 so that the line l1–r1 passes through p1
3. Adjust to prevent false extrema while keeping p1 on the l1–r1 line.

This is loosely based on the HighCharts algorithm.

Given three sequential points p0 p1 and p2 find the left and right control points for p1 .


function(dygraph) {
  this.dygraph_ = dygraph;
  /**
   * Array of points for each series.
   *
   * [series index][row index in series] = |Point| structure,
   * where series index refers to visible series only, and the
   * point index is for the reduced set of points for the current
   * zoom region (including one point just outside the window).
   * All points in the same row index share the same X value.
   *
   * @type {Array.<Array.<Dygraph.PointType>>}
   */
  this.points = [];
  this.setNames = [];
  this.annotations = [];
  this.yAxes_ = null;

  // TODO(danvk): it's odd that xTicks_ and yTicks_ are inputs, but xticks and
  // yticks are outputs. Clean this up.
  this.xTicks_ = null;
  this.yTicks_ = null;
}

Creates a new DygraphLayout object.

This class contains all the data to be charted.
It uses data coordinates, but also records the chart range (in data
coordinates) and hence is able to calculate percentage positions ('In this
view, Point A lies 25% down the x-axis.')

Two things that it does not do are:
1. Record pixel coordinates for anything.
2. (oddly) determine anything about the layout of chart elements.

The naming is a vestige of Dygraph's original PlotKit roots.

@constructor


function(event, g, contextB) {
      // prevents mouse drags from selecting page text.
      if (event.preventDefault) {
        event.preventDefault();  // Firefox, Chrome, etc.
      } else {
        event.returnValue = false;  // IE
        event.cancelBubble = true;
      }

      var canvasPos = utils.findPos(g.canvas_);
      contextB.px = canvasPos.x;
      contextB.py = canvasPos.y;
      contextB.dragStartX = utils.dragGetX_(event, contextB);
      contextB.dragStartY = utils.dragGetY_(event, contextB);
      contextB.cancelNextDblclick = false;
      contextB.tarp.cover();
    }

contextB is the same thing as this context object but renamed.

contextB is the same thing as this context object but renamed .


function(idx) {
    // If we've previously found a non-NaN point and haven't gone past it yet,
    // just use that.
    if (nextPointIdx >= idx) return;

    // We haven't found a non-NaN point yet or have moved past it,
    // look towards the right to find a non-NaN point.
    for (var j = idx; j < points.length; ++j) {
      // Clear out a previously-found point (if any) since it's no longer
      // valid, we shouldn't use it for interpolation anymore.
      nextPoint = null;
      if (!isNaN(points[j].yval) && points[j].yval !== null) {
        nextPointIdx = j;
        nextPoint = points[j];
        break;
      }
    }
  }

Find the next stackable point starting from the given index.

Find the next stackable point starting from the given index .


function validateNativeFormat(data) {
  const firstRow = data[0];
  const firstX = firstRow[0];
  if (typeof firstX !== 'number' && !utils.isDateLike(firstX)) {
    throw new Error(`Expected number or date but got ${typeof firstX}: ${firstX}.`);
  }
  for (let i = 1; i < firstRow.length; i++) {
    const val = firstRow[i];
    if (val === null || val === undefined) continue;
    if (typeof val === 'number') continue;
    if (utils.isArrayLike(val)) continue;  // e.g. error bars or custom bars.
    throw new Error(`Expected number or array but got ${typeof val}: ${val}.`);
  }
}

function
validateNativeFormat
(
data
)
{
const
firstRow
=
data
[
0
]
;
const
firstX
=
firstRow
[
0
]
;
if
(
typeof
firstX
!==
'number'
&&
!
utils
.
isDateLike
(
firstX
)
)
{
throw
new
Error
(
`
${
typeof
firstX
}
${
firstX
}
`
)
;
}
for
(
let
i
=
1
;
i
<
firstRow
.
length
;
i
++
)
{
const
val
=
firstRow
[
i
]
;
if
(
val
===
||
val
===
undefined
)
continue
;
if
(
typeof
val
===
'number'
)
continue
;
if
(
utils
.
isArrayLike
(
val
)
)
continue
;
// e.g. error bars or custom bars.
throw
new
Error
(
`
${
typeof
val
}
${
val
}
`
)
;
}
}

In native format, all values must be dates or numbers. This check isn't perfect but will catch most mistaken uses of strings.

In native format all values must be dates or numbers . This check isn t perfect but will catch most mistaken uses of strings .


function(opt_options) {
    this.canvas_ = document.createElement("canvas");
    opt_options = opt_options || {};
    this.direction_ = opt_options.direction || null;
  }

function ( opt_options ) { this . canvas_ = document . createElement ( "canvas" ) ; opt_options = opt_options || { } ; this . direction_ = opt_options . direction || null ; }


function(div) {
  var sizeSpan = document.createElement('span');
  sizeSpan.setAttribute('style', 'margin: 0; padding: 0 0 0 1em; border: 0;');
  div.appendChild(sizeSpan);
  var oneEmWidth=sizeSpan.offsetWidth;
  div.removeChild(sizeSpan);
  return oneEmWidth;
}


function Keycloak (config, keycloakConfig) {
  // If keycloakConfig is null, Config() will search for `keycloak.json`.
  this.config = new Config(keycloakConfig);

  this.grantManager = new GrantManager(this.config);

  this.stores = [ BearerStore ];

  if (!config) {
    throw new Error('Adapter configuration must be provided.');
  }

  // Add the custom scope value
  this.config.scope = config.scope;

  if (config && config.store && config.cookies) {
    throw new Error('Either `store` or `cookies` may be set, but not both');
  }

  if (config && config.store) {
    this.stores.push(new SessionStore(config.store));
  } else if (config && config.cookies) {
    this.stores.push(CookieStore);
  }

  this.config.idpHint = config.idpHint;
}

Instantiate a Keycloak.

The `config` and `keycloakConfig` hashes are both optional.

The `config` hash, if provided, may include either `store`, pointing
to the actual session-store used by your application, or `cookies`
with boolean `true` as the value to support using cookies as your
authentication store.

A session-based store is recommended, as it allows more assured control
from the Keycloak console to explicitly logout some or all sessions.

In all cases, also, authentication through a Bearer authentication
header is supported for non-interactive APIs.

The `keycloakConfig` object, by default, is populated by the contents of
a `keycloak.json` file installed alongside your application, copied from
the Keycloak administration console when you provision your application.

@constructor

@param      {Object}    config          Configuration for the Keycloak connector.
@param      {Object}    keycloakConfig  Keycloak-specific configuration.

@return     {Keycloak}  A constructed Keycloak object.


function GrantManager (config) {
  this.realmUrl = config.realmUrl;
  this.clientId = config.clientId;
  this.secret = config.secret;
  this.publicKey = config.publicKey;
  this.public = config.public;
  this.bearerOnly = config.bearerOnly;
  this.notBefore = 0;
  this.rotation = new Rotation(config);
}

function GrantManager ( config ) { this . realmUrl = config . realmUrl ; this . clientId = config . clientId ; this . secret = config . secret ; this . publicKey = config . publicKey ; this . public = config . public ; this . bearerOnly = config . bearerOnly ; this . notBefore = 0 ; this . rotation = new Rotation ( config ) ; }

Construct a grant manager.

@param {Config} config Config object.

@constructor


function Rotation (config) {
  this.realmUrl = config.realmUrl;
  this.minTimeBetweenJwksRequests = config.minTimeBetweenJwksRequests;
  this.jwks = [];
  this.lastTimeRequesTime = 0;
}

function Rotation ( config ) { this . realmUrl = config . realmUrl ; this . minTimeBetweenJwksRequests = config . minTimeBetweenJwksRequests ; this . jwks = [ ] ; this . lastTimeRequesTime = 0 ; }

Construct a Rotation instance

@param {Config} config Config object.

@constructor


function Config (config) {
  if (!config) {
    config = path.join(process.cwd(), 'keycloak.json');
  }

  if (typeof config === 'string') {
    this.loadConfiguration(config);
  } else {
    this.configure(config);
  }
}

function Config ( config ) { if ( ! config ) { config = path . join ( process . cwd ( ) , 'keycloak.json' ) ; } if ( typeof config === 'string' ) { this . loadConfiguration ( config ) ; } else { this . configure ( config ) ; } }

Construct a configuration object.

A configuration object may be constructed with either
a path to a `keycloak.json` file (which defaults to
`$PWD/keycloak.json` if not present, or with a configuration
object akin to what parsing `keycloak.json` provides.

@param {String|Object} config Configuration path or details.

@constructor


function Enforcer (keycloak, config) {
  this.keycloak = keycloak;
  this.config = config || {};

  if (!this.config.response_mode) {
    this.config.response_mode = 'permissions';
  }

  if (!this.config.resource_server_id) {
    this.config.resource_server_id = this.keycloak.getConfig().clientId;
  }
}

function Enforcer ( keycloak , config ) { this . keycloak = keycloak ; this . config = config || { } ; if ( ! this . config . response_mode ) { this . config . response_mode = 'permissions' ; } if ( ! this . config . resource_server_id ) { this . config . resource_server_id = this . keycloak . getConfig ( ) . clientId ; } }

Construct a policy enforcer.

@param {Config} config Config object.

@constructor


function Token (token, clientId) {
  this.token = token;
  this.clientId = clientId;

  if (token) {
    try {
      const parts = token.split('.');
      this.header = JSON.parse(Buffer.from(parts[0], 'base64').toString());
      this.content = JSON.parse(Buffer.from(parts[1], 'base64').toString());
      this.signature = Buffer.from(parts[2], 'base64');
      this.signed = parts[0] + '.' + parts[1];
    } catch (err) {
      this.content = {
        exp: 0
      };
    }
  }
}

function Token ( token , clientId ) { this . token = token ; this . clientId = clientId ; if ( token ) { try { const parts = token . split ( '.' ) ; this . header = JSON . parse ( Buffer . from ( parts [ 0 ] , 'base64' ) . toString ( ) ) ; this . content = JSON . parse ( Buffer . from ( parts [ 1 ] , 'base64' ) . toString ( ) ) ; this . signature = Buffer . from ( parts [ 2 ] , 'base64' ) ; this . signed = parts [ 0 ] + '.' + parts [ 1 ] ; } catch ( err ) { this . content = { exp : 0 } ; } } }

Construct a token.

Based on a JSON Web Token string, construct a token object. Optionally
if a `clientId` is provided, the token may be tested for roles with
`hasRole()`.

@constructor

@param {String} token The JSON Web Token formatted token string.
@param {String} clientId Optional clientId if this is an `access_token`.


function filterCss(abstractSyntaxTree, allowedStyles) {
    if (!allowedStyles) {
      return abstractSyntaxTree;
    }

    var filteredAST = cloneDeep(abstractSyntaxTree);
    var astRules = abstractSyntaxTree.nodes[0];
    var selectedRule;

    // Merge global and tag-specific styles into new AST.
    if (allowedStyles[astRules.selector] && allowedStyles['*']) {
      selectedRule = mergeWith(
        cloneDeep(allowedStyles[astRules.selector]),
        allowedStyles['*'],
        function(objValue, srcValue) {
          if (Array.isArray(objValue)) {
            return objValue.concat(srcValue);
          }
        }
      );
    } else {
      selectedRule = allowedStyles[astRules.selector] || allowedStyles['*'];
    }

    if (selectedRule) {
      filteredAST.nodes[0].nodes = astRules.nodes.reduce(filterDeclarations(selectedRule), []);
    }

    return filteredAST;
  }

Filters user input css properties by whitelisted regex attributes.

@param {object} abstractSyntaxTree  - Object representation of CSS attributes.
@property {array[Declaration]} abstractSyntaxTree.nodes[0] - Each object cointains prop and value key, i.e { prop: 'color', value: 'red' }.
@param {object} allowedStyles       - Keys are properties (i.e color), value is list of permitted regex rules (i.e /green/i).
@return {object}                    - Abstract Syntax Tree with filtered style attributes.

Filters user input css properties by whitelisted regex attributes .


function stringifyStyleAttributes(filteredAST) {
    return filteredAST.nodes[0].nodes
      .reduce(function(extractedAttributes, attributeObject) {
        extractedAttributes.push(
          attributeObject.prop + ':' + attributeObject.value
        );
        return extractedAttributes;
      }, [])
      .join(';');
  }

function stringifyStyleAttributes ( filteredAST ) { return filteredAST . nodes [ 0 ] . nodes . reduce ( function ( extractedAttributes , attributeObject ) { extractedAttributes . push ( attributeObject . prop + ':' + attributeObject . value ) ; return extractedAttributes ; } , [ ] ) . join ( ';' ) ; }

Extracts the style attribues from an AbstractSyntaxTree and formats those
values in the inline style attribute format.

@param  {AbstractSyntaxTree} filteredAST
@return {string}             - Example: "color:yellow;text-align:center;font-family:helvetica;"

Extracts the style attribues from an AbstractSyntaxTree and formats those values in the inline style attribute format .


function filterDeclarations(selectedRule) {
    return function (allowedDeclarationsList, attributeObject) {
      // If this property is whitelisted...
      if (selectedRule.hasOwnProperty(attributeObject.prop)) {
        var matchesRegex = selectedRule[attributeObject.prop].some(function(regularExpression) {
          return regularExpression.test(attributeObject.value);
        });

        if (matchesRegex) {
          allowedDeclarationsList.push(attributeObject);
        }
      }
      return allowedDeclarationsList;
    };
  }

function
filterDeclarations
(
selectedRule
)
{
return
function
(
allowedDeclarationsList
,
attributeObject
)
{
// If this property is whitelisted...
if
(
selectedRule
.
hasOwnProperty
(
attributeObject
.
prop
)
)
{
var
matchesRegex
=
selectedRule
[
attributeObject
.
prop
]
.
some
(
function
(
regularExpression
)
{
return
regularExpression
.
test
(
attributeObject
.
value
)
;
}
)
;
if
(
matchesRegex
)
{
allowedDeclarationsList
.
push
(
attributeObject
)
;
}
}
return
allowedDeclarationsList
;
}
;
}

Filters the existing attributes for the given property. Discards any attributes
which don't match the whitelist.

@param  {object} selectedRule             - Example: { color: red, font-family: helvetica }
@param  {array} allowedDeclarationsList   - List of declarations which pass whitelisting.
@param  {object} attributeObject          - Object representing the current css property.
@property {string} attributeObject.type   - Typically 'declaration'.
@property {string} attributeObject.prop   - The CSS property, i.e 'color'.
@property {string} attributeObject.value  - The corresponding value to the css property, i.e 'red'.
@return {function}                        - When used in Array.reduce, will return an array of Declaration objects

Filters the existing attributes for the given property . Discards any attributes which don t match the whitelist .


function readUint64(buffer, offset) {
  var hi = (buffer[offset] << 24 |
            buffer[offset + 1] << 16 |
            buffer[offset + 2] << 8 |
            buffer[offset + 3] << 0) >>> 0;
  var lo = (buffer[offset + 4] << 24 |
            buffer[offset + 5] << 16 |
            buffer[offset + 6] << 8 |
            buffer[offset + 7] << 0) >>> 0;
  return hi * 0x100000000 + lo;
}

function readUint64 ( buffer , offset ) { var hi = ( buffer [ offset ] << 24 | buffer [ offset + 1 ] << 16 | buffer [ offset + 2 ] << 8 | buffer [ offset + 3 ] << 0 ) >>> 0 ; var lo = ( buffer [ offset + 4 ] << 24 | buffer [ offset + 5 ] << 16 | buffer [ offset + 6 ] << 8 | buffer [ offset + 7 ] << 0 ) >>> 0 ; return hi * 0x100000000 + lo ; }

Yes this will lose precision over 2^53, but that can't be helped when returning a single integer. We simply won't support packfiles over 8 petabytes. I'm ok with that.

Yes this will lose precision over 2^53 but that can t be helped when returning a single integer . We simply won t support packfiles over 8 petabytes . I m ok with that .


function check(type, hash, callback) {
    if (typeof type !== "string") throw new TypeError("type must be string");
    if (typeof hash !== "string") throw new TypeError("hash must be string");
    if (hasCache[hash]) return callback(null, true);
    local.hasHash(hash, function (err, has) {
      if (err) return callback(err);
      hasCache[hash] = has;
      callback(null, has);
    });
  }

function
check
(
type
,
hash
,
callback
)
{
if
(
typeof
type
!==
"string"
)
throw
new
TypeError
(
"type must be string"
)
;
if
(
typeof
hash
!==
"string"
)
throw
new
TypeError
(
"hash must be string"
)
;
if
(
hasCache
[
hash
]
)
return
callback
(
,
true
)
;
local
.
hasHash
(
hash
,
function
(
err
,
has
)
{
if
(
err
)
return
callback
(
err
)
;
hasCache
[
hash
]
=
has
;
callback
(
,
has
)
;
}
)
;
}


function readLength() {
    var byte = delta[deltaOffset++];
    var length = byte & 0x7f;
    var shift = 7;
    while (byte & 0x80) {
      byte = delta[deltaOffset++];
      length |= (byte & 0x7f) << shift;
      shift += 7;
    }
    return length;
  }

function readLength ( ) { var byte = delta [ deltaOffset ++ ] ; var length = byte & 0x7f ; var shift = 7 ; while ( byte & 0x80 ) { byte = delta [ deltaOffset ++ ] ; length |= ( byte & 0x7f ) << shift ; shift += 7 ; } return length ; }

Read a variable length number our of delta and move the offset.

Read a variable length number our of delta and move the offset .


function $version(byte) {
    version = (version << 8) | byte;
    if (++offset < 4) return $version;
    if (version >= 2 && version <= 3) {
      offset = 0;
      return $num;
    }
    throw new Error("Invalid version number " + num);
  }

function
$version
(
byte
)
{
version
=
(
version
<<
8
)
|
byte
;
if
(
++
offset
<
4
)
return
$version
;
if
(
version
>=
2
&&
version
<=
3
)
{
offset
=
0
;
return
$num
;
}
throw
new
Error
(
"Invalid version number "
+
num
)
;
}

The version is stored as an unsigned 32 integer in network byte order. It must be version 2 or 3.

The version is stored as an unsigned 32 integer in network byte order . It must be version 2 or 3 .


function $num(byte) {
    num = (num << 8) | byte;
    if (++offset < 4) return $num;
    offset = 0;
    emit({version: version, num: num});
    return $header;
  }

function $num ( byte ) { num = ( num << 8 ) | byte ; if ( ++ offset < 4 ) return $num ; offset = 0 ; emit ( { version : version , num : num } ) ; return $header ; }

The number of objects in this packfile is also stored as an unsigned 32 bit int.

The number of objects in this packfile is also stored as an unsigned 32 bit int .


function emitObject() {
    var body = bodec.join(parts);
    if (body.length !== length) {
      throw new Error("Body length mismatch");
    }
    var item = {
      type: numToType[type],
      size: length,
      body: body,
      offset: start
    };
    if (ref) item.ref = ref;
    parts.length = 0;
    start = 0;
    offset = 0;
    type = 0;
    length = 0;
    ref = null;
    emit(item);
  }

function
emitObject
(
)
{
var
body
=
bodec
.
join
(
parts
)
;
if
(
body
.
length
!==
length
)
{
throw
new
Error
(
"Body length mismatch"
)
;
}
var
item
=
{
type
:
numToType
[
type
]
,
size
:
length
,
body
:
body
,
offset
:
start
}
;
if
(
ref
)
item
.
ref
=
ref
;
parts
.
length
=
0
;
start
=
0
;
offset
=
0
;
type
=
0
;
length
=
0
;
ref
=
;
emit
(
item
)
;
}

Common helper for emitting all three object shapes


function $body(byte, i, chunk) {
    if (inf.write(byte)) return $body;
    var buf = inf.flush();
    if (buf.length !== length) throw new Error("Length mismatch, expected " + length + " got " + buf.length);
    inf.recycle();
    if (buf.length) {
      parts.push(buf);
    }
    emitObject();
    // If this was all the objects, start calculating the sha1sum
    if (--num) return $header;
    sha1sum.update(bodec.slice(chunk, 0, i + 1));
    return $checksum;
  }

Feed the deflated code to the inflate engine


function $checksum(byte) {
    checksum += toHex(byte);
    if (++offset < 20) return $checksum;
    var actual = sha1sum.digest();
    if (checksum !== actual) throw new Error("Checksum mismatch: " + actual + " != " + checksum);
  }

function
$checksum
(
byte
)
{
checksum
+=
toHex
(
byte
)
;
if
(
++
offset
<
20
)
return
$checksum
;
var
actual
=
sha1sum
.
digest
(
)
;
if
(
checksum
!==
actual
)
throw
new
Error
(
"Checksum mismatch: "
+
actual
+
" != "
+
checksum
)
;
}


function(elem) {
    var pattern = new RegExp(_filterValue, 'i');
    var element = elem;
    if (pattern.test(element.textContent)) {
      element.style.display = '';
    } else {
      element.style.display = 'none';
    }
  }

function ( elem ) { var pattern = new RegExp ( _filterValue , 'i' ) ; var element = elem ; if ( pattern . test ( element . textContent ) ) { element . style . display = '' ; } else { element . style . display = 'none' ; } }

Hide element if doesn't contain filter value

@param {Object} element
@private

Hide element if doesn t contain filter value


function() {
    var collection = _logContainer.childNodes;
    var i = collection.length;

    if (i === 0) {
      return;
    }

    while (i) {
      _filterElement(collection[i - 1]);
      i -= 1;
    }
    window.scrollTo(0, document.body.scrollHeight);
  }

function ( ) { var collection = _logContainer . childNodes ; var i = collection . length ; if ( i === 0 ) { return ; } while ( i ) { _filterElement ( collection [ i - 1 ] ) ; i -= 1 ; } window . scrollTo ( 0 , document . body . scrollHeight ) ; }

Filter logs based on _filterValue

@function
@private


function(filterInput, uri) {
    var _url = new URL(uri);
    var _filterValueFromURL = _url.searchParams.get('filter');
    if (typeof _filterValueFromURL !== 'undefined' && _filterValueFromURL !== null) {
      _filterValue = _filterValueFromURL;
      filterInput.value = _filterValue; // eslint-disable-line
    }
  }

function
(
filterInput
,
uri
)
{
var
_url
=
new
URL
(
uri
)
;
var
_filterValueFromURL
=
_url
.
searchParams
.
get
(
'filter'
)
;
if
(
typeof
_filterValueFromURL
!==
'undefined'
&&
_filterValueFromURL
!==
)
{
_filterValue
=
_filterValueFromURL
;
filterInput
.
value
=
_filterValue
;
// eslint-disable-line
}
}

Set _filterValue from URL parameter `filter`

@function
@private

Set _filterValue from URL parameter filter


function(value, uri) {
    var _url = new URL(uri);
    var _params = new URLSearchParams(_url.search.slice(1));
    if (value === '') {
      _params.delete('filter');
    } else {
      _params.set('filter', value);
    }
    _url.search = _params.toString();
    window.history.replaceState(null, document.title, _url.toString());
  }

function ( value , uri ) { var _url = new URL ( uri ) ; var _params = new URLSearchParams ( _url . search . slice ( 1 ) ) ; if ( value === '' ) { _params . delete ( 'filter' ) ; } else { _params . set ( 'filter' , value ) ; } _url . search = _params . toString ( ) ; window . history . replaceState ( null , document . title , _url . toString ( ) ) ; }

Set parameter `filter` in URL

@function
@private


function init(opts) {
      var self = this;

      // Elements
      _logContainer = opts.container;
      _filterInput = opts.filterInput;
      _filterInput.focus();
      _topbar = opts.topbar;
      _body = opts.body;

      _setFilterValueFromURL(_filterInput, window.location.toString());

      // Filter input bind
      _filterInput.addEventListener('keyup', function(e) {
        // ESC
        if (e.keyCode === 27) {
          this.value = '';
          _filterValue = '';
        } else {
          _filterValue = this.value;
        }
        _setFilterParam(_filterValue, window.location.toString());
        _filterLogs();
      });

      // Favicon counter bind
      window.addEventListener(
        'blur',
        function() {
          _isWindowFocused = false;
        },
        true
      );
      window.addEventListener(
        'focus',
        function() {
          _isWindowFocused = true;
          _faviconReset();
        },
        true
      );

      // socket.io init
      _socket = opts.socket;
      _socket
        .on('options:lines', function(limit) {
          _linesLimit = limit;
        })
        .on('options:hide-topbar', function() {
          _topbar.className += ' hide';
          _body.className = 'no-topbar';
        })
        .on('options:no-indent', function() {
          _logContainer.className += ' no-indent';
        })
        .on('options:highlightConfig', function(highlightConfig) {
          _highlightConfig = highlightConfig;
        })
        .on('line', function(line) {
          self.log(line);
        });
    }

function
init
(
opts
)
{
var
self
=
this
;
// Elements
_logContainer
=
opts
.
container
;
_filterInput
=
opts
.
filterInput
;
_filterInput
.
focus
(
)
;
_topbar
=
opts
.
topbar
;
_body
=
opts
.
body
;
_setFilterValueFromURL
(
_filterInput
,
window
.
location
.
toString
(
)
)
;
// Filter input bind
_filterInput
.
addEventListener
(
'keyup'
,
function
(
e
)
{
// ESC
if
(
e
.
keyCode
===
27
)
{
this
.
value
=
''
;
_filterValue
=
''
;
}
else
{
_filterValue
=
this
.
value
;
}
_setFilterParam
(
_filterValue
,
window
.
location
.
toString
(
)
)
;
_filterLogs
(
)
;
}
)
;
// Favicon counter bind
window
.
addEventListener
(
'blur'
,
function
(
)
{
_isWindowFocused
=
false
;
}
,
true
)
;
window
.
addEventListener
(
'focus'
,
function
(
)
{
_isWindowFocused
=
true
;
_faviconReset
(
)
;
}
,
true
)
;
// socket.io init
_socket
=
opts
.
socket
;
_socket
.
on
(
'options:lines'
,
function
(
limit
)
{
_linesLimit
=
limit
;
}
)
.
on
(
'options:hide-topbar'
,
function
(
)
{
_topbar
.
className
+=
' hide'
;
_body
.
className
=
'no-topbar'
;
}
)
.
on
(
'options:no-indent'
,
function
(
)
{
_logContainer
.
className
+=
' no-indent'
;
}
)
.
on
(
'options:highlightConfig'
,
function
(
highlightConfig
)
{
_highlightConfig
=
highlightConfig
;
}
)
.
on
(
'line'
,
function
(
line
)
{
self
.
log
(
line
)
;
}
)
;
}

Init socket.io communication and log container

@param {Object} opts options

Init socket . io communication and log container


function (bBox) {
        var size = Math.max(bBox[3], bBox[4], bBox[5]);
        var ratio = Math.max(viewer._width, viewer._height) / Math.min(viewer._width, viewer._height);
        viewer._distance = size / Math.tan(viewer.perspectiveCamera.fov * Math.PI / 180.0) * ratio * 1.0;
    }

function ( bBox ) { var size = Math . max ( bBox [ 3 ] , bBox [ 4 ] , bBox [ 5 ] ) ; var ratio = Math . max ( viewer . _width , viewer . _height ) / Math . min ( viewer . _width , viewer . _height ) ; viewer . _distance = size / Math . tan ( viewer . perspectiveCamera . fov * Math . PI / 180.0 ) * ratio * 1.0 ; }

helper function for setting of the distance based on camera field of view and size of the product's bounding box

helper function for setting of the distance based on camera field of view and size of the product s bounding box


function handleMouseDown(event) {
        mouseDown = true;
        lastMouseX = event.clientX;
        lastMouseY = event.clientY;
        startX = event.clientX;
        startY = event.clientY;

        //get coordinates within canvas (with the right orientation)
        var r = viewer._canvas.getBoundingClientRect();
        var viewX = startX - r.left;
        var viewY = viewer._height - (startY - r.top);

        //this is for picking
        id = viewer._getID(viewX, viewY);

        /**
        * Occurs when mousedown event happens on underlying canvas.
        *
        * @event xViewer#mouseDown
        * @type {object}
        * @param {Number} id - product ID of the element or null if there wasn't any product under mouse
        */
        viewer._fire('mouseDown', {id: id});

        //keep information about the mouse button
        switch (event.button) {
            case 0:
                button = 'left';
                break;

            case 1:
                button = 'middle';
                break;

            case 2:
                button = 'right';
                break;

            default:
                button = 'left';
                break;
        }

        viewer._disableTextSelection();
    }

set initial conditions so that different gestures can be identified


function clone(obj) {
  var key, copy = {};
  if (!obj) {
    return;
  }

  for (key in obj) {
    copy[key] = obj[key];
  }

  return copy;
}

function clone ( obj ) { var key , copy = { } ; if ( ! obj ) { return ; } for ( key in obj ) { copy [ key ] = obj [ key ] ; } return copy ; }


function navigate(n) {
  var position = currentPosition();
  var numSlides = document.getElementsByClassName('slide').length;

  /* Positions are 1-indexed, so we need to add and subtract 1 */
  var nextPosition = (position - 1 + n) % numSlides + 1;

  /* Normalize nextPosition in-case of a negative modulo result */
  nextPosition = (nextPosition - 1 + numSlides) % numSlides + 1;

  document.getElementById('slide-' + position).classList.add('hidden');
  document.getElementById('slide-' + nextPosition).classList.remove('hidden');

  updateProgress();
  updateURL();
  updateTabIndex();
}

Navigates forward n pages
If n is negative, we will navigate in reverse

Navigates forward n pages If n is negative we will navigate in reverse


function updateURL() {
  try {
    window.history.replaceState({} , null, '#' + currentPosition());
  } catch (e) {
    window.location.hash = currentPosition();
  }
}

function updateURL ( ) { try { window . history . replaceState ( { } , null , '#' + currentPosition ( ) ) ; } catch ( e ) { window . location . hash = currentPosition ( ) ; } }

Updates the current URL to include a hashtag of the current page number.

Updates the current URL to include a hashtag of the current page number .


function updateProgress() {
  var progressBar = document.querySelector('.progress-bar');

  if (progressBar !== null) {
    var numSlides = document.getElementsByClassName('slide').length;
    var position = currentPosition() - 1;
    var percent = (numSlides === 1) ? 100 : 100 * position / (numSlides - 1);
    progressBar.style.width = percent.toString() + '%';
  }
}

function updateProgress ( ) { var progressBar = document . querySelector ( '.progress-bar' ) ; if ( progressBar !== null ) { var numSlides = document . getElementsByClassName ( 'slide' ) . length ; var position = currentPosition ( ) - 1 ; var percent = ( numSlides === 1 ) ? 100 : 100 * position / ( numSlides - 1 ) ; progressBar . style . width = percent . toString ( ) + '%' ; } }


function updateTabIndex() {
  var allLinks = document.querySelectorAll('.slide a');
  var position = currentPosition();
  var currentPageLinks = document.getElementById('slide-' + position).querySelectorAll('a');
  var i;

  for (i = 0; i < allLinks.length; i++) {
    allLinks[i].setAttribute('tabindex', -1);
  }

  for (i = 0; i < currentPageLinks.length; i++) {
    currentPageLinks[i].removeAttribute('tabindex');
  }
}

function
updateTabIndex
(
)
{
var
allLinks
=
document
.
querySelectorAll
(
'.slide a'
)
;
var
position
=
currentPosition
(
)
;
var
currentPageLinks
=
document
.
getElementById
(
'slide-'
+
position
)
.
querySelectorAll
(
'a'
)
;
var
i
;
for
(
i
=
0
;
i
<
allLinks
.
length
;
i
++
)
{
allLinks
[
i
]
.
setAttribute
(
'tabindex'
,
1
)
;
}
for
(
i
=
0
;
i
<
currentPageLinks
.
length
;
i
++
)
{
currentPageLinks
[
i
]
.
removeAttribute
(
'tabindex'
)
;
}
}

Removes tabindex property from all links on the current slide, sets
tabindex = -1 for all links on other slides. Prevents slides from appearing
out of control.

Removes tabindex property from all links on the current slide sets tabindex = - 1 for all links on other slides . Prevents slides from appearing out of control .


function pluck(obj, fields) {
  var plucked = {};
  if (!obj) {
    return;
  }

  fields.forEach(function (field) {
    plucked[field] = obj[field];
  });

  return plucked;
}

function pluck ( obj , fields ) { var plucked = { } ; if ( ! obj ) { return ; } fields . forEach ( function ( field ) { plucked [ field ] = obj [ field ] ; } ) ; return plucked ; }


function loadSingle(source) {
  var promise;

  if (source.match(/^https?:\/\//)) {
    promise = httpGetPromise(source);
  } else {
    promise = readFilePromise(normalizePath(source));
  }

  return promise;
}

function loadSingle ( source ) { var promise ; if ( source . match ( / ^https?:\/\/ / ) ) { promise = httpGetPromise ( source ) ; } else { promise = readFilePromise ( normalizePath ( source ) ) ; } return promise ; }

Loads a single static asset from either a filename or URL

@param {string} source The source document to load
@return {Promise.<string>} The file contents


function populateSingle(filename, destination, key) {
  return loadSingle(filename)
    .then(function (data) {
      if (data) {
        /**
         * If the key points to an array in the destination map, then
         * we should also append to an array in the `loaded` section
         * of the map.
         *
         * This is useful for style resources, where `external.style` may
         * refer to a list of resources to be loaded.
         */
        if (Object.prototype.toString.call(destination[key]) === '[object Array]') {
          destination.loaded[key] = destination.loaded[key] || [];
          destination.loaded[key].push(data);
        } else {
          destination.loaded[key] = data;
        }
      }
    });
}

Loads a single asset and sets the returned data to the `loaded` subobject
of a given resource map

Usage: helper.populateSingle(this.metadata.template, this.templates, 'slides')
helper.populateSingle(this.metadata.layout, this.templates, 'layout')

@param {string} filename The name and location of the file to load
@param {Object} destination The destination map to store the loaded data
@param {string} key The key to use for storing the loaded data in destination
@return {Promise}

Loads a single asset and sets the returned data to the loaded subobject of a given resource map


function load(map, options) {
  var promises = [];
  var loaded = {};
  var filename;

  options = options || {};

  for (var key in map) {
    if (map.hasOwnProperty(key)) {
      if (!map[key] || map[key].length === 0) {
        continue;
      }

      filename = map[key];
      if (!options.external) {
        filename = path.resolve(ROOT_DIR, filename);
      }

      promises.push(loadSingle(filename)
        .then((function (_key) {
          return function (data) {
            loaded[_key] = data;
          };
        })(key)));
    }
  }

  map.loaded = loaded;

  return Q.all(promises);
}

function load ( map , options ) { var promises = [ ] ; var loaded = { } ; var filename ; options = options || { } ; for ( var key in map ) { if ( map . hasOwnProperty ( key ) ) { if ( ! map [ key ] || map [ key ] . length === 0 ) { continue ; } filename = map [ key ] ; if ( ! options . external ) { filename = path . resolve ( ROOT_DIR , filename ) ; } promises . push ( loadSingle ( filename ) . then ( ( function ( _key ) { return function ( data ) { loaded [ _key ] = data ; } ; } ) ( key ) ) ) ; } } map . loaded = loaded ; return Q . all ( promises ) ; }

Loads files from a given map and places them in that map's `loaded` field

@param {Object} map The map of labels to filenames
@param {!Object} options Load options
@return {Promise.<Array.<Object>>} The same map with a `loaded` field
populated with file contents

Loads files from a given map and places them in that map s loaded field


function loadSettings(source, ctx) {
  return loadSingle(source).then(function (data) {
    if (data) {
      data = JSON.parse(data);
      ctx.override = data.override;
    }
  });
}

function loadSettings ( source , ctx ) { return loadSingle ( source ) . then ( function ( data ) { if ( data ) { data = JSON . parse ( data ) ; ctx . override = data . override ; } } ) ; }

Loads a settings file and sets appropriate options. Used to determine
whether or not we should completely override a style in a theme

@param {string} source The source of the settings file to load
@param {Object} ctx The given context to set our options
@return {Promise}

Loads a settings file and sets appropriate options . Used to determine whether or not we should completely override a style in a theme


function readFilePromise(filename) {
  var deferred;

  deferred = Q.defer();

  fs.readFile(filename, 'utf-8', function (err, contents) {
    if (err) {
      if (err.code === 'ENOENT') {
        debug(err.code + ': ' + filename);
        return deferred.resolve();
      }
      debug(err + ' ' + filename);
      // TODO: better error handling
      deferred.reject(err);
    } else {
      debug('read ' + filename);
      deferred.resolve(contents);
    }
  });

  return deferred.promise;
}

function
readFilePromise
(
filename
)
{
var
deferred
;
deferred
=
Q
.
defer
(
)
;
fs
.
readFile
(
filename
,
'utf-8'
,
function
(
err
,
contents
)
{
if
(
err
)
{
if
(
err
.
code
===
'ENOENT'
)
{
debug
(
err
.
code
+
': '
+
filename
)
;
return
deferred
.
resolve
(
)
;
}
debug
(
err
+
' '
+
filename
)
;
// TODO: better error handling
deferred
.
reject
(
err
)
;
}
else
{
debug
(
'read '
+
filename
)
;
deferred
.
resolve
(
contents
)
;
}
}
)
;
return
deferred
.
promise
;
}

Promise to load a file's contents

@param {string} filename The file to load
@return {Promise.<string>} The file's contents


function httpGetPromise(url) {
  var deferred = Q.defer(), get;

  var cb = function (res) {
    var data = '';

    res.on('data', function (chunk) {
      data += chunk;
    });

    res.on('err', function (err) {
      debug(err + ' ' + url);
      deferred.reject(err);
    });

    res.on('end', function () {
      if (res.statusCode !== 200) {
        debug(res.statusCode + ': ' + url);
        deferred.resolve();
      } else {
        debug('fetched ' + url);
        deferred.resolve(data);
      }
    });
  };

  if (url.match(/^https/)) {
    get = https.get(url, cb);
  } else {
    get = http.get(url, cb);
  }

  get.on('error', function (err) {
    deferred.resolve();
    debug(err + ': ' + url);
  });

  return deferred.promise;
}

function
httpGetPromise
(
url
)
{
var
deferred
=
Q
.
defer
(
)
,
get
;
var
cb
=
function
(
res
)
{
var
data
=
''
;
res
.
on
(
'data'
,
function
(
chunk
)
{
data
+=
chunk
;
}
)
;
res
.
on
(
'err'
,
function
(
err
)
{
debug
(
err
+
' '
+
url
)
;
deferred
.
reject
(
err
)
;
}
)
;
res
.
on
(
'end'
,
function
(
)
{
if
(
res
.
statusCode
!==
200
)
{
debug
(
res
.
statusCode
+
': '
+
url
)
;
deferred
.
resolve
(
)
;
}
else
{
debug
(
'fetched '
+
url
)
;
deferred
.
resolve
(
data
)
;
}
}
)
;
}
;
if
(
url
.
match
(
/
^https
/
)
)
{
get
=
https
.
get
(
url
,
cb
)
;
}
else
{
get
=
http
.
get
(
url
,
cb
)
;
}
get
.
on
(
'error'
,
function
(
err
)
{
deferred
.
resolve
(
)
;
debug
(
err
+
': '
+
url
)
;
}
)
;
return
deferred
.
promise
;
}

Promise to perform a get request and return the result

@param {string} url The url to request
@return {Promise.<string>} The body of the response


function getUserHome() {
  return process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE;
}

function getUserHome ( ) { return process . env . HOME || process . env . HOMEPATH || process . env . USERPROFILE ; }

Returns the home directory of the current user

@return {string} The path to the current user's home directory


function Request(method, urlPath, cache) {
	this._method = method;
	this._urlPath = urlPath;
	this._cache = cache;

	this._queryParams = [];
	// _postParams should initially be null instead of {} because we want to allow people to send POST requests with
	// empty data sets (if they need to).  This way, we can differentiate between a default of null, an empty data set,
	// and a populated data set.
	this._postParams = null;
	this._headers = {};
	this._timeout = null;
	this._type = "json"; // superagent's default, only for POST/PUT/PATCH methods

	// public field
	this.aborted = undefined; //default to undefined
}

Implements a subset of superagent's API. Packages up arguments
to pass to superagent under the hood.

Implements a subset of superagent s API . Packages up arguments to pass to superagent under the hood .


function logRequestError(err) {

	var {response} = err;
	if (!response) {
		logger.warning(`ReactServerAgent raised exception for URL ${this._urlPath}`, err);
	} else if (response.notFound) {
		// 404? don't care about response
		logger.warning(`Resource not found on server: ${this._urlPath}`);
	} else if (response.serverError) {
		logger.warning(`Received server error for URL ${this._urlPath}`, err);
	} else {
		logger.warning(`Unexpected status code returned for URL ${this._urlPath}`, err);
	}
}

function
logRequestError
(
err
)
{
var
{
response
}
=
err
;
if
(
!
response
)
{
logger
.
warning
(
`
${
this
.
_urlPath
}
`
,
err
)
;
}
else
if
(
response
.
notFound
)
{
// 404? don't care about response
logger
.
warning
(
`
${
this
.
_urlPath
}
`
)
;
}
else
if
(
response
.
serverError
)
{
logger
.
warning
(
`
${
this
.
_urlPath
}
`
,
err
)
;
}
else
{
logger
.
warning
(
`
${
this
.
_urlPath
}
`
,
err
)
;
}
}

private method; 'this' bound to request object

private method ; this bound to request object


function(fn, opts, trim, basePath, prefix){
	var slashPattern = isWindows
		?/\\/g
		:/\//g
	var name = fn.substring(basePath.length+trim.length, fn.length)
		.replace(/\.jsx?$/, '')
		.replace(slashPattern,'.')
	if (opts.label) {
		name += '.'+opts.label
	}
	if (prefix) {
		name = prefix + name
	}
	return name;
}

function ( fn , opts , trim , basePath , prefix ) { var slashPattern = isWindows ? / \\ / g : / \/ / g var name = fn . substring ( basePath . length + trim . length , fn . length ) . replace ( / \.jsx?$ / , '' ) . replace ( slashPattern , '.' ) if ( opts . label ) { name += '.' + opts . label } if ( prefix ) { name = prefix + name } return name ; }

Gets the name of a logger from its filepath.
@example
getName(
'my-component',
{ label: 'sub' },
'my-project.src',
'my-project/src/components/my-component.js'
) // returns "components.my-component"
@param  {String}   fn       filename
@param  {Object}   opts     { label: 'Optional logger label' }
@param  {String}   trim     The leading portion of the name to remove
@param  {String}   basePath The path to the file
@param  {String}   prefix   A prefix to prepend to the name
@return {String}            The logger name, e.g. my-project.components.my-component

Gets the name of a logger from its filepath .


function writeBody(req, res, context, start, page) {

	// standardize to an array of EarlyPromises of ReactElements
	var elementPromises = PageUtil.standardizeElements(page.getElements());

	// This is where we'll store our rendered HTML strings.  A value of
	// `undefined` means we haven't rendered that element yet.
	var rendered = elementPromises.map(() => ELEMENT_PENDING);

	// We need to return a promise that resolves when we're done, so we'll
	// maintain an array of deferreds that we punch out as we render
	// elements and we'll return a promise that resolves when they've all
	// been hit.
	var dfds = elementPromises.map(() => Q.defer());

	var doElement = (element, index) => {

		// Exceeded `FAILSAFE_RENDER_TIMEOUT`.  Bummer.
		if (rendered[index] === ELEMENT_ALREADY_WRITTEN) return;

		rendered[index] = renderElement(res, element, context);

		// If we've just rendered the next element to be written we'll
		// write it out.
		writeElements(res, rendered);

		dfds[index].resolve();
	};

	// Render elements as their data becomes available.
	elementPromises.forEach((promise, index) => promise
		.then(element => doElement(element, index))
		.catch(e => {
			logger.error(`Error rendering element ${index}`, e)
			// TODO: the error handling here should probably be merged
			// somehow with renderElement so that we get timing info.

			// In the case where there was an exception thrown while rendering,
			// the next three lines are effectively a no-op. In the case where
			// the element promise was rejected, this prevents a hang until
			// FAILSAFE_RENDER_TIMEOUT has passed.

			// No way we can recover in the second case, so let's just move on.
			// We'll call `writeElements` just in case everything is ready
			// after us.

			// This doesn't completely handle the extremely unlikely case that:
			//     1) `renderElement` successfully rendered this element, and
			//     2) `writeElements` successfully wrote it, but...
			//     3) `writeElements` threw after this element was written.
			//
			// We'll make a good-faith effort, but in this rare case writeElements is probably
			// going to fail again when we call it here. At least if that happens, _this_
			// particular element should show up properly on the page, even though the page
			// overall could be totally horked. And we won't have a 20s timeout...
			try {
				if (rendered[index] !== ELEMENT_ALREADY_WRITTEN) {
					rendered[index] = '';
					writeElements(res, rendered);
				}
			} finally {
				// try _really_ hard to resolve this deferred, to avoid a 20s hang.
				dfds[index].resolve();
			}
		})
		// just in case writeElements throws in our error callback above.
		.catch(e => logger.error(`Error recovering from error rendering element ${index}`, e))
	);

	// Some time has already elapsed since the request started.
	// Note that you can override `FAILSAFE_RENDER_TIMEOUT` with a
	// `?_debug_render_timeout={ms}` query string parameter.
	var totalWait     = DebugUtil.getRenderTimeout() || FAILSAFE_RENDER_TIMEOUT
		,   timeRemaining = totalWait - (new Date - start)

	var retval = Q.defer();
	var writeBodyDfd = Q.defer();

	// If we exceed the timeout then we'll just send empty elements for
	// anything that hadn't rendered yet.
	writeBodyDfd.promise.catch((err) => {

		// Write out what we've got.
		writeElements(res, rendered.map(
			value => value === ELEMENT_PENDING?'':value
		));

		// If it hasn't arrived by now, we're not going to wait for it.
		RLS().lateArrivals = undefined;

		// Let the client know it's not getting any more data.
		renderScriptsAsync([{ text: `__reactServerClientController.failArrival()` }], res)

		//Log timeout error but still resolve so we continue in the lifecycle process
		logger.error("Error in writeBody", err);
		retval.resolve();
	});

	Q.all(dfds.map(dfd => dfd.promise)).then(writeBodyDfd.resolve);

	const timeout = setTimeout(() => {
		// give some additional information when we time out
		writeBodyDfd.reject({
			message: "Timed out rendering.",
			// `timeRemaining` is how long we waited before timing out
			timeWaited: timeRemaining,
			elements: rendered.map(val => {
				if (val === ELEMENT_ALREADY_WRITTEN) {
					return 'W'; // written
				} else if (val === ELEMENT_PENDING) {
					return 'P'; // not rendered
				} else {
					return 'R'; // rendered, not yet written
				}
			}),
		});
	}, timeRemaining);

	// Don't leave dead timers hanging around.
	writeBodyDfd.promise.then(() => {
		clearTimeout(timeout);
		//writeBody ran successfully, sweet
		retval.resolve();
	});

	return retval.promise;
}

Writes out the ReactElements to the response. Returns a promise that fulfills when
all the ReactElements have been written out.

Writes out the ReactElements to the response . Returns a promise that fulfills when all the ReactElements have been written out .


function writeElements(res, elements) {

	// Pick up where we left off.
	var start = RLS().nextElement||(RLS().nextElement=0);

	for (var i = start; i < elements.length; RLS().nextElement = ++i){

		// If we haven't rendered the next element yet, we're done.
		if (elements[i] === ELEMENT_PENDING) break;

		// Got one!
		writeElement(res, elements[i], i);

		// Free for GC.
		elements[i] = ELEMENT_ALREADY_WRITTEN;

		if (PageUtil.PageConfig.get('isFragment')) continue;

		if (RLS().haveBootstrapped) {

			// We've already bootstrapped, so we can immediately tell the
			// client controller to wake the new element we just sent.
			wakeElementRange(res, i, i);
		} else if (i === elements.length - 1) {

			// Page didn't emit `<TheFold/>`.  Now we're done.
			// This wakes everything up through `i`.
			bootstrapClient(res, i);
		}
	}

	// It may be a while before we render the next element, so if we just
	// wrote anything let's send it down right away.
	if (i !== start) flushRes(res);
}

Write as many elements out in a row as possible and then flush output. We render elements as their data becomes available, so they might fill in out-of-order.

Write as many elements out in a row as possible and then flush output . We render elements as their data becomes available so they might fill in out - of - order .


function makeStandard(standardize, fn){
	return function(){
		return standardize(fn.apply(null, [].slice.call(arguments)));
	}
}

function makeStandard ( standardize , fn ) { return function ( ) { return standardize ( fn . apply ( null , [ ] . slice . call ( arguments ) ) ) ; } }

Return `fn` with a wrapper that puts its return value through `standardize` on the way out.

Return fn with a wrapper that puts its return value through standardize on the way out .


function (state, title, url) {
		var win = this.win;
		if (this.canClientNavigate()) {
			win.history.pushState(state, title, url);
		} else {
			this.navigationWindow().location.href = url;
		}
	}

function ( state , title , url ) { var win = this . win ; if ( this . canClientNavigate ( ) ) { win . history . pushState ( state , title , url ) ; } else { this . navigationWindow ( ) . location . href = url ; } }

Same as HTML5 pushState API, but with old browser support
@method pushState
@param {Object} state The state object
@param {String} title The title string
@param {String} url The new url

Same as HTML5 pushState API but with old browser support


function (state, title, url) {
		var win = this.win;
		if (this.canClientNavigate()) {
			win.history.replaceState(state, title, url);
		} else if (url !== this.currentUrl()) {

			// On browsers that don't support history navigation, only want to
			// replace state if the URL is actually changing.  Otherwise we're
			// in for a potential infinite refresh loop.
			this.navigationWindow().location.replace(url);
		}
	}

Same as HTML5 replaceState API, but with old browser support
@method replaceState
@param {Object} state The state object
@param {String} title The title string
@param {String} url The new url

Same as HTML5 replaceState API but with old browser support


function writeClientBootstrapFile(outputDir, opts) {
	const outputFile = outputDir + "/entry.js";
	fs.writeFileSync(outputFile, `
		import reactServer from "react-server";
	    import routes from "./routes_client";

		if (typeof window !== "undefined") {
			window.__setReactServerBase = (path) => {
				__webpack_public_path__ = path;
				window.__reactServerBase = path;
			}
		}
		window.rfBootstrap = () => {
			reactServer.logging.setLevel('main',  ${JSON.stringify(opts.logLevel)});
			reactServer.logging.setLevel('time',  ${JSON.stringify(opts.timingLogLevel)});
			reactServer.logging.setLevel('gauge', ${JSON.stringify(opts.gaugeLogLevel)});
			new reactServer.ClientController({routes}).init();
		}`
	);
	return outputFile;
}

function writeClientBootstrapFile ( outputDir , opts ) { const outputFile = outputDir + "/entry.js" ; fs . writeFileSync ( outputFile , ` ${ JSON . stringify ( opts . logLevel ) } ${ JSON . stringify ( opts . timingLogLevel ) } ${ JSON . stringify ( opts . gaugeLogLevel ) } ` ) ; return outputFile ; }

writes out a bootstrap file for the client which in turn includes the client routes file. note that outputDir must be the same directory as the client routes file, which must be named "routes_client".

writes out a bootstrap file for the client which in turn includes the client routes file . note that outputDir must be the same directory as the client routes file which must be named routes_client .


function errorInterceptor (level, msg, meta) {

	if (meta instanceof Error) {
		meta = {error: meta};
	} else if (meta && meta.status && meta.response) {
		meta = {error: meta};
	}

	if (_.isPlainObject(meta)) {
		// allow {error: <someError>} as a valid `meta`
		meta = _.mapValues(meta, normalizeError);
	}
	return meta;
}

Error objects are weird.  Let's turn them into normal objects.

Error objects are weird . Let s turn them into normal objects .


function normalizeError (err) {
	if (err instanceof Error) {
		return _.pickBy({
			message: err.message,
			stack: err.stack,
		}, val => !_.isEmpty(val));
	}

	if (err && err.status && err.response) {
		// this is probably a superagent error response. we definitely don't
		// want to log the whole thing
		return {
			response: {
				status: err.status,
				responseText: _.truncate(_.trimStart(err.response ? err.response.text : "<no response body>"), 200),
			},
		}
	}

	return err;
}

massage the error into a format suitable for logging


function wrapLogger(getLoggerForConfig, opts) {

	var mainLogger    = getLoggerForConfig('main',  opts)
		,   timeLogger    = getLoggerForConfig('time',  opts)
		,   gaugeLogger   = getLoggerForConfig('gauge', opts)
		,   classifyTime  = makeTimeClassifier(opts)
		,   classifyGauge = makeGaugeClassifier(opts)

	// These are methods that are exposed on the primary logger.
	// They just dispatch to appropriate log levels on secondary loggers.
	mainLogger.time  = (token, ms,  opts) => timeLogger [classifyTime (ms,  opts)](token, {ms });
	mainLogger.gauge = (token, val, opts) => gaugeLogger[classifyGauge(val, opts)](token, {val});

	// Expose these.
	mainLogger.timeLogger  = timeLogger;
	mainLogger.gaugeLogger = gaugeLogger;

	// This is just a convenience wrapper around the `time` method.
	mainLogger.timer = (token, opts) => {

		var t0 = new Date // For use by `timer.stop`.
			,   tt = t0       // For use by `timer.tick`.
			,   nt = 0        // Number of times `tick` has been called.
			,   ct = 0        // For storing return values.

		return {

			// The `stop` method logs the total elapsed time since
			// timer creation.
			stop: () => (mainLogger.time(token, ct = new Date - t0, opts), ct),

			// The `tick` method logs the time elapsed since the
			// last call to `tick` (or since timer creation).  A
			// tick may be named.  If a name is not passed in the
			// number of times `tick` has been called on this
			// timer will be used.  Don't mix named and un-named
			// ticks.
			tick: (name) => {
				var now = new Date

				name || (name = `tick_${nt++}`);

				mainLogger.time(`${token}.${name}`, ct=now-tt, opts);

				tt = now;

				return ct
			},
		};
	}

	return mainLogger;
}

Each logger actually has some secondary loggers attached to it for stats. This helper wires them up.

Each logger actually has some secondary loggers attached to it for stats . This helper wires them up .


function makeThresholdsSieve(options, defaults) {

	if (!options) options = {};

	// Pre-apply defaults.
	Object.keys(defaults).forEach(key => options[key] || (options[key] = defaults[key]));

	return (key, overrides) => {
		if (overrides && overrides[key] !== void 0) return overrides[key];
		return options[key];
	}
}

function
makeThresholdsSieve
(
options
,
defaults
)
{
if
(
!
options
)
options
=
{
}
;
// Pre-apply defaults.
Object
.
keys
(
defaults
)
.
forEach
(
key
=>
options
[
key
]
||
(
options
[
key
]
=
defaults
[
key
]
)
)
;
return
(
key
,
overrides
)
=>
{
if
(
overrides
&&
overrides
[
key
]
!==
void
0
)
return
overrides
[
key
]
;
return
options
[
key
]
;
}
}

This is used for classifying `time` and `gauge` values.

This is used for classifying time and gauge values .


function merge_objs(source,target) {
		for (var k in source) { if (source.hasOwnProperty(k)) {
			target[k] = source[k]; // TODO: does this need to be recursive for our purposes?
		}}
		return target;
	}


function check_chain_group_scripts_ready(chain_group) {
		var any_scripts_ready = false;
		for (var i=0; i<chain_group.scripts.length; i++) {
			if (chain_group.scripts[i].ready && chain_group.scripts[i].exec_trigger) {
				any_scripts_ready = true;
				chain_group.scripts[i].exec_trigger();
				chain_group.scripts[i].exec_trigger = null;
			}
		}
		return any_scripts_ready;
	}

function check_chain_group_scripts_ready ( chain_group ) { var any_scripts_ready = false ; for ( var i = 0 ; i < chain_group . scripts . length ; i ++ ) { if ( chain_group . scripts [ i ] . ready && chain_group . scripts [ i ] . exec_trigger ) { any_scripts_ready = true ; chain_group . scripts [ i ] . exec_trigger ( ) ; chain_group . scripts [ i ] . exec_trigger = null ; } } return any_scripts_ready ; }

does the chain group have any ready-to-execute scripts?

does the chain group have any ready - to - execute scripts?


function create_script_load_listener(elem,registry_item,flag,onload) {
		elem.onload = elem.onreadystatechange = function() {
			if ((elem.readyState && elem.readyState != "complete" && elem.readyState != "loaded") || registry_item[flag]) return;
			elem.onload = elem.onreadystatechange = null;
			onload();
		};
	}

function create_script_load_listener ( elem , registry_item , flag , onload ) { elem . onload = elem . onreadystatechange = function ( ) { if ( ( elem . readyState && elem . readyState != "complete" && elem . readyState != "loaded" ) || registry_item [ flag ] ) return ; elem . onload = elem . onreadystatechange = null ; onload ( ) ; } ; }


function script_executed(registry_item) {
		registry_item.ready = registry_item.finished = true;
		for (var i=0; i<registry_item.finished_listeners.length; i++) {
			registry_item.finished_listeners[i]();
		}
		registry_item.ready_listeners = [];
		registry_item.finished_listeners = [];
	}

function script_executed ( registry_item ) { registry_item . ready = registry_item . finished = true ; for ( var i = 0 ; i < registry_item . finished_listeners . length ; i ++ ) { registry_item . finished_listeners [ i ] ( ) ; } registry_item . ready_listeners = [ ] ; registry_item . finished_listeners = [ ] ; }


function request_script(chain_opts,script_obj,registry_item,onload,preload_this_script) {
		// setTimeout() "yielding" prevents some weird race/crash conditions in older browsers
		setTimeout(function(){
			var script, src = script_obj.real_src, xhr;

			// don't proceed until `append_to` is ready to append to
			if ("item" in append_to) { // check if `append_to` ref is still a live node list
				if (!append_to[0]) { // `append_to` node not yet ready
					// try again in a little bit -- note: will re-call the anonymous function in the outer setTimeout, not the parent `request_script()`
					setTimeout(arguments.callee,25);
					return;
				}
				// reassign from live node list ref to pure node ref -- avoids nasty IE bug where changes to DOM invalidate live node lists
				append_to = append_to[0];
			}
			script = document.createElement("script");
			if (script_obj.type) script.type = script_obj.type;
			if (script_obj.charset) script.charset = script_obj.charset;
			if (script_obj.crossOrigin) script.crossOrigin = script_obj.crossOrigin;

			// should preloading be used for this script?
			if (preload_this_script) {
				// real script preloading?
				if (real_preloading) {
					if (chain_opts[_Debug]) log_msg("start script preload: "+src);
					registry_item.elem = script;
					if (explicit_preloading) { // explicit preloading (aka, Zakas' proposal)
						script.preload = true;
						script.onpreload = onload;
					}
					else {
						script.onreadystatechange = function(){
							if (script.readyState == "loaded") onload();
						};
					}
					script.src = src;
					// NOTE: no append to DOM yet, appending will happen when ready to execute
				}

				// This is the ultimate fallback in React Server.  The
				// "cache-preloading" option in stock LABjs doesn't work in
				// modern Chrome, so... this is our last best hope.  If you're
				// configured for splitJsLoadFromExecution then you'd better
				// have xhr access to your scripts!  They need to either be on
				// the same domain or have CORS headers.
				else if (chain_opts[_UseCORSXHR] || (src.indexOf(root_domain) == 0 && chain_opts[_UseLocalXHR])) {
					xhr = new XMLHttpRequest(); // note: IE never uses XHR (it supports true preloading), so no more need for ActiveXObject fallback for IE <= 7
					if (chain_opts[_Debug]) log_msg("start script preload (xhr): "+src);
					xhr.onreadystatechange = function() {
						if (xhr.readyState == 4) {
							xhr.onreadystatechange = function(){}; // fix a memory leak in IE
							registry_item.text = xhr.responseText + "\n//@ sourceURL=" + src; // http://blog.getfirebug.com/2009/08/11/give-your-eval-a-name-with-sourceurl/
							onload();
						}
					};
					xhr.open("GET",src);
					xhr.send();
				}
				// as a last resort, use cache-preloading
				else {
					if (chain_opts[_Debug]) log_msg("start script preload (cache): "+src);
					script.type = "text/cache-script";
					create_script_load_listener(script,registry_item,"ready",function() {
						append_to.removeChild(script);
						onload();
					});
					script.src = src;
					append_to.insertBefore(script,append_to.firstChild);
				}
			}
			// use async=false for ordered async? parallel-load-serial-execute http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order
			else if (script_ordered_async) {
				if (chain_opts[_Debug]) log_msg("start script load (ordered async): "+src);
				script.async = false;
				create_script_load_listener(script,registry_item,"finished",onload);
				script.src = src;
				append_to.insertBefore(script,append_to.firstChild);
			}
			// otherwise, just a normal script element
			else {
				if (chain_opts[_Debug]) log_msg("start script load: "+src);
				create_script_load_listener(script,registry_item,"finished",onload);
				script.src = src;
				append_to.insertBefore(script,append_to.firstChild);
			}
		},0);
	}


function execute_preloaded_script(chain_opts,script_obj,registry_item) {
			var script;

			function preload_execute_finished() {
				if (script != null) { // make sure this only ever fires once
					script = null;
					script_executed(registry_item);
				}
			}

			if (registry[script_obj.src].finished) return;
			if (!chain_opts[_AllowDuplicates]) registry[script_obj.src].finished = true;

			script = registry_item.elem || document.createElement("script");
			if (script_obj.type) script.type = script_obj.type;
			if (script_obj.charset) script.charset = script_obj.charset;
			if (script_obj.crossOrigin) script.crossOrigin = script_obj.crossOrigin;
			create_script_load_listener(script,registry_item,"finished",preload_execute_finished);

			// script elem was real-preloaded
			if (registry_item.elem) {
				registry_item.elem = null;
			}
			// script was XHR preloaded
			else if (registry_item.text) {
				script.onload = script.onreadystatechange = null;	// script injection doesn't fire these events
				script.text = registry_item.text;
			}
			// script was cache-preloaded
			else {
				script.src = script_obj.real_src;
			}
			append_to.insertBefore(script,append_to.firstChild);

			// manually fire execution callback for injected scripts, since events don't fire
			if (registry_item.text) {
				preload_execute_finished();
			}
		}

execute a script that has been preloaded already


function do_script(chain_opts,script_obj,chain_group,preload_this_script) {
			var registry_item,
				registry_items,
				ready_cb = function(){ script_obj.ready_cb(script_obj,function(){ execute_preloaded_script(chain_opts,script_obj,registry_item); }); },
				finished_cb = function(){ script_obj.finished_cb(script_obj,chain_group); }
			;

			script_obj.src = canonical_uri(script_obj.src,chain_opts[_BasePath]);
			script_obj.real_src = script_obj.src +
				// append cache-bust param to URL?
				(chain_opts[_CacheBust] ? ((/\?.*$/.test(script_obj.src) ? "&_" : "?_") + ~~(Math.random()*1E9) + "=") : "")
			;

			if (!registry[script_obj.src]) registry[script_obj.src] = {items:[],finished:false};
			registry_items = registry[script_obj.src].items;

			// allowing duplicates, or is this the first recorded load of this script?
			if (chain_opts[_AllowDuplicates] || registry_items.length == 0) {
				registry_item = registry_items[registry_items.length] = {
					ready:false,
					finished:false,
					ready_listeners:[ready_cb],
					finished_listeners:[finished_cb]
				};

				request_script(chain_opts,script_obj,registry_item,
					// which callback type to pass?
					(
					 	(preload_this_script) ? // depends on script-preloading
						function(){
							registry_item.ready = true;
							for (var i=0; i<registry_item.ready_listeners.length; i++) {
								registry_item.ready_listeners[i]();
							}
							registry_item.ready_listeners = [];
						} :
						function(){ script_executed(registry_item); }
					),
					// signal if script-preloading should be used or not
					preload_this_script
				);
			}
			else {
				registry_item = registry_items[0];
				if (registry_item.finished) {
					finished_cb();
				}
				else {
					registry_item.finished_listeners.push(finished_cb);
				}
			}
		}


function(){
							registry_item.ready = true;
							for (var i=0; i<registry_item.ready_listeners.length; i++) {
								registry_item.ready_listeners[i]();
							}
							registry_item.ready_listeners = [];
						}

function ( ) { registry_item . ready = true ; for ( var i = 0 ; i < registry_item . ready_listeners . length ; i ++ ) { registry_item . ready_listeners [ i ] ( ) ; } registry_item . ready_listeners = [ ] ; }


function chain_script_ready(script_obj,exec_trigger) {
				if (chain_opts[_Debug]) log_msg("script preload finished: "+script_obj.real_src);
				script_obj.ready = true;
				script_obj.exec_trigger = function() {
					if (chain_opts[_Debug]) log_msg("script execute start: "+script_obj.real_src);
					exec_trigger();
				}
				advance_exec_cursor(); // will only check for 'ready' scripts to be executed
			}

called when a script has finished preloading


function chain_script_executed(script_obj,chain_group) {
				if (chain_opts[_Debug]) log_msg("script execution finished: "+script_obj.real_src);
				script_obj.ready = script_obj.finished = true;
				script_obj.exec_trigger = null;
				// check if chain group is all finished
				for (var i=0; i<chain_group.scripts.length; i++) {
					if (!chain_group.scripts[i].finished) return;
				}
				// chain_group is all finished if we get this far
				chain_group.finished = true;
				advance_exec_cursor();
			}

called when a script has finished executing


function advance_exec_cursor() {
				if (chain_is_corked) return;
				while (exec_cursor < chain.length) {
					if (is_func(chain[exec_cursor])) {
						if (chain_opts[_Debug]) log_msg("$LAB.wait() executing: "+chain[exec_cursor]);
						try { chain[exec_cursor++](); } catch (err) {
							if (chain_opts[_Debug]) log_error("$LAB.wait() error caught: ",err);
						}
						continue;
					}
					else if (!chain[exec_cursor].finished) {
						if (check_chain_group_scripts_ready(chain[exec_cursor])) continue;
						break;
					}
					exec_cursor++;
				}
				// we've reached the end of the chain (so far)
				if (exec_cursor == chain.length) {
					scripts_currently_loading = false;
					group = false;
				}
			}

main driver for executing each part of the chain


function init_script_chain_group() {
				if (!group || !group.scripts) {
					chain.push(group = {scripts:[],finished:true});
				}
			}

function init_script_chain_group ( ) { if ( ! group || ! group . scripts ) { chain . push ( group = { scripts : [ ] , finished : true } ) ; } }


function(){
					if (arguments.length > 0) {
						for (var i=0; i<arguments.length; i++) {
							chain.push(arguments[i]);
						}
						group = chain[chain.length-1];
					}
					else group = false;

					advance_exec_cursor();

					return chainedAPI;
				}

function ( ) { if ( arguments . length > 0 ) { for ( var i = 0 ; i < arguments . length ; i ++ ) { chain . push ( arguments [ i ] ) ; } group = chain [ chain . length - 1 ] ; } else group = false ; advance_exec_cursor ( ) ; return chainedAPI ; }

force LABjs to pause in execution at this point in the chain, until the execution thus far finishes, before proceeding

force LABjs to pause in execution at this point in the chain until the execution thus far finishes before proceeding


function build() {
  console.log('Creating an optimized production build...');
  webpack(config).run((err) => {
    if (err) {
      console.error('Failed to create a production build. Reason:');
      console.error(err.message || err);
      process.exit(1);
    }

    console.log(chalk.green('Compiled successfully.'));
    console.log(`The ${chalk.cyan('dist')} folder is ready to be deployed.`);
    console.log();
  });
}

Create the production build and print the deployment instructions.

Create the production build and print the deployment instructions .


function findLogPath(appName, fileName) {
  fileName = fileName || 'log.log';
  var userData = appName ? null : utils.getUserData();
  appName = appName || getAppName();

  var homeDir = os.homedir ? os.homedir() : process.env.HOME;

  var dir;
  switch (process.platform) {
    case 'darwin': {
      dir = prepareDir(homeDir, 'Library', 'Logs', appName)
        .or(userData)
        .or(homeDir, 'Library', 'Application Support', appName)
        .result;
      break;
    }

    case 'win32': {
      dir = prepareDir(userData)
        .or(process.env.APPDATA, appName)
        .or(homeDir, 'AppData', 'Roaming', appName)
        .result;
      break;
    }

    default: {
      dir = prepareDir(userData)
        .or(process.env.XDG_CONFIG_HOME, appName)
        .or(homeDir, '.config', appName)
        .or(process.env.XDG_DATA_HOME, appName)
        .or(homeDir, '.local', 'share', appName)
        .result;
      break;
    }
  }

  if (dir) {
    return path.join(dir, fileName);
  }

  return false;
}

function
findLogPath
(
appName
,
fileName
)
{
fileName
=
fileName
||
'log.log'
;
var
userData
=
appName
:
utils
.
getUserData
(
)
;
appName
=
appName
||
getAppName
(
)
;
var
homeDir
=
os
.
homedir
os
.
homedir
(
)
:
process
.
env
.
HOME
;
var
dir
;
switch
(
process
.
platform
)
{
case
'darwin'
:
{
dir
=
prepareDir
(
homeDir
,
'Library'
,
'Logs'
,
appName
)
.
or
(
userData
)
.
or
(
homeDir
,
'Library'
,
'Application Support'
,
appName
)
.
result
;
break
;
}
case
'win32'
:
{
dir
=
prepareDir
(
userData
)
.
or
(
process
.
env
.
APPDATA
,
appName
)
.
or
(
homeDir
,
'AppData'
,
'Roaming'
,
appName
)
.
result
;
break
;
}
default
:
{
dir
=
prepareDir
(
userData
)
.
or
(
process
.
env
.
XDG_CONFIG_HOME
,
appName
)
.
or
(
homeDir
,
'.config'
,
appName
)
.
or
(
process
.
env
.
XDG_DATA_HOME
,
appName
)
.
or
(
homeDir
,
'.local'
,
'share'
,
appName
)
.
result
;
break
;
}
}
if
(
dir
)
{
return
path
.
join
(
dir
,
fileName
)
;
}
return
false
;
}

Try to determine a platform-specific path where can write logs
@param {string} [appName] Used to determine the last part of a log path
@param {string} [fileName='log.log']
@return {string|boolean}

Try to determine a platform - specific path where can write logs


function format(msg, formatter, electronLog, removeStyles) {
  removeStyles = removeStyles !== undefined ? removeStyles : false;

  if (typeof formatter === 'function') {
    return formatter(msg, electronLog);
  }

  var date = new Date(msg.date || Date.now());
  var variables = msg.variables;
  var result = formatter;

  for (var i in variables) {
    if (!variables.hasOwnProperty(i)) continue;
    result = result.replace('{' + i + '}', variables[i]);
  }

  result = result
    .replace('{level}', msg.level)
    .replace('{text}', stringifyArray(msg.data))
    .replace('{y}', String(date.getFullYear()))
    .replace('{m}', pad(date.getMonth() + 1))
    .replace('{d}', pad(date.getDate()))
    .replace('{h}', pad(date.getHours()))
    .replace('{i}', pad(date.getMinutes()))
    .replace('{s}', pad(date.getSeconds()))
    .replace('{ms}', pad(date.getMilliseconds(), 3))
    .replace('{z}', formatTimeZone(date.getTimezoneOffset()));

  if (removeStyles) {
    result = result.replace(/%c/g, '');
  }

  return result;
}

function format ( msg , formatter , electronLog , removeStyles ) { removeStyles = removeStyles !== undefined ? removeStyles : false ; if ( typeof formatter === 'function' ) { return formatter ( msg , electronLog ) ; } var date = new Date ( msg . date || Date . now ( ) ) ; var variables = msg . variables ; var result = formatter ; for ( var i in variables ) { if ( ! variables . hasOwnProperty ( i ) ) continue ; result = result . replace ( '{' + i + '}' , variables [ i ] ) ; } result = result . replace ( '{level}' , msg . level ) . replace ( '{text}' , stringifyArray ( msg . data ) ) . replace ( '{y}' , String ( date . getFullYear ( ) ) ) . replace ( '{m}' , pad ( date . getMonth ( ) + 1 ) ) . replace ( '{d}' , pad ( date . getDate ( ) ) ) . replace ( '{h}' , pad ( date . getHours ( ) ) ) . replace ( '{i}' , pad ( date . getMinutes ( ) ) ) . replace ( '{s}' , pad ( date . getSeconds ( ) ) ) . replace ( '{ms}' , pad ( date . getMilliseconds ( ) , 3 ) ) . replace ( '{z}' , formatTimeZone ( date . getTimezoneOffset ( ) ) ) ; if ( removeStyles ) { result = result . replace ( / %c / g , '' ) ; } return result ; }

Transform Message object to a string
@param {object} msg
@param {string|function} formatter
@param {object} [electronLog]
@param {boolean} [removeStyles=false]
@return {string}


function loadPackageName() {
  var packageFile;

  try {
    if (require.main.filename) {
      packageFile = find(path.dirname(require.main.filename));
    }
  } catch (e) {
    packageFile = null;
  }

  if (!packageFile && process.resourcesPath) {
    packageFile = find(path.join(process.resourcesPath, 'app.asar'));
    var electronModule = path.join('node_modules', 'electron', 'package.json');
    if (packageFile && packageFile.indexOf(electronModule) !== -1) {
      packageFile = null;
    }
  }

  if (!packageFile) {
    packageFile = find(process.cwd());
  }

  if (!packageFile) {
    return null;
  }

  var content = fs.readFileSync(packageFile, 'utf-8');
  var packageData = JSON.parse(content);

  //noinspection JSUnresolvedVariable
  return packageData ? packageData.productName || packageData.name : false;
}

function
loadPackageName
(
)
{
var
packageFile
;
try
{
if
(
require
.
main
.
filename
)
{
packageFile
=
find
(
path
.
dirname
(
require
.
main
.
filename
)
)
;
}
}
catch
(
e
)
{
packageFile
=
;
}
if
(
!
packageFile
&&
process
.
resourcesPath
)
{
packageFile
=
find
(
path
.
join
(
process
.
resourcesPath
,
'app.asar'
)
)
;
var
electronModule
=
path
.
join
(
'node_modules'
,
'electron'
,
'package.json'
)
;
if
(
packageFile
&&
packageFile
.
indexOf
(
electronModule
)
!==
1
)
{
packageFile
=
;
}
}
if
(
!
packageFile
)
{
packageFile
=
find
(
process
.
cwd
(
)
)
;
}
if
(
!
packageFile
)
{
return
;
}
var
content
=
fs
.
readFileSync
(
packageFile
,
'utf-8'
)
;
var
packageData
=
JSON
.
parse
(
content
)
;
//noinspection JSUnresolvedVariable
return
packageData
packageData
.
productName
||
packageData
.
name
:
false
;
}

Try to load main app package
@throws {Error}
@return {Object|null}


function generateTypedocDocs(typedocDocsDir) {
  const publicApiConfigFile = path.resolve(__dirname, '../src/ng5-slider/lib/public_api.json');
  const publicApiConfig = JSON.parse(fs.readFileSync(publicApiConfigFile, { encoding: 'utf8' }));

  const files = publicApiConfig.exports
    .map(exportDef => path.resolve(__dirname, `../src/ng5-slider/lib/${exportDef.file}.ts`));

  const themeDir = path.resolve(__dirname, '../typedoc-theme');

  // HACK: When Typedoc finda a README.md file, it uses it to generate content for the index page of documentation
  // This is not very helpful, as it repeats the same stuff that's already shown on Github and NPM
  // So instead, replace the README.md with our own file
  const apiDocsReadmeFile = path.resolve(__dirname, '../typedoc-theme/README.md');
  utils.copyReadmeMd(apiDocsReadmeFile);

  const app = new typedoc.Application({
    module: 'commonjs',
    target: 'es6',
    includeDeclarations: false,
    experimentalDecorators: true,
    excludeExternals: true,
    theme: themeDir
  });

  app.generateDocs(files, typedocDocsDir);

  // HACK: restore the README.md to original
  const mainReadmeFile = path.resolve(__dirname, '../README.md');
  utils.copyReadmeMd(mainReadmeFile);
}

Run typedoc over library public API files to generate HTML files from customised typedoc theme
The resulting files are not really useful on their own; they will be used later to generate demo app code

Run typedoc over library public API files to generate HTML files from customised typedoc theme The resulting files are not really useful on their own ; they will be used later to generate demo app code