function createCampaign(callback, senderName, senderEmail, subject, body, bookId, name, attachments){
    if ((senderName===undefined)||(! senderName.length)||(senderEmail===undefined)||(! senderEmail.length)||(subject===undefined)||(! subject.length)||(body===undefined)||(! body.length)||(bookId===undefined)){
        return callback(returnError('Not all data.'));
    }
    if (name===undefined){
        name='';
    }
    if (attachments===undefined) {
        attachments='';
    }
    if (attachments.length){
        attachments = serialize(attachments);
    }
    var data = {
        sender_name: senderName,
        sender_email: senderEmail,
        //subject: encodeURIComponent(subject),
        //subject: urlencode(subject),
        subject: subject,
        body: base64(body),
        list_id: bookId,
        name: name,
        attachments: attachments
    }
    sendRequest( 'campaigns', 'POST', data, true, callback );
}

function
createCampaign
(
callback
,
senderName
,
senderEmail
,
subject
,
body
,
bookId
,
name
,
attachments
)
{
if
(
(
senderName
===
undefined
)
||
(
!
senderName
.
length
)
||
(
senderEmail
===
undefined
)
||
(
!
senderEmail
.
length
)
||
(
subject
===
undefined
)
||
(
!
subject
.
length
)
||
(
body
===
undefined
)
||
(
!
body
.
length
)
||
(
bookId
===
undefined
)
)
{
return
callback
(
returnError
(
'Not all data.'
)
)
;
}
if
(
name
===
undefined
)
{
name
=
''
;
}
if
(
attachments
===
undefined
)
{
attachments
=
''
;
}
if
(
attachments
.
length
)
{
attachments
=
serialize
(
attachments
)
;
}
var
data
=
{
sender_name
:
senderName
,
sender_email
:
senderEmail
,
//subject: encodeURIComponent(subject),
//subject: urlencode(subject),
subject
:
subject
,
body
:
base64
(
body
)
,
list_id
:
bookId
,
name
:
name
,
attachments
:
attachments
}
sendRequest
(
'campaigns'
,
'POST'
,
data
,
true
,
callback
)
;
}

Create new campaign

@param callback
@param senderName
@param senderEmail
@param subject
@param body
@param bookId
@param name
@param attachments


function addSender(callback, senderName, senderEmail){
    if ((senderEmail===undefined)||(!senderEmail.length)||(senderName===undefined)||(!senderName.length)) {
        return callback(returnError('Empty sender name or email'));
    }
    var data = {
        email: senderEmail,
        name: senderName
    }
    sendRequest( 'senders', 'POST', data, true, callback );
}

function
addSender
(
callback
,
senderName
,
senderEmail
)
{
if
(
(
senderEmail
===
undefined
)
||
(
!
senderEmail
.
length
)
||
(
senderName
===
undefined
)
||
(
!
senderName
.
length
)
)
{
return
callback
(
returnError
(
'Empty sender name or email'
)
)
;
}
var
data
=
{
email
:
senderEmail
,
name
:
senderName
}
sendRequest
(
'senders'
,
'POST'
,
data
,
true
,
callback
)
;
}

Add new sender

@param callback
@param senderName
@param senderEmail


function activateSender(callback, senderEmail, code){
    if ((senderEmail===undefined)||(!senderEmail.length)||(code===undefined)||(!code.length)){
        return callback(returnError('Empty email or activation code'));
    }
    var data = {
        code: code
    }
    sendRequest( 'senders/' + senderEmail + '/code', 'POST', data, true, callback );
}

function
activateSender
(
callback
,
senderEmail
,
code
)
{
if
(
(
senderEmail
===
undefined
)
||
(
!
senderEmail
.
length
)
||
(
code
===
undefined
)
||
(
!
code
.
length
)
)
{
return
callback
(
returnError
(
'Empty email or activation code'
)
)
;
}
var
data
=
{
code
:
code
}
sendRequest
(
'senders/'
+
senderEmail
+
'/code'
,
'POST'
,
data
,
true
,
callback
)
;
}

Activate sender using code

@param callback
@param senderEmail
@param code


function getSenderActivationMail(callback, senderEmail ) {
    if ((senderEmail===undefined)||(!senderEmail.length)){
        return callback(returnError('Empty email'));
    }
    sendRequest( 'senders/' + senderEmail + '/code', 'GET', {}, true, callback );
}

function
getSenderActivationMail
(
callback
,
senderEmail
)
{
if
(
(
senderEmail
===
undefined
)
||
(
!
senderEmail
.
length
)
)
{
return
callback
(
returnError
(
'Empty email'
)
)
;
}
sendRequest
(
'senders/'
+
senderEmail
+
'/code'
,
'GET'
,
{
}
,
true
,
callback
)
;
}

Request mail with activation code

@param callback
@param senderEmail


function getEmailGlobalInfo(callback, email) {
    if ((email===undefined)||(!email.length)){
        return callback(returnError('Empty email'));
    }
    sendRequest( 'emails/' + email, 'GET', {}, true, callback );
}

function
getEmailGlobalInfo
(
callback
,
email
)
{
if
(
(
email
===
undefined
)
||
(
!
email
.
length
)
)
{
return
callback
(
returnError
(
'Empty email'
)
)
;
}
sendRequest
(
'emails/'
+
email
,
'GET'
,
{
}
,
true
,
callback
)
;
}

Get global information about email

@param callback
@param email


function removeEmailFromAllBooks(callback, email){
    if ((email===undefined)||(!email.length)){
        return callback(returnError('Empty email'));
    }
    sendRequest( 'emails/' + email, 'DELETE', {}, true, callback );
}

function
removeEmailFromAllBooks
(
callback
,
email
)
{
if
(
(
email
===
undefined
)
||
(
!
email
.
length
)
)
{
return
callback
(
returnError
(
'Empty email'
)
)
;
}
sendRequest
(
'emails/'
+
email
,
'DELETE'
,
{
}
,
true
,
callback
)
;
}

Remove email from all books

@param callback
@param email


function emailStatByCampaigns(callback,email) {
    if ((email===undefined)||(!email.length)){
        return callback(returnError('Empty email'));
    }
    sendRequest( 'emails/' + email + '/campaigns', 'GET', {}, true, callback );
}

function
emailStatByCampaigns
(
callback
,
email
)
{
if
(
(
email
===
undefined
)
||
(
!
email
.
length
)
)
{
return
callback
(
returnError
(
'Empty email'
)
)
;
}
sendRequest
(
'emails/'
+
email
+
'/campaigns'
,
'GET'
,
{
}
,
true
,
callback
)
;
}

Get email statistic by all campaigns

@param callback
@param email


function addToBlackList(callback, emails, comment){
    if ((emails===undefined)||(!emails.length)){
        return callback(returnError('Empty email'));
    }
    if (comment === undefined) {
        comment = '';
    }
    var data = {
        emails: base64(emails),
        comment: comment
    }
    sendRequest( 'blacklist', 'POST', data, true, callback );
}

function
addToBlackList
(
callback
,
emails
,
comment
)
{
if
(
(
emails
===
undefined
)
||
(
!
emails
.
length
)
)
{
return
callback
(
returnError
(
'Empty email'
)
)
;
}
if
(
comment
===
undefined
)
{
comment
=
''
;
}
var
data
=
{
emails
:
base64
(
emails
)
,
comment
:
comment
}
sendRequest
(
'blacklist'
,
'POST'
,
data
,
true
,
callback
)
;
}

Add email to blacklist

@param callback
@param emails
@param comment


function removeFromBlackList(callback, emails){
    if ((emails===undefined)||(!emails.length)){
        return callback(returnError('Empty emails'));
    }
    var data = {
        emails: base64(emails),
    }
    sendRequest( 'blacklist', 'DELETE', data, true, callback );
}

function
removeFromBlackList
(
callback
,
emails
)
{
if
(
(
emails
===
undefined
)
||
(
!
emails
.
length
)
)
{
return
callback
(
returnError
(
'Empty emails'
)
)
;
}
var
data
=
{
emails
:
base64
(
emails
)
,
}
sendRequest
(
'blacklist'
,
'DELETE'
,
data
,
true
,
callback
)
;
}

Remove emails from blacklist

@param callback
@param emails


function smtpGetEmailInfoById(callback,id){
    if ((id===undefined)||(! id.length)) {
        return callback(returnError('Empty id'));
    }
    sendRequest( 'smtp/emails/' + id, 'GET', {}, true, callback );
}

function
smtpGetEmailInfoById
(
callback
,
id
)
{
if
(
(
id
===
undefined
)
||
(
!
id
.
length
)
)
{
return
callback
(
returnError
(
'Empty id'
)
)
;
}
sendRequest
(
'smtp/emails/'
+
id
,
'GET'
,
{
}
,
true
,
callback
)
;
}

Get information about email by id

@param callback
@param id


function minifyFile(resHtml, outputPath) {
	var resHtml = minify(resHtml, opt, function (err) {
		if (err) {
			console.error('error will processing file.');
		}
	});

	console.log('');
	console.log('Output file name : ' + outputPath);
	console.log('');
	writeFile(resHtml, outputPath);
}

function
minifyFile
(
resHtml
,
outputPath
)
{
var
resHtml
=
minify
(
resHtml
,
opt
,
function
(
err
)
{
if
(
err
)
{
console
.
error
(
'error will processing file.'
)
;
}
}
)
;
console
.
log
(
''
)
;
console
.
log
(
'Output file name : '
+
outputPath
)
;
console
.
log
(
''
)
;
writeFile
(
resHtml
,
outputPath
)
;
}


function writeFile(resHtml, outputPath) {
	fs.writeFile(outputPath, resHtml, function (err) {
		if (err) {
			console.log('');
			console.log('File error: ' + err + '. Exit.');
		} else {
			console.log('');
			console.log('All done. Exit.'.green);
		}
	});
}

function
writeFile
(
resHtml
,
outputPath
)
{
fs
.
writeFile
(
outputPath
,
resHtml
,
function
(
err
)
{
if
(
err
)
{
console
.
log
(
''
)
;
console
.
log
(
'File error: '
+
err
+
'. Exit.'
)
;
}
else
{
console
.
log
(
''
)
;
console
.
log
(
'All done. Exit.'
.
green
)
;
}
}
)
;
}


function Cookie(options) {
  this.options = options || {};
  this.options.expires =
    typeof this.options.expires === 'number' ? this.options.expires : 30;
  this.options.path =
    this.options.path !== undefined ? this.options.path : '/';
  this.options.secure = typeof this.options.secure === 'boolean'
    ? this.options.secure : false;
}

function Cookie ( options ) { this . options = options || { } ; this . options . expires = typeof this . options . expires === 'number' ? this . options . expires : 30 ; this . options . path = this . options . path !== undefined ? this . options . path : '/' ; this . options . secure = typeof this . options . secure === 'boolean' ? this . options . secure : false ; }

Create a cookie instance.

@param options.raw Do not URI encode the cookie value.
@param options.json Store the cookie value as JSON.
@param options.expires Define lifetime of the cookie in days, default is 30.
@param options.path Define the path where the cookie is valid, default is /.
@param options.domain Define the domain where the cookie is valid.
@param options.secure If true, the cookie transmission requires a
secure protocol (https).


function set(key, value, options) {
  options = options || this.options;
  var days = parseInt(options.expires || -1);
  if(value !== undefined && typeof value !== 'function') {
    var t = new Date();
    t.setDate((t.getDate() + days));
    var res = (document.cookie = [
      this.encode(key), '=', this.stringify(value),
      // use expires attribute, max-age is not supported by IE
      options.expires ? '; expires=' + t.toUTCString() : '',
      options.path ? '; path=' + options.path : '',
      options.domain ? '; domain=' + options.domain : '',
      options.secure ? '; secure' : ''
    ].join(''));
    return res;
  }
}

Set a cookie value.

@param key The cookie key name.
@param value The value for the cookie.
@param options Options to use when setting the cookie.


function get(key, value) {
  var i, parts, name, cookie;
  var result = key ? undefined : {};
  /* istanbul ignore next */
  var cookies = (document.cookie || '').split('; ');
  for (i = 0; i < cookies.length; i++) {
    parts = cookies[i].split('=');
    name = this.decode(parts.shift());
    cookie = parts.join('=');
    if (key && key === name) {
      // if second argument (value) is a function it's a converter
      result = this.read(cookie, value);
      break;
    }
    // prevent storing a cookie that we couldn't decode
    if (!key && (cookie = this.read(cookie)) !== undefined) {
      result[name] = cookie;
    }
  }
  return result;
}

Get a cookie value.

@param key The cookie key name.
@param value A converter function used when reading the cookie value.


function del(key, options) {
  if(!options) {
    options = {};
    for(var z in this.options) {
      options[z] = this.options[z];
    }
  }
  options.expires = -1;
  this.set(key, '', options);
}

function del ( key , options ) { if ( ! options ) { options = { } ; for ( var z in this . options ) { options [ z ] = this . options [ z ] ; } } options . expires = - 1 ; this . set ( key , '' , options ) ; }

Delete a cookie value.

@param key The cookie key name.


function clear(except, options) {
  var keys = this.get(), z;
  except = except || [];
  for(z in keys) {
    if(~except.indexOf(z)) {
      continue;
    }
    this.del(z, options);
  }
}

function clear ( except , options ) { var keys = this . get ( ) , z ; except = except || [ ] ; for ( z in keys ) { if ( ~ except . indexOf ( z ) ) { continue ; } this . del ( z , options ) ; } }

Clear all stored cookies, optionally keeping the
keys in the except array.

@param except Array of keys that should not be deleted.
@param options The cookie options.

Clear all stored cookies optionally keeping the keys in the except array .


function curry2 (fn, self) {
  var out = function () {
    if (arguments.length === 0) return out

    return arguments.length > 1
      ? fn.apply(self, arguments)
      : bind.call(fn, self, arguments[0])
  }

  out.uncurry = function uncurry () {
    return fn
  }

  return out
}

function curry2 ( fn , self ) { var out = function ( ) { if ( arguments . length === 0 ) return out return arguments . length > 1 ? fn . apply ( self , arguments ) : bind . call ( fn , self , arguments [ 0 ] ) } out . uncurry = function uncurry ( ) { return fn } return out }

Curry a binary function.

@param {Function} fn
Binary function to curry.

@param {Object} [self]
Function `this` context.

@return {Function|*}
If partially applied, return unary function, otherwise, return result of full application.


function cloneGalleryItem(inst, element) {

    // Clone the element
    const clone = element.cloneNode(true)

    // Remove id attribute to avoid unwanted duplicates
    clone.removeAttribute('id')

    // Add a helper class
    clone.classList.add('mh-gallery-item--sort-helper')

    return clone
}

Clone behaviour for gallery items used when creating a helper for the
purpose of sorting.

Clone behaviour for gallery items used when creating a helper for the purpose of sorting .


function (localFilePath) {
                let contentType = mime.lookup(localFilePath);
                let standerFilePath = localFilePath.replace(/\\/g, '/');
                fs.readFile(localFilePath, function (readFileErr, fileData) {
                    if (readFileErr) {
                        throw readFileErr;
                    }
                    const putConfig = {
                        Bucket: bucket.Name,
                        Body: fileData,
                        Key: standerFilePath,
                        ContentType: contentType,
                        AccessControlAllowOrigin: options.AccessControlAllowOrigin || '*',
                        CacheControl: options.CacheControl || 'no-cache',
                        Expires: options.Expires || null
                    };
                    if (options.contentEncoding) {
                        putConfig.ContentEncoding = options.contentEncoding;
                    }
                    oss.putObject(putConfig, function (putObjectErr) {
                        if (putObjectErr) {
                            console.error('error:', putObjectErr);
                            return putObjectErr;
                        }
                        console.log('upload success: ' + localFilePath);
                        if (bucketPaths.indexOf(standerFilePath) === -1) {
                            bucketPaths.push(standerFilePath);
                        }
                        if (localPaths.indexOf(standerFilePath) === -1) {
                            localPaths.push(standerFilePath);
                        }
                        //refresh cdn
                        if (options.oss.autoRefreshCDN && cdn) {
                            if (options.cdn.refreshQuota < 1) {
                                console.error('There is no refresh cdn url quota today.');
                                return;
                            }
                            let cdnDomain = '';
                            if (/^http/.test(options.cdn.domain)) {
                                cdnDomain = options.cdn.domain.replace(/^https?:?\/?\/?/, '');
                                options.cdn.secure === undefined && (options.cdn.secure = /^https/.test(options.cdn.domein));
                            }
                            else {
                                cdnDomain = options.cdn.domain;
                            }
                            let cdnObjectPath = url.format({
                                protocol: options.oss.secure ? 'https' : 'http',
                                hostname: cdnDomain,
                                pathname: standerFilePath
                            });
                            options.debug && console.log('Refreshing CDN file: ', cdnObjectPath);
                            cdn.refreshObjectCaches({
                                ObjectType: 'File',
                                ObjectPath: cdnObjectPath
                            }, function (refreshCDNErr) {
                                if (refreshCDNErr) {
                                    console.error('refresh cdn error: ', refreshCDNErr);
                                }
                                else {
                                    options.cdn.refreshQuota--;
                                    console.log('Refresh cdn file success: ', cdnObjectPath);
                                }
                            });
                        }
                    });
                });
            }


function (filePath) {
                let standerPath = filePath.replace(/\\/g, '/');
                oss.deleteObject({
                    Bucket: bucket.Name,
                    Key: standerPath
                }, function (err) {
                    if (err) {
                        console.log('error:', err);
                        return err;
                    }
                    let bucketIndex = bucketPaths.indexOf(standerPath);
                    if (bucketIndex !== -1) {
                        bucketPaths.splice(bucketIndex, 1);
                    }
                    let localIndex = localPaths.indexOf(standerPath);
                    if (localIndex !== -1) {
                        localPaths.splice(localIndex, 1);
                    }
                    console.log('delete success:' + standerPath);
                });
            }

function
(
filePath
)
{
let
standerPath
=
filePath
.
replace
(
/
\\
/
g
,
'/'
)
;
oss
.
deleteObject
(
{
Bucket
:
bucket
.
Name
,
Key
:
standerPath
}
,
function
(
err
)
{
if
(
err
)
{
console
.
log
(
'error:'
,
err
)
;
return
err
;
}
let
bucketIndex
=
bucketPaths
.
indexOf
(
standerPath
)
;
if
(
bucketIndex
!==
1
)
{
bucketPaths
.
splice
(
bucketIndex
,
1
)
;
}
let
localIndex
=
localPaths
.
indexOf
(
standerPath
)
;
if
(
localIndex
!==
1
)
{
localPaths
.
splice
(
localIndex
,
1
)
;
}
console
.
log
(
'delete success:'
+
standerPath
)
;
}
)
;
}


function setupDispatch ({ actions: actionHandlers = {}, schemas = {}, services = {}, middlewares = [], identOptions = {} }) {
  const getService = setupGetService(schemas, services)

  let dispatch = async (action) => {
    debug('Dispatch: %o', action)
    return handleAction(
      action,
      {
        schemas,
        services,
        dispatch,
        identOptions,
        getService
      },
      actionHandlers
    )
  }

  if (middlewares.length > 0) {
    dispatch = compose(...middlewares)(dispatch)
  }

  return dispatch
}

function
setupDispatch
(
{
actions
:
actionHandlers
=
{
}
,
schemas
=
{
}
,
services
=
{
}
,
middlewares
=
[
]
,
identOptions
=
{
}
}
)
{
const
getService
=
setupGetService
(
schemas
,
services
)
let
dispatch
=
async
(
action
)
=>
{
debug
(
'Dispatch: %o'
,
action
)
return
handleAction
(
action
,
{
schemas
,
services
,
dispatch
,
identOptions
,
getService
}
,
actionHandlers
)
}
if
(
middlewares
.
length
>
0
)
{
dispatch
=
compose
(
...
middlewares
)
(
dispatch
)
}
return
dispatch
}

Setup and return dispatch function. The dispatch function will call the
relevant action handler.
@param {Object} resources - Object with actions, schemas, services, and middlewares
@returns {function} Dispatch function, accepting an action as only argument

Setup and return dispatch function . The dispatch function will call the relevant action handler .


function nextSchedule (schedule, allowNow = false) {
  if (schedule) {
    try {
      const dates = later.schedule(schedule).next(2)
      return nextDate(dates, allowNow)
    } catch (error) {
      throw TypeError('Invalid schedule definition')
    }
  }
  return null
}

function
nextSchedule
(
schedule
,
allowNow
=
false
)
{
if
(
schedule
)
{
try
{
const
dates
=
later
.
schedule
(
schedule
)
.
next
(
2
)
return
nextDate
(
dates
,
allowNow
)
}
catch
(
error
)
{
throw
TypeError
(
'Invalid schedule definition'
)
}
}
return
}

Get next time for a schedule. Will never return the current time, even if it
is valid for the schedule, unless `allowNow` is true.
@param {Object} schedule - The schedule
@param {boolean} allowNow - True to allow now as next Date
@returns {Date} The next Date

Get next time for a schedule . Will never return the current time even if it is valid for the schedule unless allowNow is true .


async function deleteFn (action, { getService } = {}) {
  debug('Action: DELETE')
  const { type, id, service: serviceId, endpoint } = action.payload

  const service = (typeof getService === 'function') ? getService(type, serviceId) : null
  if (!service) {
    return createUnknownServiceError(type, serviceId, 'DELETE')
  }

  const data = prepareData(action.payload)
  if (data.length === 0) {
    return createError(`No items to delete from service '${service.id}'`, 'noaction')
  }

  const endpointDebug = (endpoint) ? `endpoint '${endpoint}'` : `endpoint matching ${type} and ${id}`
  debug('DELETE: Delete from service \'%s\' at %s.', service.id, endpointDebug)

  const { response } = await service.send(appendToAction(action, { data }))

  return (response.status === 'ok') ? { status: 'ok' } : response
}

Delete several items from a service, based on the given payload.
@param {Object} payload - Payload from action object
@param {Object} resources - Object with getService
@returns {Object} Response object with any data returned from the service

Delete several items from a service based on the given payload .


async function request (action, { getService, dispatch }) {
  debug('Action: REQUEST')

  const {
    type,
    service: serviceId = null,
    endpoint
  } = action.payload

  const service = getService(type, serviceId)
  if (!service) {
    return createUnknownServiceError(type, serviceId, 'GET')
  }

  const endpointDebug = (endpoint) ? `endpoint '${endpoint}'` : `endpoint matching type '${type}'`
  debug('REQUEST: Fetch from service %s at %s', service.id, endpointDebug)

  const { response } = await service.receive(action, dispatch)

  return response
}

async
function
request
(
action
,
{
getService
,
dispatch
}
)
{
debug
(
'Action: REQUEST'
)
const
{
type
,
service
:
serviceId
=
,
endpoint
}
=
action
.
payload
const
service
=
getService
(
type
,
serviceId
)
if
(
!
service
)
{
return
createUnknownServiceError
(
type
,
serviceId
,
'GET'
)
}
const
endpointDebug
=
(
endpoint
)
`
${
endpoint
}
`
:
`
${
type
}
`
debug
(
'REQUEST: Fetch from service %s at %s'
,
service
.
id
,
endpointDebug
)
const
{
response
}
=
await
service
.
receive
(
action
,
dispatch
)
return
response
}

Normalize and map a request to an action, and map and serialize its response.
@param {Object} action - The action object
@param {Object} resources - Object with getService and dispatch
@returns {Object} Response object

Normalize and map a request to an action and map and serialize its response .


async function getIdent ({ payload, meta }, { getService, identOptions = {} }) {
  if (!meta.ident) {
    return createError('GET_IDENT: The request has no ident', 'noaction')
  }

  const { type } = identOptions
  if (!type) {
    return createError('GET_IDENT: Integreat is not set up with authentication', 'noaction')
  }

  const service = getService(type)
  if (!service) {
    return createUnknownServiceError(type, null, 'GET_IDENT')
  }

  const propKeys = preparePropKeys(identOptions.props)
  const params = prepareParams(meta.ident, propKeys)
  if (!params) {
    return createError('GET_IDENT: The request has no ident with id or withToken', 'noaction')
  }

  const { response } = await service.send({
    type: 'GET',
    payload: { type, ...params },
    meta: { ident: { root: true } }
  })

  return prepareResponse(response, payload, propKeys)
}

Get an ident item from service, based on the meta.ident object on the action.
@param {Object} action - Action object
@param {Object} resources - Object with getService and identOptions
@returns {Object} Response object with ident item as data

Get an ident item from service based on the meta . ident object on the action .


function integreat (
  {
    schemas: typeDefs,
    services: serviceDefs,
    mappings = [],
    auths: authDefs = [],
    ident: identOptions = {}
  },
  {
    adapters = {},
    authenticators = {},
    filters = {},
    transformers = {},
    actions = {}
  } = {},
  middlewares = []
) {
  if (!serviceDefs || !typeDefs) {
    throw new TypeError('Call integreat with at least services and schemas')
  }

  // Merge custom actions with built-in actions
  actions = { ...builtinActions, ...actions }

  // Setup schemas object from type defs
  const schemas = R.compose(
    R.indexBy(R.prop('id')),
    R.map(schema)
  )(typeDefs)

  const pluralTypes = Object.keys(schemas)
    .reduce((plurals, type) => ({ ...plurals, [schemas[type].plural]: type }), {})

  // Setup auths object from auth defs
  const auths = authDefs
    .reduce((auths, def) => (def)
      ? {
        ...auths,
        [def.id]: {
          authenticator: authenticators[def && def.authenticator],
          options: def.options,
          authentication: null
        }
      }
      : auths,
    {})

  // Setup services object from service defs.
  const services = R.compose(
    R.indexBy(R.prop('id')),
    R.map(createService({
      adapters,
      auths,
      transformers,
      schemas,
      setupMapping: setupMapping({ filters, transformers, schemas, mappings })
    }))
  )(serviceDefs)

  // Return Integreat instance
  return {
    version,
    schemas,
    services,
    identType: identOptions.type,

    /**
     * Function for dispatching actions to Integreat. Will be run through the
     * chain of middlewares before the relevant action handler is called.
     * @param {Object} action - The action to dispatch
     * @returns {Promise} Promise of result object
     */
    dispatch: setupDispatch({
      actions,
      services,
      schemas,
      middlewares,
      identOptions
    }),

    /**
     * Adds the `listener` function to the service's emitter for events with the
     * given `eventName` name.
     */
    on (eventName, serviceId, listener) {
      const service = services[serviceId]
      if (service && service.on) {
        service.on(eventName, listener)
      }
    },

    /**
     * Return schema type from its plural form.
     */
    typeFromPlural (plural) {
      return pluralTypes[plural]
    }
  }
}

Return an Integreat instance with a dispatch method.
Use the dispatch method for sending actions to services, for retrieving typed
items and updating data.
@param {Object} defs - Services, schemas, mappings, and auths
@param {Object} resources - Object with adapters, authenticators, filters, transformers, and actions
@param {Array} middlewares - Array of middlewares
@returns {Object} Integration object with the dispatch method

Return an Integreat instance with a dispatch method . Use the dispatch method for sending actions to services for retrieving typed items and updating data .


function scheduleToAction (def) {
  if (!def) {
    return null
  }

  const id = def.id || null
  const schedule = parseSchedule(def.schedule)
  const nextTime = nextSchedule(schedule, true)

  return {
    ...def.action,
    meta: {
      id,
      schedule,
      queue: (nextTime) ? nextTime.getTime() : true
    }
  }
}

function scheduleToAction ( def ) { if ( ! def ) { return null } const id = def . id || null const schedule = parseSchedule ( def . schedule ) const nextTime = nextSchedule ( schedule , true ) return { ... def . action , meta : { id , schedule , queue : ( nextTime ) ? nextTime . getTime ( ) : true } } }

Create a queuable action from a schedule definition.
@param {Object} def - A schedule definition
@returns {object} An action object

Create a queuable action from a schedule definition .


async function get (action, { getService } = {}) {
  const {
    type,
    service: serviceId = null,
    onlyMappedValues = false,
    endpoint
  } = action.payload

  const service = (typeof getService === 'function')
    ? getService(type, serviceId) : null
  if (!service) {
    return createUnknownServiceError(type, serviceId, 'GET')
  }

  const id = getIdFromPayload(action.payload)

  // Do individual gets for array of ids, if there is no collection scoped endpoint
  if (Array.isArray(id) && !hasCollectionEndpoint(service.endpoints)) {
    return getIndividualItems(id, action, getService)
  }

  const endpointDebug = (endpoint) ? `endpoint '${endpoint}'` : `endpoint matching type '${type}' and id '${id}'`
  debug('GET: Fetch from service %s at %s', service.id, endpointDebug)

  const { response } = await service.send(appendToAction(action, { id, onlyMappedValues }))

  return response
}

Get several items from a service, based on the given action object.
@param {Object} action - payload and ident from the action object
@param {Object} resources - Object with getService
@returns {array} Array of data from the service

Get several items from a service based on the given action object .


function sendRequest ({ adapter, serviceId }) {
  return async ({ request, response, connection }) => {
    if (response) {
      return response
    }

    try {
      response = await adapter.send(request, connection)
      return { ...response, access: request.access }
    } catch (error) {
      return createError(`Error retrieving from service '${serviceId}'. ${error}`)
    }
  }
}

function sendRequest ( { adapter , serviceId } ) { return async ( { request , response , connection } ) => { if ( response ) { return response } try { response = await adapter . send ( request , connection ) return { ... response , access : request . access } } catch ( error ) { return createError ( ` ${ serviceId } ${ error } ` ) } } }

Send the request with the adapter and return the response. Will serialize any
data in the request, and normalize any data in the response. The access
object on the request must have status granted, and will be returned on the
response object.

@param {Object} request - The request object
@param {Object} options - adapter and serviceId
@returns {Object} The normalized response object

Send the request with the adapter and return the response . Will serialize any data in the request and normalize any data in the response . The access object on the request must have status granted and will be returned on the response object .


function schema ({
  id,
  plural,
  service,
  attributes: attrDefs,
  relationships: relDefs,
  access,
  internal = false
}) {
  const attributes = {
    ...expandFields(attrDefs || {}),
    id: { type: 'string' },
    type: { type: 'string' },
    createdAt: { type: 'date' },
    updatedAt: { type: 'date' }
  }
  const relationships = expandFields(relDefs || {})

  const defaultAttrs = prepareDefaultAttrs(attributes, attrDefs)
  const defaultRels = prepareDefaultRels(relationships, relDefs)

  const castFn = cast({ id, attributes, relationships, defaultAttrs, defaultRels })

  return {
    id,
    plural: plural || `${id}s`,
    service,
    internal,
    attributes,
    relationships,
    access,

    /**
     * Will cast the given data according to the type. Attributes will be
     * coerced to the right format, relationships will be expanded to
     * relationship objects, and object properties will be moved from
     * `attributes` or be set with defaults.
     * @param {Object} data - The data to cast
     * @param {boolean} onlyMappedValues - Will use defaults if true
     * @returns {Object} Returned data in the format expected from the schema
     */
    cast (data, { onlyMappedValues = false } = {}) {
      return mapAny((data) => castFn(data, { onlyMappedValues }), data)
    },

    /**
     * Will create a query object for a relationship, given the relationship id
     * and a data item to get field values from.
     *
     * If the relationship is set up with a query definition object, each prop
     * of this object references field ids in the given data item. The returned
     * query object will have these ids replaced with actual field values.
     *
     * @param {string} relId - The id of a relationship
     * @param {Object} data - A data item to get field values from.
     * @returns {Object} Query object
     */
    castQueryParams (relId, data) {
      return castQueryParams(relId, data, { relationships })
    }
  }
}

Create a schema with the given id and service.
@param {Object} def - Object with id, plural, service, attributes, and relationships
@returns {Object} The created schema

Create a schema with the given id and service .


function mapping ({
  filters,
  transformers,
  schemas = {},
  mappings: mappingsArr = []
} = {}) {
  const mappings = mappingsArr.reduce(
    (mappings, def) => ({ ...mappings, [def.id]: def }),
    {}
  )
  const createPipelineFn = createPipeline(filters, transformers, schemas, mappings)

  return (mapping, overrideType) => {
    const { id, type, schema, pipeline } = createPipelineFn(mapping, overrideType)
    if (!pipeline) {
      return null
    }

    const mapper = mapTransform([
      fwd('data'),
      ...pipeline,
      rev(set('data'))
    ])

    return {
      id,
      type,
      schema,

      /**
       * Map data from a service with attributes and relationships.
       * @param {Object} data - The service item to map from
       * @param {Object} options - onlyMappedValues
       * @returns {Object} Target item
       */
      fromService (data, { onlyMappedValues = true } = {}) {
        return data
          ? ensureArray(
            (onlyMappedValues) ? mapper.onlyMappedValues(data) : mapper(data)
          )
          : []
      },

      /**
       * Map data to a service with attributes and relationships.
       * @param {Object} data - The data item to map
       * @param {Object} target - Optional object to map to data on
       * @returns {Object} Mapped data
       */
      toService (data, target = null) {
        const mapped = mapper.rev.onlyMappedValues(data)
        return (
          (target
            ? Array.isArray(target)
              ? [...target].concat(mapped)
              : mergeDeepWith(concatOrRight, target, mapped)
            : mapped) || null
        )
      }
    }
  }
}

Return item mapper object with fromService and toService.
@param {Object} resources - filters, transformers, and schemas
@returns {Object} Item mapping def

Return item mapper object with fromService and toService .


function mapFromService () {
  return ({ response, request, responseMapper, mappings }) => {
    if (response.status !== 'ok') {
      return response
    }

    const type = request.params.type || Object.keys(mappings)
    const { onlyMappedValues, unmapped = false } = request.params

    if (unmapped) {
      return response
    }

    const { data, status = response.status, error, paging, params } =
      mapWithEndpoint(responseMapper, response, request.action)

    if (status !== 'ok') {
      return removeDataProp({ ...response, status, error })
    }

    const mapType = (type) => (mappings[type])
      ? mappings[type].fromService({ ...request, data }, { onlyMappedValues })
      : []

    return {
      ...response,
      status,
      ...((paging) ? { paging } : {}),
      ...((params) ? { params } : {}),
      data: (data) ? flatten(mapAny(mapType, type)) : undefined
    }
  }
}

function mapFromService ( ) { return ( { response , request , responseMapper , mappings } ) => { if ( response . status !== 'ok' ) { return response } const type = request . params . type || Object . keys ( mappings ) const { onlyMappedValues , unmapped = false } = request . params if ( unmapped ) { return response } const { data , status = response . status , error , paging , params } = mapWithEndpoint ( responseMapper , response , request . action ) if ( status !== 'ok' ) { return removeDataProp ( { ... response , status , error } ) } const mapType = ( type ) => ( mappings [ type ] ) ? mappings [ type ] . fromService ( { ... request , data } , { onlyMappedValues } ) : [ ] return { ... response , status , ... ( ( paging ) ? { paging } : { } ) , ... ( ( params ) ? { params } : { } ) , data : ( data ) ? flatten ( mapAny ( mapType , type ) ) : undefined } } }

Map the data going _to_ the service. Everything is handled by the mappings,
but this method make sure that the right types are mapped.

@param {Object} data - The data to map
@param {Object} options - mappings, params, onlyMappedValues, and endpoint
@returns {Object[]} Array of mapped items

Map the data going _to_ the service . Everything is handled by the mappings but this method make sure that the right types are mapped .


function(tailInfo){
    var z = this;
    if(tailInfo) {
      z.q.push(tailInfo);
    }

    var ti;
    //for all changed fds fire readStream
    for(var i = 0;i < z.q.length;++i) {
      ti = z.q[i];

      if(ti.reading) {
        //still reading file
        continue;
      }

      if (!z.tails[ti.stat.ino]) {
        //remove timed out file tail from q
        z.q.splice(i,1);
        --i;
        continue;
      }

      //truncated
      if(ti.stat.size < ti.pos) {
        ti.pos = 0;
      }

      var len = ti.stat.size-ti.pos;
      //remove from queue because im doing this work.
      z.q.splice(i,1);
      --i;

      z.readTail(ti,len);
    }
  }

this emits the data events on the watcher emitter for all fds


function(){
    var z = this;
    var l = 0;
    Object.keys(z.tails).forEach(function(k) {
      l += (z.tails[k].buf||'').length;
    });
    return l;
  }

function ( ) { var z = this ; var l = 0 ; Object . keys ( z . tails ) . forEach ( function ( k ) { l += ( z . tails [ k ] . buf || '' ) . length ; } ) ; return l ; }

return the total line buffer length from all active tails


function preparePipeline (pipeline, collection = {}) {
  pipeline = [].concat(pipeline)

  const replaceWithFunction = (key) => (typeof key === 'string') ? collection[key] : key
  const isFunctionOrObject = (obj) => obj && ['function', 'object'].includes(typeof obj)

  return pipeline
    .map(replaceWithFunction)
    .filter(isFunctionOrObject)
}

function preparePipeline ( pipeline , collection = { } ) { pipeline = [ ] . concat ( pipeline ) const replaceWithFunction = ( key ) => ( typeof key === 'string' ) ? collection [ key ] : key const isFunctionOrObject = ( obj ) => obj && [ 'function' , 'object' ] . includes ( typeof obj ) return pipeline . map ( replaceWithFunction ) . filter ( isFunctionOrObject ) }

Prepare pipeline by replacing keys with functions or function objects from
the collection object, and remove anything that is not functions or function
objects.
@param {array} pipeline - The pipeline definition
@param {Object} collection - Object with pipeline functions
@returns {array} Prepared pipeline

Prepare pipeline by replacing keys with functions or function objects from the collection object and remove anything that is not functions or function objects .


function castQueryParams (relId, data, { relationships }) {
  const relationship = relationships[relId]

  if (!relationship.query) {
    return {}
  }

  return Object.keys(relationship.query)
    .reduce((params, key) => {
      const value = getField(data, relationship.query[key])
      if (value === undefined) {
        throw new TypeError('Missing value for query param')
      }
      return { ...params, [key]: value }
    }, {})
}

function
castQueryParams
(
relId
,
data
,
{
relationships
}
)
{
const
relationship
=
relationships
[
relId
]
if
(
!
relationship
.
query
)
{
return
{
}
}
return
Object
.
keys
(
relationship
.
query
)
.
reduce
(
(
params
,
key
)
=>
{
const
value
=
getField
(
data
,
relationship
.
query
[
key
]
)
if
(
value
===
undefined
)
{
throw
new
TypeError
(
'Missing value for query param'
)
}
return
{
...
params
,
[
key
]
:
value
}
}
,
{
}
)
}


function setupQueue (queue) {
  let dispatch = null
  let subscribed = false

  return {
    queue,

    /**
     * Set dispatch function to use for dequeuing
     */
    setDispatch (dispatchFn) {
      dispatch = dispatchFn

      if (!subscribed && typeof dispatch === 'function') {
        queue.subscribe(dispatch)
        subscribed = true
      }
    },

    /**
     * Middleware interface for Integreat. Will push queuable actions to queue,
     * and pass the rest on to the next() function.
     *
     * @param {function} next - The next middleware
     * @returns {Object} A response object
     */
    middleware (next) {
      return middleware(next, queue)
    },

    /**
     * Schedule actions from the given defs.
     * Actions are enqueued with a timestamp, and are ran at the
     * set time.
     * @param {array} defs - An array of schedule definitions
     * @returns {array} Array of returned responses
     */
    async schedule (defs) {
      return schedule(defs, queue)
    }
  }
}

Set up Integreat queue interface.

@param {Object} queue - A supported queue implementation
@returns {Object} An Integreat queue instance with setDispatch and middleware methods


async function getMeta ({ payload, meta }, { getService }) {
  debug('Action: GET_META')

  const { service: serviceId, endpoint, keys } = payload
  const id = `meta:${serviceId}`

  const service = getService(null, serviceId)
  if (!service) {
    debug(`GET_META: Service '${serviceId}' doesn't exist`)
    return createError(`Service '${serviceId}' doesn't exist`)
  }

  const type = service.meta
  const metaService = getService(type)
  if (!metaService) {
    return createError(`Service '${service.id}' doesn't support metadata (setting was '${service.meta}')`)
  }

  const endpointDebug = (endpoint) ? `endpoint '${endpoint}'` : `endpoint matching ${type} and ${id}`
  debug('GET_META: Get meta %s for service \'%s\' on service \'%s\' at %s',
    keys, service.id, metaService.id, endpointDebug)

  const { response } = await metaService.send({
    type: 'GET',
    payload: { keys, type, id, endpoint },
    meta: { ident: meta.ident }
  })

  if (response.status === 'ok') {
    const { data } = response
    const meta = prepareMeta(keys, data[0].attributes)
    return { ...response, data: { service: serviceId, meta } }
  } else {
    return response
  }
}

Get metadata for a service, based on the given action object.
@param {Object} payload - Payload from action object
@param {Object} resources - Object with getService
@returns {Promise} Promise of metdata

Get metadata for a service based on the given action object .


async function set (action, { getService, schemas }) {
  debug('Action: SET')

  const { service: serviceId, data, endpoint, onlyMappedValues = true } = action.payload
  const type = extractType(action, data)
  const id = extractId(data)

  const service = getService(type, serviceId)
  if (!service) {
    return createUnknownServiceError(type, serviceId, 'SET')
  }

  const endpointDebug = (endpoint) ? `at endpoint '${endpoint}'` : ''
  debug('SET: Send to service %s %s', service.id, endpointDebug)

  const { response, authorizedRequestData } = await service.send(appendToAction(action, { id, type, onlyMappedValues }))

  return mergeRequestAndResponseData(response, authorizedRequestData)
}

async
function
set
(
action
,
{
getService
,
schemas
}
)
{
debug
(
'Action: SET'
)
const
{
service
:
serviceId
,
data
,
endpoint
,
onlyMappedValues
=
true
}
=
action
.
payload
const
type
=
extractType
(
action
,
data
)
const
id
=
extractId
(
data
)
const
service
=
getService
(
type
,
serviceId
)
if
(
!
service
)
{
return
createUnknownServiceError
(
type
,
serviceId
,
'SET'
)
}
const
endpointDebug
=
(
endpoint
)
`
${
endpoint
}
`
:
''
debug
(
'SET: Send to service %s %s'
,
service
.
id
,
endpointDebug
)
const
{
response
,
authorizedRequestData
}
=
await
service
.
send
(
appendToAction
(
action
,
{
id
,
type
,
onlyMappedValues
}
)
)
return
mergeRequestAndResponseData
(
response
,
authorizedRequestData
)
}

Set several items to a service, based on the given action object.
@param {Object} payload - Payload from action object
@param {Object} resources - Object with getService
@returns {Object} Response object with any data returned from the service

Set several items to a service based on the given action object .


async function setMeta ({ payload, meta }, { getService }) {
  debug('Action: SET_META')

  const {
    service: serviceId,
    meta: metaAttrs,
    endpoint
  } = payload
  const id = `meta:${serviceId}`

  const service = getService(null, serviceId)
  if (!service) {
    debug(`SET_META: Service '${serviceId}' doesn't exist`)
    return createError(`Service '${serviceId}' doesn't exist`)
  }

  const type = service.meta
  const metaService = getService(type)
  if (!metaService) {
    debug(`SET_META: Service '${service.id}' doesn't support metadata (setting was '${service.meta}')`)
    return { status: 'noaction' }
  }

  const endpointDebug = (endpoint) ? `endpoint '${endpoint}'` : `endpoint matching ${type} and ${id}`
  debug('SET_META: Send metadata %o for service \'%s\' on service \'%s\' %s',
    metaAttrs, service.id, metaService.id, endpointDebug)

  const data = { id, type, attributes: metaAttrs }
  const { response } = await metaService.send({
    type: 'SET',
    payload: { keys: Object.keys(metaAttrs), type, id, data, endpoint, onlyMappedValues: true },
    meta: { ident: meta.ident }
  })
  return response
}

Set metadata on a service, based on the given action object.
@param {Object} payload - Payload from action object
@param {Object} resources - Object with getService
@returns {Promise} Promise that will be resolved when metadata is set

Set metadata on a service based on the given action object .


function exportToJSONSchema(expSpecifications, baseSchemaURL, baseTypeURL, flat = false) {
  const namespaceResults = {};
  const endOfTypeURL = baseTypeURL[baseTypeURL.length - 1];
  if (endOfTypeURL !== '#' && endOfTypeURL !== '/') {
    baseTypeURL += '/';
  }
  for (const ns of expSpecifications.namespaces.all) {
    const lastLogger = logger;
    logger = logger.child({ shrId: ns.namespace});
    try {
      logger.debug('Exporting namespace.');
      if (flat) {
        const { schemaId, schema } = flatNamespaceToSchema(ns, expSpecifications.dataElements, baseSchemaURL, baseTypeURL);
        namespaceResults[schemaId] = schema;
      } else {
        const { schemaId, schema } = namespaceToSchema(ns, expSpecifications.dataElements, baseSchemaURL, baseTypeURL);
        namespaceResults[schemaId] = schema;
      }
      logger.debug('Finished exporting namespace.');
    } finally {
      logger = lastLogger;
    }
  }

  return namespaceResults;
}

function
exportToJSONSchema
(
expSpecifications
,
baseSchemaURL
,
baseTypeURL
,
flat
=
false
)
{
const
namespaceResults
=
{
}
;
const
endOfTypeURL
=
baseTypeURL
[
baseTypeURL
.
length
1
]
;
if
(
endOfTypeURL
!==
'#'
&&
endOfTypeURL
!==
'/'
)
{
baseTypeURL
+=
'/'
;
}
for
(
const
ns
of
expSpecifications
.
namespaces
.
all
)
{
const
lastLogger
=
logger
;
logger
=
logger
.
child
(
{
shrId
:
ns
.
namespace
}
)
;
try
{
logger
.
debug
(
'Exporting namespace.'
)
;
if
(
flat
)
{
const
{
schemaId
,
schema
}
=
flatNamespaceToSchema
(
ns
,
expSpecifications
.
dataElements
,
baseSchemaURL
,
baseTypeURL
)
;
namespaceResults
[
schemaId
]
=
schema
;
}
else
{
const
{
schemaId
,
schema
}
=
namespaceToSchema
(
ns
,
expSpecifications
.
dataElements
,
baseSchemaURL
,
baseTypeURL
)
;
namespaceResults
[
schemaId
]
=
schema
;
}
logger
.
debug
(
'Finished exporting namespace.'
)
;
}
finally
{
logger
=
lastLogger
;
}
}
return
namespaceResults
;
}

Converts a group of specifications into JSON Schema.
@param {Specifications} expSpecifications - a fully expanded Specifications object.
@param {string} baseSchemaURL - the root URL for the schema identifier.
@param {string} baseTypeURL - the root URL for the EntryType field.
@param {boolean=} flat - if true then the generated schema will not be hierarchical. Defaults to false.
@return {Object.<string, Object>} A mapping of schema ids to JSON Schema definitions.

Converts a group of specifications into JSON Schema .


function makeRef(id, enclosingNamespace, baseSchemaURL) {
  if (id.namespace === enclosingNamespace.namespace) {
    return '#/definitions/' + id.name;
  } else {
    return makeShrDefinitionURL(id, baseSchemaURL);
  }
}

function makeRef ( id , enclosingNamespace , baseSchemaURL ) { if ( id . namespace === enclosingNamespace . namespace ) { return '#/definitions/' + id . name ; } else { return makeShrDefinitionURL ( id , baseSchemaURL ) ; } }

Create a JSON Schema reference to the specified type.

@param {Identifier} id - the target type.
@param {Namespace} enclosingNamespace - the current namespace that is being evaluated.
@param {string} baseSchemaURL - the root URL for the schema identifier
@returns {string} - a JSON Schema reference to the target type.

Create a JSON Schema reference to the specified type .


function isOrWasAList(value) {
  if (value.card.isList) {
    return true;
  }
  const cardConstraints = value.constraintsFilter.own.card.constraints;
  return cardConstraints.some((oneCard) => oneCard.isList);
}

function isOrWasAList ( value ) { if ( value . card . isList ) { return true ; } const cardConstraints = value . constraintsFilter . own . card . constraints ; return cardConstraints . some ( ( oneCard ) => oneCard . isList ) ; }

Determine if a value or one of its ancestors is or was a list.

@param {Value} value - the value to test.
@return {boolean} True if the value or any of its ancestors ever had a cardinality greater than 1.

Determine if a value or one of its ancestors is or was a list .


function findOptionInChoice(choice, optionId, dataElementSpecs) {
  // First look for a direct match
  for (const option of choice.aggregateOptions) {
    if (optionId.equals(option.identifier)) {
      return option;
    }
  }
  // Then look for a match on one of the selected options's base types
  // E.g., if choice has Quantity but selected option is IntegerQuantity
  for (const option of choice.aggregateOptions) {
    if (checkHasBaseType(optionId, option.identifier, dataElementSpecs)) {
      return option;
    }
  }
  return null;
}

Searches the aggregate options of a choice for the specified option.

@param {ChoiceValue} choice - the choice to evaluate.
@param {Identifier} optionId - the identifier to find in the choice.
@param {DataElementSpecifications} dataElementSpecs - The available DataElement specs.
@returns {Value?} The first option in the choice that matches the specified optionId.

Searches the aggregate options of a choice for the specified option .


function supportsCodeConstraint(identifier, dataElementSpecs) {
  if (CODE.equals(identifier) || checkHasBaseType(identifier, new Identifier('shr.core', 'Coding'), dataElementSpecs)
      || checkHasBaseType(identifier, new Identifier('shr.core', 'CodeableConcept'), dataElementSpecs)) {
    return true;
  }
  const element = dataElementSpecs.findByIdentifier(identifier);
  if (element.value) {
    if (element.value instanceof IdentifiableValue) {
      return CODE.equals(element.value.identifier) || checkHasBaseType(element.value.identifier, new Identifier('shr.core', 'Coding'), dataElementSpecs)
          || checkHasBaseType(element.value.identifier, new Identifier('shr.core', 'CodeableConcept'), dataElementSpecs);
    } else if (element.value instanceof ChoiceValue) {
      for (const value of element.value.aggregateOptions) {
        if (value instanceof IdentifiableValue) {
          if (CODE.equals(value.identifier) || checkHasBaseType(value.identifier, new Identifier('shr.core', 'Coding'), dataElementSpecs)
              || checkHasBaseType(value.identifier, new Identifier('shr.core', 'CodeableConcept'), dataElementSpecs)) {
            return true;
          }
        }
      }
    }
  }
  return false;
}

function supportsCodeConstraint ( identifier , dataElementSpecs ) { if ( CODE . equals ( identifier ) || checkHasBaseType ( identifier , new Identifier ( 'shr.core' , 'Coding' ) , dataElementSpecs ) || checkHasBaseType ( identifier , new Identifier ( 'shr.core' , 'CodeableConcept' ) , dataElementSpecs ) ) { return true ; } const element = dataElementSpecs . findByIdentifier ( identifier ) ; if ( element . value ) { if ( element . value instanceof IdentifiableValue ) { return CODE . equals ( element . value . identifier ) || checkHasBaseType ( element . value . identifier , new Identifier ( 'shr.core' , 'Coding' ) , dataElementSpecs ) || checkHasBaseType ( element . value . identifier , new Identifier ( 'shr.core' , 'CodeableConcept' ) , dataElementSpecs ) ; } else if ( element . value instanceof ChoiceValue ) { for ( const value of element . value . aggregateOptions ) { if ( value instanceof IdentifiableValue ) { if ( CODE . equals ( value . identifier ) || checkHasBaseType ( value . identifier , new Identifier ( 'shr.core' , 'Coding' ) , dataElementSpecs ) || checkHasBaseType ( value . identifier , new Identifier ( 'shr.core' , 'CodeableConcept' ) , dataElementSpecs ) ) { return true ; } } } } } return false ; }

stealing from shr-expand
Determine if a type supports a code constraint.

@param {Identifier} identifier - The identifier of the type to check.
@param {DataElementSpecifications} dataElementSpecs - The available DataElement specs.
@return {boolean} Whether or not the given type supports a code constraint.

stealing from shr - expand Determine if a type supports a code constraint .


async function expire ({ payload, meta = {} }, { dispatch }) {
  const { service } = payload
  const { ident } = meta

  if (!service) {
    return createError(`Can't delete expired without a specified service`)
  }
  if (!payload.endpoint) {
    return createError(`Can't delete expired from service '${service}' without an endpoint`)
  }
  if (!payload.type) {
    return createError(`Can't delete expired from service '${service}' without one or more specified types`)
  }

  const response = await getExpired(payload, ident, dispatch)

  return deleteExpired(response, service, ident, dispatch)
}

async function expire ( { payload , meta = { } } , { dispatch } ) { const { service } = payload const { ident } = meta if ( ! service ) { return createError ( ` ` ) } if ( ! payload . endpoint ) { return createError ( ` ${ service } ` ) } if ( ! payload . type ) { return createError ( ` ${ service } ` ) } const response = await getExpired ( payload , ident , dispatch ) return deleteExpired ( response , service , ident , dispatch ) }

Action to delete expired items.

The given `endpoint` is used to retrieve expired items from the `service`, and
may use the paramters `timestamp` or `isodate`, which represents the current
time plus the microseconds in `msFromNow`, the former as microseconds since
January 1, 1970, the latter as an ISO formatted date and time string.

The items are mapped and typed, so the `type` param should be set to one
or more types expected from the `endpoint`, and may be a string or an array
of strings.
@param {Object} payload - Action payload (service, type, endpoint, and msFromNow)
@param {Object} resources - Dispatch and queue functions
@returns {Object} Response object


function transformRange(range, ops) {
  var rangeComps = range.split(':')
    , newRange
  var start = rangeComps[0]
  ops.forEach(op => start = transformRangeAnchor(start, op, /*isStart:*/true))
  var end = rangeComps[1]
  ops.forEach(op => end = transformRangeAnchor(end, op, /*isStart:*/false))
  if (start === end) return start
  return start+':'+end
}

function transformRange ( range , ops ) { var rangeComps = range . split ( ':' ) , newRange var start = rangeComps [ 0 ] ops . forEach ( op => start = transformRangeAnchor ( start , op , /*isStart:*/ true ) ) var end = rangeComps [ 1 ] ops . forEach ( op => end = transformRangeAnchor ( end , op , /*isStart:*/ false ) ) if ( start === end ) return start return start + ':' + end }

Transforms a range against an array of ops


function transformRangeAnchor(target, op, isStart) {
  var thisCell = parseCell(target)
  if (op instanceof InsertCol) {
    var otherCell = parseCell(op.newCol)
    if (otherCell[0] <= thisCell[0]) return column.fromInt(thisCell[0]+1)+thisCell[1]
  }
  else if (op instanceof DeleteCol) {
    var otherCell = parseCell(op.col)
    if (otherCell[0] < thisCell[0]) return column.fromInt(thisCell[0]-1)+thisCell[1]
    if (otherCell[0] === thisCell[0]) {
      // Spreadsheet selection is different from text selection:
      // While text selection ends in the first *not* selected char ( "foo| |bar" => 3,4)
      // ... spreadsheet selection ends in the last selected cell. Thus we need to
      // differentiate between start and end. Shame on those who didn't think about this!
      if (!isStart) return column.fromInt(thisCell[0]-1)+thisCell[1]     }
  }
  else if (op instanceof InsertRow) {
    var otherCell = parseCell(op.newRow)
    if (otherCell[1] <= thisCell[1]) return column.fromInt(thisCell[0])+(thisCell[1]+1)
  }
  else if (op instanceof DeleteRow) {
    var otherCell = parseCell(op.col)
    if (otherCell[1] < thisCell[1]) return column.fromInt(thisCell[0])+(thisCell[1]-1)
    if (otherCell[1] === thisCell[1]) {
      if (!isStart) return column.fromInt(thisCell[0])+(thisCell[1]-1)
    }
  }
  // If nothing has returned already then this anchor doesn't change
  return target
}

Transforms a range anchor, taking into account whether it's the start or end

Transforms a range anchor taking into account whether it s the start or end


function matchEndpoint (endpoints) {
  return ({ type, payload, meta }) => endpoints
    .find((endpoint) =>
      matchId(endpoint, { type, payload }) &&
      matchType(endpoint, { type, payload }) &&
      matchScope(endpoint, { type, payload }) &&
      matchAction(endpoint, { type, payload }) &&
      matchParams(endpoint, { type, payload }) &&
      matchFilters(endpoint, { type, payload, meta }))
}

function matchEndpoint ( endpoints ) { return ( { type , payload , meta } ) => endpoints . find ( ( endpoint ) => matchId ( endpoint , { type , payload } ) && matchType ( endpoint , { type , payload } ) && matchScope ( endpoint , { type , payload } ) && matchAction ( endpoint , { type , payload } ) && matchParams ( endpoint , { type , payload } ) && matchFilters ( endpoint , { type , payload , meta } ) ) }

Return the first matching endpoint from an array of endpoints that has
already been sortert with higher specificity first. Type should match before
scope, which should match before action, but the order here is taken care of
by the required sorting.

@param {Object[]} endpoints - Array of endpoint objects
@param {Object} action - Action object to match agains
@returns {Object} Matching endpoint

Return the first matching endpoint from an array of endpoints that has already been sortert with higher specificity first . Type should match before scope which should match before action but the order here is taken care of by the required sorting .


function createAction (type, payload = {}, meta) {
  if (!type) {
    return null
  }

  const action = { type, payload }
  if (meta) {
    action.meta = meta
  }
  return action
}

function createAction ( type , payload = { } , meta ) { if ( ! type ) { return null } const action = { type , payload } if ( meta ) { action . meta = meta } return action }

Create an action object.
@param {string} type - The action type
@param {Object} payload - The payload of the action
@param {Object} props - Other action properties
@returns {Object} An action object


function authorizeRequest ({ schemas }) {
  return ({ request }) => {
    const { access = {}, params = {}, action } = request

    const { ident = null } = access

    if (ident && ident.root) {
      return authItemsAndWrap(request, { status: 'granted', ident, scheme: 'root' }, schemas)
    }
    if (!params.type) {
      return authItemsAndWrap(request, { status: 'granted', ident, scheme: null }, schemas)
    }

    const requireAuth = !!request.auth
    const schema = schemas[params.type]
    const scheme = getScheme(schema, action)
    const status = (doAuth(scheme, ident, requireAuth)) ? 'granted' : 'refused'

    return authItemsAndWrap(request, { status, ident, scheme }, schemas)
  }
}

function authorizeRequest ( { schemas } ) { return ( { request } ) => { const { access = { } , params = { } , action } = request const { ident = null } = access if ( ident && ident . root ) { return authItemsAndWrap ( request , { status : 'granted' , ident , scheme : 'root' } , schemas ) } if ( ! params . type ) { return authItemsAndWrap ( request , { status : 'granted' , ident , scheme : null } , schemas ) } const requireAuth = ! ! request . auth const schema = schemas [ params . type ] const scheme = getScheme ( schema , action ) const status = ( doAuth ( scheme , ident , requireAuth ) ) ? 'granted' : 'refused' return authItemsAndWrap ( request , { status , ident , scheme } , schemas ) } }

Authorize the request according to the setting on the relevant schema.
Sets the access object with `status` property specifying whether access
is `granted` or `refused`, and returns the request.

The access object also includes the `ident` and the  `scheme`used for
authentication.

@param {Object} request - The request object to authorize
@param {Object} schemas - An object with all schemas that may be needed
@returns {Object} The request object with updated access object

Authorize the request according to the setting on the relevant schema . Sets the access object with status property specifying whether access is granted or refused and returns the request .


function requestFromAction (
  { type: action, payload, meta = {} },
  { endpoint, schemas = {} } = {}
) {
  const { data, ...params } = payload
  const { ident = null } = meta
  const typePlural = getPluralType(params.type, schemas)

  return {
    action,
    params,
    data,
    endpoint: (endpoint && endpoint.options) || null,
    access: { ident },
    meta: {
      typePlural
    }
  }
}

function requestFromAction ( { type : action , payload , meta = { } } , { endpoint , schemas = { } } = { } ) { const { data , ... params } = payload const { ident = null } = meta const typePlural = getPluralType ( params . type , schemas ) return { action , params , data , endpoint : ( endpoint && endpoint . options ) || null , access : { ident } , meta : { typePlural } } }

Complete missing props and allow only expected props on the request object.
@param {Object} request - The request object to complete
@returns {Object} The completed request object

Complete missing props and allow only expected props on the request object .


function getService (schemas, services) {
  return (type, service) => {
    if (!service && schemas[type]) {
      service = schemas[type].service
    }
    return services[service] || null
  }
}

function getService ( schemas , services ) { return ( type , service ) => { if ( ! service && schemas [ type ] ) { service = schemas [ type ] . service } return services [ service ] || null } }

Get service from type or service id.
@param {Object} schemas - The schemas
@param {Object} services - The services
@returns {function} Function to retrieve service from type and service id


async function sync ({ payload, meta = {} }, { dispatch }) {
  debug('Action: SYNC')
  const fromParams = await generateFromParams(payload, meta, dispatch)
  const toParams = generateToParams(payload, fromParams)

  const lastSyncedAt = new Date()

  const results = await Promise.all(
    fromParams.map(getFromService(dispatch, payload.type, meta))
  )

  if (results.some((result) => result.status !== 'ok')) {
    return (results.length === 1) ? results[0] : createError(makeErrorString(results))
  }

  const data = flatten(results.map((result) => result.data)).filter(Boolean)

  if (data.length === 0 && payload.syncNoData !== true) {
    return createError(`No items to update from service '${fromParams[0].service}'`, 'noaction')
  }

  return Promise.all([
    ...createSetMetas(fromParams, lastSyncedAt, meta.ident, dispatch),
    dispatch(action('SET', { data, ...toParams }, { ...meta, queue: true }))
  ])
    .then((responses) => {
      return { status: 'ok', data: responses }
    })
}

async
function
sync
(
{
payload
,
meta
=
{
}
}
,
{
dispatch
}
)
{
debug
(
'Action: SYNC'
)
const
fromParams
=
await
generateFromParams
(
payload
,
meta
,
dispatch
)
const
toParams
=
generateToParams
(
payload
,
fromParams
)
const
lastSyncedAt
=
new
Date
(
)
const
results
=
await
Promise
.
all
(
fromParams
.
map
(
getFromService
(
dispatch
,
payload
.
type
,
meta
)
)
)
if
(
results
.
some
(
(
result
)
=>
result
.
status
!==
'ok'
)
)
{
return
(
results
.
length
===
1
)
results
[
0
]
:
createError
(
makeErrorString
(
results
)
)
}
const
data
=
flatten
(
results
.
map
(
(
result
)
=>
result
.
data
)
)
.
filter
(
Boolean
)
if
(
data
.
length
===
0
&&
payload
.
syncNoData
!==
true
)
{
return
createError
(
`
${
fromParams
[
0
]
.
service
}
`
,
'noaction'
)
}
return
Promise
.
all
(
[
...
createSetMetas
(
fromParams
,
lastSyncedAt
,
meta
.
ident
,
dispatch
)
,
dispatch
(
action
(
'SET'
,
{
data
,
...
toParams
}
,
{
...
meta
,
queue
:
true
}
)
)
]
)
.
then
(
(
responses
)
=>
{
return
{
status
:
'ok'
,
data
:
responses
}
}
)
}

Action to sync from one service to another.

`retrieve` indicates which items to retrieve. The default is `all`, which
will retrieve all items from the `get` endpoint. Set `retrieve` to `updated`
to retrieve only items that are updated after the  `lastSyncedAt` date for
the `from` service. This is done by passing the `lastSyncedAt` date as a
parameter named `updatedAfter` to the `get` endpoint, and by actively
filter away any items received with `updatedAt` earlier than `lastSyncedAt`.

The `lastSyncedAt` metadata will be set on the `from` service when items
are retrieved and updated.

@param {Object} payload - Action payload (from, to, type, and retrieve)
@param {Object} resources - Dispatch function
@returns {Promise} Promise of the action result

Action to sync from one service to another .


function (gulp, cwd, config) {
  if (util.isNullOrUndefined(gulp)) {
    throw 'gulp must be defined';
  }

  /**
   * Configuration options that will be injected into every gulp task.
   *
   * @type {Object}
   */
  this._config = config || {},

  /**
   * Current working directory that path calculations should be relative to.
   *
   * @type {String}
   */
  this._cwd = cwd || __dirname;

  /**
   * Actual path of this file relative to the defined working directory.
   *
   * @type {String}
   */
  this._root = path.relative(this._cwd, __dirname);

  /**
   * Gulp instance. All tasks get injected the same gulp instances.
   *
   * @type {Gulp}
   */
  this._gulp = gulp;
}

Task api that configures and loads gulp tasks.

@param {!Gulp} gulp
@param {String=} cwd
@param {Object=} config

Task api that configures and loads gulp tasks .


function(bg) {
    bg = bg ? bg : false

    return (...args) => {
      return this.output(args.join(' '), this.colors(bg))
    }
  }

function
(
bg
)
{
bg
=
bg
bg
:
false
return
(
...
args
)
=>
{
return
this
.
output
(
args
.
join
(
' '
)
,
this
.
colors
(
bg
)
)
}
}


function (browserify, name, source) {
  if (utility.isNullOrUndefined(browserify)) {
    throw 'browserify must be defined.';
  }

  if (!utility.isNonEmptyString(name)) {
    throw 'name must be defined.';
  }

  if (utility.isNullOrUndefined(source)) {
    throw 'source must be defined.';
  }

  this._browserify = browserify;
  this._name = name;
  this._source = source;
  this._hasModule = false;
  this._hasResolver = false;
}

function
(
browserify
,
name
,
source
)
{
if
(
utility
.
isNullOrUndefined
(
browserify
)
)
{
throw
'browserify must be defined.'
;
}
if
(
!
utility
.
isNonEmptyString
(
name
)
)
{
throw
'name must be defined.'
;
}
if
(
utility
.
isNullOrUndefined
(
source
)
)
{
throw
'source must be defined.'
;
}
this
.
_browserify
=
browserify
;
this
.
_name
=
name
;
this
.
_source
=
source
;
this
.
_hasModule
=
false
;
this
.
_hasResolver
=
false
;
}

Babel external helper module injector.

This object will configure browserify to accept a streaming source and then
resolve any relevant compile time bindings to the built module. The module
can later by referenced by name later down the browserify pipeline and modified
further.

@param {!Browserify} browserify
@param {!String} name
@param {!Readable} source


function mapToService () {
  return ({ request, requestMapper, mappings }) => {
    const data = mapData(request.data, request, mappings)
    return {
      ...request,
      data: applyEndpointMapper(data, request, requestMapper)
    }
  }
}

function mapToService ( ) { return ( { request , requestMapper , mappings } ) => { const data = mapData ( request . data , request , mappings ) return { ... request , data : applyEndpointMapper ( data , request , requestMapper ) } } }

Map the data coming _from_ the service. Everything is handled by the mappings,
but this method make sure that the right types are mapped.

@param {Object} data - The data to map
@param {Object} mappings - The mappings to map with
@returns {Object} Mapped data

Map the data coming _from_ the service . Everything is handled by the mappings but this method make sure that the right types are mapped .


async function processMessengerBody (body, context) {
    const allMessages = getAllMessages(body)
    if (!allMessages || !allMessages.length) return false

    context = context || {}

    for (let message of allMessages) {
      message = _.cloneDeep(message)
      const messageContext = Object.assign({}, context)
      try {
        for (let plugin of middleware) {
          await plugin(message, messageContext)
        }
      } catch (error) {
        const logError = (messageContext.log && messageContext.log.error instanceof Function)
          ? messageContext.log.error
          : console.error
        logError('Error running middleware', error)
      }
    }
    return true
  }

async
function
processMessengerBody
(
body
,
context
)
{
const
allMessages
=
getAllMessages
(
body
)
if
(
!
allMessages
||
!
allMessages
.
length
)
return
false
context
=
context
||
{
}
for
(
let
message
of
allMessages
)
{
message
=
_
.
cloneDeep
(
message
)
const
messageContext
=
Object
.
assign
(
{
}
,
context
)
try
{
for
(
let
plugin
of
middleware
)
{
await
plugin
(
message
,
messageContext
)
}
}
catch
(
error
)
{
const
logError
=
(
messageContext
.
log
&&
messageContext
.
log
.
error
instanceof
Function
)
messageContext
.
log
.
error
:
console
.
error
logError
(
'Error running middleware'
,
error
)
}
}
return
true
}

Process messages from Facebook Messenger.

@param  {object}   body               _parsed_ JSON HTTP message body.
@param  {function} beforeMiddlewareFn optional function to call before executing
any plugins.
@return {boolean}                     + `true` if the Message was processed
+ `false` if the body didn't contain
Messenger messages

Process messages from Facebook Messenger .


function create(prop) {
  if (typeof prop !== 'string') {
    throw new Error('expected the first argument to be a string.');
  }

  return function(app) {
    if (this.isRegistered('base-' + prop)) return;

    // map config
    var config = utils.mapper(app)
      // store/data
      .map('store', store(app.store))
      .map('data')

      // options
      .map('enable')
      .map('disable')
      .map('option')
      .alias('options', 'option')

      // get/set
      .map('set')
      .map('del')

    // Expose `prop` (config) on the instance
    app.define(prop, proxy(config));

    // Expose `process` on app[prop]
    app[prop].process = config.process;
  };

  function store(app) {
    if (!app) return {};
    var mapper = utils.mapper(app);
    app.define(prop, proxy(mapper));
    return mapper;
  }
}

Create a function for mapping `app` properties onto the
given `prop` namespace.

@param {String} `prop` The namespace to use
@param {Object} `argv`
@return {Object}
@api public

Create a function for mapping app properties onto the given prop namespace .


function ElementMatrix(top) {
  CommanalityMatrix.call(this, top);

  this.row(' ');
  this.collum(' ');
  this.classlist = top.root.classlist;
}

function
ElementMatrix
(
top
)
{
CommanalityMatrix
.
call
(
this
,
top
)
;
this
.
row
(
' '
)
;
this
.
collum
(
' '
)
;
this
.
classlist
=
top
.
root
.
classlist
;
}

Collects features and bind them to the node density


function publicS3URI(string) {
	return encodeURIComponent(string)
		.replace(/%20/img, '+')
		.replace(/%2F/img, '/')
    .replace(/\"/img, "%22")
    .replace(/\#/img, "%23")
    .replace(/\$/img, "%24")
    .replace(/\&/img, "%26")
    .replace(/\'/img, "%27")
		.replace(/\(/img, "%28")
    .replace(/\)/img, "%29")
    .replace(/\,/img, "%2C")
    .replace(/\:/img, "%3A")
    .replace(/\;/img, "%3B")
    .replace(/\=/img, "%3D")
    .replace(/\?/img, "%3F")
    .replace(/\@/img, "%40");
}

function publicS3URI ( string ) { return encodeURIComponent ( string ) . replace ( / %20 / img , '+' ) . replace ( / %2F / img , '/' ) . replace ( / \" / img , "%22" ) . replace ( / \# / img , "%23" ) . replace ( / \$ / img , "%24" ) . replace ( / \& / img , "%26" ) . replace ( / \' / img , "%27" ) . replace ( / \( / img , "%28" ) . replace ( / \) / img , "%29" ) . replace ( / \, / img , "%2C" ) . replace ( / \: / img , "%3A" ) . replace ( / \; / img , "%3B" ) . replace ( / \= / img , "%3D" ) . replace ( / \? / img , "%3F" ) . replace ( / \@ / img , "%40" ) ; }


function (done) {
        fs.writeFile(
          path.resolve(__dirname, '../../test/reallife/expected/' + item.key + '.json'),
          JSON.stringify({
            'title': item.title,
            'text': item.text
          }, null, '\t') + '\n',
          done
        );
      }

function ( done ) { fs . writeFile ( path . resolve ( __dirname , '../../test/reallife/expected/' + item . key + '.json' ) , JSON . stringify ( { 'title' : item . title , 'text' : item . text } , null , '\t' ) + '\n' , done ) ; }


function (done) {
        fs.writeFile(
          path.resolve(__dirname, '../../test/reallife/source/' + item.key + '.html'),
          SOURCES[item.key],
          done
        );
      }

function ( done ) { fs . writeFile ( path . resolve ( __dirname , '../../test/reallife/source/' + item . key + '.html' ) , SOURCES [ item . key ] , done ) ; }


function (done) {
        datamap[item.index].labeled = true;

        fs.writeFile(
          path.resolve(__dirname, '../../test/reallife/datamap.json'),
          JSON.stringify(datamap, null, '\t') + '\n',
          done
        );
      }

function ( done ) { datamap [ item . index ] . labeled = true ; fs . writeFile ( path . resolve ( __dirname , '../../test/reallife/datamap.json' ) , JSON . stringify ( datamap , null , '\t' ) + '\n' , done ) ; }


function Node(type, parent) {
  this.type = type;
  this.parent = parent;
  this.root = parent ? parent.root : this;
  this.identifyer = parent ? (++parent.root._counter) : 0;

  // The specific constructor will set another value if necessary
  this._textLength = 0;

  this.tags = 0;
  this.density = -1;

  this.children = [];

  this._text = '';
  this._textCompiled = false;
  this._noneStyleText = '';
  this._noneStyleTextCompiled = false;

  this.blocky = false;
  this.blockyChildren = false;

  this.inTree = true;
}

Node General abstaction between all node types The rule is that this should contain the most obviouse implementation


function TextNode(parent, text) {
  Node.call(this, 'text', parent);

  // A text node has no children instead it has a text container
  this.children = null;
  this._text = text;
  this._noneStyleText = text;
}

TextNode has a parent and a text containter


function ElementNode(parent, tagname, attributes) {
  Node.call(this, 'element', parent);

  // Since this is an element there will minimum one tag
  this.tags = (tagname === 'br' || tagname === 'wbr') ? 0 : 1;

  // Element nodes also has a tagname and an attribute collection
  this.tagname = tagname;
  this.attr = attributes;
  this.classes = attributes.hasOwnProperty('class') ?
    attributes['class'].trim().split(WHITE_SPACE) : [];

  // Add node to the classlist
  this.root.classlist.addNode(this);

  this._blockySelfCache = domHelpers.BLOCK_ELEMENTS.hasOwnProperty(tagname);
  this._countTagnames = {};
}

ElementNode has a parent, tagname and attributes

ElementNode has a parent tagname and attributes


function () {
            var r;

            // Recall as new if new isn't provided :)
            if( Util.isnt.instanceof( NewClass, this ) ) {
                return ClassUtil.construct( NewClass, arguments );
            }

            // call the constructor
            if ( Util.is.Function( this.initialize ) ) {
                r = this.initialize.apply(this, arguments);
            }

            // call all constructor hooks
            this.callInitHooks();

            return typeof r != 'undefined' ? r : this;
        }


function distribute(filename, content){
    content = content;
    fs.appendFile(filename, content + "\n");
    log(rulecount + ': Append to ' + filename + ' -> ' + content);
  }

function
distribute
(
filename
,
content
)
{
content
=
content
;
fs
.
appendFile
(
filename
,
content
+
"\n"
)
;
log
(
rulecount
+
': Append to '
+
filename
+
' -> '
+
content
)
;
}

Distribute content to the cssfiles object


function detectTakeout(selectors){
    var properties = {
      takeout: false
    };

    options.takeout.forEach(function (takeout) {
      selectors.forEach(function (selector) {
        if (selector.indexOf(takeout.ruleprefix) === 0) {
          properties.takeout = true;
          properties.filename = takeout.filename;
        }
      });
    });

    return properties;
  }

function detectTakeout ( selectors ) { var properties = { takeout : false } ; options . takeout . forEach ( function ( takeout ) { selectors . forEach ( function ( selector ) { if ( selector . indexOf ( takeout . ruleprefix ) === 0 ) { properties . takeout = true ; properties . filename = takeout . filename ; } } ) ; } ) ; return properties ; }

Detect weather a selector should be extracted or not


function parseLineByLine(text) {
    var lines = text.trim().split("\n");
    var bookmarks = lines.splice(0, lines.length * 3 / 4);
    return {
        bookmarks: bookmarks,
        lines: lines
    };
}

function parseLineByLine ( text ) { var lines = text . trim ( ) . split ( "\n" ) ; var bookmarks = lines . splice ( 0 , lines . length * 3 / 4 ) ; return { bookmarks : bookmarks , lines : lines } ; }

create tuple that
@param text
@returns {{bookmarks: string[], lines: string[]}}


function CommonalityInterface(MatrixConstructor, top) {
  this.top = top;
  this.length = null;
  this.matrix = null;

  this.MatrixConstructor = MatrixConstructor;
}

function CommonalityInterface ( MatrixConstructor , top ) { this . top = top ; this . length = null ; this . matrix = null ; this . MatrixConstructor = MatrixConstructor ; }


function CommanalityMatrix(classlist) {
  // space will identify a text node and/or an element node without any classnames
  this.rowKeys = {};
  this.rowNames = [];

  this.collumKeys = {};
  this.collumNames = [];

  this.nodeMatrix = [];
  this.summaryMatrix = [];

  this.dim = [0, 0];

  this.bestIndex = [-1, -1];
  this._bestNodes = {};
}

Some abstact API for the commanality matrix


function arrayVector(size) {
  var vec = new Array(size);
  for (var i = 0; i < size; i++) vec[i] = [];
  return vec;
}

function arrayVector ( size ) { var vec = new Array ( size ) ; for ( var i = 0 ; i < size ; i ++ ) vec [ i ] = [ ] ; return vec ; }


function buildAttributeMatcher(match) {
  var keys = Object.keys(match);
  var jskey, i, l;

  var transform = '';
  var bool = '';

  transform = 'transform = {\n';
  for (i = 0, l = keys.length; i < l; i++) {
    jskey = JSON.stringify(keys[i]);

    transform += '  ' + jskey + ': attr.hasOwnProperty(' + jskey + ') ? attr[' + jskey + '].toLowerCase() : false';
    if (i !== l - 1) transform += ',';
    transform += '\n';
  }
  transform += '};\n';

  bool = 'return !!(';
  for (i = 0, l = keys.length; i < l; i++) {
    jskey = JSON.stringify(keys[i]);

    if (i > 0) bool += '    ||    ';
    bool += ' ( transform[' + jskey + ']';

    if (Array.isArray(match[keys[i]])) {
      bool += ' && ( ';

      for (var j = 0, s = match[keys[i]].length; j < s; j++) {
        if (j > 0) bool += ' || ';

        if (typeof match[keys[i]][j] === 'string') {
          bool += 'transform[' + jskey + '] === \'' + match[keys[i]][j].toLowerCase() + '\'';
        } else if (util.isRegExp(match[keys[i]][j])) {
          bool += 'match[' + jskey + '][' + j + '].test(transform[' + jskey + '])';
        }
      }

      bool += ' )';
    }

    bool += ' ) \n';
  }

  bool += '         );';

  var anonymous = new Function('attr', 'match', transform + '\n' + bool);
  return function (attr) {
    return anonymous(attr, match);
  };
}

function
buildAttributeMatcher
(
match
)
{
var
keys
=
Object
.
keys
(
match
)
;
var
jskey
,
i
,
l
;
var
transform
=
''
;
var
bool
=
''
;
transform
=
'transform = {\n'
;
for
(
i
=
0
,
l
=
keys
.
length
;
i
<
l
;
i
++
)
{
jskey
=
JSON
.
stringify
(
keys
[
i
]
)
;
transform
+=
'  '
+
jskey
+
': attr.hasOwnProperty('
+
jskey
+
') ? attr['
+
jskey
+
'].toLowerCase() : false'
;
if
(
i
!==
l
1
)
transform
+=
','
;
transform
+=
'\n'
;
}
transform
+=
'};\n'
;
bool
=
'return !!('
;
for
(
i
=
0
,
l
=
keys
.
length
;
i
<
l
;
i
++
)
{
jskey
=
JSON
.
stringify
(
keys
[
i
]
)
;
if
(
i
>
0
)
bool
+=
'    ||    '
;
bool
+=
' ( transform['
+
jskey
+
']'
;
if
(
Array
.
isArray
(
match
[
keys
[
i
]
]
)
)
{
bool
+=
' && ( '
;
for
(
var
j
=
0
,
s
=
match
[
keys
[
i
]
]
.
length
;
j
<
s
;
j
++
)
{
if
(
j
>
0
)
bool
+=
' || '
;
if
(
typeof
match
[
keys
[
i
]
]
[
j
]
===
'string'
)
{
bool
+=
'transform['
+
jskey
+
'] === \''
+
match
[
keys
[
i
]
]
[
j
]
.
toLowerCase
(
)
+
'\''
;
}
else
if
(
util
.
isRegExp
(
match
[
keys
[
i
]
]
[
j
]
)
)
{
bool
+=
'match['
+
jskey
+
']['
+
j
+
'].test(transform['
+
jskey
+
'])'
;
}
}
bool
+=
' )'
;
}
bool
+=
' ) \n'
;
}
bool
+=
'         );'
;
var
anonymous
=
new
Function
(
'attr'
,
'match'
,
transform
+
'\n'
+
bool
)
;
return
function
(
attr
)
{
return
anonymous
(
attr
,
match
)
;
}
;
}

Builds and attribute matching function, complexity is for uncomfirmed performace sake

Builds and attribute matching function complexity is for uncomfirmed performace sake


function containerOf(a, b) {
  while (b = b.parent) {
    if (a === b) return true;
  }
  return false;
}

function containerOf ( a , b ) { while ( b = b . parent ) { if ( a === b ) return true ; } return false ; }

Checks if container `a` is a container of `b`

Checks if container a is a container of b


function commonParent(a, b) {
  if (a === b) {
    return a;
  } else if (containerOf(a, b)) {
    return a;
  } else if (containerOf(b, a)) {
    return b;
  } else {
    // This will happen at some point, since the root is a container of
    // everything
    while (b = b.parent) {
      if (containerOf(b, a)) return b;
    }
  }
}


function styleParser(style) {
  style = style || '';

  var tokens = style.trim().split(/\s*(?:;|:)\s*/);
  var output = {};
  for (var i = 1, l = tokens.length; i < l; i += 2) {
    output[tokens[i - 1]] = tokens[i];
  }
  return output;
}

function styleParser ( style ) { style = style || '' ; var tokens = style . trim ( ) . split ( / \s*(?:;|:)\s* / ) ; var output = { } ; for ( var i = 1 , l = tokens . length ; i < l ; i += 2 ) { output [ tokens [ i - 1 ] ] = tokens [ i ] ; } return output ; }


function treeDistance(a, b) {
  if (a === b) return 0;
  var parent = commonParent(a, b);

  var aParent = a;
  var aCount = 0;

  var bParent = b;
  var bCount = 0;

  if (parent !== a) {
    while (parent !== aParent.parent) {
      aCount += 1;
      aParent = aParent.parent;
    }
  } else {
    bCount += 1;
  }

  if (parent !== b) {
    while (parent !== bParent.parent) {
      bCount += 1;
      bParent = bParent.parent;
    }
  } else {
    aCount += 1;
  }

  var abCount = 0;
  if (parent !== a && parent !== b) {
    abCount = Math.abs(
      parent.children.indexOf(aParent) - parent.children.indexOf(bParent)
    );
  }

  return aCount + bCount + abCount;
}

function treeDistance ( a , b ) { if ( a === b ) return 0 ; var parent = commonParent ( a , b ) ; var aParent = a ; var aCount = 0 ; var bParent = b ; var bCount = 0 ; if ( parent !== a ) { while ( parent !== aParent . parent ) { aCount += 1 ; aParent = aParent . parent ; } } else { bCount += 1 ; } if ( parent !== b ) { while ( parent !== bParent . parent ) { bCount += 1 ; bParent = bParent . parent ; } } else { aCount += 1 ; } var abCount = 0 ; if ( parent !== a && parent !== b ) { abCount = Math . abs ( parent . children . indexOf ( aParent ) - parent . children . indexOf ( bParent ) ) ; } return aCount + bCount + abCount ; }

Calculate the tree distance between a and b


function Lexer(file, options) {
  this.options = utils.extend({}, options);
  this.file = file;
  this.regex = new RegexCache();
  this.names = [];
  this.ast = {
    tags: {},
    type: 'root',
    name: 'root',
    nodes: []
  };

  this.unknown = {tags: [], blocks: []};
  this.known = {
    tags: ['extends', 'layout'],
    blocks: ['block']
  };

  this.delimiters = {
    variable: ['{{', '}}'],
    block: ['{%', '%}'],
    es6: ['${', '}'],
  };

  this.tokens = [this.ast];
  this.errors = [];
  this.stack = [];
  this.stash = [];
  this.lexers = {};
  this.fns = [];
}

function Lexer ( file , options ) { this . options = utils . extend ( { } , options ) ; this . file = file ; this . regex = new RegexCache ( ) ; this . names = [ ] ; this . ast = { tags : { } , type : 'root' , name : 'root' , nodes : [ ] } ; this . unknown = { tags : [ ] , blocks : [ ] } ; this . known = { tags : [ 'extends' , 'layout' ] , blocks : [ 'block' ] } ; this . delimiters = { variable : [ '{{' , '}}' ] , block : [ '{%' , '%}' ] , es6 : [ '${' , '}' ] , } ; this . tokens = [ this . ast ] ; this . errors = [ ] ; this . stack = [ ] ; this . stash = [ ] ; this . lexers = { } ; this . fns = [ ] ; }

Create a new `Lexer` for the given `file` and `options`.
@param {object} `file`
@param {object} `options`

Create a new Lexer for the given file and options .


function() {
    if (this.isInitialized) return;

    this.isInitialized = true;
    var lexer = this;
    this.lineno = 1;
    this.column = 1;
    this.lexed = '';

    this.file = utils.normalize(this.file);
    this.file.orig = this.file.contents;
    this.input = this.file.contents.toString();
    this.file.ast = this.ast;
    this.file.ast.variables = {};
    this.file.ast.blocks = {};

    this.input = this.input.split('{% body %}')
      .join('{% block "body" %}{% endblock %}');

    if (this.file.extends) {
      this.prependNode(this.file, 'extends');
    }

    /**
     * Tags
     */
    this.captureTag('extends');
    this.captureTag('layout');

    /**
     * Block tags
     */
    this.captureBlock('block');

    /**
     * Captures
     */

    this.capture('text', utils.negateDelims(this.delimiters));
    this.capture('newline', /^\n+/);
    this.capture('es6', /^\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/);
    this.capture('variable', /^\{{2,}([^\\}]*(?:\\.[^\\}]*)*)\}{2,}/);
    this.capture('escape', /^\\(.)/);
    this.capture('space', /^[ \t]+/);

    /**
     * Custom helpers
     */
    var helpers = this.options.helpers || {};
    if (utils.isObject(helpers)) {
      helpers = Object.keys(helpers);
    }

    helpers.forEach(function(key) {
      lexer.known.blocks.push(key);
      lexer.captureBlock(key);
    });

    /**
     * Add other names to return un-rendered
     */

    var matches = this.input.match(/\{%\s*([^%}]+)/g);
    var names = utils.getNames(matches);

    names.tags.forEach(function(key) {
      if (!utils.isRegistered(lexer, key)) {
        lexer.unknown.tags.push(key);
        lexer.captureTag(key);
      }
    });

    names.blocks.forEach(function(key) {
      if (!utils.isRegistered(lexer, key)) {
        lexer.unknown.blocks.push(key);
        lexer.captureBlock(key);
      }
    });
  }


function(msg) {
    var message = this.file.relative
      + ' line:' + this.lineno
      + ' column:' + this.column
      + ': ' + msg;

    var err = new Error(message);
    err.reason = msg;
    err.line = this.lineno;
    err.column = this.column;
    err.source = this.input;
    err.path = this.file.path;

    if (this.options.silent) {
      this.errors.push(err);
    } else {
      throw err;
    }
  }

function
(
msg
)
{
var
message
=
this
.
file
.
relative
+
' line:'
+
this
.
lineno
+
' column:'
+
this
.
column
+
': '
+
msg
;
var
err
=
new
Error
(
message
)
;
err
.
reason
=
msg
;
err
.
line
=
this
.
lineno
;
err
.
column
=
this
.
column
;
err
.
source
=
this
.
input
;
err
.
path
=
this
.
file
.
path
;
if
(
this
.
options
.
silent
)
{
this
.
errors
.
push
(
err
)
;
}
else
{
throw
err
;
}
}

Set an error message with the current line number and column.
@param {String} `msg` Message to use in the Error.

Set an error message with the current line number and column .


function(type) {
    var cached = this.regex.createVariable(type);
    var file = this.file;
    var lexer = this;

    var fn = this.lexers[type] = function() {
      var pos = lexer.position();
      var m = lexer.match(cached.strict);
      if (!m) return;

      var parent = this.prev();
      var node = pos({
        type: type,
        known: utils.has(lexer.known.tags, type),
        val: m[0].trim()
      });

      parent.known = node.known;
      var nodes = parent.nodes;

      Object.defineProperty(file.ast.variables, type, {
        configurable: true,
        set: function(val) {
          nodes = val;
        },
        get: function() {
          return nodes;
        }
      });

      Object.defineProperty(parent, 'nodes', {
        configurable: true,
        set: function(val) {
          nodes = val;
        },
        get: function() {
          return nodes;
        }
      });

      utils.define(node, 'parent', parent);
      parent.nodes.push(node);
    };

    this.addLexer(fn);
    return this;
  }

function ( type ) { var cached = this . regex . createVariable ( type ) ; var file = this . file ; var lexer = this ; var fn = this . lexers [ type ] = function ( ) { var pos = lexer . position ( ) ; var m = lexer . match ( cached . strict ) ; if ( ! m ) return ; var parent = this . prev ( ) ; var node = pos ( { type : type , known : utils . has ( lexer . known . tags , type ) , val : m [ 0 ] . trim ( ) } ) ; parent . known = node . known ; var nodes = parent . nodes ; Object . defineProperty ( file . ast . variables , type , { configurable : true , set : function ( val ) { nodes = val ; } , get : function ( ) { return nodes ; } } ) ; Object . defineProperty ( parent , 'nodes' , { configurable : true , set : function ( val ) { nodes = val ; } , get : function ( ) { return nodes ; } } ) ; utils . define ( node , 'parent' , parent ) ; parent . nodes . push ( node ) ; } ; this . addLexer ( fn ) ; return this ; }

Create a lexer for the given variable `type`.
@param {String} `type`
@return {Function}

Create a lexer for the given variable type .


function(type) {
    this.ast.tags[type] = null;
    this.names.push(type);

    var cached = this.regex.createTag(type);
    var file = this.file;
    var lexer = this;

    var fn = this.lexers[type] = function() {
      var pos = lexer.position();
      var m = lexer.match(cached.strict);
      if (!m) return;

      var name = utils.getName(m[1]);
      if (this.options.strict) {
        var isKnown = utils.has(lexer.known.tags, type);
        if (isKnown && file.hasOwnProperty(type) && !file.hasOwnProperty('isParsed')) {
          throw new Error(`only one "${type}" tag may be defined per template`);
        }
      }

      file[type] = name;
      lexer.ast.tags[type] = name;
      lexer.createNode(type, name, m, pos);
    };

    this.addLexer(fn);
    return this;
  }

function ( type ) { this . ast . tags [ type ] = null ; this . names . push ( type ) ; var cached = this . regex . createTag ( type ) ; var file = this . file ; var lexer = this ; var fn = this . lexers [ type ] = function ( ) { var pos = lexer . position ( ) ; var m = lexer . match ( cached . strict ) ; if ( ! m ) return ; var name = utils . getName ( m [ 1 ] ) ; if ( this . options . strict ) { var isKnown = utils . has ( lexer . known . tags , type ) ; if ( isKnown && file . hasOwnProperty ( type ) && ! file . hasOwnProperty ( 'isParsed' ) ) { throw new Error ( ` ${ type } ` ) ; } } file [ type ] = name ; lexer . ast . tags [ type ] = name ; lexer . createNode ( type , name , m , pos ) ; } ; this . addLexer ( fn ) ; return this ; }

Create a tag lexer for the given `type`.
@param {String} `type`
@return {Function}


function(type, name, m, pos) {
    var parent = this.prev();
    var val = m[1];
    var tok = { type: 'args', val: val };

    var node = pos({
      type: type,
      name: name,
      known: utils.has(this.known.tags, type),
      val: val.trim(),
      nodes: [tok]
    });

    utils.define(node, 'parent', parent);
    utils.define(tok, 'parent', node);
    parent.nodes.push(node);
  }

function ( type , name , m , pos ) { var parent = this . prev ( ) ; var val = m [ 1 ] ; var tok = { type : 'args' , val : val } ; var node = pos ( { type : type , name : name , known : utils . has ( this . known . tags , type ) , val : val . trim ( ) , nodes : [ tok ] } ) ; utils . define ( node , 'parent' , parent ) ; utils . define ( tok , 'parent' , node ) ; parent . nodes . push ( node ) ; }

Push AST node `type` onto `parent.nodes`
@param {String} `type`
@param {String} `name`
@param {String} `val`
@param {Function} `pos`


function(type) {
    this.names.push(type);
    var cached = this.regex.createOpen(type);
    var file = this.file;
    var lexer = this;

    return function() {
      var pos = lexer.position();
      var m = lexer.match(cached.strict);
      if (!m) return;

      var name = utils.getName(m[1]);
      var action = utils.getAction(m[1]);
      var val = m[0];

      if (!name && lexer.options[type] && lexer.options[type].args === 'required') {
        throw new Error(`no arguments defined on "${type}": ${m[0]}`);
      }

      if (!name) name = 'unnamed';
      var node = pos({
        type: `${type}.open`,
        known: utils.has(lexer.known.blocks, type),
        name: name,
        val: val.trim()
      });

      var parent = lexer.prev();
      if (parent && parent.name && parent.name !== 'root') {
        name = parent.name + '.' + name;
      }

      var block = {
        type: type,
        name: name,
        known: node.known,
        action: action,
        nodes: [node]
      };

      utils.define(node, 'parent', block);
      utils.define(block, 'parent', parent);
      block.rawArgs = m[1];
      block.args = utils.parseArgs(m[1]);

      Object.defineProperty(file.ast.blocks[type], name, {
        configurable: true,
        enumerable: true,
        set: function(val) {
          block = val;
        },
        get: function() {
          return block;
        }
      });

      parent.nodes.push(block);
      lexer.tokens.push(block);
      return block;
    };
  }

function ( type ) { this . names . push ( type ) ; var cached = this . regex . createOpen ( type ) ; var file = this . file ; var lexer = this ; return function ( ) { var pos = lexer . position ( ) ; var m = lexer . match ( cached . strict ) ; if ( ! m ) return ; var name = utils . getName ( m [ 1 ] ) ; var action = utils . getAction ( m [ 1 ] ) ; var val = m [ 0 ] ; if ( ! name && lexer . options [ type ] && lexer . options [ type ] . args === 'required' ) { throw new Error ( ` ${ type } ${ m [ 0 ] } ` ) ; } if ( ! name ) name = 'unnamed' ; var node = pos ( { type : ` ${ type } ` , known : utils . has ( lexer . known . blocks , type ) , name : name , val : val . trim ( ) } ) ; var parent = lexer . prev ( ) ; if ( parent && parent . name && parent . name !== 'root' ) { name = parent . name + '.' + name ; } var block = { type : type , name : name , known : node . known , action : action , nodes : [ node ] } ; utils . define ( node , 'parent' , block ) ; utils . define ( block , 'parent' , parent ) ; block . rawArgs = m [ 1 ] ; block . args = utils . parseArgs ( m [ 1 ] ) ; Object . defineProperty ( file . ast . blocks [ type ] , name , { configurable : true , enumerable : true , set : function ( val ) { block = val ; } , get : function ( ) { return block ; } } ) ; parent . nodes . push ( block ) ; lexer . tokens . push ( block ) ; return block ; } ; }

Create an opening tag lexer for block `name`.
@param {String} `name`
@return {Function}

Create an opening tag lexer for block name .