<commit_before>/*
 * ICESOFT COMMERCIAL SOURCE CODE LICENSE V 1.1
 *
 * The contents of this file are subject to the ICEsoft Commercial Source
 * Code License Agreement V1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of the
 * License at
 * http://www.icesoft.com/license/commercial-source-v1.1.html
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations under
 * the License.
 *
 * Copyright 2009-2014 ICEsoft Technologies Canada, Corp. All Rights Reserved.
 */

var db = require('./db');

var TRANSACTION_HEADER_KEY = 'com.icesoft.services.transaction.id';
module.exports.TRANSACTION_HEADER_KEY = TRANSACTION_HEADER_KEY;

var PROCESS_HEADER_KEY = 'com.icesoft.services.process.id';
module.exports.PROCESS_HEADER_KEY = PROCESS_HEADER_KEY;

//For the purposes of the service scope, a "request" and a "transaction" are the same.  Each
//request to our services is assigned a transactionId that travels through all relevant services
//and is the id which is used to store any request/transaction scoped data.
// var ICESOFT_REQUEST_HEADER = "com.icesoft.services.request.id";

/**
 * Get a specific scope API as defined by the provided scopeIdentifier. The result is
 * a Promise that resolves to a standard API for that particular scope.
 *
 * This is not generally meant for public consumption. Instead, clients should use the
 * concrete methods for the particular scope (getRequestScope, getBackpackScope, etc. ).
 * However, it is possible to use this for managing custom scopes if we want to provide
 * that feature.
 *
 * @param accountName
 * @param realmName
 * @param scopeIdentifier The id of the scope object to create
 * @returns {Promise}
 */
function getScope(accountName, realmName, scopeIdentifier) {

    return new Promise(function (resolve, reject) {

        var scopeId = scopeIdentifier;

        if (!scopeId) {
            reject('missing scope identifier');
        }

        db.getCollection(accountName, realmName, 'scopes', function (err, scopesCollection) {

            if (err) {
                reject(err);
            }

            //This object contains the general API for any scope.  The collection is always
            //the same, the only difference between them is which scopeId is used as the
            //database _id and that's provided when you initially get the scope.
            var scopeAPI = {

                setAttribute: function (key, value) {

                    return new Promise(function (resolve, reject) {

                        var updateAttribute = {};
                        updateAttribute[key] = value;

                        scopesCollection
                            .updateOne(
                                {_scopeId: scopeId},
                                {$set: updateAttribute},
                                {upsert: true})
                            .then(
                                function (result) {
                                    if (result.result && result.result.ok === 1) {
                                        resolve(updateAttribute);
                                    } else {
                                        reject(result.result);
                                    }
                                }
                            )
                            .catch(
                                function (err) {
                                    reject(err);
                                }
                            );
                    });

                },

                getAttribute: function (key) {

                    return new Promise(function (resolve, reject) {

                        scopesCollection
                            .find({_scopeId: scopeId})
                            .toArray()
                            .then(
                                function (result) {
                                    if (result[0] && result[0][key]) {
                                        resolve(result[0][key]);
                                    } else {
                                        resolve();
                                    }
                                }
                            )
                            .catch(
                                function (err) {
                                    reject(err);
                                }
                            );
                    });
                },

                removeAttribute: function (key) {

                    return new Promise(function (resolve, reject) {

                        var removeAttribute = {};
                        removeAttribute[key] = "";

                        scopesCollection
                            .updateOne(
                                {_scopeId: scopeId},
                                {$unset: removeAttribute})
                            .then(
                                function (result) {

                                    if (result.result && result.result.ok === 1) {
                                        resolve(key);
                                    } else {
                                        reject(result.result);
                                    }
                                }
                            )
                            .catch(
                                function (err) {
                                    reject(err);
                                }
                            );
                    });
                },

                getAttributeKeys: function () {

                    return new Promise(function (resolve, reject) {
                        scopesCollection
                            .find({_scopeId: scopeId})
                            .project({_id: 0, _scopeId: 0})
                            .toArray()
                            .then(
                                function (result) {
                                    resolve(Object.keys(result[0]));
                                }
                            )
                            .catch(
                                function (err) {
                                    reject(err);
                                }
                            );
                    });

                },

                getId: function () {
                    return scopeId;
                },

                invalidate: function () {
                    return new Promise(function (resolve, reject) {
                        scopesCollection
                            .remove({_scopeId: scopeId})
                            .then(
                                function (result) {
                                    if (result.result && result.result.ok === 1) {
                                        resolve(scopeId);
                                    } else {
                                        reject(result.result);
                                    }
                                }
                            )
                            .catch(
                                function (err) {
                                    reject(err);
                                }
                            );
                    });
                },

                //The following have not been implemented yet.  They reflect what we know
                //of standard JavaEE session APIs but may or may not be applicable for our
                //purposes.
                getCreationTime: function () {
                    //TODO
                    return new Promise(function (resolve, reject) {
                        resolve();
                    });
                },

                getLastAccessedTime: function () {
                    //TODO
                    return new Promise(function (resolve, reject) {
                        resolve();
                    });
                },

                getMaxInactiveInterval: function () {
                    //TODO
                    return new Promise(function (resolve, reject) {
                        resolve();
                    });
                },

                setMaxInactiveInterval: function (interval) {
                    //TODO
                    return new Promise(function (resolve, reject) {
                        resolve();
                    });
                }

            };

            resolve(scopeAPI);
        });

    });

}
module.exports.getScope = getScope;

// -------------------------
// BASE SCOPE FUNCTIONS
// -------------------------

//The following functions are the base calls used by all scope-related
//functions. They simply use the provided scopeId to operate since all
//scopes use their own id to store the specific data.

function getScopeFromBarrel(barrel, scopeId) {
    return getScope(barrel.accountId, barrel.realmId, scopeId);
}

function setAttribute(barrel, scopeId, key, value) {

    return new Promise(function (resolve, reject) {

        getScopeFromBarrel(barrel, scopeId)
            .then(
                function (scope) {

                    scope.setAttribute(key, value)
                        .then(
                            function (setResult) {
                                resolve(setResult);
                            }
                        )
                        .catch(
                            function (err) {
                                reject(err);
                            }
                        );
                })
            .catch(
                function (err) {
                    reject(err);
                }
            );
    });
}

function getAttribute(barrel, scopeId, key) {

    return new Promise(function (resolve, reject) {

        getScopeFromBarrel(barrel, scopeId)
            .then(
                function (scope) {

                    scope.getAttribute(key)
                        .then(
                            function (getResult) {
                                resolve(getResult);
                            }
                        )
                        .catch(
                            function (err) {
                                reject(err);
                            }
                        );
                })
            .catch(
                function (err) {
                    reject(err);
                }
            );
    });
}

function removeAttribute(barrel, scopeId, key) {

    return new Promise(function (resolve, reject) {

        getScopeFromBarrel(barrel, scopeId)
            .then(
                function (scope) {

                    scope.removeAttribute(key)
                        .then(
                            function (removeResult) {
                                resolve(removeResult);
                            }
                        )
                        .catch(
                            function (err) {
                                reject(err);
                            }
                        );
                })
            .catch(
                function (err) {
                    reject(err);
                }
            );
    });
}

function getAttributeKeys(barrel, scopeId) {

    return new Promise(function (resolve, reject) {

        getScopeFromBarrel(barrel, scopeId)
            .then(
                function (scope) {

                    scope.getAttributeKeys()
                        .then(
                            function (keysResult) {
                                resolve(keysResult);
                            }
                        )
                        .catch(
                            function (err) {
                                reject(err);
                            }
                        );
                })
            .catch(
                function (err) {
                    reject(err);
                }
            );
    });
}

function invalidate(barrel, scopeId) {

    return new Promise(function (resolve, reject) {

        getScopeFromBarrel(barrel, scopeId)
            .then(
                function (scope) {

                    scope.invalidate()
                        .then(
                            function (invalidateResult) {
                                resolve(invalidateResult);
                            }
                        )
                        .catch(
                            function (err) {
                                reject(err);
                            }
                        );
                })
            .catch(
                function (err) {
                    reject(err);
                }
            );
    });
}

/**
 * Extracts the raw request from the barrel and uses that to get
 * the value of the specified header.
 *
 * @param barrel
 * @param headerName
 * @returns {*}
 */
function getHeader(barrel, headerName) {
    //TODO: make sure this is correct and robust
    return barrel.req.headers[headerName];
}

/**
 * Get a listing of all the scopes in the given account and realm.
 *
 * @param accountName The account name
 * @param realmName The realm
 * @returns {Promise}
 */
function getAllScopes(accountName, realmName) {

    return new Promise(function (resolve, reject) {

        db.getCollection(accountName, realmName, 'scopes', function (err, scopesCollection) {

            if (err) {
                reject(err);
            }
            scopesCollection.find().toArray(function (err, scopes) {
                if (err) {
                    console.log('err! ', err);
                    reject(err);
                }
                resolve(scopes);
            });
        });
    });
}
module.exports.getScopesDirectory = getAllScopes;

// -------------------------
// TRANSACTION SCOPE
// -------------------------

/**
 * Get the transaction id header from the request object stored in the barrel.
 *
 * @param barrel
 * @returns {*}
 */
function getTransactionId(barrel) {
    return getHeader(barrel, TRANSACTION_HEADER_KEY);
}

/**
 * Set a transaction-scoped key/value pair.
 *
 * @param barrel
 * @param key
 * @param value
 * @returns {Promise|Promise<T>}
 */
function setTransactionAttribute(barrel, key, value) {
    return setAttribute(barrel, getTransactionId(barrel), key, value);
}
module.exports.setTransactionAttribute = setTransactionAttribute;

/**
 * Get the value of a transaction-scoped attribute.
 *
 * @param barrel
 * @param key
 * @returns {Promise|Promise<T>}
 */
function getTransactionAttribute(barrel, key) {
    return getAttribute(barrel, getTransactionId(barrel), key);
}
module.exports.getTransactionAttribute = getTransactionAttribute;

/**
 * Remove a transaction-scoped key/value pair.
 *
 * @param barrel
 * @param key
 * @returns {Promise|Promise<T>}
 */
function removeTransactionAttribute(barrel, key) {
    return removeAttribute(barrel, getTransactionId(barrel), key);
}
module.exports.removeTransactionAttribute = removeTransactionAttribute;

/**
 * Get all the current transaction-scoped keys.
 *
 * @param barrel
 * @returns {Promise|Promise<T>}
 */
function getTransactionAttributeKeys(barrel) {
    return getAttributeKeys(barrel, getTransactionId(barrel));
}
module.exports.getTransactionAttributeKeys = getTransactionAttributeKeys;

/**
 * Invalidate the current transaction scoped storage.  This should
 * generally be used for cleaning up the entire scope when it's no longer
 * valid.
 *
 * @param barrel
 * @returns {Promise|Promise<T>}
 */
function invalidateTransaction(barrel) {
    return invalidate(barrel, getTransactionId(barrel));
}
module.exports.invalidateTransaction = invalidateTransaction;

// -------------------------
// REALM SCOPE
// -------------------------

/**
 * Get the realm id header from the request object stored in the barrel.
 *
 * @param barrel
 * @returns {*}
 */
function getRealmId(barrel) {
    return "_realm_" + barrel.realmId;
}

/**
 * Set a realm-scoped key/value pair.
 *
 * @param barrel
 * @param key
 * @param value
 * @returns {Promise|Promise<T>}
 */
function setRealmAttribute(barrel, key, value) {
    return setAttribute(barrel, getRealmId(barrel), key, value);
}
module.exports.setRealmAttribute = setRealmAttribute;

/**
 * Get the value of a realm-scoped attribute.
 *
 * @param barrel
 * @param key
 * @returns {Promise|Promise<T>}
 */
function getRealmAttribute(barrel, key) {
    return getAttribute(barrel, getRealmId(barrel), key);
}
module.exports.getRealmAttribute = getRealmAttribute;

/**
 * Remove a realm-scoped key/value pair.
 *
 * @param barrel
 * @param key
 * @returns {Promise|Promise<T>}
 */
function removeRealmAttribute(barrel, key) {
    return removeAttribute(barrel, getRealmId(barrel), key);
}
module.exports.removeRealmAttribute = removeRealmAttribute;

/**
 * Get all the current realm-scoped keys.
 *
 * @param barrel
 * @returns {Promise|Promise<T>}
 */
function getRealmAttributeKeys(barrel) {
    return getAttributeKeys(barrel, getRealmId(barrel));
}
module.exports.getRealmAttributeKeys = getRealmAttributeKeys;

/**
 * Invalidate the current realm-scoped storage.  This should
 * generally be used for cleaning up the entire scope when it's no longer
 * valid.
 *
 * @param barrel
 * @returns {Promise|Promise<T>}
 */
function invalidateRealm(barrel) {
    return invalidate(barrel, getRealmId(barrel));
}
module.exports.invalidateRealm = invalidateRealm;

// -------------------------
// PROCESS SCOPE
// -------------------------

/**
 * Get the process id header from the request object stored in the barrel.
 *
 * @param barrel
 * @returns The current process id (if there is one).
 */
function getProcessId(barrel) {
    return getHeader(barrel, PROCESS_HEADER_KEY);
}

<commit_msg>add the beginnings of an API for Action scoped data<commit_after>/*
 * ICESOFT COMMERCIAL SOURCE CODE LICENSE V 1.1
 *
 * The contents of this file are subject to the ICEsoft Commercial Source
 * Code License Agreement V1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of the
 * License at
 * http://www.icesoft.com/license/commercial-source-v1.1.html
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations under
 * the License.
 *
 * Copyright 2009-2014 ICEsoft Technologies Canada, Corp. All Rights Reserved.
 */

var db = require('./db');

var TRANSACTION_HEADER_KEY = 'com.icesoft.services.transaction.id';
module.exports.TRANSACTION_HEADER_KEY = TRANSACTION_HEADER_KEY;

var PROCESS_HEADER_KEY = 'com.icesoft.services.process.id';
module.exports.PROCESS_HEADER_KEY = PROCESS_HEADER_KEY;

//For the purposes of the service scope, a "request" and a "transaction" are the same.  Each
//request to our services is assigned a transactionId that travels through all relevant services
//and is the id which is used to store any request/transaction scoped data.
// var ICESOFT_REQUEST_HEADER = "com.icesoft.services.request.id";

/**
 * Get a specific scope API as defined by the provided scopeIdentifier. The result is
 * a Promise that resolves to a standard API for that particular scope.
 *
 * This is not generally meant for public consumption. Instead, clients should use the
 * concrete methods for the particular scope (getRequestScope, getBackpackScope, etc. ).
 * However, it is possible to use this for managing custom scopes if we want to provide
 * that feature.
 *
 * @param accountName
 * @param realmName
 * @param scopeIdentifier The id of the scope object to create
 * @returns {Promise}
 */
function getScope(accountName, realmName, scopeIdentifier) {

    return new Promise(function (resolve, reject) {

        var scopeId = scopeIdentifier;

        if (!scopeId) {
            reject('missing scope identifier');
        }

        db.getCollection(accountName, realmName, 'scopes', function (err, scopesCollection) {

            if (err) {
                reject(err);
            }

            //This object contains the general API for any scope.  The collection is always
            //the same, the only difference between them is which scopeId is used as the
            //database _id and that's provided when you initially get the scope.
            var scopeAPI = {

                setAttribute: function (key, value) {

                    return new Promise(function (resolve, reject) {

                        var updateAttribute = {};
                        updateAttribute[key] = value;

                        scopesCollection
                            .updateOne(
                                {_scopeId: scopeId},
                                {$set: updateAttribute},
                                {upsert: true})
                            .then(
                                function (result) {
                                    if (result.result && result.result.ok === 1) {
                                        resolve(updateAttribute);
                                    } else {
                                        reject(result.result);
                                    }
                                }
                            )
                            .catch(
                                function (err) {
                                    reject(err);
                                }
                            );
                    });

                },

                getAttribute: function (key) {

                    return new Promise(function (resolve, reject) {

                        scopesCollection
                            .find({_scopeId: scopeId})
                            .toArray()
                            .then(
                                function (result) {
                                    if (result[0] && result[0][key]) {
                                        resolve(result[0][key]);
                                    } else {
                                        resolve();
                                    }
                                }
                            )
                            .catch(
                                function (err) {
                                    reject(err);
                                }
                            );
                    });
                },

                removeAttribute: function (key) {

                    return new Promise(function (resolve, reject) {

                        var removeAttribute = {};
                        removeAttribute[key] = "";

                        scopesCollection
                            .updateOne(
                                {_scopeId: scopeId},
                                {$unset: removeAttribute})
                            .then(
                                function (result) {

                                    if (result.result && result.result.ok === 1) {
                                        resolve(key);
                                    } else {
                                        reject(result.result);
                                    }
                                }
                            )
                            .catch(
                                function (err) {
                                    reject(err);
                                }
                            );
                    });
                },

                getAttributeKeys: function () {

                    return new Promise(function (resolve, reject) {
                        scopesCollection
                            .find({_scopeId: scopeId})
                            .project({_id: 0, _scopeId: 0})
                            .toArray()
                            .then(
                                function (result) {
                                    resolve(Object.keys(result[0]));
                                }
                            )
                            .catch(
                                function (err) {
                                    reject(err);
                                }
                            );
                    });

                },

                getId: function () {
                    return scopeId;
                },

                invalidate: function () {
                    return new Promise(function (resolve, reject) {
                        scopesCollection
                            .remove({_scopeId: scopeId})
                            .then(
                                function (result) {
                                    if (result.result && result.result.ok === 1) {
                                        resolve(scopeId);
                                    } else {
                                        reject(result.result);
                                    }
                                }
                            )
                            .catch(
                                function (err) {
                                    reject(err);
                                }
                            );
                    });
                },

                //The following have not been implemented yet.  They reflect what we know
                //of standard JavaEE session APIs but may or may not be applicable for our
                //purposes.
                getCreationTime: function () {
                    //TODO
                    return new Promise(function (resolve, reject) {
                        resolve();
                    });
                },

                getLastAccessedTime: function () {
                    //TODO
                    return new Promise(function (resolve, reject) {
                        resolve();
                    });
                },

                getMaxInactiveInterval: function () {
                    //TODO
                    return new Promise(function (resolve, reject) {
                        resolve();
                    });
                },

                setMaxInactiveInterval: function (interval) {
                    //TODO
                    return new Promise(function (resolve, reject) {
                        resolve();
                    });
                }

            };

            resolve(scopeAPI);
        });

    });

}
module.exports.getScope = getScope;

// -------------------------
// BASE SCOPE FUNCTIONS
// -------------------------

//The following functions are the base calls used by all scope-related
//functions. They simply use the provided scopeId to operate since all
//scopes use their own id to store the specific data.

function getScopeFromBarrel(barrel, scopeId) {
    return getScope(barrel.accountId, barrel.realmId, scopeId);
}

function setAttribute(barrel, scopeId, key, value) {

    return new Promise(function (resolve, reject) {

        getScopeFromBarrel(barrel, scopeId)
            .then(
                function (scope) {

                    scope.setAttribute(key, value)
                        .then(
                            function (setResult) {
                                resolve(setResult);
                            }
                        )
                        .catch(
                            function (err) {
                                reject(err);
                            }
                        );
                })
            .catch(
                function (err) {
                    reject(err);
                }
            );
    });
}

function getAttribute(barrel, scopeId, key) {

    return new Promise(function (resolve, reject) {

        getScopeFromBarrel(barrel, scopeId)
            .then(
                function (scope) {

                    scope.getAttribute(key)
                        .then(
                            function (getResult) {
                                resolve(getResult);
                            }
                        )
                        .catch(
                            function (err) {
                                reject(err);
                            }
                        );
                })
            .catch(
                function (err) {
                    reject(err);
                }
            );
    });
}

function removeAttribute(barrel, scopeId, key) {

    return new Promise(function (resolve, reject) {

        getScopeFromBarrel(barrel, scopeId)
            .then(
                function (scope) {

                    scope.removeAttribute(key)
                        .then(
                            function (removeResult) {
                                resolve(removeResult);
                            }
                        )
                        .catch(
                            function (err) {
                                reject(err);
                            }
                        );
                })
            .catch(
                function (err) {
                    reject(err);
                }
            );
    });
}

function getAttributeKeys(barrel, scopeId) {

    return new Promise(function (resolve, reject) {

        getScopeFromBarrel(barrel, scopeId)
            .then(
                function (scope) {

                    scope.getAttributeKeys()
                        .then(
                            function (keysResult) {
                                resolve(keysResult);
                            }
                        )
                        .catch(
                            function (err) {
                                reject(err);
                            }
                        );
                })
            .catch(
                function (err) {
                    reject(err);
                }
            );
    });
}

function invalidate(barrel, scopeId) {

    return new Promise(function (resolve, reject) {

        getScopeFromBarrel(barrel, scopeId)
            .then(
                function (scope) {

                    scope.invalidate()
                        .then(
                            function (invalidateResult) {
                                resolve(invalidateResult);
                            }
                        )
                        .catch(
                            function (err) {
                                reject(err);
                            }
                        );
                })
            .catch(
                function (err) {
                    reject(err);
                }
            );
    });
}

/**
 * Extracts the raw request from the barrel and uses that to get
 * the value of the specified header.
 *
 * @param barrel
 * @param headerName
 * @returns {*}
 */
function getHeader(barrel, headerName) {
    //TODO: make sure this is correct and robust
    return barrel.req.headers[headerName];
}

/**
 * Get a listing of all the scopes in the given account and realm.
 *
 * @param accountName The account name
 * @param realmName The realm
 * @returns {Promise}
 */
function getAllScopes(accountName, realmName) {

    return new Promise(function (resolve, reject) {

        db.getCollection(accountName, realmName, 'scopes', function (err, scopesCollection) {

            if (err) {
                reject(err);
            }
            scopesCollection.find().toArray(function (err, scopes) {
                if (err) {
                    console.log('err! ', err);
                    reject(err);
                }
                resolve(scopes);
            });
        });
    });
}
module.exports.getScopesDirectory = getAllScopes;

// -------------------------
// TRANSACTION SCOPE
// -------------------------

/**
 * Get the transaction id header from the request object stored in the barrel.
 *
 * @param barrel
 * @returns {*}
 */
function getTransactionId(barrel) {
    return getHeader(barrel, TRANSACTION_HEADER_KEY);
}

/**
 * Set a transaction-scoped key/value pair.
 *
 * @param barrel
 * @param key
 * @param value
 * @returns {Promise|Promise<T>}
 */
function setTransactionAttribute(barrel, key, value) {
    return setAttribute(barrel, getTransactionId(barrel), key, value);
}
module.exports.setTransactionAttribute = setTransactionAttribute;

/**
 * Get the value of a transaction-scoped attribute.
 *
 * @param barrel
 * @param key
 * @returns {Promise|Promise<T>}
 */
function getTransactionAttribute(barrel, key) {
    return getAttribute(barrel, getTransactionId(barrel), key);
}
module.exports.getTransactionAttribute = getTransactionAttribute;

/**
 * Remove a transaction-scoped key/value pair.
 *
 * @param barrel
 * @param key
 * @returns {Promise|Promise<T>}
 */
function removeTransactionAttribute(barrel, key) {
    return removeAttribute(barrel, getTransactionId(barrel), key);
}
module.exports.removeTransactionAttribute = removeTransactionAttribute;

/**
 * Get all the current transaction-scoped keys.
 *
 * @param barrel
 * @returns {Promise|Promise<T>}
 */
function getTransactionAttributeKeys(barrel) {
    return getAttributeKeys(barrel, getTransactionId(barrel));
}
module.exports.getTransactionAttributeKeys = getTransactionAttributeKeys;

/**
 * Invalidate the current transaction scoped storage.  This should
 * generally be used for cleaning up the entire scope when it's no longer
 * valid.
 *
 * @param barrel
 * @returns {Promise|Promise<T>}
 */
function invalidateTransaction(barrel) {
    return invalidate(barrel, getTransactionId(barrel));
}
module.exports.invalidateTransaction = invalidateTransaction;

// -------------------------
// REALM SCOPE
// -------------------------

/**
 * Get the realm id header from the request object stored in the barrel.
 *
 * @param barrel
 * @returns {*}
 */
function getRealmId(barrel) {
    return "_realm_" + barrel.realmId;
}

/**
 * Set a realm-scoped key/value pair.
 *
 * @param barrel
 * @param key
 * @param value
 * @returns {Promise|Promise<T>}
 */
function setRealmAttribute(barrel, key, value) {
    return setAttribute(barrel, getRealmId(barrel), key, value);
}
module.exports.setRealmAttribute = setRealmAttribute;

/**
 * Get the value of a realm-scoped attribute.
 *
 * @param barrel
 * @param key
 * @returns {Promise|Promise<T>}
 */
function getRealmAttribute(barrel, key) {
    return getAttribute(barrel, getRealmId(barrel), key);
}
module.exports.getRealmAttribute = getRealmAttribute;

/**
 * Remove a realm-scoped key/value pair.
 *
 * @param barrel
 * @param key
 * @returns {Promise|Promise<T>}
 */
function removeRealmAttribute(barrel, key) {
    return removeAttribute(barrel, getRealmId(barrel), key);
}
module.exports.removeRealmAttribute = removeRealmAttribute;

/**
 * Get all the current realm-scoped keys.
 *
 * @param barrel
 * @returns {Promise|Promise<T>}
 */
function getRealmAttributeKeys(barrel) {
    return getAttributeKeys(barrel, getRealmId(barrel));
}
module.exports.getRealmAttributeKeys = getRealmAttributeKeys;

/**
 * Invalidate the current realm-scoped storage.  This should
 * generally be used for cleaning up the entire scope when it's no longer
 * valid.
 *
 * @param barrel
 * @returns {Promise|Promise<T>}
 */
function invalidateRealm(barrel) {
    return invalidate(barrel, getRealmId(barrel));
}
module.exports.invalidateRealm = invalidateRealm;

// -------------------------
// ACTION SCOPE
// -------------------------

/**
 * Get the currently executing action id from the barrel.
 *
 * @param barrel
 * @returns The current action id (if there is one).
 */
function getActionId(barrel) {

    //TODO: What uniquely identifies the currently running action?
    //      We just need to check and retrieve that information from the
    //      barrel.  For example, if we are in the Action service and
    //      executing an action, the validatedResourceId coupled with something
    //      like the tx id - together that would uniquely identify the scope.
    if (
        barrel.meta && barrel.meta.service && barrel.meta.service === 'action' &&
        barrel.serviceEvent && barrel.serviceEvent === 'execute'
    ) {
        return barrel.validatedResourceId;
    }
    return null;
}

/**
 * Set a action-scoped key/value pair.
 *
 * @param barrel
 * @param key
 * @param value
 * @returns {Promise|Promise<T>}
 */
function setActionAttribute(barrel, key, value) {
    return setAttribute(barrel, getActionId(barrel), key, value);
}
module.exports.setActionAttribute = setActionAttribute;

/**
 * Get the value of a action-scoped attribute.
 *
 * @param barrel
 * @param key
 * @returns {Promise|Promise<T>}
 */
function getActionAttribute(barrel, key) {
    return getAttribute(barrel, getActionId(barrel), key);
}
module.exports.getActionAttribute = getActionAttribute;

/**
 * Remove a action-scoped key/value pair.
 *
 * @param barrel
 * @param key
 * @returns {Promise|Promise<T>}
 */
function removeActionAttribute(barrel, key) {
    return removeAttribute(barrel, getActionId(barrel), key);
}
module.exports.removeActionAttribute = removeActionAttribute;

/**
 * Get all the current action-scoped keys.
 *
 * @param barrel
 * @returns {Promise|Promise<T>}
 */
function getActionAttributeKeys(barrel) {
    return getAttributeKeys(barrel, getActionId(barrel));
}
module.exports.getActionAttributeKeys = getActionAttributeKeys;

/**
 * Invalidate the current action-scoped storage.  This should
 * generally be used for cleaning up the entire scope when it's no longer
 * valid.
 *
 * @param barrel
 * @returns {Promise|Promise<T>}
 */
function invalidateAction(barrel) {
    return invalidate(barrel, getActionId(barrel));
}
module.exports.invalidateAction = invalidateAction;
       <|endoftext|>


<commit_before>var $ = require('jQuery');
var isFirstTime = true;

// SDK Needs to create video and canvas nodes in the DOM in order to function
// Here we are adding those nodes a predefined div.
var divRoot = $("#affdex_elements")[0];
var width = 640;
var height = 480;
var faceMode = affdex.FaceDetectorMode.LARGE_FACES;
//Construct a CameraDetector and specify the image width / height and face detector mode.
var detector = new affdex.CameraDetector(divRoot, width, height, faceMode);

//Enable detection of all Expressions, Emotions and Emojis classifiers.
detector.detectAllEmotions();
detector.detectAllExpressions();
detector.detectAllEmojis();
detector.detectAllAppearance();

//Add a callback to notify when the detector is initialized and ready for runing.
detector.addEventListener("onInitializeSuccess", function() {
    log('#logs', "The detector reports initialized");
    //Display canvas instead of video feed because we want to draw the feature points on it
    $("#face_video_canvas").css("display", "block");
    $("#face_video").css("display", "none");
});

function log(node_name, msg) {
    $(node_name).append("" + msg + "
")
}

//function executes when Start button is pushed.
function onStart() {
    if (detector && !detector.isRunning) {
        $("#logs").html("");
        detector.start();
    }
    log('#logs', "Clicked the start button");
}

//function executes when the Stop button is pushed.
function onStop() {
    log('#logs', "Clicked the stop button");
    if (detector && detector.isRunning) {
        detector.removeEventListener();
        detector.stop();
    }
};

//function executes when the Reset button is pushed.
function onReset() {
    log('#logs', "Clicked the reset button");
    if (detector && detector.isRunning) {
        detector.reset();

        $('#results').html("");
    }
};

//Add a callback to notify when camera access is allowed
detector.addEventListener("onWebcamConnectSuccess", function() {
    log('#logs', "Webcam access allowed");
});

//Add a callback to notify when camera access is denied
detector.addEventListener("onWebcamConnectFailure", function() {
    log('#logs', "webcam denied");
    console.log("Webcam access denied");
});

//Add a callback to notify when detector is stopped
detector.addEventListener("onStopSuccess", function() {
    log('#logs', "The detector reports stopped");
    $("#results").html("");
});

//Add a callback to receive the results from processing an image.
//The faces object contains the list of the faces detected in an image.
//Faces object contains probabilities for all the different expressions, emotions and appearance metrics
detector.addEventListener("onImageResultsSuccess", function(faces, image, timestamp) {
    if (isFirstTime) {
        document.getElementById("video").play();
    } else {
        isFirstTime = false;
    }
    $('#results').html("");
    log('#results', "Timestamp: " + timestamp.toFixed(2));
    log('#results', "Number of faces found: " + faces.length);
    if (faces.length > 0) {
        log('#results', "Appearance: " + JSON.stringify(faces[0].appearance));
        log('#results', "Emotions: " + JSON.stringify(faces[0].emotions, function(key, val) {
            return val.toFixed ? Number(val.toFixed(0)) : val;
        }));
        log('#results', "Expressions: " + JSON.stringify(faces[0].expressions, function(key, val) {
            return val.toFixed ? Number(val.toFixed(0)) : val;
        }));
        log('#results', "Emoji: " + faces[0].emojis.dominantEmoji);
        drawFeaturePoints(image, faces[0].featurePoints);
    }
});

//Draw the detected facial feature points on the image
function drawFeaturePoints(img, featurePoints) {
    var contxt = $('#face_video_canvas')[0].getContext('2d');

    var hRatio = contxt.canvas.width / img.width;
    var vRatio = contxt.canvas.height / img.height;
    var ratio = Math.min(hRatio, vRatio);

    contxt.strokeStyle = "#FFFFFF";
    for (var id in featurePoints) {
        contxt.beginPath();
        contxt.arc(featurePoints[id].x,
            featurePoints[id].y, 2, 0, 2 * Math.PI);
        contxt.stroke();

    }
}

<commit_msg>remove drawing facial feature points function<commit_after>var $ = require('jQuery');
var isFirstTime = true;

// SDK Needs to create video and canvas nodes in the DOM in order to function
// Here we are adding those nodes a predefined div.
var divRoot = $("#affdex_elements")[0];
var width = 640;
var height = 480;
var faceMode = affdex.FaceDetectorMode.LARGE_FACES;
//Construct a CameraDetector and specify the image width / height and face detector mode.
var detector = new affdex.CameraDetector(divRoot, width, height, faceMode);

//Enable detection of all Expressions, Emotions and Emojis classifiers.
detector.detectAllEmotions();
detector.detectAllExpressions();
detector.detectAllEmojis();
detector.detectAllAppearance();

//Add a callback to notify when the detector is initialized and ready for runing.
detector.addEventListener("onInitializeSuccess", function() {
    log('#logs', "The detector reports initialized");
    //Display canvas instead of video feed because we want to draw the feature points on it
    $("#face_video_canvas").css("display", "block");
    $("#face_video").css("display", "none");
});

function log(node_name, msg) {
    $(node_name).append("" + msg + "
")
}

//function executes when Start button is pushed.
function onStart() {
    if (detector && !detector.isRunning) {
        $("#logs").html("");
        detector.start();
    }
    log('#logs', "Clicked the start button");
}

//function executes when the Stop button is pushed.
function onStop() {
    log('#logs', "Clicked the stop button");
    if (detector && detector.isRunning) {
        detector.removeEventListener();
        detector.stop();
    }
};

//function executes when the Reset button is pushed.
function onReset() {
    log('#logs', "Clicked the reset button");
    if (detector && detector.isRunning) {
        detector.reset();

        $('#results').html("");
    }
};

//Add a callback to notify when camera access is allowed
detector.addEventListener("onWebcamConnectSuccess", function() {
    log('#logs', "Webcam access allowed");
});

//Add a callback to notify when camera access is denied
detector.addEventListener("onWebcamConnectFailure", function() {
    log('#logs', "webcam denied");
    console.log("Webcam access denied");
});

//Add a callback to notify when detector is stopped
detector.addEventListener("onStopSuccess", function() {
    log('#logs', "The detector reports stopped");
    $("#results").html("");
});

//Add a callback to receive the results from processing an image.
//The faces object contains the list of the faces detected in an image.
//Faces object contains probabilities for all the different expressions, emotions and appearance metrics
detector.addEventListener("onImageResultsSuccess", function(faces, image, timestamp) {
    if (isFirstTime) {
        document.getElementById("video").play();
    } else {
        isFirstTime = false;
    }
    $('#results').html("");
    log('#results', "Timestamp: " + timestamp.toFixed(2));
    log('#results', "Number of faces found: " + faces.length);
    if (faces.length > 0) {
        log('#results', "Appearance: " + JSON.stringify(faces[0].appearance));
        log('#results', "Emotions: " + JSON.stringify(faces[0].emotions, function(key, val) {
            return val.toFixed ? Number(val.toFixed(0)) : val;
        }));
        log('#results', "Expressions: " + JSON.stringify(faces[0].expressions, function(key, val) {
            return val.toFixed ? Number(val.toFixed(0)) : val;
        }));
        log('#results', "Emoji: " + faces[0].emojis.dominantEmoji);
    }
});

<|endoftext|>


<commit_before>var xl = require('excel4node');
var xml = require('xml');
var tabular = require('tabular-json');

module.exports = function(config) {
  return function(req, res, next) {
    res.sendme = function(json) {
      function send(json, extension, filename) {
        var options = {};
        if (typeof config !== 'undefined') {
          for (var prop in config) {
            options[prop] = config[prop];
          }
        }
        if (typeof config[extension] !== undefined) {
          for (var p in config[extension]) {
            options[p] = config[extension][p];
          }
        }
        switch (extension) {
        case 'json':
          res.json(json);
          break;
        case 'xml':
          if (json instanceof Array) {
            var wrap = {};
            wrap.data = json;
            res.send(xml(wrap, {declaration: true}));
          } else res.send(xml(json, {declaration: true}));
          break;
        case 'xlsx':
          var wb = new xl.WorkBook();
          var ws = wb.WorkSheet(filename);
          var rows = tabular.array(json, options);
          for (var r=1; r<=rows.length; r++) {
            for (var c=1; c<=rows[r-1].length; c++) {
              var v = rows[r-1][c-1];
              if (typeof v === 'string') {
                ws.Cell(r,c).String(v);
              } else if (v instanceof Date) {
                ws.Cell(r,c).Date(v);
              } else if (v) {
                ws.Cell(r,c).Number(v);
              }
            }
          }
          wb.write(filename+"."+extension, res);
          break;
        case 'csv':
          res.send(tabular.delimit(json, options));
          break;
        case 'html':
          res.send(tabular.html(json, options));
          break;
        default:
          options.separator = typeof options.separator !== 'undefined' ? options.separator : '\t';
          options.stringWrap = typeof options.stringWrap !== 'undefined' ? options.stringWrap : '';
          res.send(tabular.delimit(json, options));
          break;
        }
      }

      var filename = req.path.split('/').pop();
      filename = filename.split('.');
      var extension = filename.pop();
      filename = filename.join('.');
      switch (extension) {
      case 'json':
        res.set('Content-Type', 'application/json');
        send(json, 'json', filename);
        break;
      case 'xml':
        res.set('Content-Type', 'text/xml');
        send(json, 'xml', filename);
        break;
      case 'xlsx':
        res.set('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
        send(json, 'xlsx', filename);
        break;
      case 'csv':
        res.set('Content-Type', 'application/csv');
        send(json, 'csv', filename);
        break;
      case 'html':
        res.set('Content-Type', 'text/html');
        send(json, 'html', filename);
        break;
      case 'txt':
        res.set('Content-Type', 'text/plain');
        send(json, 'txt', filename);
        break;
      default:
        res.format({
          'application/json': function(){
            send(json, 'json', filename);
          },
          'application/xml': function() {
            send(json, 'xml', filename);
          },
          'text/xml': function(){
            send(json, 'xml', filename);
          },
          'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': function() {
            send(json, 'xlsx', filename);
          },
          'application/csv': function() {
            send(json, 'csv', filename);
          },
          'text/html': function(){
            send(json, 'html', filename);
          },
          'text/plain': function(){
            send(json, 'txt', filename);
          },
          'default': function() {
            res.status(406).json('Not Acceptable');
          }
        });
      }

    };
    next();
  };
};
<commit_msg>Bug fix.<commit_after>var xl = require('excel4node');
var xml = require('xml');
var tabular = require('tabular-json');

module.exports = function(config) {
  return function(req, res, next) {
    res.sendme = function(json) {
      function send(json, extension, filename) {
        var options = {};
        if (typeof config !== 'undefined') {
          for (var prop in config) {
            options[prop] = config[prop];
          }
          if (typeof config[extension] !== 'undefined') {
            for (var p in config[extension]) {
              options[p] = config[extension][p];
            }
          }
        }
        switch (extension) {
        case 'json':
          res.json(json);
          break;
        case 'xml':
          if (json instanceof Array) {
            var wrap = {};
            wrap.data = json;
            res.send(xml(wrap, {declaration: true}));
          } else res.send(xml(json, {declaration: true}));
          break;
        case 'xlsx':
          var wb = new xl.WorkBook();
          var ws = wb.WorkSheet(filename);
          var rows = tabular.array(json, options);
          for (var r=1; r<=rows.length; r++) {
            for (var c=1; c<=rows[r-1].length; c++) {
              var v = rows[r-1][c-1];
              if (typeof v === 'string') {
                ws.Cell(r,c).String(v);
              } else if (v instanceof Date) {
                ws.Cell(r,c).Date(v);
              } else if (v) {
                ws.Cell(r,c).Number(v);
              }
            }
          }
          wb.write(filename+"."+extension, res);
          break;
        case 'csv':
          res.send(tabular.delimit(json, options));
          break;
        case 'html':
          res.send(tabular.html(json, options));
          break;
        default:
          options.separator = typeof options.separator !== 'undefined' ? options.separator : '\t';
          options.stringWrap = typeof options.stringWrap !== 'undefined' ? options.stringWrap : '';
          res.send(tabular.delimit(json, options));
          break;
        }
      }

      var filename = req.path.split('/').pop();
      filename = filename.split('.');
      var extension = filename.pop();
      filename = filename.join('.');
      switch (extension) {
      case 'json':
        res.set('Content-Type', 'application/json');
        send(json, 'json', filename);
        break;
      case 'xml':
        res.set('Content-Type', 'text/xml');
        send(json, 'xml', filename);
        break;
      case 'xlsx':
        res.set('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
        send(json, 'xlsx', filename);
        break;
      case 'csv':
        res.set('Content-Type', 'application/csv');
        send(json, 'csv', filename);
        break;
      case 'html':
        res.set('Content-Type', 'text/html');
        send(json, 'html', filename);
        break;
      case 'txt':
        res.set('Content-Type', 'text/plain');
        send(json, 'txt', filename);
        break;
      default:
        res.format({
          'application/json': function(){
            send(json, 'json', filename);
          },
          'application/xml': function() {
            send(json, 'xml', filename);
          },
          'text/xml': function(){
            send(json, 'xml', filename);
          },
          'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': function() {
            send(json, 'xlsx', filename);
          },
          'application/csv': function() {
            send(json, 'csv', filename);
          },
          'text/html': function(){
            send(json, 'html', filename);
          },
          'text/plain': function(){
            send(json, 'txt', filename);
          },
          'default': function() {
            res.status(406).json('Not Acceptable');
          }
        });
      }

    };
    next();
  };
};
<|endoftext|>


<commit_before>var xl = require('excel4node');
var xml = require('js2xmlparser');
var tabular = require('tabular-json');

module.exports = function(config) {
  return function(req, res, next) {
    res.sendme = function(json) {
      function send(json, extension, filename) {
        var options = {};
        if (typeof config !== 'undefined') {
          config.sort = typeof config.sort !== 'undefined' ? config.sort : req.query.sort.split(',') || [];
          for (var prop in config) {
            options[prop] = config[prop];
          }
          if (typeof config[extension] !== 'undefined') {
            for (var p in config[extension]) {
              options[p] = config[extension][p];
            }
          }
        }
        switch (extension) {
        case 'json':
          res.json(json);
          break;
        case 'xml':
          if (json instanceof Array) {
            var wrap = {};
            wrap[filename] = json;
            res.send(xml('data', wrap));
          } else res.send(xml(filename, json));
          break;
        case 'xlsx':
          var wb = new xl.WorkBook();
          var ws = wb.WorkSheet(filename);
          var rows = tabular.array(json, options);
          for (var r=1; r<=rows.length; r++) {
            for (var c=1; c<=rows[r-1].length; c++) {
              var v = rows[r-1][c-1];
              if (typeof v === 'string') {
                ws.Cell(r,c).String(v);
              } else if (v instanceof Date) {
                ws.Cell(r,c).Date(v);
              } else if (v) {
                ws.Cell(r,c).Number(v);
              }
            }
          }
          wb.write(filename+"."+extension, res);
          break;
        case 'csv':
          res.send(tabular.delimit(json, options));
          break;
        case 'html':
          res.send(tabular.html(json, options));
          break;
        default:
          options.separator = typeof options.separator !== 'undefined' ? options.separator : '\t';
          options.stringWrap = typeof options.stringWrap !== 'undefined' ? options.stringWrap : '';
          res.send(tabular.delimit(json, options));
          break;
        }
      }

      var filename = req.path.split('/').pop();
      filename = filename.split('.');
      var extension = filename.pop();
      filename = filename.join('.');
      switch (extension) {
      case 'json':
        res.set('Content-Type', 'application/json');
        send(json, 'json', filename);
        break;
      case 'xml':
        res.set('Content-Type', 'text/xml');
        send(json, 'xml', filename);
        break;
      case 'xlsx':
        res.set('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
        send(json, 'xlsx', filename);
        break;
      case 'csv':
        res.set('Content-Type', 'application/csv');
        send(json, 'csv', filename);
        break;
      case 'html':
        res.set('Content-Type', 'text/html');
        send(json, 'html', filename);
        break;
      case 'txt':
        res.set('Content-Type', 'text/plain');
        send(json, 'txt', filename);
        break;
      default:
        res.format({
          'application/json': function(){
            send(json, 'json', filename);
          },
          'application/xml': function() {
            send(json, 'xml', filename);
          },
          'text/xml': function(){
            send(json, 'xml', filename);
          },
          'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': function() {
            send(json, 'xlsx', filename);
          },
          'application/csv': function() {
            send(json, 'csv', filename);
          },
          'text/html': function(){
            send(json, 'html', filename);
          },
          'text/plain': function(){
            send(json, 'txt', filename);
          },
          'default': function() {
            res.status(406).json('Not Acceptable');
          }
        });
      }

    };
    next();
  };
};
<commit_msg>Removed req.query.sort<commit_after>var xl = require('excel4node');
var xml = require('js2xmlparser');
var tabular = require('tabular-json');

module.exports = function(config) {
  return function(req, res, next) {
    res.sendme = function(json, sendOpts) {
      function send(json, extension, filename) {
        var options = {};
        options = typeof options !== 'undefined' ? options : {};
        if (typeof config !== 'undefined') {
          for (var prop in config) {
            options[prop] = config[prop];
          }
          if (typeof config[extension] !== 'undefined') {
            for (var p in config[extension]) {
              options[p] = config[extension][p];
            }
          }
        }
        if (typeof sendOpts === 'object') {
          for (var sendProp in sendOpts) {
            options[sendProp] = sendOpts[sendProp];
          }
        }
        switch (extension) {
        case 'json':
          res.json(json);
          break;
        case 'xml':
          if (json instanceof Array) {
            var wrap = {};
            wrap[filename] = json;
            res.send(xml('data', wrap));
          } else res.send(xml(filename, json));
          break;
        case 'xlsx':
          var wb = new xl.WorkBook();
          var ws = wb.WorkSheet(filename);
          var rows = tabular.array(json, options);
          for (var r=1; r<=rows.length; r++) {
            for (var c=1; c<=rows[r-1].length; c++) {
              var v = rows[r-1][c-1];
              if (typeof v === 'string') {
                ws.Cell(r,c).String(v);
              } else if (v instanceof Date) {
                ws.Cell(r,c).Date(v);
              } else if (v) {
                ws.Cell(r,c).Number(v);
              }
            }
          }
          wb.write(filename+"."+extension, res);
          break;
        case 'csv':
          res.send(tabular.delimit(json, options));
          break;
        case 'html':
          res.send(tabular.html(json, options));
          break;
        default:
          options.separator = typeof options.separator !== 'undefined' ? options.separator : '\t';
          options.stringWrap = typeof options.stringWrap !== 'undefined' ? options.stringWrap : '';
          res.send(tabular.delimit(json, options));
          break;
        }
      }

      var filename = req.path.split('/').pop();
      filename = filename.split('.');
      var extension = filename.pop();
      filename = filename.join('.');
      switch (extension) {
      case 'json':
        res.set('Content-Type', 'application/json');
        send(json, 'json', filename);
        break;
      case 'xml':
        res.set('Content-Type', 'text/xml');
        send(json, 'xml', filename);
        break;
      case 'xlsx':
        res.set('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
        send(json, 'xlsx', filename);
        break;
      case 'csv':
        res.set('Content-Type', 'application/csv');
        send(json, 'csv', filename);
        break;
      case 'html':
        res.set('Content-Type', 'text/html');
        send(json, 'html', filename);
        break;
      case 'txt':
        res.set('Content-Type', 'text/plain');
        send(json, 'txt', filename);
        break;
      default:
        res.format({
          'application/json': function(){
            send(json, 'json', filename);
          },
          'application/xml': function() {
            send(json, 'xml', filename);
          },
          'text/xml': function(){
            send(json, 'xml', filename);
          },
          'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': function() {
            send(json, 'xlsx', filename);
          },
          'application/csv': function() {
            send(json, 'csv', filename);
          },
          'text/html': function(){
            send(json, 'html', filename);
          },
          'text/plain': function(){
            send(json, 'txt', filename);
          },
          'default': function() {
            res.status(406).json('Not Acceptable');
          }
        });
      }

    };
    next();
  };
};
<|endoftext|>


<commit_before>var naan = require('naan');
var async = require('async');
var request = require('request');
var _ = require('underscore');
var assert = require('assert');
var util = require('util');
var Core = require('seraph-core');

// Bind all functions of an object to a context (recursively)
var bindAllTo = function(context, all) {
  return Object.keys(all).reduce(function(bound, key) {
    if (typeof all[key] == 'object') bound[key] = bindAllTo(context, all[key]);
    else if (typeof all[key] == 'function') bound[key] = all[key].bind(context);
    else bound[key] = all[key];
    return bound;
  }, {});
}

// Polyfill Object.setPrototypeOf for older node versions.
var setPrototypeOf = Object.setPrototypeOf || function setPrototypeOfPolyfill(obj, proto) { obj.__proto__ = proto; };

function Seraph(options) {
  var core = new Core(options);

  setPrototypeOf(Object.getPrototypeOf(this), core);
  this.options = core.options;

  _.bindAll.apply(_, [this].concat(_.functions(this)));

  this.node = bindAllTo(this, require('./node'));
  this.relationship = this.rel = bindAllTo(this, require('./relationship'));
  this.index = bindAllTo(this, require('./index'));
  this.constraints = bindAllTo(this, require('./constraints'));
  var legacyindexGeneric = bindAllTo(this, require('./legacyindex'));

  // Alias & curry seraph.index on seraph.node & seraph.rel
  this.node.legacyindex = naan.curry(legacyindexGeneric.add, 'node');
  this.rel.legacyindex = naan.curry(legacyindexGeneric.add, 'relationship');
  naan.ecrock(this.node.legacyindex, legacyindexGeneric, naan.curry, 'node');
  naan.ecrock(this.rel.legacyindex, legacyindexGeneric, naan.curry, 'relationship');

  _.extend(this, this.node);
}

// returns a new batch if the context was not already that of a batch - prevents
// batch nesting which can break intra-batch referencing
Seraph.prototype._safeBatch = function() {
  return this.isBatch ? this : this.batch();
};

// similarly, this takes a BatchSeraph and only commits it if the calling context
// is not that of a batch.
Seraph.prototype._safeBatchCommit = function(txn, callback) {
  if (this.isBatch) {
    if (callback) this.commitCallbacks.push(callback);
  } else {
    txn.commit(callback);
  }
};

/**
 * If `obj` is an object, return the value of key <options.id>. Otherwise,
 * return `obj`.
 *
 * If `requireData` is truthy, `obj` must be an object, otherwise undefined is
 * returned.
 */
Seraph.prototype._getId = function(obj, requireData) {
  var id;
  if (requireData) {
    id = typeof obj == 'object' ? obj[this.options.id] : undefined;
  } else if (this._isBatchId(obj)) {
    return obj;
  } else {
    id = typeof obj == 'object' ? obj[this.options.id] : obj;
  }

  if (id != null) id = parseInt(id, 10);
  return id;
};

Seraph.prototype._isValidId = function(id) {
  return !isNaN(parseInt(id, 10)) || this._isBatchId(id);
};

/**
 * Take the end off a url and parse it as an int
 */
Seraph.prototype._extractId = function(location) {
  var matches = location.match(/\/(\d+)$/);
  if (!matches) {
    return null;
  }

  return parseInt(matches[1], 10);
};

/**
 * Infer whether or not the given object is a node
 */
Seraph.nodeFlags = [
  'outgoing_relationships',
  'incoming_relationships',
  'all_relationships',
  'data',
  'properties',
  'self'
];
Seraph.prototype._isNode = function(node) {
  if (!node || typeof node !== 'object') {
    return false;
  }

  var inNode = node.hasOwnProperty.bind(node);
  return Seraph.nodeFlags.every(inNode) &&
         typeof node.data === 'object';
};

/**
 * Infer whether or not the given object is a relationship
 */
Seraph.relationshipFlags = [
  'start',
  'data',
  'self',
  'properties',
  'end'
];
Seraph.prototype._isRelationship = function(rel) {
  if (!rel || typeof rel !== 'object') {
    return false;
  }

  var inRelationship = rel.hasOwnProperty.bind(rel);
  return Seraph.relationshipFlags.every(inRelationship) &&
         typeof rel.data === 'object';
};

Seraph.prototype._isBatchId = function(id) {
  return this.isBatch && typeof id == 'string' && id.match(/^{\d+}$/);
};

Seraph.prototype._nodeRoot = function(id) {
  return this._isBatchId(id) ? id : 'node/' + id;
};

Seraph.prototype._relRoot = function(id) {
  return this._isBatchId(id) ? id : 'relationship/' + id;
};

/**
 * Returns the url to an entity given an id
 */
Seraph.prototype._location = function(type, id) {
  if (this._isBatchId(id)) return id;
  return util.format('%s%s/%s/%d',
                     this.options.server, this.options.endpoint, type, id);
};

/**
 * Create a relationship object from the given relationship data returned from
 * the neo4j server
 */
Seraph.prototype._createRelationshipObject = function(relationshipData) {
  var relationshipObj = {
    start: this._extractId(relationshipData.start),
    end: this._extractId(relationshipData.end),
    type: relationshipData.type,
    properties: relationshipData.data
  };

  relationshipObj[this.options.id] = this._extractId(relationshipData.self);

  return relationshipObj;
};

/**
 * Create a node object from the given node data return from the neo4j server
 */
Seraph.prototype._createNodeObject = function(nodeData) {
  var nodeObj = nodeData.data || {};
  nodeObj[this.options.id] = this._extractId(nodeData.self);

  return nodeObj;
};

  /**
   * Perform a cypher query. Maps to POST cypher
   */
Seraph.prototype.queryRaw = function(query, params, callback) {
  if (typeof query !== 'string') {
    return callback(new Error('Invalid Query'));
  }
  if (typeof params !== 'object') {
    if (typeof params === 'function') {
      callback = params;
    }
    params = {};
  }

  query = { statements: [ {
    statement: query,
    parameters: params,
    resultDataContents: ['REST']
  } ] } ;
  var op = this.operation('transaction/commit', query);
  this.call(op, function(err, result) {
    if (err || result.errors[0]) {
      callback(err || result.errors[0]);
    } else {
      result = result.results[0];
      result.data = result.data.map(function(row) { return row.rest });
      callback(null, result);
    }
  });
};

Seraph.prototype._parseQueryResult = function(result) {
  var self = this;
  var namedResults = result.data.map(function(row) {
    return result.columns.reduce(function(rowObj, columnName, columnIndex) {
      var resultItem = row[columnIndex];
      function extractAttributes(item) {
        if (self._isNode(item)) {
          return self._createNodeObject(item);
        } else if (self._isRelationship(item)) {
          return self._createRelationshipObject(item);
        } else if (Array.isArray(item)) {
          return item.map(extractAttributes);
        } else if (item === Object(item)) {
          return _.mapObject(item, extractAttributes);
        } else {
          return item;
        }
      }

      rowObj[columnName] = extractAttributes(resultItem);

      return rowObj;
    }, {});
  });

  if (namedResults.length > 0) {
    var resultsAreObjects = typeof namedResults[0][result.columns[0]] == 'object';
    if (result.columns.length === 1 && resultsAreObjects) {
      namedResults = namedResults.map(function(namedResult) {
        return namedResult[result.columns[0]];
      });
    } else if (namedResults.length == 1 && !resultsAreObjects) {
      namedResults = namedResults[0];
    }
  }

  return namedResults;
}

/**
 * Perform a cypher query and map the columns and results together.
 */
Seraph.prototype.query = function(query, params, callback) {
  if (typeof params !== 'object') {
    if (typeof params === 'function') {
      callback = params;
    }
    params = {};
  }

  var self = this;
  this.queryRaw(query, params, function(err, result) {
    if (err) {
      return callback(err);
    }

    callback(null, self._parseQueryResult(result));
  });
};

var globalCounter = 0;
function wrapForBatchFormat(id) { return '{' + id + '}' };
function BatchSeraphId(id, refersTo, batch) {
  if (Array.isArray(refersTo)) {
    refersTo = refersTo.map(wrapForBatchFormat);
    refersTo.forEach(function(id, index) {
      this[index] = id;
    }.bind(this));
  } else {
    refersTo = wrapForBatchFormat(refersTo);
  }

  this.id = id;
  this.refersTo = refersTo;
  this.batch = batch;
}
Object.defineProperty(BatchSeraphId.prototype, 'valueOf', {
  enumerable: false, configurable: false, writable: false,
  value: function() { return this.id }
});
Object.defineProperty(BatchSeraphId.prototype, 'toString', {
  enumerable: false, configurable: false, writable: false,
  value: function() { return this.id }
});

function BatchSeraph(parentSeraph) {
  var self = this;
  var uniq = Date.now() + ++globalCounter;

  function isBatchId(id) {
    return id instanceof BatchSeraphId && id.batch == uniq;
  };

  function createId(id, refersTo) {
    return new BatchSeraphId(id, refersTo, uniq);
  };

  function transformBatchArgs(args) {
    return args.map(function(arg) {
      if (Array.isArray(arg)) return transformBatchArgs(arg);
      return isBatchId(arg) ? arg.refersTo : arg;
    });
  };

  function wrapFunctions(parent, target) {
    var derived = target || {};

    Object.keys(parent).forEach(function(key) {
      var valueType = typeof parent[key];

      if (valueType === 'function') {
        derived[key] = wrapFunction(parent[key]);

        if (Object.keys(parent[key]).length > 0) {
          derived[key] = wrapFunctions(parent[key], derived[key]);
        }
      } else if (valueType === 'object') {
        derived[key] = wrapFunctions(parent[key]);
      } else {
        derived[key] = parent[key];
      }
    });
    return derived;
  }

  function wrapFunction(fn) {
    fn = naan.rcurry(fn, function(err, result) {
      if (err && !self.error) self.error = err;
      self.results.push(result);
      var cb = self.callbacks.shift();
      if (cb) cb(err, result);
    });
    return function() {
      self.operationQueueStack.unshift([]);

      var args = [].slice.apply(arguments);

      if (args.length > 1 && typeof args[args.length - 1] == 'function') {
        self.callbacks.push(args.pop());
      } else {
        self.callbacks.push(null);
      }

      args = transformBatchArgs(args);

      // Context does not matter because all functions are bound upon seraph init
      fn.apply(undefined, args);

      var operationIds = _.pluck(self.operationQueueStack[0], 'id');
      self.operationQueueStack.shift();

      var operationId = operationIds.length
        ? operationIds[0] - self.operationOffset : undefined;

      if (operationIds.length > 1) {
        self.operationOffset += operationIds.length - 1;
        operationId = createId(operationId, operationIds);
      } else if (operationId != null) {
        operationId = createId(operationId, operationIds[0]);
      }

      return operationId;
    };
  }

  this.super = new Seraph(parentSeraph.options);
  this.__proto__ = wrapFunctions(this.super);
  this.isBatch = this.super.isBatch = true;
  this.batch = undefined; // disabled nesting.
  this.processors = [];
  this.operations = [];
  this.callbacks = [];
  this.results = [];
  this.operationOffset = 0;
  this.operationQueueStack = [];
  this.commitCallbacks = [];

  this.super.call = function(operation, processor) {
    operation.id = self.operations.length;
    if (!operation.body) delete operation.body;

    self.operations.push(operation);
    self.processors.push(processor.bind(self.super));
    self.operationQueueStack[0].push(operation);
  };

  this.commit = function(callback) {
    if (callback) self.commitCallbacks.push(callback);
    if (self.error) {
      return self.commitCallbacks.forEach(function(callback) {
        callback(self.error);
      });
    }
    var op = parentSeraph.operation('batch', 'POST', self.operations);
    parentSeraph.call(op, function(err, results) {
      if (err) {
        while (self.callbacks.length) {
          var cb = self.callbacks.shift();
          if (cb) cb(err);
        }
        return self.commitCallbacks.forEach(function(callback) {
          callback(err);
        });
      }

      results.forEach(function(result) {
        self.processors.shift()(null, result.body || {}, result.location);
      });

      self.commitCallbacks.forEach(function(callback) {
        callback(null, self.results);
      });
    });
  };
}

Seraph.prototype.isBatch = false;

Seraph.prototype.batch = function(operations, callback) {
  if (!arguments.length) return new BatchSeraph(this);

  var batchSeraph = new BatchSeraph(this);
  operations(batchSeraph);
  batchSeraph.commit(callback);
};

module.exports = function(options) {
  if (options && options.thunkify) {
    delete options.thunkify;
    return require('../co')(options);
  }
  return new Seraph(options);
};
<commit_msg>Some keys could have null or undefined values, especially with the agent support it's true. So avoid walking down such keys.<commit_after>var naan = require('naan');
var async = require('async');
var request = require('request');
var _ = require('underscore');
var assert = require('assert');
var util = require('util');
var Core = require('seraph-core');

// Bind all functions of an object to a context (recursively)
var bindAllTo = function(context, all) {
  return Object.keys(all).reduce(function(bound, key) {
    if (typeof all[key] == 'object') bound[key] = bindAllTo(context, all[key]);
    else if (typeof all[key] == 'function') bound[key] = all[key].bind(context);
    else bound[key] = all[key];
    return bound;
  }, {});
}

// Polyfill Object.setPrototypeOf for older node versions.
var setPrototypeOf = Object.setPrototypeOf || function setPrototypeOfPolyfill(obj, proto) { obj.__proto__ = proto; };

function Seraph(options) {
  var core = new Core(options);

  setPrototypeOf(Object.getPrototypeOf(this), core);
  this.options = core.options;

  _.bindAll.apply(_, [this].concat(_.functions(this)));

  this.node = bindAllTo(this, require('./node'));
  this.relationship = this.rel = bindAllTo(this, require('./relationship'));
  this.index = bindAllTo(this, require('./index'));
  this.constraints = bindAllTo(this, require('./constraints'));
  var legacyindexGeneric = bindAllTo(this, require('./legacyindex'));

  // Alias & curry seraph.index on seraph.node & seraph.rel
  this.node.legacyindex = naan.curry(legacyindexGeneric.add, 'node');
  this.rel.legacyindex = naan.curry(legacyindexGeneric.add, 'relationship');
  naan.ecrock(this.node.legacyindex, legacyindexGeneric, naan.curry, 'node');
  naan.ecrock(this.rel.legacyindex, legacyindexGeneric, naan.curry, 'relationship');

  _.extend(this, this.node);
}

// returns a new batch if the context was not already that of a batch - prevents
// batch nesting which can break intra-batch referencing
Seraph.prototype._safeBatch = function() {
  return this.isBatch ? this : this.batch();
};

// similarly, this takes a BatchSeraph and only commits it if the calling context
// is not that of a batch.
Seraph.prototype._safeBatchCommit = function(txn, callback) {
  if (this.isBatch) {
    if (callback) this.commitCallbacks.push(callback);
  } else {
    txn.commit(callback);
  }
};

/**
 * If `obj` is an object, return the value of key <options.id>. Otherwise,
 * return `obj`.
 *
 * If `requireData` is truthy, `obj` must be an object, otherwise undefined is
 * returned.
 */
Seraph.prototype._getId = function(obj, requireData) {
  var id;
  if (requireData) {
    id = typeof obj == 'object' ? obj[this.options.id] : undefined;
  } else if (this._isBatchId(obj)) {
    return obj;
  } else {
    id = typeof obj == 'object' ? obj[this.options.id] : obj;
  }

  if (id != null) id = parseInt(id, 10);
  return id;
};

Seraph.prototype._isValidId = function(id) {
  return !isNaN(parseInt(id, 10)) || this._isBatchId(id);
};

/**
 * Take the end off a url and parse it as an int
 */
Seraph.prototype._extractId = function(location) {
  var matches = location.match(/\/(\d+)$/);
  if (!matches) {
    return null;
  }

  return parseInt(matches[1], 10);
};

/**
 * Infer whether or not the given object is a node
 */
Seraph.nodeFlags = [
  'outgoing_relationships',
  'incoming_relationships',
  'all_relationships',
  'data',
  'properties',
  'self'
];
Seraph.prototype._isNode = function(node) {
  if (!node || typeof node !== 'object') {
    return false;
  }

  var inNode = node.hasOwnProperty.bind(node);
  return Seraph.nodeFlags.every(inNode) &&
         typeof node.data === 'object';
};

/**
 * Infer whether or not the given object is a relationship
 */
Seraph.relationshipFlags = [
  'start',
  'data',
  'self',
  'properties',
  'end'
];
Seraph.prototype._isRelationship = function(rel) {
  if (!rel || typeof rel !== 'object') {
    return false;
  }

  var inRelationship = rel.hasOwnProperty.bind(rel);
  return Seraph.relationshipFlags.every(inRelationship) &&
         typeof rel.data === 'object';
};

Seraph.prototype._isBatchId = function(id) {
  return this.isBatch && typeof id == 'string' && id.match(/^{\d+}$/);
};

Seraph.prototype._nodeRoot = function(id) {
  return this._isBatchId(id) ? id : 'node/' + id;
};

Seraph.prototype._relRoot = function(id) {
  return this._isBatchId(id) ? id : 'relationship/' + id;
};

/**
 * Returns the url to an entity given an id
 */
Seraph.prototype._location = function(type, id) {
  if (this._isBatchId(id)) return id;
  return util.format('%s%s/%s/%d',
                     this.options.server, this.options.endpoint, type, id);
};

/**
 * Create a relationship object from the given relationship data returned from
 * the neo4j server
 */
Seraph.prototype._createRelationshipObject = function(relationshipData) {
  var relationshipObj = {
    start: this._extractId(relationshipData.start),
    end: this._extractId(relationshipData.end),
    type: relationshipData.type,
    properties: relationshipData.data
  };

  relationshipObj[this.options.id] = this._extractId(relationshipData.self);

  return relationshipObj;
};

/**
 * Create a node object from the given node data return from the neo4j server
 */
Seraph.prototype._createNodeObject = function(nodeData) {
  var nodeObj = nodeData.data || {};
  nodeObj[this.options.id] = this._extractId(nodeData.self);

  return nodeObj;
};

  /**
   * Perform a cypher query. Maps to POST cypher
   */
Seraph.prototype.queryRaw = function(query, params, callback) {
  if (typeof query !== 'string') {
    return callback(new Error('Invalid Query'));
  }
  if (typeof params !== 'object') {
    if (typeof params === 'function') {
      callback = params;
    }
    params = {};
  }

  query = { statements: [ {
    statement: query,
    parameters: params,
    resultDataContents: ['REST']
  } ] } ;
  var op = this.operation('transaction/commit', query);
  this.call(op, function(err, result) {
    if (err || result.errors[0]) {
      callback(err || result.errors[0]);
    } else {
      result = result.results[0];
      result.data = result.data.map(function(row) { return row.rest });
      callback(null, result);
    }
  });
};

Seraph.prototype._parseQueryResult = function(result) {
  var self = this;
  var namedResults = result.data.map(function(row) {
    return result.columns.reduce(function(rowObj, columnName, columnIndex) {
      var resultItem = row[columnIndex];
      function extractAttributes(item) {
        if (self._isNode(item)) {
          return self._createNodeObject(item);
        } else if (self._isRelationship(item)) {
          return self._createRelationshipObject(item);
        } else if (Array.isArray(item)) {
          return item.map(extractAttributes);
        } else if (item === Object(item)) {
          return _.mapObject(item, extractAttributes);
        } else {
          return item;
        }
      }

      rowObj[columnName] = extractAttributes(resultItem);

      return rowObj;
    }, {});
  });

  if (namedResults.length > 0) {
    var resultsAreObjects = typeof namedResults[0][result.columns[0]] == 'object';
    if (result.columns.length === 1 && resultsAreObjects) {
      namedResults = namedResults.map(function(namedResult) {
        return namedResult[result.columns[0]];
      });
    } else if (namedResults.length == 1 && !resultsAreObjects) {
      namedResults = namedResults[0];
    }
  }

  return namedResults;
}

/**
 * Perform a cypher query and map the columns and results together.
 */
Seraph.prototype.query = function(query, params, callback) {
  if (typeof params !== 'object') {
    if (typeof params === 'function') {
      callback = params;
    }
    params = {};
  }

  var self = this;
  this.queryRaw(query, params, function(err, result) {
    if (err) {
      return callback(err);
    }

    callback(null, self._parseQueryResult(result));
  });
};

var globalCounter = 0;
function wrapForBatchFormat(id) { return '{' + id + '}' };
function BatchSeraphId(id, refersTo, batch) {
  if (Array.isArray(refersTo)) {
    refersTo = refersTo.map(wrapForBatchFormat);
    refersTo.forEach(function(id, index) {
      this[index] = id;
    }.bind(this));
  } else {
    refersTo = wrapForBatchFormat(refersTo);
  }

  this.id = id;
  this.refersTo = refersTo;
  this.batch = batch;
}
Object.defineProperty(BatchSeraphId.prototype, 'valueOf', {
  enumerable: false, configurable: false, writable: false,
  value: function() { return this.id }
});
Object.defineProperty(BatchSeraphId.prototype, 'toString', {
  enumerable: false, configurable: false, writable: false,
  value: function() { return this.id }
});

function BatchSeraph(parentSeraph) {
  var self = this;
  var uniq = Date.now() + ++globalCounter;

  function isBatchId(id) {
    return id instanceof BatchSeraphId && id.batch == uniq;
  };

  function createId(id, refersTo) {
    return new BatchSeraphId(id, refersTo, uniq);
  };

  function transformBatchArgs(args) {
    return args.map(function(arg) {
      if (Array.isArray(arg)) return transformBatchArgs(arg);
      return isBatchId(arg) ? arg.refersTo : arg;
    });
  };

  function wrapFunctions(parent, target) {
    var derived = target || {};

    // parent could be undefined or null, so skip walking such
    parent && Object.keys(parent).forEach(function(key) {
      var valueType = typeof parent[key];

      if (valueType === 'function') {
        derived[key] = wrapFunction(parent[key]);

        if (Object.keys(parent[key]).length > 0) {
          derived[key] = wrapFunctions(parent[key], derived[key]);
        }
      } else if (valueType === 'object') {
        derived[key] = wrapFunctions(parent[key]);
      } else {
        derived[key] = parent[key];
      }
    });
    return derived;
  }

  function wrapFunction(fn) {
    fn = naan.rcurry(fn, function(err, result) {
      if (err && !self.error) self.error = err;
      self.results.push(result);
      var cb = self.callbacks.shift();
      if (cb) cb(err, result);
    });
    return function() {
      self.operationQueueStack.unshift([]);

      var args = [].slice.apply(arguments);

      if (args.length > 1 && typeof args[args.length - 1] == 'function') {
        self.callbacks.push(args.pop());
      } else {
        self.callbacks.push(null);
      }

      args = transformBatchArgs(args);

      // Context does not matter because all functions are bound upon seraph init
      fn.apply(undefined, args);

      var operationIds = _.pluck(self.operationQueueStack[0], 'id');
      self.operationQueueStack.shift();

      var operationId = operationIds.length
        ? operationIds[0] - self.operationOffset : undefined;

      if (operationIds.length > 1) {
        self.operationOffset += operationIds.length - 1;
        operationId = createId(operationId, operationIds);
      } else if (operationId != null) {
        operationId = createId(operationId, operationIds[0]);
      }

      return operationId;
    };
  }

  this.super = new Seraph(parentSeraph.options);
  this.__proto__ = wrapFunctions(this.super);
  this.isBatch = this.super.isBatch = true;
  this.batch = undefined; // disabled nesting.
  this.processors = [];
  this.operations = [];
  this.callbacks = [];
  this.results = [];
  this.operationOffset = 0;
  this.operationQueueStack = [];
  this.commitCallbacks = [];

  this.super.call = function(operation, processor) {
    operation.id = self.operations.length;
    if (!operation.body) delete operation.body;

    self.operations.push(operation);
    self.processors.push(processor.bind(self.super));
    self.operationQueueStack[0].push(operation);
  };

  this.commit = function(callback) {
    if (callback) self.commitCallbacks.push(callback);
    if (self.error) {
      return self.commitCallbacks.forEach(function(callback) {
        callback(self.error);
      });
    }
    var op = parentSeraph.operation('batch', 'POST', self.operations);
    parentSeraph.call(op, function(err, results) {
      if (err) {
        while (self.callbacks.length) {
          var cb = self.callbacks.shift();
          if (cb) cb(err);
        }
        return self.commitCallbacks.forEach(function(callback) {
          callback(err);
        });
      }

      results.forEach(function(result) {
        self.processors.shift()(null, result.body || {}, result.location);
      });

      self.commitCallbacks.forEach(function(callback) {
        callback(null, self.results);
      });
    });
  };
}

Seraph.prototype.isBatch = false;

Seraph.prototype.batch = function(operations, callback) {
  if (!arguments.length) return new BatchSeraph(this);

  var batchSeraph = new BatchSeraph(this);
  operations(batchSeraph);
  batchSeraph.commit(callback);
};

module.exports = function(options) {
  if (options && options.thunkify) {
    delete options.thunkify;
    return require('../co')(options);
  }
  return new Seraph(options);
};
<|endoftext|>


<commit_before>'use strict';
var Hapi = require('hapi');
var config = require('config');
var mongoose = require('hoist-model')._mongoose;
var router = require('./router');
var _ = require('lodash');

function Server() {

}

Server.prototype.createHapiServer = function () {
  var server = new Hapi.Server();
  server.connection({
    port: config.get('Hoist.http.port')
  });
  router.mapRoutes(server);
  return server;
};
Server.prototype.start = function () {
  mongoose.connect(config.get('Hoist.mongo.db'), _.bind(function () {
    this.hapi = this.createHapiServer();
    this.hapi.start(function () {
      console.log('server started');
    });
  },this));
};
Server.prototype.stop = function (cb) {
  /* istanbul ignore next */
  if (this.hapi) {
    console.log('closing server');
    this.hapi.stop(function () {
      delete this.hapi;
      mongoose.disconnect(function () {
        cb();
      });
    });
  } else {
    cb();
  }
};
module.exports = new Server();
<commit_msg>fix shutdown logic<commit_after>'use strict';
var Hapi = require('hapi');
var config = require('config');
var mongoose = require('hoist-model')._mongoose;
var router = require('./router');
var _ = require('lodash');
var logger = require('hoist-logger');

function Server() {

}

Server.prototype.createHapiServer = function () {
  var server = new Hapi.Server();
  server.connection({
    port: config.get('Hoist.http.port')
  });
  router.mapRoutes(server);
  return server;
};
Server.prototype.start = function () {
  mongoose.connect(config.get('Hoist.mongo.db'), _.bind(function () {
    this.hapi = this.createHapiServer();
    this.hapi.start(function () {
      logger.info('server started');
    });
  }, this));
};
Server.prototype.stop = function (cb) {
  /* istanbul ignore next */
  if (this.hapi) {
    logger.info('server shutting down');
    this.hapi.stop(function () {
      delete this.hapi;
      mongoose.disconnect(function () {
        logger.info('server shutdown');
        cb();
      });
    });
  } else {
    cb();
  }
};
module.exports = new Server();
<|endoftext|>


<commit_before>'use strict'

const _ = require('lodash')
const path = require('path')

module.exports = {

  registerPlugins (config, server, app) {
    app.log.debug('trailpack-hapi: registering', config.plugins.length, 'plugins')

    return server.register(config.plugins)
      .then(() => {
        if (_.isFunction(config.onPluginsLoaded)) {
          config.onPluginsLoaded.call(app)
        }
      })
      .catch(err => {
        app.log.error('Hapi Error:', err)
        throw err
      })
  },

  registerViews (config, server, app) {
    if (!config.views.engines.html && !config.views.engines.pug) { //for pug need not html key
      app.log.debug('config.views: No view engine is set. Not loading.')
      return
    }

    app.log.debug('trailpack-hapi: registering views')
    server.views(config.views)
  },

  registerRoutes (config, server, app) {
    server.route(app.routes)

    if (app.config.main.paths.www) {
      if(Array.isArray(app.config.main.paths.www)){
        app.config.main.paths.www.forEach(item =>{
          let staticDir = path.relative(app.config.main.paths.root, item.path)
          server.route({
            method: 'GET',
            path: item.humanUrl ? item.humanUrl.concat('/{filename*}') : '/'.concat(staticDir.replace(/\\/g, '/'), '/{filename*}'),
            handler: {
              file: function(request) {
                return path.join(staticDir, request.params.filename)
              }
            }
          })
        })
      }else{
        const staticDir = path.relative(app.config.main.paths.root, app.config.main.paths.www)
        server.route({
          method: 'GET',
          path: '/'.concat(staticDir.replace(/\\/g, '/'), '/{filename*}'),
          handler: {
            file: function(request) {
              return path.join(staticDir, request.params.filename)
            }
          }
        })
      }
    }
    else {
      app.log.debug('config.paths.www: No www directory is set, static files will not be loaded')
    }
  },

  registerExtensions (config, server, app) {
    config.extensions.forEach(ext => {
      ext.method = ext.method.bind({ app: app })
      server.ext(ext)
    })
  }
}
<commit_msg>forEach -> map<commit_after>'use strict'

const _ = require('lodash')
const path = require('path')

module.exports = {

  registerPlugins (config, server, app) {
    app.log.debug('trailpack-hapi: registering', config.plugins.length, 'plugins')

    return server.register(config.plugins)
      .then(() => {
        if (_.isFunction(config.onPluginsLoaded)) {
          config.onPluginsLoaded.call(app)
        }
      })
      .catch(err => {
        app.log.error('Hapi Error:', err)
        throw err
      })
  },

  registerViews (config, server, app) {
    if (!config.views.engines.html && !config.views.engines.pug) { //for pug need not html key
      app.log.debug('config.views: No view engine is set. Not loading.')
      return
    }

    app.log.debug('trailpack-hapi: registering views')
    server.views(config.views)
  },

  registerRoutes (config, server, app) {
    server.route(app.routes)

    if (app.config.main.paths.www) {
      if(Array.isArray(app.config.main.paths.www)){
        app.config.main.paths.www.map(item =>{
          let staticDir = path.relative(app.config.main.paths.root, item.path)
          server.route({
            method: 'GET',
            path: item.humanUrl ? item.humanUrl.concat('/{filename*}') : '/'.concat(staticDir.replace(/\\/g, '/'), '/{filename*}'),
            handler: {
              file: function(request) {
                return path.join(staticDir, request.params.filename)
              }
            }
          })
        })
      }else{
        const staticDir = path.relative(app.config.main.paths.root, app.config.main.paths.www)
        server.route({
          method: 'GET',
          path: '/'.concat(staticDir.replace(/\\/g, '/'), '/{filename*}'),
          handler: {
            file: function(request) {
              return path.join(staticDir, request.params.filename)
            }
          }
        })
      }
    }
    else {
      app.log.debug('config.paths.www: No www directory is set, static files will not be loaded')
    }
  },

  registerExtensions (config, server, app) {
    config.extensions.forEach(ext => {
      ext.method = ext.method.bind({ app: app })
      server.ext(ext)
    })
  }
}
<|endoftext|>