function encodeUserAuth(user) {
  if (!user) {
    return null;
  }

  var token = user.token;
  if (token) {
    var sha1 = typeof token === 'object' ? token.sha1 : token;
    return 'token ' + sha1;
  }

  return 'Basic ' + base64.encode(user.username + ':' + user.password)
}

function
encodeUserAuth
(
user
)
{
if
(
!
user
)
{
return
;
}
var
token
=
user
.
token
;
if
(
token
)
{
var
sha1
=
typeof
token
===
'object'
token
.
sha1
:
token
;
return
'token '
+
sha1
;
}
return
'Basic '
+
base64
.
encode
(
user
.
username
+
':'
+
user
.
password
)
}

Generates the authentication parameter for the user
Preference will be given to the token if it exists
@param user the use used for authentication. Requires token or username and password
@return {string|null} the properly formatted authentication string


function Vec4() {
        switch ( arguments.length ) {
            case 1:
                // array or VecN argument
                var argument = arguments[0];
                this.x = argument.x || argument[0] || 0.0;
                this.y = argument.y || argument[1] || 0.0;
                this.z = argument.z || argument[2] || 0.0;
                this.w = argument.w || argument[3] || 0.0;
                break;
            case 4:
                // individual component arguments
                this.x = arguments[0];
                this.y = arguments[1];
                this.z = arguments[2];
                this.w = arguments[3] || 0.0;
                break;
            default:
                this.x = 0.0;
                this.y = 0.0;
                this.z = 0.0;
                this.w = 0.0;
                break;
        }
    }

function Vec4 ( ) { switch ( arguments . length ) { case 1 : var argument = arguments [ 0 ] ; this . x = argument . x || argument [ 0 ] || 0.0 ; this . y = argument . y || argument [ 1 ] || 0.0 ; this . z = argument . z || argument [ 2 ] || 0.0 ; this . w = argument . w || argument [ 3 ] || 0.0 ; break ; case 4 : this . x = arguments [ 0 ] ; this . y = arguments [ 1 ] ; this . z = arguments [ 2 ] ; this . w = arguments [ 3 ] || 0.0 ; break ; default : this . x = 0.0 ; this . y = 0.0 ; this . z = 0.0 ; this . w = 0.0 ; break ; } }

Instantiates a Vec4 object.
@class Vec4
@classdesc A four component vector.


function create(EConstructor) {
  FormattedError.displayName = EConstructor.displayName || EConstructor.name

  return FormattedError

  function FormattedError(format) {
    if (format) {
      format = formatter.apply(null, arguments)
    }

    return new EConstructor(format)
  }
}

function create ( EConstructor ) { FormattedError . displayName = EConstructor . displayName || EConstructor . name return FormattedError function FormattedError ( format ) { if ( format ) { format = formatter . apply ( null , arguments ) } return new EConstructor ( format ) } }

Create a new `EConstructor`, with the formatted `format` as a first argument.

Create a new EConstructor with the formatted format as a first argument .


function Mat44( that ) {
        that = that || [
            1, 0, 0, 0,
            0, 1, 0, 0,
            0, 0, 1, 0,
            0, 0, 0, 1
        ];
        if ( that instanceof Array ) {
            this.data = that;
        } else {
            this.data = new Array( 16 );
            this.data[0] = that.data[0];
            this.data[1] = that.data[1];
            this.data[2] = that.data[2];
            this.data[3] = that.data[3];
            this.data[4] = that.data[4];
            this.data[5] = that.data[5];
            this.data[6] = that.data[6];
            this.data[7] = that.data[7];
            this.data[8] = that.data[8];
            this.data[9] = that.data[9];
            this.data[10] = that.data[10];
            this.data[11] = that.data[11];
            this.data[12] = that.data[12];
            this.data[13] = that.data[13];
            this.data[14] = that.data[14];
            this.data[15] = that.data[15];
        }
    }

function Mat44 ( that ) { that = that || [ 1 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 1 ] ; if ( that instanceof Array ) { this . data = that ; } else { this . data = new Array ( 16 ) ; this . data [ 0 ] = that . data [ 0 ] ; this . data [ 1 ] = that . data [ 1 ] ; this . data [ 2 ] = that . data [ 2 ] ; this . data [ 3 ] = that . data [ 3 ] ; this . data [ 4 ] = that . data [ 4 ] ; this . data [ 5 ] = that . data [ 5 ] ; this . data [ 6 ] = that . data [ 6 ] ; this . data [ 7 ] = that . data [ 7 ] ; this . data [ 8 ] = that . data [ 8 ] ; this . data [ 9 ] = that . data [ 9 ] ; this . data [ 10 ] = that . data [ 10 ] ; this . data [ 11 ] = that . data [ 11 ] ; this . data [ 12 ] = that . data [ 12 ] ; this . data [ 13 ] = that . data [ 13 ] ; this . data [ 14 ] = that . data [ 14 ] ; this . data [ 15 ] = that . data [ 15 ] ; } }

Instantiates a Mat44 object.
@class Mat44
@classdesc A 4x4 column-major matrix.


function Vec2() {
        switch ( arguments.length ) {
            case 1:
                // array or VecN argument
                var argument = arguments[0];
                this.x = argument.x || argument[0] || 0.0;
                this.y = argument.y || argument[1] || 0.0;
                break;
            case 2:
                // individual component arguments
                this.x = arguments[0];
                this.y = arguments[1];
                break;
            default:
                this.x = 0;
                this.y = 0;
                break;
        }
    }

function Vec2 ( ) { switch ( arguments . length ) { case 1 : var argument = arguments [ 0 ] ; this . x = argument . x || argument [ 0 ] || 0.0 ; this . y = argument . y || argument [ 1 ] || 0.0 ; break ; case 2 : this . x = arguments [ 0 ] ; this . y = arguments [ 1 ] ; break ; default : this . x = 0 ; this . y = 0 ; break ; } }

Instantiates a Vec2 object.
@class Vec2
@classdesc A two component vector.


function Quaternion() {
        switch ( arguments.length ) {
            case 1:
                // array or Quaternion argument
                var argument = arguments[0];
                if ( argument.w !== undefined ) {
                    this.w = argument.w;
                } else if ( argument[0] !== undefined ) {
                    this.w = argument[0];
                } else {
                    this.w = 1.0;
                }
                this.x = argument.x || argument[1] || 0.0;
                this.y = argument.y || argument[2] || 0.0;
                this.z = argument.z || argument[3] || 0.0;
                break;
            case 4:
                // individual component arguments
                this.w = arguments[0];
                this.x = arguments[1];
                this.y = arguments[2];
                this.z = arguments[3];
                break;
            default:
                this.w = 1;
                this.x = 0;
                this.y = 0;
                this.z = 0;
                break;
        }
    }

function Quaternion ( ) { switch ( arguments . length ) { case 1 : var argument = arguments [ 0 ] ; if ( argument . w !== undefined ) { this . w = argument . w ; } else if ( argument [ 0 ] !== undefined ) { this . w = argument [ 0 ] ; } else { this . w = 1.0 ; } this . x = argument . x || argument [ 1 ] || 0.0 ; this . y = argument . y || argument [ 2 ] || 0.0 ; this . z = argument . z || argument [ 3 ] || 0.0 ; break ; case 4 : this . w = arguments [ 0 ] ; this . x = arguments [ 1 ] ; this . y = arguments [ 2 ] ; this . z = arguments [ 3 ] ; break ; default : this . w = 1 ; this . x = 0 ; this . y = 0 ; this . z = 0 ; break ; } }

Instantiates a Quaternion object.
@class Quaternion
@classdesc A quaternion representing an orientation.


function Vec3() {
        switch ( arguments.length ) {
            case 1:
                // array or VecN argument
                var argument = arguments[0];
                this.x = argument.x || argument[0] || 0.0;
                this.y = argument.y || argument[1] || 0.0;
                this.z = argument.z || argument[2] || 0.0;
                break;
            case 3:
                // individual component arguments
                this.x = arguments[0];
                this.y = arguments[1];
                this.z = arguments[2];
                break;
            default:
                this.x = 0.0;
                this.y = 0.0;
                this.z = 0.0;
                break;
        }
    }

function Vec3 ( ) { switch ( arguments . length ) { case 1 : var argument = arguments [ 0 ] ; this . x = argument . x || argument [ 0 ] || 0.0 ; this . y = argument . y || argument [ 1 ] || 0.0 ; this . z = argument . z || argument [ 2 ] || 0.0 ; break ; case 3 : this . x = arguments [ 0 ] ; this . y = arguments [ 1 ] ; this . z = arguments [ 2 ] ; break ; default : this . x = 0.0 ; this . y = 0.0 ; this . z = 0.0 ; break ; } }

Instantiates a Vec3 object.
@class Vec3
@classdesc A three component vector.


function() {
		if (!document.getElementById("snackbar-container")) {
			var snackbarContainer = document.createElement("div");

			snackbarContainer.setAttribute("id", "snackbar-container");

			document.body.appendChild(snackbarContainer);
		}
	}

function ( ) { if ( ! document . getElementById ( "snackbar-container" ) ) { var snackbarContainer = document . createElement ( "div" ) ; snackbarContainer . setAttribute ( "id" , "snackbar-container" ) ; document . body . appendChild ( snackbarContainer ) ; } }

Create container for the snackbar

@return {void}


function(element) {
		var __self = this;
		// Adding event listener for when user clicks on the snackbar to remove it
		element.addEventListener("click", function(){
			if (typeof __self.callback == "function") {
				__self.callback();
			}
			element.setAttribute("class", "snackbar");
	    	__self.destroy(element);
		});

		// Stopping the timer when user hovers on the snackbar
		element.addEventListener("mouseenter",function(){
			__self.timer.pause();
		});
		element.addEventListener("mouseout",function(){
			__self.timer.resume();
		});
	}

function ( element ) { var __self = this ; element . addEventListener ( "click" , function ( ) { if ( typeof __self . callback == "function" ) { __self . callback ( ) ; } element . setAttribute ( "class" , "snackbar" ) ; __self . destroy ( element ) ; } ) ; element . addEventListener ( "mouseenter" , function ( ) { __self . timer . pause ( ) ; } ) ; element . addEventListener ( "mouseout" , function ( ) { __self . timer . resume ( ) ; } ) ; }

Activate the listeners

@param  {Object} element
@return {void}


function(newOptions) {
		var __self = this,
  			options = newOptions || {};

    	for (var opt in this.options) {
        	if (__self.options.hasOwnProperty(opt) && !options.hasOwnProperty(opt)) {
            	options[opt] = __self.options[opt];
        	}
        }
       	return options;
	}

function ( newOptions ) { var __self = this , options = newOptions || { } ; for ( var opt in this . options ) { if ( __self . options . hasOwnProperty ( opt ) && ! options . hasOwnProperty ( opt ) ) { options [ opt ] = __self . options [ opt ] ; } } return options ; }

Compare the options to the default ones.

@param  {Object} newOptions
@return {Object}

Compare the options to the default ones .


function(Vue){
		var __self = this;
		Vue.prototype.$snackbar = {};
	  	Vue.prototype.$snackbar.create = function(data, options, callback){
	  		__self.create(data, options, callback);
	  	};
	}

function ( Vue ) { var __self = this ; Vue . prototype . $snackbar = { } ; Vue . prototype . $snackbar . create = function ( data , options , callback ) { __self . create ( data , options , callback ) ; } ; }

Install function for Vue

@param  {Object} Vue
@return {void}


function Transform( that ) {
        that = that || {};
        if ( that.data instanceof Array ) {
            // Mat33 or Mat44, extract transform components
            that = that.decompose();
            this.rotation = that.rotation;
            this.translation = that.translation || new Vec3();
            this.scale = that.scale;
        } else {
            // set individual components, by value
            this.rotation = that.rotation ? new Quaternion( that.rotation ) : new Quaternion();
            this.translation = that.translation ? new Vec3( that.translation ) : new Vec3();
            if ( typeof that.scale === 'number' ) {
                this.scale = new Vec3( that.scale, that.scale, that.scale );
            } else {
                this.scale = that.scale ? new Vec3( that.scale ) : new Vec3( 1, 1, 1 );
            }
        }
    }

function Transform ( that ) { that = that || { } ; if ( that . data instanceof Array ) { that = that . decompose ( ) ; this . rotation = that . rotation ; this . translation = that . translation || new Vec3 ( ) ; this . scale = that . scale ; } else { this . rotation = that . rotation ? new Quaternion ( that . rotation ) : new Quaternion ( ) ; this . translation = that . translation ? new Vec3 ( that . translation ) : new Vec3 ( ) ; if ( typeof that . scale === 'number' ) { this . scale = new Vec3 ( that . scale , that . scale , that . scale ) ; } else { this . scale = that . scale ? new Vec3 ( that . scale ) : new Vec3 ( 1 , 1 , 1 ) ; } } }

Instantiates a Transform object.
@class Transform
@classdesc A transform representing an orientation, position, and scale.


function Triangle() {
        switch ( arguments.length ) {
            case 1:
                // array or object argument
                var arg = arguments[0];
                this.a = new Vec3( arg[0] || arg.a );
                this.b = new Vec3( arg[1] || arg.b );
                this.c = new Vec3( arg[2] || arg.c );
                break;
            case 3:
                // individual vector arguments
                this.a = new Vec3( arguments[0] );
                this.b = new Vec3( arguments[1] );
                this.c = new Vec3( arguments[2] );
                break;
            default:
                this.a = new Vec3( 0, 0, 0 );
                this.b = new Vec3( 1, 0, 0 );
                this.c = new Vec3( 1, 1, 0 );
                break;
        }
    }

function Triangle ( ) { switch ( arguments . length ) { case 1 : var arg = arguments [ 0 ] ; this . a = new Vec3 ( arg [ 0 ] || arg . a ) ; this . b = new Vec3 ( arg [ 1 ] || arg . b ) ; this . c = new Vec3 ( arg [ 2 ] || arg . c ) ; break ; case 3 : this . a = new Vec3 ( arguments [ 0 ] ) ; this . b = new Vec3 ( arguments [ 1 ] ) ; this . c = new Vec3 ( arguments [ 2 ] ) ; break ; default : this . a = new Vec3 ( 0 , 0 , 0 ) ; this . b = new Vec3 ( 1 , 0 , 0 ) ; this . c = new Vec3 ( 1 , 1 , 0 ) ; break ; } }

Instantiates a Triangle object.
@class Triangle
@classdesc A CCW-winded triangle object.


function bash(str, pattern, options) {
  if (typeof str !== 'string') {
    throw new TypeError('expected a string');
  }
  if (typeof pattern !== 'string') {
    throw new TypeError('expected a string');
  }

  if (isWindows()) {
    throw new Error('bash-match does not work on windows');
  }

  try {
    var opts = createOptions(pattern, options);
    var res = spawn.sync(getBashPath(), cmd(str, pattern, opts), opts);
    var err = toString(res.stderr);
    if (err) {
      return handleError(err, opts);
    }
    return !!toString(res.stdout);
  } catch (err) {
    return handleError(err, opts);
  }
}

function
bash
(
str
,
pattern
,
options
)
{
if
(
typeof
str
!==
'string'
)
{
throw
new
TypeError
(
'expected a string'
)
;
}
if
(
typeof
pattern
!==
'string'
)
{
throw
new
TypeError
(
'expected a string'
)
;
}
if
(
isWindows
(
)
)
{
throw
new
Error
(
'bash-match does not work on windows'
)
;
}
try
{
var
opts
=
createOptions
(
pattern
,
options
)
;
var
res
=
spawn
.
sync
(
getBashPath
(
)
,
cmd
(
str
,
pattern
,
opts
)
,
opts
)
;
var
err
=
toString
(
res
.
stderr
)
;
if
(
err
)
{
return
handleError
(
err
,
opts
)
;
}
return
!
!
toString
(
res
.
stdout
)
;
}
catch
(
err
)
{
return
handleError
(
err
,
opts
)
;
}
}

Returns true if `str` matches the given `pattern`.

```js
var bash = require('bash-match');
console.log(bash('foo', 'f*'));
//=> true

console.log(bash('foo', 'b*'));
//=> false
```

@param {String} `str`
@param {String} `pattern`
@param {Options} `options` Set `strictErrors` to true to throw when bash throws an error. Otherwise it just returns false.
@return {Boolean}
@details false
@api public

Returns true if str matches the given pattern .


function cmd(str, pattern, options) {
  var valid = ['dotglob', 'extglob', 'failglob', 'globstar', 'nocaseglob', 'nullglob'];
  var args = [];

  for (var key in options) {
    if (options.hasOwnProperty(key) && valid.indexOf(key) !== -1) {
      args.push('-O', key);
    }
  }
  args.push('-c', 'IFS=$"\n"; if [[ "' + str + '" = ' + pattern + ' ]]; then echo true; fi');
  return args;
}

function
cmd
(
str
,
pattern
,
options
)
{
var
valid
=
[
'dotglob'
,
'extglob'
,
'failglob'
,
'globstar'
,
'nocaseglob'
,
'nullglob'
]
;
var
args
=
[
]
;
for
(
var
key
in
options
)
{
if
(
options
.
hasOwnProperty
(
key
)
&&
valid
.
indexOf
(
key
)
!==
1
)
{
args
.
push
(
'-O'
,
key
)
;
}
}
args
.
push
(
'-c'
,
'IFS=$"\n"; if [[ "'
+
\n
+
str
+
'" = '
+
pattern
)
;
' ]]; then echo true; fi'
}


function createOptions(pattern, options) {
  if (options && options.normalized === true) return options;
  var opts = extend({cwd: process.cwd()}, options);
  if (opts.nocase === true) opts.nocaseglob = true;
  if (opts.nonull === true) opts.nullglob = true;
  if (opts.dot === true) opts.dotglob = true;
  if (!opts.hasOwnProperty('globstar') && pattern.indexOf('**') !== -1) {
    opts.globstar = true;
  }
  if (!opts.hasOwnProperty('extglob') && isExtglob(pattern)) {
    opts.extglob = true;
  }
  opts.normalized = true;
  return opts;
}

function createOptions ( pattern , options ) { if ( options && options . normalized === true ) return options ; var opts = extend ( { cwd : process . cwd ( ) } , options ) ; if ( opts . nocase === true ) opts . nocaseglob = true ; if ( opts . nonull === true ) opts . nullglob = true ; if ( opts . dot === true ) opts . dotglob = true ; if ( ! opts . hasOwnProperty ( 'globstar' ) && pattern . indexOf ( '**' ) !== - 1 ) { opts . globstar = true ; } if ( ! opts . hasOwnProperty ( 'extglob' ) && isExtglob ( pattern ) ) { opts . extglob = true ; } opts . normalized = true ; return opts ; }


function getBashPath() {
  if (bashPath) return bashPath;
  if (fs.existsSync('/usr/local/bin/bash')) {
    bashPath = '/usr/local/bin/bash';
  } else if (fs.existsSync('/bin/bash')) {
    bashPath = '/bin/bash';
  } else {
    bashPath = 'bash';
  }
  return bashPath;
}

function getBashPath ( ) { if ( bashPath ) return bashPath ; if ( fs . existsSync ( '/usr/local/bin/bash' ) ) { bashPath = '/usr/local/bin/bash' ; } else if ( fs . existsSync ( '/bin/bash' ) ) { bashPath = '/bin/bash' ; } else { bashPath = 'bash' ; } return bashPath ; }


function Memory(options) {
  options = options || {};
  var self = this;
  self.flush = options.db._db._memory.flush || false;
  self.flushInterval = options.db._db._memory.flushInterval || 10000;
  self.flushFile = options.file;
  self.memoryTable = [];
  console.log('Data will be handled using \'Memory\' driver');
  // :S yeah we need to load it synchronously otherwise it might be loaded after the first insert
  var content = util.fileSystem.readSync(self.flushFile);
  self.set(content);
  if (self.flush) {
    console.log('\'Memory\' driver will flush data every %sms', self.flushInterval);
    // set interval to flush
    setInterval(function flushToDisk() {
      util.fileSystem.lock(self.flushFile, function afterLock(err) {
        if (err) {
          throw err;
        }
        self.get(function afterGet(err, inMemoryContent) {
          if (err) {
            util.fileSystem.unlock(self.flushFile);
            throw err;
          }
          util.fileSystem.write(self.flushFile, inMemoryContent, function afterWrite(err) {
            util.fileSystem.unlock(self.flushFile);
            if (err) {
              throw err;
            }
          });
        });
      });
    }, self.flushInterval);
  }
}

Provides in memory storage and regular flush to disk.

@param {object} options
@param {object}  options.db
@param {float}  options.db._flush
@param {string}  options.file
@constructor

Provides in memory storage and regular flush to disk .


function deductcost() {
  var cost = [];
  if (!giving.have || giving.have.length < 1) return;

  // flatten
  var cost = [];
  for (var i = 0; i < giving.have.length; i++) {
    for (var j = 0; j < giving.have[i].length; j++) {
      cost.push(giving.have[i][j]);
    }
  }
  if (typeof cost[0] === 'string') cost = [cost];

  function deduct(from, amt) {
    var current = parseInt(from.getAttribute('data-quantity'));
    current -= amt;
    from.setAttribute('data-quantity', current);
    updateAmounts(from);
    if (current < 1) {
      from.setAttribute('data-type', 'none');
      from.innerHTML = '';
    }
  }

  [].forEach.call(craftable.querySelectorAll('li'), function(li, i) {
    var row = Math.floor(i / 3);
    var has = (li.getAttribute('data-type') || 'none').toLowerCase();
    for (var c = 0; c < cost.length; c++) {
      if (cost[c][0].toLowerCase() === has) {
        var price = cost[c][1];
        cost.splice(c, 1);
        deduct(li, price);
        return false;
      }
    }
  });
}

function deductcost ( ) { var cost = [ ] ; if ( ! giving . have || giving . have . length < 1 ) return ; var cost = [ ] ; for ( var i = 0 ; i < giving . have . length ; i ++ ) { for ( var j = 0 ; j < giving . have [ i ] . length ; j ++ ) { cost . push ( giving . have [ i ] [ j ] ) ; } } if ( typeof cost [ 0 ] === 'string' ) cost = [ cost ] ; function deduct ( from , amt ) { var current = parseInt ( from . getAttribute ( 'data-quantity' ) ) ; current -= amt ; from . setAttribute ( 'data-quantity' , current ) ; updateAmounts ( from ) ; if ( current < 1 ) { from . setAttribute ( 'data-type' , 'none' ) ; from . innerHTML = '' ; } } [ ] . forEach . call ( craftable . querySelectorAll ( 'li' ) , function ( li , i ) { var row = Math . floor ( i / 3 ) ; var has = ( li . getAttribute ( 'data-type' ) || 'none' ) . toLowerCase ( ) ; for ( var c = 0 ; c < cost . length ; c ++ ) { if ( cost [ c ] [ 0 ] . toLowerCase ( ) === has ) { var price = cost [ c ] [ 1 ] ; cost . splice ( c , 1 ) ; deduct ( li , price ) ; return false ; } } } ) ; }

removes the items from craftable if result is picked up


function (sub_node) {
                if ( sub_node ) {
                    walk(sub_node, depth + 1);

                } else if ( node.pages ) {
                    node.pages.forEach(function (sub_node, name) {
                        walk(sub_node, depth + 1);
                    });
                }
            }

function ( sub_node ) { if ( sub_node ) { walk ( sub_node , depth + 1 ) ; } else if ( node . pages ) { node . pages . forEach ( function ( sub_node , name ) { walk ( sub_node , depth + 1 ) ; } ) ; } }


function(provides) {
		if (_.isArray(provides)) {
			this._arguments = this._provides = (!this._provides) ? provides : this._provides.concat(provides);
		} else {
			this._provides = _.extend({}, this._provides, provides);
			this._arguments = _.map(this.deps, function(key) {
				return this._provides[key];
			}, this);
		}
		return this;
	}

function ( provides ) { if ( _ . isArray ( provides ) ) { this . _arguments = this . _provides = ( ! this . _provides ) ? provides : this . _provides . concat ( provides ) ; } else { this . _provides = _ . extend ( { } , this . _provides , provides ) ; this . _arguments = _ . map ( this . deps , function ( key ) { return this . _provides [ key ] ; } , this ) ; } return this ; }

Registers dependencies that can be provided to the function
@param  {Object|Array} provides map of key: value pairs or an array of values
@return {Wrapper} this instance


function(context, callback) {
		if (arguments.length === 1) {
			callback = context;
			context = this._context;
		}
		if (this.isAsync) {
			// clone the arguments so this.call can be reused with different callbacks
			var asyncArgs = this._arguments.slice();
			// push the callback onto the new arguments array
			asyncArgs.push(callback);
			// call the function
			this.fn.apply(context, asyncArgs);
		} else {
			// if the function isn't async, allow it to be called with or without a callback
			if (callback) {
				// If a callback is provided, it must use the error-first arguments pattern.
				// The return value of the function will be the second argument.
				try {
					callback(null, this.fn.apply(context, this._arguments));
				} catch(e) {
					callback(e);
				}
			} else {
				// If no callback is provided simply return the result of the function
				return this.fn.apply(context, this._arguments);
			}
		}
	}

function ( context , callback ) { if ( arguments . length === 1 ) { callback = context ; context = this . _context ; } if ( this . isAsync ) { var asyncArgs = this . _arguments . slice ( ) ; asyncArgs . push ( callback ) ; this . fn . apply ( context , asyncArgs ) ; } else { if ( callback ) { try { callback ( null , this . fn . apply ( context , this . _arguments ) ) ; } catch ( e ) { callback ( e ) ; } } else { return this . fn . apply ( context , this . _arguments ) ; } } }

Calls the function

Will return the result if not async and no callback is provided

@param  {Object} context (optional)
@param  {Function} callback


function each(arr, callback) {
		var wrapper = this;
		if (this.isAsync) {
			return async.each(arr, function(item, cb) {
				wrapper.call(item, cb);
			}, callback);
		} else {
			arr.each(function(item) {
				wrapper.call(item);
			});
			if (callback) { callback(); }
		}
	}

function each ( arr , callback ) { var wrapper = this ; if ( this . isAsync ) { return async . each ( arr , function ( item , cb ) { wrapper . call ( item , cb ) ; } , callback ) ; } else { arr . each ( function ( item ) { wrapper . call ( item ) ; } ) ; if ( callback ) { callback ( ) ; } } }

Applies the function iterator to each item in arr, in parallel.

The context of the function will be the current item in the array.

@param  {Array} arr
@param  {Function} callback

Applies the function iterator to each item in arr in parallel .


function map(arr, callback) {
		var wrapper = this;
		if (this.isAsync) {
			async.map(arr, function(item, cb) {
				wrapper.call(item, cb);
			}, callback);
		} else {
			callback(null, arr.map(function(item) {
				return wrapper.call(item);
			}));
		}
	}

function map ( arr , callback ) { var wrapper = this ; if ( this . isAsync ) { async . map ( arr , function ( item , cb ) { wrapper . call ( item , cb ) ; } , callback ) ; } else { callback ( null , arr . map ( function ( item ) { return wrapper . call ( item ) ; } ) ) ; } }

Returns the results of interating the function on each item in an array.

The context of the function will be the current item in the array.

@param  {Array} arr
@param  {Function} callback
@return {Array}

Returns the results of interating the function on each item in an array .


function(selectedDates, dateStr, instance) {
					that.setProperty("dateValue", selectedDates, true);
					that.fireOnChange({selectedDates: selectedDates, dateStr: dateStr, instance: instance});
				}

function ( selectedDates , dateStr , instance ) { that . setProperty ( "dateValue" , selectedDates , true ) ; that . fireOnChange ( { selectedDates : selectedDates , dateStr : dateStr , instance : instance } ) ; }

force wrap to true defining events callback


function startServer(options) {

  options = initOptions(options);

  var app = connect()
    , root = options.root
    , TEST = process.env.TEST
    , isSilent = options.silent || TEST;

  if (!isSilent) {
    app.use(log);
  }

  var smOpts = {};
  var smOptMap = {
    ftpl: 'template'
    , style: 'style'
  };
  Object.keys(smOptMap).forEach(function (key) {
    if (options[key] !== undefined) smOpts[smOptMap[key]] = options[key];
  });

  // serve markdown file
  app.use(serveMarkdown(root, smOpts));
  // common files
  app.use(serveStatic(root, {index: ['index.html']}));

  // serve directory
  app.use(serveIndex(root, {
    icon: true
    , template: options.dtpl
    , stylesheet: options.style
    , view: options.view
  }));

  debug('server run in ' + (process.env.TEST ? 'TEST' : 'PRODUCTION') + ' mode')
  if (!TEST) {
    app.listen(options.port);
    showSuccessInfo(options);
  }

  return app;
}

function
startServer
(
options
)
{
options
=
initOptions
(
options
)
;
var
app
=
connect
(
)
,
root
=
options
.
root
,
TEST
=
process
.
env
.
TEST
,
isSilent
=
options
.
silent
||
TEST
;
if
(
!
isSilent
)
{
app
.
use
(
log
)
;
}
var
smOpts
=
{
}
;
var
smOptMap
=
{
ftpl
:
'template'
,
style
:
'style'
}
;
Object
.
keys
(
smOptMap
)
.
forEach
(
function
(
key
)
{
if
(
options
[
key
]
!==
undefined
)
smOpts
[
smOptMap
[
key
]
]
=
options
[
key
]
;
}
)
;
app
.
use
(
serveMarkdown
(
root
,
smOpts
)
)
;
app
.
use
(
serveStatic
(
root
,
{
index
:
[
'index.html'
]
}
)
)
;
app
.
use
(
serveIndex
(
root
,
{
icon
:
true
,
template
:
options
.
dtpl
,
stylesheet
:
options
.
style
,
view
:
options
.
view
}
)
)
;
debug
(
'server run in '
+
(
process
.
env
.
TEST
'TEST'
:
'PRODUCTION'
)
+
' mode'
)
if
(
!
TEST
)
{
app
.
listen
(
options
.
port
)
;
showSuccessInfo
(
options
)
;
}
return
app
;
}


function showSuccessInfo(options) {

  // server start success
  if (options.silent) return;

  console.log(chalk.blue('serve start Success: ')
      + '\n'
      + chalk.green('\t url   ')
      + chalk.grey('http://127.0.0.1:')
      + chalk.red(options.port)
      + chalk.grey('/')
      + '\n'
      + chalk.green('\t serve ')
      + chalk.grey(options.root)
  );

}

function
showSuccessInfo
(
options
)
{
if
(
options
.
silent
)
return
;
console
.
log
(
chalk
.
blue
(
'serve start Success: '
)
+
'\n'
+
\n
+
chalk
.
green
(
'\t url   '
)
+
\t
+
chalk
.
grey
(
'http://127.0.0.1:'
)
+
chalk
.
red
(
options
.
port
)
+
chalk
.
grey
(
'/'
)
+
'\n'
)
;
}


function log(req, res, next) {
  console.log('['
      + chalk.grey(ts())
      + '] '
      + chalk.white(decodeURI(req.url))
  );
  next();
}

function
log
(
req
,
res
,
next
)
{
console
.
log
(
'['
+
chalk
.
grey
(
ts
(
)
)
+
'] '
+
chalk
.
white
(
decodeURI
(
req
.
url
)
)
)
;
next
(
)
;
}

simple log middleware, output the access log

simple log middleware output the access log


function (valueToSet, type, iface, propertyKeys) {
    type = type.toLowerCase();
    propertyKeys.forEach(function(propertyKey) {
      if(type == 'get')
        valueToSet['Get'+propertyKey] = function (callback) {
          iface.getProperty(propertyKey, callback);
        }
      else
        valueToSet['Set'+propertyKey] = function (value, callback) {
          iface.setProperty(propertyKey, value, callback);
        }
    });
}

function ( valueToSet , type , iface , propertyKeys ) { type = type . toLowerCase ( ) ; propertyKeys . forEach ( function ( propertyKey ) { if ( type == 'get' ) valueToSet [ 'Get' + propertyKey ] = function ( callback ) { iface . getProperty ( propertyKey , callback ) ; } else valueToSet [ 'Set' + propertyKey ] = function ( value , callback ) { iface . setProperty ( propertyKey , value , callback ) ; } } ) ; }


function init(user_id,secret,storage) {
    API_USER_ID=user_id;
    API_SECRET=secret;
    TOKEN_STORAGE=storage;

    var hashName = md5(API_USER_ID+'::'+API_SECRET);
    if (fs.existsSync(TOKEN_STORAGE+hashName)) {
        TOKEN = fs.readFileSync(TOKEN_STORAGE+hashName,{encoding:'utf8'});
    }

    if (! TOKEN.length) {
        getToken();
    }
}

function init ( user_id , secret , storage ) { API_USER_ID = user_id ; API_SECRET = secret ; TOKEN_STORAGE = storage ; var hashName = md5 ( API_USER_ID + '::' + API_SECRET ) ; if ( fs . existsSync ( TOKEN_STORAGE + hashName ) ) { TOKEN = fs . readFileSync ( TOKEN_STORAGE + hashName , { encoding : 'utf8' } ) ; } if ( ! TOKEN . length ) { getToken ( ) ; } }

Sendpulse API initialization

@param userId
@param secret
@param storage


function sendRequest(path, method, data, useToken, callback){
    var headers = {}
    headers['Content-Type'] = 'application/json';
    headers['Content-Length'] =  Buffer.byteLength(JSON.stringify(data));

    if (useToken && TOKEN.length) {
        headers['Authorization'] = 'Bearer '+TOKEN;
    }
    if (method === undefined) {
        method = 'POST';
    }
    if (useToken === undefined) {
        useToken = false;
    }

    var options = {
        //uri: API_URL,
        path: '/'+path,
        port: 443,
        hostname: API_URL,
        method: method,
        headers: headers,
    };

    var req = https.request(
        options,
        function(response) {
            var str = '';
            response.on('data', function (chunk) {
                if (response.statusCode==401) {
                    getToken();
                    sendRequest(path, method, data, true, callback);
                } else {
                    str += chunk;
                }
            });

            response.on('end', function () {
                if (response.statusCode != 401) {
                    try {
                        var answer = JSON.parse(str);
                    } catch (ex) {
                        var answer = returnError();
                    }
                    callback(answer);
                }
            });
        }
    );
    req.write(JSON.stringify(data));
    req.end();
}

function
sendRequest
(
path
,
method
,
data
,
useToken
,
callback
)
{
var
headers
=
{
}
headers
[
'Content-Type'
]
=
'application/json'
;
headers
[
'Content-Length'
]
=
Buffer
.
byteLength
(
JSON
.
stringify
(
data
)
)
;
if
(
useToken
&&
TOKEN
.
length
)
{
headers
[
'Authorization'
]
=
'Bearer '
+
TOKEN
;
}
if
(
method
===
undefined
)
{
method
=
'POST'
;
}
if
(
useToken
===
undefined
)
{
useToken
=
false
;
}
var
options
=
{
path
:
'/'
+
path
,
port
:
443
,
hostname
:
API_URL
,
method
:
method
,
headers
:
headers
,
}
;
var
req
=
https
.
request
(
options
,
function
(
response
)
{
var
str
=
''
;
response
.
on
(
'data'
,
function
(
chunk
)
{
if
(
response
.
statusCode
==
401
)
{
getToken
(
)
;
sendRequest
(
path
,
method
,
data
,
true
,
callback
)
;
}
else
{
str
+=
chunk
;
}
}
)
;
response
.
on
(
'end'
,
function
(
)
{
if
(
response
.
statusCode
!=
401
)
{
try
{
var
answer
=
JSON
.
parse
(
str
)
;
}
catch
(
ex
)
{
var
answer
=
returnError
(
)
;
}
callback
(
answer
)
;
}
}
)
;
}
)
;
req
.
write
(
JSON
.
stringify
(
data
)
)
;
req
.
end
(
)
;
}

Form and send request to API service

@param path
@param method
@param data
@param useToken
@param callback
Define the function  that will be called
when a response is received.


function getToken(){
    var data={
        grant_type:'client_credentials',
        client_id: API_USER_ID,
        client_secret: API_SECRET
    }
    sendRequest( 'oauth/access_token', 'POST', data, false, saveToken );
    function saveToken(data) {
        TOKEN = data.access_token;
        var hashName = md5(API_USER_ID+'::'+API_SECRET);
        fs.writeFileSync(TOKEN_STORAGE+hashName, TOKEN);
    }
}

function getToken ( ) { var data = { grant_type : 'client_credentials' , client_id : API_USER_ID , client_secret : API_SECRET } sendRequest ( 'oauth/access_token' , 'POST' , data , false , saveToken ) ; function saveToken ( data ) { TOKEN = data . access_token ; var hashName = md5 ( API_USER_ID + '::' + API_SECRET ) ; fs . writeFileSync ( TOKEN_STORAGE + hashName , TOKEN ) ; } }


function returnError(message){
    var data = {is_error:1};
    if (message !== undefined && message.length) {
        data['message'] = message
    }
    return data;
}

function returnError ( message ) { var data = { is_error : 1 } ; if ( message !== undefined && message . length ) { data [ 'message' ] = message } return data ; }


function createAddressBook(callback,bookName) {
    if ((bookName === undefined) || (! bookName.length)) {
        return callback(returnError("Empty book name"));
    }
    var data = {bookName: bookName};
    sendRequest( 'addressbooks', 'POST', data, true, callback );
}

function
createAddressBook
(
callback
,
bookName
)
{
if
(
(
bookName
===
undefined
)
||
(
!
bookName
.
length
)
)
{
return
callback
(
returnError
(
"Empty book name"
)
)
;
}
var
data
=
{
bookName
:
bookName
}
;
sendRequest
(
'addressbooks'
,
'POST'
,
data
,
true
,
callback
)
;
}

Create address book

@param callback
@param bookName


function editAddressBook(callback,id,bookName) {
    if ((id===undefined) || (bookName === undefined) || (! bookName.length)) {
        return callback(returnError("Empty book name or book id"));
    }
    var data = {name: bookName};
    sendRequest( 'addressbooks/' + id, 'PUT', data, true, callback );
}

function
editAddressBook
(
callback
,
id
,
bookName
)
{
if
(
(
id
===
undefined
)
||
(
bookName
===
undefined
)
||
(
!
bookName
.
length
)
)
{
return
callback
(
returnError
(
"Empty book name or book id"
)
)
;
}
var
data
=
{
name
:
bookName
}
;
sendRequest
(
'addressbooks/'
+
id
,
'PUT'
,
data
,
true
,
callback
)
;
}

Edit address book name

@param callback
@param id
@param bookName


function removeAddressBook(callback,id){
    if (id===undefined) {
        return callback(returnError('Empty book id'));
    }
    sendRequest( 'addressbooks/' + id, 'DELETE', {}, true, callback );
}

function
removeAddressBook
(
callback
,
id
)
{
if
(
id
===
undefined
)
{
return
callback
(
returnError
(
'Empty book id'
)
)
;
}
sendRequest
(
'addressbooks/'
+
id
,
'DELETE'
,
{
}
,
true
,
callback
)
;
}

Remove address book

@param callback
@param id


function getBookInfo(callback,id){
    if (id===undefined) {
        return callback(returnError('Empty book id'));
    }
    sendRequest( 'addressbooks/' + id, 'GET', {}, true, callback );
}

function
getBookInfo
(
callback
,
id
)
{
if
(
id
===
undefined
)
{
return
callback
(
returnError
(
'Empty book id'
)
)
;
}
sendRequest
(
'addressbooks/'
+
id
,
'GET'
,
{
}
,
true
,
callback
)
;
}

Get information about book

@param callback
@param id


function getEmailsFromBook(callback,id){
    if (id===undefined) {
        return callback(returnError('Empty book id'));
    }
    sendRequest( 'addressbooks/' + id + '/emails', 'GET', {}, true, callback );
}

function
getEmailsFromBook
(
callback
,
id
)
{
if
(
id
===
undefined
)
{
return
callback
(
returnError
(
'Empty book id'
)
)
;
}
sendRequest
(
'addressbooks/'
+
id
+
'/emails'
,
'GET'
,
{
}
,
true
,
callback
)
;
}

List email addresses from book

@param callback
@param id


function addEmails(callback,id,emails){
    if ((id===undefined) || (emails === undefined) || (! emails.length)) {
        return callback(returnError("Empty email or book id"));
    }
    var data = {emails: serialize(emails)};
    sendRequest( 'addressbooks/' + id + '/emails', 'POST', data, true, callback );
}

function
addEmails
(
callback
,
id
,
emails
)
{
if
(
(
id
===
undefined
)
||
(
emails
===
undefined
)
||
(
!
emails
.
length
)
)
{
return
callback
(
returnError
(
"Empty email or book id"
)
)
;
}
var
data
=
{
emails
:
serialize
(
emails
)
}
;
sendRequest
(
'addressbooks/'
+
id
+
'/emails'
,
'POST'
,
data
,
true
,
callback
)
;
}

Add new emails to address book

@param callback
@param id
@param emails


function getEmailInfo(callback,id,email){
    if ((id===undefined) || (email === undefined) || (! email.length)) {
        return callback(returnError("Empty email or book id"));
    }
    sendRequest( 'addressbooks/' + id + '/emails/' + email, 'GET', {}, true, callback );

}

function
getEmailInfo
(
callback
,
id
,
email
)
{
if
(
(
id
===
undefined
)
||
(
email
===
undefined
)
||
(
!
email
.
length
)
)
{
return
callback
(
returnError
(
"Empty email or book id"
)
)
;
}
sendRequest
(
'addressbooks/'
+
id
+
'/emails/'
+
email
,
'GET'
,
{
}
,
true
,
callback
)
;
}

Get information about email address from book

@param callback
@param id
@param email


function campaignCost(callback,id) {
    if (id===undefined) {
        return callback(returnError('Empty book id'));
    }
    sendRequest( 'addressbooks/' + id + '/cost', 'GET', {}, true, callback );

}

function
campaignCost
(
callback
,
id
)
{
if
(
id
===
undefined
)
{
return
callback
(
returnError
(
'Empty book id'
)
)
;
}
sendRequest
(
'addressbooks/'
+
id
+
'/cost'
,
'GET'
,
{
}
,
true
,
callback
)
;
}

Get cost of campaign based on address book

@param callback
@param id


function listCampaigns(callback,limit,offset){
    var data={}
    if (limit === undefined) {
        limit = null;
    } else {
        data['limit'] = limit;
    }
    if (offset === undefined) {
        offset = null;
    } else {
        data['offset'] = offset;
    }
    sendRequest('campaigns', 'GET', data, true, callback);
}

function listCampaigns ( callback , limit , offset ) { var data = { } if ( limit === undefined ) { limit = null ; } else { data [ 'limit' ] = limit ; } if ( offset === undefined ) { offset = null ; } else { data [ 'offset' ] = offset ; } sendRequest ( 'campaigns' , 'GET' , data , true , callback ) ; }

Get list of campaigns

@param callback
@param limit
@param offset


function getCampaignInfo(callback,id){
    if (id===undefined) {
        return callback(returnError('Empty book id'));
    }
    sendRequest( 'campaigns/' + id, 'GET', {}, true, callback );
}

function
getCampaignInfo
(
callback
,
id
)
{
if
(
id
===
undefined
)
{
return
callback
(
returnError
(
'Empty book id'
)
)
;
}
sendRequest
(
'campaigns/'
+
id
,
'GET'
,
{
}
,
true
,
callback
)
;
}

Get information about campaign

@param callback
@param id


function campaignStatByCountries(callback,id){
    if (id===undefined) {
        return callback(returnError('Empty book id'));
    }
    sendRequest( 'campaigns/' + id + '/countries', 'GET', {}, true, callback );
}

function
campaignStatByCountries
(
callback
,
id
)
{
if
(
id
===
undefined
)
{
return
callback
(
returnError
(
'Empty book id'
)
)
;
}
sendRequest
(
'campaigns/'
+
id
+
'/countries'
,
'GET'
,
{
}
,
true
,
callback
)
;
}

Get campaign statistic by countries

@param callback
@param id


function campaignStatByReferrals(callback,id){
    if (id===undefined) {
        return callback(returnError('Empty book id'));
    }
    sendRequest( 'campaigns/' + id + '/referrals', 'GET', {}, true, callback );
}

function
campaignStatByReferrals
(
callback
,
id
)
{
if
(
id
===
undefined
)
{
return
callback
(
returnError
(
'Empty book id'
)
)
;
}
sendRequest
(
'campaigns/'
+
id
+
'/referrals'
,
'GET'
,
{
}
,
true
,
callback
)
;
}

Get campaign statistic by referrals

@param callback
@param id


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
:
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;
  }
}

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
)
,
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;
}

function
get
(
key
,
value
)
{
var
i
,
parts
,
name
,
cookie
;
var
result
=
key
undefined
:
{
}
;
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
)
{
result
=
this
.
read
(
cookie
,
value
)
;
break
;
}
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
}

function cloneGalleryItem ( inst , element ) { const clone = element . cloneNode ( true ) clone . removeAttribute ( 'id' ) 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
}

async
function
get
(
action
,
{
getService
}
=
{
}
)
{
const
{
type
,
service
:
serviceId
=
,
onlyMappedValues
=
false
,
endpoint
}
=
action
.
payload
const
service
=
(
typeof
getService
===
'function'
)
getService
(
type
,
serviceId
)
:
if
(
!
service
)
{
return
createUnknownServiceError
(
type
,
serviceId
,
'GET'
)
}
const
id
=
getIdFromPayload
(
action
.
payload
)
if
(
Array
.
isArray
(
id
)
&&
!
hasCollectionEndpoint
(
service
.
endpoints
)
)
{
return
getIndividualItems
(
id
,
action
,
getService
)
}
const
endpointDebug
=
(
endpoint
)
`
${
endpoint
}
`
:
`
${
type
}
${
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 })
    }
  }
}

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 } ` , service , internal , attributes , relationships , access , cast ( data , { onlyMappedValues = false } = { } ) { return mapAny ( ( data ) => castFn ( data , { onlyMappedValues } ) , data ) } , 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
        )
      }
    }
  }
}

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 , fromService ( data , { onlyMappedValues = true } = { } ) { return data ? ensureArray ( ( onlyMappedValues ) ? mapper . onlyMappedValues ( data ) : mapper ( 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);
    }
  }

function ( tailInfo ) { var z = this ; if ( tailInfo ) { z . q . push ( tailInfo ) ; } var ti ; for ( var i = 0 ; i < z . q . length ; ++ i ) { ti = z . q [ i ] ; if ( ti . reading ) { continue ; } if ( ! z . tails [ ti . stat . ino ] ) { z . q . splice ( i , 1 ) ; -- i ; continue ; } if ( ti . stat . size < ti . pos ) { ti . pos = 0 ; } var len = ti . stat . size - ti . pos ; 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)
    }
  }
}

function setupQueue ( queue ) { let dispatch = null let subscribed = false return { queue , setDispatch ( dispatchFn ) { dispatch = dispatchFn if ( ! subscribed && typeof dispatch === 'function' ) { queue . subscribe ( dispatch ) subscribed = true } } , middleware ( next ) { return middleware ( next , queue ) } , 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;
}

function findOptionInChoice ( choice , optionId , dataElementSpecs ) { for ( const option of choice . aggregateOptions ) { if ( optionId . equals ( option . identifier ) ) { return option ; } } 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 .