but can be
specified with options.tag
.All formats support the property options.allow
which is a list of property names that are allowed only in the output for each record, non-existent
properties will be replaced by empty strings.
The mapping
object property can redefine different tag/header names to be put into the file instead of the exact column names from the records.
lib.toTemplate(text, obj, options)
Given a template with @..@ placeholders, replace each placeholder with the value from the obj.
The obj
can be an object or an array of objects in which case all objects will be checked for the value until non empty.
To use @ in the template specify it as @@
The options if given may provide the following:
Example:
lib.toTemplate("http://www.site.com/@code@/@id@", { id: 123, code: "YYY" }, { encoding: "url" })
lib.toTemplate("Hello @name|friend@!", {})
lib.escapeUnicode(text)
Convert all Unicode binary symbols into Javascript text representation
lib.unescape(str)
Convert escaped characters into native symbols
lib.textToXml(str)
Convert all special symbols into xml entities
lib.textToEntity(str)
Convert all special symbols into html entities
lib.entityToText(str)
Convert html entities into their original symbols
lib.isObject(v)
Returns true of the argument is a generic object, not a null, Buffer, Date, RegExp or Array
lib.isNumber(val)
Return true if the value is a number
lib.isPrefix(val, prefix)
Return true if the value is prefixed
lib.isUuid(val, prefix)
Returns true if the value represents an UUID
lib.isPositive(val)
Returns true if a number is positive, i.e. greater than zero
lib.isArray(val, dflt)
Returns the array if the value is non empty array or dflt value if given or undefined
lib.isEmpty(val)
Return true of the given value considered empty
lib.isNumeric(val)
Returns true if the value is a number or string representing a number
lib.isNumericType(type)
Returns true if the given type belongs to the numeric family of data types
lib.isDate(d)
Returns true if the given date is valid
lib.isTimeRange(time1, time2, options)
Returns 0 if the current time is not within specified valid time range or it is invalid. Only continious time rang eis support, it does not handle over the midninght ranges, i.e. time1 is always must be greater than time2.
options.tz
to specify timezone, no timezone means current timezone.
options.date
if given must be a list of dates in the format: YYY-MM-DD,...
lib.isTrue(val1, val2, op, type)
Evaluate expr, compare 2 values with optional type and operation
lib.isMatched(obj, condition)
All properties in the object obj
must match all properties in the object condition
,
each value in condition
is treated as RegExp,
if the value is equal to 'null' which means an empty or non-existed value,
if the value begins with ! it means no match is expected, the leading ! will be stripped.
if condition
is an array then returns true if any matched
empty condition returns true
Example:
lib.isMatched({id:1,name:2,notifications0:1,type:"user,admin"}, {notifications0:0})
lib.isMatched({id:1,name:2,notifications0:1,type:"user,admin"}, {notifications0:1,type:"!admin"})
lib.isFlag(list, name)
Returns true if name
exists in the array list
, search is case sensitive. if name
is an array it will return true if
any element in the array exists in the list
.
lib.toFlags(cmd, list, name)
Flags command utility, update flags array and returns a new array, the commands are:
name
flags if does not existsname
name
name
lib.forEachLine(file, options, lineCallback, endCallback)
Call callback for each line in the file options may specify the following parameters:
options.header
it is a function
it will be called with the first line as an argument and must return true if this line needs to be skipped,
"'
Properties updated and returned in the options:
lib.forEach(list, iterator, callback)
Apply an iterator function to each item in an array in parallel. Execute a callback when all items have been completed or immediately if there is an error provided.
lib.forEach([ 1, 2, 3 ], function (i, next) {
console.log(i);
next();
}, function (err) {
console.log('done');
});
lib.forEvery(list, iterator, callback)
Same as forEach
except that the iterator will be called for every item in the list, all errors will be ignored
lib.forEachSeries(list, iterator, callback)
Apply an iterator function to each item in an array serially. Execute a callback when all items have been completed or immediately if there is is an error provided.
lib.forEachSeries([ 1, 2, 3 ], function (i, next) {
console.log(i);
next();
}, function (err) {
console.log('done');
});
lib.forEverySeries(list, iterator, callback)
Same as forEachSeries
except that the iterator will be called for every item in the list, all errors will be passed to the next
item with optional additional data argument.
lib.forEverySeries([ 1, 2, 3 ], function (i, next, err, data) {
console.log(i, err, data);
next(err, i, data);
}, function (err, data) {
console.log('done', err, data);
});
lib.forEachLimit(list, limit, iterator, callback)
Apply an iterator function to each item in an array in parallel as many as specified in limit
at a time. Execute a callback when all items
have been completed or immediately if there is is an error provided.
lib.forEveryLimit(list, limit, iterator, callback)
Same as forEachLimit
but does not stop on error, all items will be processed and errors will be collected in an array and
passed to the final callback
lib.forEachItem(options, next, iterator, callback)
Apply an iterator function to each item returned by the next(item, cb)
function until it returns null
or the iterator returns an error in the callback,
the final callback will be called after all iterators are finished.
If no item is available the next()
should return empty value, it will be called again in options.interval
ms if specified or
immediately in the next tick cycle.
The max number of iterators to run at the same time is controlled by options.max
, default is 1.
The maximum time waiting for items can be specified by options.timeout
, it is not an error condition, just another way to stop
processing if it takes too long because the next()
function is a black box just returning items to process. Timeout will send null
to the queue and it will stop after all iterators are finished.
var list = [1, 2, "", "", 3, "", 4, "", "", "", null];
lib.forEachItem({ max: 2, interval: 1000, timeout: 30000 },
function(next) {
next(list.shift());
},
function(item, next) {
console.log("item:", item);
next();
},
(err) => {
console.log("done", err);
});
lib.parallel(tasks, callback)
Execute a list of functions in parallel and execute a callback upon completion or occurance of an error. Each function will be passed a callback to signal completion. The callback accepts an error for the first argument. The iterator and callback will be called via setImmediate function to allow the main loop to process I/O.
lib.everyParallel(tasks, callback)
Same as lib.parallel
but all functions will be called and any error will be ignored
lib.series(tasks, callback)
Execute a list of functions serially and execute a callback upon completion or occurance of an error. Each function will be passed a callback to signal completion. The callback accepts either an error for the first argument in which case the flow will be aborted and the final callback will be called immediately or some optional data to be passed to thr next iterator function as a second argument.
The iterator and callback will be called via setImmediate function to allow the main loop to process I/O.
lib.series([
function(next) {
setTimeout(function () { next(null, "data"); }, 100);
},
function(next, data) {
setTimeout(function () { next(); }, 100);
},
], function(err) {
console.log(err);
});
lib.everySeries(tasks, callback)
Same as lib.series
but all functions will be called with errors passed to the next task, only the last passed error will be returned
lib.everySeries([
function(next, err) {
setTimeout(function () { next("error1", "data1"); }, 100);
},
function(next, err, data) {
setTimeout(function () { next(err, "data2"); }, 100);
},
], function(err, data) {
console.log(err, data);
});
lib.whilst(test, iterator, callback, data)
While the test function returns true keep running the iterator, call the callback at the end if specified. All functions are called via setImmediate.
var count = 0;
lib.whilst(
function() {
return count < 5;
},
function (next) {
count++;
setTimeout(next, 1000);
},
function (err, data) {
console.log(err, data, count);
});
lib.doWhilst(iterator, test, callback, data)
Keep running iterator while the test function returns true, call the callback at the end if specified. All functions are called via setImmediate.
lib.deferCallback(parent, msg, callback, timeout)
Register the callback to be run later for the given message, the message may have the __id
property which will be used for keeping track of the responses or it will be generated.
The parent
can be any object and is used to register the timer and keep reference to it.
A timeout is created for this message, if runCallback
for this message will not be called in time the timeout handler will call the callback
anyway with the original message.
The callback passed will be called with only one argument which is the message, what is inside the message this function does not care. If any errors must be passed, use the message object for it, no other arguments are expected.
lib.onDeferCallback(msg)
To be called on timeout or when explicitely called by the runCallback
, it is called in the context of the message.
lib.runCallback(parent, msg)
Run delayed callback for the message previously registered with the deferCallback
method.
The message must have id
property which is used to find the corresponding callback, if the msg is a JSON string it will be converted into the object.
Same parent object must be used for deferCallback
and this method.
lib.deferInterval(parent, interval, name, callback)
Assign or clear an interval timer, keep the reference in the given parent object
lib.geoHash(latitude, longitude, options)
Return object with geohash for given coordinates to be used for location search
The options may contain the following properties:
min-distance
value will be used.lib.geoDistance(latitude1, longitude1, latitude2, longitude2, options)
Return distance between two locations
The options can specify the following properties:
Example: round to the nearest full 5 km and use only 1 decimal point, if the distance is 13, it will be 15.0
lib.geoDistance(34, -188, 34.4, -119, { round: 5.1 })
lib.busyTimer(name, val)
Busy timer handler, supports commands:
lib.sortByVersion(list, name)
Sort a list be version in descending order, an item can be a string or an object with
a property to sort by, in such case name
must be specified which property to use for sorting.
The name format is assumed to be: XXXXX-N.N.N
lib.getUser(user)
Return an object with user info from the /etc/passwd file, user can be uid or name, if user is ommitted the current user is returned
lib.getGroup(group)
Return an object with specified group info for the current user of for the given group id or name
lib.dropPrivileges(uid, gid)
Drop root privileges and switch to a regular user
lib.encrypt(key, data, algorithm, encode)
Encrypt data with the given key code
lib.decrypt(key, data, algorithm, encode)
Decrypt data with the given key code
lib.ip2int(ip)
Convert an IP address into integer
lib.int2ip(int)
Convert an integer into IP address
lib.inCidr(ip, cidr)
Return true if the given IP address is within the given CIDR block
lib.cidrRange(cidr)
Return first and last IP addresses for the CIDR block
lib.sign (key, data, algorithm, encode)
HMAC signing and base64 encoded, default algorithm is sha1
lib.hash (data, algorithm, encode)
Hash and base64 encoded, default algorithm is sha1
lib.uuid(prefix, options)
Return unique Id without any special characters and in lower case
lib.getHashid(salt, min, alphabet)
Return cached Hashids object for the given configuration
lib.suuid(prefix, options)
Returns a short unique id
lib.tuuid(prefix, encode)
Returns time sortable unique id, inspired by https://github.com/paixaop/node-time-uuid
lib.tuuidTime(str)
Return time in milliseconds from the time uuid
lib.random(size)
Generate random key, size if specified defines how many random bits to generate
lib.randomUShort()
Return random number between 0 and USHORT_MAX
lib.randomShort()
Return random number between 0 and SHORT_MAX
lib.randomUInt()
Return random number between 0 and ULONG_MAX
lib.randomFloat()
Returns random number between 0 and 1, 32 bits
lib.randomInt(min, max)
Return random integer between min and max inclusive using crypto generator, based on https://github.com/joepie91/node-random-number-csprng
lib.randomNum(min, max, decs)
Generates a random number between given min and max (required) Optional third parameter indicates the number of decimal points to return:
lib.clock()
Returns current time in microseconds
lib.shuffle(list)
Randomize the list items in place
lib.now()
Return number of seconds for current time
lib.weekOfYear(date, utc)
Return an ISO week number for given date, from https://www.epochconverter.com/weeknumbers
lib.strftime(date, fmt, options)
Format date object
lib.sprintf(fmt, args)
C-sprintf alike based on http://stackoverflow.com/a/13439711 Usage:
lib.toRFC3339 (date)
Return RFC3339 formatted timestamp for a date or current time
lib.zeropad(n, width)
Return a string with leading zeros
lib.matchRegexp(str, rx, index)
Perform match on a regexp for a string and returns matched value, if no index is specified returns item 1, this is a simple case for oneshot match and only single matched element.
lib.testRegexp(str, rx)
Perform test on a regexp for a string and returns true only if matched.
lib.replaceRegexp(str, rx, val)
Safe version of replace for strings, always returns a string, if val
is not provided performs
removal of the matched patterns
lib.unicode2Ascii(str)
Replace Unicode symbols with ASCII equivalents
lib.strTrim(str, chars)
Remove all whitespace from the begining and end of the given string, if an array with characters is not given then it trims all whitespace
lib.strSplit(str, sep, options)
Split string into array, ignore empty items,
sep
is an RegExp to use as a separator instead of default pattern [,\|]
,options
is an object with the same properties as for the toParams
, datatype' will be used with
lib.toValue` to convert the value for each itemIf str
is an array and type is not specified then all non-string items will be returned as is.
lib.strSplitUnique(str, sep, options)
Split as above but keep only unique items, case-insensitive
lib.phraseSplit(str, options)
Split a string into phrases separated by options.separator
character(s) and surrounded by characters in options.quotes
. The default separator is space and
default quotes are both double and single quote. If options.keepempty
is given all empty parts will be kept in the list.
lib.arrayLength(list)
Return the length of an array or 0 if it is not an array
lib.arrayRemove(list, item)
Remove the given item from the list in place, returns the same list
lib.arrayUnique(list, key)
Returns only unique items in the array, optional key
specified the name of the column to use when determining uniqueness if items are objects.
lib.arrayFlatten(list)
Flatten array of arrays into a single array
lib.jsonToBase64(data, secret, algorithm)
Stringify JSON into base64 string, if secret is given, sign the data with it
lib.base64ToJson(data, secret, algorithm)
Parse base64 JSON into JavaScript object, in some cases this can be just a number then it is passed as it is, if secret is given verify that data is not chnaged and was signed with the same secret
lib.strCompress(data, encoding)
lib.domainName(host)
Extract domain from the host name, takes all host parts except the first one
lib.newError(msg, status, code)
Return a new Error object, msg can be a string or an object with message, code, status properties. The default error status is 400 if not specified.
lib.traceError(err)
Returns the error stack or the error itself, to be used in error messages
lib.exists(obj, name)
Return true if a variable or property in the object exists,
Example:
lib.exists({ 1: 1 }, "1")
lib.exists([ 1, 2, 3 ], 1)
lib.exists([ 1, 2, 3 ], [ 1, 5 ])
lib.callback()
Returns first valid function object from the arguments, if no function found a placeholder is returned
lib.objClone()
A copy of an object, this is a shallow copy, only arrays and objects are created but all other types are just referenced in the new object
lib.objClone({ 1: 2 }, "3", 3, "4", 4)
lib.objNew()
Return new object using arguments as name value pairs for new object properties
lib.objFlatten(obj, options)
Flatten a javascript object into a single-depth object, all nested values will have property names appended separated by comma
The options properties:
Example
> lib.objFlatten({ a: { c: 1 }, b: { d: 1 } } )
{ 'a.c': 1, 'b.d': 1 }
> lib.objFlatten({ a: { c: 1 }, b: { d: [1,2,3] } }, { index: 1 })
{ 'a.c': 1, 'b.d.1': 1, 'b.d.2': 2, 'b.d.3': 3 }
lib.objClean(obj, options)
Cleanup object properties, delete all undefined values in place by default. Additional options:
null
is true then delete all null properties.type
is a RegExp then all properties that match it by type will be deleted.name
is a RegExp then all properties that match it by name will be deleted.value
is a RegExp then all string|number|boolean properties that match it by value will be deleted.array
is true then process all array items recursivellyExample
lib.cleanObj({ a: 1, b: true, c: undefined, d: 2, e: null, l: ["a", "b", null, undefined, { a: 1, b: undefined } ] },{ null:1, array:1, type: /boolean/}) { a: 1, d: 2, l: [ 'a', 'b', { a: 1 } ] }
lib.objExtend(obj, val, options)
Add properties to an existing object, two use cases:
Options properties:
lib.objExtend({ a: 1 }, 'b', 2, 'c' 3 )
lib.objExtend({ a: 1 }, { b: 2, c: 3 }, {})
lib.objExtend({ a: 1 }, { b: 2, _c: 3, _d: 4 }, { remove: /^_/ })
lib.objMerge(obj, val, options)
Merge two objects, all properties from the val
override existing properties in the obj
, returns a new object, shallow copy,
only top level properties are reassigned.
Options properties:
Example
var o = lib.objMerge({ a:1, b:2, c:3 }, { c:5, d:1, _e: 4, x: 2 }, { allow: /^(c|d)/, remove: /^_/ })
o = { a:1, b:2, c:5, d:1 }
lib.objDel()
Delete properties from the object, first arg is an object, the rest are properties to be deleted
lib.objSearch(obj, options)
Return an object consisting of properties that matched given criteria in the given object or object of objects. options can define the following properties:
name
or if it is a string by the given propertyExample
lib.objSearch({id:{index:1},name:{index:3},type:{index:2},descr:{}}, { exists: 'index', sort: 1 });
{ id: { index: 1 }, type: { index: 2 }, name: { index: 3 } }
lib.objSearch({id:1,name:"test",type:"test",descr:"descr"}, { hasvalue: 'test', count: 1});
2
lib.objGet(obj, name, options)
Return a property from the object, name specifies the path to the property, if the required property belong to another object inside the top one the name uses . to separate objects. This is a convenient method to extract properties from nested objects easily. Options may contains the following properties:
Example:
> lib.objGet({ response: { item : { id: 123, name: "Test" } } }, "response.item.name")
"Test"
> lib.objGet({ response: { item : { id: 123, name: "Test" } } }, "response.item.name", { list: 1 })
[ "Test" ]
> lib.objGet({ response: { item : { id: 123, name: "Test" } } }, "response.item.name", { owner: 1 })
{ item : { id: 123, name: "Test" } }
lib.objSet(obj, name, value, options)
Set a property of the object, name can be an array or a string with property path inside the object, all non existent intermediate objects will be create automatically. The options can have the folowing properties:
.
Example
var a = lib.objSet({}, "response.item.count", 1)
lib.objSet(a, "response.item.count", 1, { incr: 1 })
lib.objIncr(obj, name, count, result)
Increment a property by the specified number, if the property does not exist it will be created,
returns new incremented value or the value specified by the result
argument.
It uses lib.objSet
so the property name can be a nested path.
lib.objMult(obj, name, count, result)
Similar to objIncr
but does multiplication
lib.objKeys(obj)
Return all property names for an object
lib.objDescr(obj, options)
Return an object structure as a string object by showing primitive properties only,
for arrays it shows the length and options.count
or 15 first items,
strings are limited by options.length
or 256 bytes, if truncated the full string length is shown.
the object depth is limited by options.depth
or 5 levels deep, the number of properties are limited by options.count or 15,
all properties that match options.ignore
will be skipped from the output, if options.allow
is a regexp, only properties that
match it will be output. Use options.replace
for replacing anything in the final string.
lib.stringify(obj, filter)
JSON stringify without exceptions, on error just returns an empty string and logs the error
lib.jsonFormat(obj, options)
Nicely format an object with indentations, optional indentlevel
can be used to control until which level deep
to use newlines for objects.
lib.jsonParse(obj, options)
Silent JSON parse, returns null on error, no exceptions raised.
options can specify the following properties:
lib.xmlParse(obj, options)
Same arguments as for jsonParse
lib.moveFile(src, dst, overwrite, callback)
Copy file and then remove the source, do not overwrite existing file
lib.copyFile(src, dst, overwrite, callback)
Copy file, overwrite is optional flag, by default do not overwrite
lib.execProcess(cmd, callback)
Run the process and return all output to the callback, this a simply wrapper around child_processes.exec so the lib.runProcess can be used without importing the child_processes module. All fatal errors are logged.
lib.spawnProcess(cmd, args, options, callback)
Run specified command with the optional arguments, this is similar to child_process.spawn with callback being called after the process exited
Example
lib.spawProcess("ls", "-ls", { cwd: "/tmp" }, lib.log)
lib.spawnSeries(cmds, options, callback)
Run a series of commands, cmds
is an object where a property name is a command to execute and the value is an array of arguments or null.
if options.error
is 1, then stop on first error or if non-zero status on a process exit.
Example:
lib.spawnSeries({"ls": "-la",
"ps": "augx",
"du": { argv: "-sh", stdio: "inherit", cwd: "/tmp" },
"uname": ["-a"] },
lib.log)
lib.statSync(file)
Non-exception version, returns empty object, mtime is 0 in case file does not exist or number of seconds of last modified time mdate is a Date object with last modified time
lib.readFileSync(file, options)
Return contents of a file, empty if not exist or on error.
Options can specify the format:
lib.readFile(file, options, callback)
Same as lib.readFileSync
but asynchronous
lib.findFilter(file, stat, options)
Filter function to be used in findFile methods
lib.findFileSync(file, options)
Return list of files than match filter recursively starting with given path, file is the starting path.
The options may contain the following:
Example:
lib.findFileSync("modules/", { depth: 1, types: "f", include: /\.js$/ }).sort()
lib.findFile(dir, options, callback)
Async version of find file, same options as in the sync version
lib.watchFiles(options, fileCallback, endCallback)
Watch files in a dir for changes and call the callback, the parameters:
lib.makePathSync(dir)
Recursively create all directories, return 1 if created or 0 on error or if exists, no exceptions are raised, error is logged only
lib.makePath(dir, callback)
Async version of makePath, stops on first error
lib.unlink(name, callback)
Unlink a file, no error on non-existent file, callback is optional
lib.unlinkPath(dir, callback)
Recursively remove all files and folders in the given path, returns an error to the callback if any
lib.unlinkPathSync(dir)
Recursively remove all files and folders in the given path, stops on first error
lib.chownSync(uid, gid)
Change file owner, multiples files can be specified, do not report errors about non existent files, the uid/gid must be set to non-root user for this function to work and it is called by the root only, all the rest of the arguments are used as files names
Example:
lib.chownSync(1, 1, "/path/file1", "/path/file2")
lib.mkdirSync()
Create a directories if do not exist, multiple dirs can be specified, all preceeding directories are not created
Example:
lib.mkdirSync("dir1", "dir2")
lib.Pool(options)
Create a resource pool, create
and close
callbacks must be given which perform allocation and deallocation of the resources like db connections.
Options defines the following properties:
function(err, item)
If no create implementation callback is given then all operations are basically noop but still cals the callbacks.
Example:
var pool = new lib.Pool({ min: 1, max: 5,
create: function(cb) {
someDb.connect(function(err) { cb(err, this) }
},
destroy: function(client) {
client.close() }
})
pool.aquire(function(err, client) {
...
client.findItem....
...
pool.release(client);
});
lib.Pool.prototype.init(options)
Initialize pool properties, this can be run anytime even on the active pool to override some properties
lib.Pool.prototype.acquire(callback)
Return next available resource item, if not available immediately wait for defined amount of time before calling the callback with an error. The callback second argument is active resource item.
lib.Pool.prototype.destroy(item, callback)
Destroy the resource item calling the provided close callback
lib.Pool.prototype.release(item)
Return the resource item back to the list of available resources.
lib.Pool.prototype.destroyAll()
Close all active items
lib.Pool.prototype.stats()
Return an object with stats
lib.Pool.prototype.shutdown(callback, maxtime)
Close all connections and shutdown the pool, no more items will be open and the pool cannot be used without re-initialization, if callback is provided then wait until all items are released and call it, optional maxtime can be used to retsrict how long to wait for all items to be released, when expired the callback will be called
lib.Pool.prototype._call(name, callback)
Call registered method and catch exceptions, pass it to the callback if given
lib.Pool.prototype._timer()
Timer to ensure pool integrity
logger
Simple logger utility for debugging
logger.registerLevel(level, callback, options)
Register a custom level handler, must be invoked via logger.logger
only, if no handler registered for given level
the whole message will be logger as an error. The custom hadnler is called in the context of the module which means
the options are available inside the handler.
The following properties are supported automatically:
logger.setSyslog (on)
Set or close syslog mode
logger.setFile(file, options)
Redirect logging into file
logger.setLevel(level)
Set the output level, it can be a number or one of the supported level names
logger.setDebugFilter(str)
Enable debugging level for this label, if used with the same debugging level it will be printed regardless of the global level,
a label is first argument to the logger.debug
methods, it is used as is, usually the fist argument is
the current function name with comma, like logger.debug("select:", name, args)
logger.printSyslog(level, msg)
syslog allows facility to be specified after log level like info:local0 for LOG_LOCAL0
logger.errorWithOptions(err, options)
Prints the given error and the rest of the arguments, the logger level to be used is determined for the given error by code,
uses options
or options.logger_error
as the level if a string,
if options.logger_error
is an object, extract the level by err.code
or use *
as the default level for not matched codes,
the default is to use the error
level.
In case the level is notice or info the error will only show status/code/message properties in order not to print stack trace
logger.trace()
Print stack backtrace as error
logger.logger()
A generic logger method, safe, first arg is supposed to be a logging level, if not valid the error level is used
logger.print()
Default write handler
logger.write(str)
Stream emulation
TokenBucket.prototype.configure(rate, max, interval)
Initialize existing token with numbers for rate calculations
TokenBucket.prototype.toJSON()
Return a JSON object to be serialized/saved
TokenBucket.prototype.toString()
Return a string to be serialized/saved
TokenBucket.prototype.toArray()
Return an array object to be serialized/saved
TokenBucket.prototype.equal(rate, max, interval)
Return true if this bucket uses the same rates in arguments
TokenBucket.prototype.consume(tokens)
Consume N tokens from the bucket, if no capacity, the tokens are not pulled from the bucket.
Refill the bucket by tracking elapsed time from the last time we touched it.
min(totalTokens, current + (fillRate * elapsedTime))
TokenBucket.prototype.delay(tokens)
Returns number of milliseconds to wait till number of tokens can be available again
Msg.prototype.init(options, callback)
Initialize supported notification services, it supports jobs arguments convention so can be used in the jobs that need to send push notifications in the worker process.
Msg.prototype.shutdown(options, callback)
Shutdown notification services, wait till all pending messages are sent before calling the callback
Msg.prototype.send(device, options, callback)
Deliver a notification for the given device token(s).
The device
is where to send the message to, can be multiple ids separated by , or |.
Options with the following properties:
Msg.prototype.parseDevice(device)
Parse device URN and returns an object with all parts into separate properties. A device URN can be in the following format: [service://]device_token[@app]
apn
, gcm
, sns
, the default
service uses APN deliveryMsg.prototype.getClient(dev)
Return a client module that supports the given device
Msg.prototype.getConfig(name)
Return a list of all config cert/key parameters for the given name. Each item in the list is an object with the following properties: key, secret, app
Msg.prototype.getAgent(mod, dev)
Return an agent for the given module for the given device
client.check(dev)
Returns true if given device is supported by APN
client.init(options)
Initialize Apple Push Notification service in the current process, Apple supports multiple connections to the APN gateway but not too many so this should be called on the dedicated backend hosts, on multi-core servers every spawn web process will initialize a connection to APN gateway.
client.close(callback)
Close APN agent, try to send all pending messages before closing the gateway connection
client.send(dev, options, callback)
Send push notification to an Apple device, returns true if the message has been queued.
The options may contain the following properties:
client.init(options)
Initialize Google Cloud Messaging service to send push notifications to mobile devices
client.close(callback)
Close GCM connection, flush the queue
client.send(dev, options, callback)
Send push notification to an Android device, return true if queued.
client.retryOnError()
Retry on server error, honor Retry-After header if present, use it only on the first error
client.init(options)
Initialize Google Cloud Messaging service to send push notifications to mobile devices
client.close(callback)
Close GCM connection, flush the queue
client.send(dev, options, callback)
Send push notification to an Android device, return true if queued.
client.retryOnError()
Retry on server error, honor Retry-After header if present, use it only on the first error
server.start()
Start the server process, call the callback to perform some initialization before launchng any server, just after core.init
server.startMonitor(options)
Start process monitor, running as root
server.startMaster(options)
Setup worker environment
server.startWeb(options)
Create Express server, setup worker environment, call supplied callback to set initial environment
server.startWebProcess()
Spawn web server from the master as a separate master with web workers, it is used when web and master processes are running on the same server
server.handleChildProcess(child, type, method)
Setup exit listener on the child process and restart it
server.startProcess()
Restart the main process with the same arguments and setup as a monitor for the spawn child
server.startWatcher()
Watch source files for modifications and restart
server.startDaemon()
Create daemon from the current process, restart node with -daemon removed in the background
server.onProcessExit()
Kill all child processes on exit
server.onProcessTerminate()
Terminates the server process, it is called on SIGTERM signal but can be called manually for graceful shitdown,
it runs shutdown[Role]
methods before exiting
server.writePidfile()
Create a pid file for the current process
server.shutdown(options, callback)
Shutdown the system immediately, mostly to be used in the remote jobs as the last task
server.respawn(callback)
If respawning too fast, delay otherwise schedule new process after short timeout
server.spawnProcess(args, skip, opts)
Start new process reusing global process arguments, args will be added and args in the skip list will be removed
accounts
Account management
Database tables
// Basic account information
bk_account: {
id: { primary: 1, pub: 1 },
login: {},
status: { type: "text" },
type: { type: "text", list: 1, admin: 1 },
name: { pub: 1, notempty: 1 },
first_name: { pub: 1 },
last_name: { pub: 1 },
email: { type: "email" },
phone: { type: "phone" },
website: {},
company: {},
birthday: { type: "string" },
gender: {},
street: {},
city: {},
county: {},
state: {},
zipcode: {},
country: {},
device_id: {}, // Device(s) for notifications the format is: [service://]token[@appname]
ctime: { type: "now", readonly: 1 }, // Create time
mtime: { type: "now" }, // Last update time
},
},
}; module.exports = accounts;
// Initialize the module accounts.init = function(options) {
db.describeTables();
}
accounts.configureMdule = function(options, callback) {
db.setProcessRow("post", "bk_account", function(req, row) {
if (row.birthday) {
row.age = Math.floor((Date.now() - lib.toDate(row.birthday))/(86400000*365));
}
// If only used as alias then split manually
if (row.name && !row.first_name) {
var name = row.name.split(" ");
if (name.length > 1) row.last_name = name.pop();
row.first_name = name.join(" ");
}
accounts.configureWeb(options, callback)
Create API endpoints and routes
accounts.configureAccountsAPI()
Account management
accounts.getAccount(req, options, callback)
Returns current account, used in /account/get API call, req.account will be filled with the properties from the db
accounts.notifyAccount(options, callback)
Send Push notification to the account. The delivery is not guaranteed, if the message was queued for delivery, no errors will be returned.
The options may contain the following:
lib.isMatched
In addition the device_id can be saved in the format service://id where the service is one of the supported delivery services, this way the notification system will pick the right delivery service depending on the device id, the default service is apple.
Example:
bk_account.notifyAccount({ account_id: "123", msg: "test", badge: 1, sound: 1, allow: { notifications0: 1, type: "user" }, enable: { sound: "sound0", badge: "badge0" } })
accounts.listAccount(rows, options, callback)
Return account details for the list of rows, options.account_key
specified the column to use for the account id in the rows
, or id
will be used.
The result accounts are cleaned for public columns, all original properties from the rows
are kept as is.
If options.existing is 1 then return only record with found accounts, all other records in the rows will be deleted
accounts.selectAccount(req, options, callback)
Query accounts, used in /accout/select API call, simple wrapper around db.select but can be replaced in the apps while using the same API endpoint
accounts.addAccount(req, options, callback)
Register new account, used in /account/add API call, but the req does not have to be an Express request, it just need to have query and options objects.
accounts.updateAccount(req, options, callback)
Update existing account, used in /account/update API call
accounts.deleteAccount(req, callback)
Delete account specified by the obj. Used in /account/del
API call.
The options may contain keep
array with tables to be kept, for example
delete an account but keep all messages and location: keep:["bk_message","bk_location"]
This methods is suitable for background jobs
accounts.renameAccount(req, callback)
Rename account alias
accounts.fetchAccount(query, options, callback)
Override OAuth account management
mod
Account management
mod.configureWeb(options, callback)
Create API endpoints and routes
mod.configureDataAPI()
API for full access to all tables
mod.processShardStart(req, options, callback)
Get the last processed sequence for the shard
mod.processRecords(req, options, callback)
Commit a batch of shard records processed
files
Account management
files.configureWeb(options, callback)
Create API endpoints and routes
files.configureFilesAPI()
Generic file management
mod
Icons management
Database tables
bk_icon: {
id: { primary: 1 }, // account id
type: { // prefix:type
primary: 1,
pub: 1,
join: [ "prefix", "type" ],
unjoin: 1,
separator: ":",
ops: { select: "begins_with" }
},
prefix: {}, // icon prefix/namespace
descr: { pub: 1 }, // user provided caption
acl_allow: {}, // who can see it: all, auth, id:id...
tags: { type: "list" }, // detected or attached tags
width: { type: "int" },
height: { type: "int" },
rotation: { type: "int" }, // rotation angle
ext: {}, // saved image extension
latitude: { type: "real" },
longitude: { type: "real" },
mtime: { type: "now" },
},
},
limit: { "*": 0 },
controls: {
width: { type: "number" },
height: { type: "number" },
rotate: { type: "number" },
quality: { type: "number" },
brightness: { type: "number" },
contrast: { type: "number" },
bgcolor: { type: "string" },
verify: { type: "bool" },
extkeep: { type: "regexp" },
autodel: { type: "bool" },
}
}; module.exports = mod;
// Initialize the module mod.init = function(options) {
core.describeArgs("icons", [
{ name: "limit", type: "map", datatype: "int", descr: "Set the limit of how many icons by type can be uploaded by an account, type:N,type:N..., type * means global limit for any icon type" },
]);
}
mod.configureMiddleware = function(options, callback) {
api.registerControlParams(mod.controls);
callback();
}
// Create API endpoints and routes mod.configureWeb = function(options, callback) {
this.configureIconsAPI();
callback()
}
// Generic icon management mod.configureIconsAPI = function() {
api.app.all(/^\/icon\/([a-z]+)$/, function(req, res) {
var options = api.getOptions(req);
options.cleanup = "bk_icon";
if (!req.query.prefix) return api.sendReply(res, 400, "prefix is required");
if (!req.query.id) req.query.id = req.account.id;
if (!req.query.type) req.query.type = "";
switch (req.params[0]) {
case "get":
mod.send(req, options);
break;
case "select":
mod.select(req.query, function(err, rows) {
api.sendJSON(req, err, rows);
mod.upload(req, options, callback)
Process icon request, put or del, update table and deal with the actual image data, always overwrite the icon file Verify icon limits before adding new icons
mod.select(query, options, callback)
Return list of icons for the account, used in /icon/get API call
mod.del(options, callback)
Delete an icon, only one icon at a time, options must profile id, prefix. It will try to delete an icon file even if there is no record in the bk_icon table.
mod.send(req, options)
Return icon to the client, checks the bk_icon table for existence and permissions
mod
Messages management
Database tables
// New messages, the inbox
bk_message: {
id: { primary: 1 }, // my account_id
mtime: {
primary: 1, // mtime:sender
join: ["mtime","sender"],
unjoin: 1,
},
sender: { type: "text" }, // sender id
name: {}, // sender name
msg: {}, // Text of the message
icon: { type: "int" }, // 1 - icon present, 0 - no icon
icon_type: {}, // png, gif, jpg
read: { type: "int" }, // 1 - read, 0 - unread
flags: { type: "list" },
ctime: { type: "now", readonly: 1 },
},
// Archived messages
bk_archive: {
id: { primary: 1 }, // my account_id
mtime: {
primary: 1, // mtime:sender
join: ["mtime","sender"],
unjoin: 1,
},
sender: { type: "text" }, // sender id
name: {}, // sender name
msg: {}, // text of the message
icon: { type: "int" }, // 1 - icon present, 0 - no icon
icon_type: {}, // png, gif, jpg
flags: { type: "list" },
ctime: { type: "now", readonly: 1 },
},
// Messages sent
bk_sent: {
id: { primary: 1 }, // my account
mtime: {
primary: 1, // mtime:recipient
join: ["mtime","recipient"],
unjoin: 1,
},
recipient: { type: "text" }, // recipient id
name: {}, // recipient name if known
msg: {}, // text of the message
icon: { type: "int" }, // 1 - icon present, 0 - no icon
icon_type: {}, // png, gif, jpg
flags: { type: "list" },
ctime: { type: "now", readonly: 1 },
},
},
controls: {
archive: { type: "bool" },
trash: { type: "bool" },
nosent: { type: "bool" },
},
cacheOptions: { cacheName: "messages", ttl: 3600000 },
}; module.exports = mod;
mod.init = function(options) {
core.describeArgs(mod.name, [
{ name: "cache-name", obj: "cacheOptions", descr: "Cache name for keeping unread messages counter" },
{ name: "cache-ttl", type: "number", obj: "cacheOptions", nocamel: 1, key: "ttl", min: 0, descr: "How long in ms to keep unread messages counter" },
]);
}
mod.configureMiddleware = function(options, callback) {
api.registerControlParams(mod.controls);
callback();
}
mod.configureModule = function(options, callback) {
db.setProcessRow("post", "bk_message", function(req, row) {
if (row.icon) row.icon = api.iconUrl({ prefix: 'message', id: row.id, type: row.mtime + ":" + row.sender, ext: row.icon_type }); else delete row.icon;
mod.configureWeb(options, callback)
Create API endpoints and routes
mod.configureMessagesAPI()
Messaging management
mod.getArchiveMessage(req, options, callback)
Return archived messages, used in /message/get API call
mod.getSentMessage(req, options, callback)
Return sent messages to the specified account, used in /message/get/sent API call
mod.getMessage(req, options, callback)
Return new/unread messages, used in /message/get API call
mod.addMessage(req, options, callback)
Add new message(s), used in /message/add API call
The following options properties can be used:
mod.archiveMessage(req, options, callback)
Move matched messages to the archive, used in /message/archive API call
mod.delMessage(req, options, callback)
Delete matched messages, used in /message/del` API call
mod.delArchiveMessage(req, options, callback)
Delete matched messages in the archive, used in /message/del/archive` API call
mod.delSentMessage(req, options, callback)
Delete matched messages i sent, used in /message/del/sent` API call
mod.updateMessage(req, options, callback)
Update a message or all messages for the given account from the given sender, used in /message/del` API call
mod.updateArchiveMessage(req, options, callback)
Update a messages in the archive, used in /message/update/archive` API call
mod.readMessage(req, options, callback)
Mark matched messages as read, used in /message/read` API call
shell.exit(err, msg)
Exit and write to the console a message or error message if non empty
shell.getUser(obj, callback)
Resolves a user from obj.id
or obj.login
params and return the record in the callback
shell.getQuery()
Returns an object with all command line params that do not start with dash(-), treat 2 subsequent parms without dashes as name value pair
shell.getQueryList()
Returns a list with all command line params that do not start with dash(-), only the trailing arguments will be collected
shell.getArgs(options)
Returns an object with all command line params starting with dash set with the value if the next param does not start with dash or 1.
By sefault all args are zatored as is with dahses, if options.camel`` is true then all args will be stored in camel form,
if
options.underscor`e is true then all args will be stored with dashes convertyed into underscores.
shell.getOption(name, options)
Return an argument by name from the options, options may contain parameters in camel form or with underscores, both formats will be checked
shell.getArg(name, options, dflt)
Return first available value for the given name, options first, then command arg and then default,
shell.runShell(options)
Start REPL shell or execute any subcommand if specified in the command line. A subcommand may return special string to indicate how to treat the flow:
shell.cmdShowInfo(options)
App version
shell.cmdRunFile(options)
Load a module and optionally execute it
Example:
var bkjs = require("backendjs")
bkjs.app.test = 123;
exports.run = function() {
console.log("run");
}
exports.newMethod = function() {
console.log(bkjs.core.version, "version");
}
Save into a file a.js and run
bksh -run-file a.js
In the shell now it new methods can be executed
> shell.newMethod()
shell.cmdRunApi(options)
Run API server inside the shell
shell.cmdRunJobs(options)
Run jobs workers inside the shell
shell.cmdAccountGet(options)
Show account records by id or login
shell.cmdAccountAdd(options)
Add a user
shell.cmdAccountDel(options)
Delete a user and all its history according to the options
shell.cmdLoginGet(options)
Show account records by id or login
shell.cmdLoginAdd(options)
Add a user login
shell.cmdLoginUpdate(options)
Update a user login
shell.cmdLoginDel(options)
Delete a user login
shell.cmdLocationPut(options)
Update location
shell.cmdLogWatch(options)
Run logwatcher and exit
shell.cmdSendRequest(options)
Send API request
},(err, opts)
If executed as standalone script directly in the node
shell.awsCheckTags(obj, name)
Check all names in the tag set for given name pattern(s), all arguments after 0 are checked
shell.awsFilterSubnets(subnets, zone, name)
Return matched subnet ids by availability zone and/or name pattern
shell.awsGetSelfImages(name, callback)
Retrieve my AMIs for the given name pattern
shell.awsSearchImage(filter, appName, callback)
Return an image that matches given app name latest version
shell.awsGetAmazonImages(options, callback)
Return Amazon AMIs for the current region, HVM type only
shell.awsGetElbCount(name, equal, total, options, callback)
Wait ELB to have instance count equal or not to the expected total
shell.awsLaunchInstances(options, callback)
Launch instances by run mode and/or other criteria
shell.cmdAwsLaunchInstances(options)
Delete an AMI with the snapshot
shell.cmdAwsDeleteImage(options)
Delete an AMI with the snapshot
shell.cmdAwsCreateImage(options)
Create an AMI from the current instance of the instance by id
shell.cmdAwsRebootInstances(options)
Reboot instances by run mode and/or other criteria
shell.cmdAwsTerminateInstances(options)
Terminate instances by run mode and/or other criteria
shell.cmdAwsShowInstances(options)
Show running instances by run mode and/or other criteria
shell.cmdAwsSetRoute53(options)
Update a Route53 record with IP/names of all instances specified by the filter
shell.cmdAwsShowElb(options)
Show ELB running instances
shell.cmdAwsRebootElb(options)
Reboot instances in the ELB, one by one
shell.cmdAwsReplaceElb(options)
Deploy new version in the ELB, terminate the old version
shell.cmdAwsSetupSsh(options)
Open/close SSH access to the specified group for the current external IP address
shell.cmdAwsSetupInstance(options)
Launch an instance and setup it with provisioning script
shell.cmdAwsS3Get(options)
Get file
shell.cmdAwsS3Put(options)
Put file
shell.cmdAwsS3List(options)
List folder
shell.cmdDbGetConfig(options)
Show all config parameters
shell.cmdDbTables(options)
Show all tables
shell.cmdDbSelect(options)
Show record that match the search criteria, return up to -count N
records
shell.cmdDbScan(options)
Show all records that match search criteria
shell.cmdDbBackup(options)
Save all tables to the specified directory or the server home
shell.cmdDbRestore(options)
Restore tables
shell.cmdDbPut(options)
Put a record
shell.cmdDbDel(options)
Delete a record
shell.cmdDbDelAll(options)
Delete all records
shell.cmdDbDrop(options)
Drop a table
shell.assert(next, err)
To be used in the tests, this function takes the following arguments:
assert(next, err, ....)
NOTES:
-test-forever
any error is ignored and not reportedtests.test.delay
is set it will be used to delay calling the next callback and reset, this is for
one time delays.Example
function(next) {
db.get("bk_account", { id: "123" }, function(err, row) {
tests.assert(next, err || !row || row.id != "123", "Record not found", row)
});
}
shell.cmdTestRun(options)
Run the test function which is defined in the tests module, all arguments will be taken from the options or the command line. Options
use the same names as command line arguments without preceeding test-
prefix.
The common command line arguments that supported:
All other common command line arguments are used normally, like -db-pool to specify which db to use.
After finish or in case of error the process exits if no callback is given.
Example, store it in tests/tests.js:
var bkjs = require("backendjs");
var tests = bkjs.core.modules.tests;
tests.test_mytest = function(next) {
bkjs.db.get("bk_account", { id: "123" }, function(err, row) {
tests.assert(next, err || !row || row.id != "123", "Record not found", row)
});
}
# bksh -test-run mytest
Custom tests:
create a user for backend testing, if the API does not require authentication skip this step:
./app.sh -shell -account-add login testuser secret testpw
configure global backend credentials
echo "backend-login=testuser" >> etc/config.local
echo "backend-secret=testpw" >> etc/config.local
to start a test command in the shell using local ./tests.js
./app.sh -shell -test-run account
to start a test command in the shell using custom file with tests
./app.sh -shell -test-run api -test-file tests/api.js
mod
Status management
Database tables
bk_status: {
id: { primary: 1, pub: 1 }, // account id
name: { pub: 1 }, // account name
status: { pub: 1 }, // status, online, offline, away
atime: { type: "bigint", pub: 1 }, // last access time
mtime: { type: "now", pub: 1 }, // last update time
},
},
// Intervals between updating presence status table
args: [
{ name: "interval", type: "number", min: 60000, max: 86400000, descr: "Max idle period in milliseconds after which the status will be considered offline" },
{ name: "update-interval", type: "number", min: 60000, max: 86400000, descr: "Period in milliseconds between database flushing updates in the case when bk_status is cached" },
],
interval: 60000,
updateInterval: 180000,
}; module.exports = mod;
// Returns status record for given account, used in /status/get API call.
// It always returns status object even if it was never set before, on return the record contains
// a property online
set to true of false according to the idle period and actual status.
//
// If status was explicitely set to offline
then it is considered offline until changed to other value,
// for other cases status
property is not used, it is supposed for the application extention.
//
mod.get = function(id, options, callback)
{
if (typeof options == "function") callback = options, options = null;
var now = Date.now();
db.get("bk_status", { id: id }, options, function(err, status, info) {
if (err) return callback(err);
if (!status) status = { id: id, status: "", online: false, atime: 0, mtime: 0 };
status.online = now - status.atime < mod.interval && status.status != "offline" ? true : false;
status._cached = info.cached;
callback(err, status);
mod.select(ids, options, callback)
Return status records for specified list of account ids.
mod.update(status, options, callback)
Maintain online status, update to db every status-interval seconds, only update the db if last update happened
longer than status-interval
milliseconds ago, keep atime up-to-date in the cache on every status update.
On return and if it was flushed to db the atime
will be equal to mtime
.
NOTE: All properties from the obj
will be saved in the bk_status record, existing properties will be overriden
mod.bkDeleteAccount(req, callback)
This methods is suitable for background jobs
system
System management
system.init(options)
Initialize the module
system.configureWeb(options, callback)
Create API endpoints and routes
system.configureSystemAPI()
API for internal provisioning and configuration
Pool.prototype.put(table, obj, options, callback)
No REPLACE INTO support but UPDATE creates new record if no primary key exists
pool
Create a database pool that works with CouchDB server.
In addition to the standard commands it can execute any CouchDB HTTP API directly
db.query({ op: "GET", text: "/db/url" }, { pool: "couchdb" }, lib.log)
db.query({ op: "PUT", text: "/db/url", obj: { a: 1 b: 2 } }, { pool: "couchdb" }, lib.log)
pool
Setup LMDB/LevelDB database driver, this is simplified driver which supports only basic key-value operations, table parameter is ignored, the object only supports the properties name and value in the record objects.
Because this driver supports 2 databases it requires type to be specified, possible values are: lmdb, leveldb
Options are passed to the LMDB low level driver as MDB_ flags according to http://symas.com/mdb/doc/ and as properties for LevelDB as described in http://leveldb.googlecode.com/svn/trunk/doc/index.html
The LevelDB database can only be shared by one process so if no unique options.url is given, it will create a unique database using core.processId()
Pool.prototype.put(table, obj, opts, callback)
No REPLACE INTO support, do it manually
Pool.prototype.cacheIndexes(options, callback)
Cache indexes using the information_schema
Pool.prototype.bindValue(val, info, options)
Convert JS array into db PostgreSQL array format: {..}
pool
Redis database pool, uses Hash to store the records
pool
Create a database pool that works with the Riak database.
By default the driver uses simple key-value mode of operations, to enable bucket-type mode
pass bucketType in the -db-riak-options
:
To use maps for the object records set useMaps
in the -db-riak-options
-db-riak-options '{ "bucketType": "bk", "useMaps": 1 }'
In addition to the standard commands it can execute any Riak HTTP API directly
db.query({ op: "GET", text: "/buckets?buckets=true" }, { pool: "riak" }, lib.log)
db.query({ op: "POST", text: "/buckets/bucket/counter/name", obj: 1 }, { pool: "riak" }, lib.log)
client
Queue client using RabbitMQ server
Database tables
bk_queue: {
id: { primary: 1 },
active: { type: "int", index: 1, value: 0 }, // job status, new, running
data: { type: "json", projections: 1 }, // job definition object
mtime: { type: "now", index: 1 }
},
},
};
ipc.modules.push(client);
client.createClient = function(url, options) {
if (url.match(/^db:/)) return new IpcDbClient(url, options);
}
function IpcDbClient(url, options) {
Client.call(this, url, options);
this.options.interval = lib.toNumber(this.options.interval, { dflt: 30, min: 1 });
this.options.count = lib.toNumber(this.options.count, { dflt: 1, min: 1 });
this.options.visibilityTimeout = lib.toNumber(this.options.visibilityTimeout, { min: 0, dflt: this.options.interval });
this.emit("ready");
} util.inherits(IpcDbClient, Client);
IpcDbClient.prototype.monitorQueue = function() {
var options = { pool: this.options.pool, updateCollect: 1, sort: "active_mtime", ops: { mtime: "lt" }, expected: { active: 1 } };
var query = { active: 1, mtime: Date.now() - this.options.visibilityTimeout * 1000 };
db.updateAll("bk_queue", query, { active: 0 }, options, function(err, rows) {
for (var i in rows) logger.error("ipc.monitor:", lib.toAge(rows[i].mtime), rows[i]);
client
Cache client based on HazelCast server using https://github.com/hazelcast/hazelcast-nodejs-client
To support more than one server use either one:
ipc-cache=hazelcast://host?bk-servers=host2,host3
ipc-cache=memcache://host1 ipc-cache-options-servers=host1,host2
To pass module specific options:
ipc-cache-options-map-name=defaultMap ipc-cache-options-map-prefix=|
client.send(dev, options, callback)
Send push notification to a device using AWS SNS service, device_id must be a valid SNS endpoint ARN.
The options may contain the following properties:


Hypothesis for Canvas is in beta test. If you'd like to try it, please contact
Jeremy Dean
(jeremydean@hypothes.is), Director of Education.


{{ define "main" }}
Sorry, we couldn't find this page. But don't worry, you can find plenty of other things on homepage.


Define the scenario¶
Create a new .ini file and use this template:
[START]
LAT:
LONG:
ALT:
Duration:
Heading:
Speed:
Acceleration:
Rateheading:
Turnrate:
Turnradius:
Cn0:
Propagation:
Antenna:
Tropo:
Iono:
keepalt:
ECEFpos:
Multipath:
SpeedOverGround:
Verticalspeed:
Enuvel:
Ecefvel:
VerticalAcceleration:
ENUAccel:
ECEFAccel:
PRYattitude:
DPRYattitude:
Kepler:
[SECTION 1]
LAT:
LONG:
ALT:
Duration:
Heading:
Speed:
Acceleration:
Rateheading:
Turnrate:
Turnradius:
Cn0:
Propagation:
Antenna:
Tropo:
Iono:
keepalt:
signaltype:
ECEFpos:
Multipath:
SpeedOverGround:
Verticalspeed:
Enuvel:
Ecefvel:
VerticalAcceleration:
ENUAccel:
ECEFAccel:
PRYattitude:
DPRYattitude:
Kepler:
[END]
In the [START] section, just fill the Latitude, Longitude and altitude information.
Copy/Paste the number of [SECTION] needed.
In each section, put all the parameters you want to set from (section-1) to the section, if not given, default parameters will be set. Pay attention:
- fill LAT, LONG, ALT or Duration, Heading not both!
- fill LAT, LONG, ALT or ECEFpos not both
- fill ENUvel or ECEFvel or Speed or SpeedOverGround not four of them
- fill ENUaccel or ECEFaccel or Acceleration not three of them
- fill PRYattitue or DPRYattitude not both


Tahaa lies in the same barrier reef as Raiatea to the south. Tahaa is often called the Vanilla island due to those numerous plantations that flourish in the fertile valleys bordered by deepwater bays. You can navigate the channel encircling the island.
Cruisers report that Tahaa is investing heavily in making its bays more attractive to the cruiser. There are now mooring balls installed and book swaps etc.
No clearance necessary as Tahaa is considered one with Raiatea.
A public dock (Quai de Tapuamu) at Uporu/Iripau is available for loading/unloading.
Mooring balls have also been installed on the west side of Tahaa, but not at the coral garden. You still have to anchor SOUTH of the coral garden.
Haamene Bay on the east of Tahaa is the largest protected body of water on the island. It cuts about 2 miles into the centre of the island, which makes it very still and peaceful. There is also a nice restaurant at the head of the bay which is also the best place to anchor for protection and scenery. Three mooring buoys have now been installed close to the town. The new boardwalk is almost finished and the library (located behind the ice house) is happy to lend books to cruisers and accepts books as well.
Caution: As well as the public moorings, many local businesses have installed private moorings for the free use of any yacht that patronizes their activities. Some are unsuitable for yachts and therefore it is important to check any mooring before leaving the yacht unattended!
Last updated April 2015.


- Symptoms : cold
- Date : 02/03/2018
- Hospital : Tata Hospital
- Description : Fever due to season change
- Medicines : paracitamol
- weight : 70kg
- height : 170cm
- Symptoms : vomiting
- Date : 20/03/2018
- Hospital : Zydus Hospital
- Description : Food poisioning due to unhealthy food
- Medicines : avomin
- weight : 67kg
- height : 170cm
FOOD ALLERGY
The signs and symptoms may range from mild to severe.They may include itchiness, swelling of the tongue, vomiting, diarrhea, hives, trouble breathing, or low blood pressure.
"He had a severe fracture in his right hand and a bone is replaced by steel rode."


Public data
12.5K
Your data
16
Reference data
116.1K
Favorites
18
Filter by type
Genome
119
Genome feature
71M
Assembly
44
Expression Matrix
35
Reads
19
Pangenome
3
Media
0
Amplicon Matrix
0
112,234 results
Sort results
Genome
06/20/2018
Deinococcus radiodurans R1
Narrative:
Radiodurans Annotations
Favorite
Copy
Assembly
06/20/2018
Deinococcus radiodurans A162374
Narrative:
Radiodurans Annotations
Favorited
Copy
Amplicon matrix
06/20/2018
Deinococcus radiodurans R1
Narrative:
Radiodurans Annotations
Favorite
Copy
Genome
06/20/2018
Deinococcus radiodurans R1
Narrative:
Radiodurans Annotations
Favorite
Copy
Assembly
06/20/2018
Deinococcus radiodurans A162374
Narrative:
Radiodurans Annotations
Favorite
Copy
Amplicon matrix
06/20/2018
Deinococcus radiodurans R1
Narrative:
Radiodurans Annotations
Favorite
Copy