diff --git a/KEMMessaging/index.js b/KEMMessaging/index.js
index 8019baae3c8eacabf9e51437e9c9e9c1e959c471..ec9bb6c8cbdbf0a88228a6806fc52f0d4b3c5bfa 100644
--- a/KEMMessaging/index.js
+++ b/KEMMessaging/index.js
@@ -4,6 +4,12 @@ var express = require('express');
 var bodyParser  = require('body-parser');
 var app = express();
 var fs = require("fs");
+var admin = require("firebase-admin");
+
+admin.initializeApp({
+  credential: admin.credential.cert("serviceAccountKey.json"),
+  databaseURL: "https://kemmessaging-150309.firebaseio.com"
+});
 
 var config = {
     apiKey: "AIzaSyAAgIT5hnKHOYgojI_qiqzG3Vr0HjUqT0k",
@@ -58,13 +64,49 @@ app.post('/onlineUser', function (req, res) {
 app.post('/addMessage', function (req, res) {
    // First read existing users.
    var chat = req.body.message;
+   var idToken = req.body.token;
+   var sendemail = req.body.sender;
+   var rcvemail = req.body.rcv;
    console.log( chat );
+   console.log( idToken );
+   console.log( sendemail );
+   console.log( rcvemail );
+   admin.auth().verifyIdToken(idToken)
+  .then(function(decodedToken) {
+    var uid = decodedToken.uid;
+    console.log( uid );
+
+    admin.auth().getUser(uid)
+    .then(function(userRecord) {
+      console.log("Successfully fetched user data:", userRecord.toJSON());
+      if (userRecord.email == sendemail){
+        admin.auth().getUserByEmail(rcvemail)
+        .then(function(userRecord) {
+          // See the tables above for the contents of userRecord
+          console.log("Successfully fetched user data:", userRecord.toJSON());
+        })
+        .catch(function(error) {
+          console.log("Error fetching user data:", error);
+        });
+      }
+    })
+    .catch(function(error) {
+      console.log("Error fetching user data:", error);
+    });    
+  }).catch(function(error) {
+    // Handle error
+  });
+
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "Content-Type");
    res.header("Access-Control-Allow-Methods", "GET, POST");
    res.end("addMessage");
 })
 
+function verifyUser(idToken, user){
+
+}
+
 function onlineUser() {
   var listRef = firebase.database().ref('onlineUser/');
   var userRef = listRef.push();
diff --git a/KEMMessaging/node_modules/firebase-admin/README.md b/KEMMessaging/node_modules/firebase-admin/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..2a275ec08fe09fddfa75ae500637a7fa95ba546e
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/README.md
@@ -0,0 +1,71 @@
+# Firebase Admin Node.js SDK
+
+
+## Table of Contents
+
+ * [Overview](#overview)
+ * [Installation](#installation)
+ * [Documentation](#documentation)
+ * [Release Notes](#release-notes)
+ * [Acknowledgments](#acknowledgments)
+ * [License](#license)
+
+
+## Overview
+
+[Firebase](https://firebase.google.com) provides the tools and infrastructure
+you need to develop your app, grow your user base, and earn money. The Firebase
+Admin Node.js SDK provides admin (second-party) access to several Firebase
+services.
+
+For more information, visit the
+[Firebase Admin SDK setup guide](https://firebase.google.com/docs/admin/setup/).
+
+
+## Installation
+
+The Firebase Admin Node.js SDK is available on npm as `firebase-admin`:
+
+```bash
+$ npm install --save firebase-admin
+```
+
+To use the module in your application, `require` it from any JavaScript file:
+
+```js
+var admin = require("firebase-admin");
+```
+
+If you are using ES2015, you can `import` the module instead:
+
+```js
+import * as admin from "firebase-admin";
+```
+
+
+## Documentation
+
+* [Setup Guide](https://firebase.google.com/docs/admin/setup/)
+* [Database Guide](https://firebase.google.com/docs/database/admin/start/)
+* [Authentication Guide](https://firebase.google.com/docs/auth/admin/)
+* [API Reference](https://firebase.google.com/docs/reference/admin/node/)
+
+
+## Release Notes
+
+Release Notes for the Firebase Admin Node.js SDK are available
+[here](https://firebase.google.com/support/release-notes/admin/node/).
+
+
+## Acknowledgments
+
+Thanks to the team at [Casetext](https://casetext.com/) for transferring
+ownership of the `firebase-admin` npm module over to the Firebase team
+and for their longtime use and support of the Firebase platform.
+
+
+## License
+
+The Firebase Admin Node.js SDK is covered by the
+[Terms of Service for Firebase Services](https://firebase.google.com/terms/).
+
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/auth/auth-api-request.d.ts b/KEMMessaging/node_modules/firebase-admin/lib/auth/auth-api-request.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5eb2e8962321bc57284080a781429c07ce62c851
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/auth/auth-api-request.d.ts
@@ -0,0 +1,87 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+/// <reference types="chai" />
+import { Credential } from './credential';
+import { ApiSettings } from '../utils/api-request';
+/** Instantiates the getAccountInfo endpoint settings. */
+export declare const FIREBASE_AUTH_GET_ACCOUNT_INFO: ApiSettings;
+/** Instantiates the deleteAccount endpoint settings. */
+export declare const FIREBASE_AUTH_DELETE_ACCOUNT: ApiSettings;
+/** Instantiates the setAccountInfo endpoint settings for updating existing accounts. */
+export declare const FIREBASE_AUTH_SET_ACCOUNT_INFO: ApiSettings;
+/**
+ * Instantiates the uploadAccount endpoint settings for creating a new user with uid
+ * specified.
+ */
+export declare const FIREBASE_AUTH_UPLOAD_ACCOUNT: ApiSettings;
+/**
+ * Instantiates the signupNewUser endpoint settings for creating a new user without
+ * uid being specified. The backend will create a new one and return it.
+ */
+export declare const FIREBASE_AUTH_SIGN_UP_NEW_USER: ApiSettings;
+/**
+ * Class that provides mechanism to send requests to the Firebase Auth backend endpoints.
+ *
+ * @param {Credential} credential The service account credential used to sign HTTP requests.
+ * @constructor
+ */
+export declare class FirebaseAuthRequestHandler {
+    private host;
+    private port;
+    private path;
+    private headers;
+    private timeout;
+    private signedApiRequestHandler;
+    /**
+     * @param {Object} response The response to check for errors.
+     * @return {string} The error code if present, an empty string otherwise.
+     */
+    private static getErrorCode(response);
+    constructor(credential: Credential);
+    /**
+     * Looks a user by uid.
+     *
+     * @param {string} uid The uid of the user to lookup.
+     * @return {Promise<Object>} A promise that resolves with the user information.
+     */
+    getAccountInfoByUid(uid: string): Promise<Object>;
+    /**
+     * Looks a user by email.
+     *
+     * @param {string} email The email of the user to lookup.
+     * @return {Promise<Object>} A promise that resolves with the user information.
+     */
+    getAccountInfoByEmail(email: string): Promise<Object>;
+    /**
+     * Deletes an account identified by a uid.
+     *
+     * @param {string} uid The uid of the user to delete.
+     * @return {Promise<Object>} A promise that resolves when the user is deleted.
+     */
+    deleteAccount(uid: string): Promise<Object>;
+    /**
+     * Edits an existing user.
+     *
+     * @param {string} uid The user to edit.
+     * @param {Object} properties The properties to set on the user.
+     * @return {Promise<string>} A promise that resolves when the operation completes
+     *     with the user id that was edited.
+     */
+    updateExistingAccount(uid: string, properties: Object): Promise<string>;
+    /**
+     * Create a new user with the properties supplied.
+     *
+     * @param {Object} properties The properties to set on the user.
+     * @return {Promise<string>} A promise that resolves when the operation completes
+     *     with the user id that was created.
+     */
+    createNewAccount(properties: Object): Promise<string>;
+    /**
+     * Invokes the request handler based on the API settings object passed.
+     *
+     * @param {ApiSettings} apiSettings The API endpoint settings to apply to request and response.
+     * @param {Object} requestData The request data.
+     * @return {Promise<Object>} A promise that resolves with the response.
+     */
+    private invokeRequestHandler(apiSettings, requestData);
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/auth/auth-api-request.js b/KEMMessaging/node_modules/firebase-admin/lib/auth/auth-api-request.js
new file mode 100644
index 0000000000000000000000000000000000000000..ac8b4b0af3fc8c8f55334c084dd7b57a1cd5e876
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/auth/auth-api-request.js
@@ -0,0 +1,398 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+"use strict";
+var validator = require('../utils/validator');
+var deep_copy_1 = require('../utils/deep-copy');
+var error_1 = require('../utils/error');
+var api_request_1 = require('../utils/api-request');
+/** Firebase Auth backend host. */
+var FIREBASE_AUTH_HOST = 'www.googleapis.com';
+/** Firebase Auth backend port number. */
+var FIREBASE_AUTH_PORT = 443;
+/** Firebase Auth backend path. */
+var FIREBASE_AUTH_PATH = '/identitytoolkit/v3/relyingparty/';
+/** Firebase Auth request header. */
+var FIREBASE_AUTH_HEADER = {
+    'Content-Type': 'application/json',
+};
+/** Firebase Auth request timeout duration in seconds. */
+var FIREBASE_AUTH_TIMEOUT = 10000;
+/**
+ * Validates a create/edit request object. All unsupported parameters
+ * are removed from the original request. If an invalid field is passed
+ * an error is thrown.
+ *
+ * @param {any} request The create/edit request object.
+ */
+function validateCreateEditRequest(request) {
+    // Hash set of whitelisted parameters.
+    var validKeys = {
+        displayName: true,
+        localId: true,
+        email: true,
+        password: true,
+        rawPassword: true,
+        emailVerified: true,
+        photoUrl: true,
+        disabled: true,
+        disableUser: true,
+        deleteAttribute: true,
+        sanityCheck: true,
+    };
+    // Remove invalid keys from original request.
+    for (var key in request) {
+        if (!(key in validKeys)) {
+            delete request[key];
+        }
+    }
+    // For any invalid parameter, use the external key name in the error description.
+    // displayName should be a string.
+    if (typeof request.displayName !== 'undefined' &&
+        typeof request.displayName !== 'string') {
+        throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_DISPLAY_NAME);
+    }
+    if (typeof request.localId !== 'undefined' && !validator.isUid(request.localId)) {
+        // This is called localId on the backend but the developer specifies this as
+        // uid externally. So the error message should use the client facing name.
+        throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_UID);
+    }
+    // email should be a string and a valid email.
+    if (typeof request.email !== 'undefined' && !validator.isEmail(request.email)) {
+        throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_EMAIL);
+    }
+    // password should be a string and a minimum of 6 chars.
+    if (typeof request.password !== 'undefined' &&
+        !validator.isPassword(request.password)) {
+        throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_PASSWORD);
+    }
+    // rawPassword should be a string and a minimum of 6 chars.
+    if (typeof request.rawPassword !== 'undefined' &&
+        !validator.isPassword(request.rawPassword)) {
+        // This is called rawPassword on the backend but the developer specifies this as
+        // password externally. So the error message should use the client facing name.
+        throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_PASSWORD);
+    }
+    // emailVerified should be a boolean.
+    if (typeof request.emailVerified !== 'undefined' &&
+        typeof request.emailVerified !== 'boolean') {
+        throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_EMAIL_VERIFIED);
+    }
+    // photoUrl should be a URL.
+    if (typeof request.photoUrl !== 'undefined' &&
+        !validator.isURL(request.photoUrl)) {
+        // This is called photoUrl on the backend but the developer specifies this as
+        // photoURL externally. So the error message should use the client facing name.
+        throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_PHOTO_URL);
+    }
+    // disabled should be a boolean.
+    if (typeof request.disabled !== 'undefined' &&
+        typeof request.disabled !== 'boolean') {
+        throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_DISABLED_FIELD);
+    }
+    // disableUser should be a boolean.
+    if (typeof request.disableUser !== 'undefined' &&
+        typeof request.disableUser !== 'boolean') {
+        // This is called disableUser on the backend but the developer specifies this as
+        // disabled externally. So the error message should use the client facing name.
+        throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_DISABLED_FIELD);
+    }
+}
+;
+/** Instantiates the getAccountInfo endpoint settings. */
+exports.FIREBASE_AUTH_GET_ACCOUNT_INFO = new api_request_1.ApiSettings('getAccountInfo', 'POST')
+    .setRequestValidator(function (request) {
+    if (!request.localId && !request.email) {
+        throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INTERNAL_ERROR, 'INTERNAL ASSERT FAILED: Server request is missing user identifier');
+    }
+})
+    .setResponseValidator(function (response) {
+    if (!response.users) {
+        throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.USER_NOT_FOUND);
+    }
+});
+/** Instantiates the deleteAccount endpoint settings. */
+exports.FIREBASE_AUTH_DELETE_ACCOUNT = new api_request_1.ApiSettings('deleteAccount', 'POST')
+    .setRequestValidator(function (request) {
+    if (!request.localId) {
+        throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INTERNAL_ERROR, 'INTERNAL ASSERT FAILED: Server request is missing user identifier');
+    }
+});
+/** Instantiates the setAccountInfo endpoint settings for updating existing accounts. */
+exports.FIREBASE_AUTH_SET_ACCOUNT_INFO = new api_request_1.ApiSettings('setAccountInfo', 'POST')
+    .setRequestValidator(function (request) {
+    // localId is a required parameter.
+    if (typeof request.localId === 'undefined') {
+        throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INTERNAL_ERROR, 'INTERNAL ASSERT FAILED: Server request is missing user identifier');
+    }
+    validateCreateEditRequest(request);
+})
+    .setResponseValidator(function (response) {
+    // If the localId is not returned, then the request failed.
+    if (!response.localId) {
+        throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.USER_NOT_FOUND);
+    }
+});
+/**
+ * Instantiates the uploadAccount endpoint settings for creating a new user with uid
+ * specified.
+ */
+exports.FIREBASE_AUTH_UPLOAD_ACCOUNT = new api_request_1.ApiSettings('uploadAccount', 'POST')
+    .setRequestValidator(function (request) {
+    var validKeys = {
+        users: true,
+        // Required to throw an error when a user already exists with the provided uid.
+        allowOverwrite: true,
+        // Required to throw an error if the email is already in use by another account.
+        sanityCheck: true,
+    };
+    // Remove unsupported properties.
+    for (var key in request) {
+        if (!(key in validKeys)) {
+            delete request[key];
+        }
+    }
+    // Required uploadAccount parameter.
+    if (typeof request.users === 'undefined' ||
+        request.users == null ||
+        !request.users.length) {
+        throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INTERNAL_ERROR, 'INTERNAL ASSERT FAILED: Invalid uploadAccount request. No users provider.');
+    }
+    // Validate each user within users.
+    for (var _i = 0, _a = request.users; _i < _a.length; _i++) {
+        var user = _a[_i];
+        // localId is a required parameter.
+        if (typeof user.localId === 'undefined') {
+            throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INTERNAL_ERROR, 'INTERNAL ASSERT FAILED: Server request is missing user identifier');
+        }
+        // Validate user.
+        validateCreateEditRequest(user);
+    }
+})
+    .setResponseValidator(function (response) {
+    // Return the first error. UploadAccount is used to upload multiple accounts.
+    // If an error occurs in any account to be upload, an array of errors is
+    // returned.
+    if (typeof response.error !== 'undefined' &&
+        response.error.length &&
+        typeof response.error[0].message === 'string') {
+        // Get error description.
+        if (response.error[0].message.indexOf('can not overwrite') !== -1) {
+            // Duplicate user error
+            throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.UID_ALREADY_EXISTS, response.error[0].message);
+        }
+        throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INTERNAL_ERROR, 'INTERNAL ASSERT FAILED: ' + response.error[0].message);
+    }
+});
+/**
+ * Instantiates the signupNewUser endpoint settings for creating a new user without
+ * uid being specified. The backend will create a new one and return it.
+ */
+exports.FIREBASE_AUTH_SIGN_UP_NEW_USER = new api_request_1.ApiSettings('signupNewUser', 'POST')
+    .setRequestValidator(function (request) {
+    // localId should not be specified.
+    // This should not occur as when the uid is provided, uploadAccount is used instead.
+    if (typeof request.localId !== 'undefined') {
+        throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INTERNAL_ERROR, 'INTERNAL ASSERT FAILED: User identifier must not be specified');
+    }
+    validateCreateEditRequest(request);
+})
+    .setResponseValidator(function (response) {
+    // If the localId is not returned, then the request failed.
+    if (!response.localId) {
+        throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INTERNAL_ERROR, 'INTERNAL ASSERT FAILED: Unable to create new user');
+    }
+});
+/**
+ * Class that provides mechanism to send requests to the Firebase Auth backend endpoints.
+ *
+ * @param {Credential} credential The service account credential used to sign HTTP requests.
+ * @constructor
+ */
+var FirebaseAuthRequestHandler = (function () {
+    function FirebaseAuthRequestHandler(credential) {
+        this.host = FIREBASE_AUTH_HOST;
+        this.port = FIREBASE_AUTH_PORT;
+        this.path = FIREBASE_AUTH_PATH;
+        this.headers = FIREBASE_AUTH_HEADER;
+        this.timeout = FIREBASE_AUTH_TIMEOUT;
+        this.signedApiRequestHandler = new api_request_1.SignedApiRequestHandler(credential);
+    }
+    /**
+     * @param {Object} response The response to check for errors.
+     * @return {string} The error code if present, an empty string otherwise.
+     */
+    FirebaseAuthRequestHandler.getErrorCode = function (response) {
+        return (response.error && response.error.message) || null;
+    };
+    /**
+     * Looks a user by uid.
+     *
+     * @param {string} uid The uid of the user to lookup.
+     * @return {Promise<Object>} A promise that resolves with the user information.
+     */
+    FirebaseAuthRequestHandler.prototype.getAccountInfoByUid = function (uid) {
+        var request = {
+            localId: [uid],
+        };
+        return this.invokeRequestHandler(exports.FIREBASE_AUTH_GET_ACCOUNT_INFO, request);
+    };
+    /**
+     * Looks a user by email.
+     *
+     * @param {string} email The email of the user to lookup.
+     * @return {Promise<Object>} A promise that resolves with the user information.
+     */
+    FirebaseAuthRequestHandler.prototype.getAccountInfoByEmail = function (email) {
+        var request = {
+            email: [email],
+        };
+        return this.invokeRequestHandler(exports.FIREBASE_AUTH_GET_ACCOUNT_INFO, request);
+    };
+    /**
+     * Deletes an account identified by a uid.
+     *
+     * @param {string} uid The uid of the user to delete.
+     * @return {Promise<Object>} A promise that resolves when the user is deleted.
+     */
+    FirebaseAuthRequestHandler.prototype.deleteAccount = function (uid) {
+        var request = {
+            localId: uid,
+        };
+        return this.invokeRequestHandler(exports.FIREBASE_AUTH_DELETE_ACCOUNT, request);
+    };
+    /**
+     * Edits an existing user.
+     *
+     * @param {string} uid The user to edit.
+     * @param {Object} properties The properties to set on the user.
+     * @return {Promise<string>} A promise that resolves when the operation completes
+     *     with the user id that was edited.
+     */
+    FirebaseAuthRequestHandler.prototype.updateExistingAccount = function (uid, properties) {
+        // Build the setAccountInfo request.
+        var request = deep_copy_1.deepCopy(properties);
+        request.localId = uid;
+        // For deleting displayName or photoURL, these values must be passed as null.
+        // They will be removed from the backend request and an additional parameter
+        // deleteAttribute: ['PHOTO_URL', 'DISPLAY_NAME']
+        // with an array of the parameter names to delete will be passed.
+        // Parameters that are deletable and their deleteAttribute names.
+        // Use client facing names, photoURL instead of photoUrl.
+        var deletableParams = {
+            displayName: 'DISPLAY_NAME',
+            photoURL: 'PHOTO_URL',
+        };
+        // Properties to delete if available.
+        request.deleteAttribute = [];
+        for (var key in deletableParams) {
+            if (request[key] === null) {
+                // Add property identifier to list of attributes to delete.
+                request.deleteAttribute.push(deletableParams[key]);
+                // Remove property from request.
+                delete request[key];
+            }
+        }
+        if (request.deleteAttribute.length === 0) {
+            delete request.deleteAttribute;
+        }
+        // Rewrite photoURL to photoUrl.
+        if (typeof request.photoURL !== 'undefined') {
+            request.photoUrl = request.photoURL;
+            delete request.photoURL;
+        }
+        // Rewrite disabled to disableUser.
+        if (typeof request.disabled !== 'undefined') {
+            request.disableUser = request.disabled;
+            delete request.disabled;
+        }
+        return this.invokeRequestHandler(exports.FIREBASE_AUTH_SET_ACCOUNT_INFO, request)
+            .then(function (response) {
+            return response.localId;
+        });
+    };
+    /**
+     * Create a new user with the properties supplied.
+     *
+     * @param {Object} properties The properties to set on the user.
+     * @return {Promise<string>} A promise that resolves when the operation completes
+     *     with the user id that was created.
+     */
+    FirebaseAuthRequestHandler.prototype.createNewAccount = function (properties) {
+        // Build the signupNewUser/uploadAccount request.
+        var request = deep_copy_1.deepCopy(properties);
+        var finalRequest;
+        var apiSettings;
+        // Rewrite photoURL to photoUrl.
+        if (typeof request.photoURL !== 'undefined') {
+            request.photoUrl = request.photoURL;
+            delete request.photoURL;
+        }
+        if (typeof request.uid !== 'undefined') {
+            request.localId = request.uid;
+            // If uid specified, use uploadAccount endpoint.
+            apiSettings = exports.FIREBASE_AUTH_UPLOAD_ACCOUNT;
+            // This endpoint takes a hashed password.
+            // To pass a plain text password, pass it via rawPassword field.
+            if (typeof request.password !== 'undefined') {
+                request.rawPassword = request.password;
+                delete request.password;
+            }
+            // Construct uploadAccount request.
+            finalRequest = {
+                users: [request],
+                // Do not overwrite existing users.
+                allowOverwrite: false,
+                // Do not allow duplicate emails.
+                // This will force the backend to throw an error when an email is
+                // already in use by another existing account.
+                sanityCheck: true,
+            };
+        }
+        else {
+            // If uid not specified, use signupNewUser endpoint.
+            apiSettings = exports.FIREBASE_AUTH_SIGN_UP_NEW_USER;
+            finalRequest = request;
+        }
+        return this.invokeRequestHandler(apiSettings, finalRequest)
+            .then(function (response) {
+            // Return the user id. It is returned in the setAccountInfo and signupNewUser
+            // endpoints but not the uploadAccount endpoint. In that case return the same
+            // one in request.
+            return (response.localId || request.localId);
+        });
+    };
+    /**
+     * Invokes the request handler based on the API settings object passed.
+     *
+     * @param {ApiSettings} apiSettings The API endpoint settings to apply to request and response.
+     * @param {Object} requestData The request data.
+     * @return {Promise<Object>} A promise that resolves with the response.
+     */
+    FirebaseAuthRequestHandler.prototype.invokeRequestHandler = function (apiSettings, requestData) {
+        var _this = this;
+        var path = this.path + apiSettings.getEndpoint();
+        var httpMethod = apiSettings.getHttpMethod();
+        return Promise.resolve()
+            .then(function () {
+            // Validate request.
+            var requestValidator = apiSettings.getRequestValidator();
+            requestValidator(requestData);
+            // Process request.
+            return _this.signedApiRequestHandler.sendRequest(_this.host, _this.port, path, httpMethod, requestData, _this.headers, _this.timeout);
+        })
+            .then(function (response) {
+            // Check for backend errors in the response.
+            var errorCode = FirebaseAuthRequestHandler.getErrorCode(response);
+            if (errorCode) {
+                throw error_1.FirebaseAuthError.fromServerError(errorCode);
+            }
+            // Validate response.
+            var responseValidator = apiSettings.getResponseValidator();
+            responseValidator(response);
+            // Return entire response.
+            return response;
+        });
+    };
+    return FirebaseAuthRequestHandler;
+}());
+exports.FirebaseAuthRequestHandler = FirebaseAuthRequestHandler;
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/auth/auth.d.ts b/KEMMessaging/node_modules/firebase-admin/lib/auth/auth.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..49c6a0d29bdcee359103aefb07c5dfc82974f49e
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/auth/auth.d.ts
@@ -0,0 +1,142 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+/// <reference types="chai" />
+import { Credential } from './credential';
+import { FirebaseApp } from '../firebase-app';
+import { FirebaseServiceInterface, FirebaseServiceInternalsInterface } from '../firebase-service';
+import { UserRecord } from './user-record';
+/**
+ * Auth service bound to the provided app.
+ *
+ * @param {Object} app The app for this auth service
+ * @constructor
+ */
+declare class Auth implements FirebaseServiceInterface {
+    private app_;
+    private tokenGenerator_;
+    private authTokenManager_;
+    private authRequestHandler;
+    private userWriteMap;
+    constructor(app: FirebaseApp);
+    readonly app: FirebaseApp;
+    readonly INTERNAL: AuthTokenManager;
+    /**
+     * Creates a new custom token that can be sent back to a client to use with
+     * signInWithCustomToken().
+     *
+     * @param {string} uid The uid to use as the JWT subject.
+     * @param {Object=} developerClaims Optional additional claims to include in the JWT payload.
+     *
+     * @return {Promise<string>} A JWT for the provided payload.
+     */
+    createCustomToken(uid: string, developerClaims?: Object): Promise<string>;
+    /**
+     * Verifies a JWT auth token. Returns a Promise with the tokens claims. Rejects
+     * the promise if the token could not be verified.
+     *
+     * @param {string} idToken The JWT to verify.
+     * @return {Object} A Promise that will be fulfilled after a successful verification.
+     */
+    verifyIdToken(idToken: string): Promise<Object>;
+    /**
+     * Looks up the user identified by the provided user id and returns a promise that is
+     * fulfilled with a user record for the given user if that user is found.
+     *
+     * @param {string} uid The uid of the user to look up.
+     * @return {Promise<UserRecord>} A promise that resolves with the corresponding user record.
+     */
+    getUser(uid: string): Promise<UserRecord>;
+    /**
+     * Looks up the user identified by the provided email and returns a promise that is
+     * fulfilled with a user record for the given user if that user is found.
+     *
+     * @param {string} email The email of the user to look up.
+     * @return {Promise<UserRecord>} A promise that resolves with the corresponding user record.
+     */
+    getUserByEmail(email: string): Promise<UserRecord>;
+    /**
+     * Creates a new user with the properties provided.
+     *
+     * @param {Object} properties The properties to set on the new user record to be created.
+     * @return {Promise<UserRecord>} A promise that resolves with the newly created user record.
+     */
+    createUser(properties: Object): Promise<UserRecord>;
+    /**
+     * Deletes the user identified by the provided user id and returns a promise that is
+     * fulfilled when the user is found and successfully deleted.
+     *
+     * @param {string} uid The uid of the user to delete.
+     * @return {Promise<void>} A promise that resolves when the user is successfully deleted.
+     */
+    deleteUser(uid: string): Promise<void>;
+    /**
+     * Updates an existing user with the properties provided.
+     *
+     * @param {string} uid The uid identifier of the user to update.
+     * @param {Object} properties The properties to update on the existing user.
+     * @return {Promise<UserRecord>} A promise that resolves with the modified user record.
+     */
+    updateUser(uid: string, properties: Object): Promise<UserRecord>;
+    /**
+     * Deletes the user identified by the provided user id and returns a promise that is
+     * fulfilled when the user is found and successfully deleted.
+     * This will run without being serialized in the user write queue.
+     *
+     * @param {string} uid The uid of the user to delete.
+     * @return {Promise<void>} A promise that resolves when the user is successfully deleted.
+     */
+    private deleteUserUnserialized(uid);
+    /**
+     * Updates an existing user with the properties provided.
+     * This will run without being serialized in the user write queue.
+     *
+     * @param {string} uid The uid identifier of the user to update.
+     * @param {Object} properties The properties to update on the existing user.
+     * @return {Promise<UserRecord>} A promise that resolves with the modified user record.
+     */
+    private updateUserUnserialized(uid, properties);
+    /**
+     * @param {string} uid The uid identifier of the request.
+     * @param {() => Promise<any>} boundFn Promise returning function to queue with this
+     *     context and arguments already bound.
+     * @return {Promise<any>} The resulting promise which resolves when all pending previous
+     *     promises on the same user are resolved.
+     */
+    private serializeApiRequest(uid, boundFn);
+}
+export declare class FirebaseAccessToken {
+    accessToken: string;
+    expirationTime: number;
+}
+export declare class AuthTokenManager implements FirebaseServiceInternalsInterface {
+    private credential;
+    private cachedToken;
+    private tokenListeners;
+    constructor(credential: Credential);
+    /**
+     * Deletes the service and its associated resources.
+     *
+     * @return {Promise<()>} An empty Promise that will be fulfilled when the service is deleted.
+     */
+    delete(): Promise<void>;
+    /**
+     * Gets an auth token for the associated app.
+     *
+     * @param {boolean} forceRefresh Whether or not to force a token refresh.
+     * @return {Promise<Object>} A Promise that will be fulfilled with the current or new token.
+     */
+    getToken(forceRefresh?: boolean): Promise<FirebaseAccessToken>;
+    /**
+     * Adds a listener that is called each time a token changes.
+     *
+     * @param {function(string)} listener The listener that will be called with each new token.
+     */
+    addAuthTokenListener(listener: (token: string) => void): void;
+    /**
+     * Removes a token listener.
+     *
+     * @param {function(string)} listener The listener to remove.
+     */
+    removeAuthTokenListener(listener: (token: string) => void): void;
+}
+export { Auth };
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/auth/auth.js b/KEMMessaging/node_modules/firebase-admin/lib/auth/auth.js
new file mode 100644
index 0000000000000000000000000000000000000000..5c1acb1db1960970a99610be8f91a15a1eb168f1
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/auth/auth.js
@@ -0,0 +1,358 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+"use strict";
+var token_generator_1 = require('./token-generator');
+var credential_1 = require('./credential');
+var auth_api_request_1 = require('./auth-api-request');
+var user_record_1 = require('./user-record');
+var error_1 = require('../utils/error');
+/**
+ * Gets a Credential from app options.
+ *
+ * @return {Credential}
+ */
+function getCredential(app) {
+    var opts = app.options;
+    if (opts.credential) {
+        return opts.credential;
+    }
+    // We must be careful because '' is falsy. An opt || env test would coalesce '' || undefined as undefined.
+    var certificateOrPath = typeof opts.serviceAccount === 'undefined' ?
+        process.env.GOOGLE_APPLICATION_CREDENTIALS :
+        opts.serviceAccount;
+    if (typeof certificateOrPath === 'string') {
+        return new credential_1.CertCredential(credential_1.Certificate.fromPath(certificateOrPath));
+    }
+    else if (typeof certificateOrPath === 'object') {
+        return new credential_1.CertCredential(new credential_1.Certificate(certificateOrPath));
+    }
+    else {
+        throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_SERVICE_ACCOUNT);
+    }
+}
+/**
+ * Auth service bound to the provided app.
+ *
+ * @param {Object} app The app for this auth service
+ * @constructor
+ */
+var Auth = (function () {
+    function Auth(app) {
+        if (typeof app !== 'object' || !('options' in app)) {
+            throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_ARGUMENT, 'First parameter to Auth constructor must be an instance of FirebaseApp');
+        }
+        this.app_ = app;
+        var credential = getCredential(app);
+        if (credential && typeof credential.getAccessToken !== 'function') {
+            throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CREDENTIAL, 'Called initializeApp() with an invalid credential parameter');
+        }
+        this.authTokenManager_ = new AuthTokenManager(credential);
+        // TODO (inlined): plumb this into a factory method for tokenGenerator_ once we
+        // can generate custom tokens from access tokens.
+        var serviceAccount;
+        if (typeof credential.getCertificate === 'function') {
+            serviceAccount = credential.getCertificate();
+        }
+        if (serviceAccount) {
+            this.tokenGenerator_ = new token_generator_1.FirebaseTokenGenerator(serviceAccount);
+        }
+        // Initialize auth request handler with the credential.
+        this.authRequestHandler = new auth_api_request_1.FirebaseAuthRequestHandler(credential);
+        // Initialize user record write map (uid to queue).
+        // Firebase auth backend does not lock transactions running on the same user record.
+        // Edits on the same user record could overwrite each other, depending on the last one
+        // to execute.
+        // Multiple create user requests with the same email could create multiple
+        // records where one will always be used depending on the backend lookup algorithm.
+        // This promise queue ensures user record writes are serialized.
+        // TODO(bojeil): Remove this logic (b/32584015) which is currently blocked by b/32556583
+        this.userWriteMap = {};
+    }
+    Object.defineProperty(Auth.prototype, "app", {
+        get: function () {
+            return this.app_;
+        },
+        enumerable: true,
+        configurable: true
+    });
+    Object.defineProperty(Auth.prototype, "INTERNAL", {
+        get: function () {
+            return this.authTokenManager_;
+        },
+        enumerable: true,
+        configurable: true
+    });
+    /**
+     * Creates a new custom token that can be sent back to a client to use with
+     * signInWithCustomToken().
+     *
+     * @param {string} uid The uid to use as the JWT subject.
+     * @param {Object=} developerClaims Optional additional claims to include in the JWT payload.
+     *
+     * @return {Promise<string>} A JWT for the provided payload.
+     */
+    Auth.prototype.createCustomToken = function (uid, developerClaims) {
+        if (typeof this.tokenGenerator_ === 'undefined') {
+            throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CREDENTIAL, 'Must initialize app with a cert credential to call auth().createCustomToken()');
+        }
+        return this.tokenGenerator_.createCustomToken(uid, developerClaims);
+    };
+    ;
+    /**
+     * Verifies a JWT auth token. Returns a Promise with the tokens claims. Rejects
+     * the promise if the token could not be verified.
+     *
+     * @param {string} idToken The JWT to verify.
+     * @return {Object} A Promise that will be fulfilled after a successful verification.
+     */
+    Auth.prototype.verifyIdToken = function (idToken) {
+        if (typeof this.tokenGenerator_ === 'undefined') {
+            throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CREDENTIAL, 'Must initialize app with a cert credential to call auth().verifyIdToken()');
+        }
+        return this.tokenGenerator_.verifyIdToken(idToken);
+    };
+    ;
+    /**
+     * Looks up the user identified by the provided user id and returns a promise that is
+     * fulfilled with a user record for the given user if that user is found.
+     *
+     * @param {string} uid The uid of the user to look up.
+     * @return {Promise<UserRecord>} A promise that resolves with the corresponding user record.
+     */
+    Auth.prototype.getUser = function (uid) {
+        return this.authRequestHandler.getAccountInfoByUid(uid)
+            .then(function (response) {
+            // Returns the user record populated with server response.
+            return new user_record_1.UserRecord(response.users[0]);
+        });
+    };
+    ;
+    /**
+     * Looks up the user identified by the provided email and returns a promise that is
+     * fulfilled with a user record for the given user if that user is found.
+     *
+     * @param {string} email The email of the user to look up.
+     * @return {Promise<UserRecord>} A promise that resolves with the corresponding user record.
+     */
+    Auth.prototype.getUserByEmail = function (email) {
+        return this.authRequestHandler.getAccountInfoByEmail(email)
+            .then(function (response) {
+            // Returns the user record populated with server response.
+            return new user_record_1.UserRecord(response.users[0]);
+        });
+    };
+    ;
+    /**
+     * Creates a new user with the properties provided.
+     *
+     * @param {Object} properties The properties to set on the new user record to be created.
+     * @return {Promise<UserRecord>} A promise that resolves with the newly created user record.
+     */
+    Auth.prototype.createUser = function (properties) {
+        var _this = this;
+        return this.authRequestHandler.createNewAccount(properties)
+            .then(function (uid) {
+            // Return the corresponding user record.
+            return _this.getUser(uid);
+        })
+            .catch(function (error) {
+            if (error.code === 'auth/user-not-found') {
+                // Something must have happened after creating the user and then retrieving it.
+                throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INTERNAL_ERROR, 'Unable to create the user record provided.');
+            }
+            throw error;
+        });
+    };
+    ;
+    /**
+     * Deletes the user identified by the provided user id and returns a promise that is
+     * fulfilled when the user is found and successfully deleted.
+     *
+     * @param {string} uid The uid of the user to delete.
+     * @return {Promise<void>} A promise that resolves when the user is successfully deleted.
+     */
+    Auth.prototype.deleteUser = function (uid) {
+        // Add to queue and wait for it to execute.
+        return this.serializeApiRequest(uid, this.deleteUserUnserialized.bind(this, uid));
+    };
+    ;
+    /**
+     * Updates an existing user with the properties provided.
+     *
+     * @param {string} uid The uid identifier of the user to update.
+     * @param {Object} properties The properties to update on the existing user.
+     * @return {Promise<UserRecord>} A promise that resolves with the modified user record.
+     */
+    Auth.prototype.updateUser = function (uid, properties) {
+        // Add to queue and wait for it to execute.
+        return this.serializeApiRequest(uid, this.updateUserUnserialized.bind(this, uid, properties));
+    };
+    ;
+    /**
+     * Deletes the user identified by the provided user id and returns a promise that is
+     * fulfilled when the user is found and successfully deleted.
+     * This will run without being serialized in the user write queue.
+     *
+     * @param {string} uid The uid of the user to delete.
+     * @return {Promise<void>} A promise that resolves when the user is successfully deleted.
+     */
+    Auth.prototype.deleteUserUnserialized = function (uid) {
+        return this.authRequestHandler.deleteAccount(uid)
+            .then(function (response) {
+            // Return nothing on success.
+        });
+    };
+    ;
+    /**
+     * Updates an existing user with the properties provided.
+     * This will run without being serialized in the user write queue.
+     *
+     * @param {string} uid The uid identifier of the user to update.
+     * @param {Object} properties The properties to update on the existing user.
+     * @return {Promise<UserRecord>} A promise that resolves with the modified user record.
+     */
+    Auth.prototype.updateUserUnserialized = function (uid, properties) {
+        var _this = this;
+        return this.authRequestHandler.updateExistingAccount(uid, properties)
+            .then(function (existingUid) {
+            // Return the corresponding user record.
+            return _this.getUser(existingUid);
+        });
+    };
+    ;
+    /**
+     * @param {string} uid The uid identifier of the request.
+     * @param {() => Promise<any>} boundFn Promise returning function to queue with this
+     *     context and arguments already bound.
+     * @return {Promise<any>} The resulting promise which resolves when all pending previous
+     *     promises on the same user are resolved.
+     */
+    Auth.prototype.serializeApiRequest = function (uid, boundFn) {
+        var _this = this;
+        // Check if there is a pending queue for the current user.
+        // If not initialize one.
+        if (typeof this.userWriteMap[uid] === 'undefined') {
+            this.userWriteMap[uid] = {
+                queue: Promise.resolve(),
+                pending: 0,
+            };
+        }
+        // Increment pending counter for current user.
+        this.userWriteMap[uid].pending++;
+        this.userWriteMap[uid].queue = this.userWriteMap[uid].queue
+            .then(function () {
+            return boundFn();
+        }, function (error) {
+            return boundFn();
+        })
+            .then(function (result) {
+            // Clean up any user specific queues that are no longer pending.
+            if (--_this.userWriteMap[uid].pending === 0) {
+                delete _this.userWriteMap[uid];
+            }
+            // Funnel result back.
+            return result;
+        }, function (error) {
+            // Clean up any user specific queues that are no longer pending.
+            if (--_this.userWriteMap[uid].pending === 0) {
+                delete _this.userWriteMap[uid];
+            }
+            // Rethrow error.
+            throw error;
+        });
+        return this.userWriteMap[uid].queue;
+    };
+    ;
+    return Auth;
+}());
+exports.Auth = Auth;
+;
+var FirebaseAccessToken = (function () {
+    function FirebaseAccessToken() {
+    }
+    return FirebaseAccessToken;
+}());
+exports.FirebaseAccessToken = FirebaseAccessToken;
+var AuthTokenManager = (function () {
+    function AuthTokenManager(credential) {
+        this.credential = credential;
+        this.tokenListeners = [];
+    }
+    /**
+     * Deletes the service and its associated resources.
+     *
+     * @return {Promise<()>} An empty Promise that will be fulfilled when the service is deleted.
+     */
+    AuthTokenManager.prototype.delete = function () {
+        // There are no resources to clean up
+        return Promise.resolve(undefined);
+    };
+    /**
+     * Gets an auth token for the associated app.
+     *
+     * @param {boolean} forceRefresh Whether or not to force a token refresh.
+     * @return {Promise<Object>} A Promise that will be fulfilled with the current or new token.
+     */
+    AuthTokenManager.prototype.getToken = function (forceRefresh) {
+        var _this = this;
+        var expired = this.cachedToken && this.cachedToken.expirationTime < Date.now();
+        if (this.cachedToken && !forceRefresh && !expired) {
+            return Promise.resolve(this.cachedToken);
+        }
+        else {
+            // credential may be an external class; resolving it in a promise helps us
+            // protect against exceptions and upgrades the result to a promise in all cases.
+            return Promise.resolve()
+                .then(function () {
+                return _this.credential.getAccessToken();
+            })
+                .then(function (result) {
+                if (result === null) {
+                    return null;
+                }
+                // Since the customer can provide the credential implementation, we want to weakly verify
+                // the return type until the type is properly exported.
+                if (typeof result !== 'object' ||
+                    typeof result.expires_in !== 'number' ||
+                    typeof result.access_token !== 'string') {
+                    throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CREDENTIAL, 'initializeApp() was called with a credential ' +
+                        'that creates invalid access tokens: ' + JSON.stringify(result));
+                }
+                var token = {
+                    accessToken: result.access_token,
+                    expirationTime: Date.now() + (result.expires_in * 1000),
+                };
+                var hasAccessTokenChanged = (_this.cachedToken && _this.cachedToken.accessToken !== token.accessToken);
+                var hasExpirationChanged = (_this.cachedToken && _this.cachedToken.expirationTime !== token.expirationTime);
+                if (!_this.cachedToken || hasAccessTokenChanged || hasExpirationChanged) {
+                    _this.cachedToken = token;
+                    _this.tokenListeners.forEach(function (listener) {
+                        listener(token.accessToken);
+                    });
+                }
+                return token;
+            });
+        }
+    };
+    /**
+     * Adds a listener that is called each time a token changes.
+     *
+     * @param {function(string)} listener The listener that will be called with each new token.
+     */
+    AuthTokenManager.prototype.addAuthTokenListener = function (listener) {
+        this.tokenListeners.push(listener);
+        if (this.cachedToken) {
+            listener(this.cachedToken.accessToken);
+        }
+    };
+    /**
+     * Removes a token listener.
+     *
+     * @param {function(string)} listener The listener to remove.
+     */
+    AuthTokenManager.prototype.removeAuthTokenListener = function (listener) {
+        this.tokenListeners = this.tokenListeners.filter(function (other) { return other !== listener; });
+    };
+    return AuthTokenManager;
+}());
+exports.AuthTokenManager = AuthTokenManager;
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/auth/credential.d.ts b/KEMMessaging/node_modules/firebase-admin/lib/auth/credential.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9403259a38a570a344d102651360af1779aa7a04
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/auth/credential.d.ts
@@ -0,0 +1,74 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+/// <reference types="chai" />
+export declare class RefreshToken {
+    clientId: string;
+    clientSecret: string;
+    refreshToken: string;
+    type: string;
+    static fromPath(path: string): RefreshToken;
+    constructor(json: Object);
+}
+/**
+ * A struct containing the fields necessary to use service-account JSON credentials.
+ */
+export declare class Certificate {
+    projectId: string;
+    privateKey: string;
+    clientEmail: string;
+    static fromPath(path: string): Certificate;
+    constructor(json: Object);
+}
+/**
+ * Interface for Google OAuth 2.0 access tokens.
+ */
+export declare type GoogleOAuthAccessToken = {
+    access_token: string;
+    expires_in: number;
+};
+/**
+ * Implementation of Credential that uses a service account certificate.
+ */
+export declare class CertCredential implements Credential {
+    private certificate_;
+    constructor(serviceAccountPathOrObject: string | Object);
+    getAccessToken(): Promise<GoogleOAuthAccessToken>;
+    getCertificate(): Certificate;
+    private createAuthJwt_();
+}
+/**
+ * Interface for things that generate access tokens.
+ */
+export interface Credential {
+    getAccessToken(): Promise<GoogleOAuthAccessToken>;
+    getCertificate(): Certificate;
+}
+/**
+ * Implementation of Credential that gets access tokens from refresh tokens.
+ */
+export declare class RefreshTokenCredential implements Credential {
+    private refreshToken_;
+    constructor(refreshTokenPathOrObject: string | Object);
+    getAccessToken(): Promise<GoogleOAuthAccessToken>;
+    getCertificate(): Certificate;
+}
+/**
+ * Implementation of Credential that gets access tokens from the metadata service available
+ * in the Google Cloud Platform. This authenticates the process as the default service account
+ * of an App Engine instance or Google Compute Engine machine.
+ */
+export declare class MetadataServiceCredential implements Credential {
+    getAccessToken(): Promise<GoogleOAuthAccessToken>;
+    getCertificate(): Certificate;
+}
+/**
+ * ApplicationDefaultCredential implements the process for loading credentials as
+ * described in https://developers.google.com/identity/protocols/application-default-credentials
+ */
+export declare class ApplicationDefaultCredential implements Credential {
+    private credential_;
+    constructor();
+    getAccessToken(): Promise<GoogleOAuthAccessToken>;
+    getCertificate(): Certificate;
+    getCredential(): Credential;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/auth/credential.js b/KEMMessaging/node_modules/firebase-admin/lib/auth/credential.js
new file mode 100644
index 0000000000000000000000000000000000000000..607ca1089d43d0c76941b0250b0986fabbf716cb
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/auth/credential.js
@@ -0,0 +1,292 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+"use strict";
+var jwt = require('jsonwebtoken');
+// Use untyped import syntax for Node built-ins
+var fs = require('fs');
+var os = require('os');
+var http = require('http');
+var path = require('path');
+var https = require('https');
+var GOOGLE_TOKEN_AUDIENCE = 'https://accounts.google.com/o/oauth2/token';
+var GOOGLE_AUTH_TOKEN_HOST = 'accounts.google.com';
+var GOOGLE_AUTH_TOKEN_PATH = '/o/oauth2/token';
+var GOOGLE_AUTH_TOKEN_PORT = 443;
+// NOTE: the Google Metadata Service uses HTTP over a vlan
+var GOOGLE_METADATA_SERVICE_HOST = 'metadata.google.internal';
+var GOOGLE_METADATA_SERVICE_PATH = '/computeMetadata/v1beta1/instance/service-accounts/default/token';
+var configDir = (function () {
+    // Windows has a dedicated low-rights location for apps at ~/Application Data
+    var sys = os.platform();
+    if (sys && sys.length >= 3 && sys.substring(0, 3).toLowerCase() === 'win') {
+        return process.env.APPDATA;
+    }
+    // On *nix the gcloud cli creates a . dir.
+    return process.env.HOME && path.resolve(process.env.HOME, '.config');
+})();
+var GCLOUD_CREDENTIAL_SUFFIX = 'gcloud/application_default_credentials.json';
+var GCLOUD_CREDENTIAL_PATH = configDir && path.resolve(configDir, GCLOUD_CREDENTIAL_SUFFIX);
+var REFRESH_TOKEN_HOST = 'www.googleapis.com';
+var REFRESH_TOKEN_PORT = 443;
+var REFRESH_TOKEN_PATH = '/oauth2/v4/token';
+var ONE_HOUR_IN_SECONDS = 60 * 60;
+var JWT_ALGORITHM = 'RS256';
+function copyAttr(to, from, key, alt) {
+    var tmp = from[key] || from[alt];
+    if (typeof tmp !== 'undefined') {
+        to[key] = tmp;
+    }
+}
+var RefreshToken = (function () {
+    function RefreshToken(json) {
+        copyAttr(this, json, 'clientId', 'client_id');
+        copyAttr(this, json, 'clientSecret', 'client_secret');
+        copyAttr(this, json, 'refreshToken', 'refresh_token');
+        copyAttr(this, json, 'type', 'type');
+        if (typeof this.clientId !== 'string' || !this.clientId) {
+            throw new Error('Refresh token must contain a "client_id" field');
+        }
+        else if (typeof this.clientSecret !== 'string' || !this.clientSecret) {
+            throw new Error('Refresh token must contain a "client_secret" field');
+        }
+        else if (typeof this.refreshToken !== 'string' || !this.refreshToken) {
+            throw new Error('Refresh token must contain a "refresh_token" field');
+        }
+        else if (typeof this.type !== 'string' || !this.type) {
+            throw new Error('Refresh token must contain a "type" field');
+        }
+    }
+    /*
+     * Tries to load a RefreshToken from a path. If the path is not present, returns null.
+     * Throws if data at the path is invalid.
+     */
+    RefreshToken.fromPath = function (path) {
+        var jsonString;
+        try {
+            jsonString = fs.readFileSync(path, 'utf8');
+        }
+        catch (ignored) {
+            // Ignore errors if the file is not present, as this is sometimes an expected condition
+            return null;
+        }
+        try {
+            return new RefreshToken(JSON.parse(jsonString));
+        }
+        catch (error) {
+            // Throw a nicely formed error message if the file contents cannot be parsed
+            throw new Error('Failed to parse refresh token file: ' + error);
+        }
+    };
+    return RefreshToken;
+}());
+exports.RefreshToken = RefreshToken;
+/**
+ * A struct containing the fields necessary to use service-account JSON credentials.
+ */
+var Certificate = (function () {
+    function Certificate(json) {
+        // TODO: validate Certificate
+        copyAttr(this, json, 'projectId', 'project_id');
+        copyAttr(this, json, 'privateKey', 'private_key');
+        copyAttr(this, json, 'clientEmail', 'client_email');
+        if (typeof this.privateKey !== 'string' || !this.privateKey) {
+            throw new Error('Service account key must contain a string "private_key" field');
+        }
+        else if (typeof this.clientEmail !== 'string' || !this.clientEmail) {
+            throw new Error('Service account key must contain a string "client_email" field');
+        }
+    }
+    Certificate.fromPath = function (path) {
+        try {
+            return new Certificate(JSON.parse(fs.readFileSync(path, 'utf8')));
+        }
+        catch (error) {
+            // Throw a nicely formed error message if the file contents cannot be parsed
+            throw new Error('Failed to parse service account key file: ' + error);
+        }
+    };
+    return Certificate;
+}());
+exports.Certificate = Certificate;
+/**
+ * A wrapper around the http and https request libraries to simplify & promisify JSON requests.
+ * TODO(inlined): Create a type for "transit".
+ */
+function requestAccessToken(transit, options, data) {
+    return new Promise(function (resolve, reject) {
+        var req = transit.request(options, function (res) {
+            var buffers = [];
+            res.on('data', function (buffer) { return buffers.push(buffer); });
+            res.on('end', function () {
+                try {
+                    var json = JSON.parse(Buffer.concat(buffers).toString());
+                    if (json.error) {
+                        var msg = 'Error fetching access token: ' + json.error;
+                        if (json.error_description) {
+                            msg += ' (' + json.error_description + ')';
+                        }
+                        reject(new Error(msg));
+                    }
+                    else if (!json.access_token || !json.expires_in) {
+                        reject(new Error('Unexpected response from server'));
+                    }
+                    else {
+                        resolve(json);
+                    }
+                }
+                catch (err) {
+                    reject(err);
+                }
+            });
+        });
+        req.on('error', reject);
+        if (data) {
+            req.write(data);
+        }
+        req.end();
+    });
+}
+/**
+ * Implementation of Credential that uses a service account certificate.
+ */
+var CertCredential = (function () {
+    function CertCredential(serviceAccountPathOrObject) {
+        if (typeof serviceAccountPathOrObject === 'string') {
+            this.certificate_ = Certificate.fromPath(serviceAccountPathOrObject);
+        }
+        else {
+            this.certificate_ = new Certificate(serviceAccountPathOrObject);
+        }
+    }
+    CertCredential.prototype.getAccessToken = function () {
+        var token = this.createAuthJwt_();
+        var postData = 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3A' +
+            'grant-type%3Ajwt-bearer&assertion=' +
+            token;
+        var options = {
+            method: 'POST',
+            host: GOOGLE_AUTH_TOKEN_HOST,
+            port: GOOGLE_AUTH_TOKEN_PORT,
+            path: GOOGLE_AUTH_TOKEN_PATH,
+            headers: {
+                'Content-Type': 'application/x-www-form-urlencoded',
+                'Content-Length': postData.length,
+            },
+        };
+        return requestAccessToken(https, options, postData);
+    };
+    CertCredential.prototype.getCertificate = function () {
+        return this.certificate_;
+    };
+    CertCredential.prototype.createAuthJwt_ = function () {
+        var claims = {
+            scope: [
+                'https://www.googleapis.com/auth/userinfo.email',
+                'https://www.googleapis.com/auth/firebase.database',
+                'https://www.googleapis.com/auth/identitytoolkit',
+            ].join(' '),
+        };
+        // This method is actually synchronous so we can capture and return the buffer.
+        return jwt.sign(claims, this.certificate_.privateKey, {
+            audience: GOOGLE_TOKEN_AUDIENCE,
+            expiresIn: ONE_HOUR_IN_SECONDS,
+            issuer: this.certificate_.clientEmail,
+            algorithm: JWT_ALGORITHM,
+        });
+    };
+    return CertCredential;
+}());
+exports.CertCredential = CertCredential;
+/**
+ * Implementation of Credential that gets access tokens from refresh tokens.
+ */
+var RefreshTokenCredential = (function () {
+    function RefreshTokenCredential(refreshTokenPathOrObject) {
+        if (typeof refreshTokenPathOrObject === 'string') {
+            this.refreshToken_ = RefreshToken.fromPath(refreshTokenPathOrObject);
+        }
+        else {
+            this.refreshToken_ = new RefreshToken(refreshTokenPathOrObject);
+        }
+    }
+    RefreshTokenCredential.prototype.getAccessToken = function () {
+        var postData = 'client_id=' + this.refreshToken_.clientId + '&' +
+            'client_secret=' + this.refreshToken_.clientSecret + '&' +
+            'refresh_token=' + this.refreshToken_.refreshToken + '&' +
+            'grant_type=refresh_token';
+        var options = {
+            method: 'POST',
+            host: REFRESH_TOKEN_HOST,
+            port: REFRESH_TOKEN_PORT,
+            path: REFRESH_TOKEN_PATH,
+            headers: {
+                'Content-Type': 'application/x-www-form-urlencoded',
+                'Content-Length': postData.length,
+            },
+        };
+        return requestAccessToken(https, options, postData);
+    };
+    ;
+    RefreshTokenCredential.prototype.getCertificate = function () {
+        return null;
+    };
+    return RefreshTokenCredential;
+}());
+exports.RefreshTokenCredential = RefreshTokenCredential;
+/**
+ * Implementation of Credential that gets access tokens from the metadata service available
+ * in the Google Cloud Platform. This authenticates the process as the default service account
+ * of an App Engine instance or Google Compute Engine machine.
+ */
+var MetadataServiceCredential = (function () {
+    function MetadataServiceCredential() {
+    }
+    MetadataServiceCredential.prototype.getAccessToken = function () {
+        var options = {
+            method: 'GET',
+            host: GOOGLE_METADATA_SERVICE_HOST,
+            path: GOOGLE_METADATA_SERVICE_PATH,
+            headers: {
+                'Content-Length': 0,
+            },
+        };
+        return requestAccessToken(http, options);
+    };
+    MetadataServiceCredential.prototype.getCertificate = function () {
+        return null;
+    };
+    return MetadataServiceCredential;
+}());
+exports.MetadataServiceCredential = MetadataServiceCredential;
+/**
+ * ApplicationDefaultCredential implements the process for loading credentials as
+ * described in https://developers.google.com/identity/protocols/application-default-credentials
+ */
+var ApplicationDefaultCredential = (function () {
+    function ApplicationDefaultCredential() {
+        if (process.env.GOOGLE_APPLICATION_CREDENTIALS) {
+            var serviceAccount = Certificate.fromPath(process.env.GOOGLE_APPLICATION_CREDENTIALS);
+            this.credential_ = new CertCredential(serviceAccount);
+            return;
+        }
+        // It is OK to not have this file. If it is present, it must be valid.
+        var refreshToken = RefreshToken.fromPath(GCLOUD_CREDENTIAL_PATH);
+        if (refreshToken) {
+            this.credential_ = new RefreshTokenCredential(refreshToken);
+            return;
+        }
+        this.credential_ = new MetadataServiceCredential();
+    }
+    ApplicationDefaultCredential.prototype.getAccessToken = function () {
+        return this.credential_.getAccessToken();
+    };
+    ApplicationDefaultCredential.prototype.getCertificate = function () {
+        return this.credential_.getCertificate();
+    };
+    // Used in testing to verify we are delegating to the correct implementation.
+    ApplicationDefaultCredential.prototype.getCredential = function () {
+        return this.credential_;
+    };
+    return ApplicationDefaultCredential;
+}());
+exports.ApplicationDefaultCredential = ApplicationDefaultCredential;
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/auth/register-auth.d.ts b/KEMMessaging/node_modules/firebase-admin/lib/auth/register-auth.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c45f52d0eb5ca831cd63a3ddde8763d4e866d881
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/auth/register-auth.d.ts
@@ -0,0 +1,5 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+import { FirebaseServiceInterface } from '../firebase-service';
+import { FirebaseServiceNamespace } from '../firebase-namespace';
+export default function (): FirebaseServiceNamespace<FirebaseServiceInterface>;
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/auth/register-auth.js b/KEMMessaging/node_modules/firebase-admin/lib/auth/register-auth.js
new file mode 100644
index 0000000000000000000000000000000000000000..0030ce6d9dcd9cadabec9a87f45d42fcdeba5123
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/auth/register-auth.js
@@ -0,0 +1,41 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+"use strict";
+var auth_1 = require('./auth');
+var firebase = require('../default-namespace');
+/**
+ * Factory function that creates a new auth service.
+ * @param {Object} app The app for this service
+ * @param {function(Object)} extendApp An extend function to extend the app
+ *                                     namespace
+ * @return {Auth} The auth service for the specified app.
+ */
+function serviceFactory(app, extendApp) {
+    var auth = new auth_1.Auth(app);
+    extendApp({
+        INTERNAL: {
+            getToken: auth.INTERNAL.getToken.bind(auth.INTERNAL),
+            addAuthTokenListener: auth.INTERNAL.addAuthTokenListener.bind(auth.INTERNAL),
+            removeAuthTokenListener: auth.INTERNAL.removeAuthTokenListener.bind(auth.INTERNAL),
+        },
+    });
+    return auth;
+}
+/**
+ * Handles app life-cycle events. Initializes auth so listerners and getToken() functions are
+ * available to other services immediately.
+ *
+ * @param {string} event The app event that is occurring.
+ * @param {FirebaseApp} app The app for which the app hook is firing.
+ */
+var appHook = function (event, app) {
+    if (event === 'create') {
+        // Initializes auth so listeners and getToken() functions are available to other services immediately.
+        app.auth();
+    }
+};
+function default_1() {
+    return firebase.INTERNAL.registerService('auth', serviceFactory, { Auth: auth_1.Auth }, appHook);
+}
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.default = default_1;
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/auth/token-generator.d.ts b/KEMMessaging/node_modules/firebase-admin/lib/auth/token-generator.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..27789694b37893cb08e771c418cb3d8a431647c1
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/auth/token-generator.d.ts
@@ -0,0 +1,44 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+/// <reference types="chai" />
+import { Certificate } from './credential';
+/**
+ * Class for generating and verifying different types of Firebase Auth tokens (JWTs).
+ */
+export declare class FirebaseTokenGenerator {
+    private certificate_;
+    private publicKeys_;
+    private publicKeysExpireAt_;
+    constructor(certificate: Certificate);
+    /**
+     * Creates a new Firebase Auth Custom token.
+     *
+     * @param {string} uid The user ID to use for the generated Firebase Auth Custom token.
+     * @param {Object} [developerClaims] Optional developer claims to include in the generated Firebase
+     *                 Auth Custom token.
+     * @return {Promise<string>} A Promise fulfilled with a Firebase Auth Custom token signed with a
+     *                           service account key and containing the provided payload.
+     */
+    createCustomToken(uid: string, developerClaims?: Object): Promise<string>;
+    /**
+     * Verifies the format and signature of a Firebase Auth ID token.
+     *
+     * @param {string} idToken The Firebase Auth ID token to verify.
+     * @return {Promise<Object>} A promise fulfilled with the decoded claims of the Firebase Auth ID
+     *                           token.
+     */
+    verifyIdToken(idToken: string): Promise<Object>;
+    /**
+     * Returns whether or not the provided developer claims are valid.
+     *
+     * @param {Object} [developerClaims] Optional developer claims to validate.
+     * @return {boolean} True if the provided claims are valid; otherwise, false.
+     */
+    private isDeveloperClaimsValid_(developerClaims?);
+    /**
+     * Fetches the public keys for the Google certs.
+     *
+     * @return {Promise<Object>} A promise fulfilled with public keys for the Google certs.
+     */
+    private fetchPublicKeys_();
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/auth/token-generator.js b/KEMMessaging/node_modules/firebase-admin/lib/auth/token-generator.js
new file mode 100644
index 0000000000000000000000000000000000000000..09966e5b412359726fcbde1cbab923d441327f51
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/auth/token-generator.js
@@ -0,0 +1,244 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+"use strict";
+var jwt = require('jsonwebtoken');
+// Use untyped import syntax for Node built-ins
+var https = require('https');
+var ALGORITHM = 'RS256';
+var ONE_HOUR_IN_SECONDS = 60 * 60;
+// List of blacklisted claims which cannot be provided when creating a custom token
+var BLACKLISTED_CLAIMS = [
+    'acr', 'amr', 'at_hash', 'aud', 'auth_time', 'azp', 'cnf', 'c_hash', 'exp', 'iat', 'iss', 'jti',
+    'nbf', 'nonce',
+];
+// URL containing the public keys for the Google certs (whose private keys are used to sign Firebase
+// Auth ID tokens)
+var CLIENT_CERT_URL = 'https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com';
+// Audience to use for Firebase Auth Custom tokens
+var FIREBASE_AUDIENCE = 'https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit';
+/**
+ * Class for generating and verifying different types of Firebase Auth tokens (JWTs).
+ */
+var FirebaseTokenGenerator = (function () {
+    function FirebaseTokenGenerator(certificate) {
+        if (!certificate) {
+            throw new Error('Must provide a service account to use FirebaseTokenGenerator');
+        }
+        this.certificate_ = certificate;
+    }
+    /**
+     * Creates a new Firebase Auth Custom token.
+     *
+     * @param {string} uid The user ID to use for the generated Firebase Auth Custom token.
+     * @param {Object} [developerClaims] Optional developer claims to include in the generated Firebase
+     *                 Auth Custom token.
+     * @return {Promise<string>} A Promise fulfilled with a Firebase Auth Custom token signed with a
+     *                           service account key and containing the provided payload.
+     */
+    FirebaseTokenGenerator.prototype.createCustomToken = function (uid, developerClaims) {
+        var errorMessage;
+        if (typeof uid !== 'string' || uid === '') {
+            errorMessage = 'First argument to createCustomToken() must be a non-empty string uid';
+        }
+        else if (uid.length > 128) {
+            errorMessage = 'First argument to createCustomToken() must a uid with less than or equal to 128 characters';
+        }
+        else if (!this.isDeveloperClaimsValid_(developerClaims)) {
+            errorMessage = 'Second argument to createCustomToken() must be an object containing the developer claims';
+        }
+        if (typeof errorMessage !== 'undefined') {
+            throw new Error(errorMessage);
+        }
+        var jwtPayload = {};
+        if (typeof developerClaims !== 'undefined') {
+            var claims = {};
+            for (var key in developerClaims) {
+                /* istanbul ignore else */
+                if (developerClaims.hasOwnProperty(key)) {
+                    if (BLACKLISTED_CLAIMS.indexOf(key) !== -1) {
+                        throw new Error("Developer claim \"" + key + "\" is reserved and cannot be specified");
+                    }
+                    claims[key] = developerClaims[key];
+                }
+            }
+            jwtPayload.claims = claims;
+        }
+        jwtPayload.uid = uid;
+        var customToken = jwt.sign(jwtPayload, this.certificate_.privateKey, {
+            audience: FIREBASE_AUDIENCE,
+            expiresIn: ONE_HOUR_IN_SECONDS,
+            issuer: this.certificate_.clientEmail,
+            subject: this.certificate_.clientEmail,
+            algorithm: ALGORITHM,
+        });
+        return Promise.resolve(customToken);
+    };
+    /**
+     * Verifies the format and signature of a Firebase Auth ID token.
+     *
+     * @param {string} idToken The Firebase Auth ID token to verify.
+     * @return {Promise<Object>} A promise fulfilled with the decoded claims of the Firebase Auth ID
+     *                           token.
+     */
+    FirebaseTokenGenerator.prototype.verifyIdToken = function (idToken) {
+        if (typeof idToken !== 'string') {
+            throw new Error('First argument to verifyIdToken() must be a Firebase ID token');
+        }
+        if (typeof this.certificate_.projectId !== 'string' || this.certificate_.projectId === '') {
+            throw new Error('verifyIdToken() requires a service account with "project_id" set');
+        }
+        var fullDecodedToken = jwt.decode(idToken, {
+            complete: true,
+        });
+        var header = fullDecodedToken && fullDecodedToken.header;
+        var payload = fullDecodedToken && fullDecodedToken.payload;
+        var projectIdMatchMessage = ' Make sure the ID token comes from the same Firebase project as the ' +
+            'service account used to authenticate this SDK.';
+        var verifyIdTokenDocsMessage = ' See https://firebase.google.com/docs/auth/admin/verify-id-tokens ' +
+            'for details on how to retrieve an ID token.';
+        var errorMessage;
+        if (!fullDecodedToken) {
+            errorMessage = 'Decoding Firebase ID token failed. Make sure you passed the entire string JWT ' +
+                'which represents an ID token.' + verifyIdTokenDocsMessage;
+        }
+        else if (typeof header.kid === 'undefined') {
+            var isCustomToken = (payload.aud === FIREBASE_AUDIENCE);
+            var isLegacyCustomToken = (header.alg === 'HS256' && payload.v === 0 && 'd' in payload && 'uid' in payload.d);
+            if (isCustomToken) {
+                errorMessage = 'verifyIdToken() expects an ID token, but was given a custom token.';
+            }
+            else if (isLegacyCustomToken) {
+                errorMessage = 'verifyIdToken() expects an ID token, but was given a legacy custom token.';
+            }
+            else {
+                errorMessage = 'Firebase ID token has no "kid" claim.';
+            }
+            errorMessage += verifyIdTokenDocsMessage;
+        }
+        else if (header.alg !== ALGORITHM) {
+            errorMessage = 'Firebase ID token has incorrect algorithm. Expected "' + ALGORITHM + '" but got ' +
+                '"' + header.alg + '".' + verifyIdTokenDocsMessage;
+        }
+        else if (payload.aud !== this.certificate_.projectId) {
+            errorMessage = 'Firebase ID token has incorrect "aud" (audience) claim. Expected "' +
+                this.certificate_.projectId + '" but got "' + payload.aud + '".' + projectIdMatchMessage +
+                verifyIdTokenDocsMessage;
+        }
+        else if (payload.iss !== 'https://securetoken.google.com/' + this.certificate_.projectId) {
+            errorMessage = 'Firebase ID token has incorrect "iss" (issuer) claim. Expected ' +
+                '"https://securetoken.google.com/' + this.certificate_.projectId + '" but got "' +
+                payload.iss + '".' + projectIdMatchMessage + verifyIdTokenDocsMessage;
+        }
+        else if (typeof payload.sub !== 'string') {
+            errorMessage = 'Firebase ID token has no "sub" (subject) claim.' + verifyIdTokenDocsMessage;
+        }
+        else if (payload.sub === '') {
+            errorMessage = 'Firebase ID token has an empty string "sub" (subject) claim.' + verifyIdTokenDocsMessage;
+        }
+        else if (payload.sub.length > 128) {
+            errorMessage = 'Firebase ID token has "sub" (subject) claim longer than 128 characters.' +
+                verifyIdTokenDocsMessage;
+        }
+        if (typeof errorMessage !== 'undefined') {
+            return Promise.reject(new Error(errorMessage));
+        }
+        return this.fetchPublicKeys_().then(function (publicKeys) {
+            if (!publicKeys.hasOwnProperty(header.kid)) {
+                errorMessage = 'Firebase ID token has "kid" claim which does not correspond to a known ' +
+                    'public key. Most likely the ID token is expired, so get a fresh token from your client ' +
+                    'app and try again.' + verifyIdTokenDocsMessage;
+                return Promise.reject(new Error(errorMessage));
+            }
+            return new Promise(function (resolve, reject) {
+                jwt.verify(idToken, publicKeys[header.kid], {
+                    algorithms: [ALGORITHM],
+                }, function (error, decodedToken) {
+                    if (error) {
+                        if (error.name === 'TokenExpiredError') {
+                            errorMessage = 'Firebase ID token has expired. Get a fresh token from your client app and try ' +
+                                'again.' + verifyIdTokenDocsMessage;
+                        }
+                        else if (error.name === 'JsonWebTokenError') {
+                            errorMessage = 'Firebase ID token has invalid signature.' + verifyIdTokenDocsMessage;
+                        }
+                        reject(new Error(errorMessage));
+                    }
+                    else {
+                        decodedToken.uid = decodedToken.sub;
+                        resolve(decodedToken);
+                    }
+                });
+            });
+        });
+    };
+    /**
+     * Returns whether or not the provided developer claims are valid.
+     *
+     * @param {Object} [developerClaims] Optional developer claims to validate.
+     * @return {boolean} True if the provided claims are valid; otherwise, false.
+     */
+    FirebaseTokenGenerator.prototype.isDeveloperClaimsValid_ = function (developerClaims) {
+        if (typeof developerClaims === 'undefined') {
+            return true;
+        }
+        if (typeof developerClaims === 'object' && developerClaims !== null && !(developerClaims instanceof Array)) {
+            return true;
+        }
+        return false;
+    };
+    /**
+     * Fetches the public keys for the Google certs.
+     *
+     * @return {Promise<Object>} A promise fulfilled with public keys for the Google certs.
+     */
+    FirebaseTokenGenerator.prototype.fetchPublicKeys_ = function () {
+        var _this = this;
+        var publicKeysExist = (typeof this.publicKeys_ !== 'undefined');
+        var publicKeysExpiredExists = (typeof this.publicKeysExpireAt_ !== 'undefined');
+        var publicKeysStillValid = (publicKeysExpiredExists && Date.now() < this.publicKeysExpireAt_);
+        if (publicKeysExist && publicKeysStillValid) {
+            return Promise.resolve(this.publicKeys_);
+        }
+        return new Promise(function (resolve, reject) {
+            https.get(CLIENT_CERT_URL, function (res) {
+                var buffers = [];
+                res.on('data', function (buffer) { return buffers.push(buffer); });
+                res.on('end', function () {
+                    try {
+                        var response = JSON.parse(Buffer.concat(buffers).toString());
+                        if (response.error) {
+                            var errorMessage = 'Error fetching public keys for Google certs: ' + response.error;
+                            /* istanbul ignore else */
+                            if (response.error_description) {
+                                errorMessage += ' (' + response.error_description + ')';
+                            }
+                            reject(new Error(errorMessage));
+                        }
+                        else {
+                            /* istanbul ignore else */
+                            if (res.headers.hasOwnProperty('cache-control')) {
+                                var cacheControlHeader = res.headers['cache-control'];
+                                var parts = cacheControlHeader.split(',');
+                                parts.forEach(function (part) {
+                                    var subParts = part.trim().split('=');
+                                    if (subParts[0] === 'max-age') {
+                                        var maxAge = subParts[1];
+                                        _this.publicKeysExpireAt_ = Date.now() + (maxAge * 1000);
+                                    }
+                                });
+                            }
+                            _this.publicKeys_ = response;
+                            resolve(response);
+                        }
+                    }
+                    catch (e) {
+                        /* istanbul ignore next */
+                        reject(e);
+                    }
+                });
+            }).on('error', reject);
+        });
+    };
+    return FirebaseTokenGenerator;
+}());
+exports.FirebaseTokenGenerator = FirebaseTokenGenerator;
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/auth/user-record.d.ts b/KEMMessaging/node_modules/firebase-admin/lib/auth/user-record.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8ffaf699a3cb58b2d567a79294925a01635e75e1
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/auth/user-record.d.ts
@@ -0,0 +1,87 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+/// <reference types="chai" />
+/**
+ * User metadata class that provides metadata information like user account creation
+ * and last sign in time.
+ *
+ * @param {Object} response The server side response returned from the getAccountInfo
+ *     endpoint.
+ * @constructor
+ */
+export declare class UserMetadata {
+    private lastSignedInAtInternal;
+    private createdAtInternal;
+    constructor(response: any);
+    /** @return {Date} The user's last sign-in date. */
+    readonly lastSignedInAt: Date;
+    /** @return {Date} The user's account creation date. */
+    readonly createdAt: Date;
+    /** @return {Object} The plain object representation of the user's metadata. */
+    toJSON(): Object;
+}
+/**
+ * User info class that provides provider user information for different
+ * Firebase providers like google.com, facebook.com, password, etc.
+ *
+ * @param {Object} response The server side response returned from the getAccountInfo
+ *     endpoint.
+ * @constructor
+ */
+export declare class UserInfo {
+    private uidInternal;
+    private displayNameInternal;
+    private emailInternal;
+    private photoURLInternal;
+    private providerIdInternal;
+    constructor(response: any);
+    /** @return {string} The provider user id. */
+    readonly uid: string;
+    /** @return {string} The provider display name. */
+    readonly displayName: string;
+    /** @return {string} The provider email. */
+    readonly email: string;
+    /** @return {string} The provider photo URL. */
+    readonly photoURL: string;
+    /** @return {string} The provider Firebase ID. */
+    readonly providerId: string;
+    /** @return {Object} The plain object representation of the current provider data. */
+    toJSON(): Object;
+}
+/**
+ * User record class that defines the Firebase user object populated from
+ * the Firebase Auth getAccountInfo response.
+ *
+ * @param {Object} response The server side response returned from the getAccountInfo
+ *     endpoint.
+ * @constructor
+ */
+export declare class UserRecord {
+    private uidInternal;
+    private emailInternal;
+    private emailVerifiedInternal;
+    private displayNameInternal;
+    private photoURLInternal;
+    private disabledInternal;
+    private metadataInternal;
+    private providerDataInternal;
+    constructor(response: any);
+    /** @return {string} The Firebase user id corresponding to the current user record. */
+    readonly uid: string;
+    /** @return {string} The primary email corresponding to the current user record. */
+    readonly email: string;
+    /** @return {boolean} Whether the primary email is verified. */
+    readonly emailVerified: boolean;
+    /** @return {string} The display name corresponding to the current user record. */
+    readonly displayName: string;
+    /** @return {string} The photo URL corresponding to the current user record. */
+    readonly photoURL: string;
+    /** @return {boolean} Whether the current user is disabled or not. */
+    readonly disabled: boolean;
+    /** @return {UserMetadata} The user record's metadata. */
+    readonly metadata: UserMetadata;
+    /** @return {UserInfo[]} The list of providers linked to the current record. */
+    readonly providerData: UserInfo[];
+    /** @return {Object} The plain object representation of the user record. */
+    toJSON(): Object;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/auth/user-record.js b/KEMMessaging/node_modules/firebase-admin/lib/auth/user-record.js
new file mode 100644
index 0000000000000000000000000000000000000000..a202b7f0a3df09a067c00a0ca7312d51286ab33c
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/auth/user-record.js
@@ -0,0 +1,252 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+"use strict";
+var error_1 = require('../utils/error');
+/**
+ * Parses a time stamp string or number and returns the corresponding date if valid.
+ *
+ * @param {any} time The unix timestamp string or number in milliseconds.
+ * @return {Date} The corresponding date if valid.
+ */
+function parseDate(time) {
+    try {
+        var date = new Date(parseInt(time, 10));
+        if (!isNaN(date.getTime())) {
+            return date;
+        }
+    }
+    catch (e) {
+    }
+    return null;
+}
+/**
+ * User metadata class that provides metadata information like user account creation
+ * and last sign in time.
+ *
+ * @param {Object} response The server side response returned from the getAccountInfo
+ *     endpoint.
+ * @constructor
+ */
+var UserMetadata = (function () {
+    function UserMetadata(response) {
+        // Creation date is required.
+        this.createdAtInternal = parseDate(response.createdAt);
+        if (!this.createdAtInternal) {
+            throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INTERNAL_ERROR, 'INTERNAL ASSERT FAILED: Invalid metadata response');
+        }
+        this.lastSignedInAtInternal = parseDate(response.lastLoginAt);
+    }
+    Object.defineProperty(UserMetadata.prototype, "lastSignedInAt", {
+        /** @return {Date} The user's last sign-in date. */
+        get: function () {
+            return this.lastSignedInAtInternal;
+        },
+        enumerable: true,
+        configurable: true
+    });
+    Object.defineProperty(UserMetadata.prototype, "createdAt", {
+        /** @return {Date} The user's account creation date. */
+        get: function () {
+            return this.createdAtInternal;
+        },
+        enumerable: true,
+        configurable: true
+    });
+    /** @return {Object} The plain object representation of the user's metadata. */
+    UserMetadata.prototype.toJSON = function () {
+        return {
+            lastSignedInAt: this.lastSignedInAt,
+            createdAt: this.createdAt,
+        };
+    };
+    return UserMetadata;
+}());
+exports.UserMetadata = UserMetadata;
+/**
+ * User info class that provides provider user information for different
+ * Firebase providers like google.com, facebook.com, password, etc.
+ *
+ * @param {Object} response The server side response returned from the getAccountInfo
+ *     endpoint.
+ * @constructor
+ */
+var UserInfo = (function () {
+    function UserInfo(response) {
+        // Provider user id and provider id are required.
+        if (!response.rawId || !response.providerId) {
+            throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INTERNAL_ERROR, 'INTERNAL ASSERT FAILED: Invalid user info response');
+        }
+        this.uidInternal = response.rawId;
+        this.displayNameInternal = response.displayName;
+        this.emailInternal = response.email;
+        this.photoURLInternal = response.photoUrl;
+        this.providerIdInternal = response.providerId;
+    }
+    Object.defineProperty(UserInfo.prototype, "uid", {
+        /** @return {string} The provider user id. */
+        get: function () {
+            return this.uidInternal;
+        },
+        enumerable: true,
+        configurable: true
+    });
+    Object.defineProperty(UserInfo.prototype, "displayName", {
+        /** @return {string} The provider display name. */
+        get: function () {
+            return this.displayNameInternal;
+        },
+        enumerable: true,
+        configurable: true
+    });
+    Object.defineProperty(UserInfo.prototype, "email", {
+        /** @return {string} The provider email. */
+        get: function () {
+            return this.emailInternal;
+        },
+        enumerable: true,
+        configurable: true
+    });
+    Object.defineProperty(UserInfo.prototype, "photoURL", {
+        /** @return {string} The provider photo URL. */
+        get: function () {
+            return this.photoURLInternal;
+        },
+        enumerable: true,
+        configurable: true
+    });
+    Object.defineProperty(UserInfo.prototype, "providerId", {
+        /** @return {string} The provider Firebase ID. */
+        get: function () {
+            return this.providerIdInternal;
+        },
+        enumerable: true,
+        configurable: true
+    });
+    /** @return {Object} The plain object representation of the current provider data. */
+    UserInfo.prototype.toJSON = function () {
+        return {
+            uid: this.uid,
+            displayName: this.displayName,
+            email: this.email,
+            photoURL: this.photoURL,
+            providerId: this.providerId,
+        };
+    };
+    return UserInfo;
+}());
+exports.UserInfo = UserInfo;
+/**
+ * User record class that defines the Firebase user object populated from
+ * the Firebase Auth getAccountInfo response.
+ *
+ * @param {Object} response The server side response returned from the getAccountInfo
+ *     endpoint.
+ * @constructor
+ */
+var UserRecord = (function () {
+    function UserRecord(response) {
+        // The Firebase user id is required.
+        if (!response.localId) {
+            throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INTERNAL_ERROR, 'INTERNAL ASSERT FAILED: Invalid user response');
+        }
+        this.uidInternal = response.localId;
+        this.emailInternal = response.email;
+        this.emailVerifiedInternal = !!response.emailVerified;
+        this.displayNameInternal = response.displayName;
+        this.photoURLInternal = response.photoUrl;
+        // If disabled is not provided, the account is enabled by default.
+        this.disabledInternal = response.disabled || false;
+        this.metadataInternal = new UserMetadata(response);
+        var providerData = response.providerUserInfo || [];
+        this.providerDataInternal = [];
+        for (var _i = 0, providerData_1 = providerData; _i < providerData_1.length; _i++) {
+            var entry = providerData_1[_i];
+            this.providerData.push(new UserInfo(entry));
+        }
+    }
+    Object.defineProperty(UserRecord.prototype, "uid", {
+        /** @return {string} The Firebase user id corresponding to the current user record. */
+        get: function () {
+            return this.uidInternal;
+        },
+        enumerable: true,
+        configurable: true
+    });
+    Object.defineProperty(UserRecord.prototype, "email", {
+        /** @return {string} The primary email corresponding to the current user record. */
+        get: function () {
+            return this.emailInternal;
+        },
+        enumerable: true,
+        configurable: true
+    });
+    Object.defineProperty(UserRecord.prototype, "emailVerified", {
+        /** @return {boolean} Whether the primary email is verified. */
+        get: function () {
+            return this.emailVerifiedInternal;
+        },
+        enumerable: true,
+        configurable: true
+    });
+    Object.defineProperty(UserRecord.prototype, "displayName", {
+        /** @return {string} The display name corresponding to the current user record. */
+        get: function () {
+            return this.displayNameInternal;
+        },
+        enumerable: true,
+        configurable: true
+    });
+    Object.defineProperty(UserRecord.prototype, "photoURL", {
+        /** @return {string} The photo URL corresponding to the current user record. */
+        get: function () {
+            return this.photoURLInternal;
+        },
+        enumerable: true,
+        configurable: true
+    });
+    Object.defineProperty(UserRecord.prototype, "disabled", {
+        /** @return {boolean} Whether the current user is disabled or not. */
+        get: function () {
+            return this.disabledInternal;
+        },
+        enumerable: true,
+        configurable: true
+    });
+    Object.defineProperty(UserRecord.prototype, "metadata", {
+        /** @return {UserMetadata} The user record's metadata. */
+        get: function () {
+            return this.metadataInternal;
+        },
+        enumerable: true,
+        configurable: true
+    });
+    Object.defineProperty(UserRecord.prototype, "providerData", {
+        /** @return {UserInfo[]} The list of providers linked to the current record. */
+        get: function () {
+            return this.providerDataInternal;
+        },
+        enumerable: true,
+        configurable: true
+    });
+    /** @return {Object} The plain object representation of the user record. */
+    UserRecord.prototype.toJSON = function () {
+        var json = {};
+        json.uid = this.uid;
+        json.email = this.email;
+        json.emailVerified = this.emailVerified;
+        json.displayName = this.displayName;
+        json.photoURL = this.photoURL;
+        json.disabled = this.disabled;
+        // Convert metadata to json.
+        json.metadata = this.metadata.toJSON();
+        json.providerData = [];
+        for (var _i = 0, _a = this.providerData; _i < _a.length; _i++) {
+            var entry = _a[_i];
+            // Convert each provider data to json.
+            json.providerData.push(entry.toJSON());
+        }
+        return json;
+    };
+    return UserRecord;
+}());
+exports.UserRecord = UserRecord;
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/database/database.js b/KEMMessaging/node_modules/firebase-admin/lib/database/database.js
new file mode 100644
index 0000000000000000000000000000000000000000..b7c7a2f98e2a81ce152a5d1f0e87ec8ea2be4de5
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/database/database.js
@@ -0,0 +1,255 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+/*! typedarray.js
+    Copyright (c) 2010, Linden Research, Inc.
+
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+    THE SOFTWARE. */
+/* Copied from firebase/firebase-client-js commit aa7be5ef965c51c86b7e13fdfa39ed12a812c29a */
+(function() {
+  var firebase = require('../default-namespace');
+  var h,aa=this;function n(a){return void 0!==a}function ba(){}function ca(a){a.Tb=function(){return a.Ve?a.Ve:a.Ve=new a}}
+function da(a){var b=typeof a;if("object"==b)if(a){if(a instanceof Array)return"array";if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if("[object Window]"==c)return"object";if("[object Array]"==c||"number"==typeof a.length&&"undefined"!=typeof a.splice&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("splice"))return"array";if("[object Function]"==c||"undefined"!=typeof a.call&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("call"))return"function"}else return"null";
+else if("function"==b&&"undefined"==typeof a.call)return"object";return b}function ea(a){return"array"==da(a)}function fa(a){var b=da(a);return"array"==b||"object"==b&&"number"==typeof a.length}function p(a){return"string"==typeof a}function ga(a){return"number"==typeof a}function ha(a){return"function"==da(a)}function ia(a){var b=typeof a;return"object"==b&&null!=a||"function"==b}function ja(a,b,c){return a.call.apply(a.bind,arguments)}
+function ka(a,b,c){if(!a)throw Error();if(2<arguments.length){var d=Array.prototype.slice.call(arguments,2);return function(){var c=Array.prototype.slice.call(arguments);Array.prototype.unshift.apply(c,d);return a.apply(b,c)}}return function(){return a.apply(b,arguments)}}function q(a,b,c){q=Function.prototype.bind&&-1!=Function.prototype.bind.toString().indexOf("native code")?ja:ka;return q.apply(null,arguments)}
+function la(a,b){function c(){}c.prototype=b.prototype;a.zg=b.prototype;a.prototype=new c;a.prototype.constructor=a;a.tg=function(a,c,f){for(var g=Array(arguments.length-2),k=2;k<arguments.length;k++)g[k-2]=arguments[k];return b.prototype[c].apply(a,g)}};function ma(){this.Va=-1};function na(){this.Va=-1;this.Va=64;this.M=[];this.Sd=[];this.zf=[];this.xd=[];this.xd[0]=128;for(var a=1;a<this.Va;++a)this.xd[a]=0;this.Md=this.Yb=0;this.reset()}la(na,ma);na.prototype.reset=function(){this.M[0]=1732584193;this.M[1]=4023233417;this.M[2]=2562383102;this.M[3]=271733878;this.M[4]=3285377520;this.Md=this.Yb=0};
+function oa(a,b,c){c||(c=0);var d=a.zf;if(p(b))for(var e=0;16>e;e++)d[e]=b.charCodeAt(c)<<24|b.charCodeAt(c+1)<<16|b.charCodeAt(c+2)<<8|b.charCodeAt(c+3),c+=4;else for(e=0;16>e;e++)d[e]=b[c]<<24|b[c+1]<<16|b[c+2]<<8|b[c+3],c+=4;for(e=16;80>e;e++){var f=d[e-3]^d[e-8]^d[e-14]^d[e-16];d[e]=(f<<1|f>>>31)&4294967295}b=a.M[0];c=a.M[1];for(var g=a.M[2],k=a.M[3],m=a.M[4],l,e=0;80>e;e++)40>e?20>e?(f=k^c&(g^k),l=1518500249):(f=c^g^k,l=1859775393):60>e?(f=c&g|k&(c|g),l=2400959708):(f=c^g^k,l=3395469782),f=(b<<
+5|b>>>27)+f+m+l+d[e]&4294967295,m=k,k=g,g=(c<<30|c>>>2)&4294967295,c=b,b=f;a.M[0]=a.M[0]+b&4294967295;a.M[1]=a.M[1]+c&4294967295;a.M[2]=a.M[2]+g&4294967295;a.M[3]=a.M[3]+k&4294967295;a.M[4]=a.M[4]+m&4294967295}
+na.prototype.update=function(a,b){if(null!=a){n(b)||(b=a.length);for(var c=b-this.Va,d=0,e=this.Sd,f=this.Yb;d<b;){if(0==f)for(;d<=c;)oa(this,a,d),d+=this.Va;if(p(a))for(;d<b;){if(e[f]=a.charCodeAt(d),++f,++d,f==this.Va){oa(this,e);f=0;break}}else for(;d<b;)if(e[f]=a[d],++f,++d,f==this.Va){oa(this,e);f=0;break}}this.Yb=f;this.Md+=b}};function pa(a){a=String(a);if(/^\s*$/.test(a)?0:/^[\],:{}\s\u2028\u2029]*$/.test(a.replace(/\\["\\\/bfnrtu]/g,"@").replace(/"[^"\\\n\r\u2028\u2029\x00-\x08\x0a-\x1f]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:[\s\u2028\u2029]*\[)+/g,"")))try{return eval("("+a+")")}catch(b){}throw Error("Invalid JSON string: "+a);}function qa(){this.Dd=void 0}
+function ra(a,b,c){switch(typeof b){case "string":sa(b,c);break;case "number":c.push(isFinite(b)&&!isNaN(b)?b:"null");break;case "boolean":c.push(b);break;case "undefined":c.push("null");break;case "object":if(null==b){c.push("null");break}if(ea(b)){var d=b.length;c.push("[");for(var e="",f=0;f<d;f++)c.push(e),e=b[f],ra(a,a.Dd?a.Dd.call(b,String(f),e):e,c),e=",";c.push("]");break}c.push("{");d="";for(f in b)Object.prototype.hasOwnProperty.call(b,f)&&(e=b[f],"function"!=typeof e&&(c.push(d),sa(f,c),
+c.push(":"),ra(a,a.Dd?a.Dd.call(b,f,e):e,c),d=","));c.push("}");break;case "function":break;default:throw Error("Unknown type: "+typeof b);}}var ta={'"':'\\"',"\\":"\\\\","/":"\\/","\b":"\\b","\f":"\\f","\n":"\\n","\r":"\\r","\t":"\\t","\x0B":"\\u000b"},ua=/\uffff/.test("\uffff")?/[\\\"\x00-\x1f\x7f-\uffff]/g:/[\\\"\x00-\x1f\x7f-\xff]/g;
+function sa(a,b){b.push('"',a.replace(ua,function(a){if(a in ta)return ta[a];var b=a.charCodeAt(0),e="\\u";16>b?e+="000":256>b?e+="00":4096>b&&(e+="0");return ta[a]=e+b.toString(16)}),'"')};function t(a,b){for(var c in a)b.call(void 0,a[c],c,a)}function va(a,b){var c={},d;for(d in a)c[d]=b.call(void 0,a[d],d,a);return c}function wa(a,b){for(var c in a)if(!b.call(void 0,a[c],c,a))return!1;return!0}function xa(a){var b=0,c;for(c in a)b++;return b}function ya(a){for(var b in a)return b}function za(a){var b=[],c=0,d;for(d in a)b[c++]=a[d];return b}function Aa(a){var b=[],c=0,d;for(d in a)b[c++]=d;return b}function Ba(a,b){for(var c in a)if(a[c]==b)return!0;return!1}
+function Ca(a,b,c){for(var d in a)if(b.call(c,a[d],d,a))return d}function Da(a,b){var c=Ca(a,b,void 0);return c&&a[c]}function Ea(a){for(var b in a)return!1;return!0}function Fa(a){var b={},c;for(c in a)b[c]=a[c];return b};var u=Array.prototype,Ga=u.indexOf?function(a,b,c){return u.indexOf.call(a,b,c)}:function(a,b,c){c=null==c?0:0>c?Math.max(0,a.length+c):c;if(p(a))return p(b)&&1==b.length?a.indexOf(b,c):-1;for(;c<a.length;c++)if(c in a&&a[c]===b)return c;return-1},Ha=u.forEach?function(a,b,c){u.forEach.call(a,b,c)}:function(a,b,c){for(var d=a.length,e=p(a)?a.split(""):a,f=0;f<d;f++)f in e&&b.call(c,e[f],f,a)},Ia=u.filter?function(a,b,c){return u.filter.call(a,b,c)}:function(a,b,c){for(var d=a.length,e=[],f=0,g=p(a)?
+a.split(""):a,k=0;k<d;k++)if(k in g){var m=g[k];b.call(c,m,k,a)&&(e[f++]=m)}return e},Ja=u.map?function(a,b,c){return u.map.call(a,b,c)}:function(a,b,c){for(var d=a.length,e=Array(d),f=p(a)?a.split(""):a,g=0;g<d;g++)g in f&&(e[g]=b.call(c,f[g],g,a));return e},Ka=u.reduce?function(a,b,c,d){for(var e=[],f=1,g=arguments.length;f<g;f++)e.push(arguments[f]);d&&(e[0]=q(b,d));return u.reduce.apply(a,e)}:function(a,b,c,d){var e=c;Ha(a,function(c,g){e=b.call(d,e,c,g,a)});return e},La=u.every?function(a,b,
+c){return u.every.call(a,b,c)}:function(a,b,c){for(var d=a.length,e=p(a)?a.split(""):a,f=0;f<d;f++)if(f in e&&!b.call(c,e[f],f,a))return!1;return!0};function Ma(a,b){var c=Na(a,b,void 0);return 0>c?null:p(a)?a.charAt(c):a[c]}function Na(a,b,c){for(var d=a.length,e=p(a)?a.split(""):a,f=0;f<d;f++)if(f in e&&b.call(c,e[f],f,a))return f;return-1}function Oa(a,b){var c=Ga(a,b);0<=c&&u.splice.call(a,c,1)}function Pa(a,b){a.sort(b||Qa)}function Qa(a,b){return a>b?1:a<b?-1:0};var v;a:{var Ra=aa.navigator;if(Ra){var Sa=Ra.userAgent;if(Sa){v=Sa;break a}}v=""};var Ta=-1!=v.indexOf("Opera")||-1!=v.indexOf("OPR"),Ua=-1!=v.indexOf("Trident")||-1!=v.indexOf("MSIE"),Va=-1!=v.indexOf("Gecko")&&-1==v.toLowerCase().indexOf("webkit")&&!(-1!=v.indexOf("Trident")||-1!=v.indexOf("MSIE")),Wa=-1!=v.toLowerCase().indexOf("webkit");
+(function(){var a="",b;if(Ta&&aa.opera)return a=aa.opera.version,ha(a)?a():a;Va?b=/rv\:([^\);]+)(\)|;)/:Ua?b=/\b(?:MSIE|rv)[: ]([^\);]+)(\)|;)/:Wa&&(b=/WebKit\/(\S+)/);b&&(a=(a=b.exec(v))?a[1]:"");return Ua&&(b=(b=aa.document)?b.documentMode:void 0,b>parseFloat(a))?String(b):a})();var Xa=null,Ya=null;
+function Za(a,b){if(!fa(a))throw Error("encodeByteArray takes an array as a parameter");if(!Xa){Xa={};Ya={};for(var c=0;65>c;c++)Xa[c]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(c),Ya[c]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.".charAt(c)}for(var c=b?Ya:Xa,d=[],e=0;e<a.length;e+=3){var f=a[e],g=e+1<a.length,k=g?a[e+1]:0,m=e+2<a.length,l=m?a[e+2]:0,r=f>>2,f=(f&3)<<4|k>>4,k=(k&15)<<2|l>>6,l=l&63;m||(l=64,g||(k=64));d.push(c[r],c[f],c[k],c[l])}return d.join("")}
+;function $a(a,b){if(!a)throw ab(b);}function ab(a){return Error("Firebase Database ("+firebase.SDK_VERSION+") INTERNAL ASSERT FAILED: "+a)};function bb(a){return"undefined"!==typeof JSON&&n(JSON.parse)?JSON.parse(a):pa(a)}function w(a){if("undefined"!==typeof JSON&&n(JSON.stringify))a=JSON.stringify(a);else{var b=[];ra(new qa,a,b);a=b.join("")}return a};function cb(a,b){return Object.prototype.hasOwnProperty.call(a,b)}function y(a,b){if(Object.prototype.hasOwnProperty.call(a,b))return a[b]}function db(a,b){for(var c in a)Object.prototype.hasOwnProperty.call(a,c)&&b(c,a[c])};var eb=firebase.Promise;function fb(){var a=this;this.reject=this.resolve=null;this.ra=new eb(function(b,c){a.resolve=b;a.reject=c})}function gb(a,b){return function(c,d){c?a.reject(c):a.resolve(d);ha(b)&&(hb(a.ra),1===b.length?b(c):b(c,d))}}function hb(a){a.then(void 0,ba)};function ib(a){for(var b=[],c=0,d=0;d<a.length;d++){var e=a.charCodeAt(d);55296<=e&&56319>=e&&(e-=55296,d++,$a(d<a.length,"Surrogate pair missing trail surrogate."),e=65536+(e<<10)+(a.charCodeAt(d)-56320));128>e?b[c++]=e:(2048>e?b[c++]=e>>6|192:(65536>e?b[c++]=e>>12|224:(b[c++]=e>>18|240,b[c++]=e>>12&63|128),b[c++]=e>>6&63|128),b[c++]=e&63|128)}return b}function jb(a){for(var b=0,c=0;c<a.length;c++){var d=a.charCodeAt(c);128>d?b++:2048>d?b+=2:55296<=d&&56319>=d?(b+=4,c++):b+=3}return b};function kb(a){var b=[];db(a,function(a,d){ea(d)?Ha(d,function(d){b.push(encodeURIComponent(a)+"="+encodeURIComponent(d))}):b.push(encodeURIComponent(a)+"="+encodeURIComponent(d))});return b.length?"&"+b.join("&"):""};function z(a,b,c,d){var e;d<b?e="at least "+b:d>c&&(e=0===c?"none":"no more than "+c);if(e)throw Error(a+" failed: Was called with "+d+(1===d?" argument.":" arguments.")+" Expects "+e+".");}function A(a,b,c){var d="";switch(b){case 1:d=c?"first":"First";break;case 2:d=c?"second":"Second";break;case 3:d=c?"third":"Third";break;case 4:d=c?"fourth":"Fourth";break;default:throw Error("errorPrefix called with argumentNumber > 4.  Need to update it?");}return a=a+" failed: "+(d+" argument ")}
+function B(a,b,c,d){if((!d||n(c))&&!ha(c))throw Error(A(a,b,d)+"must be a valid function.");}function lb(a,b,c){if(n(c)&&(!ia(c)||null===c))throw Error(A(a,b,!0)+"must be a valid context object.");};function mb(a,b){this.committed=a;this.snapshot=b};function nb(a){this.lc=a}nb.prototype.getToken=function(a){return this.lc.INTERNAL.getToken(a).then(null,function(a){return a&&"auth/token-not-initialized"===a.code?(C("Got auth/token-not-initialized error.  Treating as null token."),null):Promise.reject(a)})};function ob(a,b){a.lc.INTERNAL.addAuthTokenListener(b)};function pb(a,b){this.type=qb;this.source=a;this.path=b}pb.prototype.Jc=function(){return this.path.e()?new pb(this.source,D):new pb(this.source,E(this.path))};pb.prototype.toString=function(){return"Operation("+this.path+": "+this.source.toString()+" listen_complete)"};function rb(a,b,c){this.type=sb;this.source=a;this.path=b;this.Fa=c}rb.prototype.Jc=function(a){return this.path.e()?new rb(this.source,D,this.Fa.Q(a)):new rb(this.source,E(this.path),this.Fa)};rb.prototype.toString=function(){return"Operation("+this.path+": "+this.source.toString()+" overwrite: "+this.Fa.toString()+")"};function tb(a,b){return ub(a.name,b.name)}function vb(a,b){return ub(a,b)};function G(a,b){this.name=a;this.R=b}function wb(a,b){return new G(a,b)};function xb(){this.Hd=H}xb.prototype.j=function(a){return this.Hd.P(a)};xb.prototype.toString=function(){return this.Hd.toString()};function yb(){this.qc={}}function zb(a,b,c){n(c)||(c=1);cb(a.qc,b)||(a.qc[b]=0);a.qc[b]+=c}yb.prototype.get=function(){return Fa(this.qc)};function Ab(a){this.Df=a;this.od=null}Ab.prototype.get=function(){var a=this.Df.get(),b=Fa(a);if(this.od)for(var c in this.od)b[c]-=this.od[c];this.od=a;return b};function Bb(a){this.rc=a;this.Ad="firebase:"}h=Bb.prototype;h.set=function(a,b){null==b?this.rc.removeItem(this.Ad+a):this.rc.setItem(this.Ad+a,w(b))};h.get=function(a){a=this.rc.getItem(this.Ad+a);return null==a?null:bb(a)};h.remove=function(a){this.rc.removeItem(this.Ad+a)};h.We=!1;h.toString=function(){return this.rc.toString()};function Cb(){this.mc={}}Cb.prototype.set=function(a,b){null==b?delete this.mc[a]:this.mc[a]=b};Cb.prototype.get=function(a){return cb(this.mc,a)?this.mc[a]:null};Cb.prototype.remove=function(a){delete this.mc[a]};Cb.prototype.We=!0;function Db(a){try{if("undefined"!==typeof window&&"undefined"!==typeof window[a]){var b=window[a];b.setItem("firebase:sentinel","cache");b.removeItem("firebase:sentinel");return new Bb(b)}}catch(c){}return new Cb}var Eb=Db("localStorage"),Fb=Db("sessionStorage");function Gb(a,b,c,d,e){this.host=a.toLowerCase();this.domain=this.host.substr(this.host.indexOf(".")+1);this.Pc=b;this.me=c;this.rg=d;this.ef=e||"";this.Za=Eb.get("host:"+a)||this.host}function Hb(a,b){b!==a.Za&&(a.Za=b,"s-"===a.Za.substr(0,2)&&Eb.set("host:"+a.host,a.Za))}
+function Ib(a,b,c){I("string"===typeof b,"typeof type must == string");I("object"===typeof c,"typeof params must == object");if(b===Jb)b=(a.Pc?"wss://":"ws://")+a.Za+"/.ws?";else if(b===Kb)b=(a.Pc?"https://":"http://")+a.Za+"/.lp?";else throw Error("Unknown connection type: "+b);a.host!==a.Za&&(c.ns=a.me);var d=[];t(c,function(a,b){d.push(b+"="+a)});return b+d.join("&")}Gb.prototype.toString=function(){var a=(this.Pc?"https://":"http://")+this.host;this.ef&&(a+="<"+this.ef+">");return a};(function(){var a=process.version;if("v0.10.22"===a||"v0.10.23"===a||"v0.10.24"===a){var b=function(a,b,c){this.chunk=a;this.encoding=b;this.callback=c},c=function(a,c,d,e,l){c.objectMode||!1===c.decodeStrings||"string"!==typeof d||(d=new Buffer(d,e));Buffer.isBuffer(d)&&(e="buffer");var r=c.objectMode?1:d.length;c.length+=r;var x=c.length<c.highWaterMark;x||(c.needDrain=!0);c.writing?c.buffer.push(new b(d,e,l)):(c.writelen=r,c.writecb=l,c.writing=!0,c.sync=!0,a._write(d,e,c.onwrite),c.sync=!1);return x},
+d=function(a,b,c,d){var e=!0;if(!Buffer.isBuffer(c)&&"string"!==typeof c&&null!==c&&void 0!==c&&!b.objectMode){var r=new TypeError("Invalid non-string/buffer chunk");a.emit("error",r);process.nextTick(function(){d(r)});e=!1}return e},e=function(a,b){var c=Error("write after end");a.emit("error",c);process.nextTick(function(){b(c)})},a=require("_stream_writable");a.prototype.write=function(a,b,k){var m=this._writableState,l=!1;"function"===typeof b&&(k=b,b=null);Buffer.isBuffer(a)?b="buffer":b||(b=
+m.defaultEncoding);"function"!==typeof k&&(k=function(){});m.ended?e(this,k):d(this,m,a,k)&&(l=c(this,m,a,b,k));return l};require("_stream_duplex").prototype.write=a.prototype.write}})();function Lb(a,b){return a&&"object"===typeof a?(I(".sv"in a,"Unexpected leaf node or priority contents"),b[a[".sv"]]):a}function Mb(a,b){var c=new Nb;Ob(a,new J(""),function(a,e){Pb(c,a,Qb(e,b))});return c}function Qb(a,b){var c=a.C().H(),c=Lb(c,b),d;if(a.J()){var e=Lb(a.Ca(),b);return e!==a.Ca()||c!==a.C().H()?new Rb(e,K(c)):a}d=a;c!==a.C().H()&&(d=d.fa(new Rb(c)));a.O(L,function(a,c){var e=Qb(c,b);e!==c&&(d=d.T(a,e))});return d};function Sb(a,b){this.Ka=a;this.ba=b?b:Tb}h=Sb.prototype;h.Na=function(a,b){return new Sb(this.Ka,this.ba.Na(a,b,this.Ka).X(null,null,!1,null,null))};h.remove=function(a){return new Sb(this.Ka,this.ba.remove(a,this.Ka).X(null,null,!1,null,null))};h.get=function(a){for(var b,c=this.ba;!c.e();){b=this.Ka(a,c.key);if(0===b)return c.value;0>b?c=c.left:0<b&&(c=c.right)}return null};
+function Ub(a,b){for(var c,d=a.ba,e=null;!d.e();){c=a.Ka(b,d.key);if(0===c){if(d.left.e())return e?e.key:null;for(d=d.left;!d.right.e();)d=d.right;return d.key}0>c?d=d.left:0<c&&(e=d,d=d.right)}throw Error("Attempted to find predecessor key for a nonexistent key.  What gives?");}h.e=function(){return this.ba.e()};h.count=function(){return this.ba.count()};h.Dc=function(){return this.ba.Dc()};h.cc=function(){return this.ba.cc()};h.ha=function(a){return this.ba.ha(a)};
+h.Ub=function(a){return new Vb(this.ba,null,this.Ka,!1,a)};h.Vb=function(a,b){return new Vb(this.ba,a,this.Ka,!1,b)};h.Xb=function(a,b){return new Vb(this.ba,a,this.Ka,!0,b)};h.Te=function(a){return new Vb(this.ba,null,this.Ka,!0,a)};function Vb(a,b,c,d,e){this.Fd=e||null;this.he=d;this.Oa=[];for(e=1;!a.e();)if(e=b?c(a.key,b):1,d&&(e*=-1),0>e)a=this.he?a.left:a.right;else if(0===e){this.Oa.push(a);break}else this.Oa.push(a),a=this.he?a.right:a.left}
+function M(a){if(0===a.Oa.length)return null;var b=a.Oa.pop(),c;c=a.Fd?a.Fd(b.key,b.value):{key:b.key,value:b.value};if(a.he)for(b=b.left;!b.e();)a.Oa.push(b),b=b.right;else for(b=b.right;!b.e();)a.Oa.push(b),b=b.left;return c}function Wb(a){if(0===a.Oa.length)return null;var b;b=a.Oa;b=b[b.length-1];return a.Fd?a.Fd(b.key,b.value):{key:b.key,value:b.value}}function Xb(a,b,c,d,e){this.key=a;this.value=b;this.color=null!=c?c:!0;this.left=null!=d?d:Tb;this.right=null!=e?e:Tb}h=Xb.prototype;
+h.X=function(a,b,c,d,e){return new Xb(null!=a?a:this.key,null!=b?b:this.value,null!=c?c:this.color,null!=d?d:this.left,null!=e?e:this.right)};h.count=function(){return this.left.count()+1+this.right.count()};h.e=function(){return!1};h.ha=function(a){return this.left.ha(a)||a(this.key,this.value)||this.right.ha(a)};function Yb(a){return a.left.e()?a:Yb(a.left)}h.Dc=function(){return Yb(this).key};h.cc=function(){return this.right.e()?this.key:this.right.cc()};
+h.Na=function(a,b,c){var d,e;e=this;d=c(a,e.key);e=0>d?e.X(null,null,null,e.left.Na(a,b,c),null):0===d?e.X(null,b,null,null,null):e.X(null,null,null,null,e.right.Na(a,b,c));return Zb(e)};function $b(a){if(a.left.e())return Tb;a.left.ea()||a.left.left.ea()||(a=ac(a));a=a.X(null,null,null,$b(a.left),null);return Zb(a)}
+h.remove=function(a,b){var c,d;c=this;if(0>b(a,c.key))c.left.e()||c.left.ea()||c.left.left.ea()||(c=ac(c)),c=c.X(null,null,null,c.left.remove(a,b),null);else{c.left.ea()&&(c=bc(c));c.right.e()||c.right.ea()||c.right.left.ea()||(c=cc(c),c.left.left.ea()&&(c=bc(c),c=cc(c)));if(0===b(a,c.key)){if(c.right.e())return Tb;d=Yb(c.right);c=c.X(d.key,d.value,null,null,$b(c.right))}c=c.X(null,null,null,null,c.right.remove(a,b))}return Zb(c)};h.ea=function(){return this.color};
+function Zb(a){a.right.ea()&&!a.left.ea()&&(a=dc(a));a.left.ea()&&a.left.left.ea()&&(a=bc(a));a.left.ea()&&a.right.ea()&&(a=cc(a));return a}function ac(a){a=cc(a);a.right.left.ea()&&(a=a.X(null,null,null,null,bc(a.right)),a=dc(a),a=cc(a));return a}function dc(a){return a.right.X(null,null,a.color,a.X(null,null,!0,null,a.right.left),null)}function bc(a){return a.left.X(null,null,a.color,null,a.X(null,null,!0,a.left.right,null))}
+function cc(a){return a.X(null,null,!a.color,a.left.X(null,null,!a.left.color,null,null),a.right.X(null,null,!a.right.color,null,null))}function ec(){}h=ec.prototype;h.X=function(){return this};h.Na=function(a,b){return new Xb(a,b,null)};h.remove=function(){return this};h.count=function(){return 0};h.e=function(){return!0};h.ha=function(){return!1};h.Dc=function(){return null};h.cc=function(){return null};h.ea=function(){return!1};var Tb=new ec;var fc=function(){var a=1;return function(){return a++}}(),I=$a,gc=ab;function hc(a){try{return(new Buffer(a,"base64")).toString("utf8")}catch(b){C("base64Decode failed: ",b)}return null}function ic(a){var b=ib(a);a=new na;a.update(b);var b=[],c=8*a.Md;56>a.Yb?a.update(a.xd,56-a.Yb):a.update(a.xd,a.Va-(a.Yb-56));for(var d=a.Va-1;56<=d;d--)a.Sd[d]=c&255,c/=256;oa(a,a.Sd);for(d=c=0;5>d;d++)for(var e=24;0<=e;e-=8)b[c]=a.M[d]>>e&255,++c;return Za(b)}
+function jc(a){for(var b="",c=0;c<arguments.length;c++)b=fa(arguments[c])?b+jc.apply(null,arguments[c]):"object"===typeof arguments[c]?b+w(arguments[c]):b+arguments[c],b+=" ";return b}var kc=null,lc=!0;
+function mc(a,b){$a(!b||!0===a||!1===a,"Can't turn on custom loggers persistently.");!0===a?("undefined"!==typeof console&&("function"===typeof console.log?kc=q(console.log,console):"object"===typeof console.log&&(kc=function(a){console.log(a)})),b&&Fb.set("logging_enabled",!0)):ha(a)?kc=a:(kc=null,Fb.remove("logging_enabled"))}function C(a){!0===lc&&(lc=!1,null===kc&&!0===Fb.get("logging_enabled")&&mc(!0));if(kc){var b=jc.apply(null,arguments);kc(b)}}
+function nc(a){return function(){C(a,arguments)}}function oc(a){if("undefined"!==typeof console){var b="FIREBASE INTERNAL ERROR: "+jc.apply(null,arguments);"undefined"!==typeof console.error?console.error(b):console.log(b)}}function pc(a){var b=jc.apply(null,arguments);throw Error("FIREBASE FATAL ERROR: "+b);}function N(a){if("undefined"!==typeof console){var b="FIREBASE WARNING: "+jc.apply(null,arguments);"undefined"!==typeof console.warn?console.warn(b):console.log(b)}}
+function qc(a){var b,c,d,e,f,g=a;f=c=a=b="";d=!0;e="https";if(p(g)){var k=g.indexOf("//");0<=k&&(e=g.substring(0,k-1),g=g.substring(k+2));k=g.indexOf("/");-1===k&&(k=g.length);b=g.substring(0,k);f="";g=g.substring(k).split("/");for(k=0;k<g.length;k++)if(0<g[k].length){var m=g[k];try{m=decodeURIComponent(m.replace(/\+/g," "))}catch(l){}f+="/"+m}g=b.split(".");3===g.length?(a=g[1],c=g[0].toLowerCase()):2===g.length&&(a=g[0]);k=b.indexOf(":");0<=k&&(d="https"===e||"wss"===e)}"firebase"===a&&pc(b+" is no longer supported. Please use <YOUR FIREBASE>.firebaseio.com instead");
+c&&"undefined"!=c||pc("Cannot parse Firebase url. Please use https://<YOUR FIREBASE>.firebaseio.com");d||"undefined"!==typeof window&&window.location&&window.location.protocol&&-1!==window.location.protocol.indexOf("https:")&&N("Insecure Firebase access from a secure page. Please use https in calls to new Firebase().");return{gc:new Gb(b,d,c,"ws"===e||"wss"===e),path:new J(f)}}function rc(a){return ga(a)&&(a!=a||a==Number.POSITIVE_INFINITY||a==Number.NEGATIVE_INFINITY)}function sc(a){a()}
+function ub(a,b){if(a===b)return 0;if("[MIN_NAME]"===a||"[MAX_NAME]"===b)return-1;if("[MIN_NAME]"===b||"[MAX_NAME]"===a)return 1;var c=tc(a),d=tc(b);return null!==c?null!==d?0==c-d?a.length-b.length:c-d:-1:null!==d?1:a<b?-1:1}function uc(a,b){if(b&&a in b)return b[a];throw Error("Missing required key ("+a+") in object: "+w(b));}
+function vc(a){if("object"!==typeof a||null===a)return w(a);var b=[],c;for(c in a)b.push(c);b.sort();c="{";for(var d=0;d<b.length;d++)0!==d&&(c+=","),c+=w(b[d]),c+=":",c+=vc(a[b[d]]);return c+"}"}function wc(a,b){if(a.length<=b)return[a];for(var c=[],d=0;d<a.length;d+=b)d+b>a?c.push(a.substring(d,a.length)):c.push(a.substring(d,d+b));return c}function xc(a,b){if(ea(a))for(var c=0;c<a.length;++c)b(c,a[c]);else t(a,b)}
+function yc(a){I(!rc(a),"Invalid JSON number");var b,c,d,e;0===a?(d=c=0,b=-Infinity===1/a?1:0):(b=0>a,a=Math.abs(a),a>=Math.pow(2,-1022)?(d=Math.min(Math.floor(Math.log(a)/Math.LN2),1023),c=d+1023,d=Math.round(a*Math.pow(2,52-d)-Math.pow(2,52))):(c=0,d=Math.round(a/Math.pow(2,-1074))));e=[];for(a=52;a;--a)e.push(d%2?1:0),d=Math.floor(d/2);for(a=11;a;--a)e.push(c%2?1:0),c=Math.floor(c/2);e.push(b?1:0);e.reverse();b=e.join("");c="";for(a=0;64>a;a+=8)d=parseInt(b.substr(a,8),2).toString(16),1===d.length&&
+(d="0"+d),c+=d;return c.toLowerCase()}var zc=/^-?\d{1,10}$/;function tc(a){return zc.test(a)&&(a=Number(a),-2147483648<=a&&2147483647>=a)?a:null}function Ac(a){try{a()}catch(b){setTimeout(function(){N("Exception was thrown by user callback.",b.stack||"");throw b;},Math.floor(0))}}function Bc(a,b,c){Object.defineProperty(a,b,{get:c})}function Cc(a,b){var c=setTimeout(a,b);"object"===typeof c&&c.unref&&c.unref();return c};function Dc(a){var b={},c={},d={},e="";try{var f=a.split("."),b=bb(hc(f[0])||""),c=bb(hc(f[1])||""),e=f[2],d=c.d||{};delete c.d}catch(g){}return{wg:b,Ge:c,data:d,mg:e}}function Ec(a){a=Dc(a);var b=a.Ge;return!!a.mg&&!!b&&"object"===typeof b&&b.hasOwnProperty("iat")}function Fc(a){a=Dc(a).Ge;return"object"===typeof a&&!0===y(a,"admin")};function Gc(a,b,c){this.type=Hc;this.source=a;this.path=b;this.children=c}Gc.prototype.Jc=function(a){if(this.path.e())return a=this.children.subtree(new J(a)),a.e()?null:a.value?new rb(this.source,D,a.value):new Gc(this.source,D,a);I(O(this.path)===a,"Can't get a merge for a child not on the path of the operation");return new Gc(this.source,E(this.path),this.children)};Gc.prototype.toString=function(){return"Operation("+this.path+": "+this.source.toString()+" merge: "+this.children.toString()+")"};function Ic(a,b,c){this.f=nc("p:rest:");this.L=a;this.Eb=b;this.Xc=c;this.$={}}function Jc(a,b){if(n(b))return"tag$"+b;I(Kc(a.m),"should have a tag if it's not a default query.");return a.path.toString()}h=Ic.prototype;
+h.Xe=function(a,b,c,d){var e=a.path.toString();this.f("Listen called for "+e+" "+a.ja());var f=Jc(a,c),g={};this.$[f]=g;a=Lc(a.m);var k=this;Mc(this,e+".json",a,function(a,b){var r=b;404===a&&(a=r=null);null===a&&k.Eb(e,r,!1,c);y(k.$,f)===g&&d(a?401==a?"permission_denied":"rest_error:"+a:"ok",null)})};h.tf=function(a,b){var c=Jc(a,b);delete this.$[c]};h.hf=function(){};h.oe=function(){};h.bf=function(){};h.vd=function(){};h.put=function(){};h.Ye=function(){};h.ve=function(){};
+function Mc(a,b,c,d){c=c||{};c.format="export";a.Xc.getToken(!1).then(function(e){(e=e&&e.accessToken)&&(c.auth=e);var f=(a.L.Pc?"https://":"http://")+a.L.host+b+"?"+kb(c);a.f("Sending REST request for "+f);var g=new XMLHttpRequest;g.onreadystatechange=function(){if(d&&4===g.readyState){a.f("REST Response for "+f+" received. status:",g.status,"response:",g.responseText);var b=null;if(200<=g.status&&300>g.status){try{b=bb(g.responseText)}catch(c){N("Failed to parse JSON response for "+f+": "+g.responseText)}d(null,
+b)}else 401!==g.status&&404!==g.status&&N("Got unsuccessful REST response for "+f+" Status: "+g.status),d(g.status);d=null}};g.open("GET",f,!0);g.send()})};function Nc(){}var Oc={};function Pc(a){return q(a.compare,a)}Nc.prototype.kd=function(a,b){return 0!==this.compare(new G("[MIN_NAME]",a),new G("[MIN_NAME]",b))};Nc.prototype.Ec=function(){return Qc};function Rc(a){I(!a.e()&&".priority"!==O(a),"Can't create PathIndex with empty path or .priority key");this.$b=a}la(Rc,Nc);h=Rc.prototype;h.uc=function(a){return!a.P(this.$b).e()};h.compare=function(a,b){var c=a.R.P(this.$b),d=b.R.P(this.$b),c=c.pc(d);return 0===c?ub(a.name,b.name):c};
+h.Bc=function(a,b){var c=K(a),c=H.F(this.$b,c);return new G(b,c)};h.Cc=function(){var a=H.F(this.$b,Sc);return new G("[MAX_NAME]",a)};h.toString=function(){return this.$b.slice().join("/")};function Tc(){}la(Tc,Nc);h=Tc.prototype;h.compare=function(a,b){var c=a.R.C(),d=b.R.C(),c=c.pc(d);return 0===c?ub(a.name,b.name):c};h.uc=function(a){return!a.C().e()};h.kd=function(a,b){return!a.C().Z(b.C())};h.Ec=function(){return Qc};h.Cc=function(){return new G("[MAX_NAME]",new Rb("[PRIORITY-POST]",Sc))};
+h.Bc=function(a,b){var c=K(a);return new G(b,new Rb("[PRIORITY-POST]",c))};h.toString=function(){return".priority"};var L=new Tc;function Uc(){}la(Uc,Nc);h=Uc.prototype;h.compare=function(a,b){return ub(a.name,b.name)};h.uc=function(){throw gc("KeyIndex.isDefinedOn not expected to be called.");};h.kd=function(){return!1};h.Ec=function(){return Qc};h.Cc=function(){return new G("[MAX_NAME]",H)};h.Bc=function(a){I(p(a),"KeyIndex indexValue must always be a string.");return new G(a,H)};h.toString=function(){return".key"};
+var Vc=new Uc;function Wc(){}la(Wc,Nc);h=Wc.prototype;h.compare=function(a,b){var c=a.R.pc(b.R);return 0===c?ub(a.name,b.name):c};h.uc=function(){return!0};h.kd=function(a,b){return!a.Z(b)};h.Ec=function(){return Qc};h.Cc=function(){return Xc};h.Bc=function(a,b){var c=K(a);return new G(b,c)};h.toString=function(){return".value"};var Yc=new Wc;function Zc(a,b){this.ld=a;this.ac=b}Zc.prototype.get=function(a){var b=y(this.ld,a);if(!b)throw Error("No index defined for "+a);return b===Oc?null:b};function ad(a,b,c){var d=va(a.ld,function(d,f){var g=y(a.ac,f);I(g,"Missing index implementation for "+f);if(d===Oc){if(g.uc(b.R)){for(var k=[],m=c.Ub(wb),l=M(m);l;)l.name!=b.name&&k.push(l),l=M(m);k.push(b);return bd(k,Pc(g))}return Oc}g=c.get(b.name);k=d;g&&(k=k.remove(new G(b.name,g)));return k.Na(b,b.R)});return new Zc(d,a.ac)}
+function cd(a,b,c){var d=va(a.ld,function(a){if(a===Oc)return a;var d=c.get(b.name);return d?a.remove(new G(b.name,d)):a});return new Zc(d,a.ac)}var dd=new Zc({".priority":Oc},{".priority":L});function Rb(a,b){this.B=a;I(n(this.B)&&null!==this.B,"LeafNode shouldn't be created with null/undefined value.");this.aa=b||H;ed(this.aa);this.Bb=null}var fd=["object","boolean","number","string"];h=Rb.prototype;h.J=function(){return!0};h.C=function(){return this.aa};h.fa=function(a){return new Rb(this.B,a)};h.Q=function(a){return".priority"===a?this.aa:H};h.P=function(a){return a.e()?this:".priority"===O(a)?this.aa:H};h.Da=function(){return!1};h.Se=function(){return null};
+h.T=function(a,b){return".priority"===a?this.fa(b):b.e()&&".priority"!==a?this:H.T(a,b).fa(this.aa)};h.F=function(a,b){var c=O(a);if(null===c)return b;if(b.e()&&".priority"!==c)return this;I(".priority"!==c||1===gd(a),".priority must be the last token in a path");return this.T(c,H.F(E(a),b))};h.e=function(){return!1};h.Cb=function(){return 0};h.O=function(){return!1};h.H=function(a){return a&&!this.C().e()?{".value":this.Ca(),".priority":this.C().H()}:this.Ca()};
+h.hash=function(){if(null===this.Bb){var a="";this.aa.e()||(a+="priority:"+hd(this.aa.H())+":");var b=typeof this.B,a=a+(b+":"),a="number"===b?a+yc(this.B):a+this.B;this.Bb=ic(a)}return this.Bb};h.Ca=function(){return this.B};h.pc=function(a){if(a===H)return 1;if(a instanceof P)return-1;I(a.J(),"Unknown node type");var b=typeof a.B,c=typeof this.B,d=Ga(fd,b),e=Ga(fd,c);I(0<=d,"Unknown leaf type: "+b);I(0<=e,"Unknown leaf type: "+c);return d===e?"object"===c?0:this.B<a.B?-1:this.B===a.B?0:1:e-d};
+h.lb=function(){return this};h.vc=function(){return!0};h.Z=function(a){return a===this?!0:a.J()?this.B===a.B&&this.aa.Z(a.aa):!1};h.toString=function(){return w(this.H(!0))};function P(a,b,c){this.k=a;(this.aa=b)&&ed(this.aa);a.e()&&I(!this.aa||this.aa.e(),"An empty node cannot have a priority");this.wb=c;this.Bb=null}h=P.prototype;h.J=function(){return!1};h.C=function(){return this.aa||H};h.fa=function(a){return this.k.e()?this:new P(this.k,a,this.wb)};h.Q=function(a){if(".priority"===a)return this.C();a=this.k.get(a);return null===a?H:a};h.P=function(a){var b=O(a);return null===b?this:this.Q(b).P(E(a))};h.Da=function(a){return null!==this.k.get(a)};
+h.T=function(a,b){I(b,"We should always be passing snapshot nodes");if(".priority"===a)return this.fa(b);var c=new G(a,b),d,e;b.e()?(d=this.k.remove(a),c=cd(this.wb,c,this.k)):(d=this.k.Na(a,b),c=ad(this.wb,c,this.k));e=d.e()?H:this.aa;return new P(d,e,c)};h.F=function(a,b){var c=O(a);if(null===c)return b;I(".priority"!==O(a)||1===gd(a),".priority must be the last token in a path");var d=this.Q(c).F(E(a),b);return this.T(c,d)};h.e=function(){return this.k.e()};h.Cb=function(){return this.k.count()};
+var id=/^(0|[1-9]\d*)$/;h=P.prototype;h.H=function(a){if(this.e())return null;var b={},c=0,d=0,e=!0;this.O(L,function(f,g){b[f]=g.H(a);c++;e&&id.test(f)?d=Math.max(d,Number(f)):e=!1});if(!a&&e&&d<2*c){var f=[],g;for(g in b)f[g]=b[g];return f}a&&!this.C().e()&&(b[".priority"]=this.C().H());return b};h.hash=function(){if(null===this.Bb){var a="";this.C().e()||(a+="priority:"+hd(this.C().H())+":");this.O(L,function(b,c){var d=c.hash();""!==d&&(a+=":"+b+":"+d)});this.Bb=""===a?"":ic(a)}return this.Bb};
+h.Se=function(a,b,c){return(c=jd(this,c))?(a=Ub(c,new G(a,b)))?a.name:null:Ub(this.k,a)};function kd(a,b){var c;c=(c=jd(a,b))?(c=c.Dc())&&c.name:a.k.Dc();return c?new G(c,a.k.get(c)):null}function ld(a,b){var c;c=(c=jd(a,b))?(c=c.cc())&&c.name:a.k.cc();return c?new G(c,a.k.get(c)):null}h.O=function(a,b){var c=jd(this,a);return c?c.ha(function(a){return b(a.name,a.R)}):this.k.ha(b)};h.Ub=function(a){return this.Vb(a.Ec(),a)};
+h.Vb=function(a,b){var c=jd(this,b);if(c)return c.Vb(a,function(a){return a});for(var c=this.k.Vb(a.name,wb),d=Wb(c);null!=d&&0>b.compare(d,a);)M(c),d=Wb(c);return c};h.Te=function(a){return this.Xb(a.Cc(),a)};h.Xb=function(a,b){var c=jd(this,b);if(c)return c.Xb(a,function(a){return a});for(var c=this.k.Xb(a.name,wb),d=Wb(c);null!=d&&0<b.compare(d,a);)M(c),d=Wb(c);return c};h.pc=function(a){return this.e()?a.e()?0:-1:a.J()||a.e()?1:a===Sc?-1:0};
+h.lb=function(a){if(a===Vc||Ba(this.wb.ac,a.toString()))return this;var b=this.wb,c=this.k;I(a!==Vc,"KeyIndex always exists and isn't meant to be added to the IndexMap.");for(var d=[],e=!1,c=c.Ub(wb),f=M(c);f;)e=e||a.uc(f.R),d.push(f),f=M(c);d=e?bd(d,Pc(a)):Oc;e=a.toString();c=Fa(b.ac);c[e]=a;a=Fa(b.ld);a[e]=d;return new P(this.k,this.aa,new Zc(a,c))};h.vc=function(a){return a===Vc||Ba(this.wb.ac,a.toString())};
+h.Z=function(a){if(a===this)return!0;if(a.J())return!1;if(this.C().Z(a.C())&&this.k.count()===a.k.count()){var b=this.Ub(L);a=a.Ub(L);for(var c=M(b),d=M(a);c&&d;){if(c.name!==d.name||!c.R.Z(d.R))return!1;c=M(b);d=M(a)}return null===c&&null===d}return!1};function jd(a,b){return b===Vc?null:a.wb.get(b.toString())}h.toString=function(){return w(this.H(!0))};function K(a,b){if(null===a)return H;var c=null;"object"===typeof a&&".priority"in a?c=a[".priority"]:"undefined"!==typeof b&&(c=b);I(null===c||"string"===typeof c||"number"===typeof c||"object"===typeof c&&".sv"in c,"Invalid priority type found: "+typeof c);"object"===typeof a&&".value"in a&&null!==a[".value"]&&(a=a[".value"]);if("object"!==typeof a||".sv"in a)return new Rb(a,K(c));if(a instanceof Array){var d=H,e=a;t(e,function(a,b){if(cb(e,b)&&"."!==b.substring(0,1)){var c=K(a);if(c.J()||!c.e())d=
+d.T(b,c)}});return d.fa(K(c))}var f=[],g=!1,k=a;db(k,function(a){if("string"!==typeof a||"."!==a.substring(0,1)){var b=K(k[a]);b.e()||(g=g||!b.C().e(),f.push(new G(a,b)))}});if(0==f.length)return H;var m=bd(f,tb,function(a){return a.name},vb);if(g){var l=bd(f,Pc(L));return new P(m,K(c),new Zc({".priority":l},{".priority":L}))}return new P(m,K(c),dd)}var md=Math.log(2);
+function nd(a){this.count=parseInt(Math.log(a+1)/md,10);this.Ke=this.count-1;this.Bf=a+1&parseInt(Array(this.count+1).join("1"),2)}function od(a){var b=!(a.Bf&1<<a.Ke);a.Ke--;return b}
+function bd(a,b,c,d){function e(b,d){var f=d-b;if(0==f)return null;if(1==f){var l=a[b],r=c?c(l):l;return new Xb(r,l.R,!1,null,null)}var l=parseInt(f/2,10)+b,f=e(b,l),x=e(l+1,d),l=a[l],r=c?c(l):l;return new Xb(r,l.R,!1,f,x)}a.sort(b);var f=function(b){function d(b,g){var k=r-b,x=r;r-=b;var x=e(k+1,x),k=a[k],F=c?c(k):k,x=new Xb(F,k.R,g,null,x);f?f.left=x:l=x;f=x}for(var f=null,l=null,r=a.length,x=0;x<b.count;++x){var F=od(b),$c=Math.pow(2,b.count-(x+1));F?d($c,!1):(d($c,!1),d($c,!0))}return l}(new nd(a.length));
+return null!==f?new Sb(d||b,f):new Sb(d||b)}function hd(a){return"number"===typeof a?"number:"+yc(a):"string:"+a}function ed(a){if(a.J()){var b=a.H();I("string"===typeof b||"number"===typeof b||"object"===typeof b&&cb(b,".sv"),"Priority must be a string or number.")}else I(a===Sc||a.e(),"priority of unexpected type.");I(a===Sc||a.C().e(),"Priority nodes can't have a priority of their own.")}var H=new P(new Sb(vb),null,dd);function pd(){P.call(this,new Sb(vb),H,dd)}la(pd,P);h=pd.prototype;
+h.pc=function(a){return a===this?0:1};h.Z=function(a){return a===this};h.C=function(){return this};h.Q=function(){return H};h.e=function(){return!1};var Sc=new pd,Qc=new G("[MIN_NAME]",H),Xc=new G("[MAX_NAME]",Sc);function qd(a,b){this.qf={};this.Sc=new Ab(a);this.va=b;var c=1E4+2E4*Math.random();Cc(q(this.jf,this),Math.floor(c))}qd.prototype.jf=function(){var a=this.Sc.get(),b={},c=!1,d;for(d in a)0<a[d]&&cb(this.qf,d)&&(b[d]=a[d],c=!0);c&&this.va.ve(b);Cc(q(this.jf,this),Math.floor(6E5*Math.random()))};var rd={},sd={};function td(a){a=a.toString();rd[a]||(rd[a]=new yb);return rd[a]}function ud(a,b){var c=a.toString();sd[c]||(sd[c]=b());return sd[c]};function vd(){this.set={}}h=vd.prototype;h.add=function(a,b){this.set[a]=null!==b?b:!0};h.contains=function(a){return cb(this.set,a)};h.get=function(a){return this.contains(a)?this.set[a]:void 0};h.remove=function(a){delete this.set[a]};h.clear=function(){this.set={}};h.e=function(){return Ea(this.set)};h.count=function(){return xa(this.set)};function wd(a,b){t(a.set,function(a,d){b(d,a)})}h.keys=function(){var a=[];t(this.set,function(b,c){a.push(c)});return a};function xd(a){I(ea(a)&&0<a.length,"Requires a non-empty array");this.Af=a;this.Ac={}}xd.prototype.De=function(a,b){var c;c=this.Ac[a]||[];var d=c.length;if(0<d){for(var e=Array(d),f=0;f<d;f++)e[f]=c[f];c=e}else c=[];for(d=0;d<c.length;d++)c[d].Fe.apply(c[d].La,Array.prototype.slice.call(arguments,1))};xd.prototype.dc=function(a,b,c){yd(this,a);this.Ac[a]=this.Ac[a]||[];this.Ac[a].push({Fe:b,La:c});(a=this.Re(a))&&b.apply(c,a)};
+xd.prototype.Fc=function(a,b,c){yd(this,a);a=this.Ac[a]||[];for(var d=0;d<a.length;d++)if(a[d].Fe===b&&(!c||c===a[d].La)){a.splice(d,1);break}};function yd(a,b){I(Ma(a.Af,function(a){return a===b}),"Unknown event: "+b)};var zd=function(){var a=0,b=[];return function(c){var d=c===a;a=c;for(var e=Array(8),f=7;0<=f;f--)e[f]="-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz".charAt(c%64),c=Math.floor(c/64);I(0===c,"Cannot push at time == 0");c=e.join("");if(d){for(f=11;0<=f&&63===b[f];f--)b[f]=0;b[f]++}else for(f=0;12>f;f++)b[f]=Math.floor(64*Math.random());for(f=0;12>f;f++)c+="-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz".charAt(b[f]);I(20===c.length,"nextPushId: Length should be 20.");
+return c}}();function J(a,b){if(1==arguments.length){this.o=a.split("/");for(var c=0,d=0;d<this.o.length;d++)0<this.o[d].length&&(this.o[c]=this.o[d],c++);this.o.length=c;this.Y=0}else this.o=a,this.Y=b}function Q(a,b){var c=O(a);if(null===c)return b;if(c===O(b))return Q(E(a),E(b));throw Error("INTERNAL ERROR: innerPath ("+b+") is not within outerPath ("+a+")");}
+function Ad(a,b){for(var c=a.slice(),d=b.slice(),e=0;e<c.length&&e<d.length;e++){var f=ub(c[e],d[e]);if(0!==f)return f}return c.length===d.length?0:c.length<d.length?-1:1}function O(a){return a.Y>=a.o.length?null:a.o[a.Y]}function gd(a){return a.o.length-a.Y}function E(a){var b=a.Y;b<a.o.length&&b++;return new J(a.o,b)}function Bd(a){return a.Y<a.o.length?a.o[a.o.length-1]:null}h=J.prototype;
+h.toString=function(){for(var a="",b=this.Y;b<this.o.length;b++)""!==this.o[b]&&(a+="/"+this.o[b]);return a||"/"};h.slice=function(a){return this.o.slice(this.Y+(a||0))};h.parent=function(){if(this.Y>=this.o.length)return null;for(var a=[],b=this.Y;b<this.o.length-1;b++)a.push(this.o[b]);return new J(a,0)};
+h.n=function(a){for(var b=[],c=this.Y;c<this.o.length;c++)b.push(this.o[c]);if(a instanceof J)for(c=a.Y;c<a.o.length;c++)b.push(a.o[c]);else for(a=a.split("/"),c=0;c<a.length;c++)0<a[c].length&&b.push(a[c]);return new J(b,0)};h.e=function(){return this.Y>=this.o.length};h.Z=function(a){if(gd(this)!==gd(a))return!1;for(var b=this.Y,c=a.Y;b<=this.o.length;b++,c++)if(this.o[b]!==a.o[c])return!1;return!0};
+h.contains=function(a){var b=this.Y,c=a.Y;if(gd(this)>gd(a))return!1;for(;b<this.o.length;){if(this.o[b]!==a.o[c])return!1;++b;++c}return!0};var D=new J("");function Cd(a,b){this.Pa=a.slice();this.Ga=Math.max(1,this.Pa.length);this.Me=b;for(var c=0;c<this.Pa.length;c++)this.Ga+=jb(this.Pa[c]);Dd(this)}Cd.prototype.push=function(a){0<this.Pa.length&&(this.Ga+=1);this.Pa.push(a);this.Ga+=jb(a);Dd(this)};Cd.prototype.pop=function(){var a=this.Pa.pop();this.Ga-=jb(a);0<this.Pa.length&&--this.Ga};
+function Dd(a){if(768<a.Ga)throw Error(a.Me+"has a key path longer than 768 bytes ("+a.Ga+").");if(32<a.Pa.length)throw Error(a.Me+"path specified exceeds the maximum depth that can be written (32) or object contains a cycle "+Ed(a));}function Ed(a){return 0==a.Pa.length?"":"in property '"+a.Pa.join(".")+"'"};function Fd(a){a instanceof Gd||pc("Don't call new Database() directly - please use firebase.database().");this.ta=a;this.ba=new R(a,D);this.INTERNAL=new Hd(this)}var Id={TIMESTAMP:{".sv":"timestamp"}};h=Fd.prototype;h.app=null;h.gf=function(a){Jd(this,"ref");z("database.ref",0,1,arguments.length);return n(a)?this.ba.n(a):this.ba};
+h.gg=function(a){Jd(this,"database.refFromURL");z("database.refFromURL",1,1,arguments.length);var b=qc(a);Kd("database.refFromURL",b);var c=b.gc;c.host!==this.ta.L.host&&pc("database.refFromURL: Host name does not match the current database: (found "+c.host+" but expected "+this.ta.L.host+")");return this.gf(b.path.toString())};function Jd(a,b){null===a.ta&&pc("Cannot call "+b+" on a deleted database.")}h.Pf=function(){z("database.goOffline",0,0,arguments.length);Jd(this,"goOffline");this.ta.$a()};
+h.Qf=function(){z("database.goOnline",0,0,arguments.length);Jd(this,"goOnline");this.ta.hc()};Object.defineProperty(Fd.prototype,"app",{get:function(){return this.ta.app}});function Hd(a){this.Xa=a}Hd.prototype.delete=function(){Jd(this.Xa,"delete");var a=Ld.Tb(),b=this.Xa.ta;y(a.jb,b.app.name)!==b&&pc("Database "+b.app.name+" has already been deleted.");b.$a();delete a.jb[b.app.name];this.Xa.ta=null;this.Xa.ba=null;this.Xa=this.Xa.INTERNAL=null;return firebase.Promise.resolve()};
+Fd.prototype.ref=Fd.prototype.gf;Fd.prototype.refFromURL=Fd.prototype.gg;Fd.prototype.goOnline=Fd.prototype.Qf;Fd.prototype.goOffline=Fd.prototype.Pf;Hd.prototype["delete"]=Hd.prototype.delete;function Nb(){this.k=this.B=null}Nb.prototype.find=function(a){if(null!=this.B)return this.B.P(a);if(a.e()||null==this.k)return null;var b=O(a);a=E(a);return this.k.contains(b)?this.k.get(b).find(a):null};function Pb(a,b,c){if(b.e())a.B=c,a.k=null;else if(null!==a.B)a.B=a.B.F(b,c);else{null==a.k&&(a.k=new vd);var d=O(b);a.k.contains(d)||a.k.add(d,new Nb);a=a.k.get(d);b=E(b);Pb(a,b,c)}}
+function Md(a,b){if(b.e())return a.B=null,a.k=null,!0;if(null!==a.B){if(a.B.J())return!1;var c=a.B;a.B=null;c.O(L,function(b,c){Pb(a,new J(b),c)});return Md(a,b)}return null!==a.k?(c=O(b),b=E(b),a.k.contains(c)&&Md(a.k.get(c),b)&&a.k.remove(c),a.k.e()?(a.k=null,!0):!1):!0}function Ob(a,b,c){null!==a.B?c(b,a.B):a.O(function(a,e){var f=new J(b.toString()+"/"+a);Ob(e,f,c)})}Nb.prototype.O=function(a){null!==this.k&&wd(this.k,function(b,c){a(b,c)})};function Nd(a,b){this.value=a;this.children=b||Od}var Od=new Sb(function(a,b){return a===b?0:a<b?-1:1});function Pd(a){var b=S;t(a,function(a,d){b=b.set(new J(d),a)});return b}h=Nd.prototype;h.e=function(){return null===this.value&&this.children.e()};function Qd(a,b,c){if(null!=a.value&&c(a.value))return{path:D,value:a.value};if(b.e())return null;var d=O(b);a=a.children.get(d);return null!==a?(b=Qd(a,E(b),c),null!=b?{path:(new J(d)).n(b.path),value:b.value}:null):null}
+function Rd(a,b){return Qd(a,b,function(){return!0})}h.subtree=function(a){if(a.e())return this;var b=this.children.get(O(a));return null!==b?b.subtree(E(a)):S};h.set=function(a,b){if(a.e())return new Nd(b,this.children);var c=O(a),d=(this.children.get(c)||S).set(E(a),b),c=this.children.Na(c,d);return new Nd(this.value,c)};
+h.remove=function(a){if(a.e())return this.children.e()?S:new Nd(null,this.children);var b=O(a),c=this.children.get(b);return c?(a=c.remove(E(a)),b=a.e()?this.children.remove(b):this.children.Na(b,a),null===this.value&&b.e()?S:new Nd(this.value,b)):this};h.get=function(a){if(a.e())return this.value;var b=this.children.get(O(a));return b?b.get(E(a)):null};
+function Sd(a,b,c){if(b.e())return c;var d=O(b);b=Sd(a.children.get(d)||S,E(b),c);d=b.e()?a.children.remove(d):a.children.Na(d,b);return new Nd(a.value,d)}function Td(a,b){return Ud(a,D,b)}function Ud(a,b,c){var d={};a.children.ha(function(a,f){d[a]=Ud(f,b.n(a),c)});return c(b,a.value,d)}function Vd(a,b,c){return Wd(a,b,D,c)}function Wd(a,b,c,d){var e=a.value?d(c,a.value):!1;if(e)return e;if(b.e())return null;e=O(b);return(a=a.children.get(e))?Wd(a,E(b),c.n(e),d):null}
+function Xd(a,b,c){Yd(a,b,D,c)}function Yd(a,b,c,d){if(b.e())return a;a.value&&d(c,a.value);var e=O(b);return(a=a.children.get(e))?Yd(a,E(b),c.n(e),d):S}function Zd(a,b){$d(a,D,b)}function $d(a,b,c){a.children.ha(function(a,e){$d(e,b.n(a),c)});a.value&&c(b,a.value)}function ae(a,b){a.children.ha(function(a,d){d.value&&b(a,d.value)})}var S=new Nd(null);Nd.prototype.toString=function(){var a={};Zd(this,function(b,c){a[b.toString()]=c.toString()});return w(a)};function be(a){this.W=a}var ce=new be(new Nd(null));function de(a,b,c){if(b.e())return new be(new Nd(c));var d=Rd(a.W,b);if(null!=d){var e=d.path,d=d.value;b=Q(e,b);d=d.F(b,c);return new be(a.W.set(e,d))}a=Sd(a.W,b,new Nd(c));return new be(a)}function ee(a,b,c){var d=a;db(c,function(a,c){d=de(d,b.n(a),c)});return d}be.prototype.Cd=function(a){if(a.e())return ce;a=Sd(this.W,a,S);return new be(a)};function fe(a,b){var c=Rd(a.W,b);return null!=c?a.W.get(c.path).P(Q(c.path,b)):null}
+function ge(a){var b=[],c=a.W.value;null!=c?c.J()||c.O(L,function(a,c){b.push(new G(a,c))}):a.W.children.ha(function(a,c){null!=c.value&&b.push(new G(a,c.value))});return b}function he(a,b){if(b.e())return a;var c=fe(a,b);return null!=c?new be(new Nd(c)):new be(a.W.subtree(b))}be.prototype.e=function(){return this.W.e()};be.prototype.apply=function(a){return ie(D,this.W,a)};
+function ie(a,b,c){if(null!=b.value)return c.F(a,b.value);var d=null;b.children.ha(function(b,f){".priority"===b?(I(null!==f.value,"Priority writes must always be leaf nodes"),d=f.value):c=ie(a.n(b),f,c)});c.P(a).e()||null===d||(c=c.F(a.n(".priority"),d));return c};function je(a,b,c){this.type=ke;this.source=le;this.path=a;this.Mb=b;this.Gd=c}je.prototype.Jc=function(a){if(this.path.e()){if(null!=this.Mb.value)return I(this.Mb.children.e(),"affectedTree should not have overlapping affected paths."),this;a=this.Mb.subtree(new J(a));return new je(D,a,this.Gd)}I(O(this.path)===a,"operationForChild called for unrelated child.");return new je(E(this.path),this.Mb,this.Gd)};
+je.prototype.toString=function(){return"Operation("+this.path+": "+this.source.toString()+" ack write revert="+this.Gd+" affectedTree="+this.Mb+")"};var sb=0,Hc=1,ke=2,qb=3;function me(a,b,c,d){this.ae=a;this.Pe=b;this.Fb=c;this.Be=d;I(!d||b,"Tagged queries must be from server.")}var le=new me(!0,!1,null,!1),ne=new me(!1,!0,null,!1);me.prototype.toString=function(){return this.ae?"user":this.Be?"server(queryID="+this.Fb+")":"server"};function oe(){this.children={};this.Zc=0;this.value=null}function pe(a,b,c){this.sd=a?a:"";this.Mc=b?b:null;this.A=c?c:new oe}function qe(a,b){for(var c=b instanceof J?b:new J(b),d=a,e;null!==(e=O(c));)d=new pe(e,d,y(d.A.children,e)||new oe),c=E(c);return d}h=pe.prototype;h.Ca=function(){return this.A.value};function re(a,b){I("undefined"!==typeof b,"Cannot set value to undefined");a.A.value=b;se(a)}h.clear=function(){this.A.value=null;this.A.children={};this.A.Zc=0;se(this)};
+h.gd=function(){return 0<this.A.Zc};h.e=function(){return null===this.Ca()&&!this.gd()};h.O=function(a){var b=this;t(this.A.children,function(c,d){a(new pe(d,b,c))})};function te(a,b,c,d){c&&!d&&b(a);a.O(function(a){te(a,b,!0,d)});c&&d&&b(a)}function ue(a,b){for(var c=a.parent();null!==c&&!b(c);)c=c.parent()}h.path=function(){return new J(null===this.Mc?this.sd:this.Mc.path()+"/"+this.sd)};h.name=function(){return this.sd};h.parent=function(){return this.Mc};
+function se(a){if(null!==a.Mc){var b=a.Mc,c=a.sd,d=a.e(),e=cb(b.A.children,c);d&&e?(delete b.A.children[c],b.A.Zc--,se(b)):d||e||(b.A.children[c]=a.A,b.A.Zc++,se(b))}};var ve=/[\[\].#$\/\u0000-\u001F\u007F]/,we=/[\[\].#$\u0000-\u001F\u007F]/;function xe(a){return p(a)&&0!==a.length&&!ve.test(a)}function ye(a){return null===a||p(a)||ga(a)&&!rc(a)||ia(a)&&cb(a,".sv")}function ze(a,b,c,d){d&&!n(b)||Ae(A(a,1,d),b,c)}
+function Ae(a,b,c){c instanceof J&&(c=new Cd(c,a));if(!n(b))throw Error(a+"contains undefined "+Ed(c));if(ha(b))throw Error(a+"contains a function "+Ed(c)+" with contents: "+b.toString());if(rc(b))throw Error(a+"contains "+b.toString()+" "+Ed(c));if(p(b)&&b.length>10485760/3&&10485760<jb(b))throw Error(a+"contains a string greater than 10485760 utf8 bytes "+Ed(c)+" ('"+b.substring(0,50)+"...')");if(ia(b)){var d=!1,e=!1;db(b,function(b,g){if(".value"===b)d=!0;else if(".priority"!==b&&".sv"!==b&&(e=
+!0,!xe(b)))throw Error(a+" contains an invalid key ("+b+") "+Ed(c)+'.  Keys must be non-empty strings and can\'t contain ".", "#", "$", "/", "[", or "]"');c.push(b);Ae(a,g,c);c.pop()});if(d&&e)throw Error(a+' contains ".value" child '+Ed(c)+" in addition to actual children.");}}
+function Be(a,b){var c,d;for(c=0;c<b.length;c++){d=b[c];for(var e=d.slice(),f=0;f<e.length;f++)if((".priority"!==e[f]||f!==e.length-1)&&!xe(e[f]))throw Error(a+"contains an invalid key ("+e[f]+") in path "+d.toString()+'. Keys must be non-empty strings and can\'t contain ".", "#", "$", "/", "[", or "]"');}b.sort(Ad);e=null;for(c=0;c<b.length;c++){d=b[c];if(null!==e&&e.contains(d))throw Error(a+"contains a path "+e.toString()+" that is ancestor of another path "+d.toString());e=d}}
+function Ce(a,b,c){var d=A(a,1,!1);if(!ia(b)||ea(b))throw Error(d+" must be an object containing the children to replace.");var e=[];db(b,function(a,b){var k=new J(a);Ae(d,b,c.n(k));if(".priority"===Bd(k)&&!ye(b))throw Error(d+"contains an invalid value for '"+k.toString()+"', which must be a valid Firebase priority (a string, finite number, server value, or null).");e.push(k)});Be(d,e)}
+function De(a,b,c){if(rc(c))throw Error(A(a,b,!1)+"is "+c.toString()+", but must be a valid Firebase priority (a string, finite number, server value, or null).");if(!ye(c))throw Error(A(a,b,!1)+"must be a valid Firebase priority (a string, finite number, server value, or null).");}
+function Ee(a,b,c){if(!c||n(b))switch(b){case "value":case "child_added":case "child_removed":case "child_changed":case "child_moved":break;default:throw Error(A(a,1,c)+'must be a valid event type: "value", "child_added", "child_removed", "child_changed", or "child_moved".');}}function Fe(a,b){if(n(b)&&!xe(b))throw Error(A(a,2,!0)+'was an invalid key: "'+b+'".  Firebase keys must be non-empty strings and can\'t contain ".", "#", "$", "/", "[", or "]").');}
+function Ge(a,b){if(!p(b)||0===b.length||we.test(b))throw Error(A(a,1,!1)+'was an invalid path: "'+b+'". Paths must be non-empty strings and can\'t contain ".", "#", "$", "[", or "]"');}function He(a,b){if(".info"===O(b))throw Error(a+" failed: Can't modify data under /.info/");}
+function Kd(a,b){var c=b.path.toString(),d;!(d=!p(b.gc.host)||0===b.gc.host.length||!xe(b.gc.me))&&(d=0!==c.length)&&(c&&(c=c.replace(/^\/*\.info(\/|$)/,"/")),d=!(p(c)&&0!==c.length&&!we.test(c)));if(d)throw Error(A(a,1,!1)+'must be a valid firebase URL and the path can\'t contain ".", "#", "$", "[", or "]".');};function T(a,b,c){this.A=a;this.V=b;this.g=c}T.prototype.H=function(){z("Firebase.DataSnapshot.val",0,0,arguments.length);return this.A.H()};T.prototype.val=T.prototype.H;T.prototype.Ne=function(){z("Firebase.DataSnapshot.exportVal",0,0,arguments.length);return this.A.H(!0)};T.prototype.exportVal=T.prototype.Ne;T.prototype.Lf=function(){z("Firebase.DataSnapshot.exists",0,0,arguments.length);return!this.A.e()};T.prototype.exists=T.prototype.Lf;
+T.prototype.n=function(a){z("Firebase.DataSnapshot.child",0,1,arguments.length);ga(a)&&(a=String(a));Ge("Firebase.DataSnapshot.child",a);var b=new J(a),c=this.V.n(b);return new T(this.A.P(b),c,L)};T.prototype.child=T.prototype.n;T.prototype.Da=function(a){z("Firebase.DataSnapshot.hasChild",1,1,arguments.length);Ge("Firebase.DataSnapshot.hasChild",a);var b=new J(a);return!this.A.P(b).e()};T.prototype.hasChild=T.prototype.Da;
+T.prototype.C=function(){z("Firebase.DataSnapshot.getPriority",0,0,arguments.length);return this.A.C().H()};T.prototype.getPriority=T.prototype.C;T.prototype.forEach=function(a){z("Firebase.DataSnapshot.forEach",1,1,arguments.length);B("Firebase.DataSnapshot.forEach",1,a,!1);if(this.A.J())return!1;var b=this;return!!this.A.O(this.g,function(c,d){return a(new T(d,b.V.n(c),L))})};T.prototype.forEach=T.prototype.forEach;
+T.prototype.gd=function(){z("Firebase.DataSnapshot.hasChildren",0,0,arguments.length);return this.A.J()?!1:!this.A.e()};T.prototype.hasChildren=T.prototype.gd;T.prototype.getKey=function(){z("Firebase.DataSnapshot.key",0,0,arguments.length);return this.V.getKey()};Bc(T.prototype,"key",T.prototype.getKey);T.prototype.Cb=function(){z("Firebase.DataSnapshot.numChildren",0,0,arguments.length);return this.A.Cb()};T.prototype.numChildren=T.prototype.Cb;
+T.prototype.ub=function(){z("Firebase.DataSnapshot.ref",0,0,arguments.length);return this.V};Bc(T.prototype,"ref",T.prototype.ub);function U(a,b){this.ta=a;this.qa=b}U.prototype.cancel=function(a){z("Firebase.onDisconnect().cancel",0,1,arguments.length);B("Firebase.onDisconnect().cancel",1,a,!0);var b=new fb;this.ta.vd(this.qa,gb(b,a));return b.ra};U.prototype.cancel=U.prototype.cancel;U.prototype.remove=function(a){z("Firebase.onDisconnect().remove",0,1,arguments.length);He("Firebase.onDisconnect().remove",this.qa);B("Firebase.onDisconnect().remove",1,a,!0);var b=new fb;Ie(this.ta,this.qa,null,gb(b,a));return b.ra};
+U.prototype.remove=U.prototype.remove;U.prototype.set=function(a,b){z("Firebase.onDisconnect().set",1,2,arguments.length);He("Firebase.onDisconnect().set",this.qa);ze("Firebase.onDisconnect().set",a,this.qa,!1);B("Firebase.onDisconnect().set",2,b,!0);var c=new fb;Ie(this.ta,this.qa,a,gb(c,b));return c.ra};U.prototype.set=U.prototype.set;
+U.prototype.Hb=function(a,b,c){z("Firebase.onDisconnect().setWithPriority",2,3,arguments.length);He("Firebase.onDisconnect().setWithPriority",this.qa);ze("Firebase.onDisconnect().setWithPriority",a,this.qa,!1);De("Firebase.onDisconnect().setWithPriority",2,b);B("Firebase.onDisconnect().setWithPriority",3,c,!0);var d=new fb;Je(this.ta,this.qa,a,b,gb(d,c));return d.ra};U.prototype.setWithPriority=U.prototype.Hb;
+U.prototype.update=function(a,b){z("Firebase.onDisconnect().update",1,2,arguments.length);He("Firebase.onDisconnect().update",this.qa);if(ea(a)){for(var c={},d=0;d<a.length;++d)c[""+d]=a[d];a=c;N("Passing an Array to Firebase.onDisconnect().update() is deprecated. Use set() if you want to overwrite the existing data, or an Object with integer keys if you really do want to only update some of the children.")}Ce("Firebase.onDisconnect().update",a,this.qa);B("Firebase.onDisconnect().update",2,b,!0);
+c=new fb;Ke(this.ta,this.qa,a,gb(c,b));return c.ra};U.prototype.update=U.prototype.update;function Le(){xd.call(this,["visible"]);var a,b;"undefined"!==typeof document&&"undefined"!==typeof document.addEventListener&&("undefined"!==typeof document.hidden?(b="visibilitychange",a="hidden"):"undefined"!==typeof document.mozHidden?(b="mozvisibilitychange",a="mozHidden"):"undefined"!==typeof document.msHidden?(b="msvisibilitychange",a="msHidden"):"undefined"!==typeof document.webkitHidden&&(b="webkitvisibilitychange",a="webkitHidden"));this.Kb=!0;if(b){var c=this;document.addEventListener(b,
+function(){var b=!document[a];b!==c.Kb&&(c.Kb=b,c.De("visible",b))},!1)}}la(Le,xd);Le.prototype.Re=function(a){I("visible"===a,"Unknown event type: "+a);return[this.Kb]};ca(Le);function Me(a,b,c){this.A=a;this.da=b;this.Qb=c}function Ne(a){return a.da}function Oe(a){return a.Qb}function Pe(a,b){return b.e()?a.da&&!a.Qb:Qe(a,O(b))}function Qe(a,b){return a.da&&!a.Qb||a.A.Da(b)}Me.prototype.j=function(){return this.A};function V(a,b,c,d){this.type=a;this.Ia=b;this.Wa=c;this.ne=d;this.Bd=void 0}function Re(a){return new V(Se,a)}var Se="value";function Te(){this.eb={}}
+function Ue(a,b){var c=b.type,d=b.Wa;I("child_added"==c||"child_changed"==c||"child_removed"==c,"Only child changes supported for tracking");I(".priority"!==d,"Only non-priority child changes can be tracked.");var e=y(a.eb,d);if(e){var f=e.type;if("child_added"==c&&"child_removed"==f)a.eb[d]=new V("child_changed",b.Ia,d,e.Ia);else if("child_removed"==c&&"child_added"==f)delete a.eb[d];else if("child_removed"==c&&"child_changed"==f)a.eb[d]=new V("child_removed",e.ne,d);else if("child_changed"==c&&
+"child_added"==f)a.eb[d]=new V("child_added",b.Ia,d);else if("child_changed"==c&&"child_changed"==f)a.eb[d]=new V("child_changed",b.Ia,d,e.ne);else throw gc("Illegal combination of changes: "+b+" occurred after "+e);}else a.eb[d]=b};function Ve(){}Ve.prototype.Qe=function(){return null};Ve.prototype.be=function(){return null};var We=new Ve;function Xe(a,b,c){this.wf=a;this.Ja=b;this.wd=c}Xe.prototype.Qe=function(a){var b=this.Ja.N;if(Qe(b,a))return b.j().Q(a);b=null!=this.wd?new Me(this.wd,!0,!1):this.Ja.w();return this.wf.nc(a,b)};Xe.prototype.be=function(a,b,c){var d=null!=this.wd?this.wd:Ye(this.Ja);a=this.wf.Td(d,b,1,c,a);return 0===a.length?null:a[0]};function Ze(a,b,c,d){this.Yd=b;this.Jd=c;this.Bd=d;this.ed=a}Ze.prototype.Wb=function(){var a=this.Jd.ub();return"value"===this.ed?a.path:a.getParent().path};Ze.prototype.ce=function(){return this.ed};Ze.prototype.Rb=function(){return this.Yd.Rb(this)};Ze.prototype.toString=function(){return this.Wb().toString()+":"+this.ed+":"+w(this.Jd.Ne())};function $e(a,b,c){this.Yd=a;this.error=b;this.path=c}$e.prototype.Wb=function(){return this.path};$e.prototype.ce=function(){return"cancel"};
+$e.prototype.Rb=function(){return this.Yd.Rb(this)};$e.prototype.toString=function(){return this.path.toString()+":cancel"};function af(a){this.V=a;this.g=a.m.g}function bf(a,b,c,d){var e=[],f=[];Ha(b,function(b){"child_changed"===b.type&&a.g.kd(b.ne,b.Ia)&&f.push(new V("child_moved",b.Ia,b.Wa))});cf(a,e,"child_removed",b,d,c);cf(a,e,"child_added",b,d,c);cf(a,e,"child_moved",f,d,c);cf(a,e,"child_changed",b,d,c);cf(a,e,Se,b,d,c);return e}function cf(a,b,c,d,e,f){d=Ia(d,function(a){return a.type===c});Pa(d,q(a.Ff,a));Ha(d,function(c){var d=df(a,c,f);Ha(e,function(e){e.lf(c.type)&&b.push(e.createEvent(d,a.V))})})}
+function df(a,b,c){"value"!==b.type&&"child_removed"!==b.type&&(b.Bd=c.Se(b.Wa,b.Ia,a.g));return b}af.prototype.Ff=function(a,b){if(null==a.Wa||null==b.Wa)throw gc("Should only compare child_ events.");return this.g.compare(new G(a.Wa,a.Ia),new G(b.Wa,b.Ia))};function ef(){this.tb=[]}function ff(a,b){for(var c=null,d=0;d<b.length;d++){var e=b[d],f=e.Wb();null===c||f.Z(c.Wb())||(a.tb.push(c),c=null);null===c&&(c=new gf(f));c.add(e)}c&&a.tb.push(c)}function hf(a,b,c){ff(a,c);jf(a,function(a){return a.Z(b)})}function kf(a,b,c){ff(a,c);jf(a,function(a){return a.contains(b)||b.contains(a)})}
+function jf(a,b){for(var c=!0,d=0;d<a.tb.length;d++){var e=a.tb[d];if(e)if(e=e.Wb(),b(e)){for(var e=a.tb[d],f=0;f<e.fd.length;f++){var g=e.fd[f];if(null!==g){e.fd[f]=null;var k=g.Rb();kc&&C("event: "+g.toString());Ac(k)}}a.tb[d]=null}else c=!1}c&&(a.tb=[])}function gf(a){this.qa=a;this.fd=[]}gf.prototype.add=function(a){this.fd.push(a)};gf.prototype.Wb=function(){return this.qa};function lf(a,b,c){this.Nb=a;this.pb=b;this.rb=c||null}h=lf.prototype;h.lf=function(a){return"value"===a};h.createEvent=function(a,b){var c=b.m.g;return new Ze("value",this,new T(a.Ia,b.ub(),c))};h.Rb=function(a){var b=this.rb;if("cancel"===a.ce()){I(this.pb,"Raising a cancel event on a listener with no cancel callback");var c=this.pb;return function(){c.call(b,a.error)}}var d=this.Nb;return function(){d.call(b,a.Jd)}};h.Ie=function(a,b){return this.pb?new $e(this,a,b):null};
+h.matches=function(a){return a instanceof lf?a.Nb&&this.Nb?a.Nb===this.Nb&&a.rb===this.rb:!0:!1};h.Ue=function(){return null!==this.Nb};function mf(a,b,c){this.ga=a;this.pb=b;this.rb=c}h=mf.prototype;h.lf=function(a){a="children_added"===a?"child_added":a;return("children_removed"===a?"child_removed":a)in this.ga};h.Ie=function(a,b){return this.pb?new $e(this,a,b):null};
+h.createEvent=function(a,b){I(null!=a.Wa,"Child events should have a childName.");var c=b.ub().n(a.Wa);return new Ze(a.type,this,new T(a.Ia,c,b.m.g),a.Bd)};h.Rb=function(a){var b=this.rb;if("cancel"===a.ce()){I(this.pb,"Raising a cancel event on a listener with no cancel callback");var c=this.pb;return function(){c.call(b,a.error)}}var d=this.ga[a.ed];return function(){d.call(b,a.Jd,a.Bd)}};
+h.matches=function(a){if(a instanceof mf){if(!this.ga||!a.ga)return!0;if(this.rb===a.rb){var b=xa(a.ga);if(b===xa(this.ga)){if(1===b){var b=ya(a.ga),c=ya(this.ga);return c===b&&(!a.ga[b]||!this.ga[c]||a.ga[b]===this.ga[c])}return wa(this.ga,function(b,c){return a.ga[c]===b})}}}return!1};h.Ue=function(){return null!==this.ga};function W(a,b,c,d){this.u=a;this.path=b;this.m=c;this.Kc=d}
+function nf(a){var b=null,c=null;a.ka&&(b=of(a));a.na&&(c=pf(a));if(a.g===Vc){if(a.ka){if("[MIN_NAME]"!=qf(a))throw Error("Query: When ordering by key, you may only pass one argument to startAt(), endAt(), or equalTo().");if("string"!==typeof b)throw Error("Query: When ordering by key, the argument passed to startAt(), endAt(),or equalTo() must be a string.");}if(a.na){if("[MAX_NAME]"!=rf(a))throw Error("Query: When ordering by key, you may only pass one argument to startAt(), endAt(), or equalTo().");if("string"!==
+typeof c)throw Error("Query: When ordering by key, the argument passed to startAt(), endAt(),or equalTo() must be a string.");}}else if(a.g===L){if(null!=b&&!ye(b)||null!=c&&!ye(c))throw Error("Query: When ordering by priority, the first argument passed to startAt(), endAt(), or equalTo() must be a valid priority value (null, a number, or a string).");}else if(I(a.g instanceof Rc||a.g===Yc,"unknown index type."),null!=b&&"object"===typeof b||null!=c&&"object"===typeof c)throw Error("Query: First argument passed to startAt(), endAt(), or equalTo() cannot be an object.");
+}function sf(a){if(a.ka&&a.na&&a.xa&&(!a.xa||""===a.kb))throw Error("Query: Can't combine startAt(), endAt(), and limit(). Use limitToFirst() or limitToLast() instead.");}function tf(a,b){if(!0===a.Kc)throw Error(b+": You can't combine multiple orderBy calls.");}h=W.prototype;h.ub=function(){z("Query.ref",0,0,arguments.length);return new R(this.u,this.path)};
+h.dc=function(a,b,c,d){z("Query.on",2,4,arguments.length);Ee("Query.on",a,!1);B("Query.on",2,b,!1);var e=uf("Query.on",c,d);if("value"===a)vf(this.u,this,new lf(b,e.cancel||null,e.La||null));else{var f={};f[a]=b;vf(this.u,this,new mf(f,e.cancel,e.La))}return b};
+h.Fc=function(a,b,c){z("Query.off",0,3,arguments.length);Ee("Query.off",a,!0);B("Query.off",2,b,!0);lb("Query.off",3,c);var d=null,e=null;"value"===a?d=new lf(b||null,null,c||null):a&&(b&&(e={},e[a]=b),d=new mf(e,null,c||null));e=this.u;d=".info"===O(this.path)?e.md.ib(this,d):e.K.ib(this,d);hf(e.ca,this.path,d)};
+h.Zf=function(a,b){function c(k){f&&(f=!1,e.Fc(a,c),b&&b.call(d.La,k),g.resolve(k))}z("Query.once",1,4,arguments.length);Ee("Query.once",a,!1);B("Query.once",2,b,!0);var d=uf("Query.once",arguments[2],arguments[3]),e=this,f=!0,g=new fb;hb(g.ra);this.dc(a,c,function(b){e.Fc(a,c);d.cancel&&d.cancel.call(d.La,b);g.reject(b)});return g.ra};
+h.je=function(a){z("Query.limitToFirst",1,1,arguments.length);if(!ga(a)||Math.floor(a)!==a||0>=a)throw Error("Query.limitToFirst: First argument must be a positive integer.");if(this.m.xa)throw Error("Query.limitToFirst: Limit was already set (by another call to limit, limitToFirst, or limitToLast).");return new W(this.u,this.path,this.m.je(a),this.Kc)};
+h.ke=function(a){z("Query.limitToLast",1,1,arguments.length);if(!ga(a)||Math.floor(a)!==a||0>=a)throw Error("Query.limitToLast: First argument must be a positive integer.");if(this.m.xa)throw Error("Query.limitToLast: Limit was already set (by another call to limit, limitToFirst, or limitToLast).");return new W(this.u,this.path,this.m.ke(a),this.Kc)};
+h.$f=function(a){z("Query.orderByChild",1,1,arguments.length);if("$key"===a)throw Error('Query.orderByChild: "$key" is invalid.  Use Query.orderByKey() instead.');if("$priority"===a)throw Error('Query.orderByChild: "$priority" is invalid.  Use Query.orderByPriority() instead.');if("$value"===a)throw Error('Query.orderByChild: "$value" is invalid.  Use Query.orderByValue() instead.');Ge("Query.orderByChild",a);tf(this,"Query.orderByChild");var b=new J(a);if(b.e())throw Error("Query.orderByChild: cannot pass in empty path.  Use Query.orderByValue() instead.");
+b=new Rc(b);b=wf(this.m,b);nf(b);return new W(this.u,this.path,b,!0)};h.ag=function(){z("Query.orderByKey",0,0,arguments.length);tf(this,"Query.orderByKey");var a=wf(this.m,Vc);nf(a);return new W(this.u,this.path,a,!0)};h.bg=function(){z("Query.orderByPriority",0,0,arguments.length);tf(this,"Query.orderByPriority");var a=wf(this.m,L);nf(a);return new W(this.u,this.path,a,!0)};
+h.cg=function(){z("Query.orderByValue",0,0,arguments.length);tf(this,"Query.orderByValue");var a=wf(this.m,Yc);nf(a);return new W(this.u,this.path,a,!0)};h.Kd=function(a,b){z("Query.startAt",0,2,arguments.length);ze("Query.startAt",a,this.path,!0);Fe("Query.startAt",b);var c=this.m.Kd(a,b);sf(c);nf(c);if(this.m.ka)throw Error("Query.startAt: Starting point was already set (by another call to startAt or equalTo).");n(a)||(b=a=null);return new W(this.u,this.path,c,this.Kc)};
+h.dd=function(a,b){z("Query.endAt",0,2,arguments.length);ze("Query.endAt",a,this.path,!0);Fe("Query.endAt",b);var c=this.m.dd(a,b);sf(c);nf(c);if(this.m.na)throw Error("Query.endAt: Ending point was already set (by another call to endAt or equalTo).");return new W(this.u,this.path,c,this.Kc)};
+h.If=function(a,b){z("Query.equalTo",1,2,arguments.length);ze("Query.equalTo",a,this.path,!1);Fe("Query.equalTo",b);if(this.m.ka)throw Error("Query.equalTo: Starting point was already set (by another call to endAt or equalTo).");if(this.m.na)throw Error("Query.equalTo: Ending point was already set (by another call to endAt or equalTo).");return this.Kd(a,b).dd(a,b)};
+h.toString=function(){z("Query.toString",0,0,arguments.length);for(var a=this.path,b="",c=a.Y;c<a.o.length;c++)""!==a.o[c]&&(b+="/"+encodeURIComponent(String(a.o[c])));return this.u.toString()+(b||"/")};h.ja=function(){var a=vc(xf(this.m));return"{}"===a?"default":a};
+h.isEqual=function(a){z("Query.isEqual",1,1,arguments.length);if(!(a instanceof W))throw Error("Query.isEqual failed: First argument must be an instance of firebase.database.Query.");var b=this.u===a.u,c=this.path.Z(a.path),d=this.ja()===a.ja();return b&&c&&d};
+function uf(a,b,c){var d={cancel:null,La:null};if(b&&c)d.cancel=b,B(a,3,d.cancel,!0),d.La=c,lb(a,4,d.La);else if(b)if("object"===typeof b&&null!==b)d.La=b;else if("function"===typeof b)d.cancel=b;else throw Error(A(a,3,!0)+" must either be a cancel callback or a context object.");return d}W.prototype.on=W.prototype.dc;W.prototype.off=W.prototype.Fc;W.prototype.once=W.prototype.Zf;W.prototype.limitToFirst=W.prototype.je;W.prototype.limitToLast=W.prototype.ke;W.prototype.orderByChild=W.prototype.$f;
+W.prototype.orderByKey=W.prototype.ag;W.prototype.orderByPriority=W.prototype.bg;W.prototype.orderByValue=W.prototype.cg;W.prototype.startAt=W.prototype.Kd;W.prototype.endAt=W.prototype.dd;W.prototype.equalTo=W.prototype.If;W.prototype.toString=W.prototype.toString;W.prototype.isEqual=W.prototype.isEqual;Bc(W.prototype,"ref",W.prototype.ub);function yf(a){this.g=a}h=yf.prototype;h.F=function(a,b,c,d,e,f){I(a.vc(this.g),"A node must be indexed if only a child is updated");e=a.Q(b);if(e.P(d).Z(c.P(d))&&e.e()==c.e())return a;null!=f&&(c.e()?a.Da(b)?Ue(f,new V("child_removed",e,b)):I(a.J(),"A child remove without an old child only makes sense on a leaf node"):e.e()?Ue(f,new V("child_added",c,b)):Ue(f,new V("child_changed",c,b,e)));return a.J()&&c.e()?a:a.T(b,c).lb(this.g)};
+h.ya=function(a,b,c){null!=c&&(a.J()||a.O(L,function(a,e){b.Da(a)||Ue(c,new V("child_removed",e,a))}),b.J()||b.O(L,function(b,e){if(a.Da(b)){var f=a.Q(b);f.Z(e)||Ue(c,new V("child_changed",e,b,f))}else Ue(c,new V("child_added",e,b))}));return b.lb(this.g)};h.fa=function(a,b){return a.e()?H:a.fa(b)};h.Ma=function(){return!1};h.Sb=function(){return this};function zf(a){this.de=new yf(a.g);this.g=a.g;var b;a.ka?(b=qf(a),b=a.g.Bc(of(a),b)):b=a.g.Ec();this.Rc=b;a.na?(b=rf(a),a=a.g.Bc(pf(a),b)):a=a.g.Cc();this.sc=a}h=zf.prototype;h.matches=function(a){return 0>=this.g.compare(this.Rc,a)&&0>=this.g.compare(a,this.sc)};h.F=function(a,b,c,d,e,f){this.matches(new G(b,c))||(c=H);return this.de.F(a,b,c,d,e,f)};
+h.ya=function(a,b,c){b.J()&&(b=H);var d=b.lb(this.g),d=d.fa(H),e=this;b.O(L,function(a,b){e.matches(new G(a,b))||(d=d.T(a,H))});return this.de.ya(a,d,c)};h.fa=function(a){return a};h.Ma=function(){return!0};h.Sb=function(){return this.de};function Af(a){this.sa=new zf(a);this.g=a.g;I(a.xa,"Only valid if limit has been set");this.oa=a.oa;this.Gb=!Bf(a)}h=Af.prototype;h.F=function(a,b,c,d,e,f){this.sa.matches(new G(b,c))||(c=H);return a.Q(b).Z(c)?a:a.Cb()<this.oa?this.sa.Sb().F(a,b,c,d,e,f):Cf(this,a,b,c,e,f)};
+h.ya=function(a,b,c){var d;if(b.J()||b.e())d=H.lb(this.g);else if(2*this.oa<b.Cb()&&b.vc(this.g)){d=H.lb(this.g);b=this.Gb?b.Xb(this.sa.sc,this.g):b.Vb(this.sa.Rc,this.g);for(var e=0;0<b.Oa.length&&e<this.oa;){var f=M(b),g;if(g=this.Gb?0>=this.g.compare(this.sa.Rc,f):0>=this.g.compare(f,this.sa.sc))d=d.T(f.name,f.R),e++;else break}}else{d=b.lb(this.g);d=d.fa(H);var k,m,l;if(this.Gb){b=d.Te(this.g);k=this.sa.sc;m=this.sa.Rc;var r=Pc(this.g);l=function(a,b){return r(b,a)}}else b=d.Ub(this.g),k=this.sa.Rc,
+m=this.sa.sc,l=Pc(this.g);for(var e=0,x=!1;0<b.Oa.length;)f=M(b),!x&&0>=l(k,f)&&(x=!0),(g=x&&e<this.oa&&0>=l(f,m))?e++:d=d.T(f.name,H)}return this.sa.Sb().ya(a,d,c)};h.fa=function(a){return a};h.Ma=function(){return!0};h.Sb=function(){return this.sa.Sb()};
+function Cf(a,b,c,d,e,f){var g;if(a.Gb){var k=Pc(a.g);g=function(a,b){return k(b,a)}}else g=Pc(a.g);I(b.Cb()==a.oa,"");var m=new G(c,d),l=a.Gb?kd(b,a.g):ld(b,a.g),r=a.sa.matches(m);if(b.Da(c)){for(var x=b.Q(c),l=e.be(a.g,l,a.Gb);null!=l&&(l.name==c||b.Da(l.name));)l=e.be(a.g,l,a.Gb);e=null==l?1:g(l,m);if(r&&!d.e()&&0<=e)return null!=f&&Ue(f,new V("child_changed",d,c,x)),b.T(c,d);null!=f&&Ue(f,new V("child_removed",x,c));b=b.T(c,H);return null!=l&&a.sa.matches(l)?(null!=f&&Ue(f,new V("child_added",
+l.R,l.name)),b.T(l.name,l.R)):b}return d.e()?b:r&&0<=g(l,m)?(null!=f&&(Ue(f,new V("child_removed",l.R,l.name)),Ue(f,new V("child_added",d,c))),b.T(c,d).T(l.name,H)):b};function Df(){this.Pb=this.na=this.Ib=this.ka=this.xa=!1;this.oa=0;this.kb="";this.bc=null;this.xb="";this.Zb=null;this.vb="";this.g=L}var Ef=new Df;function Bf(a){return""===a.kb?a.ka:"l"===a.kb}function of(a){I(a.ka,"Only valid if start has been set");return a.bc}function qf(a){I(a.ka,"Only valid if start has been set");return a.Ib?a.xb:"[MIN_NAME]"}function pf(a){I(a.na,"Only valid if end has been set");return a.Zb}
+function rf(a){I(a.na,"Only valid if end has been set");return a.Pb?a.vb:"[MAX_NAME]"}function Ff(a){var b=new Df;b.xa=a.xa;b.oa=a.oa;b.ka=a.ka;b.bc=a.bc;b.Ib=a.Ib;b.xb=a.xb;b.na=a.na;b.Zb=a.Zb;b.Pb=a.Pb;b.vb=a.vb;b.g=a.g;b.kb=a.kb;return b}h=Df.prototype;h.je=function(a){var b=Ff(this);b.xa=!0;b.oa=a;b.kb="l";return b};h.ke=function(a){var b=Ff(this);b.xa=!0;b.oa=a;b.kb="r";return b};h.Kd=function(a,b){var c=Ff(this);c.ka=!0;n(a)||(a=null);c.bc=a;null!=b?(c.Ib=!0,c.xb=b):(c.Ib=!1,c.xb="");return c};
+h.dd=function(a,b){var c=Ff(this);c.na=!0;n(a)||(a=null);c.Zb=a;n(b)?(c.Pb=!0,c.vb=b):(c.yg=!1,c.vb="");return c};function wf(a,b){var c=Ff(a);c.g=b;return c}function xf(a){var b={};a.ka&&(b.sp=a.bc,a.Ib&&(b.sn=a.xb));a.na&&(b.ep=a.Zb,a.Pb&&(b.en=a.vb));if(a.xa){b.l=a.oa;var c=a.kb;""===c&&(c=Bf(a)?"l":"r");b.vf=c}a.g!==L&&(b.i=a.g.toString());return b}function X(a){return!(a.ka||a.na||a.xa)}function Kc(a){return X(a)&&a.g==L}
+function Lc(a){var b={};if(Kc(a))return b;var c;a.g===L?c="$priority":a.g===Yc?c="$value":a.g===Vc?c="$key":(I(a.g instanceof Rc,"Unrecognized index type!"),c=a.g.toString());b.orderBy=w(c);a.ka&&(b.startAt=w(a.bc),a.Ib&&(b.startAt+=","+w(a.xb)));a.na&&(b.endAt=w(a.Zb),a.Pb&&(b.endAt+=","+w(a.vb)));a.xa&&(Bf(a)?b.limitToFirst=a.oa:b.limitToLast=a.oa);return b}h.toString=function(){return w(xf(this))};function Gf(a,b){this.N=a;this.Id=b}function Hf(a,b,c,d){return new Gf(new Me(b,c,d),a.Id)}function If(a){return a.N.da?a.N.j():null}Gf.prototype.w=function(){return this.Id};function Ye(a){return a.Id.da?a.Id.j():null};function Jf(a,b){this.Od=a;this.Cf=b}function Kf(a){this.U=a}
+Kf.prototype.bb=function(a,b,c,d){var e=new Te,f;if(b.type===sb)b.source.ae?c=Lf(this,a,b.path,b.Fa,c,d,e):(I(b.source.Pe,"Unknown source."),f=b.source.Be||Oe(a.w())&&!b.path.e(),c=Mf(this,a,b.path,b.Fa,c,d,f,e));else if(b.type===Hc)b.source.ae?c=Nf(this,a,b.path,b.children,c,d,e):(I(b.source.Pe,"Unknown source."),f=b.source.Be||Oe(a.w()),c=Of(this,a,b.path,b.children,c,d,f,e));else if(b.type===ke)if(b.Gd)if(b=b.path,null!=c.ic(b))c=a;else{f=new Xe(c,a,d);d=a.N.j();if(b.e()||".priority"===O(b))Ne(a.w())?
+b=c.Aa(Ye(a)):(b=a.w().j(),I(b instanceof P,"serverChildren would be complete if leaf node"),b=c.oc(b)),b=this.U.ya(d,b,e);else{var g=O(b),k=c.nc(g,a.w());null==k&&Qe(a.w(),g)&&(k=d.Q(g));b=null!=k?this.U.F(d,g,k,E(b),f,e):a.N.j().Da(g)?this.U.F(d,g,H,E(b),f,e):d;b.e()&&Ne(a.w())&&(d=c.Aa(Ye(a)),d.J()&&(b=this.U.ya(b,d,e)))}d=Ne(a.w())||null!=c.ic(D);c=Hf(a,b,d,this.U.Ma())}else c=Pf(this,a,b.path,b.Mb,c,d,e);else if(b.type===qb)d=b.path,b=a.w(),f=b.j(),g=b.da||d.e(),c=Qf(this,new Gf(a.N,new Me(f,
+g,b.Qb)),d,c,We,e);else throw gc("Unknown operation type: "+b.type);e=za(e.eb);d=c;b=d.N;b.da&&(f=b.j().J()||b.j().e(),g=If(a),(0<e.length||!a.N.da||f&&!b.j().Z(g)||!b.j().C().Z(g.C()))&&e.push(Re(If(d))));return new Jf(c,e)};
+function Qf(a,b,c,d,e,f){var g=b.N;if(null!=d.ic(c))return b;var k;if(c.e())I(Ne(b.w()),"If change path is empty, we must have complete server data"),Oe(b.w())?(e=Ye(b),d=d.oc(e instanceof P?e:H)):d=d.Aa(Ye(b)),f=a.U.ya(b.N.j(),d,f);else{var m=O(c);if(".priority"==m)I(1==gd(c),"Can't have a priority with additional path components"),f=g.j(),k=b.w().j(),d=d.Yc(c,f,k),f=null!=d?a.U.fa(f,d):g.j();else{var l=E(c);Qe(g,m)?(k=b.w().j(),d=d.Yc(c,g.j(),k),d=null!=d?g.j().Q(m).F(l,d):g.j().Q(m)):d=d.nc(m,
+b.w());f=null!=d?a.U.F(g.j(),m,d,l,e,f):g.j()}}return Hf(b,f,g.da||c.e(),a.U.Ma())}function Mf(a,b,c,d,e,f,g,k){var m=b.w();g=g?a.U:a.U.Sb();if(c.e())d=g.ya(m.j(),d,null);else if(g.Ma()&&!m.Qb)d=m.j().F(c,d),d=g.ya(m.j(),d,null);else{var l=O(c);if(!Pe(m,c)&&1<gd(c))return b;var r=E(c);d=m.j().Q(l).F(r,d);d=".priority"==l?g.fa(m.j(),d):g.F(m.j(),l,d,r,We,null)}m=m.da||c.e();b=new Gf(b.N,new Me(d,m,g.Ma()));return Qf(a,b,c,e,new Xe(e,b,f),k)}
+function Lf(a,b,c,d,e,f,g){var k=b.N;e=new Xe(e,b,f);if(c.e())g=a.U.ya(b.N.j(),d,g),a=Hf(b,g,!0,a.U.Ma());else if(f=O(c),".priority"===f)g=a.U.fa(b.N.j(),d),a=Hf(b,g,k.da,k.Qb);else{c=E(c);var m=k.j().Q(f);if(!c.e()){var l=e.Qe(f);d=null!=l?".priority"===Bd(c)&&l.P(c.parent()).e()?l:l.F(c,d):H}m.Z(d)?a=b:(g=a.U.F(k.j(),f,d,c,e,g),a=Hf(b,g,k.da,a.U.Ma()))}return a}
+function Nf(a,b,c,d,e,f,g){var k=b;Zd(d,function(d,l){var r=c.n(d);Qe(b.N,O(r))&&(k=Lf(a,k,r,l,e,f,g))});Zd(d,function(d,l){var r=c.n(d);Qe(b.N,O(r))||(k=Lf(a,k,r,l,e,f,g))});return k}function Rf(a,b){Zd(b,function(b,d){a=a.F(b,d)});return a}
+function Of(a,b,c,d,e,f,g,k){if(b.w().j().e()&&!Ne(b.w()))return b;var m=b;c=c.e()?d:Sd(S,c,d);var l=b.w().j();c.children.ha(function(c,d){if(l.Da(c)){var F=b.w().j().Q(c),F=Rf(F,d);m=Mf(a,m,new J(c),F,e,f,g,k)}});c.children.ha(function(c,d){var F=!Qe(b.w(),c)&&null==d.value;l.Da(c)||F||(F=b.w().j().Q(c),F=Rf(F,d),m=Mf(a,m,new J(c),F,e,f,g,k))});return m}
+function Pf(a,b,c,d,e,f,g){if(null!=e.ic(c))return b;var k=Oe(b.w()),m=b.w();if(null!=d.value){if(c.e()&&m.da||Pe(m,c))return Mf(a,b,c,m.j().P(c),e,f,k,g);if(c.e()){var l=S;m.j().O(Vc,function(a,b){l=l.set(new J(a),b)});return Of(a,b,c,l,e,f,k,g)}return b}l=S;Zd(d,function(a){var b=c.n(a);Pe(m,b)&&(l=l.set(a,m.j().P(b)))});return Of(a,b,c,l,e,f,k,g)};function Sf(a,b){this.V=a;var c=a.m,d=new yf(c.g),c=X(c)?new yf(c.g):c.xa?new Af(c):new zf(c);this.ff=new Kf(c);var e=b.w(),f=b.N,g=d.ya(H,e.j(),null),k=c.ya(H,f.j(),null);this.Ja=new Gf(new Me(k,f.da,c.Ma()),new Me(g,e.da,d.Ma()));this.Ya=[];this.Jf=new af(a)}function Tf(a){return a.V}h=Sf.prototype;h.w=function(){return this.Ja.w().j()};h.fb=function(a){var b=Ye(this.Ja);return b&&(X(this.V.m)||!a.e()&&!b.Q(O(a)).e())?b.P(a):null};h.e=function(){return 0===this.Ya.length};h.Lb=function(a){this.Ya.push(a)};
+h.ib=function(a,b){var c=[];if(b){I(null==a,"A cancel should cancel all event registrations.");var d=this.V.path;Ha(this.Ya,function(a){(a=a.Ie(b,d))&&c.push(a)})}if(a){for(var e=[],f=0;f<this.Ya.length;++f){var g=this.Ya[f];if(!g.matches(a))e.push(g);else if(a.Ue()){e=e.concat(this.Ya.slice(f+1));break}}this.Ya=e}else this.Ya=[];return c};
+h.bb=function(a,b,c){a.type===Hc&&null!==a.source.Fb&&(I(Ye(this.Ja),"We should always have a full cache before handling merges"),I(If(this.Ja),"Missing event cache, even though we have a server cache"));var d=this.Ja;a=this.ff.bb(d,a,b,c);b=this.ff;c=a.Od;I(c.N.j().vc(b.U.g),"Event snap not indexed");I(c.w().j().vc(b.U.g),"Server snap not indexed");I(Ne(a.Od.w())||!Ne(d.w()),"Once a server snap is complete, it should never go back");this.Ja=a.Od;return Uf(this,a.Cf,a.Od.N.j(),null)};
+function Vf(a,b){var c=a.Ja.N,d=[];c.j().J()||c.j().O(L,function(a,b){d.push(new V("child_added",b,a))});c.da&&d.push(Re(c.j()));return Uf(a,d,c.j(),b)}function Uf(a,b,c,d){return bf(a.Jf,b,c,d?[d]:a.Ya)};function Wf(){this.za={}}h=Wf.prototype;h.e=function(){return Ea(this.za)};h.bb=function(a,b,c){var d=a.source.Fb;if(null!==d)return d=y(this.za,d),I(null!=d,"SyncTree gave us an op for an invalid query."),d.bb(a,b,c);var e=[];t(this.za,function(d){e=e.concat(d.bb(a,b,c))});return e};h.Lb=function(a,b,c,d,e){var f=a.ja(),g=y(this.za,f);if(!g){var g=c.Aa(e?d:null),k=!1;g?k=!0:(g=d instanceof P?c.oc(d):H,k=!1);g=new Sf(a,new Gf(new Me(g,k,!1),new Me(d,e,!1)));this.za[f]=g}g.Lb(b);return Vf(g,b)};
+h.ib=function(a,b,c){var d=a.ja(),e=[],f=[],g=null!=Xf(this);if("default"===d){var k=this;t(this.za,function(a,d){f=f.concat(a.ib(b,c));a.e()&&(delete k.za[d],X(a.V.m)||e.push(a.V))})}else{var m=y(this.za,d);m&&(f=f.concat(m.ib(b,c)),m.e()&&(delete this.za[d],X(m.V.m)||e.push(m.V)))}g&&null==Xf(this)&&e.push(new R(a.u,a.path));return{hg:e,Kf:f}};function Yf(a){return Ia(za(a.za),function(a){return!X(a.V.m)})}h.fb=function(a){var b=null;t(this.za,function(c){b=b||c.fb(a)});return b};
+function Zf(a,b){if(X(b.m))return Xf(a);var c=b.ja();return y(a.za,c)}function Xf(a){return Da(a.za,function(a){return X(a.V.m)})||null};function $f(){this.S=ce;this.la=[];this.yc=-1}function ag(a,b){for(var c=0;c<a.la.length;c++){var d=a.la[c];if(d.Wc===b)return d}return null}h=$f.prototype;
+h.Cd=function(a){var b=Na(this.la,function(b){return b.Wc===a});I(0<=b,"removeWrite called with nonexistent writeId.");var c=this.la[b];this.la.splice(b,1);for(var d=c.visible,e=!1,f=this.la.length-1;d&&0<=f;){var g=this.la[f];g.visible&&(f>=b&&bg(g,c.path)?d=!1:c.path.contains(g.path)&&(e=!0));f--}if(d){if(e)this.S=cg(this.la,dg,D),this.yc=0<this.la.length?this.la[this.la.length-1].Wc:-1;else if(c.Fa)this.S=this.S.Cd(c.path);else{var k=this;t(c.children,function(a,b){k.S=k.S.Cd(c.path.n(b))})}return!0}return!1};
+h.Aa=function(a,b,c,d){if(c||d){var e=he(this.S,a);return!d&&e.e()?b:d||null!=b||null!=fe(e,D)?(e=cg(this.la,function(b){return(b.visible||d)&&(!c||!(0<=Ga(c,b.Wc)))&&(b.path.contains(a)||a.contains(b.path))},a),b=b||H,e.apply(b)):null}e=fe(this.S,a);if(null!=e)return e;e=he(this.S,a);return e.e()?b:null!=b||null!=fe(e,D)?(b=b||H,e.apply(b)):null};
+h.oc=function(a,b){var c=H,d=fe(this.S,a);if(d)d.J()||d.O(L,function(a,b){c=c.T(a,b)});else if(b){var e=he(this.S,a);b.O(L,function(a,b){var d=he(e,new J(a)).apply(b);c=c.T(a,d)});Ha(ge(e),function(a){c=c.T(a.name,a.R)})}else e=he(this.S,a),Ha(ge(e),function(a){c=c.T(a.name,a.R)});return c};h.Yc=function(a,b,c,d){I(c||d,"Either existingEventSnap or existingServerSnap must exist");a=a.n(b);if(null!=fe(this.S,a))return null;a=he(this.S,a);return a.e()?d.P(b):a.apply(d.P(b))};
+h.nc=function(a,b,c){a=a.n(b);var d=fe(this.S,a);return null!=d?d:Qe(c,b)?he(this.S,a).apply(c.j().Q(b)):null};h.ic=function(a){return fe(this.S,a)};h.Td=function(a,b,c,d,e,f){var g;a=he(this.S,a);g=fe(a,D);if(null==g)if(null!=b)g=a.apply(b);else return[];g=g.lb(f);if(g.e()||g.J())return[];b=[];a=Pc(f);e=e?g.Xb(c,f):g.Vb(c,f);for(f=M(e);f&&b.length<d;)0!==a(f,c)&&b.push(f),f=M(e);return b};
+function bg(a,b){return a.Fa?a.path.contains(b):!!Ca(a.children,function(c,d){return a.path.n(d).contains(b)})}function dg(a){return a.visible}
+function cg(a,b,c){for(var d=ce,e=0;e<a.length;++e){var f=a[e];if(b(f)){var g=f.path;if(f.Fa)c.contains(g)?(g=Q(c,g),d=de(d,g,f.Fa)):g.contains(c)&&(g=Q(g,c),d=de(d,D,f.Fa.P(g)));else if(f.children)if(c.contains(g))g=Q(c,g),d=ee(d,g,f.children);else{if(g.contains(c))if(g=Q(g,c),g.e())d=ee(d,D,f.children);else if(f=y(f.children,O(g)))f=f.P(E(g)),d=de(d,D,f)}else throw gc("WriteRecord should have .snap or .children");}}return d}function eg(a,b){this.Jb=a;this.W=b}h=eg.prototype;
+h.Aa=function(a,b,c){return this.W.Aa(this.Jb,a,b,c)};h.oc=function(a){return this.W.oc(this.Jb,a)};h.Yc=function(a,b,c){return this.W.Yc(this.Jb,a,b,c)};h.ic=function(a){return this.W.ic(this.Jb.n(a))};h.Td=function(a,b,c,d,e){return this.W.Td(this.Jb,a,b,c,d,e)};h.nc=function(a,b){return this.W.nc(this.Jb,a,b)};h.n=function(a){return new eg(this.Jb.n(a),this.W)};function fg(a){this.wa=S;this.hb=new $f;this.Ae={};this.fc={};this.zc=a}function gg(a,b,c,d,e){var f=a.hb,g=e;I(d>f.yc,"Stacking an older write on top of newer ones");n(g)||(g=!0);f.la.push({path:b,Fa:c,Wc:d,visible:g});g&&(f.S=de(f.S,b,c));f.yc=d;return e?hg(a,new rb(le,b,c)):[]}function ig(a,b,c,d){var e=a.hb;I(d>e.yc,"Stacking an older merge on top of newer ones");e.la.push({path:b,children:c,Wc:d,visible:!0});e.S=ee(e.S,b,c);e.yc=d;c=Pd(c);return hg(a,new Gc(le,b,c))}
+function jg(a,b,c){c=c||!1;var d=ag(a.hb,b);if(a.hb.Cd(b)){var e=S;null!=d.Fa?e=e.set(D,!0):db(d.children,function(a,b){e=e.set(new J(a),b)});return hg(a,new je(d.path,e,c))}return[]}function kg(a,b,c){c=Pd(c);return hg(a,new Gc(ne,b,c))}function lg(a,b,c,d){d=mg(a,d);if(null!=d){var e=ng(d);d=e.path;e=e.Fb;b=Q(d,b);c=new rb(new me(!1,!0,e,!0),b,c);return og(a,d,c)}return[]}
+function pg(a,b,c,d){if(d=mg(a,d)){var e=ng(d);d=e.path;e=e.Fb;b=Q(d,b);c=Pd(c);c=new Gc(new me(!1,!0,e,!0),b,c);return og(a,d,c)}return[]}
+fg.prototype.Lb=function(a,b){var c=a.path,d=null,e=!1;Xd(this.wa,c,function(a,b){var f=Q(a,c);d=d||b.fb(f);e=e||null!=Xf(b)});var f=this.wa.get(c);f?(e=e||null!=Xf(f),d=d||f.fb(D)):(f=new Wf,this.wa=this.wa.set(c,f));var g;null!=d?g=!0:(g=!1,d=H,ae(this.wa.subtree(c),function(a,b){var c=b.fb(D);c&&(d=d.T(a,c))}));var k=null!=Zf(f,a);if(!k&&!X(a.m)){var m=qg(a);I(!(m in this.fc),"View does not exist, but we have a tag");var l=rg++;this.fc[m]=l;this.Ae["_"+l]=m}g=f.Lb(a,b,new eg(c,this.hb),d,g);k||
+e||(f=Zf(f,a),g=g.concat(sg(this,a,f)));return g};
+fg.prototype.ib=function(a,b,c){var d=a.path,e=this.wa.get(d),f=[];if(e&&("default"===a.ja()||null!=Zf(e,a))){f=e.ib(a,b,c);e.e()&&(this.wa=this.wa.remove(d));e=f.hg;f=f.Kf;b=-1!==Na(e,function(a){return X(a.m)});var g=Vd(this.wa,d,function(a,b){return null!=Xf(b)});if(b&&!g&&(d=this.wa.subtree(d),!d.e()))for(var d=tg(d),k=0;k<d.length;++k){var m=d[k],l=m.V,m=ug(this,m);this.zc.xe(vg(l),wg(this,l),m.hd,m.G)}if(!g&&0<e.length&&!c)if(b)this.zc.Ld(vg(a),null);else{var r=this;Ha(e,function(a){a.ja();
+var b=r.fc[qg(a)];r.zc.Ld(vg(a),b)})}xg(this,e)}return f};fg.prototype.Aa=function(a,b){var c=this.hb,d=Vd(this.wa,a,function(b,c){var d=Q(b,a);if(d=c.fb(d))return d});return c.Aa(a,d,b,!0)};function tg(a){return Td(a,function(a,c,d){if(c&&null!=Xf(c))return[Xf(c)];var e=[];c&&(e=Yf(c));t(d,function(a){e=e.concat(a)});return e})}function xg(a,b){for(var c=0;c<b.length;++c){var d=b[c];if(!X(d.m)){var d=qg(d),e=a.fc[d];delete a.fc[d];delete a.Ae["_"+e]}}}
+function vg(a){return X(a.m)&&!Kc(a.m)?a.ub():a}function sg(a,b,c){var d=b.path,e=wg(a,b);c=ug(a,c);b=a.zc.xe(vg(b),e,c.hd,c.G);d=a.wa.subtree(d);if(e)I(null==Xf(d.value),"If we're adding a query, it shouldn't be shadowed");else for(e=Td(d,function(a,b,c){if(!a.e()&&b&&null!=Xf(b))return[Tf(Xf(b))];var d=[];b&&(d=d.concat(Ja(Yf(b),function(a){return a.V})));t(c,function(a){d=d.concat(a)});return d}),d=0;d<e.length;++d)c=e[d],a.zc.Ld(vg(c),wg(a,c));return b}
+function ug(a,b){var c=b.V,d=wg(a,c);return{hd:function(){return(b.w()||H).hash()},G:function(b){if("ok"===b){if(d){var f=c.path;if(b=mg(a,d)){var g=ng(b);b=g.path;g=g.Fb;f=Q(b,f);f=new pb(new me(!1,!0,g,!0),f);b=og(a,b,f)}else b=[]}else b=hg(a,new pb(ne,c.path));return b}f="Unknown Error";"too_big"===b?f="The data requested exceeds the maximum size that can be accessed with a single request.":"permission_denied"==b?f="Client doesn't have permission to access the desired data.":"unavailable"==b&&
+(f="The service is unavailable");f=Error(b+" at "+c.path.toString()+": "+f);f.code=b.toUpperCase();return a.ib(c,null,f)}}}function qg(a){return a.path.toString()+"$"+a.ja()}function ng(a){var b=a.indexOf("$");I(-1!==b&&b<a.length-1,"Bad queryKey.");return{Fb:a.substr(b+1),path:new J(a.substr(0,b))}}function mg(a,b){var c=a.Ae,d="_"+b;return d in c?c[d]:void 0}function wg(a,b){var c=qg(b);return y(a.fc,c)}var rg=1;
+function og(a,b,c){var d=a.wa.get(b);I(d,"Missing sync point for query tag that we're tracking");return d.bb(c,new eg(b,a.hb),null)}function hg(a,b){return yg(a,b,a.wa,null,new eg(D,a.hb))}function yg(a,b,c,d,e){if(b.path.e())return zg(a,b,c,d,e);var f=c.get(D);null==d&&null!=f&&(d=f.fb(D));var g=[],k=O(b.path),m=b.Jc(k);if((c=c.children.get(k))&&m)var l=d?d.Q(k):null,k=e.n(k),g=g.concat(yg(a,m,c,l,k));f&&(g=g.concat(f.bb(b,e,d)));return g}
+function zg(a,b,c,d,e){var f=c.get(D);null==d&&null!=f&&(d=f.fb(D));var g=[];c.children.ha(function(c,f){var l=d?d.Q(c):null,r=e.n(c),x=b.Jc(c);x&&(g=g.concat(zg(a,x,f,l,r)))});f&&(g=g.concat(f.bb(b,e,d)));return g};function Ag(){return"undefined"!==typeof window&&!!(window.cordova||window.phonegap||window.PhoneGap)&&/ios|iphone|ipod|ipad|android|blackberry|iemobile/i.test("undefined"!==typeof navigator&&"string"===typeof navigator.userAgent?navigator.userAgent:"")};function Bg(){xd.call(this,["online"]);this.ec=!0;if("undefined"!==typeof window&&"undefined"!==typeof window.addEventListener&&!Ag()){var a=this;window.addEventListener("online",function(){a.ec||(a.ec=!0,a.De("online",!0))},!1);window.addEventListener("offline",function(){a.ec&&(a.ec=!1,a.De("online",!1))},!1)}}la(Bg,xd);Bg.prototype.Re=function(a){I("online"===a,"Unknown event type: "+a);return[this.ec]};ca(Bg);var Jb="websocket",Kb="long_polling";function Cg(a){this.qe=a;this.zd=[];this.Ob=0;this.Ud=-1;this.Db=null}function Dg(a,b,c){a.Ud=b;a.Db=c;a.Ud<a.Ob&&(a.Db(),a.Db=null)}function Eg(a,b,c){for(a.zd[b]=c;a.zd[a.Ob];){var d=a.zd[a.Ob];delete a.zd[a.Ob];for(var e=0;e<d.length;++e)if(d[e]){var f=a;Ac(function(){f.qe(d[e])})}if(a.Ob===a.Ud){a.Db&&(clearTimeout(a.Db),a.Db(),a.Db=null);break}a.Ob++}};function Fg(a,b,c,d){this.Vd=a;this.f=nc(a);this.gc=b;this.nb=this.ob=0;this.Ua=td(b);this.sf=c;this.tc=!1;this.Ab=d;this.Vc=function(a){return Ib(b,Kb,a)}}var Gg,Hg;
+Fg.prototype.open=function(a,b){this.Je=0;this.ia=b;this.af=new Cg(a);this.yb=!1;var c=this;this.qb=setTimeout(function(){c.f("Timed out trying to connect.");c.ab();c.qb=null},Math.floor(3E4));sc(function(){if(!c.yb){c.Sa=new Ig(function(a,b,d,k,m){Jg(c,arguments);if(c.Sa)if(c.qb&&(clearTimeout(c.qb),c.qb=null),c.tc=!0,"start"==a)c.id=b,c.dg=d;else if("close"===a)b?(c.Sa.of=!1,Dg(c.af,b,function(){c.ab()})):c.ab();else throw Error("Unrecognized command received: "+a);},function(a,b){Jg(c,arguments);
+Eg(c.af,a,b)},function(){c.ab()},c.Vc);var a={start:"t"};a.ser=Math.floor(1E8*Math.random());c.Sa.qg&&(a.cb=c.Sa.qg);a.v="5";c.sf&&(a.s=c.sf);c.Ab&&(a.ls=c.Ab);a=c.Vc(a);c.f("Connecting via long-poll to "+a);Kg(c.Sa,a,function(){})}})};Fg.prototype.start=function(){var a=this.Sa,b=this.dg;a.le=this.id;a.$e=b;for(a.Qd=!0;Lg(a););};
+Fg.isAvailable=function(){return Gg||!Hg&&"undefined"!==typeof document&&null!=document.createElement&&!("object"===typeof window&&window.chrome&&window.chrome.extension&&!/^chrome/.test(window.location.href))&&!("object"===typeof Windows&&"object"===typeof Windows.sg)&&!1};h=Fg.prototype;h.pd=function(){};h.Qc=function(){this.yb=!0;this.Sa&&(this.Sa.close(),this.Sa=null);this.Ze&&(document.body.removeChild(this.Ze),this.Ze=null);this.qb&&(clearTimeout(this.qb),this.qb=null)};
+h.ab=function(){this.yb||(this.f("Longpoll is closing itself"),this.Qc(),this.ia&&(this.ia(this.tc),this.ia=null))};h.close=function(){this.yb||(this.f("Longpoll is being closed."),this.Qc())};h.send=function(a){a=w(a);this.ob+=a.length;zb(this.Ua,"bytes_sent",a.length);a=ib(a);a=Za(a,!0);a=wc(a,1840);for(var b=0;b<a.length;b++){var c=this.Sa;c.Nc.push({jg:this.Je,pg:a.length,Le:a[b]});c.Qd&&Lg(c);this.Je++}};function Jg(a,b){var c=w(b).length;a.nb+=c;zb(a.Ua,"bytes_received",c)}
+function Ig(a,b,c,d){this.Vc=d;this.gb=c;this.se=new vd;this.Nc=[];this.Xd=Math.floor(1E8*Math.random());this.of=!0;this.Ef=a;this.Wf=b}Ig.prototype.close=function(){this.Qd=!1;if(this.rd){this.rd.ug.body.innerHTML="";var a=this;setTimeout(function(){null!==a.rd&&(document.body.removeChild(a.rd),a.rd=null)},Math.floor(0))}if(this.le){var b={disconn:"t"};b.id=this.le;b.pw=this.$e;b=this.Vc(b);Mg(b)}if(b=this.gb)this.gb=null,b()};
+function Lg(a){if(a.Qd&&a.of&&a.se.count()<(0<a.Nc.length?2:1)){a.Xd++;var b={};b.id=a.le;b.pw=a.$e;b.ser=a.Xd;for(var b=a.Vc(b),c="",d=0;0<a.Nc.length;)if(1870>=a.Nc[0].Le.length+30+c.length){var e=a.Nc.shift(),c=c+"&seg"+d+"="+e.jg+"&ts"+d+"="+e.pg+"&d"+d+"="+e.Le;d++}else break;Ng(a,b+c,a.Xd);return!0}return!1}function Ng(a,b,c){function d(){a.se.remove(c);Lg(a)}a.se.add(c,1);var e=setTimeout(d,Math.floor(25E3));Kg(a,b,function(){clearTimeout(e);d()})}function Kg(a,b,c){Og(a,b,c)}var Pg=null;
+function Mg(a,b){Pg||(Pg=require("request"));Pg(a,function(c,d,e){if(c)throw"Rest request for "+a.url+" failed.";b&&b(e)})}function Og(a,b,c){Mg({url:b,vg:!0},function(b){Qg(a,b);c()})}function Qg(a,b){eval("var jsonpCB = function(pLPCommand, pRTLPCB) {"+b+"}");jsonpCB(a.Ef,a.Wf)};var Rg=null,Rg=require("faye-websocket").Client;function Sg(a,b,c,d){this.Vd=a;this.f=nc(this.Vd);this.frames=this.wc=null;this.nb=this.ob=this.Ce=0;this.Ua=td(b);a={v:"5"};c&&(a.s=c);d&&(a.ls=d);this.Wd=Ib(b,Jb,a)}var Tg;
+Sg.prototype.open=function(a,b){this.gb=b;this.Vf=a;this.f("Websocket connecting to "+this.Wd);this.tc=!1;Eb.set("previous_websocket_failure",!0);try{var c={headers:{"User-Agent":"Firebase/5/"+firebase.SDK_VERSION+"/"+process.platform+"/Node"}},d=process.env,e=0==this.Wd.indexOf("wss://")?d.HTTPS_PROXY||d.https_proxy:d.HTTP_PROXY||d.http_proxy;e&&(c.proxy={origin:e});this.Ha=new Rg(this.Wd,[],c)}catch(f){this.f("Error instantiating WebSocket.");(c=f.message||f.data)&&this.f(c);this.ab();return}var g=
+this;this.Ha.onopen=function(){g.f("Websocket connected.");g.tc=!0};this.Ha.onclose=function(){g.f("Websocket connection was disconnected.");g.Ha=null;g.ab()};this.Ha.onmessage=function(a){if(null!==g.Ha)if(a=a.data,g.nb+=a.length,zb(g.Ua,"bytes_received",a.length),Ug(g),null!==g.frames)Vg(g,a);else{a:{I(null===g.frames,"We already have a frame buffer");if(6>=a.length){var b=Number(a);if(!isNaN(b)){g.Ce=b;g.frames=[];a=null;break a}}g.Ce=1;g.frames=[]}null!==a&&Vg(g,a)}};this.Ha.onerror=function(a){g.f("WebSocket error.  Closing connection.");
+(a=a.message||a.data)&&g.f(a);g.ab()}};Sg.prototype.start=function(){};Sg.isAvailable=function(){var a=!1;if("undefined"!==typeof navigator&&navigator.userAgent){var b=navigator.userAgent.match(/Android ([0-9]{0,}\.[0-9]{0,})/);b&&1<b.length&&4.4>parseFloat(b[1])&&(a=!0)}return!a&&null!==Rg&&!Tg};Sg.responsesRequiredToBeHealthy=2;Sg.healthyTimeout=3E4;h=Sg.prototype;h.pd=function(){Eb.remove("previous_websocket_failure")};
+function Vg(a,b){a.frames.push(b);if(a.frames.length==a.Ce){var c=a.frames.join("");a.frames=null;c=bb(c);a.Vf(c)}}h.send=function(a){Ug(this);a=w(a);this.ob+=a.length;zb(this.Ua,"bytes_sent",a.length);a=wc(a,16384);1<a.length&&Wg(this,String(a.length));for(var b=0;b<a.length;b++)Wg(this,a[b])};h.Qc=function(){this.yb=!0;this.wc&&(clearInterval(this.wc),this.wc=null);this.Ha&&(this.Ha.close(),this.Ha=null)};
+h.ab=function(){this.yb||(this.f("WebSocket is closing itself"),this.Qc(),this.gb&&(this.gb(this.tc),this.gb=null))};h.close=function(){this.yb||(this.f("WebSocket is being closed"),this.Qc())};function Ug(a){clearInterval(a.wc);a.wc=setInterval(function(){a.Ha&&Wg(a,"0");Ug(a)},Math.floor(45E3))}function Wg(a,b){try{a.Ha.send(b)}catch(c){a.f("Exception thrown from WebSocket.send():",c.message||c.data,"Closing connection."),setTimeout(q(a.ab,a),0)}};function Xg(a){Yg(this,a)}var Zg=[Fg,Sg];function Yg(a,b){var c=Sg&&Sg.isAvailable(),d=c&&!(Eb.We||!0===Eb.get("previous_websocket_failure"));b.rg&&(c||N("wss:// URL used, but browser isn't known to support websockets.  Trying anyway."),d=!0);if(d)a.Tc=[Sg];else{var e=a.Tc=[];xc(Zg,function(a,b){b&&b.isAvailable()&&e.push(b)})}}function $g(a){if(0<a.Tc.length)return a.Tc[0];throw Error("No transports available");};function ah(a,b,c,d,e,f,g){this.id=a;this.f=nc("c:"+this.id+":");this.qe=c;this.Ic=d;this.ia=e;this.pe=f;this.L=b;this.yd=[];this.He=0;this.rf=new Xg(b);this.Ta=0;this.Ab=g;this.f("Connection created");bh(this)}
+function bh(a){var b=$g(a.rf);a.I=new b("c:"+a.id+":"+a.He++,a.L,void 0,a.Ab);a.ue=b.responsesRequiredToBeHealthy||0;var c=ch(a,a.I),d=dh(a,a.I);a.Uc=a.I;a.Oc=a.I;a.D=null;a.zb=!1;setTimeout(function(){a.I&&a.I.open(c,d)},Math.floor(0));b=b.healthyTimeout||0;0<b&&(a.jd=Cc(function(){a.jd=null;a.zb||(a.I&&102400<a.I.nb?(a.f("Connection exceeded healthy timeout but has received "+a.I.nb+" bytes.  Marking connection healthy."),a.zb=!0,a.I.pd()):a.I&&10240<a.I.ob?a.f("Connection exceeded healthy timeout but has sent "+
+a.I.ob+" bytes.  Leaving connection alive."):(a.f("Closing unhealthy connection after timeout."),a.close()))},Math.floor(b)))}function dh(a,b){return function(c){b===a.I?(a.I=null,c||0!==a.Ta?1===a.Ta&&a.f("Realtime connection lost."):(a.f("Realtime connection failed."),"s-"===a.L.Za.substr(0,2)&&(Eb.remove("host:"+a.L.host),a.L.Za=a.L.host)),a.close()):b===a.D?(a.f("Secondary connection lost."),c=a.D,a.D=null,a.Uc!==c&&a.Oc!==c||a.close()):a.f("closing an old connection")}}
+function ch(a,b){return function(c){if(2!=a.Ta)if(b===a.Oc){var d=uc("t",c);c=uc("d",c);if("c"==d){if(d=uc("t",c),"d"in c)if(c=c.d,"h"===d){var d=c.ts,e=c.v,f=c.h;a.pf=c.s;Hb(a.L,f);0==a.Ta&&(a.I.start(),eh(a,a.I,d),"5"!==e&&N("Protocol version mismatch detected"),c=a.rf,(c=1<c.Tc.length?c.Tc[1]:null)&&fh(a,c))}else if("n"===d){a.f("recvd end transmission on primary");a.Oc=a.D;for(c=0;c<a.yd.length;++c)a.ud(a.yd[c]);a.yd=[];gh(a)}else"s"===d?(a.f("Connection shutdown command received. Shutting down..."),
+a.pe&&(a.pe(c),a.pe=null),a.ia=null,a.close()):"r"===d?(a.f("Reset packet received.  New host: "+c),Hb(a.L,c),1===a.Ta?a.close():(hh(a),bh(a))):"e"===d?oc("Server Error: "+c):"o"===d?(a.f("got pong on primary."),ih(a),jh(a)):oc("Unknown control packet command: "+d)}else"d"==d&&a.ud(c)}else if(b===a.D)if(d=uc("t",c),c=uc("d",c),"c"==d)"t"in c&&(c=c.t,"a"===c?kh(a):"r"===c?(a.f("Got a reset on secondary, closing it"),a.D.close(),a.Uc!==a.D&&a.Oc!==a.D||a.close()):"o"===c&&(a.f("got pong on secondary."),
+a.nf--,kh(a)));else if("d"==d)a.yd.push(c);else throw Error("Unknown protocol layer: "+d);else a.f("message on old connection")}}ah.prototype.ua=function(a){lh(this,{t:"d",d:a})};function gh(a){a.Uc===a.D&&a.Oc===a.D&&(a.f("cleaning up and promoting a connection: "+a.D.Vd),a.I=a.D,a.D=null)}
+function kh(a){0>=a.nf?(a.f("Secondary connection is healthy."),a.zb=!0,a.D.pd(),a.D.start(),a.f("sending client ack on secondary"),a.D.send({t:"c",d:{t:"a",d:{}}}),a.f("Ending transmission on primary"),a.I.send({t:"c",d:{t:"n",d:{}}}),a.Uc=a.D,gh(a)):(a.f("sending ping on secondary."),a.D.send({t:"c",d:{t:"p",d:{}}}))}ah.prototype.ud=function(a){ih(this);this.qe(a)};function ih(a){a.zb||(a.ue--,0>=a.ue&&(a.f("Primary connection is healthy."),a.zb=!0,a.I.pd()))}
+function fh(a,b){a.D=new b("c:"+a.id+":"+a.He++,a.L,a.pf);a.nf=b.responsesRequiredToBeHealthy||0;a.D.open(ch(a,a.D),dh(a,a.D));Cc(function(){a.D&&(a.f("Timed out trying to upgrade."),a.D.close())},Math.floor(6E4))}function eh(a,b,c){a.f("Realtime connection established.");a.I=b;a.Ta=1;a.Ic&&(a.Ic(c,a.pf),a.Ic=null);0===a.ue?(a.f("Primary connection is healthy."),a.zb=!0):Cc(function(){jh(a)},Math.floor(5E3))}
+function jh(a){a.zb||1!==a.Ta||(a.f("sending ping on primary."),lh(a,{t:"c",d:{t:"p",d:{}}}))}function lh(a,b){if(1!==a.Ta)throw"Connection is not connected";a.Uc.send(b)}ah.prototype.close=function(){2!==this.Ta&&(this.f("Closing realtime connection."),this.Ta=2,hh(this),this.ia&&(this.ia(),this.ia=null))};function hh(a){a.f("Shutting down all connections");a.I&&(a.I.close(),a.I=null);a.D&&(a.D.close(),a.D=null);a.jd&&(clearTimeout(a.jd),a.jd=null)};function mh(a,b,c,d,e,f){this.id=nh++;this.f=nc("p:"+this.id+":");this.nd={};this.$={};this.pa=[];this.Lc=0;this.Hc=[];this.ma=!1;this.Ra=1E3;this.qd=3E5;this.Eb=b;this.Gc=c;this.re=d;this.L=a;this.mb=this.Ea=this.Ab=this.we=null;this.Xc=e;this.$d=!1;this.ge=0;this.Rd=f;this.sb=null;this.Kb=!1;this.Ed={};this.ig=0;this.Oe=!0;this.xc=this.ie=null;oh(this,0);Le.Tb().dc("visible",this.Yf,this);-1===a.host.indexOf("fblocal")&&Bg.Tb().dc("online",this.Xf,this)}var nh=0,ph=0;h=mh.prototype;
+h.ua=function(a,b,c){var d=++this.ig;a={r:d,a:a,b:b};this.f(w(a));I(this.ma,"sendRequest call when we're not connected not allowed.");this.Ea.ua(a);c&&(this.Ed[d]=c)};h.Xe=function(a,b,c,d){var e=a.ja(),f=a.path.toString();this.f("Listen called for "+f+" "+e);this.$[f]=this.$[f]||{};I(Kc(a.m)||!X(a.m),"listen() called for non-default but complete query");I(!this.$[f][e],"listen() called twice for same path/queryId.");a={G:d,hd:b,eg:a,tag:c};this.$[f][e]=a;this.ma&&qh(this,a)};
+function qh(a,b){var c=b.eg,d=c.path.toString(),e=c.ja();a.f("Listen on "+d+" for "+e);var f={p:d};b.tag&&(f.q=xf(c.m),f.t=b.tag);f.h=b.hd();a.ua("q",f,function(f){var k=f.d,m=f.s;if(k&&"object"===typeof k&&cb(k,"w")){var l=y(k,"w");ea(l)&&0<=Ga(l,"no_index")&&N("Using an unspecified index. Consider adding "+('".indexOn": "'+c.m.g.toString()+'"')+" at "+c.path.toString()+" to your security rules for better performance")}(a.$[d]&&a.$[d][e])===b&&(a.f("listen response",f),"ok"!==m&&rh(a,d,e),b.G&&b.G(m,
+k))})}h.hf=function(a){this.mb=a;this.f("Auth token refreshed");this.mb?sh(this):this.ma&&this.ua("unauth",{},function(){});if(a&&40===a.length||Fc(a))this.f("Admin auth credential detected.  Reducing max reconnect time."),this.qd=3E4};function sh(a){if(a.ma&&a.mb){var b=a.mb,c=Ec(b)?"auth":"gauth",d={cred:b};null===a.Rd?d.noauth=!0:"object"===typeof a.Rd&&(d.authvar=a.Rd);a.ua(c,d,function(c){var d=c.s;c=c.d||"error";a.mb===b&&("ok"===d?a.ge=0:th(a,d,c))})}}
+h.tf=function(a,b){var c=a.path.toString(),d=a.ja();this.f("Unlisten called for "+c+" "+d);I(Kc(a.m)||!X(a.m),"unlisten() called for non-default but complete query");if(rh(this,c,d)&&this.ma){var e=xf(a.m);this.f("Unlisten on "+c+" for "+d);c={p:c};b&&(c.q=e,c.t=b);this.ua("n",c)}};h.oe=function(a,b,c){this.ma?uh(this,"o",a,b,c):this.Hc.push({te:a,action:"o",data:b,G:c})};h.bf=function(a,b,c){this.ma?uh(this,"om",a,b,c):this.Hc.push({te:a,action:"om",data:b,G:c})};
+h.vd=function(a,b){this.ma?uh(this,"oc",a,null,b):this.Hc.push({te:a,action:"oc",data:null,G:b})};function uh(a,b,c,d,e){c={p:c,d:d};a.f("onDisconnect "+b,c);a.ua(b,c,function(a){e&&setTimeout(function(){e(a.s,a.d)},Math.floor(0))})}h.put=function(a,b,c,d){vh(this,"p",a,b,c,d)};h.Ye=function(a,b,c,d){vh(this,"m",a,b,c,d)};function vh(a,b,c,d,e,f){d={p:c,d:d};n(f)&&(d.h=f);a.pa.push({action:b,kf:d,G:e});a.Lc++;b=a.pa.length-1;a.ma?wh(a,b):a.f("Buffering put: "+c)}
+function wh(a,b){var c=a.pa[b].action,d=a.pa[b].kf,e=a.pa[b].G;a.pa[b].fg=a.ma;a.ua(c,d,function(d){a.f(c+" response",d);delete a.pa[b];a.Lc--;0===a.Lc&&(a.pa=[]);e&&e(d.s,d.d)})}h.ve=function(a){this.ma&&(a={c:a},this.f("reportStats",a),this.ua("s",a,function(a){"ok"!==a.s&&this.f("reportStats","Error sending stats: "+a.d)}))};
+h.ud=function(a){if("r"in a){this.f("from server: "+w(a));var b=a.r,c=this.Ed[b];c&&(delete this.Ed[b],c(a.b))}else{if("error"in a)throw"A server-side error has occurred: "+a.error;"a"in a&&(b=a.a,a=a.b,this.f("handleServerMessage",b,a),"d"===b?this.Eb(a.p,a.d,!1,a.t):"m"===b?this.Eb(a.p,a.d,!0,a.t):"c"===b?xh(this,a.p,a.q):"ac"===b?th(this,a.s,a.d):"sd"===b?this.we?this.we(a):"msg"in a&&"undefined"!==typeof console&&console.log("FIREBASE: "+a.msg.replace("\n","\nFIREBASE: ")):oc("Unrecognized action received from server: "+
+w(b)+"\nAre you using the latest client?"))}};h.Ic=function(a,b){this.f("connection ready");this.ma=!0;this.xc=(new Date).getTime();this.re({serverTimeOffset:a-(new Date).getTime()});this.Ab=b;if(this.Oe){var c={};c["sdk.js."+firebase.SDK_VERSION.replace(/\./g,"-")]=1;Ag()?c["framework.cordova"]=1:"object"===typeof navigator&&"ReactNative"===navigator.product&&(c["framework.reactnative"]=1);this.ve(c)}yh(this);this.Oe=!1;this.Gc(!0)};
+function oh(a,b){I(!a.Ea,"Scheduling a connect when we're already connected/ing?");a.sb&&clearTimeout(a.sb);a.sb=setTimeout(function(){a.sb=null;zh(a)},Math.floor(b))}h.Yf=function(a){a&&!this.Kb&&this.Ra===this.qd&&(this.f("Window became visible.  Reducing delay."),this.Ra=1E3,this.Ea||oh(this,0));this.Kb=a};h.Xf=function(a){a?(this.f("Browser went online."),this.Ra=1E3,this.Ea||oh(this,0)):(this.f("Browser went offline.  Killing connection."),this.Ea&&this.Ea.close())};
+h.cf=function(){this.f("data client disconnected");this.ma=!1;this.Ea=null;for(var a=0;a<this.pa.length;a++){var b=this.pa[a];b&&"h"in b.kf&&b.fg&&(b.G&&b.G("disconnect"),delete this.pa[a],this.Lc--)}0===this.Lc&&(this.pa=[]);this.Ed={};Ah(this)&&(this.Kb?this.xc&&(3E4<(new Date).getTime()-this.xc&&(this.Ra=1E3),this.xc=null):(this.f("Window isn't visible.  Delaying reconnect."),this.Ra=this.qd,this.ie=(new Date).getTime()),a=Math.max(0,this.Ra-((new Date).getTime()-this.ie)),a*=Math.random(),this.f("Trying to reconnect in "+
+a+"ms"),oh(this,a),this.Ra=Math.min(this.qd,1.3*this.Ra));this.Gc(!1)};
+function zh(a){if(Ah(a)){a.f("Making a connection attempt");a.ie=(new Date).getTime();a.xc=null;var b=q(a.ud,a),c=q(a.Ic,a),d=q(a.cf,a),e=a.id+":"+ph++,f=a.Ab,g=!1,k=null,m=function(){k?k.close():(g=!0,d())};a.Ea={close:m,ua:function(a){I(k,"sendRequest call when we're not connected not allowed.");k.ua(a)}};var l=a.$d;a.$d=!1;a.Xc.getToken(l).then(function(l){g?C("getToken() completed but was canceled"):(C("getToken() completed. Creating connection."),a.mb=l&&l.accessToken,k=new ah(e,a.L,b,c,d,function(b){N(b+
+" ("+a.L.toString()+")");a.$a("server_kill")},f))}).then(null,function(b){a.f("Failed to get token: "+b);g||m()})}}h.$a=function(a){C("Interrupting connection for reason: "+a);this.nd[a]=!0;this.Ea?this.Ea.close():(this.sb&&(clearTimeout(this.sb),this.sb=null),this.ma&&this.cf())};h.hc=function(a){C("Resuming connection for reason: "+a);delete this.nd[a];Ea(this.nd)&&(this.Ra=1E3,this.Ea||oh(this,0))};
+function xh(a,b,c){c=c?Ja(c,function(a){return vc(a)}).join("$"):"default";(a=rh(a,b,c))&&a.G&&a.G("permission_denied")}function rh(a,b,c){b=(new J(b)).toString();var d;n(a.$[b])?(d=a.$[b][c],delete a.$[b][c],0===xa(a.$[b])&&delete a.$[b]):d=void 0;return d}
+function th(a,b,c){C("Auth token revoked: "+b+"/"+c);a.mb=null;a.$d=!0;a.Ea.close();"invalid_token"===b&&(a.ge++,3<=a.ge&&(a.Ra=3E4,a=a.Xc,b='Provided authentication credentials for the app named "'+a.lc.name+'" are invalid. This usually indicates your app was not initialized correctly. ',b="credential"in a.lc.options?b+'Make sure the "credential" property provided to initializeApp() is authorized to access the specified "databaseURL" and is from the correct project.':"serviceAccount"in a.lc.options?
+b+'Make sure the "serviceAccount" property provided to initializeApp() is authorized to access the specified "databaseURL" and is from the correct project.':b+'Make sure the "apiKey" and "databaseURL" properties provided to initializeApp() match the values provided for your app at https://console.firebase.google.com/.',N(b)))}
+function yh(a){sh(a);t(a.$,function(b){t(b,function(b){qh(a,b)})});for(var b=0;b<a.pa.length;b++)a.pa[b]&&wh(a,b);for(;a.Hc.length;)b=a.Hc.shift(),uh(a,b.action,b.te,b.data,b.G)}function Ah(a){var b;b=Bg.Tb().ec;return Ea(a.nd)&&b};var Y={Mf:function(){Gg=Tg=!0}};Y.forceLongPolling=Y.Mf;Y.Nf=function(){Hg=!0};Y.forceWebSockets=Y.Nf;Y.Tf=function(){return Sg.isAvailable()};Y.isWebSocketsAvailable=Y.Tf;Y.lg=function(a,b){a.u.Qa.we=b};Y.setSecurityDebugCallback=Y.lg;Y.ye=function(a,b){a.u.ye(b)};Y.stats=Y.ye;Y.ze=function(a,b){a.u.ze(b)};Y.statsIncrementCounter=Y.ze;Y.cd=function(a){return a.u.cd};Y.dataUpdateCount=Y.cd;Y.Sf=function(a,b){a.u.fe=b};Y.interceptServerData=Y.Sf;function Gd(a,b,c){this.app=c;var d=new nb(c);this.L=a;this.Ua=td(a);this.Sc=null;this.ca=new ef;this.td=1;this.Qa=null;if(b||0<=("object"===typeof window&&window.navigator&&window.navigator.userAgent||"").search(/googlebot|google webmaster tools|bingbot|yahoo! slurp|baiduspider|yandexbot|duckduckbot/i))this.va=new Ic(this.L,q(this.Eb,this),d),setTimeout(q(this.Gc,this,!0),0);else{b=c.options.databaseAuthVariableOverride;if("undefined"!==da(b)&&null!==b){if("object"!==da(b))throw Error("Only objects are supported for option databaseAuthVariableOverride");
+try{w(b)}catch(e){throw Error("Invalid authOverride provided: "+e);}}this.va=this.Qa=new mh(this.L,q(this.Eb,this),q(this.Gc,this),q(this.re,this),d,b)}var f=this;ob(d,function(a){f.va.hf(a)});this.og=ud(a,q(function(){return new qd(this.Ua,this.va)},this));this.jc=new pe;this.ee=new xb;this.md=new fg({xe:function(a,b,c,d){b=[];c=f.ee.j(a.path);c.e()||(b=hg(f.md,new rb(ne,a.path,c)),setTimeout(function(){d("ok")},0));return b},Ld:ba});Bh(this,"connected",!1);this.ia=new Nb;this.Xa=new Fd(this);this.cd=
+0;this.fe=null;this.K=new fg({xe:function(a,b,c,d){f.va.Xe(a,c,b,function(b,c){var e=d(b,c);kf(f.ca,a.path,e)});return[]},Ld:function(a,b){f.va.tf(a,b)}})}h=Gd.prototype;h.toString=function(){return(this.L.Pc?"https://":"http://")+this.L.host};h.name=function(){return this.L.me};function Ch(a){a=a.ee.j(new J(".info/serverTimeOffset")).H()||0;return(new Date).getTime()+a}function Dh(a){a=a={timestamp:Ch(a)};a.timestamp=a.timestamp||(new Date).getTime();return a}
+h.Eb=function(a,b,c,d){this.cd++;var e=new J(a);b=this.fe?this.fe(a,b):b;a=[];d?c?(b=va(b,function(a){return K(a)}),a=pg(this.K,e,b,d)):(b=K(b),a=lg(this.K,e,b,d)):c?(d=va(b,function(a){return K(a)}),a=kg(this.K,e,d)):(d=K(b),a=hg(this.K,new rb(ne,e,d)));d=e;0<a.length&&(d=Eh(this,e));kf(this.ca,d,a)};h.Gc=function(a){Bh(this,"connected",a);!1===a&&Fh(this)};h.re=function(a){var b=this;xc(a,function(a,d){Bh(b,d,a)})};
+function Bh(a,b,c){b=new J("/.info/"+b);c=K(c);var d=a.ee;d.Hd=d.Hd.F(b,c);c=hg(a.md,new rb(ne,b,c));kf(a.ca,b,c)}h.Hb=function(a,b,c,d){this.f("set",{path:a.toString(),value:b,xg:c});var e=Dh(this);b=K(b,c);var e=Qb(b,e),f=this.td++,e=gg(this.K,a,e,f,!0);ff(this.ca,e);var g=this;this.va.put(a.toString(),b.H(!0),function(b,c){var e="ok"===b;e||N("set at "+a+" failed: "+b);e=jg(g.K,f,!e);kf(g.ca,a,e);Gh(d,b,c)});e=Hh(this,a);Eh(this,e);kf(this.ca,e,[])};
+h.update=function(a,b,c){this.f("update",{path:a.toString(),value:b});var d=!0,e=Dh(this),f={};t(b,function(a,b){d=!1;var c=K(a);f[b]=Qb(c,e)});if(d)C("update() called with empty data.  Don't do anything."),Gh(c,"ok");else{var g=this.td++,k=ig(this.K,a,f,g);ff(this.ca,k);var m=this;this.va.Ye(a.toString(),b,function(b,d){var e="ok"===b;e||N("update at "+a+" failed: "+b);var e=jg(m.K,g,!e),f=a;0<e.length&&(f=Eh(m,a));kf(m.ca,f,e);Gh(c,b,d)});t(b,function(b,c){var d=Hh(m,a.n(c));Eh(m,d)});kf(this.ca,
+a,[])}};function Fh(a){a.f("onDisconnectEvents");var b=Dh(a),c=[];Ob(Mb(a.ia,b),D,function(b,e){c=c.concat(hg(a.K,new rb(ne,b,e)));var f=Hh(a,b);Eh(a,f)});a.ia=new Nb;kf(a.ca,D,c)}h.vd=function(a,b){var c=this;this.va.vd(a.toString(),function(d,e){"ok"===d&&Md(c.ia,a);Gh(b,d,e)})};function Ie(a,b,c,d){var e=K(c);a.va.oe(b.toString(),e.H(!0),function(c,g){"ok"===c&&Pb(a.ia,b,e);Gh(d,c,g)})}
+function Je(a,b,c,d,e){var f=K(c,d);a.va.oe(b.toString(),f.H(!0),function(c,d){"ok"===c&&Pb(a.ia,b,f);Gh(e,c,d)})}function Ke(a,b,c,d){var e=!0,f;for(f in c)e=!1;e?(C("onDisconnect().update() called with empty data.  Don't do anything."),Gh(d,"ok")):a.va.bf(b.toString(),c,function(e,f){if("ok"===e)for(var m in c){var l=K(c[m]);Pb(a.ia,b.n(m),l)}Gh(d,e,f)})}function vf(a,b,c){c=".info"===O(b.path)?a.md.Lb(b,c):a.K.Lb(b,c);hf(a.ca,b.path,c)}h.$a=function(){this.Qa&&this.Qa.$a("repo_interrupt")};
+h.hc=function(){this.Qa&&this.Qa.hc("repo_interrupt")};h.ye=function(a){if("undefined"!==typeof console){a?(this.Sc||(this.Sc=new Ab(this.Ua)),a=this.Sc.get()):a=this.Ua.get();var b=Ka(Aa(a),function(a,b){return Math.max(b.length,a)},0),c;for(c in a){for(var d=a[c],e=c.length;e<b+2;e++)c+=" ";console.log(c+d)}}};h.ze=function(a){zb(this.Ua,a);this.og.qf[a]=!0};h.f=function(a){var b="";this.Qa&&(b=this.Qa.id+":");C(b,arguments)};
+function Gh(a,b,c){a&&Ac(function(){if("ok"==b)a(null);else{var d=(b||"error").toUpperCase(),e=d;c&&(e+=": "+c);e=Error(e);e.code=d;a(e)}})};function Ih(a,b,c,d,e){function f(){}a.f("transaction on "+b);var g=new R(a,b);g.dc("value",f);c={path:b,update:c,G:d,status:null,df:fc(),Ee:e,mf:0,Nd:function(){g.Fc("value",f)},Pd:null,Ba:null,$c:null,ad:null,bd:null};d=a.K.Aa(b,void 0)||H;c.$c=d;d=c.update(d.H());if(n(d)){Ae("transaction failed: Data returned ",d,c.path);c.status=1;e=qe(a.jc,b);var k=e.Ca()||[];k.push(c);re(e,k);"object"===typeof d&&null!==d&&cb(d,".priority")?(k=y(d,".priority"),I(ye(k),"Invalid priority returned by transaction. Priority must be a valid string, finite number, server value, or null.")):
+k=(a.K.Aa(b)||H).C().H();e=Dh(a);d=K(d,k);e=Qb(d,e);c.ad=d;c.bd=e;c.Ba=a.td++;c=gg(a.K,b,e,c.Ba,c.Ee);kf(a.ca,b,c);Jh(a)}else c.Nd(),c.ad=null,c.bd=null,c.G&&(a=new T(c.$c,new R(a,c.path),L),c.G(null,!1,a))}function Jh(a,b){var c=b||a.jc;b||Kh(a,c);if(null!==c.Ca()){var d=Lh(a,c);I(0<d.length,"Sending zero length transaction queue");La(d,function(a){return 1===a.status})&&Mh(a,c.path(),d)}else c.gd()&&c.O(function(b){Jh(a,b)})}
+function Mh(a,b,c){for(var d=Ja(c,function(a){return a.Ba}),e=a.K.Aa(b,d)||H,d=e,e=e.hash(),f=0;f<c.length;f++){var g=c[f];I(1===g.status,"tryToSendTransactionQueue_: items in queue should all be run.");g.status=2;g.mf++;var k=Q(b,g.path),d=d.F(k,g.ad)}d=d.H(!0);a.va.put(b.toString(),d,function(d){a.f("transaction put response",{path:b.toString(),status:d});var e=[];if("ok"===d){d=[];for(f=0;f<c.length;f++){c[f].status=3;e=e.concat(jg(a.K,c[f].Ba));if(c[f].G){var g=c[f].bd,k=new R(a,c[f].path);d.push(q(c[f].G,
+null,null,!0,new T(g,k,L)))}c[f].Nd()}Kh(a,qe(a.jc,b));Jh(a);kf(a.ca,b,e);for(f=0;f<d.length;f++)Ac(d[f])}else{if("datastale"===d)for(f=0;f<c.length;f++)c[f].status=4===c[f].status?5:1;else for(N("transaction at "+b.toString()+" failed: "+d),f=0;f<c.length;f++)c[f].status=5,c[f].Pd=d;Eh(a,b)}},e)}function Eh(a,b){var c=Nh(a,b),d=c.path(),c=Lh(a,c);Oh(a,c,d);return d}
+function Oh(a,b,c){if(0!==b.length){for(var d=[],e=[],f=Ia(b,function(a){return 1===a.status}),f=Ja(f,function(a){return a.Ba}),g=0;g<b.length;g++){var k=b[g],m=Q(c,k.path),l=!1,r;I(null!==m,"rerunTransactionsUnderNode_: relativePath should not be null.");if(5===k.status)l=!0,r=k.Pd,e=e.concat(jg(a.K,k.Ba,!0));else if(1===k.status)if(25<=k.mf)l=!0,r="maxretry",e=e.concat(jg(a.K,k.Ba,!0));else{var x=a.K.Aa(k.path,f)||H;k.$c=x;var F=b[g].update(x.H());n(F)?(Ae("transaction failed: Data returned ",F,
+k.path),m=K(F),"object"===typeof F&&null!=F&&cb(F,".priority")||(m=m.fa(x.C())),x=k.Ba,F=Dh(a),F=Qb(m,F),k.ad=m,k.bd=F,k.Ba=a.td++,Oa(f,x),e=e.concat(gg(a.K,k.path,F,k.Ba,k.Ee)),e=e.concat(jg(a.K,x,!0))):(l=!0,r="nodata",e=e.concat(jg(a.K,k.Ba,!0)))}kf(a.ca,c,e);e=[];l&&(b[g].status=3,setTimeout(b[g].Nd,Math.floor(0)),b[g].G&&("nodata"===r?(k=new R(a,b[g].path),d.push(q(b[g].G,null,null,!1,new T(b[g].$c,k,L)))):d.push(q(b[g].G,null,Error(r),!1,null))))}Kh(a,a.jc);for(g=0;g<d.length;g++)Ac(d[g]);Jh(a)}}
+function Nh(a,b){for(var c,d=a.jc;null!==(c=O(b))&&null===d.Ca();)d=qe(d,c),b=E(b);return d}function Lh(a,b){var c=[];Ph(a,b,c);c.sort(function(a,b){return a.df-b.df});return c}function Ph(a,b,c){var d=b.Ca();if(null!==d)for(var e=0;e<d.length;e++)c.push(d[e]);b.O(function(b){Ph(a,b,c)})}function Kh(a,b){var c=b.Ca();if(c){for(var d=0,e=0;e<c.length;e++)3!==c[e].status&&(c[d]=c[e],d++);c.length=d;re(b,0<c.length?c:null)}b.O(function(b){Kh(a,b)})}
+function Hh(a,b){var c=Nh(a,b).path(),d=qe(a.jc,b);ue(d,function(b){Qh(a,b)});Qh(a,d);te(d,function(b){Qh(a,b)});return c}
+function Qh(a,b){var c=b.Ca();if(null!==c){for(var d=[],e=[],f=-1,g=0;g<c.length;g++)4!==c[g].status&&(2===c[g].status?(I(f===g-1,"All SENT items should be at beginning of queue."),f=g,c[g].status=4,c[g].Pd="set"):(I(1===c[g].status,"Unexpected transaction status in abort"),c[g].Nd(),e=e.concat(jg(a.K,c[g].Ba,!0)),c[g].G&&d.push(q(c[g].G,null,Error("set"),!1,null))));-1===f?re(b,null):c.length=f+1;kf(a.ca,b.path(),e);for(g=0;g<d.length;g++)Ac(d[g])}};function Ld(){this.jb={};this.uf=!1}Ld.prototype.$a=function(){for(var a in this.jb)this.jb[a].$a()};Ld.prototype.hc=function(){for(var a in this.jb)this.jb[a].hc()};Ld.prototype.Zd=function(a){this.uf=a};ca(Ld);Ld.prototype.interrupt=Ld.prototype.$a;Ld.prototype.resume=Ld.prototype.hc;var Z={};Z.kc=mh;Z.DataConnection=Z.kc;mh.prototype.ng=function(a,b){this.ua("q",{p:a},b)};Z.kc.prototype.simpleListen=Z.kc.prototype.ng;mh.prototype.Hf=function(a,b){this.ua("echo",{d:a},b)};Z.kc.prototype.echo=Z.kc.prototype.Hf;mh.prototype.interrupt=mh.prototype.$a;Z.yf=ah;Z.RealTimeConnection=Z.yf;ah.prototype.sendRequest=ah.prototype.ua;ah.prototype.close=ah.prototype.close;
+Z.Rf=function(a){var b=mh.prototype.put;mh.prototype.put=function(c,d,e,f){n(f)&&(f=a());b.call(this,c,d,e,f)};return function(){mh.prototype.put=b}};Z.hijackHash=Z.Rf;Z.xf=Gb;Z.ConnectionTarget=Z.xf;Z.ja=function(a){return a.ja()};Z.queryIdentifier=Z.ja;Z.Uf=function(a){return a.u.Qa.$};Z.listens=Z.Uf;Z.Zd=function(a){Ld.Tb().Zd(a)};Z.forceRestClient=Z.Zd;Z.Context=Ld;function R(a,b){if(!(a instanceof Gd))throw Error("new Firebase() no longer supported - use app.database().");W.call(this,a,b,Ef,!1);this.then=void 0;this["catch"]=void 0}la(R,W);h=R.prototype;h.getKey=function(){z("Firebase.key",0,0,arguments.length);return this.path.e()?null:Bd(this.path)};
+h.n=function(a){z("Firebase.child",1,1,arguments.length);if(ga(a))a=String(a);else if(!(a instanceof J))if(null===O(this.path)){var b=a;b&&(b=b.replace(/^\/*\.info(\/|$)/,"/"));Ge("Firebase.child",b)}else Ge("Firebase.child",a);return new R(this.u,this.path.n(a))};h.getParent=function(){z("Firebase.parent",0,0,arguments.length);var a=this.path.parent();return null===a?null:new R(this.u,a)};
+h.Of=function(){z("Firebase.ref",0,0,arguments.length);for(var a=this;null!==a.getParent();)a=a.getParent();return a};h.Gf=function(){return this.u.Xa};h.set=function(a,b){z("Firebase.set",1,2,arguments.length);He("Firebase.set",this.path);ze("Firebase.set",a,this.path,!1);B("Firebase.set",2,b,!0);var c=new fb;this.u.Hb(this.path,a,null,gb(c,b));return c.ra};
+h.update=function(a,b){z("Firebase.update",1,2,arguments.length);He("Firebase.update",this.path);if(ea(a)){for(var c={},d=0;d<a.length;++d)c[""+d]=a[d];a=c;N("Passing an Array to Firebase.update() is deprecated. Use set() if you want to overwrite the existing data, or an Object with integer keys if you really do want to only update some of the children.")}Ce("Firebase.update",a,this.path);B("Firebase.update",2,b,!0);c=new fb;this.u.update(this.path,a,gb(c,b));return c.ra};
+h.Hb=function(a,b,c){z("Firebase.setWithPriority",2,3,arguments.length);He("Firebase.setWithPriority",this.path);ze("Firebase.setWithPriority",a,this.path,!1);De("Firebase.setWithPriority",2,b);B("Firebase.setWithPriority",3,c,!0);if(".length"===this.getKey()||".keys"===this.getKey())throw"Firebase.setWithPriority failed: "+this.getKey()+" is a read-only object.";var d=new fb;this.u.Hb(this.path,a,b,gb(d,c));return d.ra};
+h.remove=function(a){z("Firebase.remove",0,1,arguments.length);He("Firebase.remove",this.path);B("Firebase.remove",1,a,!0);return this.set(null,a)};
+h.transaction=function(a,b,c){z("Firebase.transaction",1,3,arguments.length);He("Firebase.transaction",this.path);B("Firebase.transaction",1,a,!1);B("Firebase.transaction",2,b,!0);if(n(c)&&"boolean"!=typeof c)throw Error(A("Firebase.transaction",3,!0)+"must be a boolean.");if(".length"===this.getKey()||".keys"===this.getKey())throw"Firebase.transaction failed: "+this.getKey()+" is a read-only object.";"undefined"===typeof c&&(c=!0);var d=new fb;ha(b)&&hb(d.ra);Ih(this.u,this.path,a,function(a,c,g){a?
+d.reject(a):d.resolve(new mb(c,g));ha(b)&&b(a,c,g)},c);return d.ra};h.kg=function(a,b){z("Firebase.setPriority",1,2,arguments.length);He("Firebase.setPriority",this.path);De("Firebase.setPriority",1,a);B("Firebase.setPriority",2,b,!0);var c=new fb;this.u.Hb(this.path.n(".priority"),a,null,gb(c,b));return c.ra};
+h.push=function(a,b){z("Firebase.push",0,2,arguments.length);He("Firebase.push",this.path);ze("Firebase.push",a,this.path,!0);B("Firebase.push",2,b,!0);var c=Ch(this.u),d=zd(c),c=this.n(d);if(null!=a){var e=this,f=c.set(a,b).then(function(){return e.n(d)});c.then=q(f.then,f);c["catch"]=q(f.then,f,void 0);ha(b)&&hb(f)}return c};h.gb=function(){He("Firebase.onDisconnect",this.path);return new U(this.u,this.path)};R.prototype.child=R.prototype.n;R.prototype.set=R.prototype.set;R.prototype.update=R.prototype.update;
+R.prototype.setWithPriority=R.prototype.Hb;R.prototype.remove=R.prototype.remove;R.prototype.transaction=R.prototype.transaction;R.prototype.setPriority=R.prototype.kg;R.prototype.push=R.prototype.push;R.prototype.onDisconnect=R.prototype.gb;Bc(R.prototype,"database",R.prototype.Gf);Bc(R.prototype,"key",R.prototype.getKey);Bc(R.prototype,"parent",R.prototype.getParent);Bc(R.prototype,"root",R.prototype.Of);if("undefined"===typeof firebase)throw Error("Cannot install Firebase Database - be sure to load firebase-app.js first.");
+try{var Rh=firebase.INTERNAL.registerService("database",function(a){var b=Ld.Tb(),c=a.options.databaseURL;n(c)||pc("Can't determine Firebase Database URL.  Be sure to include databaseURL option when calling firebase.intializeApp().");var d=qc(c),c=d.gc;Kd("Invalid Firebase Database URL",d);d.path.e()||pc("Database URL must point to the root of a Firebase Database (not including a child path).");(d=y(b.jb,a.name))&&pc("FIREBASE INTERNAL ERROR: Database initialized multiple times.");d=new Gd(c,b.uf,
+a);b.jb[a.name]=d;return d.Xa},{Reference:R,Query:W,Database:Fd,enableLogging:mc,INTERNAL:Y,TEST_ACCESS:Z,ServerValue:Id});module.exports=Rh}catch(Sh){pc("Failed to register the Firebase Database Service ("+Sh+")")};
+})();
+
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/default-namespace.d.ts b/KEMMessaging/node_modules/firebase-admin/lib/default-namespace.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3746edc3a4a290e9a8e3b35a3dc315afb5661f52
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/default-namespace.d.ts
@@ -0,0 +1,5 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+import { FirebaseNamespace } from './firebase-namespace';
+declare let firebaseAdmin: FirebaseNamespace;
+export = firebaseAdmin;
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/default-namespace.js b/KEMMessaging/node_modules/firebase-admin/lib/default-namespace.js
new file mode 100644
index 0000000000000000000000000000000000000000..d0a8123064ae82ffe74d8a363486ef33964f69b9
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/default-namespace.js
@@ -0,0 +1,16 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+"use strict";
+var firebase_namespace_1 = require('./firebase-namespace');
+var firebaseAdmin = new firebase_namespace_1.FirebaseNamespace();
+// Inject a circular default export to allow users to use both:
+//
+//   import firebaseAdmin from 'firebase-admin';
+//   which becomes: var firebaseAdmin = require('firebase-admin').default;
+//
+// as well as the more correct:
+//
+//   import * as firebaseAdmin from 'firebase-admin';
+//   which becomes: var firebaseAdmin = require('firebase-admin');
+firebaseAdmin.default = firebaseAdmin;
+module.exports = firebaseAdmin;
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/firebase-app.d.ts b/KEMMessaging/node_modules/firebase-admin/lib/firebase-app.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..69fe96e5c57337bd5afd5ffd50c50ca506e784ec
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/firebase-app.d.ts
@@ -0,0 +1,81 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+/// <reference types="chai" />
+import { Credential } from './auth/credential';
+import { FirebaseAccessToken } from './auth/auth';
+import { FirebaseServiceInterface } from './firebase-service';
+import { FirebaseNamespaceInternals } from './firebase-namespace';
+/**
+ * Type representing a callback which is called every time an app lifecycle event occurs.
+ */
+export declare type AppHook = (event: string, app: FirebaseApp) => void;
+/**
+ * Type representing the options object passed into initializeApp().
+ */
+export declare type FirebaseAppOptions = {
+    databaseURL?: string;
+    credential?: Credential;
+    serviceAccount?: string | Object;
+    databaseAuthVariableOverride?: Object;
+};
+/**
+ * Interface representing the internals of a FirebaseApp instance.
+ */
+export interface FirebaseAppInternalsInterface {
+    getToken?(): Promise<FirebaseAccessToken>;
+    addAuthTokenListener?(fn: (token?: string) => void): void;
+    removeAuthTokenListener?(fn: (token?: string) => void): void;
+}
+/**
+ * Global context object for a collection of services using a shared authentication state.
+ */
+export declare class FirebaseApp {
+    private firebaseInternals_;
+    INTERNAL: FirebaseAppInternalsInterface;
+    private name_;
+    private options_;
+    private services_;
+    private isDeleted_;
+    constructor(options: FirebaseAppOptions, name: string, firebaseInternals_: FirebaseNamespaceInternals);
+    /**
+     * Firebase services available off of a FirebaseApp instance. These are monkey-patched via
+     * registerService(), but we need to include a dummy implementation to get TypeScript to
+     * compile it without errors.
+     */
+    auth(): FirebaseServiceInterface;
+    database(): FirebaseServiceInterface;
+    /**
+     * Returns the name of the FirebaseApp instance.
+     *
+     * @returns {string} The name of the FirebaseApp instance.
+     */
+    readonly name: string;
+    /**
+     * Returns the options for the FirebaseApp instance.
+     *
+     * @returns {FirebaseAppOptions} The options for the FirebaseApp instance.
+     */
+    readonly options: FirebaseAppOptions;
+    /**
+     * Deletes the FirebaseApp instance.
+     *
+     * @returns {Promise<void>} An empty Promise fulfilled once the FirebaseApp instance is deleted.
+     */
+    delete(): Promise<void>;
+    /**
+     * Returns the service instance associated with this FirebaseApp instance (creating it on demand
+     * if needed).
+     *
+     * @param {string} serviceName The name of the service instance to return.
+     * @return {FirebaseServiceInterface} The service instance with the provided name.
+     */
+    private getService_(serviceName);
+    /**
+     * Callback function used to extend an App instance at the time of service instance creation.
+     */
+    private extendApp_(props);
+    /**
+     * Throws an Error if the FirebaseApp instance has already been deleted.
+     */
+    private checkDestroyed_();
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/firebase-app.js b/KEMMessaging/node_modules/firebase-admin/lib/firebase-app.js
new file mode 100644
index 0000000000000000000000000000000000000000..0a1ba49fe20041b5c5e3f49138144066c19ff055
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/firebase-app.js
@@ -0,0 +1,131 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+"use strict";
+var deep_copy_1 = require('./utils/deep-copy');
+/**
+ * Global context object for a collection of services using a shared authentication state.
+ */
+var FirebaseApp = (function () {
+    function FirebaseApp(options, name, firebaseInternals_) {
+        var _this = this;
+        this.firebaseInternals_ = firebaseInternals_;
+        this.services_ = {};
+        this.isDeleted_ = false;
+        this.name_ = name;
+        this.options_ = deep_copy_1.deepCopy(options);
+        if (typeof this.options_ !== 'object' || this.options_ === null) {
+            // Ensure the options are a non-null object
+            this.options_ = {};
+        }
+        var hasCredential = ('credential' in this.options_);
+        var hasServiceAccount = ('serviceAccount' in this.options_);
+        var errorMessage;
+        if (!hasCredential && !hasServiceAccount) {
+            errorMessage = 'Options must be an object containing at least a "credential" property.';
+        }
+        else if (hasCredential && hasServiceAccount) {
+            errorMessage = 'Options cannot specify both the "credential" and "serviceAccount" properties.';
+        }
+        // TODO(jwenger): NEXT MAJOR RELEASE - throw error if the "credential" property is not specified
+        if (typeof errorMessage !== 'undefined') {
+            throw new Error("Invalid Firebase app options passed as the first argument to initializeApp() for the " +
+                ("app named \"" + this.name_ + "\". " + errorMessage));
+        }
+        // TODO(jwenger): NEXT MAJOR RELEASE - remove "serviceAccount" property deprecation warning
+        if (hasServiceAccount) {
+            /* tslint:disable:no-console */
+            console.log('WARNING: The "serviceAccount" property specified in the first argument to initializeApp() ' +
+                'is deprecated and will be removed in the next major version. You should instead use the ' +
+                '"credential" property.');
+        }
+        Object.keys(firebaseInternals_.serviceFactories).forEach(function (serviceName) {
+            // Defer calling createService() until the service is accessed
+            _this[serviceName] = _this.getService_.bind(_this, serviceName);
+        });
+    }
+    /**
+     * Firebase services available off of a FirebaseApp instance. These are monkey-patched via
+     * registerService(), but we need to include a dummy implementation to get TypeScript to
+     * compile it without errors.
+     */
+    /* istanbul ignore next */
+    FirebaseApp.prototype.auth = function () {
+        throw new Error('INTERNAL ASSERT FAILED: Firebase auth() service has not been registered.');
+    };
+    /* istanbul ignore next */
+    FirebaseApp.prototype.database = function () {
+        throw new Error('INTERNAL ASSERT FAILED: Firebase database() service has not been registered.');
+    };
+    Object.defineProperty(FirebaseApp.prototype, "name", {
+        /**
+         * Returns the name of the FirebaseApp instance.
+         *
+         * @returns {string} The name of the FirebaseApp instance.
+         */
+        get: function () {
+            this.checkDestroyed_();
+            return this.name_;
+        },
+        enumerable: true,
+        configurable: true
+    });
+    Object.defineProperty(FirebaseApp.prototype, "options", {
+        /**
+         * Returns the options for the FirebaseApp instance.
+         *
+         * @returns {FirebaseAppOptions} The options for the FirebaseApp instance.
+         */
+        get: function () {
+            this.checkDestroyed_();
+            return deep_copy_1.deepCopy(this.options_);
+        },
+        enumerable: true,
+        configurable: true
+    });
+    /**
+     * Deletes the FirebaseApp instance.
+     *
+     * @returns {Promise<void>} An empty Promise fulfilled once the FirebaseApp instance is deleted.
+     */
+    FirebaseApp.prototype.delete = function () {
+        var _this = this;
+        this.checkDestroyed_();
+        this.firebaseInternals_.removeApp(this.name_);
+        return Promise.all(Object.keys(this.services_).map(function (serviceName) {
+            return _this.services_[serviceName].INTERNAL.delete();
+        })).then(function () {
+            _this.services_ = {};
+            _this.isDeleted_ = true;
+        });
+    };
+    /**
+     * Returns the service instance associated with this FirebaseApp instance (creating it on demand
+     * if needed).
+     *
+     * @param {string} serviceName The name of the service instance to return.
+     * @return {FirebaseServiceInterface} The service instance with the provided name.
+     */
+    FirebaseApp.prototype.getService_ = function (serviceName) {
+        this.checkDestroyed_();
+        if (!(serviceName in this.services_)) {
+            this.services_[serviceName] = this.firebaseInternals_.serviceFactories[serviceName](this, this.extendApp_.bind(this));
+        }
+        return this.services_[serviceName];
+    };
+    /**
+     * Callback function used to extend an App instance at the time of service instance creation.
+     */
+    FirebaseApp.prototype.extendApp_ = function (props) {
+        deep_copy_1.deepExtend(this, props);
+    };
+    /**
+     * Throws an Error if the FirebaseApp instance has already been deleted.
+     */
+    FirebaseApp.prototype.checkDestroyed_ = function () {
+        if (this.isDeleted_) {
+            throw new Error("Firebase app named \"" + this.name_ + "\" has already been deleted.");
+        }
+    };
+    return FirebaseApp;
+}());
+exports.FirebaseApp = FirebaseApp;
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/firebase-namespace.d.ts b/KEMMessaging/node_modules/firebase-admin/lib/firebase-namespace.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d4cf9dda64f9d0b6456b76928f0951b1a1150555
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/firebase-namespace.d.ts
@@ -0,0 +1,85 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+/// <reference types="chai" />
+import { AppHook, FirebaseApp, FirebaseAppOptions } from './firebase-app';
+import { FirebaseServiceFactory, FirebaseServiceInterface } from './firebase-service';
+import { Credential } from './auth/credential';
+export interface FirebaseServiceNamespace<T extends FirebaseServiceInterface> {
+    (app?: FirebaseApp): T;
+}
+export declare class FirebaseNamespaceInternals {
+    firebase_: any;
+    serviceFactories: {
+        [serviceName: string]: FirebaseServiceFactory;
+    };
+    private apps_;
+    private appHooks_;
+    constructor(firebase_: any);
+    /**
+     * Initializes the FirebaseApp instance.
+     *
+     * @param {FirebaseAppOptions} options Options for the FirebaseApp instance.
+     * @param {string} [appName] Optional name of the FirebaseApp instance.
+     *
+     * @return {FirebaseApp} A new FirebaseApp instance.
+     */
+    initializeApp(options: FirebaseAppOptions, appName?: string): FirebaseApp;
+    /**
+     * Returns the FirebaseApp instance with the provided name (or the default FirebaseApp instance
+     * if no name is provided).
+     *
+     * @param {string} [appName=DEFAULT_APP_NAME] Optional name of the FirebaseApp instance to return.
+     * @return {FirebaseApp} The FirebaseApp instance which has the provided name.
+     */
+    app(appName?: string): FirebaseApp;
+    readonly apps: FirebaseApp[];
+    removeApp(appName: string): void;
+    registerService(serviceName: string, createService: FirebaseServiceFactory, serviceProperties?: Object, appHook?: AppHook): FirebaseServiceNamespace<FirebaseServiceInterface>;
+    /**
+     * Calls the app hooks corresponding to the provided event name for each service within the
+     * provided FirebaseApp instance.
+     *
+     * @param {FirebaseApp} app The FirebaseApp instance whose app hooks to call.
+     * @param {string} eventName The event name representing which app hooks to call.
+     */
+    private callAppHooks_(app, eventName);
+}
+/**
+ * Global Firebase context object.
+ */
+export declare class FirebaseNamespace {
+    credential: {
+        cert: (serviceAccountPathOrObject: string | Object) => Credential;
+        refreshToken: (refreshTokenPathOrObject: string | Object) => Credential;
+        applicationDefault: () => Credential;
+    };
+    SDK_VERSION: string;
+    INTERNAL: FirebaseNamespaceInternals;
+    Promise: any;
+    constructor();
+    /**
+     * Firebase services available off of a FirebaseNamespace instance. These are monkey-patched via
+     * registerService(), but we need to include a dummy implementation to get TypeScript to
+     * compile it without errors.
+     */
+    auth(): FirebaseServiceInterface;
+    database(): FirebaseServiceInterface;
+    /**
+     * Initializes the FirebaseApp instance.
+     *
+     * @param {FirebaseAppOptions} options Options for the FirebaseApp instance.
+     * @param {string} [appName] Optional name of the FirebaseApp instance.
+     *
+     * @return {FirebaseApp} A new FirebaseApp instance.
+     */
+    initializeApp(options: FirebaseAppOptions, appName?: string): FirebaseApp;
+    /**
+     * Returns the FirebaseApp instance with the provided name (or the default FirebaseApp instance
+     * if no name is provided).
+     *
+     * @param {string} [appName] Optional name of the FirebaseApp instance to return.
+     * @return {FirebaseApp} The FirebaseApp instance which has the provided name.
+     */
+    app(appName?: string): FirebaseApp;
+    readonly apps: FirebaseApp[];
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/firebase-namespace.js b/KEMMessaging/node_modules/firebase-admin/lib/firebase-namespace.js
new file mode 100644
index 0000000000000000000000000000000000000000..cc86cbb613a2fc85f9029c564b6da3b8582d6066
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/firebase-namespace.js
@@ -0,0 +1,246 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+"use strict";
+var deep_copy_1 = require('./utils/deep-copy');
+var firebase_app_1 = require('./firebase-app');
+var credential_1 = require('./auth/credential');
+var DEFAULT_APP_NAME = '[DEFAULT]';
+var globalAppDefaultCred;
+var globalCertCreds = {};
+var globalRefreshTokenCreds = {};
+var FirebaseNamespaceInternals = (function () {
+    function FirebaseNamespaceInternals(firebase_) {
+        this.firebase_ = firebase_;
+        this.serviceFactories = {};
+        this.apps_ = {};
+        this.appHooks_ = {};
+    }
+    /**
+     * Initializes the FirebaseApp instance.
+     *
+     * @param {FirebaseAppOptions} options Options for the FirebaseApp instance.
+     * @param {string} [appName] Optional name of the FirebaseApp instance.
+     *
+     * @return {FirebaseApp} A new FirebaseApp instance.
+     */
+    FirebaseNamespaceInternals.prototype.initializeApp = function (options, appName) {
+        if (appName === void 0) { appName = DEFAULT_APP_NAME; }
+        if (typeof appName !== 'string' || appName === '') {
+            throw new Error("Illegal Firebase app name \"" + appName + "\" provided. App name must be a non-empty string.");
+        }
+        else if (appName in this.apps_) {
+            if (appName === DEFAULT_APP_NAME) {
+                throw new Error('The default Firebase app already exists. This means you called initializeApp() ' +
+                    'more than once without providing an app name as the second argument. In most cases ' +
+                    'you only need to call initializeApp() once. But if you do want to initialize ' +
+                    'multiple apps, pass a second argument to initializeApp() to give each app a unique ' +
+                    'name.');
+            }
+            else {
+                throw new Error(("Firebase app named \"" + appName + "\" already exists. This means you called initializeApp() ") +
+                    'more than once with the same app name as the second argument. Make sure you provide a ' +
+                    'unique name every time you call initializeApp().');
+            }
+        }
+        var app = new firebase_app_1.FirebaseApp(options, appName, this);
+        this.apps_[appName] = app;
+        this.callAppHooks_(app, 'create');
+        return app;
+    };
+    /**
+     * Returns the FirebaseApp instance with the provided name (or the default FirebaseApp instance
+     * if no name is provided).
+     *
+     * @param {string} [appName=DEFAULT_APP_NAME] Optional name of the FirebaseApp instance to return.
+     * @return {FirebaseApp} The FirebaseApp instance which has the provided name.
+     */
+    FirebaseNamespaceInternals.prototype.app = function (appName) {
+        if (appName === void 0) { appName = DEFAULT_APP_NAME; }
+        if (typeof appName !== 'string' || appName === '') {
+            throw new Error("Illegal Firebase app name \"" + appName + "\" provided. App name must be a non-empty string.");
+        }
+        else if (!(appName in this.apps_)) {
+            var errorMessage = void 0;
+            if (appName === DEFAULT_APP_NAME) {
+                errorMessage = 'The default Firebase app does not exist. ';
+            }
+            else {
+                errorMessage = "Firebase app named \"" + appName + "\" does not exist. ";
+            }
+            errorMessage += 'Make sure you call initializeApp() before using any of the Firebase services.';
+            throw new Error(errorMessage);
+        }
+        return this.apps_[appName];
+    };
+    Object.defineProperty(FirebaseNamespaceInternals.prototype, "apps", {
+        /*
+         * Returns an array of all the non-deleted FirebaseApp instances.
+         *
+         * @return {Array<FirebaseApp>} An array of all the non-deleted FirebaseApp instances
+         */
+        get: function () {
+            var _this = this;
+            // Return a copy so the caller cannot mutate the array
+            return Object.keys(this.apps_).map(function (appName) { return _this.apps_[appName]; });
+        },
+        enumerable: true,
+        configurable: true
+    });
+    /*
+     * Removes the specified FirebaseApp instance.
+     *
+     * @param {string} appName The name of the FirebaseApp instance to remove.
+     */
+    FirebaseNamespaceInternals.prototype.removeApp = function (appName) {
+        if (typeof appName === 'undefined') {
+            throw new Error("No Firebase app name provided. App name must be a non-empty string.");
+        }
+        var appToRemove = this.app(appName);
+        this.callAppHooks_(appToRemove, 'delete');
+        delete this.apps_[appName];
+    };
+    /*
+     * Registers a new service on this Firebase namespace.
+     *
+     * @param {string} serviceName The name of the Firebase service to register.
+     * @param {FirebaseServiceFactory} createService A factory method to generate an instance of the Firebase service.
+     * @param {Object} [serviceProperties] Optional properties to extend this Firebase namespace with.
+     * @param {AppHook} [appHook] Optional callback that handles app-related events like app creation and deletion.
+     * @return {FirebaseServiceNamespace<FirebaseServiceInterface>} The Firebase service's namespace.
+     */
+    FirebaseNamespaceInternals.prototype.registerService = function (serviceName, createService, serviceProperties, appHook) {
+        var _this = this;
+        if (typeof serviceName === 'undefined') {
+            throw new Error("No service name provided. Service name must be a non-empty string.");
+        }
+        else if (typeof serviceName !== 'string' || serviceName === '') {
+            throw new Error("Illegal service name \"" + serviceName + "\" provided. Service name must be a non-empty string.");
+        }
+        else if (serviceName in this.serviceFactories) {
+            throw new Error("Firebase service named \"" + serviceName + "\" has already been registered.");
+        }
+        this.serviceFactories[serviceName] = createService;
+        if (appHook) {
+            this.appHooks_[serviceName] = appHook;
+        }
+        var serviceNamespace;
+        // The service namespace is an accessor function which takes a FirebaseApp instance
+        // or uses the default app if no FirebaseApp instance is provided
+        serviceNamespace = function (appArg) {
+            if (typeof appArg === 'undefined') {
+                appArg = _this.app();
+            }
+            // Forward service instance lookup to the FirebaseApp
+            return appArg[serviceName]();
+        };
+        // ... and a container for service-level properties.
+        if (serviceProperties !== undefined) {
+            deep_copy_1.deepExtend(serviceNamespace, serviceProperties);
+        }
+        // Monkey-patch the service namespace onto the Firebase namespace
+        this.firebase_[serviceName] = serviceNamespace;
+        return serviceNamespace;
+    };
+    /**
+     * Calls the app hooks corresponding to the provided event name for each service within the
+     * provided FirebaseApp instance.
+     *
+     * @param {FirebaseApp} app The FirebaseApp instance whose app hooks to call.
+     * @param {string} eventName The event name representing which app hooks to call.
+     */
+    FirebaseNamespaceInternals.prototype.callAppHooks_ = function (app, eventName) {
+        var _this = this;
+        Object.keys(this.serviceFactories).forEach(function (serviceName) {
+            if (_this.appHooks_[serviceName]) {
+                _this.appHooks_[serviceName](eventName, app);
+            }
+        });
+    };
+    return FirebaseNamespaceInternals;
+}());
+exports.FirebaseNamespaceInternals = FirebaseNamespaceInternals;
+var firebaseCredential = {
+    cert: function (serviceAccountPathOrObject) {
+        var stringifiedServiceAccount = JSON.stringify(serviceAccountPathOrObject);
+        if (!(stringifiedServiceAccount in globalCertCreds)) {
+            globalCertCreds[stringifiedServiceAccount] = new credential_1.CertCredential(serviceAccountPathOrObject);
+        }
+        return globalCertCreds[stringifiedServiceAccount];
+    },
+    refreshToken: function (refreshTokenPathOrObject) {
+        var stringifiedRefreshToken = JSON.stringify(refreshTokenPathOrObject);
+        if (!(stringifiedRefreshToken in globalRefreshTokenCreds)) {
+            globalRefreshTokenCreds[stringifiedRefreshToken] = new credential_1.RefreshTokenCredential(refreshTokenPathOrObject);
+        }
+        return globalRefreshTokenCreds[stringifiedRefreshToken];
+    },
+    applicationDefault: function () {
+        if (typeof globalAppDefaultCred === 'undefined') {
+            globalAppDefaultCred = new credential_1.ApplicationDefaultCredential();
+        }
+        return globalAppDefaultCred;
+    },
+};
+/**
+ * Global Firebase context object.
+ */
+var FirebaseNamespace = (function () {
+    /* tslint:enable */
+    function FirebaseNamespace() {
+        this.credential = firebaseCredential;
+        this.SDK_VERSION = '4.0.3';
+        /* tslint:disable */
+        // TODO(jwenger): Database is the only consumer of firebase.Promise. We should update it to use
+        // use the native Promise and then remove this.
+        this.Promise = Promise;
+        this.INTERNAL = new FirebaseNamespaceInternals(this);
+    }
+    /**
+     * Firebase services available off of a FirebaseNamespace instance. These are monkey-patched via
+     * registerService(), but we need to include a dummy implementation to get TypeScript to
+     * compile it without errors.
+     */
+    /* istanbul ignore next */
+    FirebaseNamespace.prototype.auth = function () {
+        throw new Error('INTERNAL ASSERT FAILED: Firebase auth() service has not been registered.');
+    };
+    /* istanbul ignore next */
+    FirebaseNamespace.prototype.database = function () {
+        throw new Error('INTERNAL ASSERT FAILED: Firebase database() service has not been registered.');
+    };
+    /**
+     * Initializes the FirebaseApp instance.
+     *
+     * @param {FirebaseAppOptions} options Options for the FirebaseApp instance.
+     * @param {string} [appName] Optional name of the FirebaseApp instance.
+     *
+     * @return {FirebaseApp} A new FirebaseApp instance.
+     */
+    FirebaseNamespace.prototype.initializeApp = function (options, appName) {
+        return this.INTERNAL.initializeApp(options, appName);
+    };
+    /**
+     * Returns the FirebaseApp instance with the provided name (or the default FirebaseApp instance
+     * if no name is provided).
+     *
+     * @param {string} [appName] Optional name of the FirebaseApp instance to return.
+     * @return {FirebaseApp} The FirebaseApp instance which has the provided name.
+     */
+    FirebaseNamespace.prototype.app = function (appName) {
+        return this.INTERNAL.app(appName);
+    };
+    Object.defineProperty(FirebaseNamespace.prototype, "apps", {
+        /*
+         * Returns an array of all the non-deleted FirebaseApp instances.
+         *
+         * @return {Array<FirebaseApp>} An array of all the non-deleted FirebaseApp instances
+         */
+        get: function () {
+            return this.INTERNAL.apps;
+        },
+        enumerable: true,
+        configurable: true
+    });
+    return FirebaseNamespace;
+}());
+exports.FirebaseNamespace = FirebaseNamespace;
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/firebase-service.d.ts b/KEMMessaging/node_modules/firebase-admin/lib/firebase-service.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5bfe3e901550f70ad3359320ed0614a478c147c8
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/firebase-service.d.ts
@@ -0,0 +1,24 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+/// <reference types="chai" />
+import { FirebaseApp } from './firebase-app';
+/**
+ * Internals of a FirebaseService instance.
+ */
+export interface FirebaseServiceInternalsInterface {
+    delete(): Promise<void>;
+}
+/**
+ * Services are exposed through instances, each of which is associated with a FirebaseApp.
+ */
+export interface FirebaseServiceInterface {
+    app: FirebaseApp;
+    INTERNAL: FirebaseServiceInternalsInterface;
+}
+/**
+ * Factory method to create FirebaseService instances given a FirebaseApp instance. Can optionally
+ * add properties and methods to each FirebaseApp instance via the extendApp() function.
+ */
+export interface FirebaseServiceFactory {
+    (app: FirebaseApp, extendApp?: (props: Object) => void): FirebaseServiceInterface;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/firebase-service.js b/KEMMessaging/node_modules/firebase-admin/lib/firebase-service.js
new file mode 100644
index 0000000000000000000000000000000000000000..de9f4d7655a6aef7948535026148b8a46f323282
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/firebase-service.js
@@ -0,0 +1,3 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+"use strict";
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/index.d.ts b/KEMMessaging/node_modules/firebase-admin/lib/index.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..abca330fd68ad3f1b46eb851cc1ec6faf44c3deb
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/index.d.ts
@@ -0,0 +1,4 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+import * as firebase from './default-namespace';
+export = firebase;
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/index.js b/KEMMessaging/node_modules/firebase-admin/lib/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..fad5665e7c78ebd8c6995d9d0c2f8a066aa28342
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/index.js
@@ -0,0 +1,14 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+"use strict";
+var firebase = require('./default-namespace');
+var register_auth_1 = require('./auth/register-auth');
+// Register the database service
+// For historical reasons, the database code is included as minified code and registers itself
+// as a side effect of requiring the file.
+/* tslint:disable:no-var-requires */
+require('./database/database');
+/* tslint:enable:no-var-requires */
+// Register the auth service
+register_auth_1.default();
+module.exports = firebase;
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/utils/api-request.d.ts b/KEMMessaging/node_modules/firebase-admin/lib/utils/api-request.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..485296855bb65d087b7a6ae1da688681e107db46
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/utils/api-request.d.ts
@@ -0,0 +1,83 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+/// <reference types="chai" />
+import { Credential } from '../auth/credential';
+/** Http method type definition. */
+export declare type HttpMethod = 'GET' | 'POST';
+/** API callback function type definition. */
+export declare type ApiCallbackFunction = (data: Object) => void;
+/**
+ * Base class for handling HTTP requests.
+ */
+export declare class HttpRequestHandler {
+    /**
+     * Sends HTTP requests and returns a promise that resolves with the result.
+     *
+     * @param {string} host The HTTP host.
+     * @param {number} port The port number.
+     * @param {string} path The endpoint path.
+     * @param {HttpMethod} httpMethod The http method.
+     * @param {Object} [data] The request JSON.
+     * @param {Object} [headers] The request headers.
+     * @param {number} [timeout] The request timeout in milliseconds.
+     * @return {Promise<Object>} A promise that resolves with the response.
+     */
+    sendRequest(host: string, port: number, path: string, httpMethod: HttpMethod, data?: Object, headers?: Object, timeout?: number): Promise<Object>;
+}
+/**
+ * Class that extends HttpRequestHandler and signs HTTP requests with a service
+ * credential access token.
+ *
+ * @param {Credential} credential The service account credential used to
+ *     sign HTTP requests.
+ * @constructor
+ */
+export declare class SignedApiRequestHandler extends HttpRequestHandler {
+    private credential;
+    constructor(credential: Credential);
+    /**
+     * Sends HTTP requests and returns a promise that resolves with the result.
+     *
+     * @param {string} host The HTTP host.
+     * @param {number} port The port number.
+     * @param {string} path The endpoint path.
+     * @param {HttpMethod} httpMethod The http method.
+     * @param {Object} data The request JSON.
+     * @param {Object} headers The request headers.
+     * @param {number} timeout The request timeout in milliseconds.
+     * @return {Promise} A promise that resolves with the response.
+     */
+    sendRequest(host: string, port: number, path: string, httpMethod: HttpMethod, data: Object, headers: Object, timeout: number): Promise<Object>;
+}
+/**
+ * Class that defines all the settings for the backend API endpoint.
+ *
+ * @param {string} endpoint The Firebase Auth backend endpoint.
+ * @param {HttpMethod} httpMethod The http method for that endpoint.
+ * @constructor
+ */
+export declare class ApiSettings {
+    private endpoint;
+    private httpMethod;
+    private requestValidator;
+    private responseValidator;
+    constructor(endpoint: string, httpMethod?: HttpMethod);
+    /** @return {string} The backend API endpoint. */
+    getEndpoint(): string;
+    /** @return {HttpMethod} The request HTTP method. */
+    getHttpMethod(): HttpMethod;
+    /**
+     * @param {ApiCallbackFunction} requestValidator The request validator.
+     * @return {ApiSettings} The current API settings instance.
+     */
+    setRequestValidator(requestValidator: ApiCallbackFunction): ApiSettings;
+    /** @return {ApiCallbackFunction} The request validator. */
+    getRequestValidator(): ApiCallbackFunction;
+    /**
+     * @param {ApiCallbackFunction} responseValidator The response validator.
+     * @return {ApiSettings} The current API settings instance.
+     */
+    setResponseValidator(responseValidator: ApiCallbackFunction): ApiSettings;
+    /** @return {ApiCallbackFunction} The response validator. */
+    getResponseValidator(): ApiCallbackFunction;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/utils/api-request.js b/KEMMessaging/node_modules/firebase-admin/lib/utils/api-request.js
new file mode 100644
index 0000000000000000000000000000000000000000..83d323001064b70eb16cb87969ccccdb2469d45d
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/utils/api-request.js
@@ -0,0 +1,179 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+"use strict";
+var __extends = (this && this.__extends) || function (d, b) {
+    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
+    function __() { this.constructor = d; }
+    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+};
+var deep_copy_1 = require('./deep-copy');
+var https = require('https');
+/**
+ * Base class for handling HTTP requests.
+ */
+var HttpRequestHandler = (function () {
+    function HttpRequestHandler() {
+    }
+    /**
+     * Sends HTTP requests and returns a promise that resolves with the result.
+     *
+     * @param {string} host The HTTP host.
+     * @param {number} port The port number.
+     * @param {string} path The endpoint path.
+     * @param {HttpMethod} httpMethod The http method.
+     * @param {Object} [data] The request JSON.
+     * @param {Object} [headers] The request headers.
+     * @param {number} [timeout] The request timeout in milliseconds.
+     * @return {Promise<Object>} A promise that resolves with the response.
+     */
+    HttpRequestHandler.prototype.sendRequest = function (host, port, path, httpMethod, data, headers, timeout) {
+        var requestData;
+        if (data) {
+            try {
+                requestData = JSON.stringify(data);
+            }
+            catch (e) {
+                return Promise.reject(e);
+            }
+            headers['Content-Length'] = requestData.length;
+        }
+        var options = {
+            method: httpMethod,
+            host: host,
+            port: port,
+            path: path,
+            headers: headers,
+        };
+        // Only https endpoints.
+        return new Promise(function (resolve, reject) {
+            var req = https.request(options, function (res) {
+                var buffers = [];
+                res.on('data', function (buffer) { return buffers.push(buffer); });
+                res.on('end', function () {
+                    try {
+                        var json = JSON.parse(Buffer.concat(buffers).toString());
+                        resolve(json);
+                    }
+                    catch (err) {
+                        reject('Failed to parse response data: ' + err.toString());
+                    }
+                });
+            });
+            if (timeout) {
+                // Listen to timeouts and throw a network error.
+                req.on('socket', function (socket) {
+                    socket.setTimeout(timeout);
+                    socket.on('timeout', function () {
+                        req.abort();
+                        reject(new Error(host + ' network timeout. Try again.'));
+                    });
+                });
+            }
+            req.on('error', reject);
+            if (requestData) {
+                req.write(requestData);
+            }
+            req.end();
+        });
+    };
+    return HttpRequestHandler;
+}());
+exports.HttpRequestHandler = HttpRequestHandler;
+/**
+ * Class that extends HttpRequestHandler and signs HTTP requests with a service
+ * credential access token.
+ *
+ * @param {Credential} credential The service account credential used to
+ *     sign HTTP requests.
+ * @constructor
+ */
+var SignedApiRequestHandler = (function (_super) {
+    __extends(SignedApiRequestHandler, _super);
+    function SignedApiRequestHandler(credential) {
+        _super.call(this);
+        this.credential = credential;
+    }
+    /**
+     * Sends HTTP requests and returns a promise that resolves with the result.
+     *
+     * @param {string} host The HTTP host.
+     * @param {number} port The port number.
+     * @param {string} path The endpoint path.
+     * @param {HttpMethod} httpMethod The http method.
+     * @param {Object} data The request JSON.
+     * @param {Object} headers The request headers.
+     * @param {number} timeout The request timeout in milliseconds.
+     * @return {Promise} A promise that resolves with the response.
+     */
+    SignedApiRequestHandler.prototype.sendRequest = function (host, port, path, httpMethod, data, headers, timeout) {
+        var ancestorSendRequest = _super.prototype.sendRequest;
+        return this.credential.getAccessToken().then(function (accessTokenObj) {
+            if (accessTokenObj == null) {
+                return Promise.reject('Unable to fetch Google OAuth2 access token. ' +
+                    'Make sure you initialized the SDK with a credential that can f' +
+                    'etch access tokens.');
+            }
+            var headersCopy = deep_copy_1.deepCopy(headers);
+            var authorizationHeaderKey = 'Authorization';
+            headersCopy[authorizationHeaderKey] = 'Bearer ' + accessTokenObj.access_token;
+            return ancestorSendRequest(host, port, path, httpMethod, data, headersCopy, timeout);
+        });
+    };
+    return SignedApiRequestHandler;
+}(HttpRequestHandler));
+exports.SignedApiRequestHandler = SignedApiRequestHandler;
+/**
+ * Class that defines all the settings for the backend API endpoint.
+ *
+ * @param {string} endpoint The Firebase Auth backend endpoint.
+ * @param {HttpMethod} httpMethod The http method for that endpoint.
+ * @constructor
+ */
+var ApiSettings = (function () {
+    function ApiSettings(endpoint, httpMethod) {
+        if (httpMethod === void 0) { httpMethod = 'POST'; }
+        this.endpoint = endpoint;
+        this.httpMethod = httpMethod;
+        if (!endpoint) {
+            throw new Error('Unspecified API settings endpoint');
+        }
+        this.setRequestValidator(null)
+            .setResponseValidator(null);
+    }
+    /** @return {string} The backend API endpoint. */
+    ApiSettings.prototype.getEndpoint = function () {
+        return this.endpoint;
+    };
+    /** @return {HttpMethod} The request HTTP method. */
+    ApiSettings.prototype.getHttpMethod = function () {
+        return this.httpMethod;
+    };
+    /**
+     * @param {ApiCallbackFunction} requestValidator The request validator.
+     * @return {ApiSettings} The current API settings instance.
+     */
+    ApiSettings.prototype.setRequestValidator = function (requestValidator) {
+        var nullFunction = function (request) { return undefined; };
+        this.requestValidator = requestValidator || nullFunction;
+        return this;
+    };
+    /** @return {ApiCallbackFunction} The request validator. */
+    ApiSettings.prototype.getRequestValidator = function () {
+        return this.requestValidator;
+    };
+    /**
+     * @param {ApiCallbackFunction} responseValidator The response validator.
+     * @return {ApiSettings} The current API settings instance.
+     */
+    ApiSettings.prototype.setResponseValidator = function (responseValidator) {
+        var nullFunction = function (request) { return undefined; };
+        this.responseValidator = responseValidator || nullFunction;
+        return this;
+    };
+    /** @return {ApiCallbackFunction} The response validator. */
+    ApiSettings.prototype.getResponseValidator = function () {
+        return this.responseValidator;
+    };
+    return ApiSettings;
+}());
+exports.ApiSettings = ApiSettings;
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/utils/deep-copy.d.ts b/KEMMessaging/node_modules/firebase-admin/lib/utils/deep-copy.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8b81c5bd2f2b43313bb6bbf3035f4b0b1088c96a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/utils/deep-copy.d.ts
@@ -0,0 +1,25 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+/**
+ * Returns a deep copy of an object or array.
+ *
+ * @param {Object|array} value The object or array to deep copy.
+ * @return {Object|array} A deep copy of the provided object or array.
+ */
+export declare function deepCopy<T>(value: T): T;
+/**
+ * Copies properties from source to target (recursively allows extension of objects and arrays).
+ * Scalar values in the target are over-written. If target is undefined, an object of the
+ * appropriate type will be created (and returned).
+ *
+ * We recursively copy all child properties of plain objects in the source - so that namespace-like
+ * objects are merged.
+ *
+ * Note that the target can be a function, in which case the properties in the source object are
+ * copied onto it as static properties of the function.
+ *
+ * @param {any} target The value which is being extended.
+ * @param {any} source The value whose properties are extending the target.
+ * @return {any} The target value.
+ */
+export declare function deepExtend(target: any, source: any): any;
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/utils/deep-copy.js b/KEMMessaging/node_modules/firebase-admin/lib/utils/deep-copy.js
new file mode 100644
index 0000000000000000000000000000000000000000..ce10b44ed0454f5f907b5e875836131176979009
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/utils/deep-copy.js
@@ -0,0 +1,60 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+"use strict";
+/**
+ * Returns a deep copy of an object or array.
+ *
+ * @param {Object|array} value The object or array to deep copy.
+ * @return {Object|array} A deep copy of the provided object or array.
+ */
+function deepCopy(value) {
+    return deepExtend(undefined, value);
+}
+exports.deepCopy = deepCopy;
+/**
+ * Copies properties from source to target (recursively allows extension of objects and arrays).
+ * Scalar values in the target are over-written. If target is undefined, an object of the
+ * appropriate type will be created (and returned).
+ *
+ * We recursively copy all child properties of plain objects in the source - so that namespace-like
+ * objects are merged.
+ *
+ * Note that the target can be a function, in which case the properties in the source object are
+ * copied onto it as static properties of the function.
+ *
+ * @param {any} target The value which is being extended.
+ * @param {any} source The value whose properties are extending the target.
+ * @return {any} The target value.
+ */
+function deepExtend(target, source) {
+    if (!(source instanceof Object)) {
+        return source;
+    }
+    switch (source.constructor) {
+        case Date:
+            // Treat Dates like scalars; if the target date object had any child
+            // properties - they will be lost!
+            var dateValue = source;
+            return new Date(dateValue.getTime());
+        case Object:
+            if (target === undefined) {
+                target = {};
+            }
+            break;
+        case Array:
+            // Always copy the array source and overwrite the target.
+            target = [];
+            break;
+        default:
+            // Not a plain Object - treat it as a scalar.
+            return source;
+    }
+    for (var prop in source) {
+        if (!source.hasOwnProperty(prop)) {
+            continue;
+        }
+        target[prop] = deepExtend(target[prop], source[prop]);
+    }
+    return target;
+}
+exports.deepExtend = deepExtend;
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/utils/error.d.ts b/KEMMessaging/node_modules/firebase-admin/lib/utils/error.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..85370ac5d334e31c22479b5104db4ee6c5ee3456
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/utils/error.d.ts
@@ -0,0 +1,119 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+/// <reference types="node" />
+/// <reference types="chai" />
+/**
+ * Defines error info type. This includes a code and message string.
+ */
+declare type ErrorInfo = {
+    code: string;
+    message: string;
+};
+/**
+ * Firebase error code structure. This extends Error.
+ *
+ * @param {ErrorInfo} errorInfo The error information (code and message).
+ * @constructor
+ */
+declare class FirebaseError extends Error {
+    private errorInfo;
+    constructor(errorInfo: ErrorInfo);
+    /** @return {string} The error code. */
+    readonly code: string;
+    /** @return {string} The error message. */
+    readonly message: string;
+    /** @return {Object} The object representation of the error. */
+    toJSON(): Object;
+}
+/**
+ * Firebase Auth error code structure. This extends FirebaseError.
+ *
+ * @param {ErrorInfo} info The error code info.
+ * @param {string} [message] The error message. This will override the default
+ *     message if provided.
+ * @constructor
+ */
+declare class FirebaseAuthError extends FirebaseError {
+    /**
+     * Creates the developer facing error corresponding to the backend error code.
+     *
+     * @param {string} serverErrorCode The server error code.
+     * @param {string} [message] The error message. The default message is used
+     *     if not provided.
+     * @return {FirebaseAuthError} The corresponding developer facing error.
+     */
+    static fromServerError(serverErrorCode: string, message?: string): FirebaseAuthError;
+    constructor(info: ErrorInfo, message?: string);
+}
+/** @const {TODO} Auth client error codes and their default messages. */
+declare class AuthClientErrorCode {
+    static INVALID_ARGUMENT: {
+        code: string;
+        message: string;
+    };
+    static EMAIL_ALREADY_EXISTS: {
+        code: string;
+        message: string;
+    };
+    static INTERNAL_ERROR: {
+        code: string;
+        message: string;
+    };
+    static INVALID_CREDENTIAL: {
+        code: string;
+        message: string;
+    };
+    static INVALID_DISABLED_FIELD: {
+        code: string;
+        message: string;
+    };
+    static INVALID_DISPLAY_NAME: {
+        code: string;
+        message: string;
+    };
+    static INVALID_EMAIL_VERIFIED: {
+        code: string;
+        message: string;
+    };
+    static INVALID_EMAIL: {
+        code: string;
+        message: string;
+    };
+    static INVALID_PASSWORD: {
+        code: string;
+        message: string;
+    };
+    static INVALID_PHOTO_URL: {
+        code: string;
+        message: string;
+    };
+    static INVALID_SERVICE_ACCOUNT: {
+        code: string;
+        message: string;
+    };
+    static INVALID_UID: {
+        code: string;
+        message: string;
+    };
+    static MISSING_UID: {
+        code: string;
+        message: string;
+    };
+    static OPERATION_NOT_ALLOWED: {
+        code: string;
+        message: string;
+    };
+    static PROJECT_NOT_FOUND: {
+        code: string;
+        message: string;
+    };
+    static UID_ALREADY_EXISTS: {
+        code: string;
+        message: string;
+    };
+    static USER_NOT_FOUND: {
+        code: string;
+        message: string;
+    };
+}
+export { ErrorInfo, FirebaseError, FirebaseAuthError, AuthClientErrorCode };
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/utils/error.js b/KEMMessaging/node_modules/firebase-admin/lib/utils/error.js
new file mode 100644
index 0000000000000000000000000000000000000000..935209bd29cb4c2bf26b26c11140489adab61303
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/utils/error.js
@@ -0,0 +1,184 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+"use strict";
+var __extends = (this && this.__extends) || function (d, b) {
+    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
+    function __() { this.constructor = d; }
+    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+};
+var deep_copy_1 = require('../utils/deep-copy');
+/**
+ * Firebase error code structure. This extends Error.
+ *
+ * @param {ErrorInfo} errorInfo The error information (code and message).
+ * @constructor
+ */
+var FirebaseError = (function (_super) {
+    __extends(FirebaseError, _super);
+    function FirebaseError(errorInfo) {
+        _super.call(this, errorInfo.message);
+        this.errorInfo = errorInfo;
+    }
+    Object.defineProperty(FirebaseError.prototype, "code", {
+        /** @return {string} The error code. */
+        get: function () {
+            return this.errorInfo.code;
+        },
+        enumerable: true,
+        configurable: true
+    });
+    Object.defineProperty(FirebaseError.prototype, "message", {
+        /** @return {string} The error message. */
+        get: function () {
+            return this.errorInfo.message;
+        },
+        enumerable: true,
+        configurable: true
+    });
+    /** @return {Object} The object representation of the error. */
+    FirebaseError.prototype.toJSON = function () {
+        return {
+            code: this.code,
+            message: this.message,
+        };
+    };
+    return FirebaseError;
+}(Error));
+exports.FirebaseError = FirebaseError;
+/**
+ * Firebase Auth error code structure. This extends FirebaseError.
+ *
+ * @param {ErrorInfo} info The error code info.
+ * @param {string} [message] The error message. This will override the default
+ *     message if provided.
+ * @constructor
+ */
+var FirebaseAuthError = (function (_super) {
+    __extends(FirebaseAuthError, _super);
+    function FirebaseAuthError(info, message) {
+        // Override default message if custom message provided.
+        _super.call(this, { code: 'auth/' + info.code, message: message || info.message });
+    }
+    /**
+     * Creates the developer facing error corresponding to the backend error code.
+     *
+     * @param {string} serverErrorCode The server error code.
+     * @param {string} [message] The error message. The default message is used
+     *     if not provided.
+     * @return {FirebaseAuthError} The corresponding developer facing error.
+     */
+    FirebaseAuthError.fromServerError = function (serverErrorCode, message) {
+        // If not found, default to internal error.
+        var clientCodeKey = AUTH_SERVER_TO_CLIENT_CODE[serverErrorCode] || 'INTERNAL_ERROR';
+        var error = deep_copy_1.deepCopy(AuthClientErrorCode[clientCodeKey]);
+        error.message = message || error.message;
+        return new FirebaseAuthError(error);
+    };
+    return FirebaseAuthError;
+}(FirebaseError));
+exports.FirebaseAuthError = FirebaseAuthError;
+/** @const {TODO} Auth client error codes and their default messages. */
+var AuthClientErrorCode = (function () {
+    function AuthClientErrorCode() {
+    }
+    AuthClientErrorCode.INVALID_ARGUMENT = {
+        code: 'argument-error',
+        message: 'Invalid argument provided.',
+    };
+    AuthClientErrorCode.EMAIL_ALREADY_EXISTS = {
+        code: 'email-already-exists',
+        message: 'The email address is already in use by another account.',
+    };
+    AuthClientErrorCode.INTERNAL_ERROR = {
+        code: 'internal-error',
+        message: 'An internal error has occurred.',
+    };
+    AuthClientErrorCode.INVALID_CREDENTIAL = {
+        code: 'invalid-credential',
+        message: 'Invalid credential object provided.',
+    };
+    AuthClientErrorCode.INVALID_DISABLED_FIELD = {
+        code: 'invalid-disabled-field',
+        message: 'The disabled field must be a boolean.',
+    };
+    AuthClientErrorCode.INVALID_DISPLAY_NAME = {
+        code: 'invalid-display-name',
+        message: 'The displayName field must be a valid string.',
+    };
+    AuthClientErrorCode.INVALID_EMAIL_VERIFIED = {
+        code: 'invalid-email-verified',
+        message: 'The emailVerified field must be a boolean.',
+    };
+    AuthClientErrorCode.INVALID_EMAIL = {
+        code: 'invalid-email',
+        message: 'The email address is improperly formatted.',
+    };
+    AuthClientErrorCode.INVALID_PASSWORD = {
+        code: 'invalid-password',
+        message: 'The password must be a string with at least 6 characters.',
+    };
+    AuthClientErrorCode.INVALID_PHOTO_URL = {
+        code: 'invalid-photo-url',
+        message: 'The photoURL field must be a valid URL.',
+    };
+    AuthClientErrorCode.INVALID_SERVICE_ACCOUNT = {
+        code: 'invalid-service-account',
+        message: 'The service account provided is invalid.',
+    };
+    AuthClientErrorCode.INVALID_UID = {
+        code: 'invalid-uid',
+        message: 'The uid must be a non-empty string with at most 128 characters.',
+    };
+    AuthClientErrorCode.MISSING_UID = {
+        code: 'missing-uid',
+        message: 'A uid identifier is required for the current operation.',
+    };
+    AuthClientErrorCode.OPERATION_NOT_ALLOWED = {
+        code: 'operation-not-allowed',
+        message: 'The given sign-in provider is disabled for this Firebase project. ' +
+            'Enable it in the Firebase console, under the sign-in method tab of the ' +
+            'Auth section.',
+    };
+    AuthClientErrorCode.PROJECT_NOT_FOUND = {
+        code: 'project-not-found',
+        message: 'No Firebase project was found for the provided credential.',
+    };
+    AuthClientErrorCode.UID_ALREADY_EXISTS = {
+        code: 'uid-already-exists',
+        message: 'The user with the provided uid already exists.',
+    };
+    AuthClientErrorCode.USER_NOT_FOUND = {
+        code: 'user-not-found',
+        message: 'There is no user record corresponding to the provided identifier.',
+    };
+    return AuthClientErrorCode;
+}());
+exports.AuthClientErrorCode = AuthClientErrorCode;
+;
+/** @const {ServerToClientCode} Auth server to client enum error codes. */
+var AUTH_SERVER_TO_CLIENT_CODE = {
+    // Project not found.
+    CONFIGURATION_NOT_FOUND: 'PROJECT_NOT_FOUND',
+    // uploadAccount provides an email that already exists.
+    DUPLICATE_EMAIL: 'EMAIL_EXISTS',
+    // uploadAccount provides a localId that already exists.
+    DUPLICATE_LOCAL_ID: 'UID_ALREADY_EXISTS',
+    // setAccountInfo email already exists.
+    EMAIL_EXISTS: 'EMAIL_ALREADY_EXISTS',
+    // Invalid email provided.
+    INVALID_EMAIL: 'INVALID_EMAIL',
+    // Invalid service account.
+    INVALID_SERVICE_ACCOUNT: 'INVALID_SERVICE_ACCOUNT',
+    // No localId provided (deleteAccount missing localId).
+    MISSING_LOCAL_ID: 'MISSING_UID',
+    // Empty user list in uploadAccount.
+    MISSING_USER_ACCOUNT: 'MISSING_UID',
+    // Password auth disabled in console.
+    OPERATION_NOT_ALLOWED: 'OPERATION_NOT_ALLOWED',
+    // Project not found.
+    PROJECT_NOT_FOUND: 'PROJECT_NOT_FOUND',
+    // User on which action is to be performed is not found.
+    USER_NOT_FOUND: 'USER_NOT_FOUND',
+    // Password provided is too weak.
+    WEAK_PASSWORD: 'INVALID_PASSWORD',
+};
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/utils/validator.d.ts b/KEMMessaging/node_modules/firebase-admin/lib/utils/validator.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..96b6e2b987ce8a580d96d5f330299665b365d136
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/utils/validator.d.ts
@@ -0,0 +1,30 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+/**
+ * Validates that a string is a valid Firebase Auth uid.
+ *
+ * @param {any} uid The string to validate.
+ * @return {boolean} Whether the string is a valid Firebase Auth uid.
+ */
+export declare function isUid(uid: any): boolean;
+/**
+ * Validates that a string is a valid Firebase Auth password.
+ *
+ * @param {any} password The password string to validate.
+ * @return {boolean} Whether the string is a valid Firebase Auth password.
+ */
+export declare function isPassword(password: any): boolean;
+/**
+ * Validates that a string is a valid email.
+ *
+ * @param {any} email The string to validate.
+ * @return {boolean} Whether the string is valid email or not.
+ */
+export declare function isEmail(email: any): boolean;
+/**
+ * Validates that a string is a valid web URL.
+ *
+ * @param {any} urlStr The string to validate.
+ * @return {boolean} Whether the string is valid web URL or not.
+ */
+export declare function isURL(urlStr: any): boolean;
diff --git a/KEMMessaging/node_modules/firebase-admin/lib/utils/validator.js b/KEMMessaging/node_modules/firebase-admin/lib/utils/validator.js
new file mode 100644
index 0000000000000000000000000000000000000000..089f91a6bf108e69ba02571b3ce14f68b6659695
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/lib/utils/validator.js
@@ -0,0 +1,85 @@
+/*! firebase-admin v4.0.3
+    https://firebase.google.com/terms/ */
+"use strict";
+var url = require('url');
+/**
+ * Validates that a string is a valid Firebase Auth uid.
+ *
+ * @param {any} uid The string to validate.
+ * @return {boolean} Whether the string is a valid Firebase Auth uid.
+ */
+function isUid(uid) {
+    return typeof uid === 'string' && uid.length > 0 && uid.length <= 128;
+}
+exports.isUid = isUid;
+/**
+ * Validates that a string is a valid Firebase Auth password.
+ *
+ * @param {any} password The password string to validate.
+ * @return {boolean} Whether the string is a valid Firebase Auth password.
+ */
+function isPassword(password) {
+    // A password must be a string of at least 6 characters.
+    return typeof password === 'string' && password.length >= 6;
+}
+exports.isPassword = isPassword;
+/**
+ * Validates that a string is a valid email.
+ *
+ * @param {any} email The string to validate.
+ * @return {boolean} Whether the string is valid email or not.
+ */
+function isEmail(email) {
+    if (typeof email !== 'string') {
+        return false;
+    }
+    // There must at least one character before the @ symbol and another after.
+    var re = /^[^@]+@[^@]+$/;
+    return re.test(email);
+}
+exports.isEmail = isEmail;
+/**
+ * Validates that a string is a valid web URL.
+ *
+ * @param {any} urlStr The string to validate.
+ * @return {boolean} Whether the string is valid web URL or not.
+ */
+function isURL(urlStr) {
+    if (typeof urlStr !== 'string') {
+        return false;
+    }
+    // Lookup illegal characters.
+    var re = /[^a-z0-9\:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=\.\-\_\~\%]/i;
+    if (re.test(urlStr)) {
+        return false;
+    }
+    try {
+        var uri = url.parse(urlStr);
+        var scheme = uri.protocol;
+        var slashes = uri.slashes;
+        var hostname = uri.hostname;
+        var pathname = uri.pathname;
+        if ((scheme !== 'http:' && scheme !== 'https:') || !slashes) {
+            return false;
+        }
+        // Validate hostname: Can contain letters, numbers, underscore and dashes separated by a dot.
+        // Each zone must not start with a hyphen or underscore.
+        if (!/^[a-zA-Z0-9]+[\w\-]*([\.]?[a-zA-Z0-9]+[\w\-]*)*$/.test(hostname)) {
+            return false;
+        }
+        // Allow for pathnames: (/chars+)*
+        // Where chars can be a combination of: a-z A-Z 0-9 - _ . ~ ! $ & ' ( ) * + , ; = : @
+        var pathnameRe = /^(\/[\w\-\.\~\!\$\'\(\)\*\+\,\;\=\:\@]+)*$/;
+        // Validate pathname.
+        if (pathname &&
+            pathname !== '/' &&
+            !pathnameRe.test(pathname)) {
+            return false;
+        }
+    }
+    catch (e) {
+        return false;
+    }
+    return true;
+}
+exports.isURL = isURL;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/@types/jsonwebtoken/README.md b/KEMMessaging/node_modules/firebase-admin/node_modules/@types/jsonwebtoken/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..21af7b7cde25f4ba6068f723ccd4863a22f9a322
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/@types/jsonwebtoken/README.md
@@ -0,0 +1,18 @@
+# Installation
+> `npm install --save @types/jsonwebtoken`
+
+# Summary
+This package contains type definitions for jsonwebtoken 7.1.6 (https://github.com/auth0/node-jsonwebtoken).
+
+# Details
+Files were exported from https://www.github.com/DefinitelyTyped/DefinitelyTyped/tree/types-2.0/jsonwebtoken
+
+Additional Details
+ * Last updated: Thu, 06 Oct 2016 16:57:04 GMT
+ * File structure: ProperModule
+ * Library Dependencies: node
+ * Module Dependencies: none
+ * Global values: decode, verify
+
+# Credits
+These definitions were written by Maxime LUCE <https://github.com/SomaticIT>, Daniel Heim <https://github.com/danielheim>.
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/@types/jsonwebtoken/index.d.ts b/KEMMessaging/node_modules/firebase-admin/node_modules/@types/jsonwebtoken/index.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..656098caba4c981b008d9e4a7652302585e8eda2
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/@types/jsonwebtoken/index.d.ts
@@ -0,0 +1,127 @@
+// Type definitions for jsonwebtoken 7.1.6
+// Project: https://github.com/auth0/node-jsonwebtoken
+// Definitions by: Maxime LUCE <https://github.com/SomaticIT>, Daniel Heim <https://github.com/danielheim>
+// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
+
+/// <reference types="node" />
+
+export class JsonWebTokenError extends Error {
+    inner: Error;
+
+    constructor(message: string, error?: Error);
+}
+
+export class TokenExpiredError extends JsonWebTokenError {
+    expiredAt: number;
+
+    constructor(message: string, expiredAt: number);
+}
+
+export class NotBeforeError extends JsonWebTokenError {
+    date: Date;
+
+    constructor(message: string, date: Date);
+}
+
+export interface SignOptions {
+    /**
+     * Signature algorithm. Could be one of these values :
+     * - HS256:    HMAC using SHA-256 hash algorithm
+     * - HS384:    HMAC using SHA-384 hash algorithm
+     * - HS512:    HMAC using SHA-512 hash algorithm
+     * - RS256:    RSASSA using SHA-256 hash algorithm
+     * - RS384:    RSASSA using SHA-384 hash algorithm
+     * - RS512:    RSASSA using SHA-512 hash algorithm
+     * - ES256:    ECDSA using P-256 curve and SHA-256 hash algorithm
+     * - ES384:    ECDSA using P-384 curve and SHA-384 hash algorithm
+     * - ES512:    ECDSA using P-521 curve and SHA-512 hash algorithm
+     * - none:     No digital signature or MAC value included
+     */
+    algorithm?: string;
+    /** @member {string} - Lifetime for the token expressed in a string describing a time span [rauchg/ms](https://github.com/rauchg/ms.js). Eg: `60`, `"2 days"`, `"10h"`, `"7d"` */
+    expiresIn?: string | number;
+    notBefore?: string;
+    audience?: string;
+    subject?: string;
+    issuer?: string;
+    jwtid?: string;
+    noTimestamp?: boolean;
+    header?: Object;
+    encoding?: string;
+}
+
+export interface VerifyOptions {
+    algorithms?: string[];
+    audience?: string | string[];
+    clockTolerance?: number;
+    issuer?: string | string[];
+    ignoreExpiration?: boolean;
+    ignoreNotBefore?: boolean;
+    jwtId?: string;
+    subject?: string;
+    /**
+     *@deprecated
+     *@member {string} - Max age of token
+     */
+    maxAge?: string;
+}
+
+export interface DecodeOptions {
+    complete?: boolean;
+    json?: boolean;
+}
+
+export interface VerifyCallback {
+    (err: JsonWebTokenError | TokenExpiredError | NotBeforeError, decoded: any): void;
+}
+
+export interface SignCallback {
+    (err: Error, encoded: string): void;
+}
+
+/**
+ * Synchronously sign the given payload into a JSON Web Token string
+ * @param {String|Object|Buffer} payload - Payload to sign, could be an literal, buffer or string
+ * @param {String|Buffer} secretOrPrivateKey - Either the secret for HMAC algorithms, or the PEM encoded private key for RSA and ECDSA.
+ * @param {SignOptions} [options] - Options for the signature
+ * @returns {String} The JSON Web Token string
+ */
+export declare function sign(payload: string | Buffer | Object, secretOrPrivateKey: string | Buffer, options?: SignOptions): string;
+
+/**
+ * Sign the given payload into a JSON Web Token string
+ * @param {String|Object|Buffer} payload - Payload to sign, could be an literal, buffer or string
+ * @param {String|Buffer} secretOrPrivateKey - Either the secret for HMAC algorithms, or the PEM encoded private key for RSA and ECDSA.
+ * @param {SignOptions} [options] - Options for the signature
+ * @param {Function} callback - Callback to get the encoded token on
+ */
+export declare function sign(payload: string | Buffer | Object, secretOrPrivateKey: string | Buffer, callback: SignCallback): void;
+export declare function sign(payload: string | Buffer | Object, secretOrPrivateKey: string | Buffer, options: SignOptions, callback: SignCallback): void;
+
+/**
+ * Synchronously verify given token using a secret or a public key to get a decoded token
+ * @param {String} token - JWT string to verify
+ * @param {String|Buffer} secretOrPublicKey - Either the secret for HMAC algorithms, or the PEM encoded public key for RSA and ECDSA.
+ * @param {VerifyOptions} [options] - Options for the verification
+ * @returns The decoded token.
+ */
+declare function verify(token: string, secretOrPublicKey: string | Buffer): any;
+declare function verify(token: string, secretOrPublicKey: string | Buffer, options?: VerifyOptions): any;
+
+/**
+ * Asynchronously verify given token using a secret or a public key to get a decoded token
+ * @param {String} token - JWT string to verify
+ * @param {String|Buffer} secretOrPublicKey - Either the secret for HMAC algorithms, or the PEM encoded public key for RSA and ECDSA.
+ * @param {VerifyOptions} [options] - Options for the verification
+ * @param {Function} callback - Callback to get the decoded token on
+ */
+declare function verify(token: string, secretOrPublicKey: string | Buffer, callback?: VerifyCallback): void;
+declare function verify(token: string, secretOrPublicKey: string | Buffer, options?: VerifyOptions, callback?: VerifyCallback): void;
+
+/**
+ * Returns the decoded payload without verifying if the signature is valid.
+ * @param {String} token - JWT string to decode
+ * @param {DecodeOptions} [options] - Options for decoding
+ * @returns {Object} The decoded Token
+ */
+declare function decode(token: string, options?: DecodeOptions): any;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/@types/jsonwebtoken/package.json b/KEMMessaging/node_modules/firebase-admin/node_modules/@types/jsonwebtoken/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..b0224d2582b292827b09740fc1e7fe6d0f40b6ed
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/@types/jsonwebtoken/package.json
@@ -0,0 +1,62 @@
+{
+  "_args": [
+    [
+      {
+        "raw": "@types/jsonwebtoken@https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-7.1.33.tgz",
+        "scope": "@types",
+        "escapedName": "@types%2fjsonwebtoken",
+        "name": "@types/jsonwebtoken",
+        "rawSpec": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-7.1.33.tgz",
+        "spec": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-7.1.33.tgz",
+        "type": "remote"
+      },
+      "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin"
+    ]
+  ],
+  "_from": "@types/jsonwebtoken@>=7.1.33 <8.0.0",
+  "_id": "@types/jsonwebtoken@7.1.33",
+  "_inCache": true,
+  "_location": "/firebase-admin/@types/jsonwebtoken",
+  "_phantomChildren": {},
+  "_requested": {
+    "raw": "@types/jsonwebtoken@https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-7.1.33.tgz",
+    "scope": "@types",
+    "escapedName": "@types%2fjsonwebtoken",
+    "name": "@types/jsonwebtoken",
+    "rawSpec": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-7.1.33.tgz",
+    "spec": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-7.1.33.tgz",
+    "type": "remote"
+  },
+  "_requiredBy": [
+    "/firebase-admin"
+  ],
+  "_resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-7.1.33.tgz",
+  "_shasum": "e2fab98787b53c04d252471c747f1ba22a5965d7",
+  "_shrinkwrap": null,
+  "_spec": "@types/jsonwebtoken@https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-7.1.33.tgz",
+  "_where": "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin",
+  "author": {
+    "name": "Maxime LUCE",
+    "email": "https://github.com/SomaticIT"
+  },
+  "dependencies": {
+    "@types/node": "*"
+  },
+  "description": "TypeScript definitions for jsonwebtoken 7.1.6",
+  "devDependencies": {},
+  "license": "MIT",
+  "main": "",
+  "name": "@types/jsonwebtoken",
+  "optionalDependencies": {},
+  "peerDependencies": {},
+  "readme": "# Installation\r\n> `npm install --save @types/jsonwebtoken`\r\n\r\n# Summary\r\nThis package contains type definitions for jsonwebtoken 7.1.6 (https://github.com/auth0/node-jsonwebtoken).\r\n\r\n# Details\r\nFiles were exported from https://www.github.com/DefinitelyTyped/DefinitelyTyped/tree/types-2.0/jsonwebtoken\r\n\r\nAdditional Details\r\n * Last updated: Thu, 06 Oct 2016 16:57:04 GMT\r\n * File structure: ProperModule\r\n * Library Dependencies: node\r\n * Module Dependencies: none\r\n * Global values: decode, verify\r\n\r\n# Credits\r\nThese definitions were written by Maxime LUCE <https://github.com/SomaticIT>, Daniel Heim <https://github.com/danielheim>.\r\n",
+  "readmeFilename": "README.md",
+  "repository": {
+    "type": "git",
+    "url": "https://www.github.com/DefinitelyTyped/DefinitelyTyped.git"
+  },
+  "scripts": {},
+  "typesPublisherContentHash": "f7f28125b4f5ed094965bd1543115a450f3163da580e23e7fb77882287df7efd",
+  "typings": "index.d.ts",
+  "version": "7.1.33"
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/@types/jsonwebtoken/types-metadata.json b/KEMMessaging/node_modules/firebase-admin/node_modules/@types/jsonwebtoken/types-metadata.json
new file mode 100644
index 0000000000000000000000000000000000000000..26394e537f19f2dd6fc13cd1a5151fed17f53318
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/@types/jsonwebtoken/types-metadata.json
@@ -0,0 +1,28 @@
+{
+    "authors": "Maxime LUCE <https://github.com/SomaticIT>, Daniel Heim <https://github.com/danielheim>",
+    "definitionFilename": "index.d.ts",
+    "libraryDependencies": [
+        "node"
+    ],
+    "moduleDependencies": [],
+    "libraryMajorVersion": "7",
+    "libraryMinorVersion": "1",
+    "libraryName": "jsonwebtoken 7.1.6",
+    "typingsPackageName": "jsonwebtoken",
+    "projectName": "https://github.com/auth0/node-jsonwebtoken",
+    "sourceRepoURL": "https://www.github.com/DefinitelyTyped/DefinitelyTyped",
+    "sourceBranch": "types-2.0",
+    "kind": "ProperModule",
+    "globals": [
+        "decode",
+        "verify"
+    ],
+    "declaredModules": [
+        "jsonwebtoken"
+    ],
+    "files": [
+        "index.d.ts"
+    ],
+    "hasPackageJson": false,
+    "contentHash": "f7f28125b4f5ed094965bd1543115a450f3163da580e23e7fb77882287df7efd"
+}
\ No newline at end of file
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/@types/node/README.md b/KEMMessaging/node_modules/firebase-admin/node_modules/@types/node/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..08a72b4cd1ef849e799c08c5d12c0ed7e45ba8ef
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/@types/node/README.md
@@ -0,0 +1,18 @@
+# Installation
+> `npm install --save @types/node`
+
+# Summary
+This package contains type definitions for Node.js v6.x (http://nodejs.org/).
+
+# Details
+Files were exported from https://www.github.com/DefinitelyTyped/DefinitelyTyped/tree/types-2.0/node
+
+Additional Details
+ * Last updated: Mon, 21 Nov 2016 14:53:06 GMT
+ * File structure: ModuleAugmentation
+ * Library Dependencies: none
+ * Module Dependencies: child_process, crypto, events, http, net, readline, stream, tls
+ * Global values: Buffer, NodeJS, SlowBuffer, __dirname, __filename, clearImmediate, clearInterval, clearTimeout, console, exports, global, module, process, require, setImmediate, setInterval, setTimeout
+
+# Credits
+These definitions were written by Microsoft TypeScript <http://typescriptlang.org>, DefinitelyTyped <https://github.com/DefinitelyTyped/DefinitelyTyped>.
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/@types/node/index.d.ts b/KEMMessaging/node_modules/firebase-admin/node_modules/@types/node/index.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..acb11a18ef6fa70e99c47af2bbe22df0fc89e5a2
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/@types/node/index.d.ts
@@ -0,0 +1,3967 @@
+// Type definitions for Node.js v6.x
+// Project: http://nodejs.org/
+// Definitions by: Microsoft TypeScript <http://typescriptlang.org>, DefinitelyTyped <https://github.com/DefinitelyTyped/DefinitelyTyped>
+// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
+
+/************************************************
+*                                               *
+*               Node.js v6.x API                *
+*                                               *
+************************************************/
+
+// This needs to be global to avoid TS2403 in case lib.dom.d.ts is present in the same build
+interface Console {
+    Console: typeof NodeJS.Console;
+    assert(value: any, message?: string, ...optionalParams: any[]): void;
+    dir(obj: any, options?: {showHidden?: boolean, depth?: number, colors?: boolean}): void;
+    error(message?: any, ...optionalParams: any[]): void;
+    info(message?: any, ...optionalParams: any[]): void;
+    log(message?: any, ...optionalParams: any[]): void;
+    time(label: string): void;
+    timeEnd(label: string): void;
+    trace(message?: any, ...optionalParams: any[]): void;
+    warn(message?: any, ...optionalParams: any[]): void;
+}
+
+interface Error {
+    stack?: string;
+}
+
+interface ErrorConstructor {
+    captureStackTrace(targetObject: Object, constructorOpt?: Function): void;
+    stackTraceLimit: number;
+}
+
+// compat for TypeScript 1.8
+// if you use with --target es3 or --target es5 and use below definitions,
+// use the lib.es6.d.ts that is bundled with TypeScript 1.8.
+interface MapConstructor { }
+interface WeakMapConstructor { }
+interface SetConstructor { }
+interface WeakSetConstructor { }
+
+/************************************************
+*                                               *
+*                   GLOBAL                      *
+*                                               *
+************************************************/
+declare var process: NodeJS.Process;
+declare var global: NodeJS.Global;
+declare var console: Console;
+
+declare var __filename: string;
+declare var __dirname: string;
+
+declare function setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeJS.Timer;
+declare function clearTimeout(timeoutId: NodeJS.Timer): void;
+declare function setInterval(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeJS.Timer;
+declare function clearInterval(intervalId: NodeJS.Timer): void;
+declare function setImmediate(callback: (...args: any[]) => void, ...args: any[]): any;
+declare function clearImmediate(immediateId: any): void;
+
+interface NodeRequireFunction {
+    (id: string): any;
+}
+
+interface NodeRequire extends NodeRequireFunction {
+    resolve(id: string): string;
+    cache: any;
+    extensions: any;
+    main: NodeModule;
+}
+
+declare var require: NodeRequire;
+
+interface NodeModule {
+    exports: any;
+    require: NodeRequireFunction;
+    id: string;
+    filename: string;
+    loaded: boolean;
+    parent: NodeModule;
+    children: NodeModule[];
+}
+
+declare var module: NodeModule;
+
+// Same as module.exports
+declare var exports: any;
+declare var SlowBuffer: {
+    new (str: string, encoding?: string): Buffer;
+    new (size: number): Buffer;
+    new (size: Uint8Array): Buffer;
+    new (array: any[]): Buffer;
+    prototype: Buffer;
+    isBuffer(obj: any): boolean;
+    byteLength(string: string, encoding?: string): number;
+    concat(list: Buffer[], totalLength?: number): Buffer;
+};
+
+
+// Buffer class
+type BufferEncoding = "ascii" | "utf8" | "utf16le" | "ucs2" | "binary" | "hex";
+interface Buffer extends NodeBuffer { }
+
+/**
+ * Raw data is stored in instances of the Buffer class.
+ * A Buffer is similar to an array of integers but corresponds to a raw memory allocation outside the V8 heap.  A Buffer cannot be resized.
+ * Valid string encodings: 'ascii'|'utf8'|'utf16le'|'ucs2'(alias of 'utf16le')|'base64'|'binary'(deprecated)|'hex'
+ */
+declare var Buffer: {
+    /**
+     * Allocates a new buffer containing the given {str}.
+     *
+     * @param str String to store in buffer.
+     * @param encoding encoding to use, optional.  Default is 'utf8'
+     */
+    new (str: string, encoding?: string): Buffer;
+    /**
+     * Allocates a new buffer of {size} octets.
+     *
+     * @param size count of octets to allocate.
+     */
+    new (size: number): Buffer;
+    /**
+     * Allocates a new buffer containing the given {array} of octets.
+     *
+     * @param array The octets to store.
+     */
+    new (array: Uint8Array): Buffer;
+    /**
+     * Produces a Buffer backed by the same allocated memory as
+     * the given {ArrayBuffer}.
+     *
+     *
+     * @param arrayBuffer The ArrayBuffer with which to share memory.
+     */
+    new (arrayBuffer: ArrayBuffer): Buffer;
+    /**
+     * Allocates a new buffer containing the given {array} of octets.
+     *
+     * @param array The octets to store.
+     */
+    new (array: any[]): Buffer;
+    /**
+     * Copies the passed {buffer} data onto a new {Buffer} instance.
+     *
+     * @param buffer The buffer to copy.
+     */
+    new (buffer: Buffer): Buffer;
+    prototype: Buffer;
+    /**
+     * Allocates a new Buffer using an {array} of octets.
+     *
+     * @param array
+     */
+    from(array: any[]): Buffer;
+    /**
+     * When passed a reference to the .buffer property of a TypedArray instance,
+     * the newly created Buffer will share the same allocated memory as the TypedArray.
+     * The optional {byteOffset} and {length} arguments specify a memory range
+     * within the {arrayBuffer} that will be shared by the Buffer.
+     *
+     * @param arrayBuffer The .buffer property of a TypedArray or a new ArrayBuffer()
+     * @param byteOffset
+     * @param length
+     */
+    from(arrayBuffer: ArrayBuffer, byteOffset?: number, length?: number): Buffer;
+    /**
+     * Copies the passed {buffer} data onto a new Buffer instance.
+     *
+     * @param buffer
+     */
+    from(buffer: Buffer): Buffer;
+    /**
+     * Creates a new Buffer containing the given JavaScript string {str}.
+     * If provided, the {encoding} parameter identifies the character encoding.
+     * If not provided, {encoding} defaults to 'utf8'.
+     *
+     * @param str
+     */
+    from(str: string, encoding?: string): Buffer;
+    /**
+     * Returns true if {obj} is a Buffer
+     *
+     * @param obj object to test.
+     */
+    isBuffer(obj: any): obj is Buffer;
+    /**
+     * Returns true if {encoding} is a valid encoding argument.
+     * Valid string encodings in Node 0.12: 'ascii'|'utf8'|'utf16le'|'ucs2'(alias of 'utf16le')|'base64'|'binary'(deprecated)|'hex'
+     *
+     * @param encoding string to test.
+     */
+    isEncoding(encoding: string): boolean;
+    /**
+     * Gives the actual byte length of a string. encoding defaults to 'utf8'.
+     * This is not the same as String.prototype.length since that returns the number of characters in a string.
+     *
+     * @param string string to test.
+     * @param encoding encoding used to evaluate (defaults to 'utf8')
+     */
+    byteLength(string: string, encoding?: string): number;
+    /**
+     * Returns a buffer which is the result of concatenating all the buffers in the list together.
+     *
+     * If the list has no items, or if the totalLength is 0, then it returns a zero-length buffer.
+     * If the list has exactly one item, then the first item of the list is returned.
+     * If the list has more than one item, then a new Buffer is created.
+     *
+     * @param list An array of Buffer objects to concatenate
+     * @param totalLength Total length of the buffers when concatenated.
+     *   If totalLength is not provided, it is read from the buffers in the list. However, this adds an additional loop to the function, so it is faster to provide the length explicitly.
+     */
+    concat(list: Buffer[], totalLength?: number): Buffer;
+    /**
+     * The same as buf1.compare(buf2).
+     */
+    compare(buf1: Buffer, buf2: Buffer): number;
+    /**
+     * Allocates a new buffer of {size} octets.
+     *
+     * @param size count of octets to allocate.
+     * @param fill if specified, buffer will be initialized by calling buf.fill(fill).
+     *    If parameter is omitted, buffer will be filled with zeros.
+     * @param encoding encoding used for call to buf.fill while initalizing
+     */
+    alloc(size: number, fill?: string | Buffer | number, encoding?: string): Buffer;
+    /**
+     * Allocates a new buffer of {size} octets, leaving memory not initialized, so the contents
+     * of the newly created Buffer are unknown and may contain sensitive data.
+     *
+     * @param size count of octets to allocate
+     */
+    allocUnsafe(size: number): Buffer;
+    /**
+     * Allocates a new non-pooled buffer of {size} octets, leaving memory not initialized, so the contents
+     * of the newly created Buffer are unknown and may contain sensitive data.
+     *
+     * @param size count of octets to allocate
+     */
+    allocUnsafeSlow(size: number): Buffer;
+};
+
+/************************************************
+*                                               *
+*               GLOBAL INTERFACES               *
+*                                               *
+************************************************/
+declare namespace NodeJS {
+    export var Console: {
+        prototype: Console;
+        new(stdout: WritableStream, stderr?: WritableStream): Console;
+    }
+
+    export interface ErrnoException extends Error {
+        errno?: number;
+        code?: string;
+        path?: string;
+        syscall?: string;
+        stack?: string;
+    }
+
+    export class EventEmitter {
+        addListener(event: string | symbol, listener: Function): this;
+        on(event: string | symbol, listener: Function): this;
+        once(event: string | symbol, listener: Function): this;
+        removeListener(event: string | symbol, listener: Function): this;
+        removeAllListeners(event?: string | symbol): this;
+        setMaxListeners(n: number): this;
+        getMaxListeners(): number;
+        listeners(event: string | symbol): Function[];
+        emit(event: string | symbol, ...args: any[]): boolean;
+        listenerCount(type: string | symbol): number;
+        // Added in Node 6...
+        prependListener(event: string | symbol, listener: Function): this;
+        prependOnceListener(event: string | symbol, listener: Function): this;
+        eventNames(): (string | symbol)[];
+    }
+
+    export interface ReadableStream extends EventEmitter {
+        readable: boolean;
+        read(size?: number): string | Buffer;
+        setEncoding(encoding: string | null): void;
+        pause(): ReadableStream;
+        resume(): ReadableStream;
+        pipe<T extends WritableStream>(destination: T, options?: { end?: boolean; }): T;
+        unpipe<T extends WritableStream>(destination?: T): void;
+        unshift(chunk: string): void;
+        unshift(chunk: Buffer): void;
+        wrap(oldStream: ReadableStream): ReadableStream;
+    }
+
+    export interface WritableStream extends EventEmitter {
+        writable: boolean;
+        write(buffer: Buffer | string, cb?: Function): boolean;
+        write(str: string, encoding?: string, cb?: Function): boolean;
+        end(): void;
+        end(buffer: Buffer, cb?: Function): void;
+        end(str: string, cb?: Function): void;
+        end(str: string, encoding?: string, cb?: Function): void;
+    }
+
+    export interface ReadWriteStream extends ReadableStream, WritableStream {
+      pause(): ReadWriteStream;
+      resume(): ReadWriteStream;
+    }
+
+    export interface Events extends EventEmitter { }
+
+    export interface Domain extends Events {
+        run(fn: Function): void;
+        add(emitter: Events): void;
+        remove(emitter: Events): void;
+        bind(cb: (err: Error, data: any) => any): any;
+        intercept(cb: (data: any) => any): any;
+        dispose(): void;
+
+        addListener(event: string, listener: Function): this;
+        on(event: string, listener: Function): this;
+        once(event: string, listener: Function): this;
+        removeListener(event: string, listener: Function): this;
+        removeAllListeners(event?: string): this;
+    }
+
+    export interface MemoryUsage {
+        rss: number;
+        heapTotal: number;
+        heapUsed: number;
+    }
+
+    export interface ProcessVersions {
+        http_parser: string;
+        node: string;
+        v8: string;
+        ares: string;
+        uv: string;
+        zlib: string;
+        modules: string;
+        openssl: string;
+    }
+
+    export interface Process extends EventEmitter {
+        stdout: WritableStream;
+        stderr: WritableStream;
+        stdin: ReadableStream;
+        argv: string[];
+        argv0: string;
+        execArgv: string[];
+        execPath: string;
+        abort(): void;
+        chdir(directory: string): void;
+        cwd(): string;
+        env: any;
+        exit(code?: number): void;
+        exitCode: number;
+        getgid(): number;
+        setgid(id: number): void;
+        setgid(id: string): void;
+        getuid(): number;
+        setuid(id: number): void;
+        setuid(id: string): void;
+        version: string;
+        versions: ProcessVersions;
+        config: {
+            target_defaults: {
+                cflags: any[];
+                default_configuration: string;
+                defines: string[];
+                include_dirs: string[];
+                libraries: string[];
+            };
+            variables: {
+                clang: number;
+                host_arch: string;
+                node_install_npm: boolean;
+                node_install_waf: boolean;
+                node_prefix: string;
+                node_shared_openssl: boolean;
+                node_shared_v8: boolean;
+                node_shared_zlib: boolean;
+                node_use_dtrace: boolean;
+                node_use_etw: boolean;
+                node_use_openssl: boolean;
+                target_arch: string;
+                v8_no_strict_aliasing: number;
+                v8_use_snapshot: boolean;
+                visibility: string;
+            };
+        };
+        kill(pid: number, signal?: string | number): void;
+        pid: number;
+        title: string;
+        arch: string;
+        platform: string;
+        mainModule?: NodeModule;
+        memoryUsage(): MemoryUsage;
+        nextTick(callback: Function, ...args: any[]): void;
+        umask(mask?: number): number;
+        uptime(): number;
+        hrtime(time?: [number, number]): [number, number];
+        domain: Domain;
+
+        // Worker
+        send?(message: any, sendHandle?: any): void;
+        disconnect(): void;
+        connected: boolean;
+    }
+
+    export interface Global {
+        Array: typeof Array;
+        ArrayBuffer: typeof ArrayBuffer;
+        Boolean: typeof Boolean;
+        Buffer: typeof Buffer;
+        DataView: typeof DataView;
+        Date: typeof Date;
+        Error: typeof Error;
+        EvalError: typeof EvalError;
+        Float32Array: typeof Float32Array;
+        Float64Array: typeof Float64Array;
+        Function: typeof Function;
+        GLOBAL: Global;
+        Infinity: typeof Infinity;
+        Int16Array: typeof Int16Array;
+        Int32Array: typeof Int32Array;
+        Int8Array: typeof Int8Array;
+        Intl: typeof Intl;
+        JSON: typeof JSON;
+        Map: MapConstructor;
+        Math: typeof Math;
+        NaN: typeof NaN;
+        Number: typeof Number;
+        Object: typeof Object;
+        Promise: Function;
+        RangeError: typeof RangeError;
+        ReferenceError: typeof ReferenceError;
+        RegExp: typeof RegExp;
+        Set: SetConstructor;
+        String: typeof String;
+        Symbol: Function;
+        SyntaxError: typeof SyntaxError;
+        TypeError: typeof TypeError;
+        URIError: typeof URIError;
+        Uint16Array: typeof Uint16Array;
+        Uint32Array: typeof Uint32Array;
+        Uint8Array: typeof Uint8Array;
+        Uint8ClampedArray: Function;
+        WeakMap: WeakMapConstructor;
+        WeakSet: WeakSetConstructor;
+        clearImmediate: (immediateId: any) => void;
+        clearInterval: (intervalId: NodeJS.Timer) => void;
+        clearTimeout: (timeoutId: NodeJS.Timer) => void;
+        console: typeof console;
+        decodeURI: typeof decodeURI;
+        decodeURIComponent: typeof decodeURIComponent;
+        encodeURI: typeof encodeURI;
+        encodeURIComponent: typeof encodeURIComponent;
+        escape: (str: string) => string;
+        eval: typeof eval;
+        global: Global;
+        isFinite: typeof isFinite;
+        isNaN: typeof isNaN;
+        parseFloat: typeof parseFloat;
+        parseInt: typeof parseInt;
+        process: Process;
+        root: Global;
+        setImmediate: (callback: (...args: any[]) => void, ...args: any[]) => any;
+        setInterval: (callback: (...args: any[]) => void, ms: number, ...args: any[]) => NodeJS.Timer;
+        setTimeout: (callback: (...args: any[]) => void, ms: number, ...args: any[]) => NodeJS.Timer;
+        undefined: typeof undefined;
+        unescape: (str: string) => string;
+        gc: () => void;
+        v8debug?: any;
+    }
+
+    export interface Timer {
+        ref(): void;
+        unref(): void;
+    }
+}
+
+interface IterableIterator<T> { }
+
+/**
+ * @deprecated
+ */
+interface NodeBuffer extends Uint8Array {
+    write(string: string, offset?: number, length?: number, encoding?: string): number;
+    toString(encoding?: string, start?: number, end?: number): string;
+    toJSON(): { type: 'Buffer', data: any[] };
+    equals(otherBuffer: Buffer): boolean;
+    compare(otherBuffer: Buffer, targetStart?: number, targetEnd?: number, sourceStart?: number, sourceEnd?: number): number;
+    copy(targetBuffer: Buffer, targetStart?: number, sourceStart?: number, sourceEnd?: number): number;
+    slice(start?: number, end?: number): Buffer;
+    writeUIntLE(value: number, offset: number, byteLength: number, noAssert?: boolean): number;
+    writeUIntBE(value: number, offset: number, byteLength: number, noAssert?: boolean): number;
+    writeIntLE(value: number, offset: number, byteLength: number, noAssert?: boolean): number;
+    writeIntBE(value: number, offset: number, byteLength: number, noAssert?: boolean): number;
+    readUIntLE(offset: number, byteLength: number, noAssert?: boolean): number;
+    readUIntBE(offset: number, byteLength: number, noAssert?: boolean): number;
+    readIntLE(offset: number, byteLength: number, noAssert?: boolean): number;
+    readIntBE(offset: number, byteLength: number, noAssert?: boolean): number;
+    readUInt8(offset: number, noAssert?: boolean): number;
+    readUInt16LE(offset: number, noAssert?: boolean): number;
+    readUInt16BE(offset: number, noAssert?: boolean): number;
+    readUInt32LE(offset: number, noAssert?: boolean): number;
+    readUInt32BE(offset: number, noAssert?: boolean): number;
+    readInt8(offset: number, noAssert?: boolean): number;
+    readInt16LE(offset: number, noAssert?: boolean): number;
+    readInt16BE(offset: number, noAssert?: boolean): number;
+    readInt32LE(offset: number, noAssert?: boolean): number;
+    readInt32BE(offset: number, noAssert?: boolean): number;
+    readFloatLE(offset: number, noAssert?: boolean): number;
+    readFloatBE(offset: number, noAssert?: boolean): number;
+    readDoubleLE(offset: number, noAssert?: boolean): number;
+    readDoubleBE(offset: number, noAssert?: boolean): number;
+    swap16(): Buffer;
+    swap32(): Buffer;
+    swap64(): Buffer;
+    writeUInt8(value: number, offset: number, noAssert?: boolean): number;
+    writeUInt16LE(value: number, offset: number, noAssert?: boolean): number;
+    writeUInt16BE(value: number, offset: number, noAssert?: boolean): number;
+    writeUInt32LE(value: number, offset: number, noAssert?: boolean): number;
+    writeUInt32BE(value: number, offset: number, noAssert?: boolean): number;
+    writeInt8(value: number, offset: number, noAssert?: boolean): number;
+    writeInt16LE(value: number, offset: number, noAssert?: boolean): number;
+    writeInt16BE(value: number, offset: number, noAssert?: boolean): number;
+    writeInt32LE(value: number, offset: number, noAssert?: boolean): number;
+    writeInt32BE(value: number, offset: number, noAssert?: boolean): number;
+    writeFloatLE(value: number, offset: number, noAssert?: boolean): number;
+    writeFloatBE(value: number, offset: number, noAssert?: boolean): number;
+    writeDoubleLE(value: number, offset: number, noAssert?: boolean): number;
+    writeDoubleBE(value: number, offset: number, noAssert?: boolean): number;
+    fill(value: any, offset?: number, end?: number): this;
+    indexOf(value: string | number | Buffer, byteOffset?: number, encoding?: string): number;
+    lastIndexOf(value: string | number | Buffer, byteOffset?: number, encoding?: string): number;
+    entries(): IterableIterator<[number, number]>;
+    includes(value: string | number | Buffer, byteOffset?: number, encoding?: string): boolean;
+    keys(): IterableIterator<number>;
+    values(): IterableIterator<number>;
+}
+
+/************************************************
+*                                               *
+*                   MODULES                     *
+*                                               *
+************************************************/
+declare module "buffer" {
+    export var INSPECT_MAX_BYTES: number;
+    var BuffType: typeof Buffer;
+    var SlowBuffType: typeof SlowBuffer;
+    export { BuffType as Buffer, SlowBuffType as SlowBuffer };
+}
+
+declare module "querystring" {
+    export interface StringifyOptions {
+        encodeURIComponent?: Function;
+    }
+
+    export interface ParseOptions {
+        maxKeys?: number;
+        decodeURIComponent?: Function;
+    }
+
+    export function stringify<T>(obj: T, sep?: string, eq?: string, options?: StringifyOptions): string;
+    export function parse(str: string, sep?: string, eq?: string, options?: ParseOptions): any;
+    export function parse<T extends {}>(str: string, sep?: string, eq?: string, options?: ParseOptions): T;
+    export function escape(str: string): string;
+    export function unescape(str: string): string;
+}
+
+declare module "events" {
+    export class EventEmitter extends NodeJS.EventEmitter {
+        static EventEmitter: EventEmitter;
+        static listenerCount(emitter: EventEmitter, event: string | symbol): number; // deprecated
+        static defaultMaxListeners: number;
+
+        addListener(event: string | symbol, listener: Function): this;
+        on(event: string | symbol, listener: Function): this;
+        once(event: string | symbol, listener: Function): this;
+        prependListener(event: string | symbol, listener: Function): this;
+        prependOnceListener(event: string | symbol, listener: Function): this;
+        removeListener(event: string | symbol, listener: Function): this;
+        removeAllListeners(event?: string | symbol): this;
+        setMaxListeners(n: number): this;
+        getMaxListeners(): number;
+        listeners(event: string | symbol): Function[];
+        emit(event: string | symbol, ...args: any[]): boolean;
+        eventNames(): (string | symbol)[];
+        listenerCount(type: string | symbol): number;
+    }
+}
+
+declare module "http" {
+    import * as events from "events";
+    import * as net from "net";
+    import * as stream from "stream";
+
+    export interface RequestOptions {
+        protocol?: string;
+        host?: string;
+        hostname?: string;
+        family?: number;
+        port?: number;
+        localAddress?: string;
+        socketPath?: string;
+        method?: string;
+        path?: string;
+        headers?: { [key: string]: any };
+        auth?: string;
+        agent?: Agent | boolean;
+    }
+
+    export interface Server extends net.Server {
+        setTimeout(msecs: number, callback: Function): void;
+        maxHeadersCount: number;
+        timeout: number;
+        listening: boolean;
+    }
+    /**
+     * @deprecated Use IncomingMessage
+     */
+    export interface ServerRequest extends IncomingMessage {
+        connection: net.Socket;
+    }
+    export interface ServerResponse extends stream.Writable {
+        // Extended base methods
+        write(buffer: Buffer): boolean;
+        write(buffer: Buffer, cb?: Function): boolean;
+        write(str: string, cb?: Function): boolean;
+        write(str: string, encoding?: string, cb?: Function): boolean;
+        write(str: string, encoding?: string, fd?: string): boolean;
+
+        writeContinue(): void;
+        writeHead(statusCode: number, reasonPhrase?: string, headers?: any): void;
+        writeHead(statusCode: number, headers?: any): void;
+        statusCode: number;
+        statusMessage: string;
+        headersSent: boolean;
+        setHeader(name: string, value: string | string[]): void;
+        setTimeout(msecs: number, callback: Function): ServerResponse;
+        sendDate: boolean;
+        getHeader(name: string): string;
+        removeHeader(name: string): void;
+        write(chunk: any, encoding?: string): any;
+        addTrailers(headers: any): void;
+        finished: boolean;
+
+        // Extended base methods
+        end(): void;
+        end(buffer: Buffer, cb?: Function): void;
+        end(str: string, cb?: Function): void;
+        end(str: string, encoding?: string, cb?: Function): void;
+        end(data?: any, encoding?: string): void;
+    }
+    export interface ClientRequest extends stream.Writable {
+        // Extended base methods
+        write(buffer: Buffer): boolean;
+        write(buffer: Buffer, cb?: Function): boolean;
+        write(str: string, cb?: Function): boolean;
+        write(str: string, encoding?: string, cb?: Function): boolean;
+        write(str: string, encoding?: string, fd?: string): boolean;
+
+        write(chunk: any, encoding?: string): void;
+        abort(): void;
+        setTimeout(timeout: number, callback?: Function): void;
+        setNoDelay(noDelay?: boolean): void;
+        setSocketKeepAlive(enable?: boolean, initialDelay?: number): void;
+
+        setHeader(name: string, value: string | string[]): void;
+        getHeader(name: string): string;
+        removeHeader(name: string): void;
+        addTrailers(headers: any): void;
+
+        // Extended base methods
+        end(): void;
+        end(buffer: Buffer, cb?: Function): void;
+        end(str: string, cb?: Function): void;
+        end(str: string, encoding?: string, cb?: Function): void;
+        end(data?: any, encoding?: string): void;
+    }
+    export interface IncomingMessage extends stream.Readable {
+        httpVersion: string;
+        httpVersionMajor: number;
+        httpVersionMinor: number;
+        connection: net.Socket;
+        headers: any;
+        rawHeaders: string[];
+        trailers: any;
+        rawTrailers: any;
+        setTimeout(msecs: number, callback: Function): NodeJS.Timer;
+        /**
+         * Only valid for request obtained from http.Server.
+         */
+        method?: string;
+        /**
+         * Only valid for request obtained from http.Server.
+         */
+        url?: string;
+        /**
+         * Only valid for response obtained from http.ClientRequest.
+         */
+        statusCode?: number;
+        /**
+         * Only valid for response obtained from http.ClientRequest.
+         */
+        statusMessage?: string;
+        socket: net.Socket;
+        destroy(error?: Error): void;
+    }
+    /**
+     * @deprecated Use IncomingMessage
+     */
+    export interface ClientResponse extends IncomingMessage { }
+
+    export interface AgentOptions {
+        /**
+         * Keep sockets around in a pool to be used by other requests in the future. Default = false
+         */
+        keepAlive?: boolean;
+        /**
+         * When using HTTP KeepAlive, how often to send TCP KeepAlive packets over sockets being kept alive. Default = 1000.
+         * Only relevant if keepAlive is set to true.
+         */
+        keepAliveMsecs?: number;
+        /**
+         * Maximum number of sockets to allow per host. Default for Node 0.10 is 5, default for Node 0.12 is Infinity
+         */
+        maxSockets?: number;
+        /**
+         * Maximum number of sockets to leave open in a free state. Only relevant if keepAlive is set to true. Default = 256.
+         */
+        maxFreeSockets?: number;
+    }
+
+    export class Agent {
+        maxSockets: number;
+        sockets: any;
+        requests: any;
+
+        constructor(opts?: AgentOptions);
+
+        /**
+         * Destroy any sockets that are currently in use by the agent.
+         * It is usually not necessary to do this. However, if you are using an agent with KeepAlive enabled,
+         * then it is best to explicitly shut down the agent when you know that it will no longer be used. Otherwise,
+         * sockets may hang open for quite a long time before the server terminates them.
+         */
+        destroy(): void;
+    }
+
+    export var METHODS: string[];
+
+    export var STATUS_CODES: {
+        [errorCode: number]: string;
+        [errorCode: string]: string;
+    };
+    export function createServer(requestListener?: (request: IncomingMessage, response: ServerResponse) => void): Server;
+    export function createClient(port?: number, host?: string): any;
+    export function request(options: RequestOptions, callback?: (res: IncomingMessage) => void): ClientRequest;
+    export function get(options: any, callback?: (res: IncomingMessage) => void): ClientRequest;
+    export var globalAgent: Agent;
+}
+
+declare module "cluster" {
+    import * as child from "child_process";
+    import * as events from "events";
+    import * as net from "net";
+
+    // interfaces
+    export interface ClusterSettings {
+        execArgv?: string[]; // default: process.execArgv
+        exec?: string;
+        args?: string[];
+        silent?: boolean;
+        stdio?: any[];
+        uid?: number;
+        gid?: number;
+    }
+
+    export interface ClusterSetupMasterSettings {
+        exec?: string;  // default: process.argv[1]
+        args?: string[];  // default: process.argv.slice(2)
+        silent?: boolean;  // default: false
+        stdio?: any[];
+    }
+
+    export interface Address {
+        address: string;
+        port: number;
+        addressType: number | "udp4" | "udp6";  // 4, 6, -1, "udp4", "udp6"
+    }
+
+    export class Worker extends events.EventEmitter {
+        id: string;
+        process: child.ChildProcess;
+        suicide: boolean;
+        send(message: any, sendHandle?: any): boolean;
+        kill(signal?: string): void;
+        destroy(signal?: string): void;
+        disconnect(): void;
+        isConnected(): boolean;
+        isDead(): boolean;
+        exitedAfterDisconnect: boolean;
+
+        /**
+         * events.EventEmitter
+         *   1. disconnect
+         *   2. error
+         *   3. exit
+         *   4. listening
+         *   5. message
+         *   6. online
+         */
+        addListener(event: string, listener: Function): this;
+        addListener(event: "disconnect", listener: () => void): this;
+        addListener(event: "error", listener: (code: number, signal: string) => void): this;
+        addListener(event: "exit", listener: (code: number, signal: string) => void): this;
+        addListener(event: "listening", listener: (address: Address) => void): this;
+        addListener(event: "message", listener: (message: any, handle: net.Socket | net.Server) => void): this;  // the handle is a net.Socket or net.Server object, or undefined.
+        addListener(event: "online", listener: () => void): this;
+
+        emit(event: string, listener: Function): boolean
+        emit(event: "disconnect", listener: () => void): boolean
+        emit(event: "error", listener: (code: number, signal: string) => void): boolean
+        emit(event: "exit", listener: (code: number, signal: string) => void): boolean
+        emit(event: "listening", listener: (address: Address) => void): boolean
+        emit(event: "message", listener: (message: any, handle: net.Socket | net.Server) => void): boolean
+        emit(event: "online", listener: () => void): boolean
+
+        on(event: string, listener: Function): this;
+        on(event: "disconnect", listener: () => void): this;
+        on(event: "error", listener: (code: number, signal: string) => void): this;
+        on(event: "exit", listener: (code: number, signal: string) => void): this;
+        on(event: "listening", listener: (address: Address) => void): this;
+        on(event: "message", listener: (message: any, handle: net.Socket | net.Server) => void): this;  // the handle is a net.Socket or net.Server object, or undefined.
+        on(event: "online", listener: () => void): this;
+
+        once(event: string, listener: Function): this;
+        once(event: "disconnect", listener: () => void): this;
+        once(event: "error", listener: (code: number, signal: string) => void): this;
+        once(event: "exit", listener: (code: number, signal: string) => void): this;
+        once(event: "listening", listener: (address: Address) => void): this;
+        once(event: "message", listener: (message: any, handle: net.Socket | net.Server) => void): this;  // the handle is a net.Socket or net.Server object, or undefined.
+        once(event: "online", listener: () => void): this;
+
+        prependListener(event: string, listener: Function): this;
+        prependListener(event: "disconnect", listener: () => void): this;
+        prependListener(event: "error", listener: (code: number, signal: string) => void): this;
+        prependListener(event: "exit", listener: (code: number, signal: string) => void): this;
+        prependListener(event: "listening", listener: (address: Address) => void): this;
+        prependListener(event: "message", listener: (message: any, handle: net.Socket | net.Server) => void): this;  // the handle is a net.Socket or net.Server object, or undefined.
+        prependListener(event: "online", listener: () => void): this;
+
+        prependOnceListener(event: string, listener: Function): this;
+        prependOnceListener(event: "disconnect", listener: () => void): this;
+        prependOnceListener(event: "error", listener: (code: number, signal: string) => void): this;
+        prependOnceListener(event: "exit", listener: (code: number, signal: string) => void): this;
+        prependOnceListener(event: "listening", listener: (address: Address) => void): this;
+        prependOnceListener(event: "message", listener: (message: any, handle: net.Socket | net.Server) => void): this;  // the handle is a net.Socket or net.Server object, or undefined.
+        prependOnceListener(event: "online", listener: () => void): this;
+    }
+
+    export interface Cluster extends events.EventEmitter {
+        Worker: Worker;
+        disconnect(callback?: Function): void;
+        fork(env?: any): Worker;
+        isMaster: boolean;
+        isWorker: boolean;
+        // TODO: cluster.schedulingPolicy
+        settings: ClusterSettings;
+        setupMaster(settings?: ClusterSetupMasterSettings): void;
+        worker: Worker;
+        workers: {
+            [index: string]: Worker
+        };
+
+        /**
+         * events.EventEmitter
+         *   1. disconnect
+         *   2. exit
+         *   3. fork
+         *   4. listening
+         *   5. message
+         *   6. online
+         *   7. setup
+         */
+        addListener(event: string, listener: Function): this;
+        addListener(event: "disconnect", listener: (worker: Worker) => void): this;
+        addListener(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): this;
+        addListener(event: "fork", listener: (worker: Worker) => void): this;
+        addListener(event: "listening", listener: (worker: Worker, address: Address) => void): this;
+        addListener(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): this;  // the handle is a net.Socket or net.Server object, or undefined.
+        addListener(event: "online", listener: (worker: Worker) => void): this;
+        addListener(event: "setup", listener: (settings: any) => void): this;
+
+        emit(event: string, listener: Function): boolean;
+        emit(event: "disconnect", listener: (worker: Worker) => void): boolean;
+        emit(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): boolean;
+        emit(event: "fork", listener: (worker: Worker) => void): boolean;
+        emit(event: "listening", listener: (worker: Worker, address: Address) => void): boolean;
+        emit(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): boolean;
+        emit(event: "online", listener: (worker: Worker) => void): boolean;
+        emit(event: "setup", listener: (settings: any) => void): boolean;
+
+        on(event: string, listener: Function): this;
+        on(event: "disconnect", listener: (worker: Worker) => void): this;
+        on(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): this;
+        on(event: "fork", listener: (worker: Worker) => void): this;
+        on(event: "listening", listener: (worker: Worker, address: Address) => void): this;
+        on(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): this;  // the handle is a net.Socket or net.Server object, or undefined.
+        on(event: "online", listener: (worker: Worker) => void): this;
+        on(event: "setup", listener: (settings: any) => void): this;
+
+        once(event: string, listener: Function): this;
+        once(event: "disconnect", listener: (worker: Worker) => void): this;
+        once(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): this;
+        once(event: "fork", listener: (worker: Worker) => void): this;
+        once(event: "listening", listener: (worker: Worker, address: Address) => void): this;
+        once(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): this;  // the handle is a net.Socket or net.Server object, or undefined.
+        once(event: "online", listener: (worker: Worker) => void): this;
+        once(event: "setup", listener: (settings: any) => void): this;
+
+        prependListener(event: string, listener: Function): this;
+        prependListener(event: "disconnect", listener: (worker: Worker) => void): this;
+        prependListener(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): this;
+        prependListener(event: "fork", listener: (worker: Worker) => void): this;
+        prependListener(event: "listening", listener: (worker: Worker, address: Address) => void): this;
+        prependListener(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): this;  // the handle is a net.Socket or net.Server object, or undefined.
+        prependListener(event: "online", listener: (worker: Worker) => void): this;
+        prependListener(event: "setup", listener: (settings: any) => void): this;
+
+        prependOnceListener(event: string, listener: Function): this;
+        prependOnceListener(event: "disconnect", listener: (worker: Worker) => void): this;
+        prependOnceListener(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): this;
+        prependOnceListener(event: "fork", listener: (worker: Worker) => void): this;
+        prependOnceListener(event: "listening", listener: (worker: Worker, address: Address) => void): this;
+        prependOnceListener(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): this;  // the handle is a net.Socket or net.Server object, or undefined.
+        prependOnceListener(event: "online", listener: (worker: Worker) => void): this;
+        prependOnceListener(event: "setup", listener: (settings: any) => void): this;
+
+    }
+
+    export function disconnect(callback?: Function): void;
+    export function fork(env?: any): Worker;
+    export var isMaster: boolean;
+    export var isWorker: boolean;
+    // TODO: cluster.schedulingPolicy
+    export var settings: ClusterSettings;
+    export function setupMaster(settings?: ClusterSetupMasterSettings): void;
+    export var worker: Worker;
+    export var workers: {
+        [index: string]: Worker
+    };
+
+    /**
+     * events.EventEmitter
+     *   1. disconnect
+     *   2. exit
+     *   3. fork
+     *   4. listening
+     *   5. message
+     *   6. online
+     *   7. setup
+     */
+    export function addListener(event: string, listener: Function): Cluster;
+    export function addListener(event: "disconnect", listener: (worker: Worker) => void): Cluster;
+    export function addListener(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): Cluster;
+    export function addListener(event: "fork", listener: (worker: Worker) => void): Cluster;
+    export function addListener(event: "listening", listener: (worker: Worker, address: Address) => void): Cluster;
+    export function addListener(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): Cluster;  // the handle is a net.Socket or net.Server object, or undefined.
+    export function addListener(event: "online", listener: (worker: Worker) => void): Cluster;
+    export function addListener(event: "setup", listener: (settings: any) => void): Cluster;
+
+    export function emit(event: string, listener: Function): boolean;
+    export function emit(event: "disconnect", listener: (worker: Worker) => void): boolean;
+    export function emit(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): boolean;
+    export function emit(event: "fork", listener: (worker: Worker) => void): boolean;
+    export function emit(event: "listening", listener: (worker: Worker, address: Address) => void): boolean;
+    export function emit(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): boolean;
+    export function emit(event: "online", listener: (worker: Worker) => void): boolean;
+    export function emit(event: "setup", listener: (settings: any) => void): boolean;
+
+    export function on(event: string, listener: Function): Cluster;
+    export function on(event: "disconnect", listener: (worker: Worker) => void): Cluster;
+    export function on(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): Cluster;
+    export function on(event: "fork", listener: (worker: Worker) => void): Cluster;
+    export function on(event: "listening", listener: (worker: Worker, address: Address) => void): Cluster;
+    export function on(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): Cluster;  // the handle is a net.Socket or net.Server object, or undefined.
+    export function on(event: "online", listener: (worker: Worker) => void): Cluster;
+    export function on(event: "setup", listener: (settings: any) => void): Cluster;
+
+    export function once(event: string, listener: Function): Cluster;
+    export function once(event: "disconnect", listener: (worker: Worker) => void): Cluster;
+    export function once(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): Cluster;
+    export function once(event: "fork", listener: (worker: Worker) => void): Cluster;
+    export function once(event: "listening", listener: (worker: Worker, address: Address) => void): Cluster;
+    export function once(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): Cluster;  // the handle is a net.Socket or net.Server object, or undefined.
+    export function once(event: "online", listener: (worker: Worker) => void): Cluster;
+    export function once(event: "setup", listener: (settings: any) => void): Cluster;
+
+    export function removeListener(event: string, listener: Function): Cluster;
+    export function removeAllListeners(event?: string): Cluster;
+    export function setMaxListeners(n: number): Cluster;
+    export function getMaxListeners(): number;
+    export function listeners(event: string): Function[];
+    export function listenerCount(type: string): number;
+
+    export function prependListener(event: string, listener: Function): Cluster;
+    export function prependListener(event: "disconnect", listener: (worker: Worker) => void): Cluster;
+    export function prependListener(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): Cluster;
+    export function prependListener(event: "fork", listener: (worker: Worker) => void): Cluster;
+    export function prependListener(event: "listening", listener: (worker: Worker, address: Address) => void): Cluster;
+    export function prependListener(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): Cluster;  // the handle is a net.Socket or net.Server object, or undefined.
+    export function prependListener(event: "online", listener: (worker: Worker) => void): Cluster;
+    export function prependListener(event: "setup", listener: (settings: any) => void): Cluster;
+
+    export function prependOnceListener(event: string, listener: Function): Cluster;
+    export function prependOnceListener(event: "disconnect", listener: (worker: Worker) => void): Cluster;
+    export function prependOnceListener(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): Cluster;
+    export function prependOnceListener(event: "fork", listener: (worker: Worker) => void): Cluster;
+    export function prependOnceListener(event: "listening", listener: (worker: Worker, address: Address) => void): Cluster;
+    export function prependOnceListener(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): Cluster;  // the handle is a net.Socket or net.Server object, or undefined.
+    export function prependOnceListener(event: "online", listener: (worker: Worker) => void): Cluster;
+    export function prependOnceListener(event: "setup", listener: (settings: any) => void): Cluster;
+
+    export function eventNames(): string[];
+}
+
+declare module "zlib" {
+    import * as stream from "stream";
+    export interface ZlibOptions { chunkSize?: number; windowBits?: number; level?: number; memLevel?: number; strategy?: number; dictionary?: any; finishFlush?: number }
+
+    export interface Gzip extends stream.Transform { }
+    export interface Gunzip extends stream.Transform { }
+    export interface Deflate extends stream.Transform { }
+    export interface Inflate extends stream.Transform { }
+    export interface DeflateRaw extends stream.Transform { }
+    export interface InflateRaw extends stream.Transform { }
+    export interface Unzip extends stream.Transform { }
+
+    export function createGzip(options?: ZlibOptions): Gzip;
+    export function createGunzip(options?: ZlibOptions): Gunzip;
+    export function createDeflate(options?: ZlibOptions): Deflate;
+    export function createInflate(options?: ZlibOptions): Inflate;
+    export function createDeflateRaw(options?: ZlibOptions): DeflateRaw;
+    export function createInflateRaw(options?: ZlibOptions): InflateRaw;
+    export function createUnzip(options?: ZlibOptions): Unzip;
+
+    export function deflate(buf: Buffer, callback: (error: Error, result: any) => void): void;
+    export function deflateSync(buf: Buffer, options?: ZlibOptions): any;
+    export function deflateRaw(buf: Buffer, callback: (error: Error, result: any) => void): void;
+    export function deflateRawSync(buf: Buffer, options?: ZlibOptions): any;
+    export function gzip(buf: Buffer, callback: (error: Error, result: any) => void): void;
+    export function gzipSync(buf: Buffer, options?: ZlibOptions): any;
+    export function gunzip(buf: Buffer, callback: (error: Error, result: any) => void): void;
+    export function gunzipSync(buf: Buffer, options?: ZlibOptions): any;
+    export function inflate(buf: Buffer, callback: (error: Error, result: any) => void): void;
+    export function inflateSync(buf: Buffer, options?: ZlibOptions): any;
+    export function inflateRaw(buf: Buffer, callback: (error: Error, result: any) => void): void;
+    export function inflateRawSync(buf: Buffer, options?: ZlibOptions): any;
+    export function unzip(buf: Buffer, callback: (error: Error, result: any) => void): void;
+    export function unzipSync(buf: Buffer, options?: ZlibOptions): any;
+
+    // Constants
+    export var Z_NO_FLUSH: number;
+    export var Z_PARTIAL_FLUSH: number;
+    export var Z_SYNC_FLUSH: number;
+    export var Z_FULL_FLUSH: number;
+    export var Z_FINISH: number;
+    export var Z_BLOCK: number;
+    export var Z_TREES: number;
+    export var Z_OK: number;
+    export var Z_STREAM_END: number;
+    export var Z_NEED_DICT: number;
+    export var Z_ERRNO: number;
+    export var Z_STREAM_ERROR: number;
+    export var Z_DATA_ERROR: number;
+    export var Z_MEM_ERROR: number;
+    export var Z_BUF_ERROR: number;
+    export var Z_VERSION_ERROR: number;
+    export var Z_NO_COMPRESSION: number;
+    export var Z_BEST_SPEED: number;
+    export var Z_BEST_COMPRESSION: number;
+    export var Z_DEFAULT_COMPRESSION: number;
+    export var Z_FILTERED: number;
+    export var Z_HUFFMAN_ONLY: number;
+    export var Z_RLE: number;
+    export var Z_FIXED: number;
+    export var Z_DEFAULT_STRATEGY: number;
+    export var Z_BINARY: number;
+    export var Z_TEXT: number;
+    export var Z_ASCII: number;
+    export var Z_UNKNOWN: number;
+    export var Z_DEFLATED: number;
+    export var Z_NULL: number;
+}
+
+declare module "os" {
+    export interface CpuInfo {
+        model: string;
+        speed: number;
+        times: {
+            user: number;
+            nice: number;
+            sys: number;
+            idle: number;
+            irq: number;
+        };
+    }
+
+    export interface NetworkInterfaceInfo {
+        address: string;
+        netmask: string;
+        family: string;
+        mac: string;
+        internal: boolean;
+    }
+
+    export function hostname(): string;
+    export function loadavg(): number[];
+    export function uptime(): number;
+    export function freemem(): number;
+    export function totalmem(): number;
+    export function cpus(): CpuInfo[];
+    export function type(): string;
+    export function release(): string;
+    export function networkInterfaces(): { [index: string]: NetworkInterfaceInfo[] };
+    export function homedir(): string;
+    export function userInfo(options?: { encoding: string }): { username: string, uid: number, gid: number, shell: any, homedir: string }
+    export var constants: {
+        UV_UDP_REUSEADDR: number,
+        errno: {
+            SIGHUP: number;
+            SIGINT: number;
+            SIGQUIT: number;
+            SIGILL: number;
+            SIGTRAP: number;
+            SIGABRT: number;
+            SIGIOT: number;
+            SIGBUS: number;
+            SIGFPE: number;
+            SIGKILL: number;
+            SIGUSR1: number;
+            SIGSEGV: number;
+            SIGUSR2: number;
+            SIGPIPE: number;
+            SIGALRM: number;
+            SIGTERM: number;
+            SIGCHLD: number;
+            SIGSTKFLT: number;
+            SIGCONT: number;
+            SIGSTOP: number;
+            SIGTSTP: number;
+            SIGTTIN: number;
+            SIGTTOU: number;
+            SIGURG: number;
+            SIGXCPU: number;
+            SIGXFSZ: number;
+            SIGVTALRM: number;
+            SIGPROF: number;
+            SIGWINCH: number;
+            SIGIO: number;
+            SIGPOLL: number;
+            SIGPWR: number;
+            SIGSYS: number;
+            SIGUNUSED: number;
+        },
+        signals: {
+            E2BIG: number;
+            EACCES: number;
+            EADDRINUSE: number;
+            EADDRNOTAVAIL: number;
+            EAFNOSUPPORT: number;
+            EAGAIN: number;
+            EALREADY: number;
+            EBADF: number;
+            EBADMSG: number;
+            EBUSY: number;
+            ECANCELED: number;
+            ECHILD: number;
+            ECONNABORTED: number;
+            ECONNREFUSED: number;
+            ECONNRESET: number;
+            EDEADLK: number;
+            EDESTADDRREQ: number;
+            EDOM: number;
+            EDQUOT: number;
+            EEXIST: number;
+            EFAULT: number;
+            EFBIG: number;
+            EHOSTUNREACH: number;
+            EIDRM: number;
+            EILSEQ: number;
+            EINPROGRESS: number;
+            EINTR: number;
+            EINVAL: number;
+            EIO: number;
+            EISCONN: number;
+            EISDIR: number;
+            ELOOP: number;
+            EMFILE: number;
+            EMLINK: number;
+            EMSGSIZE: number;
+            EMULTIHOP: number;
+            ENAMETOOLONG: number;
+            ENETDOWN: number;
+            ENETRESET: number;
+            ENETUNREACH: number;
+            ENFILE: number;
+            ENOBUFS: number;
+            ENODATA: number;
+            ENODEV: number;
+            ENOENT: number;
+            ENOEXEC: number;
+            ENOLCK: number;
+            ENOLINK: number;
+            ENOMEM: number;
+            ENOMSG: number;
+            ENOPROTOOPT: number;
+            ENOSPC: number;
+            ENOSR: number;
+            ENOSTR: number;
+            ENOSYS: number;
+            ENOTCONN: number;
+            ENOTDIR: number;
+            ENOTEMPTY: number;
+            ENOTSOCK: number;
+            ENOTSUP: number;
+            ENOTTY: number;
+            ENXIO: number;
+            EOPNOTSUPP: number;
+            EOVERFLOW: number;
+            EPERM: number;
+            EPIPE: number;
+            EPROTO: number;
+            EPROTONOSUPPORT: number;
+            EPROTOTYPE: number;
+            ERANGE: number;
+            EROFS: number;
+            ESPIPE: number;
+            ESRCH: number;
+            ESTALE: number;
+            ETIME: number;
+            ETIMEDOUT: number;
+            ETXTBSY: number;
+            EWOULDBLOCK: number;
+            EXDEV: number;
+        },
+    };
+    export function arch(): string;
+    export function platform(): string;
+    export function tmpdir(): string;
+    export var EOL: string;
+    export function endianness(): "BE" | "LE";
+}
+
+declare module "https" {
+    import * as tls from "tls";
+    import * as events from "events";
+    import * as http from "http";
+
+    export interface ServerOptions {
+        pfx?: any;
+        key?: any;
+        passphrase?: string;
+        cert?: any;
+        ca?: any;
+        crl?: any;
+        ciphers?: string;
+        honorCipherOrder?: boolean;
+        requestCert?: boolean;
+        rejectUnauthorized?: boolean;
+        NPNProtocols?: any;
+        SNICallback?: (servername: string, cb: (err: Error, ctx: tls.SecureContext) => any) => any;
+    }
+
+    export interface RequestOptions extends http.RequestOptions {
+        pfx?: any;
+        key?: any;
+        passphrase?: string;
+        cert?: any;
+        ca?: any;
+        ciphers?: string;
+        rejectUnauthorized?: boolean;
+        secureProtocol?: string;
+    }
+
+    export interface Agent extends http.Agent { }
+
+    export interface AgentOptions extends http.AgentOptions {
+        pfx?: any;
+        key?: any;
+        passphrase?: string;
+        cert?: any;
+        ca?: any;
+        ciphers?: string;
+        rejectUnauthorized?: boolean;
+        secureProtocol?: string;
+        maxCachedSessions?: number;
+    }
+
+    export var Agent: {
+        new (options?: AgentOptions): Agent;
+    };
+    export interface Server extends tls.Server { }
+    export function createServer(options: ServerOptions, requestListener?: Function): Server;
+    export function request(options: RequestOptions, callback?: (res: http.IncomingMessage) => void): http.ClientRequest;
+    export function get(options: RequestOptions, callback?: (res: http.IncomingMessage) => void): http.ClientRequest;
+    export var globalAgent: Agent;
+}
+
+declare module "punycode" {
+    export function decode(string: string): string;
+    export function encode(string: string): string;
+    export function toUnicode(domain: string): string;
+    export function toASCII(domain: string): string;
+    export var ucs2: ucs2;
+    interface ucs2 {
+        decode(string: string): number[];
+        encode(codePoints: number[]): string;
+    }
+    export var version: any;
+}
+
+declare module "repl" {
+    import * as stream from "stream";
+    import * as readline from "readline";
+
+    export interface ReplOptions {
+        prompt?: string;
+        input?: NodeJS.ReadableStream;
+        output?: NodeJS.WritableStream;
+        terminal?: boolean;
+        eval?: Function;
+        useColors?: boolean;
+        useGlobal?: boolean;
+        ignoreUndefined?: boolean;
+        writer?: Function;
+        completer?: Function;
+        replMode?: any;
+        breakEvalOnSigint?: any;
+    }
+
+    export interface REPLServer extends readline.ReadLine {
+        defineCommand(keyword: string, cmd: Function | { help: string, action: Function }): void;
+        displayPrompt(preserveCursor?: boolean): void;
+
+        /**
+         * events.EventEmitter
+         * 1. exit
+         * 2. reset
+         **/
+
+        addListener(event: string, listener: Function): this;
+        addListener(event: "exit", listener: () => void): this;
+        addListener(event: "reset", listener: Function): this;
+
+        emit(event: string, ...args: any[]): boolean;
+        emit(event: "exit"): boolean;
+        emit(event: "reset", context: any): boolean;
+
+        on(event: string, listener: Function): this;
+        on(event: "exit", listener: () => void): this;
+        on(event: "reset", listener: Function): this;
+
+        once(event: string, listener: Function): this;
+        once(event: "exit", listener: () => void): this;
+        once(event: "reset", listener: Function): this;
+
+        prependListener(event: string, listener: Function): this;
+        prependListener(event: "exit", listener: () => void): this;
+        prependListener(event: "reset", listener: Function): this;
+
+        prependOnceListener(event: string, listener: Function): this;
+        prependOnceListener(event: "exit", listener: () => void): this;
+        prependOnceListener(event: "reset", listener: Function): this;
+    }
+
+    export function start(options: ReplOptions): REPLServer;
+}
+
+declare module "readline" {
+    import * as events from "events";
+    import * as stream from "stream";
+
+    export interface Key {
+        sequence?: string;
+        name?: string;
+        ctrl?: boolean;
+        meta?: boolean;
+        shift?: boolean;
+    }
+
+    export interface ReadLine extends events.EventEmitter {
+        setPrompt(prompt: string): void;
+        prompt(preserveCursor?: boolean): void;
+        question(query: string, callback: (answer: string) => void): void;
+        pause(): ReadLine;
+        resume(): ReadLine;
+        close(): void;
+        write(data: string | Buffer, key?: Key): void;
+
+        /**
+         * events.EventEmitter
+         * 1. close
+         * 2. line
+         * 3. pause
+         * 4. resume
+         * 5. SIGCONT
+         * 6. SIGINT
+         * 7. SIGTSTP
+         **/
+
+        addListener(event: string, listener: Function): this;
+        addListener(event: "close", listener: () => void): this;
+        addListener(event: "line", listener: (input: any) => void): this;
+        addListener(event: "pause", listener: () => void): this;
+        addListener(event: "resume", listener: () => void): this;
+        addListener(event: "SIGCONT", listener: () => void): this;
+        addListener(event: "SIGINT", listener: () => void): this;
+        addListener(event: "SIGTSTP", listener: () => void): this;
+
+        emit(event: string, ...args: any[]): boolean;
+        emit(event: "close"): boolean;
+        emit(event: "line", input: any): boolean;
+        emit(event: "pause"): boolean;
+        emit(event: "resume"): boolean;
+        emit(event: "SIGCONT"): boolean;
+        emit(event: "SIGINT"): boolean;
+        emit(event: "SIGTSTP"): boolean;
+
+        on(event: string, listener: Function): this;
+        on(event: "close", listener: () => void): this;
+        on(event: "line", listener: (input: any) => void): this;
+        on(event: "pause", listener: () => void): this;
+        on(event: "resume", listener: () => void): this;
+        on(event: "SIGCONT", listener: () => void): this;
+        on(event: "SIGINT", listener: () => void): this;
+        on(event: "SIGTSTP", listener: () => void): this;
+
+        once(event: string, listener: Function): this;
+        once(event: "close", listener: () => void): this;
+        once(event: "line", listener: (input: any) => void): this;
+        once(event: "pause", listener: () => void): this;
+        once(event: "resume", listener: () => void): this;
+        once(event: "SIGCONT", listener: () => void): this;
+        once(event: "SIGINT", listener: () => void): this;
+        once(event: "SIGTSTP", listener: () => void): this;
+
+        prependListener(event: string, listener: Function): this;
+        prependListener(event: "close", listener: () => void): this;
+        prependListener(event: "line", listener: (input: any) => void): this;
+        prependListener(event: "pause", listener: () => void): this;
+        prependListener(event: "resume", listener: () => void): this;
+        prependListener(event: "SIGCONT", listener: () => void): this;
+        prependListener(event: "SIGINT", listener: () => void): this;
+        prependListener(event: "SIGTSTP", listener: () => void): this;
+
+        prependOnceListener(event: string, listener: Function): this;
+        prependOnceListener(event: "close", listener: () => void): this;
+        prependOnceListener(event: "line", listener: (input: any) => void): this;
+        prependOnceListener(event: "pause", listener: () => void): this;
+        prependOnceListener(event: "resume", listener: () => void): this;
+        prependOnceListener(event: "SIGCONT", listener: () => void): this;
+        prependOnceListener(event: "SIGINT", listener: () => void): this;
+        prependOnceListener(event: "SIGTSTP", listener: () => void): this;
+    }
+
+    export interface Completer {
+        (line: string): CompleterResult;
+        (line: string, callback: (err: any, result: CompleterResult) => void): any;
+    }
+
+    export type CompleterResult = [string[], string];
+
+    export interface ReadLineOptions {
+        input: NodeJS.ReadableStream;
+        output?: NodeJS.WritableStream;
+        completer?: Completer;
+        terminal?: boolean;
+        historySize?: number;
+    }
+
+    export function createInterface(input: NodeJS.ReadableStream, output?: NodeJS.WritableStream, completer?: Completer, terminal?: boolean): ReadLine;
+    export function createInterface(options: ReadLineOptions): ReadLine;
+
+    export function cursorTo(stream: NodeJS.WritableStream, x: number, y: number): void;
+    export function moveCursor(stream: NodeJS.WritableStream, dx: number | string, dy: number | string): void;
+    export function clearLine(stream: NodeJS.WritableStream, dir: number): void;
+    export function clearScreenDown(stream: NodeJS.WritableStream): void;
+}
+
+declare module "vm" {
+    export interface Context { }
+    export interface ScriptOptions {
+        filename?: string;
+        lineOffset?: number;
+        columnOffset?: number;
+        displayErrors?: boolean;
+        timeout?: number;
+        cachedData?: Buffer;
+        produceCachedData?: boolean;
+    }
+    export interface RunningScriptOptions {
+        filename?: string;
+        lineOffset?: number;
+        columnOffset?: number;
+        displayErrors?: boolean;
+        timeout?: number;
+    }
+    export class Script {
+        constructor(code: string, options?: ScriptOptions);
+        runInContext(contextifiedSandbox: Context, options?: RunningScriptOptions): any;
+        runInNewContext(sandbox?: Context, options?: RunningScriptOptions): any;
+        runInThisContext(options?: RunningScriptOptions): any;
+    }
+    export function createContext(sandbox?: Context): Context;
+    export function isContext(sandbox: Context): boolean;
+    export function runInContext(code: string, contextifiedSandbox: Context, options?: RunningScriptOptions): any;
+    export function runInDebugContext(code: string): any;
+    export function runInNewContext(code: string, sandbox?: Context, options?: RunningScriptOptions): any;
+    export function runInThisContext(code: string, options?: RunningScriptOptions): any;
+}
+
+declare module "child_process" {
+    import * as events from "events";
+    import * as stream from "stream";
+    import * as net from "net";
+
+    export interface ChildProcess extends events.EventEmitter {
+        stdin: stream.Writable;
+        stdout: stream.Readable;
+        stderr: stream.Readable;
+        stdio: [stream.Writable, stream.Readable, stream.Readable];
+        pid: number;
+        kill(signal?: string): void;
+        send(message: any, sendHandle?: any): boolean;
+        connected: boolean;
+        disconnect(): void;
+        unref(): void;
+        ref(): void;
+    
+        /**
+         * events.EventEmitter
+         * 1. close
+         * 2. disconnet
+         * 3. error
+         * 4. exit
+         * 5. message
+         **/
+
+        addListener(event: string, listener: Function): this;
+        addListener(event: "close", listener: (code: number, signal: string) => void): this;
+        addListener(event: "disconnet", listener: () => void): this;
+        addListener(event: "error", listener: (err: Error) => void): this;
+        addListener(event: "exit", listener: (code: number, signal: string) => void): this;
+        addListener(event: "message", listener: (message: any, sendHandle: net.Socket | net.Server) => void): this;
+
+        emit(event: string, ...args: any[]): boolean;
+        emit(event: "close", code: number, signal: string): boolean;
+        emit(event: "disconnet"): boolean;
+        emit(event: "error", err: Error): boolean;
+        emit(event: "exit", code: number, signal: string): boolean;
+        emit(event: "message", message: any, sendHandle: net.Socket | net.Server): boolean;
+
+        on(event: string, listener: Function): this;
+        on(event: "close", listener: (code: number, signal: string) => void): this;
+        on(event: "disconnet", listener: () => void): this;
+        on(event: "error", listener: (err: Error) => void): this;
+        on(event: "exit", listener: (code: number, signal: string) => void): this;
+        on(event: "message", listener: (message: any, sendHandle: net.Socket | net.Server) => void): this;
+
+        once(event: string, listener: Function): this;
+        once(event: "close", listener: (code: number, signal: string) => void): this;
+        once(event: "disconnet", listener: () => void): this;
+        once(event: "error", listener: (err: Error) => void): this;
+        once(event: "exit", listener: (code: number, signal: string) => void): this;
+        once(event: "message", listener: (message: any, sendHandle: net.Socket | net.Server) => void): this;
+
+        prependListener(event: string, listener: Function): this;
+        prependListener(event: "close", listener: (code: number, signal: string) => void): this;
+        prependListener(event: "disconnet", listener: () => void): this;
+        prependListener(event: "error", listener: (err: Error) => void): this;
+        prependListener(event: "exit", listener: (code: number, signal: string) => void): this;
+        prependListener(event: "message", listener: (message: any, sendHandle: net.Socket | net.Server) => void): this;
+
+        prependOnceListener(event: string, listener: Function): this;
+        prependOnceListener(event: "close", listener: (code: number, signal: string) => void): this;
+        prependOnceListener(event: "disconnet", listener: () => void): this;
+        prependOnceListener(event: "error", listener: (err: Error) => void): this;
+        prependOnceListener(event: "exit", listener: (code: number, signal: string) => void): this;
+        prependOnceListener(event: "message", listener: (message: any, sendHandle: net.Socket | net.Server) => void): this;
+    }
+
+    export interface SpawnOptions {
+        cwd?: string;
+        env?: any;
+        stdio?: any;
+        detached?: boolean;
+        uid?: number;
+        gid?: number;
+        shell?: boolean | string;
+    }
+    export function spawn(command: string, args?: string[], options?: SpawnOptions): ChildProcess;
+
+    export interface ExecOptions {
+        cwd?: string;
+        env?: any;
+        shell?: string;
+        timeout?: number;
+        maxBuffer?: number;
+        killSignal?: string;
+        uid?: number;
+        gid?: number;
+    }
+    export interface ExecOptionsWithStringEncoding extends ExecOptions {
+        encoding: BufferEncoding;
+    }
+    export interface ExecOptionsWithBufferEncoding extends ExecOptions {
+        encoding: string; // specify `null`.
+    }
+    export function exec(command: string, callback?: (error: Error, stdout: string, stderr: string) => void): ChildProcess;
+    export function exec(command: string, options: ExecOptionsWithStringEncoding, callback?: (error: Error, stdout: string, stderr: string) => void): ChildProcess;
+    // usage. child_process.exec("tsc", {encoding: null as string}, (err, stdout, stderr) => {});
+    export function exec(command: string, options: ExecOptionsWithBufferEncoding, callback?: (error: Error, stdout: Buffer, stderr: Buffer) => void): ChildProcess;
+    export function exec(command: string, options: ExecOptions, callback?: (error: Error, stdout: string, stderr: string) => void): ChildProcess;
+
+    export interface ExecFileOptions {
+        cwd?: string;
+        env?: any;
+        timeout?: number;
+        maxBuffer?: number;
+        killSignal?: string;
+        uid?: number;
+        gid?: number;
+    }
+    export interface ExecFileOptionsWithStringEncoding extends ExecFileOptions {
+        encoding: BufferEncoding;
+    }
+    export interface ExecFileOptionsWithBufferEncoding extends ExecFileOptions {
+        encoding: string; // specify `null`.
+    }
+    export function execFile(file: string, callback?: (error: Error, stdout: string, stderr: string) => void): ChildProcess;
+    export function execFile(file: string, options?: ExecFileOptionsWithStringEncoding, callback?: (error: Error, stdout: string, stderr: string) => void): ChildProcess;
+    // usage. child_process.execFile("file.sh", {encoding: null as string}, (err, stdout, stderr) => {});
+    export function execFile(file: string, options?: ExecFileOptionsWithBufferEncoding, callback?: (error: Error, stdout: Buffer, stderr: Buffer) => void): ChildProcess;
+    export function execFile(file: string, options?: ExecFileOptions, callback?: (error: Error, stdout: string, stderr: string) => void): ChildProcess;
+    export function execFile(file: string, args?: string[], callback?: (error: Error, stdout: string, stderr: string) => void): ChildProcess;
+    export function execFile(file: string, args?: string[], options?: ExecFileOptionsWithStringEncoding, callback?: (error: Error, stdout: string, stderr: string) => void): ChildProcess;
+    // usage. child_process.execFile("file.sh", ["foo"], {encoding: null as string}, (err, stdout, stderr) => {});
+    export function execFile(file: string, args?: string[], options?: ExecFileOptionsWithBufferEncoding, callback?: (error: Error, stdout: Buffer, stderr: Buffer) => void): ChildProcess;
+    export function execFile(file: string, args?: string[], options?: ExecFileOptions, callback?: (error: Error, stdout: string, stderr: string) => void): ChildProcess;
+
+    export interface ForkOptions {
+        cwd?: string;
+        env?: any;
+        execPath?: string;
+        execArgv?: string[];
+        silent?: boolean;
+        uid?: number;
+        gid?: number;
+    }
+    export function fork(modulePath: string, args?: string[], options?: ForkOptions): ChildProcess;
+
+    export interface SpawnSyncOptions {
+        cwd?: string;
+        input?: string | Buffer;
+        stdio?: any;
+        env?: any;
+        uid?: number;
+        gid?: number;
+        timeout?: number;
+        killSignal?: string;
+        maxBuffer?: number;
+        encoding?: string;
+        shell?: boolean | string;
+    }
+    export interface SpawnSyncOptionsWithStringEncoding extends SpawnSyncOptions {
+        encoding: BufferEncoding;
+    }
+    export interface SpawnSyncOptionsWithBufferEncoding extends SpawnSyncOptions {
+        encoding: string; // specify `null`.
+    }
+    export interface SpawnSyncReturns<T> {
+        pid: number;
+        output: string[];
+        stdout: T;
+        stderr: T;
+        status: number;
+        signal: string;
+        error: Error;
+    }
+    export function spawnSync(command: string): SpawnSyncReturns<Buffer>;
+    export function spawnSync(command: string, options?: SpawnSyncOptionsWithStringEncoding): SpawnSyncReturns<string>;
+    export function spawnSync(command: string, options?: SpawnSyncOptionsWithBufferEncoding): SpawnSyncReturns<Buffer>;
+    export function spawnSync(command: string, options?: SpawnSyncOptions): SpawnSyncReturns<Buffer>;
+    export function spawnSync(command: string, args?: string[], options?: SpawnSyncOptionsWithStringEncoding): SpawnSyncReturns<string>;
+    export function spawnSync(command: string, args?: string[], options?: SpawnSyncOptionsWithBufferEncoding): SpawnSyncReturns<Buffer>;
+    export function spawnSync(command: string, args?: string[], options?: SpawnSyncOptions): SpawnSyncReturns<Buffer>;
+
+    export interface ExecSyncOptions {
+        cwd?: string;
+        input?: string | Buffer;
+        stdio?: any;
+        env?: any;
+        shell?: string;
+        uid?: number;
+        gid?: number;
+        timeout?: number;
+        killSignal?: string;
+        maxBuffer?: number;
+        encoding?: string;
+    }
+    export interface ExecSyncOptionsWithStringEncoding extends ExecSyncOptions {
+        encoding: BufferEncoding;
+    }
+    export interface ExecSyncOptionsWithBufferEncoding extends ExecSyncOptions {
+        encoding: string; // specify `null`.
+    }
+    export function execSync(command: string): Buffer;
+    export function execSync(command: string, options?: ExecSyncOptionsWithStringEncoding): string;
+    export function execSync(command: string, options?: ExecSyncOptionsWithBufferEncoding): Buffer;
+    export function execSync(command: string, options?: ExecSyncOptions): Buffer;
+
+    export interface ExecFileSyncOptions {
+        cwd?: string;
+        input?: string | Buffer;
+        stdio?: any;
+        env?: any;
+        uid?: number;
+        gid?: number;
+        timeout?: number;
+        killSignal?: string;
+        maxBuffer?: number;
+        encoding?: string;
+    }
+    export interface ExecFileSyncOptionsWithStringEncoding extends ExecFileSyncOptions {
+        encoding: BufferEncoding;
+    }
+    export interface ExecFileSyncOptionsWithBufferEncoding extends ExecFileSyncOptions {
+        encoding: string; // specify `null`.
+    }
+    export function execFileSync(command: string): Buffer;
+    export function execFileSync(command: string, options?: ExecFileSyncOptionsWithStringEncoding): string;
+    export function execFileSync(command: string, options?: ExecFileSyncOptionsWithBufferEncoding): Buffer;
+    export function execFileSync(command: string, options?: ExecFileSyncOptions): Buffer;
+    export function execFileSync(command: string, args?: string[], options?: ExecFileSyncOptionsWithStringEncoding): string;
+    export function execFileSync(command: string, args?: string[], options?: ExecFileSyncOptionsWithBufferEncoding): Buffer;
+    export function execFileSync(command: string, args?: string[], options?: ExecFileSyncOptions): Buffer;
+}
+
+declare module "url" {
+    export interface Url {
+        href?: string;
+        protocol?: string;
+        auth?: string;
+        hostname?: string;
+        port?: string;
+        host?: string;
+        pathname?: string;
+        search?: string;
+        query?: string | any;
+        slashes?: boolean;
+        hash?: string;
+        path?: string;
+    }
+
+    export function parse(urlStr: string, parseQueryString?: boolean, slashesDenoteHost?: boolean): Url;
+    export function format(url: Url): string;
+    export function resolve(from: string, to: string): string;
+}
+
+declare module "dns" {
+    export interface MxRecord {
+        exchange: string,
+        priority: number
+    }
+
+    export function lookup(domain: string, family: number, callback: (err: Error, address: string, family: number) => void): string;
+    export function lookup(domain: string, callback: (err: Error, address: string, family: number) => void): string;
+    export function resolve(domain: string, rrtype: string, callback: (err: Error, addresses: string[]) => void): string[];
+    export function resolve(domain: string, callback: (err: Error, addresses: string[]) => void): string[];
+    export function resolve4(domain: string, callback: (err: Error, addresses: string[]) => void): string[];
+    export function resolve6(domain: string, callback: (err: Error, addresses: string[]) => void): string[];
+    export function resolveMx(domain: string, callback: (err: Error, addresses: MxRecord[]) => void): string[];
+    export function resolveTxt(domain: string, callback: (err: Error, addresses: string[]) => void): string[];
+    export function resolveSrv(domain: string, callback: (err: Error, addresses: string[]) => void): string[];
+    export function resolveNs(domain: string, callback: (err: Error, addresses: string[]) => void): string[];
+    export function resolveCname(domain: string, callback: (err: Error, addresses: string[]) => void): string[];
+    export function reverse(ip: string, callback: (err: Error, domains: string[]) => void): string[];
+    export function setServers(servers: string[]): void;
+
+    //Error codes
+    export var NODATA: string;
+    export var FORMERR: string;
+    export var SERVFAIL: string;
+    export var NOTFOUND: string;
+    export var NOTIMP: string;
+    export var REFUSED: string;
+    export var BADQUERY: string;
+    export var BADNAME: string;
+    export var BADFAMILY: string;
+    export var BADRESP: string;
+    export var CONNREFUSED: string;
+    export var TIMEOUT: string;
+    export var EOF: string;
+    export var FILE: string;
+    export var NOMEM: string;
+    export var DESTRUCTION: string;
+    export var BADSTR: string;
+    export var BADFLAGS: string;
+    export var NONAME: string;
+    export var BADHINTS: string;
+    export var NOTINITIALIZED: string;
+    export var LOADIPHLPAPI: string;
+    export var ADDRGETNETWORKPARAMS: string;
+    export var CANCELLED: string;
+}
+
+declare module "net" {
+    import * as stream from "stream";
+    import * as events from "events";
+
+    export interface Socket extends stream.Duplex {
+        // Extended base methods
+        write(buffer: Buffer): boolean;
+        write(buffer: Buffer, cb?: Function): boolean;
+        write(str: string, cb?: Function): boolean;
+        write(str: string, encoding?: string, cb?: Function): boolean;
+        write(str: string, encoding?: string, fd?: string): boolean;
+
+        connect(port: number, host?: string, connectionListener?: Function): void;
+        connect(path: string, connectionListener?: Function): void;
+        bufferSize: number;
+        setEncoding(encoding?: string): void;
+        write(data: any, encoding?: string, callback?: Function): void;
+        destroy(): void;
+        pause(): Socket;
+        resume(): Socket;
+        setTimeout(timeout: number, callback?: Function): void;
+        setNoDelay(noDelay?: boolean): void;
+        setKeepAlive(enable?: boolean, initialDelay?: number): void;
+        address(): { port: number; family: string; address: string; };
+        unref(): void;
+        ref(): void;
+
+        remoteAddress: string;
+        remoteFamily: string;
+        remotePort: number;
+        localAddress: string;
+        localPort: number;
+        bytesRead: number;
+        bytesWritten: number;
+        destroyed: boolean;
+
+        // Extended base methods
+        end(): void;
+        end(buffer: Buffer, cb?: Function): void;
+        end(str: string, cb?: Function): void;
+        end(str: string, encoding?: string, cb?: Function): void;
+        end(data?: any, encoding?: string): void;
+
+        /**
+         * events.EventEmitter
+         *   1. close
+         *   2. connect
+         *   3. data
+         *   4. drain
+         *   5. end
+         *   6. error
+         *   7. lookup
+         *   8. timeout
+         */
+        addListener(event: string, listener: Function): this;
+        addListener(event: "close", listener: (had_error: boolean) => void): this;
+        addListener(event: "connect", listener: () => void): this;
+        addListener(event: "data", listener: (data: Buffer) => void): this;
+        addListener(event: "drain", listener: () => void): this;
+        addListener(event: "end", listener: () => void): this;
+        addListener(event: "error", listener: (err: Error) => void): this;
+        addListener(event: "lookup", listener: (err: Error, address: string, family: string | number, host: string) => void): this;
+        addListener(event: "timeout", listener: () => void): this;
+
+        emit(event: string, ...args: any[]): boolean;
+        emit(event: "close", had_error: boolean): boolean;
+        emit(event: "connect"): boolean;
+        emit(event: "data", data: Buffer): boolean;
+        emit(event: "drain"): boolean;
+        emit(event: "end"): boolean;
+        emit(event: "error", err: Error): boolean;
+        emit(event: "lookup", err: Error, address: string, family: string | number, host: string): boolean;
+        emit(event: "timeout"): boolean;
+
+        on(event: string, listener: Function): this;
+        on(event: "close", listener: (had_error: boolean) => void): this;
+        on(event: "connect", listener: () => void): this;
+        on(event: "data", listener: (data: Buffer) => void): this;
+        on(event: "drain", listener: () => void): this;
+        on(event: "end", listener: () => void): this;
+        on(event: "error", listener: (err: Error) => void): this;
+        on(event: "lookup", listener: (err: Error, address: string, family: string | number, host: string) => void): this;
+        on(event: "timeout", listener: () => void): this;
+
+        once(event: string, listener: Function): this;
+        once(event: "close", listener: (had_error: boolean) => void): this;
+        once(event: "connect", listener: () => void): this;
+        once(event: "data", listener: (data: Buffer) => void): this;
+        once(event: "drain", listener: () => void): this;
+        once(event: "end", listener: () => void): this;
+        once(event: "error", listener: (err: Error) => void): this;
+        once(event: "lookup", listener: (err: Error, address: string, family: string | number, host: string) => void): this;
+        once(event: "timeout", listener: () => void): this;
+
+        prependListener(event: string, listener: Function): this;
+        prependListener(event: "close", listener: (had_error: boolean) => void): this;
+        prependListener(event: "connect", listener: () => void): this;
+        prependListener(event: "data", listener: (data: Buffer) => void): this;
+        prependListener(event: "drain", listener: () => void): this;
+        prependListener(event: "end", listener: () => void): this;
+        prependListener(event: "error", listener: (err: Error) => void): this;
+        prependListener(event: "lookup", listener: (err: Error, address: string, family: string | number, host: string) => void): this;
+        prependListener(event: "timeout", listener: () => void): this;
+
+        prependOnceListener(event: string, listener: Function): this;
+        prependOnceListener(event: "close", listener: (had_error: boolean) => void): this;
+        prependOnceListener(event: "connect", listener: () => void): this;
+        prependOnceListener(event: "data", listener: (data: Buffer) => void): this;
+        prependOnceListener(event: "drain", listener: () => void): this;
+        prependOnceListener(event: "end", listener: () => void): this;
+        prependOnceListener(event: "error", listener: (err: Error) => void): this;
+        prependOnceListener(event: "lookup", listener: (err: Error, address: string, family: string | number, host: string) => void): this;
+        prependOnceListener(event: "timeout", listener: () => void): this;
+    }
+
+    export var Socket: {
+        new (options?: { fd?: string; type?: string; allowHalfOpen?: boolean; }): Socket;
+    };
+
+    export interface ListenOptions {
+        port?: number;
+        host?: string;
+        backlog?: number;
+        path?: string;
+        exclusive?: boolean;
+    }
+
+    export interface Server extends events.EventEmitter {
+        listen(port: number, hostname?: string, backlog?: number, listeningListener?: Function): Server;
+        listen(port: number, hostname?: string, listeningListener?: Function): Server;
+        listen(port: number, backlog?: number, listeningListener?: Function): Server;
+        listen(port: number, listeningListener?: Function): Server;
+        listen(path: string, backlog?: number, listeningListener?: Function): Server;
+        listen(path: string, listeningListener?: Function): Server;
+        listen(options: ListenOptions, listeningListener?: Function): Server;
+        listen(handle: any, backlog?: number, listeningListener?: Function): Server;
+        listen(handle: any, listeningListener?: Function): Server;
+        close(callback?: Function): Server;
+        address(): { port: number; family: string; address: string; };
+        getConnections(cb: (error: Error, count: number) => void): void;
+        ref(): Server;
+        unref(): Server;
+        maxConnections: number;
+        connections: number;
+
+        /**
+         * events.EventEmitter
+         *   1. close
+         *   2. connection
+         *   3. error
+         *   4. listening
+         */
+        addListener(event: string, listener: Function): this;
+        addListener(event: "close", listener: () => void): this;
+        addListener(event: "connection", listener: (socket: Socket) => void): this;
+        addListener(event: "error", listener: (err: Error) => void): this;
+        addListener(event: "listening", listener: () => void): this;
+
+        emit(event: string, ...args: any[]): boolean;
+        emit(event: "close"): boolean;
+        emit(event: "connection", socket: Socket): boolean;
+        emit(event: "error", err: Error): boolean;
+        emit(event: "listening"): boolean;
+
+        on(event: string, listener: Function): this;
+        on(event: "close", listener: () => void): this;
+        on(event: "connection", listener: (socket: Socket) => void): this;
+        on(event: "error", listener: (err: Error) => void): this;
+        on(event: "listening", listener: () => void): this;
+
+        once(event: string, listener: Function): this;
+        once(event: "close", listener: () => void): this;
+        once(event: "connection", listener: (socket: Socket) => void): this;
+        once(event: "error", listener: (err: Error) => void): this;
+        once(event: "listening", listener: () => void): this;
+
+        prependListener(event: string, listener: Function): this;
+        prependListener(event: "close", listener: () => void): this;
+        prependListener(event: "connection", listener: (socket: Socket) => void): this;
+        prependListener(event: "error", listener: (err: Error) => void): this;
+        prependListener(event: "listening", listener: () => void): this;
+
+        prependOnceListener(event: string, listener: Function): this;
+        prependOnceListener(event: "close", listener: () => void): this;
+        prependOnceListener(event: "connection", listener: (socket: Socket) => void): this;
+        prependOnceListener(event: "error", listener: (err: Error) => void): this;
+        prependOnceListener(event: "listening", listener: () => void): this;
+    }
+    export function createServer(connectionListener?: (socket: Socket) => void): Server;
+    export function createServer(options?: { allowHalfOpen?: boolean; }, connectionListener?: (socket: Socket) => void): Server;
+    export function connect(options: { port: number, host?: string, localAddress?: string, localPort?: string, family?: number, allowHalfOpen?: boolean; }, connectionListener?: Function): Socket;
+    export function connect(port: number, host?: string, connectionListener?: Function): Socket;
+    export function connect(path: string, connectionListener?: Function): Socket;
+    export function createConnection(options: { port: number, host?: string, localAddress?: string, localPort?: string, family?: number, allowHalfOpen?: boolean; }, connectionListener?: Function): Socket;
+    export function createConnection(port: number, host?: string, connectionListener?: Function): Socket;
+    export function createConnection(path: string, connectionListener?: Function): Socket;
+    export function isIP(input: string): number;
+    export function isIPv4(input: string): boolean;
+    export function isIPv6(input: string): boolean;
+}
+
+declare module "dgram" {
+    import * as events from "events";
+
+    interface RemoteInfo {
+        address: string;
+        family: string;
+        port: number;
+    }
+
+    interface AddressInfo {
+        address: string;
+        family: string;
+        port: number;
+    }
+
+    interface BindOptions {
+        port: number;
+        address?: string;
+        exclusive?: boolean;
+    }
+
+    interface SocketOptions {
+        type: "udp4" | "udp6";
+        reuseAddr?: boolean;
+    }
+
+    export function createSocket(type: string, callback?: (msg: Buffer, rinfo: RemoteInfo) => void): Socket;
+    export function createSocket(options: SocketOptions, callback?: (msg: Buffer, rinfo: RemoteInfo) => void): Socket;
+
+    export interface Socket extends events.EventEmitter {
+        send(msg: Buffer | String | any[], port: number, address: string, callback?: (error: Error, bytes: number) => void): void;
+        send(msg: Buffer | String | any[], offset: number, length: number, port: number, address: string, callback?: (error: Error, bytes: number) => void): void;
+        bind(port?: number, address?: string, callback?: () => void): void;
+        bind(options: BindOptions, callback?: Function): void;
+        close(callback?: any): void;
+        address(): AddressInfo;
+        setBroadcast(flag: boolean): void;
+        setTTL(ttl: number): void;
+        setMulticastTTL(ttl: number): void;
+        setMulticastLoopback(flag: boolean): void;
+        addMembership(multicastAddress: string, multicastInterface?: string): void;
+        dropMembership(multicastAddress: string, multicastInterface?: string): void;
+        ref(): void;
+        unref(): void;
+
+        /**
+         * events.EventEmitter
+         * 1. close
+         * 2. error
+         * 3. listening
+         * 4. message
+         **/
+        addListener(event: string, listener: Function): this;
+        addListener(event: "close", listener: () => void): this;
+        addListener(event: "error", listener: (err: Error) => void): this;
+        addListener(event: "listening", listener: () => void): this;
+        addListener(event: "message", listener: (msg: string, rinfo: AddressInfo) => void): this;
+
+        emit(event: string, ...args: any[]): boolean;
+        emit(event: "close"): boolean;
+        emit(event: "error", err: Error): boolean;
+        emit(event: "listening"): boolean;
+        emit(event: "message", msg: string, rinfo: AddressInfo): boolean;
+
+        on(event: string, listener: Function): this;
+        on(event: "close", listener: () => void): this;
+        on(event: "error", listener: (err: Error) => void): this;
+        on(event: "listening", listener: () => void): this;
+        on(event: "message", listener: (msg: string, rinfo: AddressInfo) => void): this;
+
+        once(event: string, listener: Function): this;
+        once(event: "close", listener: () => void): this;
+        once(event: "error", listener: (err: Error) => void): this;
+        once(event: "listening", listener: () => void): this;
+        once(event: "message", listener: (msg: string, rinfo: AddressInfo) => void): this;
+
+        prependListener(event: string, listener: Function): this;
+        prependListener(event: "close", listener: () => void): this;
+        prependListener(event: "error", listener: (err: Error) => void): this;
+        prependListener(event: "listening", listener: () => void): this;
+        prependListener(event: "message", listener: (msg: string, rinfo: AddressInfo) => void): this;
+
+        prependOnceListener(event: string, listener: Function): this;
+        prependOnceListener(event: "close", listener: () => void): this;
+        prependOnceListener(event: "error", listener: (err: Error) => void): this;
+        prependOnceListener(event: "listening", listener: () => void): this;
+        prependOnceListener(event: "message", listener: (msg: string, rinfo: AddressInfo) => void): this;
+    }
+}
+
+declare module "fs" {
+    import * as stream from "stream";
+    import * as events from "events";
+
+    interface Stats {
+        isFile(): boolean;
+        isDirectory(): boolean;
+        isBlockDevice(): boolean;
+        isCharacterDevice(): boolean;
+        isSymbolicLink(): boolean;
+        isFIFO(): boolean;
+        isSocket(): boolean;
+        dev: number;
+        ino: number;
+        mode: number;
+        nlink: number;
+        uid: number;
+        gid: number;
+        rdev: number;
+        size: number;
+        blksize: number;
+        blocks: number;
+        atime: Date;
+        mtime: Date;
+        ctime: Date;
+        birthtime: Date;
+    }
+
+    interface FSWatcher extends events.EventEmitter {
+        close(): void;
+
+        /**
+         * events.EventEmitter
+         *   1. change
+         *   2. error
+         */
+        addListener(event: string, listener: Function): this;
+        addListener(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this;
+        addListener(event: "error", listener: (code: number, signal: string) => void): this;
+
+        on(event: string, listener: Function): this;
+        on(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this;
+        on(event: "error", listener: (code: number, signal: string) => void): this;
+
+        once(event: string, listener: Function): this;
+        once(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this;
+        once(event: "error", listener: (code: number, signal: string) => void): this;
+
+        prependListener(event: string, listener: Function): this;
+        prependListener(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this;
+        prependListener(event: "error", listener: (code: number, signal: string) => void): this;
+
+        prependOnceListener(event: string, listener: Function): this;
+        prependOnceListener(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this;
+        prependOnceListener(event: "error", listener: (code: number, signal: string) => void): this;
+    }
+
+    export interface ReadStream extends stream.Readable {
+        close(): void;
+        destroy(): void;
+        bytesRead: number;
+        path: string | Buffer;
+
+        /**
+         * events.EventEmitter
+         *   1. open
+         *   2. close
+         */
+        addListener(event: string, listener: Function): this;
+        addListener(event: "open", listener: (fd: number) => void): this;
+        addListener(event: "close", listener: () => void): this;
+
+        on(event: string, listener: Function): this;
+        on(event: "open", listener: (fd: number) => void): this;
+        on(event: "close", listener: () => void): this;
+
+        once(event: string, listener: Function): this;
+        once(event: "open", listener: (fd: number) => void): this;
+        once(event: "close", listener: () => void): this;
+
+        prependListener(event: string, listener: Function): this;
+        prependListener(event: "open", listener: (fd: number) => void): this;
+        prependListener(event: "close", listener: () => void): this;
+
+        prependOnceListener(event: string, listener: Function): this;
+        prependOnceListener(event: "open", listener: (fd: number) => void): this;
+        prependOnceListener(event: "close", listener: () => void): this;
+    }
+
+    export interface WriteStream extends stream.Writable {
+        close(): void;
+        bytesWritten: number;
+        path: string | Buffer;
+
+        /**
+         * events.EventEmitter
+         *   1. open
+         *   2. close
+         */
+        addListener(event: string, listener: Function): this;
+        addListener(event: "open", listener: (fd: number) => void): this;
+        addListener(event: "close", listener: () => void): this;
+
+        on(event: string, listener: Function): this;
+        on(event: "open", listener: (fd: number) => void): this;
+        on(event: "close", listener: () => void): this;
+
+        once(event: string, listener: Function): this;
+        once(event: "open", listener: (fd: number) => void): this;
+        once(event: "close", listener: () => void): this;
+
+        prependListener(event: string, listener: Function): this;
+        prependListener(event: "open", listener: (fd: number) => void): this;
+        prependListener(event: "close", listener: () => void): this;
+
+        prependOnceListener(event: string, listener: Function): this;
+        prependOnceListener(event: "open", listener: (fd: number) => void): this;
+        prependOnceListener(event: "close", listener: () => void): this;
+    }
+
+    /**
+     * Asynchronous rename.
+     * @param oldPath
+     * @param newPath
+     * @param callback No arguments other than a possible exception are given to the completion callback.
+     */
+    export function rename(oldPath: string, newPath: string, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    /**
+     * Synchronous rename
+     * @param oldPath
+     * @param newPath
+     */
+    export function renameSync(oldPath: string, newPath: string): void;
+    export function truncate(path: string | Buffer, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function truncate(path: string | Buffer, len: number, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function truncateSync(path: string | Buffer, len?: number): void;
+    export function ftruncate(fd: number, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function ftruncate(fd: number, len: number, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function ftruncateSync(fd: number, len?: number): void;
+    export function chown(path: string | Buffer, uid: number, gid: number, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function chownSync(path: string | Buffer, uid: number, gid: number): void;
+    export function fchown(fd: number, uid: number, gid: number, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function fchownSync(fd: number, uid: number, gid: number): void;
+    export function lchown(path: string | Buffer, uid: number, gid: number, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function lchownSync(path: string | Buffer, uid: number, gid: number): void;
+    export function chmod(path: string | Buffer, mode: number, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function chmod(path: string | Buffer, mode: string, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function chmodSync(path: string | Buffer, mode: number): void;
+    export function chmodSync(path: string | Buffer, mode: string): void;
+    export function fchmod(fd: number, mode: number, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function fchmod(fd: number, mode: string, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function fchmodSync(fd: number, mode: number): void;
+    export function fchmodSync(fd: number, mode: string): void;
+    export function lchmod(path: string | Buffer, mode: number, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function lchmod(path: string | Buffer, mode: string, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function lchmodSync(path: string | Buffer, mode: number): void;
+    export function lchmodSync(path: string | Buffer, mode: string): void;
+    export function stat(path: string | Buffer, callback?: (err: NodeJS.ErrnoException, stats: Stats) => any): void;
+    export function lstat(path: string | Buffer, callback?: (err: NodeJS.ErrnoException, stats: Stats) => any): void;
+    export function fstat(fd: number, callback?: (err: NodeJS.ErrnoException, stats: Stats) => any): void;
+    export function statSync(path: string | Buffer): Stats;
+    export function lstatSync(path: string | Buffer): Stats;
+    export function fstatSync(fd: number): Stats;
+    export function link(srcpath: string | Buffer, dstpath: string | Buffer, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function linkSync(srcpath: string | Buffer, dstpath: string | Buffer): void;
+    export function symlink(srcpath: string | Buffer, dstpath: string | Buffer, type?: string, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function symlinkSync(srcpath: string | Buffer, dstpath: string | Buffer, type?: string): void;
+    export function readlink(path: string | Buffer, callback?: (err: NodeJS.ErrnoException, linkString: string) => any): void;
+    export function readlinkSync(path: string | Buffer): string;
+    export function realpath(path: string | Buffer, callback?: (err: NodeJS.ErrnoException, resolvedPath: string) => any): void;
+    export function realpath(path: string | Buffer, cache: { [path: string]: string }, callback: (err: NodeJS.ErrnoException, resolvedPath: string) => any): void;
+    export function realpathSync(path: string | Buffer, cache?: { [path: string]: string }): string;
+    /*
+     * Asynchronous unlink - deletes the file specified in {path}
+     *
+     * @param path
+     * @param callback No arguments other than a possible exception are given to the completion callback.
+     */
+    export function unlink(path: string | Buffer, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    /*
+     * Synchronous unlink - deletes the file specified in {path}
+     *
+     * @param path
+     */
+    export function unlinkSync(path: string | Buffer): void;
+    /*
+     * Asynchronous rmdir - removes the directory specified in {path}
+     *
+     * @param path
+     * @param callback No arguments other than a possible exception are given to the completion callback.
+     */
+    export function rmdir(path: string | Buffer, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    /*
+     * Synchronous rmdir - removes the directory specified in {path}
+     *
+     * @param path
+     */
+    export function rmdirSync(path: string | Buffer): void;
+    /*
+     * Asynchronous mkdir - creates the directory specified in {path}.  Parameter {mode} defaults to 0777.
+     *
+     * @param path
+     * @param callback No arguments other than a possible exception are given to the completion callback.
+     */
+    export function mkdir(path: string | Buffer, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    /*
+     * Asynchronous mkdir - creates the directory specified in {path}.  Parameter {mode} defaults to 0777.
+     *
+     * @param path
+     * @param mode
+     * @param callback No arguments other than a possible exception are given to the completion callback.
+     */
+    export function mkdir(path: string | Buffer, mode: number, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    /*
+     * Asynchronous mkdir - creates the directory specified in {path}.  Parameter {mode} defaults to 0777.
+     *
+     * @param path
+     * @param mode
+     * @param callback No arguments other than a possible exception are given to the completion callback.
+     */
+    export function mkdir(path: string | Buffer, mode: string, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    /*
+     * Synchronous mkdir - creates the directory specified in {path}.  Parameter {mode} defaults to 0777.
+     *
+     * @param path
+     * @param mode
+     * @param callback No arguments other than a possible exception are given to the completion callback.
+     */
+    export function mkdirSync(path: string | Buffer, mode?: number): void;
+    /*
+     * Synchronous mkdir - creates the directory specified in {path}.  Parameter {mode} defaults to 0777.
+     *
+     * @param path
+     * @param mode
+     * @param callback No arguments other than a possible exception are given to the completion callback.
+     */
+    export function mkdirSync(path: string | Buffer, mode?: string): void;
+    /*
+     * Asynchronous mkdtemp - Creates a unique temporary directory. Generates six random characters to be appended behind a required prefix to create a unique temporary directory.
+     *
+     * @param prefix
+     * @param callback The created folder path is passed as a string to the callback's second parameter.
+     */
+    export function mkdtemp(prefix: string, callback?: (err: NodeJS.ErrnoException, folder: string) => void): void;
+    /*
+     * Synchronous mkdtemp - Creates a unique temporary directory. Generates six random characters to be appended behind a required prefix to create a unique temporary directory.
+     *
+     * @param prefix
+     * @returns Returns the created folder path.
+     */
+    export function mkdtempSync(prefix: string): string;
+    export function readdir(path: string | Buffer, callback?: (err: NodeJS.ErrnoException, files: string[]) => void): void;
+    export function readdirSync(path: string | Buffer): string[];
+    export function close(fd: number, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function closeSync(fd: number): void;
+    export function open(path: string | Buffer, flags: string | number, callback: (err: NodeJS.ErrnoException, fd: number) => void): void;
+    export function open(path: string | Buffer, flags: string | number, mode: number, callback: (err: NodeJS.ErrnoException, fd: number) => void): void;
+    export function openSync(path: string | Buffer, flags: string | number, mode?: number): number;
+    export function utimes(path: string | Buffer, atime: number, mtime: number, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function utimes(path: string | Buffer, atime: Date, mtime: Date, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function utimesSync(path: string | Buffer, atime: number, mtime: number): void;
+    export function utimesSync(path: string | Buffer, atime: Date, mtime: Date): void;
+    export function futimes(fd: number, atime: number, mtime: number, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function futimes(fd: number, atime: Date, mtime: Date, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function futimesSync(fd: number, atime: number, mtime: number): void;
+    export function futimesSync(fd: number, atime: Date, mtime: Date): void;
+    export function fsync(fd: number, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function fsyncSync(fd: number): void;
+    export function write(fd: number, buffer: Buffer, offset: number, length: number, position: number, callback?: (err: NodeJS.ErrnoException, written: number, buffer: Buffer) => void): void;
+    export function write(fd: number, buffer: Buffer, offset: number, length: number, callback?: (err: NodeJS.ErrnoException, written: number, buffer: Buffer) => void): void;
+    export function write(fd: number, data: any, callback?: (err: NodeJS.ErrnoException, written: number, str: string) => void): void;
+    export function write(fd: number, data: any, offset: number, callback?: (err: NodeJS.ErrnoException, written: number, str: string) => void): void;
+    export function write(fd: number, data: any, offset: number, encoding: string, callback?: (err: NodeJS.ErrnoException, written: number, str: string) => void): void;
+    export function writeSync(fd: number, buffer: Buffer, offset: number, length: number, position?: number): number;
+    export function writeSync(fd: number, data: any, position?: number, enconding?: string): number;
+    export function read(fd: number, buffer: Buffer, offset: number, length: number, position: number, callback?: (err: NodeJS.ErrnoException, bytesRead: number, buffer: Buffer) => void): void;
+    export function readSync(fd: number, buffer: Buffer, offset: number, length: number, position: number): number;
+    /*
+     * Asynchronous readFile - Asynchronously reads the entire contents of a file.
+     *
+     * @param fileName
+     * @param encoding
+     * @param callback - The callback is passed two arguments (err, data), where data is the contents of the file.
+     */
+    export function readFile(filename: string, encoding: string, callback: (err: NodeJS.ErrnoException, data: string) => void): void;
+    /*
+     * Asynchronous readFile - Asynchronously reads the entire contents of a file.
+     *
+     * @param fileName
+     * @param options An object with optional {encoding} and {flag} properties.  If {encoding} is specified, readFile returns a string; otherwise it returns a Buffer.
+     * @param callback - The callback is passed two arguments (err, data), where data is the contents of the file.
+     */
+    export function readFile(filename: string, options: { encoding: string; flag?: string; }, callback: (err: NodeJS.ErrnoException, data: string) => void): void;
+    /*
+     * Asynchronous readFile - Asynchronously reads the entire contents of a file.
+     *
+     * @param fileName
+     * @param options An object with optional {encoding} and {flag} properties.  If {encoding} is specified, readFile returns a string; otherwise it returns a Buffer.
+     * @param callback - The callback is passed two arguments (err, data), where data is the contents of the file.
+     */
+    export function readFile(filename: string, options: { flag?: string; }, callback: (err: NodeJS.ErrnoException, data: Buffer) => void): void;
+    /*
+     * Asynchronous readFile - Asynchronously reads the entire contents of a file.
+     *
+     * @param fileName
+     * @param callback - The callback is passed two arguments (err, data), where data is the contents of the file.
+     */
+    export function readFile(filename: string, callback: (err: NodeJS.ErrnoException, data: Buffer) => void): void;
+    /*
+     * Synchronous readFile - Synchronously reads the entire contents of a file.
+     *
+     * @param fileName
+     * @param encoding
+     */
+    export function readFileSync(filename: string, encoding: string): string;
+    /*
+     * Synchronous readFile - Synchronously reads the entire contents of a file.
+     *
+     * @param fileName
+     * @param options An object with optional {encoding} and {flag} properties.  If {encoding} is specified, readFileSync returns a string; otherwise it returns a Buffer.
+     */
+    export function readFileSync(filename: string, options: { encoding: string; flag?: string; }): string;
+    /*
+     * Synchronous readFile - Synchronously reads the entire contents of a file.
+     *
+     * @param fileName
+     * @param options An object with optional {encoding} and {flag} properties.  If {encoding} is specified, readFileSync returns a string; otherwise it returns a Buffer.
+     */
+    export function readFileSync(filename: string, options?: { flag?: string; }): Buffer;
+    export function writeFile(filename: string, data: any, callback?: (err: NodeJS.ErrnoException) => void): void;
+    export function writeFile(filename: string, data: any, options: { encoding?: string; mode?: number; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void;
+    export function writeFile(filename: string, data: any, options: { encoding?: string; mode?: string; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void;
+    export function writeFileSync(filename: string, data: any, options?: { encoding?: string; mode?: number; flag?: string; }): void;
+    export function writeFileSync(filename: string, data: any, options?: { encoding?: string; mode?: string; flag?: string; }): void;
+    export function appendFile(filename: string, data: any, options: { encoding?: string; mode?: number; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void;
+    export function appendFile(filename: string, data: any, options: { encoding?: string; mode?: string; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void;
+    export function appendFile(filename: string, data: any, callback?: (err: NodeJS.ErrnoException) => void): void;
+    export function appendFileSync(filename: string, data: any, options?: { encoding?: string; mode?: number; flag?: string; }): void;
+    export function appendFileSync(filename: string, data: any, options?: { encoding?: string; mode?: string; flag?: string; }): void;
+    export function watchFile(filename: string, listener: (curr: Stats, prev: Stats) => void): void;
+    export function watchFile(filename: string, options: { persistent?: boolean; interval?: number; }, listener: (curr: Stats, prev: Stats) => void): void;
+    export function unwatchFile(filename: string, listener?: (curr: Stats, prev: Stats) => void): void;
+    export function watch(filename: string, listener?: (event: string, filename: string) => any): FSWatcher;
+    export function watch(filename: string, encoding: string, listener?: (event: string, filename: string | Buffer) => any): FSWatcher;
+    export function watch(filename: string, options: { persistent?: boolean; recursive?: boolean; encoding?: string }, listener?: (event: string, filename: string | Buffer) => any): FSWatcher;
+    export function exists(path: string | Buffer, callback?: (exists: boolean) => void): void;
+    export function existsSync(path: string | Buffer): boolean;
+
+    export namespace constants {
+        // File Access Constants
+
+        /** Constant for fs.access(). File is visible to the calling process. */
+        export const F_OK: number;
+
+        /** Constant for fs.access(). File can be read by the calling process. */
+        export const R_OK: number;
+
+        /** Constant for fs.access(). File can be written by the calling process. */
+        export const W_OK: number;
+
+        /** Constant for fs.access(). File can be executed by the calling process. */
+        export const X_OK: number;
+
+        // File Open Constants
+
+        /** Constant for fs.open(). Flag indicating to open a file for read-only access. */
+        export const O_RDONLY: number;
+
+        /** Constant for fs.open(). Flag indicating to open a file for write-only access. */
+        export const O_WRONLY: number;
+
+        /** Constant for fs.open(). Flag indicating to open a file for read-write access. */
+        export const O_RDWR: number;
+
+        /** Constant for fs.open(). Flag indicating to create the file if it does not already exist. */
+        export const O_CREAT: number;
+
+        /** Constant for fs.open(). Flag indicating that opening a file should fail if the O_CREAT flag is set and the file already exists. */
+        export const O_EXCL: number;
+
+        /** Constant for fs.open(). Flag indicating that if path identifies a terminal device, opening the path shall not cause that terminal to become the controlling terminal for the process (if the process does not already have one). */
+        export const O_NOCTTY: number;
+
+        /** Constant for fs.open(). Flag indicating that if the file exists and is a regular file, and the file is opened successfully for write access, its length shall be truncated to zero. */
+        export const O_TRUNC: number;
+
+        /** Constant for fs.open(). Flag indicating that data will be appended to the end of the file. */
+        export const O_APPEND: number;
+
+        /** Constant for fs.open(). Flag indicating that the open should fail if the path is not a directory. */
+        export const O_DIRECTORY: number;
+
+        /** Constant for fs.open(). Flag indicating reading accesses to the file system will no longer result in an update to the atime information associated with the file. This flag is available on Linux operating systems only. */
+        export const O_NOATIME: number;
+
+        /** Constant for fs.open(). Flag indicating that the open should fail if the path is a symbolic link. */
+        export const O_NOFOLLOW: number;
+
+        /** Constant for fs.open(). Flag indicating that the file is opened for synchronous I/O. */
+        export const O_SYNC: number;
+
+        /** Constant for fs.open(). Flag indicating to open the symbolic link itself rather than the resource it is pointing to. */
+        export const O_SYMLINK: number;
+
+        /** Constant for fs.open(). When set, an attempt will be made to minimize caching effects of file I/O. */
+        export const O_DIRECT: number;
+
+        /** Constant for fs.open(). Flag indicating to open the file in nonblocking mode when possible. */
+        export const O_NONBLOCK: number;
+
+        // File Type Constants
+
+        /** Constant for fs.Stats mode property for determining a file's type. Bit mask used to extract the file type code. */
+        export const S_IFMT: number;
+
+        /** Constant for fs.Stats mode property for determining a file's type. File type constant for a regular file. */
+        export const S_IFREG: number;
+
+        /** Constant for fs.Stats mode property for determining a file's type. File type constant for a directory. */
+        export const S_IFDIR: number;
+
+        /** Constant for fs.Stats mode property for determining a file's type. File type constant for a character-oriented device file. */
+        export const S_IFCHR: number;
+
+        /** Constant for fs.Stats mode property for determining a file's type. File type constant for a block-oriented device file. */
+        export const S_IFBLK: number;
+
+        /** Constant for fs.Stats mode property for determining a file's type. File type constant for a FIFO/pipe. */
+        export const S_IFIFO: number;
+
+        /** Constant for fs.Stats mode property for determining a file's type. File type constant for a symbolic link. */
+        export const S_IFLNK: number;
+
+        /** Constant for fs.Stats mode property for determining a file's type. File type constant for a socket. */
+        export const S_IFSOCK: number;
+
+        // File Mode Constants
+
+        /** Constant for fs.Stats mode property for determining access permissions for a file. File mode indicating readable, writable and executable by owner. */
+        export const S_IRWXU: number;
+
+        /** Constant for fs.Stats mode property for determining access permissions for a file. File mode indicating readable by owner. */
+        export const S_IRUSR: number;
+
+        /** Constant for fs.Stats mode property for determining access permissions for a file. File mode indicating writable by owner. */
+        export const S_IWUSR: number;
+
+        /** Constant for fs.Stats mode property for determining access permissions for a file. File mode indicating executable by owner. */
+        export const S_IXUSR: number;
+
+        /** Constant for fs.Stats mode property for determining access permissions for a file. File mode indicating readable, writable and executable by group. */
+        export const S_IRWXG: number;
+
+        /** Constant for fs.Stats mode property for determining access permissions for a file. File mode indicating readable by group. */
+        export const S_IRGRP: number;
+
+        /** Constant for fs.Stats mode property for determining access permissions for a file. File mode indicating writable by group. */
+        export const S_IWGRP: number;
+
+        /** Constant for fs.Stats mode property for determining access permissions for a file. File mode indicating executable by group. */
+        export const S_IXGRP: number;
+
+        /** Constant for fs.Stats mode property for determining access permissions for a file. File mode indicating readable, writable and executable by others. */
+        export const S_IRWXO: number;
+
+        /** Constant for fs.Stats mode property for determining access permissions for a file. File mode indicating readable by others. */
+        export const S_IROTH: number;
+
+        /** Constant for fs.Stats mode property for determining access permissions for a file. File mode indicating writable by others. */
+        export const S_IWOTH: number;
+
+        /** Constant for fs.Stats mode property for determining access permissions for a file. File mode indicating executable by others. */
+        export const S_IXOTH: number;
+    }
+
+    /** Tests a user's permissions for the file specified by path. */
+    export function access(path: string | Buffer, callback: (err: NodeJS.ErrnoException) => void): void;
+    export function access(path: string | Buffer, mode: number, callback: (err: NodeJS.ErrnoException) => void): void;
+    /** Synchronous version of fs.access. This throws if any accessibility checks fail, and does nothing otherwise. */
+    export function accessSync(path: string | Buffer, mode?: number): void;
+    export function createReadStream(path: string | Buffer, options?: {
+        flags?: string;
+        encoding?: string;
+        fd?: number;
+        mode?: number;
+        autoClose?: boolean;
+        start?: number;
+        end?: number;
+    }): ReadStream;
+    export function createWriteStream(path: string | Buffer, options?: {
+        flags?: string;
+        encoding?: string;
+        fd?: number;
+        mode?: number;
+        autoClose?: boolean;
+        start?: number;
+    }): WriteStream;
+    export function fdatasync(fd: number, callback: Function): void;
+    export function fdatasyncSync(fd: number): void;
+}
+
+declare module "path" {
+
+    /**
+     * A parsed path object generated by path.parse() or consumed by path.format().
+     */
+    export interface ParsedPath {
+        /**
+         * The root of the path such as '/' or 'c:\'
+         */
+        root: string;
+        /**
+         * The full directory path such as '/home/user/dir' or 'c:\path\dir'
+         */
+        dir: string;
+        /**
+         * The file name including extension (if any) such as 'index.html'
+         */
+        base: string;
+        /**
+         * The file extension (if any) such as '.html'
+         */
+        ext: string;
+        /**
+         * The file name without extension (if any) such as 'index'
+         */
+        name: string;
+    }
+
+    /**
+     * Normalize a string path, reducing '..' and '.' parts.
+     * When multiple slashes are found, they're replaced by a single one; when the path contains a trailing slash, it is preserved. On Windows backslashes are used.
+     *
+     * @param p string path to normalize.
+     */
+    export function normalize(p: string): string;
+    /**
+     * Join all arguments together and normalize the resulting path.
+     * Arguments must be strings. In v0.8, non-string arguments were silently ignored. In v0.10 and up, an exception is thrown.
+     *
+     * @param paths string paths to join.
+     */
+    export function join(...paths: any[]): string;
+    /**
+     * Join all arguments together and normalize the resulting path.
+     * Arguments must be strings. In v0.8, non-string arguments were silently ignored. In v0.10 and up, an exception is thrown.
+     *
+     * @param paths string paths to join.
+     */
+    export function join(...paths: string[]): string;
+    /**
+     * The right-most parameter is considered {to}.  Other parameters are considered an array of {from}.
+     *
+     * Starting from leftmost {from} paramter, resolves {to} to an absolute path.
+     *
+     * If {to} isn't already absolute, {from} arguments are prepended in right to left order, until an absolute path is found. If after using all {from} paths still no absolute path is found, the current working directory is used as well. The resulting path is normalized, and trailing slashes are removed unless the path gets resolved to the root directory.
+     *
+     * @param pathSegments string paths to join.  Non-string arguments are ignored.
+     */
+    export function resolve(...pathSegments: any[]): string;
+    /**
+     * Determines whether {path} is an absolute path. An absolute path will always resolve to the same location, regardless of the working directory.
+     *
+     * @param path path to test.
+     */
+    export function isAbsolute(path: string): boolean;
+    /**
+     * Solve the relative path from {from} to {to}.
+     * At times we have two absolute paths, and we need to derive the relative path from one to the other. This is actually the reverse transform of path.resolve.
+     *
+     * @param from
+     * @param to
+     */
+    export function relative(from: string, to: string): string;
+    /**
+     * Return the directory name of a path. Similar to the Unix dirname command.
+     *
+     * @param p the path to evaluate.
+     */
+    export function dirname(p: string): string;
+    /**
+     * Return the last portion of a path. Similar to the Unix basename command.
+     * Often used to extract the file name from a fully qualified path.
+     *
+     * @param p the path to evaluate.
+     * @param ext optionally, an extension to remove from the result.
+     */
+    export function basename(p: string, ext?: string): string;
+    /**
+     * Return the extension of the path, from the last '.' to end of string in the last portion of the path.
+     * If there is no '.' in the last portion of the path or the first character of it is '.', then it returns an empty string
+     *
+     * @param p the path to evaluate.
+     */
+    export function extname(p: string): string;
+    /**
+     * The platform-specific file separator. '\\' or '/'.
+     */
+    export var sep: string;
+    /**
+     * The platform-specific file delimiter. ';' or ':'.
+     */
+    export var delimiter: string;
+    /**
+     * Returns an object from a path string - the opposite of format().
+     *
+     * @param pathString path to evaluate.
+     */
+    export function parse(pathString: string): ParsedPath;
+    /**
+     * Returns a path string from an object - the opposite of parse().
+     *
+     * @param pathString path to evaluate.
+     */
+    export function format(pathObject: ParsedPath): string;
+
+    export module posix {
+        export function normalize(p: string): string;
+        export function join(...paths: any[]): string;
+        export function resolve(...pathSegments: any[]): string;
+        export function isAbsolute(p: string): boolean;
+        export function relative(from: string, to: string): string;
+        export function dirname(p: string): string;
+        export function basename(p: string, ext?: string): string;
+        export function extname(p: string): string;
+        export var sep: string;
+        export var delimiter: string;
+        export function parse(p: string): ParsedPath;
+        export function format(pP: ParsedPath): string;
+    }
+
+    export module win32 {
+        export function normalize(p: string): string;
+        export function join(...paths: any[]): string;
+        export function resolve(...pathSegments: any[]): string;
+        export function isAbsolute(p: string): boolean;
+        export function relative(from: string, to: string): string;
+        export function dirname(p: string): string;
+        export function basename(p: string, ext?: string): string;
+        export function extname(p: string): string;
+        export var sep: string;
+        export var delimiter: string;
+        export function parse(p: string): ParsedPath;
+        export function format(pP: ParsedPath): string;
+    }
+}
+
+declare module "string_decoder" {
+    export interface NodeStringDecoder {
+        write(buffer: Buffer): string;
+        end(buffer?: Buffer): string;
+    }
+    export var StringDecoder: {
+        new (encoding?: string): NodeStringDecoder;
+    };
+}
+
+declare module "tls" {
+    import * as crypto from "crypto";
+    import * as net from "net";
+    import * as stream from "stream";
+
+    var CLIENT_RENEG_LIMIT: number;
+    var CLIENT_RENEG_WINDOW: number;
+
+    export interface Certificate {
+        /**
+         * Country code.
+         */
+        C: string;
+        /**
+         * Street.
+         */
+        ST: string;
+        /**
+         * Locality.
+         */
+        L: string;
+        /**
+         * Organization.
+         */
+        O: string;
+        /**
+         * Organizational unit.
+         */
+        OU: string;
+        /**
+         * Common name.
+         */
+        CN: string;
+    }
+
+    export interface CipherNameAndProtocol {
+        /**
+         * The cipher name.
+         */
+        name: string;
+        /**
+         * SSL/TLS protocol version.
+         */
+        version: string;
+    }
+
+    export class TLSSocket extends stream.Duplex {
+        /**
+         * Construct a new tls.TLSSocket object from an existing TCP socket.
+         */
+        constructor(socket:net.Socket, options?: {
+          /**
+           * An optional TLS context object from tls.createSecureContext()
+           */
+          secureContext?: SecureContext,
+          /**
+           * If true the TLS socket will be instantiated in server-mode.
+           * Defaults to false.
+           */
+          isServer?: boolean,
+          /**
+           * An optional net.Server instance.
+           */
+          server?: net.Server,
+          /**
+           * If true the server will request a certificate from clients that
+           * connect and attempt to verify that certificate. Defaults to
+           * false.
+           */
+          requestCert?: boolean,
+          /**
+           * If true the server will reject any connection which is not
+           * authorized with the list of supplied CAs. This option only has an
+           * effect if requestCert is true. Defaults to false.
+           */
+          rejectUnauthorized?: boolean,
+          /**
+           * An array of strings or a Buffer naming possible NPN protocols.
+           * (Protocols should be ordered by their priority.)
+           */
+          NPNProtocols?: string[] | Buffer,
+          /**
+           * An array of strings or a Buffer naming possible ALPN protocols.
+           * (Protocols should be ordered by their priority.) When the server
+           * receives both NPN and ALPN extensions from the client, ALPN takes
+           * precedence over NPN and the server does not send an NPN extension
+           * to the client.
+           */
+          ALPNProtocols?: string[] | Buffer,
+          /**
+           * SNICallback(servername, cb) <Function> A function that will be
+           * called if the client supports SNI TLS extension. Two arguments
+           * will be passed when called: servername and cb. SNICallback should
+           * invoke cb(null, ctx), where ctx is a SecureContext instance.
+           * (tls.createSecureContext(...) can be used to get a proper
+           * SecureContext.) If SNICallback wasn't provided the default callback
+           * with high-level API will be used (see below).
+           */
+          SNICallback?: Function,
+          /**
+           * An optional Buffer instance containing a TLS session.
+           */
+          session?: Buffer,
+          /**
+           * If true, specifies that the OCSP status request extension will be
+           * added to the client hello and an 'OCSPResponse' event will be
+           * emitted on the socket before establishing a secure communication
+           */
+          requestOCSP?: boolean
+        });
+        /**
+         * Returns the bound address, the address family name and port of the underlying socket as reported by
+         * the operating system.
+         * @returns {any} - An object with three properties, e.g. { port: 12346, family: 'IPv4', address: '127.0.0.1' }.
+         */
+        address(): { port: number; family: string; address: string };
+        /**
+         * A boolean that is true if the peer certificate was signed by one of the specified CAs, otherwise false.
+         */
+        authorized: boolean;
+        /**
+         * The reason why the peer's certificate has not been verified.
+         * This property becomes available only when tlsSocket.authorized === false.
+         */
+        authorizationError: Error;
+        /**
+         * Static boolean value, always true.
+         * May be used to distinguish TLS sockets from regular ones.
+         */
+        encrypted: boolean;
+        /**
+         * Returns an object representing the cipher name and the SSL/TLS protocol version of the current connection.
+         * @returns {CipherNameAndProtocol} - Returns an object representing the cipher name
+         * and the SSL/TLS protocol version of the current connection.
+         */
+        getCipher(): CipherNameAndProtocol;
+        /**
+         * Returns an object representing the peer's certificate.
+         * The returned object has some properties corresponding to the field of the certificate.
+         * If detailed argument is true the full chain with issuer property will be returned,
+         * if false only the top certificate without issuer property.
+         * If the peer does not provide a certificate, it returns null or an empty object.
+         * @param {boolean} detailed - If true; the full chain with issuer property will be returned.
+         * @returns {any} - An object representing the peer's certificate.
+         */
+        getPeerCertificate(detailed?: boolean): {
+            subject: Certificate;
+            issuerInfo: Certificate;
+            issuer: Certificate;
+            raw: any;
+            valid_from: string;
+            valid_to: string;
+            fingerprint: string;
+            serialNumber: string;
+        };
+        /**
+         * Could be used to speed up handshake establishment when reconnecting to the server.
+         * @returns {any} - ASN.1 encoded TLS session or undefined if none was negotiated.
+         */
+        getSession(): any;
+        /**
+         * NOTE: Works only with client TLS sockets.
+         * Useful only for debugging, for session reuse provide session option to tls.connect().
+         * @returns {any} - TLS session ticket or undefined if none was negotiated.
+         */
+        getTLSTicket(): any;
+        /**
+         * The string representation of the local IP address.
+         */
+        localAddress: string;
+        /**
+         * The numeric representation of the local port.
+         */
+        localPort: string;
+        /**
+         * The string representation of the remote IP address.
+         * For example, '74.125.127.100' or '2001:4860:a005::68'.
+         */
+        remoteAddress: string;
+        /**
+         * The string representation of the remote IP family. 'IPv4' or 'IPv6'.
+         */
+        remoteFamily: string;
+        /**
+         * The numeric representation of the remote port. For example, 443.
+         */
+        remotePort: number;
+        /**
+         * Initiate TLS renegotiation process.
+         *
+         * NOTE: Can be used to request peer's certificate after the secure connection has been established.
+         * ANOTHER NOTE: When running as the server, socket will be destroyed with an error after handshakeTimeout timeout.
+         * @param {TlsOptions} options - The options may contain the following fields: rejectUnauthorized,
+         * requestCert (See tls.createServer() for details).
+         * @param {Function} callback - callback(err) will be executed with null as err, once the renegotiation
+         * is successfully completed.
+         */
+        renegotiate(options: TlsOptions, callback: (err: Error) => any): any;
+        /**
+         * Set maximum TLS fragment size (default and maximum value is: 16384, minimum is: 512).
+         * Smaller fragment size decreases buffering latency on the client: large fragments are buffered by
+         * the TLS layer until the entire fragment is received and its integrity is verified;
+         * large fragments can span multiple roundtrips, and their processing can be delayed due to packet
+         * loss or reordering. However, smaller fragments add extra TLS framing bytes and CPU overhead,
+         * which may decrease overall server throughput.
+         * @param {number} size - TLS fragment size (default and maximum value is: 16384, minimum is: 512).
+         * @returns {boolean} - Returns true on success, false otherwise.
+         */
+        setMaxSendFragment(size: number): boolean;
+
+        /**
+         * events.EventEmitter
+         * 1. OCSPResponse
+         * 2. secureConnect
+         **/
+        addListener(event: string, listener: Function): this;
+        addListener(event: "OCSPResponse", listener: (response: Buffer) => void): this;
+        addListener(event: "secureConnect", listener: () => void): this;
+
+        emit(event: string, ...args: any[]): boolean;
+        emit(event: "OCSPResponse", response: Buffer): boolean;
+        emit(event: "secureConnect"): boolean;
+
+        on(event: string, listener: Function): this;
+        on(event: "OCSPResponse", listener: (response: Buffer) => void): this;
+        on(event: "secureConnect", listener: () => void): this;
+
+        once(event: string, listener: Function): this;
+        once(event: "OCSPResponse", listener: (response: Buffer) => void): this;
+        once(event: "secureConnect", listener: () => void): this;
+
+        prependListener(event: string, listener: Function): this;
+        prependListener(event: "OCSPResponse", listener: (response: Buffer) => void): this;
+        prependListener(event: "secureConnect", listener: () => void): this;
+
+        prependOnceListener(event: string, listener: Function): this;
+        prependOnceListener(event: "OCSPResponse", listener: (response: Buffer) => void): this;
+        prependOnceListener(event: "secureConnect", listener: () => void): this;
+    }
+
+    export interface TlsOptions {
+        host?: string;
+        port?: number;
+        pfx?: string | Buffer[];
+        key?: string | string[] | Buffer | any[];
+        passphrase?: string;
+        cert?: string | string[] | Buffer | Buffer[];
+        ca?: string | string[] | Buffer | Buffer[];
+        crl?: string | string[];
+        ciphers?: string;
+        honorCipherOrder?: boolean;
+        requestCert?: boolean;
+        rejectUnauthorized?: boolean;
+        NPNProtocols?: string[] | Buffer;
+        SNICallback?: (servername: string, cb: (err: Error, ctx: SecureContext) => any) => any;
+        ecdhCurve?: string;
+        dhparam?: string | Buffer;
+        handshakeTimeout?: number;
+        ALPNProtocols?: string[] | Buffer;
+        sessionTimeout?: number;
+        ticketKeys?: any;
+        sessionIdContext?: string;
+        secureProtocol?: string;
+    }
+
+    export interface ConnectionOptions {
+        host?: string;
+        port?: number;
+        socket?: net.Socket;
+        pfx?: string | Buffer
+        key?: string | string[] | Buffer | Buffer[];
+        passphrase?: string;
+        cert?: string | string[] | Buffer | Buffer[];
+        ca?: string | Buffer | (string | Buffer)[];
+        rejectUnauthorized?: boolean;
+        NPNProtocols?: (string | Buffer)[];
+        servername?: string;
+        path?: string;
+        ALPNProtocols?: (string | Buffer)[];
+        checkServerIdentity?: (servername: string, cert: string | Buffer | (string | Buffer)[]) => any;
+        secureProtocol?: string;
+        secureContext?: Object;
+        session?: Buffer;
+        minDHSize?: number;
+    }
+
+    export interface Server extends net.Server {
+        close(): Server;
+        address(): { port: number; family: string; address: string; };
+        addContext(hostName: string, credentials: {
+            key: string;
+            cert: string;
+            ca: string;
+        }): void;
+        maxConnections: number;
+        connections: number;
+
+        /**
+         * events.EventEmitter
+         * 1. tlsClientError
+         * 2. newSession
+         * 3. OCSPRequest
+         * 4. resumeSession
+         * 5. secureConnection
+         **/
+        addListener(event: string, listener: Function): this;
+        addListener(event: "tlsClientError", listener: (err: Error, tlsSocket: TLSSocket) => void): this;
+        addListener(event: "newSession", listener: (sessionId: any, sessionData: any, callback: (err: Error, resp: Buffer) => void) => void): this;
+        addListener(event: "OCSPRequest", listener: (certificate: Buffer, issuer: Buffer, callback: Function) => void): this;
+        addListener(event: "resumeSession", listener: (sessionId: any, callback: (err: Error, sessionData: any) => void) => void): this;
+        addListener(event: "secureConnection", listener: (tlsSocket: TLSSocket) => void): this;
+
+        emit(event: string, ...args: any[]): boolean;
+        emit(event: "tlsClientError", err: Error, tlsSocket: TLSSocket): boolean;
+        emit(event: "newSession", sessionId: any, sessionData: any, callback: (err: Error, resp: Buffer) => void): boolean;
+        emit(event: "OCSPRequest", certificate: Buffer, issuer: Buffer, callback: Function): boolean;
+        emit(event: "resumeSession", sessionId: any, callback: (err: Error, sessionData: any) => void): boolean;
+        emit(event: "secureConnection", tlsSocket: TLSSocket): boolean;
+
+        on(event: string, listener: Function): this;
+        on(event: "tlsClientError", listener: (err: Error, tlsSocket: TLSSocket) => void): this;
+        on(event: "newSession", listener: (sessionId: any, sessionData: any, callback: (err: Error, resp: Buffer) => void) => void): this;
+        on(event: "OCSPRequest", listener: (certificate: Buffer, issuer: Buffer, callback: Function) => void): this;
+        on(event: "resumeSession", listener: (sessionId: any, callback: (err: Error, sessionData: any) => void) => void): this;
+        on(event: "secureConnection", listener: (tlsSocket: TLSSocket) => void): this;
+
+        once(event: string, listener: Function): this;
+        once(event: "tlsClientError", listener: (err: Error, tlsSocket: TLSSocket) => void): this;
+        once(event: "newSession", listener: (sessionId: any, sessionData: any, callback: (err: Error, resp: Buffer) => void) => void): this;
+        once(event: "OCSPRequest", listener: (certificate: Buffer, issuer: Buffer, callback: Function) => void): this;
+        once(event: "resumeSession", listener: (sessionId: any, callback: (err: Error, sessionData: any) => void) => void): this;
+        once(event: "secureConnection", listener: (tlsSocket: TLSSocket) => void): this;
+
+        prependListener(event: string, listener: Function): this;
+        prependListener(event: "tlsClientError", listener: (err: Error, tlsSocket: TLSSocket) => void): this;
+        prependListener(event: "newSession", listener: (sessionId: any, sessionData: any, callback: (err: Error, resp: Buffer) => void) => void): this;
+        prependListener(event: "OCSPRequest", listener: (certificate: Buffer, issuer: Buffer, callback: Function) => void): this;
+        prependListener(event: "resumeSession", listener: (sessionId: any, callback: (err: Error, sessionData: any) => void) => void): this;
+        prependListener(event: "secureConnection", listener: (tlsSocket: TLSSocket) => void): this;
+
+        prependOnceListener(event: string, listener: Function): this;
+        prependOnceListener(event: "tlsClientError", listener: (err: Error, tlsSocket: TLSSocket) => void): this;
+        prependOnceListener(event: "newSession", listener: (sessionId: any, sessionData: any, callback: (err: Error, resp: Buffer) => void) => void): this;
+        prependOnceListener(event: "OCSPRequest", listener: (certificate: Buffer, issuer: Buffer, callback: Function) => void): this;
+        prependOnceListener(event: "resumeSession", listener: (sessionId: any, callback: (err: Error, sessionData: any) => void) => void): this;
+        prependOnceListener(event: "secureConnection", listener: (tlsSocket: TLSSocket) => void): this;
+    }
+
+    export interface ClearTextStream extends stream.Duplex {
+        authorized: boolean;
+        authorizationError: Error;
+        getPeerCertificate(): any;
+        getCipher: {
+            name: string;
+            version: string;
+        };
+        address: {
+            port: number;
+            family: string;
+            address: string;
+        };
+        remoteAddress: string;
+        remotePort: number;
+    }
+
+    export interface SecurePair {
+        encrypted: any;
+        cleartext: any;
+    }
+
+    export interface SecureContextOptions {
+        pfx?: string | Buffer;
+        key?: string | Buffer;
+        passphrase?: string;
+        cert?: string | Buffer;
+        ca?: string | Buffer;
+        crl?: string | string[]
+        ciphers?: string;
+        honorCipherOrder?: boolean;
+    }
+
+    export interface SecureContext {
+        context: any;
+    }
+
+    export function createServer(options: TlsOptions, secureConnectionListener?: (cleartextStream: ClearTextStream) => void): Server;
+    export function connect(options: ConnectionOptions, secureConnectionListener?: () => void): ClearTextStream;
+    export function connect(port: number, host?: string, options?: ConnectionOptions, secureConnectListener?: () => void): ClearTextStream;
+    export function connect(port: number, options?: ConnectionOptions, secureConnectListener?: () => void): ClearTextStream;
+    export function createSecurePair(credentials?: crypto.Credentials, isServer?: boolean, requestCert?: boolean, rejectUnauthorized?: boolean): SecurePair;
+    export function createSecureContext(details: SecureContextOptions): SecureContext;
+}
+
+declare module "crypto" {
+    export interface Certificate {
+        exportChallenge(spkac: string | Buffer): Buffer;
+        exportPublicKey(spkac: string | Buffer): Buffer;
+        verifySpkac(spkac: Buffer): boolean;
+    }
+    export var Certificate: {
+        new (): Certificate;
+        (): Certificate;
+    }
+
+    export var fips: boolean;
+
+    export interface CredentialDetails {
+        pfx: string;
+        key: string;
+        passphrase: string;
+        cert: string;
+        ca: string | string[];
+        crl: string | string[];
+        ciphers: string;
+    }
+    export interface Credentials { context?: any; }
+    export function createCredentials(details: CredentialDetails): Credentials;
+    export function createHash(algorithm: string): Hash;
+    export function createHmac(algorithm: string, key: string | Buffer): Hmac;
+
+    type Utf8AsciiLatin1Encoding = "utf8" | "ascii" | "latin1";
+    type HexBase64Latin1Encoding = "latin1" | "hex" | "base64";
+    type Utf8AsciiBinaryEncoding = "utf8" | "ascii" | "binary";
+    type HexBase64BinaryEncoding = "binary" | "base64" | "hex";
+    type ECDHKeyFormat = "compressed" | "uncompressed" | "hybrid";
+
+    export interface Hash extends NodeJS.ReadWriteStream {
+        update(data: string | Buffer): Hash;
+        update(data: string | Buffer, input_encoding: Utf8AsciiLatin1Encoding): Hash;
+        digest(): Buffer;
+        digest(encoding: HexBase64Latin1Encoding): string;
+    }
+    export interface Hmac extends NodeJS.ReadWriteStream {
+        update(data: string | Buffer): Hmac;
+        update(data: string | Buffer, input_encoding: Utf8AsciiLatin1Encoding): Hmac;
+        digest(): Buffer;
+        digest(encoding: HexBase64Latin1Encoding): string;
+    }
+    export function createCipher(algorithm: string, password: any): Cipher;
+    export function createCipheriv(algorithm: string, key: any, iv: any): Cipher;
+    export interface Cipher extends NodeJS.ReadWriteStream {
+        update(data: Buffer): Buffer;
+        update(data: string, input_encoding: Utf8AsciiBinaryEncoding): Buffer;
+        update(data: Buffer, input_encoding: any, output_encoding: HexBase64BinaryEncoding): string;
+        update(data: string, input_encoding: Utf8AsciiBinaryEncoding, output_encoding: HexBase64BinaryEncoding): string;
+        final(): Buffer;
+        final(output_encoding: string): string;
+        setAutoPadding(auto_padding?: boolean): void;
+        getAuthTag(): Buffer;
+        setAAD(buffer: Buffer): void;
+    }
+    export function createDecipher(algorithm: string, password: any): Decipher;
+    export function createDecipheriv(algorithm: string, key: any, iv: any): Decipher;
+    export interface Decipher extends NodeJS.ReadWriteStream {
+        update(data: Buffer): Buffer;
+        update(data: string, input_encoding: HexBase64BinaryEncoding): Buffer;
+        update(data: Buffer, input_encoding: any, output_encoding: Utf8AsciiBinaryEncoding): string;
+        update(data: string, input_encoding: HexBase64BinaryEncoding, output_encoding: Utf8AsciiBinaryEncoding): string;
+        final(): Buffer;
+        final(output_encoding: string): string;
+        setAutoPadding(auto_padding?: boolean): void;
+        setAuthTag(tag: Buffer): void;
+        setAAD(buffer: Buffer): void;
+    }
+    export function createSign(algorithm: string): Signer;
+    export interface Signer extends NodeJS.WritableStream {
+        update(data: string | Buffer): Signer;
+        update(data: string | Buffer, input_encoding: Utf8AsciiLatin1Encoding): Signer;
+        sign(private_key: string | { key: string; passphrase: string }): Buffer;
+        sign(private_key: string | { key: string; passphrase: string }, output_format: HexBase64Latin1Encoding): string;
+    }
+    export function createVerify(algorith: string): Verify;
+    export interface Verify extends NodeJS.WritableStream {
+        update(data: string | Buffer): Verify;
+        update(data: string | Buffer, input_encoding: Utf8AsciiLatin1Encoding): Verify;
+        verify(object: string, signature: Buffer): boolean;
+        verify(object: string, signature: string, signature_format: HexBase64Latin1Encoding): boolean;
+    }
+    export function createDiffieHellman(prime_length: number, generator?: number): DiffieHellman;
+    export function createDiffieHellman(prime: Buffer): DiffieHellman;
+    export function createDiffieHellman(prime: string, prime_encoding: HexBase64Latin1Encoding): DiffieHellman;
+    export function createDiffieHellman(prime: string, prime_encoding: HexBase64Latin1Encoding, generator: number | Buffer): DiffieHellman;
+    export function createDiffieHellman(prime: string, prime_encoding: HexBase64Latin1Encoding, generator: string, generator_encoding: HexBase64Latin1Encoding): DiffieHellman;
+    export interface DiffieHellman {
+        generateKeys(): Buffer;
+        generateKeys(encoding: HexBase64Latin1Encoding): string;
+        computeSecret(other_public_key: Buffer): Buffer;
+        computeSecret(other_public_key: string, input_encoding: HexBase64Latin1Encoding): Buffer;
+        computeSecret(other_public_key: string, input_encoding: HexBase64Latin1Encoding, output_encoding: HexBase64Latin1Encoding): string;
+        getPrime(): Buffer;
+        getPrime(encoding: HexBase64Latin1Encoding): string;
+        getGenerator(): Buffer;
+        getGenerator(encoding: HexBase64Latin1Encoding): string;
+        getPublicKey(): Buffer;
+        getPublicKey(encoding: HexBase64Latin1Encoding): string;
+        getPrivateKey(): Buffer;
+        getPrivateKey(encoding: HexBase64Latin1Encoding): string;
+        setPublicKey(public_key: Buffer): void;
+        setPublicKey(public_key: string, encoding: string): void;
+        setPrivateKey(private_key: Buffer): void;
+        setPrivateKey(private_key: string, encoding: string): void;
+        verifyError: number;
+    }
+    export function getDiffieHellman(group_name: string): DiffieHellman;
+    export function pbkdf2(password: string | Buffer, salt: string | Buffer, iterations: number, keylen: number, digest: string, callback: (err: Error, derivedKey: Buffer) => any): void;
+    export function pbkdf2Sync(password: string | Buffer, salt: string | Buffer, iterations: number, keylen: number, digest: string): Buffer;
+    export function randomBytes(size: number): Buffer;
+    export function randomBytes(size: number, callback: (err: Error, buf: Buffer) => void): void;
+    export function pseudoRandomBytes(size: number): Buffer;
+    export function pseudoRandomBytes(size: number, callback: (err: Error, buf: Buffer) => void): void;
+    export interface RsaPublicKey {
+        key: string;
+        padding?: number;
+    }
+    export interface RsaPrivateKey {
+        key: string;
+        passphrase?: string,
+        padding?: number;
+    }
+    export function publicEncrypt(public_key: string | RsaPublicKey, buffer: Buffer): Buffer
+    export function privateDecrypt(private_key: string | RsaPrivateKey, buffer: Buffer): Buffer
+    export function privateEncrypt(private_key: string | RsaPrivateKey, buffer: Buffer): Buffer
+    export function publicDecrypt(public_key: string | RsaPublicKey, buffer: Buffer): Buffer
+    export function getCiphers(): string[];
+    export function getCurves(): string[];
+    export function getHashes(): string[];
+    export interface ECDH {
+        generateKeys(): Buffer;
+        generateKeys(encoding: HexBase64Latin1Encoding): string;
+        generateKeys(encoding: HexBase64Latin1Encoding, format: ECDHKeyFormat): string;
+        computeSecret(other_public_key: Buffer): Buffer;
+        computeSecret(other_public_key: string, input_encoding: HexBase64Latin1Encoding): Buffer;
+        computeSecret(other_public_key: string, input_encoding: HexBase64Latin1Encoding, output_encoding: HexBase64Latin1Encoding): string;
+        getPrivateKey(): Buffer;
+        getPrivateKey(encoding: HexBase64Latin1Encoding): string;
+        getPublicKey(): Buffer;
+        getPublicKey(encoding: HexBase64Latin1Encoding): string;
+        getPublicKey(encoding: HexBase64Latin1Encoding, format: ECDHKeyFormat): string;
+        setPrivateKey(private_key: Buffer): void;
+        setPrivateKey(private_key: string, encoding: HexBase64Latin1Encoding): void;
+    }
+    export function createECDH(curve_name: string): ECDH;
+    export function timingSafeEqual(a: Buffer, b: Buffer): boolean;
+    export var DEFAULT_ENCODING: string;
+}
+
+declare module "stream" {
+    import * as events from "events";
+
+    class internal extends events.EventEmitter {
+        pipe<T extends NodeJS.WritableStream>(destination: T, options?: { end?: boolean; }): T;
+    }
+    namespace internal {
+
+        export class Stream extends internal { }
+
+        export interface ReadableOptions {
+            highWaterMark?: number;
+            encoding?: string;
+            objectMode?: boolean;
+            read?: (size?: number) => any;
+        }
+
+        export class Readable extends events.EventEmitter implements NodeJS.ReadableStream {
+            readable: boolean;
+            constructor(opts?: ReadableOptions);
+            protected _read(size: number): void;
+            read(size?: number): any;
+            setEncoding(encoding: string): void;
+            pause(): Readable;
+            resume(): Readable;
+            pipe<T extends NodeJS.WritableStream>(destination: T, options?: { end?: boolean; }): T;
+            unpipe<T extends NodeJS.WritableStream>(destination?: T): void;
+            unshift(chunk: any): void;
+            wrap(oldStream: NodeJS.ReadableStream): NodeJS.ReadableStream;
+            push(chunk: any, encoding?: string): boolean;
+
+            /**
+             * Event emitter
+             * The defined events on documents including:
+             *   1. close
+             *   2. data
+             *   3. end
+             *   4. readable
+             *   5. error
+             **/
+            addListener(event: string, listener: Function): this;
+            addListener(event: string, listener: Function): this;
+            addListener(event: "close", listener: () => void): this;
+            addListener(event: "data", listener: (chunk: Buffer | string) => void): this;
+            addListener(event: "end", listener: () => void): this;
+            addListener(event: "readable", listener: () => void): this;
+            addListener(event: "error", listener: (err: Error) => void): this;
+
+            emit(event: string, ...args: any[]): boolean;
+            emit(event: "close"): boolean;
+            emit(event: "data", chunk: Buffer | string): boolean;
+            emit(event: "end"): boolean;
+            emit(event: "readable"): boolean;
+            emit(event: "error", err: Error): boolean;
+
+            on(event: string, listener: Function): this;
+            on(event: "close", listener: () => void): this;
+            on(event: "data", listener: (chunk: Buffer | string) => void): this;
+            on(event: "end", listener: () => void): this;
+            on(event: "readable", listener: () => void): this;
+            on(event: "error", listener: (err: Error) => void): this;
+
+            once(event: string, listener: Function): this;
+            once(event: "close", listener: () => void): this;
+            once(event: "data", listener: (chunk: Buffer | string) => void): this;
+            once(event: "end", listener: () => void): this;
+            once(event: "readable", listener: () => void): this;
+            once(event: "error", listener: (err: Error) => void): this;
+
+            prependListener(event: string, listener: Function): this;
+            prependListener(event: "close", listener: () => void): this;
+            prependListener(event: "data", listener: (chunk: Buffer | string) => void): this;
+            prependListener(event: "end", listener: () => void): this;
+            prependListener(event: "readable", listener: () => void): this;
+            prependListener(event: "error", listener: (err: Error) => void): this;
+
+            prependOnceListener(event: string, listener: Function): this;
+            prependOnceListener(event: "close", listener: () => void): this;
+            prependOnceListener(event: "data", listener: (chunk: Buffer | string) => void): this;
+            prependOnceListener(event: "end", listener: () => void): this;
+            prependOnceListener(event: "readable", listener: () => void): this;
+            prependOnceListener(event: "error", listener: (err: Error) => void): this;
+
+            removeListener(event: string, listener: Function): this;
+            removeListener(event: "close", listener: () => void): this;
+            removeListener(event: "data", listener: (chunk: Buffer | string) => void): this;
+            removeListener(event: "end", listener: () => void): this;
+            removeListener(event: "readable", listener: () => void): this;
+            removeListener(event: "error", listener: (err: Error) => void): this;
+        }
+
+        export interface WritableOptions {
+            highWaterMark?: number;
+            decodeStrings?: boolean;
+            objectMode?: boolean;
+            write?: (chunk: string | Buffer, encoding: string, callback: Function) => any;
+            writev?: (chunks: { chunk: string | Buffer, encoding: string }[], callback: Function) => any;
+        }
+
+        export class Writable extends events.EventEmitter implements NodeJS.WritableStream {
+            writable: boolean;
+            constructor(opts?: WritableOptions);
+            protected _write(chunk: any, encoding: string, callback: Function): void;
+            write(chunk: any, cb?: Function): boolean;
+            write(chunk: any, encoding?: string, cb?: Function): boolean;
+            end(): void;
+            end(chunk: any, cb?: Function): void;
+            end(chunk: any, encoding?: string, cb?: Function): void;
+
+            /**
+             * Event emitter
+             * The defined events on documents including:
+             *   1. close
+             *   2. drain
+             *   3. error
+             *   4. finish
+             *   5. pipe
+             *   6. unpipe
+             **/
+            addListener(event: string, listener: Function): this;
+            addListener(event: "close", listener: () => void): this;
+            addListener(event: "drain", listener: () => void): this;
+            addListener(event: "error", listener: (err: Error) => void): this;
+            addListener(event: "finish", listener: () => void): this;
+            addListener(event: "pipe", listener: (src: Readable) => void): this;
+            addListener(event: "unpipe", listener: (src: Readable) => void): this;
+
+            emit(event: string, ...args: any[]): boolean;
+            emit(event: "close"): boolean;
+            emit(event: "drain", chunk: Buffer | string): boolean;
+            emit(event: "error", err: Error): boolean;
+            emit(event: "finish"): boolean;
+            emit(event: "pipe", src: Readable): boolean;
+            emit(event: "unpipe", src: Readable): boolean;
+
+            on(event: string, listener: Function): this;
+            on(event: "close", listener: () => void): this;
+            on(event: "drain", listener: () => void): this;
+            on(event: "error", listener: (err: Error) => void): this;
+            on(event: "finish", listener: () => void): this;
+            on(event: "pipe", listener: (src: Readable) => void): this;
+            on(event: "unpipe", listener: (src: Readable) => void): this;
+
+            once(event: string, listener: Function): this;
+            once(event: "close", listener: () => void): this;
+            once(event: "drain", listener: () => void): this;
+            once(event: "error", listener: (err: Error) => void): this;
+            once(event: "finish", listener: () => void): this;
+            once(event: "pipe", listener: (src: Readable) => void): this;
+            once(event: "unpipe", listener: (src: Readable) => void): this;
+
+            prependListener(event: string, listener: Function): this;
+            prependListener(event: "close", listener: () => void): this;
+            prependListener(event: "drain", listener: () => void): this;
+            prependListener(event: "error", listener: (err: Error) => void): this;
+            prependListener(event: "finish", listener: () => void): this;
+            prependListener(event: "pipe", listener: (src: Readable) => void): this;
+            prependListener(event: "unpipe", listener: (src: Readable) => void): this;
+
+            prependOnceListener(event: string, listener: Function): this;
+            prependOnceListener(event: "close", listener: () => void): this;
+            prependOnceListener(event: "drain", listener: () => void): this;
+            prependOnceListener(event: "error", listener: (err: Error) => void): this;
+            prependOnceListener(event: "finish", listener: () => void): this;
+            prependOnceListener(event: "pipe", listener: (src: Readable) => void): this;
+            prependOnceListener(event: "unpipe", listener: (src: Readable) => void): this;
+
+            removeListener(event: string, listener: Function): this;
+            removeListener(event: "close", listener: () => void): this;
+            removeListener(event: "drain", listener: () => void): this;
+            removeListener(event: "error", listener: (err: Error) => void): this;
+            removeListener(event: "finish", listener: () => void): this;
+            removeListener(event: "pipe", listener: (src: Readable) => void): this;
+            removeListener(event: "unpipe", listener: (src: Readable) => void): this;
+        }
+
+        export interface DuplexOptions extends ReadableOptions, WritableOptions {
+            allowHalfOpen?: boolean;
+            readableObjectMode?: boolean;
+            writableObjectMode?: boolean;
+        }
+
+        // Note: Duplex extends both Readable and Writable.
+        export class Duplex extends Readable implements NodeJS.ReadWriteStream {
+            // Readable
+            pause(): Duplex;
+            resume(): Duplex;
+            // Writeable
+            writable: boolean;
+            constructor(opts?: DuplexOptions);
+            protected _write(chunk: any, encoding: string, callback: Function): void;
+            write(chunk: any, cb?: Function): boolean;
+            write(chunk: any, encoding?: string, cb?: Function): boolean;
+            end(): void;
+            end(chunk: any, cb?: Function): void;
+            end(chunk: any, encoding?: string, cb?: Function): void;
+        }
+
+        export interface TransformOptions extends DuplexOptions {
+            transform?: (chunk: string | Buffer, encoding: string, callback: Function) => any;
+            flush?: (callback: Function) => any;
+        }
+
+        // Note: Transform lacks the _read and _write methods of Readable/Writable.
+        export class Transform extends events.EventEmitter implements NodeJS.ReadWriteStream {
+            readable: boolean;
+            writable: boolean;
+            constructor(opts?: TransformOptions);
+            protected _transform(chunk: any, encoding: string, callback: Function): void;
+            protected _flush(callback: Function): void;
+            read(size?: number): any;
+            setEncoding(encoding: string): void;
+            pause(): Transform;
+            resume(): Transform;
+            pipe<T extends NodeJS.WritableStream>(destination: T, options?: { end?: boolean; }): T;
+            unpipe<T extends NodeJS.WritableStream>(destination?: T): void;
+            unshift(chunk: any): void;
+            wrap(oldStream: NodeJS.ReadableStream): NodeJS.ReadableStream;
+            push(chunk: any, encoding?: string): boolean;
+            write(chunk: any, cb?: Function): boolean;
+            write(chunk: any, encoding?: string, cb?: Function): boolean;
+            end(): void;
+            end(chunk: any, cb?: Function): void;
+            end(chunk: any, encoding?: string, cb?: Function): void;
+        }
+
+        export class PassThrough extends Transform { }
+    }
+
+    export = internal;
+}
+
+declare module "util" {
+    export interface InspectOptions {
+        showHidden?: boolean;
+        depth?: number;
+        colors?: boolean;
+        customInspect?: boolean;
+    }
+
+    export function format(format: any, ...param: any[]): string;
+    export function debug(string: string): void;
+    export function error(...param: any[]): void;
+    export function puts(...param: any[]): void;
+    export function print(...param: any[]): void;
+    export function log(string: string): void;
+    export function inspect(object: any, showHidden?: boolean, depth?: number, color?: boolean): string;
+    export function inspect(object: any, options: InspectOptions): string;
+    export function isArray(object: any): boolean;
+    export function isRegExp(object: any): boolean;
+    export function isDate(object: any): boolean;
+    export function isError(object: any): boolean;
+    export function inherits(constructor: any, superConstructor: any): void;
+    export function debuglog(key: string): (msg: string, ...param: any[]) => void;
+    export function isBoolean(object: any): boolean;
+    export function isBuffer(object: any): boolean;
+    export function isFunction(object: any): boolean;
+    export function isNull(object: any): boolean;
+    export function isNullOrUndefined(object: any): boolean;
+    export function isNumber(object: any): boolean;
+    export function isObject(object: any): boolean;
+    export function isPrimitive(object: any): boolean;
+    export function isString(object: any): boolean;
+    export function isSymbol(object: any): boolean;
+    export function isUndefined(object: any): boolean;
+    export function deprecate(fn: Function, message: string): Function;
+}
+
+declare module "assert" {
+    function internal(value: any, message?: string): void;
+    namespace internal {
+        export class AssertionError implements Error {
+            name: string;
+            message: string;
+            actual: any;
+            expected: any;
+            operator: string;
+            generatedMessage: boolean;
+
+            constructor(options?: {
+                message?: string; actual?: any; expected?: any;
+                operator?: string; stackStartFunction?: Function
+            });
+        }
+
+        export function fail(actual: any, expected: any, message: string, operator: string): void;
+        export function ok(value: any, message?: string): void;
+        export function equal(actual: any, expected: any, message?: string): void;
+        export function notEqual(actual: any, expected: any, message?: string): void;
+        export function deepEqual(actual: any, expected: any, message?: string): void;
+        export function notDeepEqual(acutal: any, expected: any, message?: string): void;
+        export function strictEqual(actual: any, expected: any, message?: string): void;
+        export function notStrictEqual(actual: any, expected: any, message?: string): void;
+        export function deepStrictEqual(actual: any, expected: any, message?: string): void;
+        export function notDeepStrictEqual(actual: any, expected: any, message?: string): void;
+        export var throws: {
+            (block: Function, message?: string): void;
+            (block: Function, error: Function, message?: string): void;
+            (block: Function, error: RegExp, message?: string): void;
+            (block: Function, error: (err: any) => boolean, message?: string): void;
+        };
+
+        export var doesNotThrow: {
+            (block: Function, message?: string): void;
+            (block: Function, error: Function, message?: string): void;
+            (block: Function, error: RegExp, message?: string): void;
+            (block: Function, error: (err: any) => boolean, message?: string): void;
+        };
+
+        export function ifError(value: any): void;
+    }
+
+    export = internal;
+}
+
+declare module "tty" {
+    import * as net from "net";
+
+    export function isatty(fd: number): boolean;
+    export interface ReadStream extends net.Socket {
+        isRaw: boolean;
+        setRawMode(mode: boolean): void;
+        isTTY: boolean;
+    }
+    export interface WriteStream extends net.Socket {
+        columns: number;
+        rows: number;
+        isTTY: boolean;
+    }
+}
+
+declare module "domain" {
+    import * as events from "events";
+
+    export class Domain extends events.EventEmitter implements NodeJS.Domain {
+        run(fn: Function): void;
+        add(emitter: events.EventEmitter): void;
+        remove(emitter: events.EventEmitter): void;
+        bind(cb: (err: Error, data: any) => any): any;
+        intercept(cb: (data: any) => any): any;
+        dispose(): void;
+        members: any[];
+        enter(): void;
+        exit(): void;
+    }
+
+    export function create(): Domain;
+}
+
+declare module "constants" {
+    export var E2BIG: number;
+    export var EACCES: number;
+    export var EADDRINUSE: number;
+    export var EADDRNOTAVAIL: number;
+    export var EAFNOSUPPORT: number;
+    export var EAGAIN: number;
+    export var EALREADY: number;
+    export var EBADF: number;
+    export var EBADMSG: number;
+    export var EBUSY: number;
+    export var ECANCELED: number;
+    export var ECHILD: number;
+    export var ECONNABORTED: number;
+    export var ECONNREFUSED: number;
+    export var ECONNRESET: number;
+    export var EDEADLK: number;
+    export var EDESTADDRREQ: number;
+    export var EDOM: number;
+    export var EEXIST: number;
+    export var EFAULT: number;
+    export var EFBIG: number;
+    export var EHOSTUNREACH: number;
+    export var EIDRM: number;
+    export var EILSEQ: number;
+    export var EINPROGRESS: number;
+    export var EINTR: number;
+    export var EINVAL: number;
+    export var EIO: number;
+    export var EISCONN: number;
+    export var EISDIR: number;
+    export var ELOOP: number;
+    export var EMFILE: number;
+    export var EMLINK: number;
+    export var EMSGSIZE: number;
+    export var ENAMETOOLONG: number;
+    export var ENETDOWN: number;
+    export var ENETRESET: number;
+    export var ENETUNREACH: number;
+    export var ENFILE: number;
+    export var ENOBUFS: number;
+    export var ENODATA: number;
+    export var ENODEV: number;
+    export var ENOENT: number;
+    export var ENOEXEC: number;
+    export var ENOLCK: number;
+    export var ENOLINK: number;
+    export var ENOMEM: number;
+    export var ENOMSG: number;
+    export var ENOPROTOOPT: number;
+    export var ENOSPC: number;
+    export var ENOSR: number;
+    export var ENOSTR: number;
+    export var ENOSYS: number;
+    export var ENOTCONN: number;
+    export var ENOTDIR: number;
+    export var ENOTEMPTY: number;
+    export var ENOTSOCK: number;
+    export var ENOTSUP: number;
+    export var ENOTTY: number;
+    export var ENXIO: number;
+    export var EOPNOTSUPP: number;
+    export var EOVERFLOW: number;
+    export var EPERM: number;
+    export var EPIPE: number;
+    export var EPROTO: number;
+    export var EPROTONOSUPPORT: number;
+    export var EPROTOTYPE: number;
+    export var ERANGE: number;
+    export var EROFS: number;
+    export var ESPIPE: number;
+    export var ESRCH: number;
+    export var ETIME: number;
+    export var ETIMEDOUT: number;
+    export var ETXTBSY: number;
+    export var EWOULDBLOCK: number;
+    export var EXDEV: number;
+    export var WSAEINTR: number;
+    export var WSAEBADF: number;
+    export var WSAEACCES: number;
+    export var WSAEFAULT: number;
+    export var WSAEINVAL: number;
+    export var WSAEMFILE: number;
+    export var WSAEWOULDBLOCK: number;
+    export var WSAEINPROGRESS: number;
+    export var WSAEALREADY: number;
+    export var WSAENOTSOCK: number;
+    export var WSAEDESTADDRREQ: number;
+    export var WSAEMSGSIZE: number;
+    export var WSAEPROTOTYPE: number;
+    export var WSAENOPROTOOPT: number;
+    export var WSAEPROTONOSUPPORT: number;
+    export var WSAESOCKTNOSUPPORT: number;
+    export var WSAEOPNOTSUPP: number;
+    export var WSAEPFNOSUPPORT: number;
+    export var WSAEAFNOSUPPORT: number;
+    export var WSAEADDRINUSE: number;
+    export var WSAEADDRNOTAVAIL: number;
+    export var WSAENETDOWN: number;
+    export var WSAENETUNREACH: number;
+    export var WSAENETRESET: number;
+    export var WSAECONNABORTED: number;
+    export var WSAECONNRESET: number;
+    export var WSAENOBUFS: number;
+    export var WSAEISCONN: number;
+    export var WSAENOTCONN: number;
+    export var WSAESHUTDOWN: number;
+    export var WSAETOOMANYREFS: number;
+    export var WSAETIMEDOUT: number;
+    export var WSAECONNREFUSED: number;
+    export var WSAELOOP: number;
+    export var WSAENAMETOOLONG: number;
+    export var WSAEHOSTDOWN: number;
+    export var WSAEHOSTUNREACH: number;
+    export var WSAENOTEMPTY: number;
+    export var WSAEPROCLIM: number;
+    export var WSAEUSERS: number;
+    export var WSAEDQUOT: number;
+    export var WSAESTALE: number;
+    export var WSAEREMOTE: number;
+    export var WSASYSNOTREADY: number;
+    export var WSAVERNOTSUPPORTED: number;
+    export var WSANOTINITIALISED: number;
+    export var WSAEDISCON: number;
+    export var WSAENOMORE: number;
+    export var WSAECANCELLED: number;
+    export var WSAEINVALIDPROCTABLE: number;
+    export var WSAEINVALIDPROVIDER: number;
+    export var WSAEPROVIDERFAILEDINIT: number;
+    export var WSASYSCALLFAILURE: number;
+    export var WSASERVICE_NOT_FOUND: number;
+    export var WSATYPE_NOT_FOUND: number;
+    export var WSA_E_NO_MORE: number;
+    export var WSA_E_CANCELLED: number;
+    export var WSAEREFUSED: number;
+    export var SIGHUP: number;
+    export var SIGINT: number;
+    export var SIGILL: number;
+    export var SIGABRT: number;
+    export var SIGFPE: number;
+    export var SIGKILL: number;
+    export var SIGSEGV: number;
+    export var SIGTERM: number;
+    export var SIGBREAK: number;
+    export var SIGWINCH: number;
+    export var SSL_OP_ALL: number;
+    export var SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION: number;
+    export var SSL_OP_CIPHER_SERVER_PREFERENCE: number;
+    export var SSL_OP_CISCO_ANYCONNECT: number;
+    export var SSL_OP_COOKIE_EXCHANGE: number;
+    export var SSL_OP_CRYPTOPRO_TLSEXT_BUG: number;
+    export var SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS: number;
+    export var SSL_OP_EPHEMERAL_RSA: number;
+    export var SSL_OP_LEGACY_SERVER_CONNECT: number;
+    export var SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER: number;
+    export var SSL_OP_MICROSOFT_SESS_ID_BUG: number;
+    export var SSL_OP_MSIE_SSLV2_RSA_PADDING: number;
+    export var SSL_OP_NETSCAPE_CA_DN_BUG: number;
+    export var SSL_OP_NETSCAPE_CHALLENGE_BUG: number;
+    export var SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG: number;
+    export var SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG: number;
+    export var SSL_OP_NO_COMPRESSION: number;
+    export var SSL_OP_NO_QUERY_MTU: number;
+    export var SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION: number;
+    export var SSL_OP_NO_SSLv2: number;
+    export var SSL_OP_NO_SSLv3: number;
+    export var SSL_OP_NO_TICKET: number;
+    export var SSL_OP_NO_TLSv1: number;
+    export var SSL_OP_NO_TLSv1_1: number;
+    export var SSL_OP_NO_TLSv1_2: number;
+    export var SSL_OP_PKCS1_CHECK_1: number;
+    export var SSL_OP_PKCS1_CHECK_2: number;
+    export var SSL_OP_SINGLE_DH_USE: number;
+    export var SSL_OP_SINGLE_ECDH_USE: number;
+    export var SSL_OP_SSLEAY_080_CLIENT_DH_BUG: number;
+    export var SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG: number;
+    export var SSL_OP_TLS_BLOCK_PADDING_BUG: number;
+    export var SSL_OP_TLS_D5_BUG: number;
+    export var SSL_OP_TLS_ROLLBACK_BUG: number;
+    export var ENGINE_METHOD_DSA: number;
+    export var ENGINE_METHOD_DH: number;
+    export var ENGINE_METHOD_RAND: number;
+    export var ENGINE_METHOD_ECDH: number;
+    export var ENGINE_METHOD_ECDSA: number;
+    export var ENGINE_METHOD_CIPHERS: number;
+    export var ENGINE_METHOD_DIGESTS: number;
+    export var ENGINE_METHOD_STORE: number;
+    export var ENGINE_METHOD_PKEY_METHS: number;
+    export var ENGINE_METHOD_PKEY_ASN1_METHS: number;
+    export var ENGINE_METHOD_ALL: number;
+    export var ENGINE_METHOD_NONE: number;
+    export var DH_CHECK_P_NOT_SAFE_PRIME: number;
+    export var DH_CHECK_P_NOT_PRIME: number;
+    export var DH_UNABLE_TO_CHECK_GENERATOR: number;
+    export var DH_NOT_SUITABLE_GENERATOR: number;
+    export var NPN_ENABLED: number;
+    export var RSA_PKCS1_PADDING: number;
+    export var RSA_SSLV23_PADDING: number;
+    export var RSA_NO_PADDING: number;
+    export var RSA_PKCS1_OAEP_PADDING: number;
+    export var RSA_X931_PADDING: number;
+    export var RSA_PKCS1_PSS_PADDING: number;
+    export var POINT_CONVERSION_COMPRESSED: number;
+    export var POINT_CONVERSION_UNCOMPRESSED: number;
+    export var POINT_CONVERSION_HYBRID: number;
+    export var O_RDONLY: number;
+    export var O_WRONLY: number;
+    export var O_RDWR: number;
+    export var S_IFMT: number;
+    export var S_IFREG: number;
+    export var S_IFDIR: number;
+    export var S_IFCHR: number;
+    export var S_IFBLK: number;
+    export var S_IFIFO: number;
+    export var S_IFSOCK: number;
+    export var S_IRWXU: number;
+    export var S_IRUSR: number;
+    export var S_IWUSR: number;
+    export var S_IXUSR: number;
+    export var S_IRWXG: number;
+    export var S_IRGRP: number;
+    export var S_IWGRP: number;
+    export var S_IXGRP: number;
+    export var S_IRWXO: number;
+    export var S_IROTH: number;
+    export var S_IWOTH: number;
+    export var S_IXOTH: number;
+    export var S_IFLNK: number;
+    export var O_CREAT: number;
+    export var O_EXCL: number;
+    export var O_NOCTTY: number;
+    export var O_DIRECTORY: number;
+    export var O_NOATIME: number;
+    export var O_NOFOLLOW: number;
+    export var O_SYNC: number;
+    export var O_SYMLINK: number;
+    export var O_DIRECT: number;
+    export var O_NONBLOCK: number;
+    export var O_TRUNC: number;
+    export var O_APPEND: number;
+    export var F_OK: number;
+    export var R_OK: number;
+    export var W_OK: number;
+    export var X_OK: number;
+    export var UV_UDP_REUSEADDR: number;
+    export var SIGQUIT: number;
+    export var SIGTRAP: number;
+    export var SIGIOT: number;
+    export var SIGBUS: number;
+    export var SIGUSR1: number;
+    export var SIGUSR2: number;
+    export var SIGPIPE: number;
+    export var SIGALRM: number;
+    export var SIGCHLD: number;
+    export var SIGSTKFLT: number;
+    export var SIGCONT: number;
+    export var SIGSTOP: number;
+    export var SIGTSTP: number;
+    export var SIGTTIN: number;
+    export var SIGTTOU: number;
+    export var SIGURG: number;
+    export var SIGXCPU: number;
+    export var SIGXFSZ: number;
+    export var SIGVTALRM: number;
+    export var SIGPROF: number;
+    export var SIGIO: number;
+    export var SIGPOLL: number;
+    export var SIGPWR: number;
+    export var SIGSYS: number;
+    export var SIGUNUSED: number;
+    export var defaultCoreCipherList: string;
+    export var defaultCipherList: string;
+    export var ENGINE_METHOD_RSA: number;
+    export var ALPN_ENABLED: number;
+}
+
+declare module "process" {
+    export = process;
+}
+
+declare module "v8" {
+    interface HeapSpaceInfo {
+        space_name: string;
+        space_size: number;
+        space_used_size: number;
+        space_available_size: number;
+        physical_space_size: number;
+    }
+    export function getHeapStatistics(): { total_heap_size: number, total_heap_size_executable: number, total_physical_size: number, total_avaialble_size: number, used_heap_size: number, heap_size_limit: number };
+    export function getHeapSpaceStatistics(): HeapSpaceInfo[];
+    export function setFlagsFromString(flags: string): void;
+}
+
+declare module "timers" {
+    export function setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeJS.Timer;
+    export function clearTimeout(timeoutId: NodeJS.Timer): void;
+    export function setInterval(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeJS.Timer;
+    export function clearInterval(intervalId: NodeJS.Timer): void;
+    export function setImmediate(callback: (...args: any[]) => void, ...args: any[]): any;
+    export function clearImmediate(immediateId: any): void;
+}
+
+declare module "console" {
+    export = console;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/@types/node/package.json b/KEMMessaging/node_modules/firebase-admin/node_modules/@types/node/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..1d84bcd440a21fa3307ab57e7f871d970135d431
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/@types/node/package.json
@@ -0,0 +1,61 @@
+{
+  "_args": [
+    [
+      {
+        "raw": "@types/node@https://registry.npmjs.org/@types/node/-/node-6.0.49.tgz",
+        "scope": "@types",
+        "escapedName": "@types%2fnode",
+        "name": "@types/node",
+        "rawSpec": "https://registry.npmjs.org/@types/node/-/node-6.0.49.tgz",
+        "spec": "https://registry.npmjs.org/@types/node/-/node-6.0.49.tgz",
+        "type": "remote"
+      },
+      "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin"
+    ]
+  ],
+  "_from": "@types/node@*",
+  "_id": "@types/node@6.0.49",
+  "_inCache": true,
+  "_location": "/firebase-admin/@types/node",
+  "_phantomChildren": {},
+  "_requested": {
+    "raw": "@types/node@https://registry.npmjs.org/@types/node/-/node-6.0.49.tgz",
+    "scope": "@types",
+    "escapedName": "@types%2fnode",
+    "name": "@types/node",
+    "rawSpec": "https://registry.npmjs.org/@types/node/-/node-6.0.49.tgz",
+    "spec": "https://registry.npmjs.org/@types/node/-/node-6.0.49.tgz",
+    "type": "remote"
+  },
+  "_requiredBy": [
+    "/firebase-admin",
+    "/firebase-admin/@types/jsonwebtoken"
+  ],
+  "_resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.49.tgz",
+  "_shasum": "c644f7305e0d64bd797c939af833f22d150e1d33",
+  "_shrinkwrap": null,
+  "_spec": "@types/node@https://registry.npmjs.org/@types/node/-/node-6.0.49.tgz",
+  "_where": "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin",
+  "author": {
+    "name": "Microsoft TypeScript",
+    "email": "http://typescriptlang.org"
+  },
+  "dependencies": {},
+  "description": "TypeScript definitions for Node.js v6.x",
+  "devDependencies": {},
+  "license": "MIT",
+  "main": "",
+  "name": "@types/node",
+  "optionalDependencies": {},
+  "peerDependencies": {},
+  "readme": "# Installation\r\n> `npm install --save @types/node`\r\n\r\n# Summary\r\nThis package contains type definitions for Node.js v6.x (http://nodejs.org/).\r\n\r\n# Details\r\nFiles were exported from https://www.github.com/DefinitelyTyped/DefinitelyTyped/tree/types-2.0/node\r\n\r\nAdditional Details\r\n * Last updated: Mon, 21 Nov 2016 14:53:06 GMT\r\n * File structure: ModuleAugmentation\r\n * Library Dependencies: none\r\n * Module Dependencies: child_process, crypto, events, http, net, readline, stream, tls\r\n * Global values: Buffer, NodeJS, SlowBuffer, __dirname, __filename, clearImmediate, clearInterval, clearTimeout, console, exports, global, module, process, require, setImmediate, setInterval, setTimeout\r\n\r\n# Credits\r\nThese definitions were written by Microsoft TypeScript <http://typescriptlang.org>, DefinitelyTyped <https://github.com/DefinitelyTyped/DefinitelyTyped>.\r\n",
+  "readmeFilename": "README.md",
+  "repository": {
+    "type": "git",
+    "url": "https://www.github.com/DefinitelyTyped/DefinitelyTyped.git"
+  },
+  "scripts": {},
+  "typesPublisherContentHash": "5df9f3f6250a8591a4bf4316e05b8f650720282cc799bee39b3ebecaaffb2a25",
+  "typings": "index.d.ts",
+  "version": "6.0.49"
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/@types/node/types-metadata.json b/KEMMessaging/node_modules/firebase-admin/node_modules/@types/node/types-metadata.json
new file mode 100644
index 0000000000000000000000000000000000000000..5a8bd2fe004271b25526b2f19231c9f1ecd7ca75
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/@types/node/types-metadata.json
@@ -0,0 +1,81 @@
+{
+    "authors": "Microsoft TypeScript <http://typescriptlang.org>, DefinitelyTyped <https://github.com/DefinitelyTyped/DefinitelyTyped>",
+    "definitionFilename": "index.d.ts",
+    "libraryDependencies": [],
+    "moduleDependencies": [
+        "child_process",
+        "crypto",
+        "events",
+        "http",
+        "net",
+        "readline",
+        "stream",
+        "tls"
+    ],
+    "libraryMajorVersion": 6,
+    "libraryMinorVersion": 0,
+    "libraryName": "Node.js v6.x",
+    "typingsPackageName": "node",
+    "projectName": "http://nodejs.org/",
+    "sourceRepoURL": "https://www.github.com/DefinitelyTyped/DefinitelyTyped",
+    "sourceBranch": "types-2.0",
+    "kind": "ModuleAugmentation",
+    "globals": [
+        "Buffer",
+        "NodeJS",
+        "SlowBuffer",
+        "__dirname",
+        "__filename",
+        "clearImmediate",
+        "clearInterval",
+        "clearTimeout",
+        "console",
+        "exports",
+        "global",
+        "module",
+        "process",
+        "require",
+        "setImmediate",
+        "setInterval",
+        "setTimeout"
+    ],
+    "declaredModules": [
+        "buffer",
+        "querystring",
+        "events",
+        "http",
+        "cluster",
+        "zlib",
+        "os",
+        "https",
+        "punycode",
+        "repl",
+        "readline",
+        "vm",
+        "child_process",
+        "url",
+        "dns",
+        "net",
+        "dgram",
+        "fs",
+        "path",
+        "string_decoder",
+        "tls",
+        "crypto",
+        "stream",
+        "util",
+        "assert",
+        "tty",
+        "domain",
+        "constants",
+        "process",
+        "v8",
+        "timers",
+        "console"
+    ],
+    "files": [
+        "index.d.ts"
+    ],
+    "hasPackageJson": false,
+    "contentHash": "5df9f3f6250a8591a4bf4316e05b8f650720282cc799bee39b3ebecaaffb2a25"
+}
\ No newline at end of file
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/base64-url/LICENSE b/KEMMessaging/node_modules/firebase-admin/node_modules/base64-url/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..95491436e579eb4e9bb8bf0bde30f0348dbf9f05
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/base64-url/LICENSE
@@ -0,0 +1,15 @@
+The ISC License
+
+Copyright (c) 2014, Joaquim José F. Serafim
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/base64-url/README.md b/KEMMessaging/node_modules/firebase-admin/node_modules/base64-url/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..b61ee471403de861f90156941762a4dbc677f707
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/base64-url/README.md
@@ -0,0 +1,52 @@
+# base64-url
+
+Base64 encode, decode, escape and unescape for URL applications.
+
+<a href="https://nodei.co/npm/base64-url/"><img src="https://nodei.co/npm/base64-url.png?downloads=true"></a>
+
+[![Build Status](https://travis-ci.org/joaquimserafim/base64-url.png?branch=master)](https://travis-ci.org/joaquimserafim/base64-url)
+
+
+## API
+
+```js
+var base64url = require('base64-url');
+
+base64url.encode('Node.js is awesome.');
+// returns Tm9kZS5qcyBpcyBhd2Vzb21lLg
+
+base64url.decode('Tm9kZS5qcyBpcyBhd2Vzb21lLg');
+// returns Node.js is awesome.
+
+base64url.escape('This+is/goingto+escape==');
+// returns This-is_goingto-escape
+
+base64url.unescape('This-is_goingto-escape');
+// returns This+is/goingto+escape==
+```
+
+
+## Development
+
+**this project has been set up with a precommit that forces you to follow a code style, no jshint issues and 100% of code coverage before commit**
+
+
+to run test
+``` js
+npm test
+```
+
+to run lint
+``` js
+npm run lint
+```
+
+to run code style
+``` js
+npm run style
+```
+
+to check code coverage
+``` js
+npm run coverage:check
+```
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/base64-url/index.js b/KEMMessaging/node_modules/firebase-admin/node_modules/base64-url/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..9ba16e90571673b8bf6ce8dc8e01a5341c9fc888
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/base64-url/index.js
@@ -0,0 +1,23 @@
+'use strict';
+
+var base64url = module.exports;
+
+base64url.unescape = function unescape (str) {
+  return (str + '==='.slice((str.length + 3) % 4))
+    .replace(/\-/g, '+')
+    .replace(/_/g, '/');
+};
+
+base64url.escape = function escape (str) {
+  return str.replace(/\+/g, '-')
+    .replace(/\//g, '_')
+    .replace(/=/g, '');
+};
+
+base64url.encode = function encode (str) {
+  return this.escape(new Buffer(str).toString('base64'));
+};
+
+base64url.decode = function decode (str) {
+  return new Buffer(this.unescape(str), 'base64').toString();
+};
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/base64-url/package.json b/KEMMessaging/node_modules/firebase-admin/node_modules/base64-url/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..91afcf47c9cb100f770f6cb577856b2e858a458b
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/base64-url/package.json
@@ -0,0 +1,88 @@
+{
+  "_args": [
+    [
+      {
+        "raw": "base64-url@https://registry.npmjs.org/base64-url/-/base64-url-1.3.3.tgz",
+        "scope": null,
+        "escapedName": "base64-url",
+        "name": "base64-url",
+        "rawSpec": "https://registry.npmjs.org/base64-url/-/base64-url-1.3.3.tgz",
+        "spec": "https://registry.npmjs.org/base64-url/-/base64-url-1.3.3.tgz",
+        "type": "remote"
+      },
+      "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin"
+    ]
+  ],
+  "_from": "base64-url@>=1.2.1 <2.0.0",
+  "_id": "base64-url@1.3.3",
+  "_inCache": true,
+  "_location": "/firebase-admin/base64-url",
+  "_phantomChildren": {},
+  "_requested": {
+    "raw": "base64-url@https://registry.npmjs.org/base64-url/-/base64-url-1.3.3.tgz",
+    "scope": null,
+    "escapedName": "base64-url",
+    "name": "base64-url",
+    "rawSpec": "https://registry.npmjs.org/base64-url/-/base64-url-1.3.3.tgz",
+    "spec": "https://registry.npmjs.org/base64-url/-/base64-url-1.3.3.tgz",
+    "type": "remote"
+  },
+  "_requiredBy": [
+    "/firebase-admin",
+    "/firebase-admin/ecdsa-sig-formatter"
+  ],
+  "_resolved": "https://registry.npmjs.org/base64-url/-/base64-url-1.3.3.tgz",
+  "_shasum": "f8b6c537f09a4fc58c99cb86e0b0e9c61461a20f",
+  "_shrinkwrap": null,
+  "_spec": "base64-url@https://registry.npmjs.org/base64-url/-/base64-url-1.3.3.tgz",
+  "_where": "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin",
+  "author": {
+    "name": "@joaquimserafim"
+  },
+  "bugs": {
+    "url": "https://github.com/joaquimserafim/base64-url/issues"
+  },
+  "dependencies": {},
+  "description": "Base64 encode, decode, escape and unescape for URL applications",
+  "devDependencies": {
+    "istanbul": "^0.3.5",
+    "jscs": "^1.9.0",
+    "jshint": "^2.5.11",
+    "pre-commit": "^1.1.3",
+    "tape": "^4.6.0"
+  },
+  "files": [
+    "LICENSE",
+    "README.md",
+    "index.js"
+  ],
+  "homepage": "https://github.com/joaquimserafim/base64-url",
+  "keywords": [
+    "base64",
+    "base64url"
+  ],
+  "license": "ISC",
+  "main": "index.js",
+  "name": "base64-url",
+  "optionalDependencies": {},
+  "pre-commit": [
+    "lint",
+    "style",
+    "test",
+    "coverage:check"
+  ],
+  "readme": "# base64-url\n\nBase64 encode, decode, escape and unescape for URL applications.\n\n<a href=\"https://nodei.co/npm/base64-url/\"><img src=\"https://nodei.co/npm/base64-url.png?downloads=true\"></a>\n\n[![Build Status](https://travis-ci.org/joaquimserafim/base64-url.png?branch=master)](https://travis-ci.org/joaquimserafim/base64-url)\n\n\n## API\n\n```js\nvar base64url = require('base64-url');\n\nbase64url.encode('Node.js is awesome.');\n// returns Tm9kZS5qcyBpcyBhd2Vzb21lLg\n\nbase64url.decode('Tm9kZS5qcyBpcyBhd2Vzb21lLg');\n// returns Node.js is awesome.\n\nbase64url.escape('This+is/goingto+escape==');\n// returns This-is_goingto-escape\n\nbase64url.unescape('This-is_goingto-escape');\n// returns This+is/goingto+escape==\n```\n\n\n## Development\n\n**this project has been set up with a precommit that forces you to follow a code style, no jshint issues and 100% of code coverage before commit**\n\n\nto run test\n``` js\nnpm test\n```\n\nto run lint\n``` js\nnpm run lint\n```\n\nto run code style\n``` js\nnpm run style\n```\n\nto check code coverage\n``` js\nnpm run coverage:check\n```\n",
+  "readmeFilename": "README.md",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/joaquimserafim/base64-url.git"
+  },
+  "scripts": {
+    "coverage": "open coverage/lcov-report/index.html",
+    "coverage:check": "istanbul check-coverage --statements 100 --functions 100 --lines 100 --branches 100",
+    "lint": "jshint -c .jshintrc *.js",
+    "style": "jscs -p google *.js",
+    "test": "istanbul cover tape test.js"
+  },
+  "version": "1.3.3"
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/dist/.gitkeep b/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/dist/.gitkeep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/dist/base64url.d.ts b/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/dist/base64url.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8ff3772a525f4e73ba6aeea202229f213c13573f
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/dist/base64url.d.ts
@@ -0,0 +1,11 @@
+/// <reference path="../typings/index.d.ts" />
+export interface Base64Url {
+    (input: string | Buffer, encoding?: string): string;
+    encode(input: string | Buffer, encoding?: string): string;
+    decode(base64url: string, encoding?: string): string;
+    toBase64(base64url: string | Buffer): string;
+    fromBase64(base64: string): string;
+    toBuffer(base64url: string): Buffer;
+}
+declare let base64url: Base64Url;
+export default base64url;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/dist/base64url.js b/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/dist/base64url.js
new file mode 100644
index 0000000000000000000000000000000000000000..577853b33587d40becd961ba88c7851a68aff7d4
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/dist/base64url.js
@@ -0,0 +1,37 @@
+"use strict";
+var pad_string_1 = require("./pad-string");
+function encode(input, encoding) {
+    if (encoding === void 0) { encoding = "utf8"; }
+    if (Buffer.isBuffer(input)) {
+        return fromBase64(input.toString("base64"));
+    }
+    return fromBase64(new Buffer(input, encoding).toString("base64"));
+}
+;
+function decode(base64url, encoding) {
+    if (encoding === void 0) { encoding = "utf8"; }
+    return new Buffer(toBase64(base64url), "base64").toString(encoding);
+}
+function toBase64(base64url) {
+    base64url = base64url.toString();
+    return pad_string_1.default(base64url)
+        .replace(/\-/g, "+")
+        .replace(/_/g, "/");
+}
+function fromBase64(base64) {
+    return base64
+        .replace(/=/g, "")
+        .replace(/\+/g, "-")
+        .replace(/\//g, "_");
+}
+function toBuffer(base64url) {
+    return new Buffer(toBase64(base64url), "base64");
+}
+var base64url = encode;
+base64url.encode = encode;
+base64url.decode = decode;
+base64url.toBase64 = toBase64;
+base64url.fromBase64 = fromBase64;
+base64url.toBuffer = toBuffer;
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.default = base64url;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/dist/pad-string.d.ts b/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/dist/pad-string.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1f692ecdecbe975b94716c1f2fca7adbfe7cbb64
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/dist/pad-string.d.ts
@@ -0,0 +1 @@
+export default function padString(input: string): string;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/dist/pad-string.js b/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/dist/pad-string.js
new file mode 100644
index 0000000000000000000000000000000000000000..8cda38a13fcf4242353832a168b7591bb6ec936a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/dist/pad-string.js
@@ -0,0 +1,20 @@
+"use strict";
+function padString(input) {
+    var segmentLength = 4;
+    var stringLength = input.length;
+    var diff = stringLength % segmentLength;
+    if (!diff) {
+        return input;
+    }
+    var position = stringLength;
+    var padLength = segmentLength - diff;
+    var paddedStringLength = stringLength + padLength;
+    var buffer = new Buffer(paddedStringLength);
+    buffer.write(input);
+    while (padLength--) {
+        buffer.write("=", position++);
+    }
+    return buffer.toString();
+}
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.default = padString;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/index.js b/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..85e5831ea676715013cb84c4f092007a4f00dfd4
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/index.js
@@ -0,0 +1,2 @@
+module.exports = require('./dist/base64url').default;
+module.exports.default = module.exports;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/package.json b/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..00211d987603f5f5a16962582013a7be7793bb04
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/package.json
@@ -0,0 +1,79 @@
+{
+  "_args": [
+    [
+      {
+        "raw": "base64url@https://registry.npmjs.org/base64url/-/base64url-2.0.0.tgz",
+        "scope": null,
+        "escapedName": "base64url",
+        "name": "base64url",
+        "rawSpec": "https://registry.npmjs.org/base64url/-/base64url-2.0.0.tgz",
+        "spec": "https://registry.npmjs.org/base64url/-/base64url-2.0.0.tgz",
+        "type": "remote"
+      },
+      "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin"
+    ]
+  ],
+  "_from": "base64url@>=2.0.0 <3.0.0",
+  "_id": "base64url@2.0.0",
+  "_inCache": true,
+  "_location": "/firebase-admin/base64url",
+  "_phantomChildren": {},
+  "_requested": {
+    "raw": "base64url@https://registry.npmjs.org/base64url/-/base64url-2.0.0.tgz",
+    "scope": null,
+    "escapedName": "base64url",
+    "name": "base64url",
+    "rawSpec": "https://registry.npmjs.org/base64url/-/base64url-2.0.0.tgz",
+    "spec": "https://registry.npmjs.org/base64url/-/base64url-2.0.0.tgz",
+    "type": "remote"
+  },
+  "_requiredBy": [
+    "/firebase-admin",
+    "/firebase-admin/jwa",
+    "/firebase-admin/jws"
+  ],
+  "_resolved": "https://registry.npmjs.org/base64url/-/base64url-2.0.0.tgz",
+  "_shasum": "eac16e03ea1438eff9423d69baa36262ed1f70bb",
+  "_shrinkwrap": null,
+  "_spec": "base64url@https://registry.npmjs.org/base64url/-/base64url-2.0.0.tgz",
+  "_where": "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin",
+  "author": {
+    "name": "Brian J Brennan"
+  },
+  "bugs": {
+    "url": "https://github.com/brianloveswords/base64url/issues"
+  },
+  "dependencies": {},
+  "description": "For encoding to/from base64urls",
+  "devDependencies": {
+    "tap": "6.1.1"
+  },
+  "files": [
+    "dist/",
+    "typings/",
+    "index.js"
+  ],
+  "homepage": "https://github.com/brianloveswords/base64url#readme",
+  "keywords": [
+    "base64",
+    "base64url"
+  ],
+  "license": "MIT",
+  "main": "index.js",
+  "name": "base64url",
+  "optionalDependencies": {},
+  "readme": "# base64url  [![Build Status](https://secure.travis-ci.org/brianloveswords/base64url.png)](http://travis-ci.org/brianloveswords/base64url)\n\nConverting to, and from, [base64url](http://en.wikipedia.org/wiki/Base64#RFC_4648)\n\n# Install\n\n```bash\n$ npm install base64url\n```\n\nAfter installing with `npm` you can require this library from JavaScript or TypeScript:\n\nJavaScript\n```js\nconst base64url = require('base64url');\n```\n\nTypeScript:\n```typescript\nimport base64url from \"base64url\";\n```\n\n# Usage\n\n## CLI\n\nThe CLI has been removed. For the time being, please install `base64url@1.0.6` if you need the CLI.\n\n## Library\n\n### base64url(input: string | Buffer, encoding: string = \"utf8\"): string\n\n### base64url.encode(input: string | Buffer, encoding: string = \"utf8\"): string\n\nbase64url encode `input`. Input should be a `string` or a `Buffer`.\n\n\nExample\n\n```js\n> base64url(\"ladies and gentlemen we are floating in space\")\n'bGFkaWVzIGFuZCBnZW50bGVtYW4sIHdlIGFyZSBmbG9hdGluZyBpbiBzcGFjZQ'\n```\n\n---\n\n### base64url.decode(input: string, encoding: string = \"utf8\"): string\n\nConvert a base64url encoded string into a raw string. The `encoding` argument can be used if the input is a string that's not utf8.\n\n```js\n> base64url.decode(\"cmlkZTogZHJlYW1zIGJ1cm4gZG93bg\")\n'ride: dreams burn down'\n```\n\n---\n\n### base64url.fromBase64(input: string): string\n\nConvert a base64 encoded string to a base64url encoded string.\n\nExample\n\n```js\n> base64url.fromBase64('qL8R4QIcQ/ZsRqOAbeRfcZhilN/MksRtDaErMA==')\n'qL8R4QIcQ_ZsRqOAbeRfcZhilN_MksRtDaErMA'\n```\n\n---\n\n\n### base64url.toBase64(input: string): string\n\nConvert a base64url encoded string to a base64 encoded string.\n\n```js\n> base64url.toBase64('qL8R4QIcQ_ZsRqOAbeRfcZhilN_MksRtDaErMA')\n'qL8R4QIcQ/ZsRqOAbeRfcZhilN/MksRtDaErMA=='\n```\n\n---\n\n\n### base64url.toBuffer(input: string): Buffer\n\nConvert a base64url encoded string to a Buffer containing the decoded bytes.\n\n```js\n> base64url.toBuffer('c3Bpcml0dWFsaXplZA')\n<Buffer 73 70 69 72 69 74 75 61 6c 69 7a 65 64>\n```\n\n# License\n\nMIT\n\n```\nCopyright (c) 2013–2016 Brian J. Brennan\n\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be included\nin all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\nOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n```\n",
+  "readmeFilename": "readme.md",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/brianloveswords/base64url.git"
+  },
+  "scripts": {
+    "build": "tsc",
+    "clean": "rm -f dist/*",
+    "prepublish": "npm run test",
+    "test": "npm run clean && npm run build && tap test/*.test.js"
+  },
+  "typings": "dist/base64url.d.ts",
+  "version": "2.0.0"
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/readme.md b/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..58be17e4f35b234001ea6f93efe7e49efa7ba6e2
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/readme.md
@@ -0,0 +1,118 @@
+# base64url  [![Build Status](https://secure.travis-ci.org/brianloveswords/base64url.png)](http://travis-ci.org/brianloveswords/base64url)
+
+Converting to, and from, [base64url](http://en.wikipedia.org/wiki/Base64#RFC_4648)
+
+# Install
+
+```bash
+$ npm install base64url
+```
+
+After installing with `npm` you can require this library from JavaScript or TypeScript:
+
+JavaScript
+```js
+const base64url = require('base64url');
+```
+
+TypeScript:
+```typescript
+import base64url from "base64url";
+```
+
+# Usage
+
+## CLI
+
+The CLI has been removed. For the time being, please install `base64url@1.0.6` if you need the CLI.
+
+## Library
+
+### base64url(input: string | Buffer, encoding: string = "utf8"): string
+
+### base64url.encode(input: string | Buffer, encoding: string = "utf8"): string
+
+base64url encode `input`. Input should be a `string` or a `Buffer`.
+
+
+Example
+
+```js
+> base64url("ladies and gentlemen we are floating in space")
+'bGFkaWVzIGFuZCBnZW50bGVtYW4sIHdlIGFyZSBmbG9hdGluZyBpbiBzcGFjZQ'
+```
+
+---
+
+### base64url.decode(input: string, encoding: string = "utf8"): string
+
+Convert a base64url encoded string into a raw string. The `encoding` argument can be used if the input is a string that's not utf8.
+
+```js
+> base64url.decode("cmlkZTogZHJlYW1zIGJ1cm4gZG93bg")
+'ride: dreams burn down'
+```
+
+---
+
+### base64url.fromBase64(input: string): string
+
+Convert a base64 encoded string to a base64url encoded string.
+
+Example
+
+```js
+> base64url.fromBase64('qL8R4QIcQ/ZsRqOAbeRfcZhilN/MksRtDaErMA==')
+'qL8R4QIcQ_ZsRqOAbeRfcZhilN_MksRtDaErMA'
+```
+
+---
+
+
+### base64url.toBase64(input: string): string
+
+Convert a base64url encoded string to a base64 encoded string.
+
+```js
+> base64url.toBase64('qL8R4QIcQ_ZsRqOAbeRfcZhilN_MksRtDaErMA')
+'qL8R4QIcQ/ZsRqOAbeRfcZhilN/MksRtDaErMA=='
+```
+
+---
+
+
+### base64url.toBuffer(input: string): Buffer
+
+Convert a base64url encoded string to a Buffer containing the decoded bytes.
+
+```js
+> base64url.toBuffer('c3Bpcml0dWFsaXplZA')
+<Buffer 73 70 69 72 69 74 75 61 6c 69 7a 65 64>
+```
+
+# License
+
+MIT
+
+```
+Copyright (c) 2013–2016 Brian J. Brennan
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+```
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/typings/globals/node/index.d.ts b/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/typings/globals/node/index.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..bba54ec450575a8dee00f9bc736f88054d6f45c2
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/typings/globals/node/index.d.ts
@@ -0,0 +1,2578 @@
+// Generated by typings
+// Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/77b1b1709315b03b9b1b67c589d599bebeeef2ee/node/node.d.ts
+interface Error {
+    stack?: string;
+}
+
+interface ErrorConstructor {
+    captureStackTrace(targetObject: Object, constructorOpt?: Function): void;
+    stackTraceLimit: number;
+}
+
+// compat for TypeScript 1.8
+// if you use with --target es3 or --target es5 and use below definitions,
+// use the lib.es6.d.ts that is bundled with TypeScript 1.8.
+interface MapConstructor {}
+interface WeakMapConstructor {}
+interface SetConstructor {}
+interface WeakSetConstructor {}
+
+/************************************************
+*                                               *
+*                   GLOBAL                      *
+*                                               *
+************************************************/
+declare var process: NodeJS.Process;
+declare var global: NodeJS.Global;
+
+declare var __filename: string;
+declare var __dirname: string;
+
+declare function setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeJS.Timer;
+declare function clearTimeout(timeoutId: NodeJS.Timer): void;
+declare function setInterval(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeJS.Timer;
+declare function clearInterval(intervalId: NodeJS.Timer): void;
+declare function setImmediate(callback: (...args: any[]) => void, ...args: any[]): any;
+declare function clearImmediate(immediateId: any): void;
+
+interface NodeRequireFunction {
+    (id: string): any;
+}
+
+interface NodeRequire extends NodeRequireFunction {
+    resolve(id:string): string;
+    cache: any;
+    extensions: any;
+    main: any;
+}
+
+declare var require: NodeRequire;
+
+interface NodeModule {
+    exports: any;
+    require: NodeRequireFunction;
+    id: string;
+    filename: string;
+    loaded: boolean;
+    parent: any;
+    children: any[];
+}
+
+declare var module: NodeModule;
+
+// Same as module.exports
+declare var exports: any;
+declare var SlowBuffer: {
+    new (str: string, encoding?: string): Buffer;
+    new (size: number): Buffer;
+    new (size: Uint8Array): Buffer;
+    new (array: any[]): Buffer;
+    prototype: Buffer;
+    isBuffer(obj: any): boolean;
+    byteLength(string: string, encoding?: string): number;
+    concat(list: Buffer[], totalLength?: number): Buffer;
+};
+
+
+// Buffer class
+type BufferEncoding = "ascii" | "utf8" | "utf16le" | "ucs2" | "binary" | "hex";
+interface Buffer extends NodeBuffer {}
+
+/**
+ * Raw data is stored in instances of the Buffer class.
+ * A Buffer is similar to an array of integers but corresponds to a raw memory allocation outside the V8 heap.  A Buffer cannot be resized.
+ * Valid string encodings: 'ascii'|'utf8'|'utf16le'|'ucs2'(alias of 'utf16le')|'base64'|'binary'(deprecated)|'hex'
+ */
+declare var Buffer: {
+    /**
+     * Allocates a new buffer containing the given {str}.
+     *
+     * @param str String to store in buffer.
+     * @param encoding encoding to use, optional.  Default is 'utf8'
+     */
+    new (str: string, encoding?: string): Buffer;
+    /**
+     * Allocates a new buffer of {size} octets.
+     *
+     * @param size count of octets to allocate.
+     */
+    new (size: number): Buffer;
+    /**
+     * Allocates a new buffer containing the given {array} of octets.
+     *
+     * @param array The octets to store.
+     */
+    new (array: Uint8Array): Buffer;
+    /**
+     * Produces a Buffer backed by the same allocated memory as
+     * the given {ArrayBuffer}.
+     *
+     *
+     * @param arrayBuffer The ArrayBuffer with which to share memory.
+     */
+    new (arrayBuffer: ArrayBuffer): Buffer;
+    /**
+     * Allocates a new buffer containing the given {array} of octets.
+     *
+     * @param array The octets to store.
+     */
+    new (array: any[]): Buffer;
+    /**
+     * Copies the passed {buffer} data onto a new {Buffer} instance.
+     *
+     * @param buffer The buffer to copy.
+     */
+    new (buffer: Buffer): Buffer;
+    prototype: Buffer;
+    /**
+     * Allocates a new Buffer using an {array} of octets.
+     *
+     * @param array
+     */
+    from(array: any[]): Buffer;
+    /**
+     * When passed a reference to the .buffer property of a TypedArray instance,
+     * the newly created Buffer will share the same allocated memory as the TypedArray.
+     * The optional {byteOffset} and {length} arguments specify a memory range
+     * within the {arrayBuffer} that will be shared by the Buffer.
+     *
+     * @param arrayBuffer The .buffer property of a TypedArray or a new ArrayBuffer()
+     * @param byteOffset
+     * @param length
+     */
+    from(arrayBuffer: ArrayBuffer, byteOffset?: number, length?:number): Buffer;
+    /**
+     * Copies the passed {buffer} data onto a new Buffer instance.
+     *
+     * @param buffer
+     */
+    from(buffer: Buffer): Buffer;
+    /**
+     * Creates a new Buffer containing the given JavaScript string {str}.
+     * If provided, the {encoding} parameter identifies the character encoding.
+     * If not provided, {encoding} defaults to 'utf8'.
+     *
+     * @param str
+     */
+    from(str: string, encoding?: string): Buffer;
+    /**
+     * Returns true if {obj} is a Buffer
+     *
+     * @param obj object to test.
+     */
+    isBuffer(obj: any): obj is Buffer;
+    /**
+     * Returns true if {encoding} is a valid encoding argument.
+     * Valid string encodings in Node 0.12: 'ascii'|'utf8'|'utf16le'|'ucs2'(alias of 'utf16le')|'base64'|'binary'(deprecated)|'hex'
+     *
+     * @param encoding string to test.
+     */
+    isEncoding(encoding: string): boolean;
+    /**
+     * Gives the actual byte length of a string. encoding defaults to 'utf8'.
+     * This is not the same as String.prototype.length since that returns the number of characters in a string.
+     *
+     * @param string string to test.
+     * @param encoding encoding used to evaluate (defaults to 'utf8')
+     */
+    byteLength(string: string, encoding?: string): number;
+    /**
+     * Returns a buffer which is the result of concatenating all the buffers in the list together.
+     *
+     * If the list has no items, or if the totalLength is 0, then it returns a zero-length buffer.
+     * If the list has exactly one item, then the first item of the list is returned.
+     * If the list has more than one item, then a new Buffer is created.
+     *
+     * @param list An array of Buffer objects to concatenate
+     * @param totalLength Total length of the buffers when concatenated.
+     *   If totalLength is not provided, it is read from the buffers in the list. However, this adds an additional loop to the function, so it is faster to provide the length explicitly.
+     */
+    concat(list: Buffer[], totalLength?: number): Buffer;
+    /**
+     * The same as buf1.compare(buf2).
+     */
+    compare(buf1: Buffer, buf2: Buffer): number;
+    /**
+     * Allocates a new buffer of {size} octets.
+     *
+     * @param size count of octets to allocate.
+     * @param fill if specified, buffer will be initialized by calling buf.fill(fill).
+     *    If parameter is omitted, buffer will be filled with zeros.
+     * @param encoding encoding used for call to buf.fill while initalizing
+     */
+    alloc(size: number, fill?: string|Buffer|number, encoding?: string): Buffer;
+     /**
+      * Allocates a new buffer of {size} octets, leaving memory not initialized, so the contents
+      * of the newly created Buffer are unknown and may contain sensitive data.
+      *
+      * @param size count of octets to allocate
+      */
+    allocUnsafe(size: number): Buffer;
+     /**
+      * Allocates a new non-pooled buffer of {size} octets, leaving memory not initialized, so the contents
+      * of the newly created Buffer are unknown and may contain sensitive data.
+      *
+      * @param size count of octets to allocate
+      */
+    allocUnsafeSlow(size: number): Buffer;
+};
+
+/************************************************
+*                                               *
+*               GLOBAL INTERFACES               *
+*                                               *
+************************************************/
+declare namespace NodeJS {
+    export interface ErrnoException extends Error {
+        errno?: number;
+        code?: string;
+        path?: string;
+        syscall?: string;
+        stack?: string;
+    }
+
+    export interface EventEmitter {
+        addListener(event: string, listener: Function): this;
+        on(event: string, listener: Function): this;
+        once(event: string, listener: Function): this;
+        removeListener(event: string, listener: Function): this;
+        removeAllListeners(event?: string): this;
+        setMaxListeners(n: number): this;
+        getMaxListeners(): number;
+        listeners(event: string): Function[];
+        emit(event: string, ...args: any[]): boolean;
+        listenerCount(type: string): number;
+    }
+
+    export interface ReadableStream extends EventEmitter {
+        readable: boolean;
+        read(size?: number): string|Buffer;
+        setEncoding(encoding: string): void;
+        pause(): void;
+        resume(): void;
+        pipe<T extends WritableStream>(destination: T, options?: { end?: boolean; }): T;
+        unpipe<T extends WritableStream>(destination?: T): void;
+        unshift(chunk: string): void;
+        unshift(chunk: Buffer): void;
+        wrap(oldStream: ReadableStream): ReadableStream;
+    }
+
+    export interface WritableStream extends EventEmitter {
+        writable: boolean;
+        write(buffer: Buffer|string, cb?: Function): boolean;
+        write(str: string, encoding?: string, cb?: Function): boolean;
+        end(): void;
+        end(buffer: Buffer, cb?: Function): void;
+        end(str: string, cb?: Function): void;
+        end(str: string, encoding?: string, cb?: Function): void;
+    }
+
+    export interface ReadWriteStream extends ReadableStream, WritableStream {}
+
+    export interface Events extends EventEmitter { }
+
+    export interface Domain extends Events {
+        run(fn: Function): void;
+        add(emitter: Events): void;
+        remove(emitter: Events): void;
+        bind(cb: (err: Error, data: any) => any): any;
+        intercept(cb: (data: any) => any): any;
+        dispose(): void;
+
+        addListener(event: string, listener: Function): this;
+        on(event: string, listener: Function): this;
+        once(event: string, listener: Function): this;
+        removeListener(event: string, listener: Function): this;
+        removeAllListeners(event?: string): this;
+    }
+
+    export interface MemoryUsage {
+        rss: number;
+        heapTotal: number;
+        heapUsed: number;
+    }
+
+    export interface Process extends EventEmitter {
+        stdout: WritableStream;
+        stderr: WritableStream;
+        stdin: ReadableStream;
+        argv: string[];
+        execArgv: string[];
+        execPath: string;
+        abort(): void;
+        chdir(directory: string): void;
+        cwd(): string;
+        env: any;
+        exit(code?: number): void;
+        getgid(): number;
+        setgid(id: number): void;
+        setgid(id: string): void;
+        getuid(): number;
+        setuid(id: number): void;
+        setuid(id: string): void;
+        version: string;
+        versions: {
+            http_parser: string;
+            node: string;
+            v8: string;
+            ares: string;
+            uv: string;
+            zlib: string;
+            modules: string;
+            openssl: string;
+        };
+        config: {
+            target_defaults: {
+                cflags: any[];
+                default_configuration: string;
+                defines: string[];
+                include_dirs: string[];
+                libraries: string[];
+            };
+            variables: {
+                clang: number;
+                host_arch: string;
+                node_install_npm: boolean;
+                node_install_waf: boolean;
+                node_prefix: string;
+                node_shared_openssl: boolean;
+                node_shared_v8: boolean;
+                node_shared_zlib: boolean;
+                node_use_dtrace: boolean;
+                node_use_etw: boolean;
+                node_use_openssl: boolean;
+                target_arch: string;
+                v8_no_strict_aliasing: number;
+                v8_use_snapshot: boolean;
+                visibility: string;
+            };
+        };
+        kill(pid:number, signal?: string|number): void;
+        pid: number;
+        title: string;
+        arch: string;
+        platform: string;
+        memoryUsage(): MemoryUsage;
+        nextTick(callback: Function): void;
+        umask(mask?: number): number;
+        uptime(): number;
+        hrtime(time?:number[]): number[];
+        domain: Domain;
+
+        // Worker
+        send?(message: any, sendHandle?: any): void;
+        disconnect(): void;
+        connected: boolean;
+    }
+
+    export interface Global {
+        Array: typeof Array;
+        ArrayBuffer: typeof ArrayBuffer;
+        Boolean: typeof Boolean;
+        Buffer: typeof Buffer;
+        DataView: typeof DataView;
+        Date: typeof Date;
+        Error: typeof Error;
+        EvalError: typeof EvalError;
+        Float32Array: typeof Float32Array;
+        Float64Array: typeof Float64Array;
+        Function: typeof Function;
+        GLOBAL: Global;
+        Infinity: typeof Infinity;
+        Int16Array: typeof Int16Array;
+        Int32Array: typeof Int32Array;
+        Int8Array: typeof Int8Array;
+        Intl: typeof Intl;
+        JSON: typeof JSON;
+        Map: MapConstructor;
+        Math: typeof Math;
+        NaN: typeof NaN;
+        Number: typeof Number;
+        Object: typeof Object;
+        Promise: Function;
+        RangeError: typeof RangeError;
+        ReferenceError: typeof ReferenceError;
+        RegExp: typeof RegExp;
+        Set: SetConstructor;
+        String: typeof String;
+        Symbol: Function;
+        SyntaxError: typeof SyntaxError;
+        TypeError: typeof TypeError;
+        URIError: typeof URIError;
+        Uint16Array: typeof Uint16Array;
+        Uint32Array: typeof Uint32Array;
+        Uint8Array: typeof Uint8Array;
+        Uint8ClampedArray: Function;
+        WeakMap: WeakMapConstructor;
+        WeakSet: WeakSetConstructor;
+        clearImmediate: (immediateId: any) => void;
+        clearInterval: (intervalId: NodeJS.Timer) => void;
+        clearTimeout: (timeoutId: NodeJS.Timer) => void;
+        console: typeof console;
+        decodeURI: typeof decodeURI;
+        decodeURIComponent: typeof decodeURIComponent;
+        encodeURI: typeof encodeURI;
+        encodeURIComponent: typeof encodeURIComponent;
+        escape: (str: string) => string;
+        eval: typeof eval;
+        global: Global;
+        isFinite: typeof isFinite;
+        isNaN: typeof isNaN;
+        parseFloat: typeof parseFloat;
+        parseInt: typeof parseInt;
+        process: Process;
+        root: Global;
+        setImmediate: (callback: (...args: any[]) => void, ...args: any[]) => any;
+        setInterval: (callback: (...args: any[]) => void, ms: number, ...args: any[]) => NodeJS.Timer;
+        setTimeout: (callback: (...args: any[]) => void, ms: number, ...args: any[]) => NodeJS.Timer;
+        undefined: typeof undefined;
+        unescape: (str: string) => string;
+        gc: () => void;
+        v8debug?: any;
+    }
+
+    export interface Timer {
+        ref() : void;
+        unref() : void;
+    }
+}
+
+/**
+ * @deprecated
+ */
+interface NodeBuffer extends Uint8Array {
+    write(string: string, offset?: number, length?: number, encoding?: string): number;
+    toString(encoding?: string, start?: number, end?: number): string;
+    toJSON(): any;
+    equals(otherBuffer: Buffer): boolean;
+    compare(otherBuffer: Buffer): number;
+    copy(targetBuffer: Buffer, targetStart?: number, sourceStart?: number, sourceEnd?: number): number;
+    slice(start?: number, end?: number): Buffer;
+    writeUIntLE(value: number, offset: number, byteLength: number, noAssert?: boolean): number;
+    writeUIntBE(value: number, offset: number, byteLength: number, noAssert?: boolean): number;
+    writeIntLE(value: number, offset: number, byteLength: number, noAssert?: boolean): number;
+    writeIntBE(value: number, offset: number, byteLength: number, noAssert?: boolean): number;
+    readUIntLE(offset: number, byteLength: number, noAssert?: boolean): number;
+    readUIntBE(offset: number, byteLength: number, noAssert?: boolean): number;
+    readIntLE(offset: number, byteLength: number, noAssert?: boolean): number;
+    readIntBE(offset: number, byteLength: number, noAssert?: boolean): number;
+    readUInt8(offset: number, noAssert?: boolean): number;
+    readUInt16LE(offset: number, noAssert?: boolean): number;
+    readUInt16BE(offset: number, noAssert?: boolean): number;
+    readUInt32LE(offset: number, noAssert?: boolean): number;
+    readUInt32BE(offset: number, noAssert?: boolean): number;
+    readInt8(offset: number, noAssert?: boolean): number;
+    readInt16LE(offset: number, noAssert?: boolean): number;
+    readInt16BE(offset: number, noAssert?: boolean): number;
+    readInt32LE(offset: number, noAssert?: boolean): number;
+    readInt32BE(offset: number, noAssert?: boolean): number;
+    readFloatLE(offset: number, noAssert?: boolean): number;
+    readFloatBE(offset: number, noAssert?: boolean): number;
+    readDoubleLE(offset: number, noAssert?: boolean): number;
+    readDoubleBE(offset: number, noAssert?: boolean): number;
+    writeUInt8(value: number, offset: number, noAssert?: boolean): number;
+    writeUInt16LE(value: number, offset: number, noAssert?: boolean): number;
+    writeUInt16BE(value: number, offset: number, noAssert?: boolean): number;
+    writeUInt32LE(value: number, offset: number, noAssert?: boolean): number;
+    writeUInt32BE(value: number, offset: number, noAssert?: boolean): number;
+    writeInt8(value: number, offset: number, noAssert?: boolean): number;
+    writeInt16LE(value: number, offset: number, noAssert?: boolean): number;
+    writeInt16BE(value: number, offset: number, noAssert?: boolean): number;
+    writeInt32LE(value: number, offset: number, noAssert?: boolean): number;
+    writeInt32BE(value: number, offset: number, noAssert?: boolean): number;
+    writeFloatLE(value: number, offset: number, noAssert?: boolean): number;
+    writeFloatBE(value: number, offset: number, noAssert?: boolean): number;
+    writeDoubleLE(value: number, offset: number, noAssert?: boolean): number;
+    writeDoubleBE(value: number, offset: number, noAssert?: boolean): number;
+    fill(value: any, offset?: number, end?: number): this;
+    // TODO: encoding param
+    indexOf(value: string | number | Buffer, byteOffset?: number): number;
+    // TODO: entries
+    // TODO: includes
+    // TODO: keys
+    // TODO: values
+}
+
+/************************************************
+*                                               *
+*                   MODULES                     *
+*                                               *
+************************************************/
+declare module "buffer" {
+    export var INSPECT_MAX_BYTES: number;
+    var BuffType: typeof Buffer;
+    var SlowBuffType: typeof SlowBuffer;
+    export { BuffType as Buffer, SlowBuffType as SlowBuffer };
+}
+
+declare module "querystring" {
+    export interface StringifyOptions {
+        encodeURIComponent?: Function;
+    }
+
+    export interface ParseOptions {
+        maxKeys?: number;
+        decodeURIComponent?: Function;
+    }
+
+    export function stringify<T>(obj: T, sep?: string, eq?: string, options?: StringifyOptions): string;
+    export function parse(str: string, sep?: string, eq?: string, options?: ParseOptions): any;
+    export function parse<T extends {}>(str: string, sep?: string, eq?: string, options?: ParseOptions): T;
+    export function escape(str: string): string;
+    export function unescape(str: string): string;
+}
+
+declare module "events" {
+    export class EventEmitter implements NodeJS.EventEmitter {
+        static EventEmitter: EventEmitter;
+        static listenerCount(emitter: EventEmitter, event: string): number; // deprecated
+        static defaultMaxListeners: number;
+
+        addListener(event: string, listener: Function): this;
+        on(event: string, listener: Function): this;
+        once(event: string, listener: Function): this;
+        prependListener(event: string, listener: Function): this;
+        prependOnceListener(event: string, listener: Function): this;
+        removeListener(event: string, listener: Function): this;
+        removeAllListeners(event?: string): this;
+        setMaxListeners(n: number): this;
+        getMaxListeners(): number;
+        listeners(event: string): Function[];
+        emit(event: string, ...args: any[]): boolean;
+        eventNames(): string[];
+        listenerCount(type: string): number;
+    }
+}
+
+declare module "http" {
+    import * as events from "events";
+    import * as net from "net";
+    import * as stream from "stream";
+
+    export interface RequestOptions {
+        protocol?: string;
+        host?: string;
+        hostname?: string;
+        family?: number;
+        port?: number;
+        localAddress?: string;
+        socketPath?: string;
+        method?: string;
+        path?: string;
+        headers?: { [key: string]: any };
+        auth?: string;
+        agent?: Agent|boolean;
+    }
+
+    export interface Server extends events.EventEmitter, net.Server {
+        setTimeout(msecs: number, callback: Function): void;
+        maxHeadersCount: number;
+        timeout: number;
+    }
+    /**
+     * @deprecated Use IncomingMessage
+     */
+    export interface ServerRequest extends IncomingMessage {
+        connection: net.Socket;
+    }
+    export interface ServerResponse extends events.EventEmitter, stream.Writable {
+        // Extended base methods
+        write(buffer: Buffer): boolean;
+        write(buffer: Buffer, cb?: Function): boolean;
+        write(str: string, cb?: Function): boolean;
+        write(str: string, encoding?: string, cb?: Function): boolean;
+        write(str: string, encoding?: string, fd?: string): boolean;
+
+        writeContinue(): void;
+        writeHead(statusCode: number, reasonPhrase?: string, headers?: any): void;
+        writeHead(statusCode: number, headers?: any): void;
+        statusCode: number;
+        statusMessage: string;
+        headersSent: boolean;
+        setHeader(name: string, value: string | string[]): void;
+        sendDate: boolean;
+        getHeader(name: string): string;
+        removeHeader(name: string): void;
+        write(chunk: any, encoding?: string): any;
+        addTrailers(headers: any): void;
+
+        // Extended base methods
+        end(): void;
+        end(buffer: Buffer, cb?: Function): void;
+        end(str: string, cb?: Function): void;
+        end(str: string, encoding?: string, cb?: Function): void;
+        end(data?: any, encoding?: string): void;
+    }
+    export interface ClientRequest extends events.EventEmitter, stream.Writable {
+        // Extended base methods
+        write(buffer: Buffer): boolean;
+        write(buffer: Buffer, cb?: Function): boolean;
+        write(str: string, cb?: Function): boolean;
+        write(str: string, encoding?: string, cb?: Function): boolean;
+        write(str: string, encoding?: string, fd?: string): boolean;
+
+        write(chunk: any, encoding?: string): void;
+        abort(): void;
+        setTimeout(timeout: number, callback?: Function): void;
+        setNoDelay(noDelay?: boolean): void;
+        setSocketKeepAlive(enable?: boolean, initialDelay?: number): void;
+
+        setHeader(name: string, value: string | string[]): void;
+        getHeader(name: string): string;
+        removeHeader(name: string): void;
+        addTrailers(headers: any): void;
+
+        // Extended base methods
+        end(): void;
+        end(buffer: Buffer, cb?: Function): void;
+        end(str: string, cb?: Function): void;
+        end(str: string, encoding?: string, cb?: Function): void;
+        end(data?: any, encoding?: string): void;
+    }
+    export interface IncomingMessage extends events.EventEmitter, stream.Readable {
+        httpVersion: string;
+        headers: any;
+        rawHeaders: string[];
+        trailers: any;
+        rawTrailers: any;
+        setTimeout(msecs: number, callback: Function): NodeJS.Timer;
+        /**
+         * Only valid for request obtained from http.Server.
+         */
+        method?: string;
+        /**
+         * Only valid for request obtained from http.Server.
+         */
+        url?: string;
+        /**
+         * Only valid for response obtained from http.ClientRequest.
+         */
+        statusCode?: number;
+        /**
+         * Only valid for response obtained from http.ClientRequest.
+         */
+        statusMessage?: string;
+        socket: net.Socket;
+    }
+    /**
+     * @deprecated Use IncomingMessage
+     */
+    export interface ClientResponse extends IncomingMessage { }
+
+    export interface AgentOptions {
+        /**
+         * Keep sockets around in a pool to be used by other requests in the future. Default = false
+         */
+        keepAlive?: boolean;
+        /**
+         * When using HTTP KeepAlive, how often to send TCP KeepAlive packets over sockets being kept alive. Default = 1000.
+         * Only relevant if keepAlive is set to true.
+         */
+        keepAliveMsecs?: number;
+        /**
+         * Maximum number of sockets to allow per host. Default for Node 0.10 is 5, default for Node 0.12 is Infinity
+         */
+        maxSockets?: number;
+        /**
+         * Maximum number of sockets to leave open in a free state. Only relevant if keepAlive is set to true. Default = 256.
+         */
+        maxFreeSockets?: number;
+    }
+
+    export class Agent {
+        maxSockets: number;
+        sockets: any;
+        requests: any;
+
+        constructor(opts?: AgentOptions);
+
+        /**
+         * Destroy any sockets that are currently in use by the agent.
+         * It is usually not necessary to do this. However, if you are using an agent with KeepAlive enabled,
+         * then it is best to explicitly shut down the agent when you know that it will no longer be used. Otherwise,
+         * sockets may hang open for quite a long time before the server terminates them.
+         */
+        destroy(): void;
+    }
+
+    export var METHODS: string[];
+
+    export var STATUS_CODES: {
+        [errorCode: number]: string;
+        [errorCode: string]: string;
+    };
+    export function createServer(requestListener?: (request: IncomingMessage, response: ServerResponse) =>void ): Server;
+    export function createClient(port?: number, host?: string): any;
+    export function request(options: RequestOptions, callback?: (res: IncomingMessage) => void): ClientRequest;
+    export function get(options: any, callback?: (res: IncomingMessage) => void): ClientRequest;
+    export var globalAgent: Agent;
+}
+
+declare module "cluster" {
+    import * as child from "child_process";
+    import * as events from "events";
+
+    export interface ClusterSettings {
+        exec?: string;
+        args?: string[];
+        silent?: boolean;
+    }
+
+    export interface Address {
+        address: string;
+        port: number;
+        addressType: string;
+    }
+
+    export class Worker extends events.EventEmitter {
+        id: string;
+        process: child.ChildProcess;
+        suicide: boolean;
+        send(message: any, sendHandle?: any): void;
+        kill(signal?: string): void;
+        destroy(signal?: string): void;
+        disconnect(): void;
+        isConnected(): boolean;
+        isDead(): boolean;
+    }
+
+    export var settings: ClusterSettings;
+    export var isMaster: boolean;
+    export var isWorker: boolean;
+    export function setupMaster(settings?: ClusterSettings): void;
+    export function fork(env?: any): Worker;
+    export function disconnect(callback?: Function): void;
+    export var worker: Worker;
+    export var workers: {
+        [index: string]: Worker
+    };
+
+    // Event emitter
+    export function addListener(event: string, listener: Function): void;
+    export function on(event: "disconnect", listener: (worker: Worker) => void): void;
+    export function on(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): void;
+    export function on(event: "fork", listener: (worker: Worker) => void): void;
+    export function on(event: "listening", listener: (worker: Worker, address: any) => void): void;
+    export function on(event: "message", listener: (worker: Worker, message: any) => void): void;
+    export function on(event: "online", listener: (worker: Worker) => void): void;
+    export function on(event: "setup", listener: (settings: any) => void): void;
+    export function on(event: string, listener: Function): any;
+    export function once(event: string, listener: Function): void;
+    export function removeListener(event: string, listener: Function): void;
+    export function removeAllListeners(event?: string): void;
+    export function setMaxListeners(n: number): void;
+    export function listeners(event: string): Function[];
+    export function emit(event: string, ...args: any[]): boolean;
+}
+
+declare module "zlib" {
+    import * as stream from "stream";
+    export interface ZlibOptions { chunkSize?: number; windowBits?: number; level?: number; memLevel?: number; strategy?: number; dictionary?: any; }
+
+    export interface Gzip extends stream.Transform { }
+    export interface Gunzip extends stream.Transform { }
+    export interface Deflate extends stream.Transform { }
+    export interface Inflate extends stream.Transform { }
+    export interface DeflateRaw extends stream.Transform { }
+    export interface InflateRaw extends stream.Transform { }
+    export interface Unzip extends stream.Transform { }
+
+    export function createGzip(options?: ZlibOptions): Gzip;
+    export function createGunzip(options?: ZlibOptions): Gunzip;
+    export function createDeflate(options?: ZlibOptions): Deflate;
+    export function createInflate(options?: ZlibOptions): Inflate;
+    export function createDeflateRaw(options?: ZlibOptions): DeflateRaw;
+    export function createInflateRaw(options?: ZlibOptions): InflateRaw;
+    export function createUnzip(options?: ZlibOptions): Unzip;
+
+    export function deflate(buf: Buffer, callback: (error: Error, result: any) =>void ): void;
+    export function deflateSync(buf: Buffer, options?: ZlibOptions): any;
+    export function deflateRaw(buf: Buffer, callback: (error: Error, result: any) =>void ): void;
+    export function deflateRawSync(buf: Buffer, options?: ZlibOptions): any;
+    export function gzip(buf: Buffer, callback: (error: Error, result: any) =>void ): void;
+    export function gzipSync(buf: Buffer, options?: ZlibOptions): any;
+    export function gunzip(buf: Buffer, callback: (error: Error, result: any) =>void ): void;
+    export function gunzipSync(buf: Buffer, options?: ZlibOptions): any;
+    export function inflate(buf: Buffer, callback: (error: Error, result: any) =>void ): void;
+    export function inflateSync(buf: Buffer, options?: ZlibOptions): any;
+    export function inflateRaw(buf: Buffer, callback: (error: Error, result: any) =>void ): void;
+    export function inflateRawSync(buf: Buffer, options?: ZlibOptions): any;
+    export function unzip(buf: Buffer, callback: (error: Error, result: any) =>void ): void;
+    export function unzipSync(buf: Buffer, options?: ZlibOptions): any;
+
+    // Constants
+    export var Z_NO_FLUSH: number;
+    export var Z_PARTIAL_FLUSH: number;
+    export var Z_SYNC_FLUSH: number;
+    export var Z_FULL_FLUSH: number;
+    export var Z_FINISH: number;
+    export var Z_BLOCK: number;
+    export var Z_TREES: number;
+    export var Z_OK: number;
+    export var Z_STREAM_END: number;
+    export var Z_NEED_DICT: number;
+    export var Z_ERRNO: number;
+    export var Z_STREAM_ERROR: number;
+    export var Z_DATA_ERROR: number;
+    export var Z_MEM_ERROR: number;
+    export var Z_BUF_ERROR: number;
+    export var Z_VERSION_ERROR: number;
+    export var Z_NO_COMPRESSION: number;
+    export var Z_BEST_SPEED: number;
+    export var Z_BEST_COMPRESSION: number;
+    export var Z_DEFAULT_COMPRESSION: number;
+    export var Z_FILTERED: number;
+    export var Z_HUFFMAN_ONLY: number;
+    export var Z_RLE: number;
+    export var Z_FIXED: number;
+    export var Z_DEFAULT_STRATEGY: number;
+    export var Z_BINARY: number;
+    export var Z_TEXT: number;
+    export var Z_ASCII: number;
+    export var Z_UNKNOWN: number;
+    export var Z_DEFLATED: number;
+    export var Z_NULL: number;
+}
+
+declare module "os" {
+    export interface CpuInfo {
+        model: string;
+        speed: number;
+        times: {
+            user: number;
+            nice: number;
+            sys: number;
+            idle: number;
+            irq: number;
+        };
+    }
+
+    export interface NetworkInterfaceInfo {
+        address: string;
+        netmask: string;
+        family: string;
+        mac: string;
+        internal: boolean;
+    }
+
+    export function tmpdir(): string;
+    export function homedir(): string;
+    export function endianness(): "BE" | "LE";
+    export function hostname(): string;
+    export function type(): string;
+    export function platform(): string;
+    export function arch(): string;
+    export function release(): string;
+    export function uptime(): number;
+    export function loadavg(): number[];
+    export function totalmem(): number;
+    export function freemem(): number;
+    export function cpus(): CpuInfo[];
+    export function networkInterfaces(): {[index: string]: NetworkInterfaceInfo[]};
+    export var EOL: string;
+}
+
+declare module "https" {
+    import * as tls from "tls";
+    import * as events from "events";
+    import * as http from "http";
+
+    export interface ServerOptions {
+        pfx?: any;
+        key?: any;
+        passphrase?: string;
+        cert?: any;
+        ca?: any;
+        crl?: any;
+        ciphers?: string;
+        honorCipherOrder?: boolean;
+        requestCert?: boolean;
+        rejectUnauthorized?: boolean;
+        NPNProtocols?: any;
+        SNICallback?: (servername: string) => any;
+    }
+
+    export interface RequestOptions extends http.RequestOptions {
+        pfx?: any;
+        key?: any;
+        passphrase?: string;
+        cert?: any;
+        ca?: any;
+        ciphers?: string;
+        rejectUnauthorized?: boolean;
+        secureProtocol?: string;
+    }
+
+    export interface Agent extends http.Agent { }
+
+    export interface AgentOptions extends http.AgentOptions {
+        maxCachedSessions?: number;
+    }
+
+    export var Agent: {
+        new (options?: AgentOptions): Agent;
+    };
+    export interface Server extends tls.Server { }
+    export function createServer(options: ServerOptions, requestListener?: Function): Server;
+    export function request(options: RequestOptions, callback?: (res: http.IncomingMessage) =>void ): http.ClientRequest;
+    export function get(options: RequestOptions, callback?: (res: http.IncomingMessage) =>void ): http.ClientRequest;
+    export var globalAgent: Agent;
+}
+
+declare module "punycode" {
+    export function decode(string: string): string;
+    export function encode(string: string): string;
+    export function toUnicode(domain: string): string;
+    export function toASCII(domain: string): string;
+    export var ucs2: ucs2;
+    interface ucs2 {
+        decode(string: string): number[];
+        encode(codePoints: number[]): string;
+    }
+    export var version: any;
+}
+
+declare module "repl" {
+    import * as stream from "stream";
+    import * as events from "events";
+
+    export interface ReplOptions {
+        prompt?: string;
+        input?: NodeJS.ReadableStream;
+        output?: NodeJS.WritableStream;
+        terminal?: boolean;
+        eval?: Function;
+        useColors?: boolean;
+        useGlobal?: boolean;
+        ignoreUndefined?: boolean;
+        writer?: Function;
+    }
+    export function start(options: ReplOptions): events.EventEmitter;
+}
+
+declare module "readline" {
+    import * as events from "events";
+    import * as stream from "stream";
+
+    export interface Key {
+        sequence?: string;
+        name?: string;
+        ctrl?: boolean;
+        meta?: boolean;
+        shift?: boolean;
+    }
+
+    export interface ReadLine extends events.EventEmitter {
+        setPrompt(prompt: string): void;
+        prompt(preserveCursor?: boolean): void;
+        question(query: string, callback: (answer: string) => void): void;
+        pause(): ReadLine;
+        resume(): ReadLine;
+        close(): void;
+        write(data: string|Buffer, key?: Key): void;
+    }
+
+    export interface Completer {
+        (line: string): CompleterResult;
+        (line: string, callback: (err: any, result: CompleterResult) => void): any;
+    }
+
+    export interface CompleterResult {
+        completions: string[];
+        line: string;
+    }
+
+    export interface ReadLineOptions {
+        input: NodeJS.ReadableStream;
+        output?: NodeJS.WritableStream;
+        completer?: Completer;
+        terminal?: boolean;
+        historySize?: number;
+    }
+
+    export function createInterface(input: NodeJS.ReadableStream, output?: NodeJS.WritableStream, completer?: Completer, terminal?: boolean): ReadLine;
+    export function createInterface(options: ReadLineOptions): ReadLine;
+
+    export function cursorTo(stream: NodeJS.WritableStream, x: number, y: number): void;
+    export function moveCursor(stream: NodeJS.WritableStream, dx: number|string, dy: number|string): void;
+    export function clearLine(stream: NodeJS.WritableStream, dir: number): void;
+    export function clearScreenDown(stream: NodeJS.WritableStream): void;
+}
+
+declare module "vm" {
+    export interface Context { }
+    export interface ScriptOptions {
+        filename?: string;
+        lineOffset?: number;
+        columnOffset?: number;
+        displayErrors?: boolean;
+        timeout?: number;
+        cachedData?: Buffer;
+        produceCachedData?: boolean;
+    }
+    export interface RunningScriptOptions {
+        filename?: string;
+        lineOffset?: number;
+        columnOffset?: number;
+        displayErrors?: boolean;
+        timeout?: number;
+    }
+    export class Script {
+        constructor(code: string, options?: ScriptOptions);
+        runInContext(contextifiedSandbox: Context, options?: RunningScriptOptions): any;
+        runInNewContext(sandbox?: Context, options?: RunningScriptOptions): any;
+        runInThisContext(options?: RunningScriptOptions): any;
+    }
+    export function createContext(sandbox?: Context): Context;
+    export function isContext(sandbox: Context): boolean;
+    export function runInContext(code: string, contextifiedSandbox: Context, options?: RunningScriptOptions): any;
+    export function runInDebugContext(code: string): any;
+    export function runInNewContext(code: string, sandbox?: Context, options?: RunningScriptOptions): any;
+    export function runInThisContext(code: string, options?: RunningScriptOptions): any;
+}
+
+declare module "child_process" {
+    import * as events from "events";
+    import * as stream from "stream";
+
+    export interface ChildProcess extends events.EventEmitter {
+        stdin:  stream.Writable;
+        stdout: stream.Readable;
+        stderr: stream.Readable;
+        stdio: [stream.Writable, stream.Readable, stream.Readable];
+        pid: number;
+        kill(signal?: string): void;
+        send(message: any, sendHandle?: any): void;
+        connected: boolean;
+        disconnect(): void;
+        unref(): void;
+    }
+
+    export interface SpawnOptions {
+        cwd?: string;
+        env?: any;
+        stdio?: any;
+        detached?: boolean;
+        uid?: number;
+        gid?: number;
+        shell?: boolean | string;
+    }
+    export function spawn(command: string, args?: string[], options?: SpawnOptions): ChildProcess;
+
+    export interface ExecOptions {
+        cwd?: string;
+        env?: any;
+        shell?: string;
+        timeout?: number;
+        maxBuffer?: number;
+        killSignal?: string;
+        uid?: number;
+        gid?: number;
+    }
+    export interface ExecOptionsWithStringEncoding extends ExecOptions {
+        encoding: BufferEncoding;
+    }
+    export interface ExecOptionsWithBufferEncoding extends ExecOptions {
+        encoding: string; // specify `null`.
+    }
+    export function exec(command: string, callback?: (error: Error, stdout: string, stderr: string) =>void ): ChildProcess;
+    export function exec(command: string, options: ExecOptionsWithStringEncoding, callback?: (error: Error, stdout: string, stderr: string) =>void ): ChildProcess;
+    // usage. child_process.exec("tsc", {encoding: null as string}, (err, stdout, stderr) => {});
+    export function exec(command: string, options: ExecOptionsWithBufferEncoding, callback?: (error: Error, stdout: Buffer, stderr: Buffer) =>void ): ChildProcess;
+    export function exec(command: string, options: ExecOptions, callback?: (error: Error, stdout: string, stderr: string) =>void ): ChildProcess;
+
+    export interface ExecFileOptions {
+        cwd?: string;
+        env?: any;
+        timeout?: number;
+        maxBuffer?: number;
+        killSignal?: string;
+        uid?: number;
+        gid?: number;
+    }
+    export interface ExecFileOptionsWithStringEncoding extends ExecFileOptions {
+        encoding: BufferEncoding;
+    }
+    export interface ExecFileOptionsWithBufferEncoding extends ExecFileOptions {
+        encoding: string; // specify `null`.
+    }
+    export function execFile(file: string, callback?: (error: Error, stdout: string, stderr: string) =>void ): ChildProcess;
+    export function execFile(file: string, options?: ExecFileOptionsWithStringEncoding, callback?: (error: Error, stdout: string, stderr: string) =>void ): ChildProcess;
+    // usage. child_process.execFile("file.sh", {encoding: null as string}, (err, stdout, stderr) => {});
+    export function execFile(file: string, options?: ExecFileOptionsWithBufferEncoding, callback?: (error: Error, stdout: Buffer, stderr: Buffer) =>void ): ChildProcess;
+    export function execFile(file: string, options?: ExecFileOptions, callback?: (error: Error, stdout: string, stderr: string) =>void ): ChildProcess;
+    export function execFile(file: string, args?: string[], callback?: (error: Error, stdout: string, stderr: string) =>void ): ChildProcess;
+    export function execFile(file: string, args?: string[], options?: ExecFileOptionsWithStringEncoding, callback?: (error: Error, stdout: string, stderr: string) =>void ): ChildProcess;
+    // usage. child_process.execFile("file.sh", ["foo"], {encoding: null as string}, (err, stdout, stderr) => {});
+    export function execFile(file: string, args?: string[], options?: ExecFileOptionsWithBufferEncoding, callback?: (error: Error, stdout: Buffer, stderr: Buffer) =>void ): ChildProcess;
+    export function execFile(file: string, args?: string[], options?: ExecFileOptions, callback?: (error: Error, stdout: string, stderr: string) =>void ): ChildProcess;
+
+    export interface ForkOptions {
+        cwd?: string;
+        env?: any;
+        execPath?: string;
+        execArgv?: string[];
+        silent?: boolean;
+        uid?: number;
+        gid?: number;
+    }
+    export function fork(modulePath: string, args?: string[], options?: ForkOptions): ChildProcess;
+
+    export interface SpawnSyncOptions {
+        cwd?: string;
+        input?: string | Buffer;
+        stdio?: any;
+        env?: any;
+        uid?: number;
+        gid?: number;
+        timeout?: number;
+        killSignal?: string;
+        maxBuffer?: number;
+        encoding?: string;
+        shell?: boolean | string;
+    }
+    export interface SpawnSyncOptionsWithStringEncoding extends SpawnSyncOptions {
+        encoding: BufferEncoding;
+    }
+    export interface SpawnSyncOptionsWithBufferEncoding extends SpawnSyncOptions {
+        encoding: string; // specify `null`.
+    }
+    export interface SpawnSyncReturns<T> {
+        pid: number;
+        output: string[];
+        stdout: T;
+        stderr: T;
+        status: number;
+        signal: string;
+        error: Error;
+    }
+    export function spawnSync(command: string): SpawnSyncReturns<Buffer>;
+    export function spawnSync(command: string, options?: SpawnSyncOptionsWithStringEncoding): SpawnSyncReturns<string>;
+    export function spawnSync(command: string, options?: SpawnSyncOptionsWithBufferEncoding): SpawnSyncReturns<Buffer>;
+    export function spawnSync(command: string, options?: SpawnSyncOptions): SpawnSyncReturns<Buffer>;
+    export function spawnSync(command: string, args?: string[], options?: SpawnSyncOptionsWithStringEncoding): SpawnSyncReturns<string>;
+    export function spawnSync(command: string, args?: string[], options?: SpawnSyncOptionsWithBufferEncoding): SpawnSyncReturns<Buffer>;
+    export function spawnSync(command: string, args?: string[], options?: SpawnSyncOptions): SpawnSyncReturns<Buffer>;
+
+    export interface ExecSyncOptions {
+        cwd?: string;
+        input?: string | Buffer;
+        stdio?: any;
+        env?: any;
+        shell?: string;
+        uid?: number;
+        gid?: number;
+        timeout?: number;
+        killSignal?: string;
+        maxBuffer?: number;
+        encoding?: string;
+    }
+    export interface ExecSyncOptionsWithStringEncoding extends ExecSyncOptions {
+        encoding: BufferEncoding;
+    }
+    export interface ExecSyncOptionsWithBufferEncoding extends ExecSyncOptions {
+        encoding: string; // specify `null`.
+    }
+    export function execSync(command: string): Buffer;
+    export function execSync(command: string, options?: ExecSyncOptionsWithStringEncoding): string;
+    export function execSync(command: string, options?: ExecSyncOptionsWithBufferEncoding): Buffer;
+    export function execSync(command: string, options?: ExecSyncOptions): Buffer;
+
+    export interface ExecFileSyncOptions {
+        cwd?: string;
+        input?: string | Buffer;
+        stdio?: any;
+        env?: any;
+        uid?: number;
+        gid?: number;
+        timeout?: number;
+        killSignal?: string;
+        maxBuffer?: number;
+        encoding?: string;
+    }
+    export interface ExecFileSyncOptionsWithStringEncoding extends ExecFileSyncOptions {
+        encoding: BufferEncoding;
+    }
+    export interface ExecFileSyncOptionsWithBufferEncoding extends ExecFileSyncOptions {
+        encoding: string; // specify `null`.
+    }
+    export function execFileSync(command: string): Buffer;
+    export function execFileSync(command: string, options?: ExecFileSyncOptionsWithStringEncoding): string;
+    export function execFileSync(command: string, options?: ExecFileSyncOptionsWithBufferEncoding): Buffer;
+    export function execFileSync(command: string, options?: ExecFileSyncOptions): Buffer;
+    export function execFileSync(command: string, args?: string[], options?: ExecFileSyncOptionsWithStringEncoding): string;
+    export function execFileSync(command: string, args?: string[], options?: ExecFileSyncOptionsWithBufferEncoding): Buffer;
+    export function execFileSync(command: string, args?: string[], options?: ExecFileSyncOptions): Buffer;
+}
+
+declare module "url" {
+    export interface Url {
+        href?: string;
+        protocol?: string;
+        auth?: string;
+        hostname?: string;
+        port?: string;
+        host?: string;
+        pathname?: string;
+        search?: string;
+        query?: string | any;
+        slashes?: boolean;
+        hash?: string;
+        path?: string;
+    }
+
+    export function parse(urlStr: string, parseQueryString?: boolean , slashesDenoteHost?: boolean ): Url;
+    export function format(url: Url): string;
+    export function resolve(from: string, to: string): string;
+}
+
+declare module "dns" {
+    export function lookup(domain: string, family: number, callback: (err: Error, address: string, family: number) =>void ): string;
+    export function lookup(domain: string, callback: (err: Error, address: string, family: number) =>void ): string;
+    export function resolve(domain: string, rrtype: string, callback: (err: Error, addresses: string[]) =>void ): string[];
+    export function resolve(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[];
+    export function resolve4(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[];
+    export function resolve6(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[];
+    export function resolveMx(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[];
+    export function resolveTxt(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[];
+    export function resolveSrv(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[];
+    export function resolveNs(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[];
+    export function resolveCname(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[];
+    export function reverse(ip: string, callback: (err: Error, domains: string[]) =>void ): string[];
+}
+
+declare module "net" {
+    import * as stream from "stream";
+
+    export interface Socket extends stream.Duplex {
+        // Extended base methods
+        write(buffer: Buffer): boolean;
+        write(buffer: Buffer, cb?: Function): boolean;
+        write(str: string, cb?: Function): boolean;
+        write(str: string, encoding?: string, cb?: Function): boolean;
+        write(str: string, encoding?: string, fd?: string): boolean;
+
+        connect(port: number, host?: string, connectionListener?: Function): void;
+        connect(path: string, connectionListener?: Function): void;
+        bufferSize: number;
+        setEncoding(encoding?: string): void;
+        write(data: any, encoding?: string, callback?: Function): void;
+        destroy(): void;
+        pause(): void;
+        resume(): void;
+        setTimeout(timeout: number, callback?: Function): void;
+        setNoDelay(noDelay?: boolean): void;
+        setKeepAlive(enable?: boolean, initialDelay?: number): void;
+        address(): { port: number; family: string; address: string; };
+        unref(): void;
+        ref(): void;
+
+        remoteAddress: string;
+        remoteFamily: string;
+        remotePort: number;
+        localAddress: string;
+        localPort: number;
+        bytesRead: number;
+        bytesWritten: number;
+
+        // Extended base methods
+        end(): void;
+        end(buffer: Buffer, cb?: Function): void;
+        end(str: string, cb?: Function): void;
+        end(str: string, encoding?: string, cb?: Function): void;
+        end(data?: any, encoding?: string): void;
+    }
+
+    export var Socket: {
+        new (options?: { fd?: string; type?: string; allowHalfOpen?: boolean; }): Socket;
+    };
+
+    export interface ListenOptions {
+        port?: number;
+        host?: string;
+        backlog?: number;
+        path?: string;
+        exclusive?: boolean;
+    }
+
+    export interface Server extends Socket {
+        listen(port: number, hostname?: string, backlog?: number, listeningListener?: Function): Server;
+        listen(port: number, hostname?: string, listeningListener?: Function): Server;
+        listen(port: number, backlog?: number, listeningListener?: Function): Server;
+        listen(port: number, listeningListener?: Function): Server;
+        listen(path: string, backlog?: number, listeningListener?: Function): Server;
+        listen(path: string, listeningListener?: Function): Server;
+        listen(handle: any, backlog?: number, listeningListener?: Function): Server;
+        listen(handle: any, listeningListener?: Function): Server;
+        listen(options: ListenOptions, listeningListener?: Function): Server;
+        close(callback?: Function): Server;
+        address(): { port: number; family: string; address: string; };
+        getConnections(cb: (error: Error, count: number) => void): void;
+        ref(): Server;
+        unref(): Server;
+        maxConnections: number;
+        connections: number;
+    }
+    export function createServer(connectionListener?: (socket: Socket) =>void ): Server;
+    export function createServer(options?: { allowHalfOpen?: boolean; }, connectionListener?: (socket: Socket) =>void ): Server;
+    export function connect(options: { port: number, host?: string, localAddress? : string, localPort? : string, family? : number, allowHalfOpen?: boolean; }, connectionListener?: Function): Socket;
+    export function connect(port: number, host?: string, connectionListener?: Function): Socket;
+    export function connect(path: string, connectionListener?: Function): Socket;
+    export function createConnection(options: { port: number, host?: string, localAddress? : string, localPort? : string, family? : number, allowHalfOpen?: boolean; }, connectionListener?: Function): Socket;
+    export function createConnection(port: number, host?: string, connectionListener?: Function): Socket;
+    export function createConnection(path: string, connectionListener?: Function): Socket;
+    export function isIP(input: string): number;
+    export function isIPv4(input: string): boolean;
+    export function isIPv6(input: string): boolean;
+}
+
+declare module "dgram" {
+    import * as events from "events";
+
+    interface RemoteInfo {
+        address: string;
+        port: number;
+        size: number;
+    }
+
+    interface AddressInfo {
+        address: string;
+        family: string;
+        port: number;
+    }
+
+    export function createSocket(type: string, callback?: (msg: Buffer, rinfo: RemoteInfo) => void): Socket;
+
+    interface Socket extends events.EventEmitter {
+        send(buf: Buffer, offset: number, length: number, port: number, address: string, callback?: (error: Error, bytes: number) => void): void;
+        bind(port: number, address?: string, callback?: () => void): void;
+        close(): void;
+        address(): AddressInfo;
+        setBroadcast(flag: boolean): void;
+        setMulticastTTL(ttl: number): void;
+        setMulticastLoopback(flag: boolean): void;
+        addMembership(multicastAddress: string, multicastInterface?: string): void;
+        dropMembership(multicastAddress: string, multicastInterface?: string): void;
+    }
+}
+
+declare module "fs" {
+    import * as stream from "stream";
+    import * as events from "events";
+
+    interface Stats {
+        isFile(): boolean;
+        isDirectory(): boolean;
+        isBlockDevice(): boolean;
+        isCharacterDevice(): boolean;
+        isSymbolicLink(): boolean;
+        isFIFO(): boolean;
+        isSocket(): boolean;
+        dev: number;
+        ino: number;
+        mode: number;
+        nlink: number;
+        uid: number;
+        gid: number;
+        rdev: number;
+        size: number;
+        blksize: number;
+        blocks: number;
+        atime: Date;
+        mtime: Date;
+        ctime: Date;
+        birthtime: Date;
+    }
+
+    interface FSWatcher extends events.EventEmitter {
+        close(): void;
+    }
+
+    export interface ReadStream extends stream.Readable {
+        close(): void;
+        destroy(): void;
+    }
+    export interface WriteStream extends stream.Writable {
+        close(): void;
+        bytesWritten: number;
+    }
+
+    /**
+     * Asynchronous rename.
+     * @param oldPath
+     * @param newPath
+     * @param callback No arguments other than a possible exception are given to the completion callback.
+     */
+    export function rename(oldPath: string, newPath: string, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    /**
+     * Synchronous rename
+     * @param oldPath
+     * @param newPath
+     */
+    export function renameSync(oldPath: string, newPath: string): void;
+    export function truncate(path: string | Buffer, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function truncate(path: string | Buffer, len: number, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function truncateSync(path: string | Buffer, len?: number): void;
+    export function ftruncate(fd: number, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function ftruncate(fd: number, len: number, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function ftruncateSync(fd: number, len?: number): void;
+    export function chown(path: string | Buffer, uid: number, gid: number, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function chownSync(path: string | Buffer, uid: number, gid: number): void;
+    export function fchown(fd: number, uid: number, gid: number, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function fchownSync(fd: number, uid: number, gid: number): void;
+    export function lchown(path: string | Buffer, uid: number, gid: number, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function lchownSync(path: string | Buffer, uid: number, gid: number): void;
+    export function chmod(path: string | Buffer, mode: number, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function chmod(path: string | Buffer, mode: string, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function chmodSync(path: string | Buffer, mode: number): void;
+    export function chmodSync(path: string | Buffer, mode: string): void;
+    export function fchmod(fd: number, mode: number, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function fchmod(fd: number, mode: string, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function fchmodSync(fd: number, mode: number): void;
+    export function fchmodSync(fd: number, mode: string): void;
+    export function lchmod(path: string | Buffer, mode: number, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function lchmod(path: string | Buffer, mode: string, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function lchmodSync(path: string | Buffer, mode: number): void;
+    export function lchmodSync(path: string | Buffer, mode: string): void;
+    export function stat(path: string | Buffer, callback?: (err: NodeJS.ErrnoException, stats: Stats) => any): void;
+    export function lstat(path: string | Buffer, callback?: (err: NodeJS.ErrnoException, stats: Stats) => any): void;
+    export function fstat(fd: number, callback?: (err: NodeJS.ErrnoException, stats: Stats) => any): void;
+    export function statSync(path: string | Buffer): Stats;
+    export function lstatSync(path: string | Buffer): Stats;
+    export function fstatSync(fd: number): Stats;
+    export function link(srcpath: string | Buffer, dstpath: string | Buffer, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function linkSync(srcpath: string | Buffer, dstpath: string | Buffer): void;
+    export function symlink(srcpath: string | Buffer, dstpath: string | Buffer, type?: string, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function symlinkSync(srcpath: string | Buffer, dstpath: string | Buffer, type?: string): void;
+    export function readlink(path: string | Buffer, callback?: (err: NodeJS.ErrnoException, linkString: string) => any): void;
+    export function readlinkSync(path: string | Buffer): string;
+    export function realpath(path: string | Buffer, callback?: (err: NodeJS.ErrnoException, resolvedPath: string) => any): void;
+    export function realpath(path: string | Buffer, cache: {[path: string]: string}, callback: (err: NodeJS.ErrnoException, resolvedPath: string) => any): void;
+    export function realpathSync(path: string | Buffer, cache?: { [path: string]: string }): string;
+    /*
+     * Asynchronous unlink - deletes the file specified in {path}
+     *
+     * @param path
+     * @param callback No arguments other than a possible exception are given to the completion callback.
+     */
+    export function unlink(path: string | Buffer, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    /*
+     * Synchronous unlink - deletes the file specified in {path}
+     *
+     * @param path
+     */
+    export function unlinkSync(path: string | Buffer): void;
+    /*
+     * Asynchronous rmdir - removes the directory specified in {path}
+     *
+     * @param path
+     * @param callback No arguments other than a possible exception are given to the completion callback.
+     */
+    export function rmdir(path: string | Buffer, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    /*
+     * Synchronous rmdir - removes the directory specified in {path}
+     *
+     * @param path
+     */
+    export function rmdirSync(path: string | Buffer): void;
+    /*
+     * Asynchronous mkdir - creates the directory specified in {path}.  Parameter {mode} defaults to 0777.
+     *
+     * @param path
+     * @param callback No arguments other than a possible exception are given to the completion callback.
+     */
+    export function mkdir(path: string | Buffer, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    /*
+     * Asynchronous mkdir - creates the directory specified in {path}.  Parameter {mode} defaults to 0777.
+     *
+     * @param path
+     * @param mode
+     * @param callback No arguments other than a possible exception are given to the completion callback.
+     */
+    export function mkdir(path: string | Buffer, mode: number, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    /*
+     * Asynchronous mkdir - creates the directory specified in {path}.  Parameter {mode} defaults to 0777.
+     *
+     * @param path
+     * @param mode
+     * @param callback No arguments other than a possible exception are given to the completion callback.
+     */
+    export function mkdir(path: string | Buffer, mode: string, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    /*
+     * Synchronous mkdir - creates the directory specified in {path}.  Parameter {mode} defaults to 0777.
+     *
+     * @param path
+     * @param mode
+     * @param callback No arguments other than a possible exception are given to the completion callback.
+     */
+    export function mkdirSync(path: string | Buffer, mode?: number): void;
+    /*
+     * Synchronous mkdir - creates the directory specified in {path}.  Parameter {mode} defaults to 0777.
+     *
+     * @param path
+     * @param mode
+     * @param callback No arguments other than a possible exception are given to the completion callback.
+     */
+    export function mkdirSync(path: string | Buffer, mode?: string): void;
+    /*
+     * Asynchronous mkdtemp - Creates a unique temporary directory. Generates six random characters to be appended behind a required prefix to create a unique temporary directory.
+     *
+     * @param prefix
+     * @param callback The created folder path is passed as a string to the callback's second parameter.
+     */
+    export function mkdtemp(prefix: string, callback?: (err: NodeJS.ErrnoException, folder: string) => void): void;
+    /*
+     * Synchronous mkdtemp - Creates a unique temporary directory. Generates six random characters to be appended behind a required prefix to create a unique temporary directory.
+     *
+     * @param prefix
+     * @returns Returns the created folder path.
+     */
+    export function mkdtempSync(prefix: string): string;
+    export function readdir(path: string | Buffer, callback?: (err: NodeJS.ErrnoException, files: string[]) => void): void;
+    export function readdirSync(path: string | Buffer): string[];
+    export function close(fd: number, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function closeSync(fd: number): void;
+    export function open(path: string | Buffer, flags: string | number, callback: (err: NodeJS.ErrnoException, fd: number) => void): void;
+    export function open(path: string | Buffer, flags: string | number, mode: number, callback: (err: NodeJS.ErrnoException, fd: number) => void): void;
+    export function openSync(path: string | Buffer, flags: string | number, mode?: number): number;
+    export function utimes(path: string | Buffer, atime: number, mtime: number, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function utimes(path: string | Buffer, atime: Date, mtime: Date, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function utimesSync(path: string | Buffer, atime: number, mtime: number): void;
+    export function utimesSync(path: string | Buffer, atime: Date, mtime: Date): void;
+    export function futimes(fd: number, atime: number, mtime: number, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function futimes(fd: number, atime: Date, mtime: Date, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function futimesSync(fd: number, atime: number, mtime: number): void;
+    export function futimesSync(fd: number, atime: Date, mtime: Date): void;
+    export function fsync(fd: number, callback?: (err?: NodeJS.ErrnoException) => void): void;
+    export function fsyncSync(fd: number): void;
+    export function write(fd: number, buffer: Buffer, offset: number, length: number, position: number, callback?: (err: NodeJS.ErrnoException, written: number, buffer: Buffer) => void): void;
+    export function write(fd: number, buffer: Buffer, offset: number, length: number, callback?: (err: NodeJS.ErrnoException, written: number, buffer: Buffer) => void): void;
+    export function write(fd: number, data: any, callback?: (err: NodeJS.ErrnoException, written: number, str: string) => void): void;
+    export function write(fd: number, data: any, offset: number, callback?: (err: NodeJS.ErrnoException, written: number, str: string) => void): void;
+    export function write(fd: number, data: any, offset: number, encoding: string, callback?: (err: NodeJS.ErrnoException, written: number, str: string) => void): void;
+    export function writeSync(fd: number, buffer: Buffer, offset: number, length: number, position?: number): number;
+    export function writeSync(fd: number, data: any, position?: number, enconding?: string): number;
+    export function read(fd: number, buffer: Buffer, offset: number, length: number, position: number, callback?: (err: NodeJS.ErrnoException, bytesRead: number, buffer: Buffer) => void): void;
+    export function readSync(fd: number, buffer: Buffer, offset: number, length: number, position: number): number;
+    /*
+     * Asynchronous readFile - Asynchronously reads the entire contents of a file.
+     *
+     * @param fileName
+     * @param encoding
+     * @param callback - The callback is passed two arguments (err, data), where data is the contents of the file.
+     */
+    export function readFile(filename: string, encoding: string, callback: (err: NodeJS.ErrnoException, data: string) => void): void;
+    /*
+     * Asynchronous readFile - Asynchronously reads the entire contents of a file.
+     *
+     * @param fileName
+     * @param options An object with optional {encoding} and {flag} properties.  If {encoding} is specified, readFile returns a string; otherwise it returns a Buffer.
+     * @param callback - The callback is passed two arguments (err, data), where data is the contents of the file.
+     */
+    export function readFile(filename: string, options: { encoding: string; flag?: string; }, callback: (err: NodeJS.ErrnoException, data: string) => void): void;
+    /*
+     * Asynchronous readFile - Asynchronously reads the entire contents of a file.
+     *
+     * @param fileName
+     * @param options An object with optional {encoding} and {flag} properties.  If {encoding} is specified, readFile returns a string; otherwise it returns a Buffer.
+     * @param callback - The callback is passed two arguments (err, data), where data is the contents of the file.
+     */
+    export function readFile(filename: string, options: { flag?: string; }, callback: (err: NodeJS.ErrnoException, data: Buffer) => void): void;
+    /*
+     * Asynchronous readFile - Asynchronously reads the entire contents of a file.
+     *
+     * @param fileName
+     * @param callback - The callback is passed two arguments (err, data), where data is the contents of the file.
+     */
+    export function readFile(filename: string, callback: (err: NodeJS.ErrnoException, data: Buffer) => void): void;
+    /*
+     * Synchronous readFile - Synchronously reads the entire contents of a file.
+     *
+     * @param fileName
+     * @param encoding
+     */
+    export function readFileSync(filename: string, encoding: string): string;
+    /*
+     * Synchronous readFile - Synchronously reads the entire contents of a file.
+     *
+     * @param fileName
+     * @param options An object with optional {encoding} and {flag} properties.  If {encoding} is specified, readFileSync returns a string; otherwise it returns a Buffer.
+     */
+    export function readFileSync(filename: string, options: { encoding: string; flag?: string; }): string;
+    /*
+     * Synchronous readFile - Synchronously reads the entire contents of a file.
+     *
+     * @param fileName
+     * @param options An object with optional {encoding} and {flag} properties.  If {encoding} is specified, readFileSync returns a string; otherwise it returns a Buffer.
+     */
+    export function readFileSync(filename: string, options?: { flag?: string; }): Buffer;
+    export function writeFile(filename: string, data: any, callback?: (err: NodeJS.ErrnoException) => void): void;
+    export function writeFile(filename: string, data: any, options: { encoding?: string; mode?: number; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void;
+    export function writeFile(filename: string, data: any, options: { encoding?: string; mode?: string; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void;
+    export function writeFileSync(filename: string, data: any, options?: { encoding?: string; mode?: number; flag?: string; }): void;
+    export function writeFileSync(filename: string, data: any, options?: { encoding?: string; mode?: string; flag?: string; }): void;
+    export function appendFile(filename: string, data: any, options: { encoding?: string; mode?: number; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void;
+    export function appendFile(filename: string, data: any, options: { encoding?: string; mode?: string; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void;
+    export function appendFile(filename: string, data: any, callback?: (err: NodeJS.ErrnoException) => void): void;
+    export function appendFileSync(filename: string, data: any, options?: { encoding?: string; mode?: number; flag?: string; }): void;
+    export function appendFileSync(filename: string, data: any, options?: { encoding?: string; mode?: string; flag?: string; }): void;
+    export function watchFile(filename: string, listener: (curr: Stats, prev: Stats) => void): void;
+    export function watchFile(filename: string, options: { persistent?: boolean; interval?: number; }, listener: (curr: Stats, prev: Stats) => void): void;
+    export function unwatchFile(filename: string, listener?: (curr: Stats, prev: Stats) => void): void;
+    export function watch(filename: string, listener?: (event: string, filename: string) => any): FSWatcher;
+    export function watch(filename: string, encoding: string, listener?: (event: string, filename: string) => any): FSWatcher;
+    export function watch(filename: string, options: { persistent?: boolean; recursive?: boolean; encoding?: string }, listener?: (event: string, filename: string) => any): FSWatcher;
+    export function exists(path: string | Buffer, callback?: (exists: boolean) => void): void;
+    export function existsSync(path: string | Buffer): boolean;
+    /** Constant for fs.access(). File is visible to the calling process. */
+    export var F_OK: number;
+    /** Constant for fs.access(). File can be read by the calling process. */
+    export var R_OK: number;
+    /** Constant for fs.access(). File can be written by the calling process. */
+    export var W_OK: number;
+    /** Constant for fs.access(). File can be executed by the calling process. */
+    export var X_OK: number;
+    /** Tests a user's permissions for the file specified by path. */
+    export function access(path: string | Buffer, callback: (err: NodeJS.ErrnoException) => void): void;
+    export function access(path: string | Buffer, mode: number, callback: (err: NodeJS.ErrnoException) => void): void;
+    /** Synchronous version of fs.access. This throws if any accessibility checks fail, and does nothing otherwise. */
+    export function accessSync(path: string | Buffer, mode ?: number): void;
+    export function createReadStream(path: string | Buffer, options?: {
+        flags?: string;
+        encoding?: string;
+        fd?: number;
+        mode?: number;
+        autoClose?: boolean;
+        start?: number;
+        end?: number;
+    }): ReadStream;
+    export function createWriteStream(path: string | Buffer, options?: {
+        flags?: string;
+        encoding?: string;
+        fd?: number;
+        mode?: number;
+    }): WriteStream;
+}
+
+declare module "path" {
+
+    /**
+     * A parsed path object generated by path.parse() or consumed by path.format().
+     */
+    export interface ParsedPath {
+        /**
+         * The root of the path such as '/' or 'c:\'
+         */
+        root: string;
+        /**
+         * The full directory path such as '/home/user/dir' or 'c:\path\dir'
+         */
+        dir: string;
+        /**
+         * The file name including extension (if any) such as 'index.html'
+         */
+        base: string;
+        /**
+         * The file extension (if any) such as '.html'
+         */
+        ext: string;
+        /**
+         * The file name without extension (if any) such as 'index'
+         */
+        name: string;
+    }
+
+    /**
+     * Normalize a string path, reducing '..' and '.' parts.
+     * When multiple slashes are found, they're replaced by a single one; when the path contains a trailing slash, it is preserved. On Windows backslashes are used.
+     *
+     * @param p string path to normalize.
+     */
+    export function normalize(p: string): string;
+    /**
+     * Join all arguments together and normalize the resulting path.
+     * Arguments must be strings. In v0.8, non-string arguments were silently ignored. In v0.10 and up, an exception is thrown.
+     *
+     * @param paths string paths to join.
+     */
+    export function join(...paths: any[]): string;
+    /**
+     * Join all arguments together and normalize the resulting path.
+     * Arguments must be strings. In v0.8, non-string arguments were silently ignored. In v0.10 and up, an exception is thrown.
+     *
+     * @param paths string paths to join.
+     */
+    export function join(...paths: string[]): string;
+    /**
+     * The right-most parameter is considered {to}.  Other parameters are considered an array of {from}.
+     *
+     * Starting from leftmost {from} paramter, resolves {to} to an absolute path.
+     *
+     * If {to} isn't already absolute, {from} arguments are prepended in right to left order, until an absolute path is found. If after using all {from} paths still no absolute path is found, the current working directory is used as well. The resulting path is normalized, and trailing slashes are removed unless the path gets resolved to the root directory.
+     *
+     * @param pathSegments string paths to join.  Non-string arguments are ignored.
+     */
+    export function resolve(...pathSegments: any[]): string;
+    /**
+     * Determines whether {path} is an absolute path. An absolute path will always resolve to the same location, regardless of the working directory.
+     *
+     * @param path path to test.
+     */
+    export function isAbsolute(path: string): boolean;
+    /**
+     * Solve the relative path from {from} to {to}.
+     * At times we have two absolute paths, and we need to derive the relative path from one to the other. This is actually the reverse transform of path.resolve.
+     *
+     * @param from
+     * @param to
+     */
+    export function relative(from: string, to: string): string;
+    /**
+     * Return the directory name of a path. Similar to the Unix dirname command.
+     *
+     * @param p the path to evaluate.
+     */
+    export function dirname(p: string): string;
+    /**
+     * Return the last portion of a path. Similar to the Unix basename command.
+     * Often used to extract the file name from a fully qualified path.
+     *
+     * @param p the path to evaluate.
+     * @param ext optionally, an extension to remove from the result.
+     */
+    export function basename(p: string, ext?: string): string;
+    /**
+     * Return the extension of the path, from the last '.' to end of string in the last portion of the path.
+     * If there is no '.' in the last portion of the path or the first character of it is '.', then it returns an empty string
+     *
+     * @param p the path to evaluate.
+     */
+    export function extname(p: string): string;
+    /**
+     * The platform-specific file separator. '\\' or '/'.
+     */
+    export var sep: string;
+    /**
+     * The platform-specific file delimiter. ';' or ':'.
+     */
+    export var delimiter: string;
+    /**
+     * Returns an object from a path string - the opposite of format().
+     *
+     * @param pathString path to evaluate.
+     */
+    export function parse(pathString: string): ParsedPath;
+    /**
+     * Returns a path string from an object - the opposite of parse().
+     *
+     * @param pathString path to evaluate.
+     */
+    export function format(pathObject: ParsedPath): string;
+
+    export module posix {
+      export function normalize(p: string): string;
+      export function join(...paths: any[]): string;
+      export function resolve(...pathSegments: any[]): string;
+      export function isAbsolute(p: string): boolean;
+      export function relative(from: string, to: string): string;
+      export function dirname(p: string): string;
+      export function basename(p: string, ext?: string): string;
+      export function extname(p: string): string;
+      export var sep: string;
+      export var delimiter: string;
+      export function parse(p: string): ParsedPath;
+      export function format(pP: ParsedPath): string;
+    }
+
+    export module win32 {
+      export function normalize(p: string): string;
+      export function join(...paths: any[]): string;
+      export function resolve(...pathSegments: any[]): string;
+      export function isAbsolute(p: string): boolean;
+      export function relative(from: string, to: string): string;
+      export function dirname(p: string): string;
+      export function basename(p: string, ext?: string): string;
+      export function extname(p: string): string;
+      export var sep: string;
+      export var delimiter: string;
+      export function parse(p: string): ParsedPath;
+      export function format(pP: ParsedPath): string;
+    }
+}
+
+declare module "string_decoder" {
+    export interface NodeStringDecoder {
+        write(buffer: Buffer): string;
+        detectIncompleteChar(buffer: Buffer): number;
+    }
+    export var StringDecoder: {
+        new (encoding: string): NodeStringDecoder;
+    };
+}
+
+declare module "tls" {
+    import * as crypto from "crypto";
+    import * as net from "net";
+    import * as stream from "stream";
+
+    var CLIENT_RENEG_LIMIT: number;
+    var CLIENT_RENEG_WINDOW: number;
+    
+    export interface Certificate {
+        /**
+         * Country code.
+         */
+        C: string;
+        /**
+         * Street.
+         */
+        ST: string;
+        /**
+         * Locality.
+         */
+        L: string;
+        /**
+         * Organization.
+         */
+        O: string;
+        /**
+         * Organizational unit.
+         */
+        OU: string;
+        /**
+         * Common name.
+         */
+        CN: string;
+    }
+
+    export interface CipherNameAndProtocol {
+        /**
+         * The cipher name.
+         */
+        name: string;
+        /**
+         * SSL/TLS protocol version.
+         */
+        version: string;
+    }
+
+    export class TLSSocket extends stream.Duplex {
+        /**
+         * Returns the bound address, the address family name and port of the underlying socket as reported by
+         * the operating system. 
+         * @returns {any} - An object with three properties, e.g. { port: 12346, family: 'IPv4', address: '127.0.0.1' }.
+         */
+        address(): { port: number; family: string; address: string };
+        /**
+         * A boolean that is true if the peer certificate was signed by one of the specified CAs, otherwise false.
+         */
+        authorized: boolean;
+        /**
+         * The reason why the peer's certificate has not been verified.
+         * This property becomes available only when tlsSocket.authorized === false.
+         */
+        authorizationError: Error;
+        /**
+         * Static boolean value, always true.
+         * May be used to distinguish TLS sockets from regular ones.
+         */
+        encrypted: boolean;
+        /**
+         * Returns an object representing the cipher name and the SSL/TLS protocol version of the current connection.
+         * @returns {CipherNameAndProtocol} - Returns an object representing the cipher name
+         * and the SSL/TLS protocol version of the current connection.
+         */
+        getCipher(): CipherNameAndProtocol;
+        /**
+         * Returns an object representing the peer's certificate.
+         * The returned object has some properties corresponding to the field of the certificate.
+         * If detailed argument is true the full chain with issuer property will be returned,
+         * if false only the top certificate without issuer property.
+         * If the peer does not provide a certificate, it returns null or an empty object.
+         * @param {boolean} detailed - If true; the full chain with issuer property will be returned.
+         * @returns {any} - An object representing the peer's certificate.
+         */
+        getPeerCertificate(detailed?: boolean): {
+            subject: Certificate;
+            issuerInfo: Certificate;
+            issuer: Certificate;
+            raw: any;
+            valid_from: string;
+            valid_to: string;
+            fingerprint: string;
+            serialNumber: string;
+        };
+        /**
+         * Could be used to speed up handshake establishment when reconnecting to the server.
+         * @returns {any} - ASN.1 encoded TLS session or undefined if none was negotiated.
+         */
+        getSession(): any;
+        /**
+         * NOTE: Works only with client TLS sockets.
+         * Useful only for debugging, for session reuse provide session option to tls.connect().
+         * @returns {any} - TLS session ticket or undefined if none was negotiated.
+         */
+        getTLSTicket(): any;
+        /**
+         * The string representation of the local IP address.
+         */
+        localAddress: string;
+        /**
+         * The numeric representation of the local port.
+         */
+        localPort: string;
+        /**
+         * The string representation of the remote IP address.
+         * For example, '74.125.127.100' or '2001:4860:a005::68'.
+         */
+        remoteAddress: string;
+        /**
+         * The string representation of the remote IP family. 'IPv4' or 'IPv6'.
+         */
+        remoteFamily: string;
+        /**
+         * The numeric representation of the remote port. For example, 443.
+         */
+        remotePort: number;
+        /**
+         * Initiate TLS renegotiation process.
+         *  
+         * NOTE: Can be used to request peer's certificate after the secure connection has been established.
+         * ANOTHER NOTE: When running as the server, socket will be destroyed with an error after handshakeTimeout timeout.
+         * @param {TlsOptions} options - The options may contain the following fields: rejectUnauthorized,
+         * requestCert (See tls.createServer() for details).
+         * @param {Function} callback - callback(err) will be executed with null as err, once the renegotiation
+         * is successfully completed.
+         */
+        renegotiate(options: TlsOptions, callback: (err: Error) => any): any;
+        /**
+         * Set maximum TLS fragment size (default and maximum value is: 16384, minimum is: 512).
+         * Smaller fragment size decreases buffering latency on the client: large fragments are buffered by
+         * the TLS layer until the entire fragment is received and its integrity is verified;
+         * large fragments can span multiple roundtrips, and their processing can be delayed due to packet
+         * loss or reordering. However, smaller fragments add extra TLS framing bytes and CPU overhead,
+         * which may decrease overall server throughput.
+         * @param {number} size - TLS fragment size (default and maximum value is: 16384, minimum is: 512).
+         * @returns {boolean} - Returns true on success, false otherwise.
+         */
+        setMaxSendFragment(size: number): boolean;
+    }
+    
+    export interface TlsOptions {
+        host?: string;
+        port?: number;
+        pfx?: any;   //string or buffer
+        key?: any;   //string or buffer
+        passphrase?: string;
+        cert?: any;
+        ca?: any;    //string or buffer
+        crl?: any;   //string or string array
+        ciphers?: string;
+        honorCipherOrder?: any;
+        requestCert?: boolean;
+        rejectUnauthorized?: boolean;
+        NPNProtocols?: any;  //array or Buffer;
+        SNICallback?: (servername: string) => any;
+    }
+
+    export interface ConnectionOptions {
+        host?: string;
+        port?: number;
+        socket?: net.Socket;
+        pfx?: string | Buffer
+        key?: string | Buffer
+        passphrase?: string;
+        cert?: string | Buffer
+        ca?: (string | Buffer)[];
+        rejectUnauthorized?: boolean;
+        NPNProtocols?: (string | Buffer)[];
+        servername?: string;
+    }
+
+    export interface Server extends net.Server {
+        close(): Server;
+        address(): { port: number; family: string; address: string; };
+        addContext(hostName: string, credentials: {
+            key: string;
+            cert: string;
+            ca: string;
+        }): void;
+        maxConnections: number;
+        connections: number;
+    }
+
+    export interface ClearTextStream extends stream.Duplex {
+        authorized: boolean;
+        authorizationError: Error;
+        getPeerCertificate(): any;
+        getCipher: {
+            name: string;
+            version: string;
+        };
+        address: {
+            port: number;
+            family: string;
+            address: string;
+        };
+        remoteAddress: string;
+        remotePort: number;
+    }
+
+    export interface SecurePair {
+        encrypted: any;
+        cleartext: any;
+    }
+
+    export interface SecureContextOptions {
+        pfx?: string | Buffer;
+        key?: string | Buffer;
+        passphrase?: string;
+        cert?: string | Buffer;
+        ca?: string | Buffer;
+        crl?: string | string[]
+        ciphers?: string;
+        honorCipherOrder?: boolean;
+    }
+
+    export interface SecureContext {
+        context: any;
+    }
+
+    export function createServer(options: TlsOptions, secureConnectionListener?: (cleartextStream: ClearTextStream) =>void ): Server;
+    export function connect(options: TlsOptions, secureConnectionListener?: () =>void ): ClearTextStream;
+    export function connect(port: number, host?: string, options?: ConnectionOptions, secureConnectListener?: () =>void ): ClearTextStream;
+    export function connect(port: number, options?: ConnectionOptions, secureConnectListener?: () =>void ): ClearTextStream;
+    export function createSecurePair(credentials?: crypto.Credentials, isServer?: boolean, requestCert?: boolean, rejectUnauthorized?: boolean): SecurePair;
+    export function createSecureContext(details: SecureContextOptions): SecureContext;
+}
+
+declare module "crypto" {
+    export interface CredentialDetails {
+        pfx: string;
+        key: string;
+        passphrase: string;
+        cert: string;
+        ca: string | string[];
+        crl: string | string[];
+        ciphers: string;
+    }
+    export interface Credentials { context?: any; }
+    export function createCredentials(details: CredentialDetails): Credentials;
+    export function createHash(algorithm: string): Hash;
+    export function createHmac(algorithm: string, key: string): Hmac;
+    export function createHmac(algorithm: string, key: Buffer): Hmac;
+    export interface Hash {
+        update(data: any, input_encoding?: string): Hash;
+        digest(encoding: 'buffer'): Buffer;
+        digest(encoding: string): any;
+        digest(): Buffer;
+    }
+    export interface Hmac extends NodeJS.ReadWriteStream {
+        update(data: any, input_encoding?: string): Hmac;
+        digest(encoding: 'buffer'): Buffer;
+        digest(encoding: string): any;
+        digest(): Buffer;
+    }
+    export function createCipher(algorithm: string, password: any): Cipher;
+    export function createCipheriv(algorithm: string, key: any, iv: any): Cipher;
+    export interface Cipher extends NodeJS.ReadWriteStream {
+        update(data: Buffer): Buffer;
+        update(data: string, input_encoding: "utf8"|"ascii"|"binary"): Buffer;
+        update(data: Buffer, input_encoding: any, output_encoding: "binary"|"base64"|"hex"): string;
+        update(data: string, input_encoding: "utf8"|"ascii"|"binary", output_encoding: "binary"|"base64"|"hex"): string;
+        final(): Buffer;
+        final(output_encoding: string): string;
+        setAutoPadding(auto_padding: boolean): void;
+        getAuthTag(): Buffer;
+    }
+    export function createDecipher(algorithm: string, password: any): Decipher;
+    export function createDecipheriv(algorithm: string, key: any, iv: any): Decipher;
+    export interface Decipher extends NodeJS.ReadWriteStream {
+        update(data: Buffer): Buffer;
+        update(data: string, input_encoding: "binary"|"base64"|"hex"): Buffer;
+        update(data: Buffer, input_encoding: any, output_encoding: "utf8"|"ascii"|"binary"): string;
+        update(data: string, input_encoding: "binary"|"base64"|"hex", output_encoding: "utf8"|"ascii"|"binary"): string;
+        final(): Buffer;
+        final(output_encoding: string): string;
+        setAutoPadding(auto_padding: boolean): void;
+        setAuthTag(tag: Buffer): void;
+    }
+    export function createSign(algorithm: string): Signer;
+    export interface Signer extends NodeJS.WritableStream {
+        update(data: any): void;
+        sign(private_key: string, output_format: string): string;
+    }
+    export function createVerify(algorith: string): Verify;
+    export interface Verify extends NodeJS.WritableStream {
+        update(data: any): void;
+        verify(object: string, signature: string, signature_format?: string): boolean;
+    }
+    export function createDiffieHellman(prime_length: number): DiffieHellman;
+    export function createDiffieHellman(prime: number, encoding?: string): DiffieHellman;
+    export interface DiffieHellman {
+        generateKeys(encoding?: string): string;
+        computeSecret(other_public_key: string, input_encoding?: string, output_encoding?: string): string;
+        getPrime(encoding?: string): string;
+        getGenerator(encoding: string): string;
+        getPublicKey(encoding?: string): string;
+        getPrivateKey(encoding?: string): string;
+        setPublicKey(public_key: string, encoding?: string): void;
+        setPrivateKey(public_key: string, encoding?: string): void;
+    }
+    export function getDiffieHellman(group_name: string): DiffieHellman;
+    export function pbkdf2(password: string|Buffer, salt: string|Buffer, iterations: number, keylen: number, callback: (err: Error, derivedKey: Buffer) => any): void;
+    export function pbkdf2(password: string|Buffer, salt: string|Buffer, iterations: number, keylen: number, digest: string, callback: (err: Error, derivedKey: Buffer) => any): void;
+    export function pbkdf2Sync(password: string|Buffer, salt: string|Buffer, iterations: number, keylen: number) : Buffer;
+    export function pbkdf2Sync(password: string|Buffer, salt: string|Buffer, iterations: number, keylen: number, digest: string) : Buffer;
+    export function randomBytes(size: number): Buffer;
+    export function randomBytes(size: number, callback: (err: Error, buf: Buffer) =>void ): void;
+    export function pseudoRandomBytes(size: number): Buffer;
+    export function pseudoRandomBytes(size: number, callback: (err: Error, buf: Buffer) =>void ): void;
+    export interface RsaPublicKey {
+        key: string;
+        padding?: any;
+    }
+    export interface RsaPrivateKey {
+        key: string;
+        passphrase?: string,
+        padding?: any;
+    }
+    export function publicEncrypt(public_key: string|RsaPublicKey, buffer: Buffer): Buffer
+    export function privateDecrypt(private_key: string|RsaPrivateKey, buffer: Buffer): Buffer
+}
+
+declare module "stream" {
+    import * as events from "events";
+
+    export class Stream extends events.EventEmitter {
+        pipe<T extends NodeJS.WritableStream>(destination: T, options?: { end?: boolean; }): T;
+    }
+
+    export interface ReadableOptions {
+        highWaterMark?: number;
+        encoding?: string;
+        objectMode?: boolean;
+    }
+
+    export class Readable extends events.EventEmitter implements NodeJS.ReadableStream {
+        readable: boolean;
+        constructor(opts?: ReadableOptions);
+        _read(size: number): void;
+        read(size?: number): any;
+        setEncoding(encoding: string): void;
+        pause(): void;
+        resume(): void;
+        pipe<T extends NodeJS.WritableStream>(destination: T, options?: { end?: boolean; }): T;
+        unpipe<T extends NodeJS.WritableStream>(destination?: T): void;
+        unshift(chunk: any): void;
+        wrap(oldStream: NodeJS.ReadableStream): NodeJS.ReadableStream;
+        push(chunk: any, encoding?: string): boolean;
+    }
+
+    export interface WritableOptions {
+        highWaterMark?: number;
+        decodeStrings?: boolean;
+        objectMode?: boolean;
+    }
+
+    export class Writable extends events.EventEmitter implements NodeJS.WritableStream {
+        writable: boolean;
+        constructor(opts?: WritableOptions);
+        _write(chunk: any, encoding: string, callback: Function): void;
+        write(chunk: any, cb?: Function): boolean;
+        write(chunk: any, encoding?: string, cb?: Function): boolean;
+        end(): void;
+        end(chunk: any, cb?: Function): void;
+        end(chunk: any, encoding?: string, cb?: Function): void;
+    }
+
+    export interface DuplexOptions extends ReadableOptions, WritableOptions {
+        allowHalfOpen?: boolean;
+    }
+
+    // Note: Duplex extends both Readable and Writable.
+    export class Duplex extends Readable implements NodeJS.ReadWriteStream {
+        writable: boolean;
+        constructor(opts?: DuplexOptions);
+        _write(chunk: any, encoding: string, callback: Function): void;
+        write(chunk: any, cb?: Function): boolean;
+        write(chunk: any, encoding?: string, cb?: Function): boolean;
+        end(): void;
+        end(chunk: any, cb?: Function): void;
+        end(chunk: any, encoding?: string, cb?: Function): void;
+    }
+
+    export interface TransformOptions extends ReadableOptions, WritableOptions {}
+
+    // Note: Transform lacks the _read and _write methods of Readable/Writable.
+    export class Transform extends events.EventEmitter implements NodeJS.ReadWriteStream {
+        readable: boolean;
+        writable: boolean;
+        constructor(opts?: TransformOptions);
+        _transform(chunk: any, encoding: string, callback: Function): void;
+        _flush(callback: Function): void;
+        read(size?: number): any;
+        setEncoding(encoding: string): void;
+        pause(): void;
+        resume(): void;
+        pipe<T extends NodeJS.WritableStream>(destination: T, options?: { end?: boolean; }): T;
+        unpipe<T extends NodeJS.WritableStream>(destination?: T): void;
+        unshift(chunk: any): void;
+        wrap(oldStream: NodeJS.ReadableStream): NodeJS.ReadableStream;
+        push(chunk: any, encoding?: string): boolean;
+        write(chunk: any, cb?: Function): boolean;
+        write(chunk: any, encoding?: string, cb?: Function): boolean;
+        end(): void;
+        end(chunk: any, cb?: Function): void;
+        end(chunk: any, encoding?: string, cb?: Function): void;
+    }
+
+    export class PassThrough extends Transform {}
+}
+
+declare module "util" {
+    export interface InspectOptions {
+        showHidden?: boolean;
+        depth?: number;
+        colors?: boolean;
+        customInspect?: boolean;
+    }
+
+    export function format(format: any, ...param: any[]): string;
+    export function debug(string: string): void;
+    export function error(...param: any[]): void;
+    export function puts(...param: any[]): void;
+    export function print(...param: any[]): void;
+    export function log(string: string): void;
+    export function inspect(object: any, showHidden?: boolean, depth?: number, color?: boolean): string;
+    export function inspect(object: any, options: InspectOptions): string;
+    export function isArray(object: any): boolean;
+    export function isRegExp(object: any): boolean;
+    export function isDate(object: any): boolean;
+    export function isError(object: any): boolean;
+    export function inherits(constructor: any, superConstructor: any): void;
+    export function debuglog(key:string): (msg:string,...param: any[])=>void;
+}
+
+declare module "assert" {
+    function internal (value: any, message?: string): void;
+    namespace internal {
+        export class AssertionError implements Error {
+            name: string;
+            message: string;
+            actual: any;
+            expected: any;
+            operator: string;
+            generatedMessage: boolean;
+
+            constructor(options?: {message?: string; actual?: any; expected?: any;
+                                  operator?: string; stackStartFunction?: Function});
+        }
+
+        export function fail(actual?: any, expected?: any, message?: string, operator?: string): void;
+        export function ok(value: any, message?: string): void;
+        export function equal(actual: any, expected: any, message?: string): void;
+        export function notEqual(actual: any, expected: any, message?: string): void;
+        export function deepEqual(actual: any, expected: any, message?: string): void;
+        export function notDeepEqual(acutal: any, expected: any, message?: string): void;
+        export function strictEqual(actual: any, expected: any, message?: string): void;
+        export function notStrictEqual(actual: any, expected: any, message?: string): void;
+        export function deepStrictEqual(actual: any, expected: any, message?: string): void;
+        export function notDeepStrictEqual(actual: any, expected: any, message?: string): void;
+        export var throws: {
+            (block: Function, message?: string): void;
+            (block: Function, error: Function, message?: string): void;
+            (block: Function, error: RegExp, message?: string): void;
+            (block: Function, error: (err: any) => boolean, message?: string): void;
+        };
+
+        export var doesNotThrow: {
+            (block: Function, message?: string): void;
+            (block: Function, error: Function, message?: string): void;
+            (block: Function, error: RegExp, message?: string): void;
+            (block: Function, error: (err: any) => boolean, message?: string): void;
+        };
+
+        export function ifError(value: any): void;
+    }
+
+    export = internal;
+}
+
+declare module "tty" {
+    import * as net from "net";
+
+    export function isatty(fd: number): boolean;
+    export interface ReadStream extends net.Socket {
+        isRaw: boolean;
+        setRawMode(mode: boolean): void;
+        isTTY: boolean;
+    }
+    export interface WriteStream extends net.Socket {
+        columns: number;
+        rows: number;
+        isTTY: boolean;
+    }
+}
+
+declare module "domain" {
+    import * as events from "events";
+
+    export class Domain extends events.EventEmitter implements NodeJS.Domain {
+        run(fn: Function): void;
+        add(emitter: events.EventEmitter): void;
+        remove(emitter: events.EventEmitter): void;
+        bind(cb: (err: Error, data: any) => any): any;
+        intercept(cb: (data: any) => any): any;
+        dispose(): void;
+    }
+
+    export function create(): Domain;
+}
+
+declare module "constants" {
+    export var E2BIG: number;
+    export var EACCES: number;
+    export var EADDRINUSE: number;
+    export var EADDRNOTAVAIL: number;
+    export var EAFNOSUPPORT: number;
+    export var EAGAIN: number;
+    export var EALREADY: number;
+    export var EBADF: number;
+    export var EBADMSG: number;
+    export var EBUSY: number;
+    export var ECANCELED: number;
+    export var ECHILD: number;
+    export var ECONNABORTED: number;
+    export var ECONNREFUSED: number;
+    export var ECONNRESET: number;
+    export var EDEADLK: number;
+    export var EDESTADDRREQ: number;
+    export var EDOM: number;
+    export var EEXIST: number;
+    export var EFAULT: number;
+    export var EFBIG: number;
+    export var EHOSTUNREACH: number;
+    export var EIDRM: number;
+    export var EILSEQ: number;
+    export var EINPROGRESS: number;
+    export var EINTR: number;
+    export var EINVAL: number;
+    export var EIO: number;
+    export var EISCONN: number;
+    export var EISDIR: number;
+    export var ELOOP: number;
+    export var EMFILE: number;
+    export var EMLINK: number;
+    export var EMSGSIZE: number;
+    export var ENAMETOOLONG: number;
+    export var ENETDOWN: number;
+    export var ENETRESET: number;
+    export var ENETUNREACH: number;
+    export var ENFILE: number;
+    export var ENOBUFS: number;
+    export var ENODATA: number;
+    export var ENODEV: number;
+    export var ENOENT: number;
+    export var ENOEXEC: number;
+    export var ENOLCK: number;
+    export var ENOLINK: number;
+    export var ENOMEM: number;
+    export var ENOMSG: number;
+    export var ENOPROTOOPT: number;
+    export var ENOSPC: number;
+    export var ENOSR: number;
+    export var ENOSTR: number;
+    export var ENOSYS: number;
+    export var ENOTCONN: number;
+    export var ENOTDIR: number;
+    export var ENOTEMPTY: number;
+    export var ENOTSOCK: number;
+    export var ENOTSUP: number;
+    export var ENOTTY: number;
+    export var ENXIO: number;
+    export var EOPNOTSUPP: number;
+    export var EOVERFLOW: number;
+    export var EPERM: number;
+    export var EPIPE: number;
+    export var EPROTO: number;
+    export var EPROTONOSUPPORT: number;
+    export var EPROTOTYPE: number;
+    export var ERANGE: number;
+    export var EROFS: number;
+    export var ESPIPE: number;
+    export var ESRCH: number;
+    export var ETIME: number;
+    export var ETIMEDOUT: number;
+    export var ETXTBSY: number;
+    export var EWOULDBLOCK: number;
+    export var EXDEV: number;
+    export var WSAEINTR: number;
+    export var WSAEBADF: number;
+    export var WSAEACCES: number;
+    export var WSAEFAULT: number;
+    export var WSAEINVAL: number;
+    export var WSAEMFILE: number;
+    export var WSAEWOULDBLOCK: number;
+    export var WSAEINPROGRESS: number;
+    export var WSAEALREADY: number;
+    export var WSAENOTSOCK: number;
+    export var WSAEDESTADDRREQ: number;
+    export var WSAEMSGSIZE: number;
+    export var WSAEPROTOTYPE: number;
+    export var WSAENOPROTOOPT: number;
+    export var WSAEPROTONOSUPPORT: number;
+    export var WSAESOCKTNOSUPPORT: number;
+    export var WSAEOPNOTSUPP: number;
+    export var WSAEPFNOSUPPORT: number;
+    export var WSAEAFNOSUPPORT: number;
+    export var WSAEADDRINUSE: number;
+    export var WSAEADDRNOTAVAIL: number;
+    export var WSAENETDOWN: number;
+    export var WSAENETUNREACH: number;
+    export var WSAENETRESET: number;
+    export var WSAECONNABORTED: number;
+    export var WSAECONNRESET: number;
+    export var WSAENOBUFS: number;
+    export var WSAEISCONN: number;
+    export var WSAENOTCONN: number;
+    export var WSAESHUTDOWN: number;
+    export var WSAETOOMANYREFS: number;
+    export var WSAETIMEDOUT: number;
+    export var WSAECONNREFUSED: number;
+    export var WSAELOOP: number;
+    export var WSAENAMETOOLONG: number;
+    export var WSAEHOSTDOWN: number;
+    export var WSAEHOSTUNREACH: number;
+    export var WSAENOTEMPTY: number;
+    export var WSAEPROCLIM: number;
+    export var WSAEUSERS: number;
+    export var WSAEDQUOT: number;
+    export var WSAESTALE: number;
+    export var WSAEREMOTE: number;
+    export var WSASYSNOTREADY: number;
+    export var WSAVERNOTSUPPORTED: number;
+    export var WSANOTINITIALISED: number;
+    export var WSAEDISCON: number;
+    export var WSAENOMORE: number;
+    export var WSAECANCELLED: number;
+    export var WSAEINVALIDPROCTABLE: number;
+    export var WSAEINVALIDPROVIDER: number;
+    export var WSAEPROVIDERFAILEDINIT: number;
+    export var WSASYSCALLFAILURE: number;
+    export var WSASERVICE_NOT_FOUND: number;
+    export var WSATYPE_NOT_FOUND: number;
+    export var WSA_E_NO_MORE: number;
+    export var WSA_E_CANCELLED: number;
+    export var WSAEREFUSED: number;
+    export var SIGHUP: number;
+    export var SIGINT: number;
+    export var SIGILL: number;
+    export var SIGABRT: number;
+    export var SIGFPE: number;
+    export var SIGKILL: number;
+    export var SIGSEGV: number;
+    export var SIGTERM: number;
+    export var SIGBREAK: number;
+    export var SIGWINCH: number;
+    export var SSL_OP_ALL: number;
+    export var SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION: number;
+    export var SSL_OP_CIPHER_SERVER_PREFERENCE: number;
+    export var SSL_OP_CISCO_ANYCONNECT: number;
+    export var SSL_OP_COOKIE_EXCHANGE: number;
+    export var SSL_OP_CRYPTOPRO_TLSEXT_BUG: number;
+    export var SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS: number;
+    export var SSL_OP_EPHEMERAL_RSA: number;
+    export var SSL_OP_LEGACY_SERVER_CONNECT: number;
+    export var SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER: number;
+    export var SSL_OP_MICROSOFT_SESS_ID_BUG: number;
+    export var SSL_OP_MSIE_SSLV2_RSA_PADDING: number;
+    export var SSL_OP_NETSCAPE_CA_DN_BUG: number;
+    export var SSL_OP_NETSCAPE_CHALLENGE_BUG: number;
+    export var SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG: number;
+    export var SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG: number;
+    export var SSL_OP_NO_COMPRESSION: number;
+    export var SSL_OP_NO_QUERY_MTU: number;
+    export var SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION: number;
+    export var SSL_OP_NO_SSLv2: number;
+    export var SSL_OP_NO_SSLv3: number;
+    export var SSL_OP_NO_TICKET: number;
+    export var SSL_OP_NO_TLSv1: number;
+    export var SSL_OP_NO_TLSv1_1: number;
+    export var SSL_OP_NO_TLSv1_2: number;
+    export var SSL_OP_PKCS1_CHECK_1: number;
+    export var SSL_OP_PKCS1_CHECK_2: number;
+    export var SSL_OP_SINGLE_DH_USE: number;
+    export var SSL_OP_SINGLE_ECDH_USE: number;
+    export var SSL_OP_SSLEAY_080_CLIENT_DH_BUG: number;
+    export var SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG: number;
+    export var SSL_OP_TLS_BLOCK_PADDING_BUG: number;
+    export var SSL_OP_TLS_D5_BUG: number;
+    export var SSL_OP_TLS_ROLLBACK_BUG: number;
+    export var ENGINE_METHOD_DSA: number;
+    export var ENGINE_METHOD_DH: number;
+    export var ENGINE_METHOD_RAND: number;
+    export var ENGINE_METHOD_ECDH: number;
+    export var ENGINE_METHOD_ECDSA: number;
+    export var ENGINE_METHOD_CIPHERS: number;
+    export var ENGINE_METHOD_DIGESTS: number;
+    export var ENGINE_METHOD_STORE: number;
+    export var ENGINE_METHOD_PKEY_METHS: number;
+    export var ENGINE_METHOD_PKEY_ASN1_METHS: number;
+    export var ENGINE_METHOD_ALL: number;
+    export var ENGINE_METHOD_NONE: number;
+    export var DH_CHECK_P_NOT_SAFE_PRIME: number;
+    export var DH_CHECK_P_NOT_PRIME: number;
+    export var DH_UNABLE_TO_CHECK_GENERATOR: number;
+    export var DH_NOT_SUITABLE_GENERATOR: number;
+    export var NPN_ENABLED: number;
+    export var RSA_PKCS1_PADDING: number;
+    export var RSA_SSLV23_PADDING: number;
+    export var RSA_NO_PADDING: number;
+    export var RSA_PKCS1_OAEP_PADDING: number;
+    export var RSA_X931_PADDING: number;
+    export var RSA_PKCS1_PSS_PADDING: number;
+    export var POINT_CONVERSION_COMPRESSED: number;
+    export var POINT_CONVERSION_UNCOMPRESSED: number;
+    export var POINT_CONVERSION_HYBRID: number;
+    export var O_RDONLY: number;
+    export var O_WRONLY: number;
+    export var O_RDWR: number;
+    export var S_IFMT: number;
+    export var S_IFREG: number;
+    export var S_IFDIR: number;
+    export var S_IFCHR: number;
+    export var S_IFBLK: number;
+    export var S_IFIFO: number;
+    export var S_IFSOCK: number;
+    export var S_IRWXU: number;
+    export var S_IRUSR: number;
+    export var S_IWUSR: number;
+    export var S_IXUSR: number;
+    export var S_IRWXG: number;
+    export var S_IRGRP: number;
+    export var S_IWGRP: number;
+    export var S_IXGRP: number;
+    export var S_IRWXO: number;
+    export var S_IROTH: number;
+    export var S_IWOTH: number;
+    export var S_IXOTH: number;
+    export var S_IFLNK: number;
+    export var O_CREAT: number;
+    export var O_EXCL: number;
+    export var O_NOCTTY: number;
+    export var O_DIRECTORY: number;
+    export var O_NOATIME: number;
+    export var O_NOFOLLOW: number;
+    export var O_SYNC: number;
+    export var O_SYMLINK: number;
+    export var O_DIRECT: number;
+    export var O_NONBLOCK: number;
+    export var O_TRUNC: number;
+    export var O_APPEND: number;
+    export var F_OK: number;
+    export var R_OK: number;
+    export var W_OK: number;
+    export var X_OK: number;
+    export var UV_UDP_REUSEADDR: number;
+}
\ No newline at end of file
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/typings/globals/node/typings.json b/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/typings/globals/node/typings.json
new file mode 100644
index 0000000000000000000000000000000000000000..788506efdb31c8338cfd558f412c0e782ede19a2
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/typings/globals/node/typings.json
@@ -0,0 +1,8 @@
+{
+  "resolution": "main",
+  "tree": {
+    "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/77b1b1709315b03b9b1b67c589d599bebeeef2ee/node/node.d.ts",
+    "raw": "registry:dt/node#6.0.0+20160709114037",
+    "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/77b1b1709315b03b9b1b67c589d599bebeeef2ee/node/node.d.ts"
+  }
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/typings/index.d.ts b/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/typings/index.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..22e4de57a74075c601e6822b5dd5ffb0abc4379c
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/base64url/typings/index.d.ts
@@ -0,0 +1 @@
+/// <reference path="globals/node/index.d.ts" />
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/buffer-equal-constant-time/.npmignore b/KEMMessaging/node_modules/firebase-admin/node_modules/buffer-equal-constant-time/.npmignore
new file mode 100644
index 0000000000000000000000000000000000000000..34e4f5c298de294fa5c1c1769b6489eb047bde9a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/buffer-equal-constant-time/.npmignore
@@ -0,0 +1,2 @@
+.*.sw[mnop]
+node_modules/
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/buffer-equal-constant-time/.travis.yml b/KEMMessaging/node_modules/firebase-admin/node_modules/buffer-equal-constant-time/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..78e1c01462f467bbb5facf6f63eb744c86200f7c
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/buffer-equal-constant-time/.travis.yml
@@ -0,0 +1,4 @@
+language: node_js
+node_js:
+- "0.11"
+- "0.10"
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/buffer-equal-constant-time/LICENSE.txt b/KEMMessaging/node_modules/firebase-admin/node_modules/buffer-equal-constant-time/LICENSE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..9a064f3f46ddd7239274cf0e80dab1bf8a820b34
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/buffer-equal-constant-time/LICENSE.txt
@@ -0,0 +1,12 @@
+Copyright (c) 2013, GoInstant Inc., a salesforce.com company
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+* Neither the name of salesforce.com, nor GoInstant, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/buffer-equal-constant-time/README.md b/KEMMessaging/node_modules/firebase-admin/node_modules/buffer-equal-constant-time/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..4f227f58bddbe9b1a06a4781efca74538b4b532a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/buffer-equal-constant-time/README.md
@@ -0,0 +1,50 @@
+# buffer-equal-constant-time
+
+Constant-time `Buffer` comparison for node.js.  Should work with browserify too.
+
+[![Build Status](https://travis-ci.org/goinstant/buffer-equal-constant-time.png?branch=master)](https://travis-ci.org/goinstant/buffer-equal-constant-time)
+
+```sh
+  npm install buffer-equal-constant-time
+```
+
+# Usage
+
+```js
+  var bufferEq = require('buffer-equal-constant-time');
+
+  var a = new Buffer('asdf');
+  var b = new Buffer('asdf');
+  if (bufferEq(a,b)) {
+    // the same!
+  } else {
+    // different in at least one byte!
+  }
+```
+
+If you'd like to install an `.equal()` method onto the node.js `Buffer` and
+`SlowBuffer` prototypes:
+
+```js
+  require('buffer-equal-constant-time').install();
+
+  var a = new Buffer('asdf');
+  var b = new Buffer('asdf');
+  if (a.equal(b)) {
+    // the same!
+  } else {
+    // different in at least one byte!
+  }
+```
+
+To get rid of the installed `.equal()` method, call `.restore()`:
+
+```js
+  require('buffer-equal-constant-time').restore();
+```
+
+# Legal
+
+&copy; 2013 GoInstant Inc., a salesforce.com company
+
+Licensed under the BSD 3-clause license.
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/buffer-equal-constant-time/index.js b/KEMMessaging/node_modules/firebase-admin/node_modules/buffer-equal-constant-time/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..5462c1f830bdbe79bf2b1fcfd811cd9799b4dd11
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/buffer-equal-constant-time/index.js
@@ -0,0 +1,41 @@
+/*jshint node:true */
+'use strict';
+var Buffer = require('buffer').Buffer; // browserify
+var SlowBuffer = require('buffer').SlowBuffer;
+
+module.exports = bufferEq;
+
+function bufferEq(a, b) {
+
+  // shortcutting on type is necessary for correctness
+  if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {
+    return false;
+  }
+
+  // buffer sizes should be well-known information, so despite this
+  // shortcutting, it doesn't leak any information about the *contents* of the
+  // buffers.
+  if (a.length !== b.length) {
+    return false;
+  }
+
+  var c = 0;
+  for (var i = 0; i < a.length; i++) {
+    /*jshint bitwise:false */
+    c |= a[i] ^ b[i]; // XOR
+  }
+  return c === 0;
+}
+
+bufferEq.install = function() {
+  Buffer.prototype.equal = SlowBuffer.prototype.equal = function equal(that) {
+    return bufferEq(this, that);
+  };
+};
+
+var origBufEqual = Buffer.prototype.equal;
+var origSlowBufEqual = SlowBuffer.prototype.equal;
+bufferEq.restore = function() {
+  Buffer.prototype.equal = origBufEqual;
+  SlowBuffer.prototype.equal = origSlowBufEqual;
+};
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/buffer-equal-constant-time/package.json b/KEMMessaging/node_modules/firebase-admin/node_modules/buffer-equal-constant-time/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..d7ecfbae46a59dea0a7e9abb3e9a8d7f32b29fa8
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/buffer-equal-constant-time/package.json
@@ -0,0 +1,71 @@
+{
+  "_args": [
+    [
+      {
+        "raw": "buffer-equal-constant-time@https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+        "scope": null,
+        "escapedName": "buffer-equal-constant-time",
+        "name": "buffer-equal-constant-time",
+        "rawSpec": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+        "spec": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+        "type": "remote"
+      },
+      "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin"
+    ]
+  ],
+  "_from": "buffer-equal-constant-time@1.0.1",
+  "_id": "buffer-equal-constant-time@1.0.1",
+  "_inCache": true,
+  "_location": "/firebase-admin/buffer-equal-constant-time",
+  "_phantomChildren": {},
+  "_requested": {
+    "raw": "buffer-equal-constant-time@https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+    "scope": null,
+    "escapedName": "buffer-equal-constant-time",
+    "name": "buffer-equal-constant-time",
+    "rawSpec": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+    "spec": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+    "type": "remote"
+  },
+  "_requiredBy": [
+    "/firebase-admin",
+    "/firebase-admin/jwa"
+  ],
+  "_resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+  "_shasum": "f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819",
+  "_shrinkwrap": null,
+  "_spec": "buffer-equal-constant-time@https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+  "_where": "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin",
+  "author": {
+    "name": "GoInstant Inc., a salesforce.com company"
+  },
+  "bugs": {
+    "url": "https://github.com/goinstant/buffer-equal-constant-time/issues"
+  },
+  "dependencies": {},
+  "description": "Constant-time comparison of Buffers",
+  "devDependencies": {
+    "mocha": "~1.15.1"
+  },
+  "homepage": "https://github.com/goinstant/buffer-equal-constant-time#readme",
+  "keywords": [
+    "buffer",
+    "equal",
+    "constant-time",
+    "crypto"
+  ],
+  "license": "BSD-3-Clause",
+  "main": "index.js",
+  "name": "buffer-equal-constant-time",
+  "optionalDependencies": {},
+  "readme": "# buffer-equal-constant-time\n\nConstant-time `Buffer` comparison for node.js.  Should work with browserify too.\n\n[![Build Status](https://travis-ci.org/goinstant/buffer-equal-constant-time.png?branch=master)](https://travis-ci.org/goinstant/buffer-equal-constant-time)\n\n```sh\n  npm install buffer-equal-constant-time\n```\n\n# Usage\n\n```js\n  var bufferEq = require('buffer-equal-constant-time');\n\n  var a = new Buffer('asdf');\n  var b = new Buffer('asdf');\n  if (bufferEq(a,b)) {\n    // the same!\n  } else {\n    // different in at least one byte!\n  }\n```\n\nIf you'd like to install an `.equal()` method onto the node.js `Buffer` and\n`SlowBuffer` prototypes:\n\n```js\n  require('buffer-equal-constant-time').install();\n\n  var a = new Buffer('asdf');\n  var b = new Buffer('asdf');\n  if (a.equal(b)) {\n    // the same!\n  } else {\n    // different in at least one byte!\n  }\n```\n\nTo get rid of the installed `.equal()` method, call `.restore()`:\n\n```js\n  require('buffer-equal-constant-time').restore();\n```\n\n# Legal\n\n&copy; 2013 GoInstant Inc., a salesforce.com company\n\nLicensed under the BSD 3-clause license.\n",
+  "readmeFilename": "README.md",
+  "repository": {
+    "type": "git",
+    "url": "git+ssh://git@github.com/goinstant/buffer-equal-constant-time.git"
+  },
+  "scripts": {
+    "test": "mocha test.js"
+  },
+  "version": "1.0.1"
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/buffer-equal-constant-time/test.js b/KEMMessaging/node_modules/firebase-admin/node_modules/buffer-equal-constant-time/test.js
new file mode 100644
index 0000000000000000000000000000000000000000..0bc972d841aedb82e4449b935992ef9c8cf79b4f
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/buffer-equal-constant-time/test.js
@@ -0,0 +1,42 @@
+/*jshint node:true */
+'use strict';
+
+var bufferEq = require('./index');
+var assert = require('assert');
+
+describe('buffer-equal-constant-time', function() {
+  var a = new Buffer('asdfasdf123456');
+  var b = new Buffer('asdfasdf123456');
+  var c = new Buffer('asdfasdf');
+
+  describe('bufferEq', function() {
+    it('says a == b', function() {
+      assert.strictEqual(bufferEq(a, b), true);
+    });
+
+    it('says a != c', function() {
+      assert.strictEqual(bufferEq(a, c), false);
+    });
+  });
+
+  describe('install/restore', function() {
+    before(function() {
+      bufferEq.install();
+    });
+    after(function() {
+      bufferEq.restore();
+    });
+
+    it('installed an .equal method', function() {
+      var SlowBuffer = require('buffer').SlowBuffer;
+      assert.ok(Buffer.prototype.equal);
+      assert.ok(SlowBuffer.prototype.equal);
+    });
+
+    it('infected existing Buffers', function() {
+      assert.strictEqual(a.equal(b), true);
+      assert.strictEqual(a.equal(c), false);
+    });
+  });
+
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/ecdsa-sig-formatter/LICENSE b/KEMMessaging/node_modules/firebase-admin/node_modules/ecdsa-sig-formatter/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..8754ed6307cb91a28bbdc96f322103218a9eb911
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/ecdsa-sig-formatter/LICENSE
@@ -0,0 +1,201 @@
+Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright 2015 D2L Corporation
+
+   Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/ecdsa-sig-formatter/README.md b/KEMMessaging/node_modules/firebase-admin/node_modules/ecdsa-sig-formatter/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..daa95d6e48b1f5368f8ea0f534b3ae1b4556eae7
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/ecdsa-sig-formatter/README.md
@@ -0,0 +1,65 @@
+# ecdsa-sig-formatter
+
+[![Build Status](https://travis-ci.org/Brightspace/node-ecdsa-sig-formatter.svg?branch=master)](https://travis-ci.org/Brightspace/node-ecdsa-sig-formatter) [![Coverage Status](https://coveralls.io/repos/Brightspace/node-ecdsa-sig-formatter/badge.svg)](https://coveralls.io/r/Brightspace/node-ecdsa-sig-formatter)
+
+Translate between JOSE and ASN.1/DER encodings for ECDSA signatures
+
+## Install
+```sh
+npm install ecdsa-sig-formatter --save
+```
+
+## Usage
+```js
+var format = require('ecdsa-sig-formatter');
+
+var derSignature = '..'; // asn.1/DER encoded ecdsa signature
+
+var joseSignature = format.derToJose(derSignature);
+
+```
+
+### API
+
+---
+
+#### `.derToJose(Buffer|String signature, String alg)` -> `String`
+
+Convert the ASN.1/DER encoded signature to a JOSE-style concatenated signature.
+Returns a _base64 url_ encoded `String`.
+
+* If _signature_ is a `String`, it should be _base64_ encoded
+* _alg_ must be one of _ES256_, _ES384_ or _ES512_
+
+---
+
+#### `.joseToDer(Buffer|String signature, String alg)` -> `Buffer`
+
+Convert the JOSE-style concatenated signature to an ASN.1/DER encoded
+signature. Returns a `Buffer`
+
+* If _signature_ is a `String`, it should be _base64 url_ encoded
+* _alg_ must be one of _ES256_, _ES384_ or _ES512_
+
+## Contributing
+
+1. **Fork** the repository. Committing directly against this repository is
+   highly discouraged.
+
+2. Make your modifications in a branch, updating and writing new unit tests
+   as necessary in the `spec` directory.
+
+3. Ensure that all tests pass with `npm test`
+
+4. `rebase` your changes against master. *Do not merge*.
+
+5. Submit a pull request to this repository. Wait for tests to run and someone
+   to chime in.
+
+### Code Style
+
+This repository is configured with [EditorConfig][EditorConfig] and
+[ESLint][ESLint] rules.
+
+[EditorConfig]: http://editorconfig.org/
+[ESLint]: http://eslint.org
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/ecdsa-sig-formatter/package.json b/KEMMessaging/node_modules/firebase-admin/node_modules/ecdsa-sig-formatter/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..2e752d542375313af523c68856c3785744499d82
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/ecdsa-sig-formatter/package.json
@@ -0,0 +1,87 @@
+{
+  "_args": [
+    [
+      {
+        "raw": "ecdsa-sig-formatter@https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.7.tgz",
+        "scope": null,
+        "escapedName": "ecdsa-sig-formatter",
+        "name": "ecdsa-sig-formatter",
+        "rawSpec": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.7.tgz",
+        "spec": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.7.tgz",
+        "type": "remote"
+      },
+      "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin"
+    ]
+  ],
+  "_from": "ecdsa-sig-formatter@1.0.7",
+  "_id": "ecdsa-sig-formatter@1.0.7",
+  "_inCache": true,
+  "_location": "/firebase-admin/ecdsa-sig-formatter",
+  "_phantomChildren": {},
+  "_requested": {
+    "raw": "ecdsa-sig-formatter@https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.7.tgz",
+    "scope": null,
+    "escapedName": "ecdsa-sig-formatter",
+    "name": "ecdsa-sig-formatter",
+    "rawSpec": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.7.tgz",
+    "spec": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.7.tgz",
+    "type": "remote"
+  },
+  "_requiredBy": [
+    "/firebase-admin",
+    "/firebase-admin/jwa"
+  ],
+  "_resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.7.tgz",
+  "_shasum": "3137e976a1d6232517e2513e04e32f79bcbdf126",
+  "_shrinkwrap": null,
+  "_spec": "ecdsa-sig-formatter@https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.7.tgz",
+  "_where": "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin",
+  "author": {
+    "name": "D2L Corporation"
+  },
+  "bugs": {
+    "url": "https://github.com/Brightspace/node-ecdsa-sig-formatter/issues"
+  },
+  "dependencies": {
+    "base64-url": "^1.2.1"
+  },
+  "description": "Translate ECDSA signatures between ASN.1/DER and JOSE-style concatenation",
+  "devDependencies": {
+    "bench": "^0.3.6",
+    "chai": "^3.5.0",
+    "coveralls": "^2.11.9",
+    "elliptic": "^6.3.1",
+    "eslint": "^2.12.0",
+    "eslint-config-brightspace": "^0.2.1",
+    "istanbul": "^0.4.3",
+    "jwk-to-pem": "^1.2.5",
+    "mocha": "^2.5.3"
+  },
+  "homepage": "https://github.com/Brightspace/node-ecdsa-sig-formatter#readme",
+  "keywords": [
+    "ecdsa",
+    "der",
+    "asn.1",
+    "jwt",
+    "jwa",
+    "jsonwebtoken",
+    "jose"
+  ],
+  "license": "Apache-2.0",
+  "main": "src/ecdsa-sig-formatter.js",
+  "name": "ecdsa-sig-formatter",
+  "optionalDependencies": {},
+  "readme": "# ecdsa-sig-formatter\n\n[![Build Status](https://travis-ci.org/Brightspace/node-ecdsa-sig-formatter.svg?branch=master)](https://travis-ci.org/Brightspace/node-ecdsa-sig-formatter) [![Coverage Status](https://coveralls.io/repos/Brightspace/node-ecdsa-sig-formatter/badge.svg)](https://coveralls.io/r/Brightspace/node-ecdsa-sig-formatter)\n\nTranslate between JOSE and ASN.1/DER encodings for ECDSA signatures\n\n## Install\n```sh\nnpm install ecdsa-sig-formatter --save\n```\n\n## Usage\n```js\nvar format = require('ecdsa-sig-formatter');\n\nvar derSignature = '..'; // asn.1/DER encoded ecdsa signature\n\nvar joseSignature = format.derToJose(derSignature);\n\n```\n\n### API\n\n---\n\n#### `.derToJose(Buffer|String signature, String alg)` -> `String`\n\nConvert the ASN.1/DER encoded signature to a JOSE-style concatenated signature.\nReturns a _base64 url_ encoded `String`.\n\n* If _signature_ is a `String`, it should be _base64_ encoded\n* _alg_ must be one of _ES256_, _ES384_ or _ES512_\n\n---\n\n#### `.joseToDer(Buffer|String signature, String alg)` -> `Buffer`\n\nConvert the JOSE-style concatenated signature to an ASN.1/DER encoded\nsignature. Returns a `Buffer`\n\n* If _signature_ is a `String`, it should be _base64 url_ encoded\n* _alg_ must be one of _ES256_, _ES384_ or _ES512_\n\n## Contributing\n\n1. **Fork** the repository. Committing directly against this repository is\n   highly discouraged.\n\n2. Make your modifications in a branch, updating and writing new unit tests\n   as necessary in the `spec` directory.\n\n3. Ensure that all tests pass with `npm test`\n\n4. `rebase` your changes against master. *Do not merge*.\n\n5. Submit a pull request to this repository. Wait for tests to run and someone\n   to chime in.\n\n### Code Style\n\nThis repository is configured with [EditorConfig][EditorConfig] and\n[ESLint][ESLint] rules.\n\n[EditorConfig]: http://editorconfig.org/\n[ESLint]: http://eslint.org\n",
+  "readmeFilename": "README.md",
+  "repository": {
+    "type": "git",
+    "url": "git+ssh://git@github.com/Brightspace/node-ecdsa-sig-formatter.git"
+  },
+  "scripts": {
+    "check-style": "eslint .",
+    "pretest": "npm run check-style",
+    "report-cov": "cat ./coverage/lcov.info | coveralls",
+    "test": "istanbul cover --root src _mocha -- spec"
+  },
+  "version": "1.0.7"
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/ecdsa-sig-formatter/src/ecdsa-sig-formatter.js b/KEMMessaging/node_modules/firebase-admin/node_modules/ecdsa-sig-formatter/src/ecdsa-sig-formatter.js
new file mode 100644
index 0000000000000000000000000000000000000000..c9d24d82636486210e8a014f123d3b178235f413
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/ecdsa-sig-formatter/src/ecdsa-sig-formatter.js
@@ -0,0 +1,180 @@
+'use strict';
+
+var base64Url = require('base64-url').escape;
+
+var getParamBytesForAlg = require('./param-bytes-for-alg');
+
+var MAX_OCTET = 0x80,
+	CLASS_UNIVERSAL = 0,
+	PRIMITIVE_BIT = 0x20,
+	TAG_SEQ = 0x10,
+	TAG_INT = 0x02,
+	ENCODED_TAG_SEQ = (TAG_SEQ | PRIMITIVE_BIT) | (CLASS_UNIVERSAL << 6),
+	ENCODED_TAG_INT = TAG_INT | (CLASS_UNIVERSAL << 6);
+
+function signatureAsBuffer(signature) {
+	if (Buffer.isBuffer(signature)) {
+		return signature;
+	} else if ('string' === typeof signature) {
+		return new Buffer(signature, 'base64');
+	}
+
+	throw new TypeError('ECDSA signature must be a Base64 string or a Buffer');
+}
+
+function derToJose(signature, alg) {
+	signature = signatureAsBuffer(signature);
+	var paramBytes = getParamBytesForAlg(alg);
+
+	// the DER encoded param should at most be the param size, plus a padding
+	// zero, since due to being a signed integer
+	var maxEncodedParamLength = paramBytes + 1;
+
+	var inputLength = signature.length;
+
+	var offset = 0;
+	if (signature[offset++] !== ENCODED_TAG_SEQ) {
+		throw new Error('Could not find expected "seq"');
+	}
+
+	var seqLength = signature[offset++];
+	if (seqLength === (MAX_OCTET | 1)) {
+		seqLength = signature[offset++];
+	}
+
+	if (inputLength - offset < seqLength) {
+		throw new Error('"seq" specified length of "' + seqLength + '", only "' + (inputLength - offset) + '" remaining');
+	}
+
+	if (signature[offset++] !== ENCODED_TAG_INT) {
+		throw new Error('Could not find expected "int" for "r"');
+	}
+
+	var rLength = signature[offset++];
+
+	if (inputLength - offset - 2 < rLength) {
+		throw new Error('"r" specified length of "' + rLength + '", only "' + (inputLength - offset - 2) + '" available');
+	}
+
+	if (maxEncodedParamLength < rLength) {
+		throw new Error('"r" specified length of "' + rLength + '", max of "' + maxEncodedParamLength + '" is acceptable');
+	}
+
+	var rOffset = offset;
+	offset += rLength;
+
+	if (signature[offset++] !== ENCODED_TAG_INT) {
+		throw new Error('Could not find expected "int" for "s"');
+	}
+
+	var sLength = signature[offset++];
+
+	if (inputLength - offset !== sLength) {
+		throw new Error('"s" specified length of "' + sLength + '", expected "' + (inputLength - offset) + '"');
+	}
+
+	if (maxEncodedParamLength < sLength) {
+		throw new Error('"s" specified length of "' + sLength + '", max of "' + maxEncodedParamLength + '" is acceptable');
+	}
+
+	var sOffset = offset;
+	offset += sLength;
+
+	if (offset !== inputLength) {
+		throw new Error('Expected to consume entire buffer, but "' + (inputLength - offset) + '" bytes remain');
+	}
+
+	var rPadding = paramBytes - rLength,
+		sPadding = paramBytes - sLength;
+
+	var dst = new Buffer(rPadding + rLength + sPadding + sLength);
+
+	for (offset = 0; offset < rPadding; ++offset) {
+		dst[offset] = 0;
+	}
+	signature.copy(dst, offset, rOffset + Math.max(-rPadding, 0), rOffset + rLength);
+
+	offset = paramBytes;
+
+	for (var o = offset; offset < o + sPadding; ++offset) {
+		dst[offset] = 0;
+	}
+	signature.copy(dst, offset, sOffset + Math.max(-sPadding, 0), sOffset + sLength);
+
+	dst = dst.toString('base64');
+	dst = base64Url(dst);
+
+	return dst;
+}
+
+function countPadding(buf, start, stop) {
+	var padding = 0;
+	for (var n = stop; start + padding < n && buf[start + padding] === 0;) {
+		++padding;
+	}
+
+	var needsSign = buf[start + padding] >= MAX_OCTET;
+	if (needsSign) {
+		--padding;
+	}
+
+	return padding;
+}
+
+function joseToDer(signature, alg) {
+	signature = signatureAsBuffer(signature);
+	var paramBytes = getParamBytesForAlg(alg);
+
+	var signatureBytes = signature.length;
+	if (signatureBytes !== paramBytes * 2) {
+		throw new TypeError('"' + alg + '" signatures must be "' + paramBytes * 2 + '" bytes, saw "' + signatureBytes + '"');
+	}
+
+	var rPadding = countPadding(signature, 0, paramBytes);
+	var sPadding = countPadding(signature, paramBytes, signature.length);
+	var rLength = paramBytes - rPadding;
+	var sLength = paramBytes - sPadding;
+
+	var rsBytes = 1 + 1 + rLength + 1 + 1 + sLength;
+
+	var shortLength = rsBytes < MAX_OCTET;
+
+	var dst = new Buffer((shortLength ? 2 : 3) + rsBytes);
+
+	var offset = 0;
+	dst[offset++] = ENCODED_TAG_SEQ;
+	if (shortLength) {
+		// Bit 8 has value "0"
+		// bits 7-1 give the length.
+		dst[offset++] = rsBytes;
+	} else {
+		// Bit 8 of first octet has value "1"
+		// bits 7-1 give the number of additional length octets.
+		dst[offset++] = MAX_OCTET	| 1;
+		// length, base 256
+		dst[offset++] = rsBytes & 0xff;
+	}
+	dst[offset++] = ENCODED_TAG_INT;
+	dst[offset++] = rLength;
+	if (rPadding < 0) {
+		dst[offset++] = 0;
+		offset += signature.copy(dst, offset, 0, paramBytes);
+	} else {
+		offset += signature.copy(dst, offset, rPadding, paramBytes);
+	}
+	dst[offset++] = ENCODED_TAG_INT;
+	dst[offset++] = sLength;
+	if (sPadding < 0) {
+		dst[offset++] = 0;
+		signature.copy(dst, offset, paramBytes);
+	} else {
+		signature.copy(dst, offset, paramBytes + sPadding);
+	}
+
+	return dst;
+}
+
+module.exports = {
+	derToJose: derToJose,
+	joseToDer: joseToDer
+};
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/ecdsa-sig-formatter/src/param-bytes-for-alg.js b/KEMMessaging/node_modules/firebase-admin/node_modules/ecdsa-sig-formatter/src/param-bytes-for-alg.js
new file mode 100644
index 0000000000000000000000000000000000000000..9fe67accd9341e9f691f259397d9277bf6d66d00
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/ecdsa-sig-formatter/src/param-bytes-for-alg.js
@@ -0,0 +1,23 @@
+'use strict';
+
+function getParamSize(keySize) {
+	var result = ((keySize / 8) | 0) + (keySize % 8 === 0 ? 0 : 1);
+	return result;
+}
+
+var paramBytesForAlg = {
+	ES256: getParamSize(256),
+	ES384: getParamSize(384),
+	ES512: getParamSize(521)
+};
+
+function getParamBytesForAlg(alg) {
+	var paramBytes = paramBytesForAlg[alg];
+	if (paramBytes) {
+		return paramBytes;
+	}
+
+	throw new Error('Unknown algorithm "' + alg + '"');
+}
+
+module.exports = getParamBytesForAlg;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/CHANGELOG.md b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..73166328ea4c2894d132e461cf3c3434c5e78e0f
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/CHANGELOG.md
@@ -0,0 +1,107 @@
+### 0.9.3 / 2015-02-19
+
+* Make sure the TCP socket is not left open when closing the connection
+
+### 0.9.2 / 2014-12-21
+
+* Only emit `error` once, and don't emit it after `close`
+
+### 0.9.1 / 2014-12-18
+
+* Check that all options to the WebSocket constructor are recognized
+
+### 0.9.0 / 2014-12-13
+
+* Allow protocol extensions to be passed into websocket-extensions
+
+### 0.8.1 / 2014-11-12
+
+* Send the correct hostname when upgrading a connection to TLS
+
+### 0.8.0 / 2014-11-08
+
+* Support connections via HTTP proxies
+* Close the connection cleanly if we're still waiting for a handshake response
+
+### 0.7.3 / 2014-10-04
+
+* Allow sockets to be closed when they are in any state other than `CLOSED`
+
+### 0.7.2 / 2013-12-29
+
+* Make sure the `close` event is emitted by clients on Node v0.10
+
+### 0.7.1 / 2013-12-03
+
+* Support the `maxLength` websocket-driver option
+* Make the client emit `error` events on network errors
+
+### 0.7.0 / 2013-09-09
+
+* Allow the server to send custom headers with EventSource responses
+
+### 0.6.1 / 2013-07-05
+
+* Add `ca` option to the client for specifying certificate authorities
+* Start the server driver asynchronously so that `onopen` handlers can be added
+
+### 0.6.0 / 2013-05-12
+
+* Add support for custom headers
+
+### 0.5.0 / 2013-05-05
+
+* Extract the protocol handlers into the `websocket-driver` library
+* Support the Node streaming API
+
+### 0.4.4 / 2013-02-14
+
+* Emit the `close` event if TCP is closed before CLOSE frame is acked
+
+### 0.4.3 / 2012-07-09
+
+* Add `Connection: close` to EventSource response
+* Handle situations where `request.socket` is undefined
+
+### 0.4.2 / 2012-04-06
+
+* Add WebSocket error code `1011`.
+* Handle URLs with no path correctly by sending `GET /`
+
+### 0.4.1 / 2012-02-26
+
+* Treat anything other than a `Buffer` as a string when calling `send()`
+
+### 0.4.0 / 2012-02-13
+
+* Add `ping()` method to server-side `WebSocket` and `EventSource`
+* Buffer `send()` calls until the draft-76 handshake is complete
+* Fix HTTPS problems on Node 0.7
+
+### 0.3.1 / 2012-01-16
+
+* Call `setNoDelay(true)` on `net.Socket` objects to reduce latency
+
+### 0.3.0 / 2012-01-13
+
+* Add support for `EventSource` connections
+
+### 0.2.0 / 2011-12-21
+
+* Add support for `Sec-WebSocket-Protocol` negotiation
+* Support `hixie-76` close frames and 75/76 ignored segments
+* Improve performance of HyBi parsing/framing functions
+* Decouple parsers from TCP and reduce write volume
+
+### 0.1.2 / 2011-12-05
+
+* Detect closed sockets on the server side when TCP connection breaks
+* Make `hixie-76` sockets work through HAProxy
+
+### 0.1.1 / 2011-11-30
+
+* Fix `addEventListener()` interface methods
+
+### 0.1.0 / 2011-11-27
+
+* Initial release, based on WebSocket components from Faye
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/README.md b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..37ef1cd919146548c12f269fdcc9602fb1e2fe10
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/README.md
@@ -0,0 +1,335 @@
+# faye-websocket
+
+* Travis CI build: [![Build
+  status](https://secure.travis-ci.org/faye/faye-websocket-node.svg)](http://travis-ci.org/faye/faye-websocket-node)
+* Autobahn tests: [server](http://faye.jcoglan.com/autobahn/servers/),
+  [client](http://faye.jcoglan.com/autobahn/clients/)
+
+This is a general-purpose WebSocket implementation extracted from the
+[Faye](http://faye.jcoglan.com) project. It provides classes for easily building
+WebSocket servers and clients in Node. It does not provide a server itself, but
+rather makes it easy to handle WebSocket connections within an existing
+[Node](http://nodejs.org/) application. It does not provide any abstraction
+other than the standard [WebSocket API](http://dev.w3.org/html5/websockets/).
+
+It also provides an abstraction for handling
+[EventSource](http://dev.w3.org/html5/eventsource/) connections, which are
+one-way connections that allow the server to push data to the client. They are
+based on streaming HTTP responses and can be easier to access via proxies than
+WebSockets.
+
+
+## Installation
+
+```
+$ npm install faye-websocket
+```
+
+
+## Handling WebSocket connections in Node
+
+You can handle WebSockets on the server side by listening for HTTP Upgrade
+requests, and creating a new socket for the request. This socket object exposes
+the usual WebSocket methods for receiving and sending messages. For example this
+is how you'd implement an echo server:
+
+```js
+var WebSocket = require('faye-websocket'),
+    http      = require('http');
+
+var server = http.createServer();
+
+server.on('upgrade', function(request, socket, body) {
+  if (WebSocket.isWebSocket(request)) {
+    var ws = new WebSocket(request, socket, body);
+    
+    ws.on('message', function(event) {
+      ws.send(event.data);
+    });
+    
+    ws.on('close', function(event) {
+      console.log('close', event.code, event.reason);
+      ws = null;
+    });
+  }
+});
+
+server.listen(8000);
+```
+
+`WebSocket` objects are also duplex streams, so you could replace the
+`ws.on('message', ...)` line with:
+
+```js
+    ws.pipe(ws);
+```
+
+Note that under certain circumstances (notably a draft-76 client connecting
+through an HTTP proxy), the WebSocket handshake will not be complete after you
+call `new WebSocket()` because the server will not have received the entire
+handshake from the client yet. In this case, calls to `ws.send()` will buffer
+the message in memory until the handshake is complete, at which point any
+buffered messages will be sent to the client.
+
+If you need to detect when the WebSocket handshake is complete, you can use the
+`onopen` event.
+
+If the connection's protocol version supports it, you can call `ws.ping()` to
+send a ping message and wait for the client's response. This method takes a
+message string, and an optional callback that fires when a matching pong message
+is received. It returns `true` iff a ping message was sent. If the client does
+not support ping/pong, this method sends no data and returns `false`.
+
+```js
+ws.ping('Mic check, one, two', function() {
+  // fires when pong is received
+});
+```
+
+
+## Using the WebSocket client
+
+The client supports both the plain-text `ws` protocol and the encrypted `wss`
+protocol, and has exactly the same interface as a socket you would use in a web
+browser. On the wire it identifies itself as `hybi-13`.
+
+```js
+var WebSocket = require('faye-websocket'),
+    ws        = new WebSocket.Client('ws://www.example.com/');
+
+ws.on('open', function(event) {
+  console.log('open');
+  ws.send('Hello, world!');
+});
+
+ws.on('message', function(event) {
+  console.log('message', event.data);
+});
+
+ws.on('close', function(event) {
+  console.log('close', event.code, event.reason);
+  ws = null;
+});
+```
+
+The WebSocket client also lets you inspect the status and headers of the
+handshake response via its `statusCode` and `headers` properties.
+
+To connect via a proxy, set the `proxy` option to the HTTP origin of the proxy,
+including any authorization information, custom headers and TLS config you
+require. Only the `origin` setting is required.
+
+```js
+var ws = new WebSocket.Client('ws://www.example.com/', null, {
+  proxy: {
+    origin:  'http://username:password@proxy.example.com',
+    headers: {'User-Agent': 'node'},
+    tls:     {cert: fs.readFileSync('client.crt')}
+  }
+});
+```
+
+The `tls` value is a Node 'TLS options' object that will be passed to
+[`tls.connect()`](http://nodejs.org/api/tls.html#tls_tls_connect_options_callback).
+
+
+## Subprotocol negotiation
+
+The WebSocket protocol allows peers to select and identify the application
+protocol to use over the connection. On the client side, you can set which
+protocols the client accepts by passing a list of protocol names when you
+construct the socket:
+
+```js
+var ws = new WebSocket.Client('ws://www.example.com/', ['irc', 'amqp']);
+```
+
+On the server side, you can likewise pass in the list of protocols the server
+supports after the other constructor arguments:
+
+```js
+var ws = new WebSocket(request, socket, body, ['irc', 'amqp']);
+```
+
+If the client and server agree on a protocol, both the client- and server-side
+socket objects expose the selected protocol through the `ws.protocol` property.
+
+
+## Protocol extensions
+
+faye-websocket is based on the
+[websocket-extensions](https://github.com/faye/websocket-extensions-node)
+framework that allows extensions to be negotiated via the
+`Sec-WebSocket-Extensions` header. To add extensions to a connection, pass an
+array of extensions to the `:extensions` option. For example, to add
+[permessage-deflate](https://github.com/faye/permessage-deflate-node):
+
+```js
+var deflate = require('permessage-deflate');
+
+var ws = new WebSocket(request, socket, body, null, {extensions: [deflate]});
+```
+
+
+## Initialization options
+
+Both the server- and client-side classes allow an options object to be passed in
+at initialization time, for example:
+
+```js
+var ws = new WebSocket(request, socket, body, protocols, options);
+var ws = new WebSocket.Client(url, protocols, options);
+```
+
+`protocols` is an array of subprotocols as described above, or `null`.
+`options` is an optional object containing any of these fields:
+
+* `extensions` - an array of
+  [websocket-extensions](https://github.com/faye/websocket-extensions-node)
+  compatible extensions, as described above
+* `headers` - an object containing key-value pairs representing HTTP headers to
+  be sent during the handshake process
+* `maxLength` - the maximum allowed size of incoming message frames, in bytes.
+  The default value is `2^26 - 1`, or 1 byte short of 64 MiB.
+* `ping` - an integer that sets how often the WebSocket should send ping frames,
+  measured in seconds
+
+The client accepts some additional options:
+
+* `proxy` - settings for a proxy as described above
+* `tls` - a Node 'TLS options' object containing TLS settings for the origin
+  server, this will be passed to
+  [`tls.connect()`](http://nodejs.org/api/tls.html#tls_tls_connect_options_callback)
+* `ca` - (legacy) a shorthand for passing `{tls: {ca: value}}`
+
+
+## WebSocket API
+
+Both server- and client-side `WebSocket` objects support the following API.
+
+* <b>`on('open', function(event) {})`</b> fires when the socket connection is
+  established. Event has no attributes.
+* <b>`on('message', function(event) {})`</b> fires when the socket receives a
+  message. Event has one attribute, <b>`data`</b>, which is either a `String`
+  (for text frames) or a `Buffer` (for binary frames).
+* <b>`on('error', function(event) {})`</b> fires when there is a protocol error
+  due to bad data sent by the other peer. This event is purely informational,
+  you do not need to implement error recover.
+* <b>`on('close', function(event) {})`</b> fires when either the client or the
+  server closes the connection. Event has two optional attributes, <b>`code`</b>
+  and <b>`reason`</b>, that expose the status code and message sent by the peer
+  that closed the connection.
+* <b>`send(message)`</b> accepts either a `String` or a `Buffer` and sends a
+  text or binary message over the connection to the other peer.
+* <b>`ping(message = '', function() {})`</b> sends a ping frame with an optional
+  message and fires the callback when a matching pong is received.
+* <b>`close(code, reason)`</b> closes the connection, sending the given status
+  code and reason text, both of which are optional.
+* <b>`version`</b> is a string containing the version of the `WebSocket`
+  protocol the connection is using.
+* <b>`protocol`</b> is a string (which may be empty) identifying the subprotocol
+  the socket is using.
+
+
+## Handling EventSource connections in Node
+
+EventSource connections provide a very similar interface, although because they
+only allow the server to send data to the client, there is no `onmessage` API.
+EventSource allows the server to push text messages to the client, where each
+message has an optional event-type and ID.
+
+```js
+var WebSocket   = require('faye-websocket'),
+    EventSource = WebSocket.EventSource,
+    http        = require('http');
+
+var server = http.createServer();
+
+server.on('request', function(request, response) {
+  if (EventSource.isEventSource(request)) {
+    var es = new EventSource(request, response);
+    console.log('open', es.url, es.lastEventId);
+    
+    // Periodically send messages
+    var loop = setInterval(function() { es.send('Hello') }, 1000);
+    
+    es.on('close', function() {
+      clearInterval(loop);
+      es = null;
+    });
+  
+  } else {
+    // Normal HTTP request
+    response.writeHead(200, {'Content-Type': 'text/plain'});
+    response.end('Hello');
+  }
+});
+
+server.listen(8000);
+```
+
+The `send` method takes two optional parameters, `event` and `id`. The default
+event-type is `'message'` with no ID. For example, to send a `notification`
+event with ID `99`:
+
+```js
+es.send('Breaking News!', {event: 'notification', id: '99'});
+```
+
+The `EventSource` object exposes the following properties:
+
+* <b>`url`</b> is a string containing the URL the client used to create the
+  EventSource.
+* <b>`lastEventId`</b> is a string containing the last event ID received by the
+  client. You can use this when the client reconnects after a dropped connection
+  to determine which messages need resending.
+
+When you initialize an EventSource with ` new EventSource()`, you can pass
+configuration options after the `response` parameter. Available options are:
+
+* <b>`headers`</b> is an object containing custom headers to be set on the
+  EventSource response.
+* <b>`retry`</b> is a number that tells the client how long (in seconds) it
+  should wait after a dropped connection before attempting to reconnect.
+* <b>`ping`</b> is a number that tells the server how often (in seconds) to send
+  'ping' packets to the client to keep the connection open, to defeat timeouts
+  set by proxies. The client will ignore these messages.
+
+For example, this creates a connection that allows access from any origin, pings
+every 15 seconds and is retryable every 10 seconds if the connection is broken:
+
+```js
+var es = new EventSource(request, response, {
+  headers: {'Access-Control-Allow-Origin': '*'},
+  ping:    15,
+  retry:   10
+});
+```
+
+You can send a ping message at any time by calling `es.ping()`. Unlike
+WebSocket, the client does not send a response to this; it is merely to send
+some data over the wire to keep the connection alive.
+
+
+## License
+
+(The MIT License)
+
+Copyright (c) 2010-2015 James Coglan
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the 'Software'), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/examples/autobahn_client.js b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/examples/autobahn_client.js
new file mode 100644
index 0000000000000000000000000000000000000000..37965438b8c73dc8f4dc7f3e0f21f13f80cc0534
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/examples/autobahn_client.js
@@ -0,0 +1,39 @@
+var WebSocket = require('../lib/faye/websocket'),
+    deflate   = require('permessage-deflate'),
+    pace      = require('pace');
+
+var host    = 'ws://localhost:9001',
+    agent   = encodeURIComponent('node-' + process.version),
+    cases   = 0,
+    options = {extensions: [deflate]};
+
+var socket = new WebSocket.Client(host + '/getCaseCount'),
+    url, progress;
+
+socket.onmessage = function(event) {
+  console.log('Total cases to run: ' + event.data);
+  cases = parseInt(event.data);
+  progress = pace(cases);
+};
+
+var runCase = function(n) {
+  if (n > cases) {
+    url = host + '/updateReports?agent=' + agent;
+    socket = new WebSocket.Client(url);
+    socket.onclose = process.exit;
+    return;
+  }
+
+  url = host + '/runCase?case=' + n + '&agent=' + agent;
+  socket = new WebSocket.Client(url, null, options);
+  socket.pipe(socket);
+
+  socket.on('close', function() {
+    progress.op();
+    runCase(n + 1);
+  });
+};
+
+socket.onclose = function() {
+  runCase(1);
+};
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/examples/client.js b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/examples/client.js
new file mode 100644
index 0000000000000000000000000000000000000000..a500f379b133106ee1e2a9bb5868b7d6445d6067
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/examples/client.js
@@ -0,0 +1,25 @@
+var WebSocket = require('../lib/faye/websocket'),
+    fs = require('fs');
+
+var url     = process.argv[2],
+    headers = {Origin: 'http://faye.jcoglan.com'},
+    ca      = fs.readFileSync(__dirname + '/../spec/server.crt'),
+    proxy   = {origin: process.argv[3], headers: {'User-Agent': 'Echo'}, tls: {ca: ca}},
+    ws      = new WebSocket.Client(url, null, {headers: headers, proxy: proxy, tls: {ca: ca}});
+
+ws.onopen = function() {
+  console.log('[open]', ws.headers);
+  ws.send('mic check');
+};
+
+ws.onclose = function(close) {
+  console.log('[close]', close.code, close.reason);
+};
+
+ws.onerror = function(error) {
+  console.log('[error]', error.message);
+};
+
+ws.onmessage = function(message) {
+  console.log('[message]', message.data);
+};
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/examples/haproxy.conf b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/examples/haproxy.conf
new file mode 100644
index 0000000000000000000000000000000000000000..bb7bc9d5b56315663764a4bada353eace90d2be6
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/examples/haproxy.conf
@@ -0,0 +1,20 @@
+defaults
+   mode http
+   timeout client  5s
+   timeout connect 5s
+   timeout server  5s
+
+frontend all 0.0.0.0:3000
+   mode http
+   timeout client 120s
+
+   option forwardfor
+   option http-server-close
+   option http-pretend-keepalive
+
+   default_backend sockets
+
+backend sockets
+   balance uri depth 2
+   timeout server  120s
+   server socket1 127.0.0.1:7000
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/examples/proxy_server.js b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/examples/proxy_server.js
new file mode 100644
index 0000000000000000000000000000000000000000..5780440bca3fa33a159b95c2d8c36682c39cf9d2
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/examples/proxy_server.js
@@ -0,0 +1,7 @@
+var ProxyServer = require('../spec/proxy_server');
+
+var port   = process.argv[2],
+    secure = process.argv[3] === 'tls',
+    proxy  = new ProxyServer({debug: true, tls: secure});
+
+proxy.listen(port);
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/examples/server.js b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/examples/server.js
new file mode 100644
index 0000000000000000000000000000000000000000..6e5abf1ae0d49daff63c6b0911dcaac354eb094c
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/examples/server.js
@@ -0,0 +1,69 @@
+var WebSocket = require('../lib/faye/websocket'),
+    deflate   = require('permessage-deflate'),
+    fs        = require('fs'),
+    http      = require('http'),
+    https     = require('https');
+
+var port    = process.argv[2] || 7000,
+    secure  = process.argv[3] === 'tls',
+    options = {extensions: [deflate], ping: 5};
+
+var upgradeHandler = function(request, socket, head) {
+  var ws = new WebSocket(request, socket, head, ['irc', 'xmpp'], options);
+  console.log('[open]', ws.url, ws.version, ws.protocol, request.headers);
+
+  ws.pipe(ws);
+
+  ws.onclose = function(event) {
+    console.log('[close]', event.code, event.reason);
+    ws = null;
+  };
+};
+
+var requestHandler = function(request, response) {
+  if (!WebSocket.EventSource.isEventSource(request))
+    return staticHandler(request, response);
+
+  var es   = new WebSocket.EventSource(request, response),
+      time = parseInt(es.lastEventId, 10) || 0;
+
+  console.log('[open]', es.url, es.lastEventId);
+
+  var loop = setInterval(function() {
+    time += 1;
+    es.send('Time: ' + time);
+    setTimeout(function() {
+      if (es) es.send('Update!!', {event: 'update', id: time});
+    }, 1000);
+  }, 2000);
+
+  fs.createReadStream(__dirname + '/haproxy.conf').pipe(es, {end: false});
+
+  es.onclose = function() {
+    clearInterval(loop);
+    console.log('[close]', es.url);
+    es = null;
+  };
+};
+
+var staticHandler = function(request, response) {
+  var path = request.url;
+
+  fs.readFile(__dirname + path, function(err, content) {
+    var status = err ? 404 : 200;
+    response.writeHead(status, {'Content-Type': 'text/html'});
+    response.write(content || 'Not found');
+    response.end();
+  });
+};
+
+var server = secure
+           ? https.createServer({
+               key:  fs.readFileSync(__dirname + '/../spec/server.key'),
+               cert: fs.readFileSync(__dirname + '/../spec/server.crt')
+             })
+           : http.createServer();
+
+server.on('request', requestHandler);
+server.on('upgrade', upgradeHandler);
+server.listen(port);
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/examples/sse.html b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/examples/sse.html
new file mode 100644
index 0000000000000000000000000000000000000000..e11a911469bc8447b883b25f577d7a4b5fb66be5
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/examples/sse.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<html>
+  <head>
+    <meta http-equiv="Content-type" content="text/html; charset=utf-8">
+    <title>EventSource test</title>
+  </head>
+  <body>
+
+    <h1>EventSource test</h1>
+    <ul></ul>
+
+    <script type="text/javascript">
+      var logger = document.getElementsByTagName('ul')[0],
+          socket = new EventSource('/');
+
+      var log = function(text) {
+        logger.innerHTML += '<li>' + text + '</li>';
+      };
+
+      socket.onopen = function() {
+        log('OPEN');
+      };
+
+      socket.onmessage = function(event) {
+        log('MESSAGE: ' + event.data);
+      };
+
+      socket.addEventListener('update', function(event) {
+        log('UPDATE(' + event.lastEventId + '): ' + event.data);
+      });
+
+      socket.onerror = function(event) {
+        log('ERROR: ' + event.message);
+      };
+    </script>
+
+  </body>
+</html>
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/examples/ws.html b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/examples/ws.html
new file mode 100644
index 0000000000000000000000000000000000000000..883cdede4d6a5f32634cc9a5737ecdd743af1e6d
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/examples/ws.html
@@ -0,0 +1,43 @@
+<!doctype html>
+<html>
+  <head>
+    <meta http-equiv="Content-type" content="text/html; charset=utf-8">
+    <title>WebSocket test</title>
+  </head>
+  <body>
+
+    <h1>WebSocket test</h1>
+    <ul></ul>
+
+    <script type="text/javascript">
+      var logger = document.getElementsByTagName('ul')[0],
+          Socket = window.MozWebSocket || window.WebSocket,
+          protos = ['foo', 'bar', 'xmpp'],
+          socket = new Socket('ws://' + location.hostname + ':' + location.port + '/', protos),
+          index  = 0;
+
+      var log = function(text) {
+        logger.innerHTML += '<li>' + text + '</li>';
+      };
+
+      socket.addEventListener('open', function() {
+        log('OPEN: ' + socket.protocol);
+        socket.send('Hello, world');
+      });
+
+      socket.onerror = function(event) {
+        log('ERROR: ' + event.message);
+      };
+
+      socket.onmessage = function(event) {
+        log('MESSAGE: ' + event.data);
+        setTimeout(function() { socket.send(++index + ' ' + event.data) }, 2000);
+      };
+
+      socket.onclose = function(event) {
+        log('CLOSE: ' + event.code + ', ' + event.reason);
+      };
+    </script>
+
+  </body>
+</html>
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/lib/faye/eventsource.js b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/lib/faye/eventsource.js
new file mode 100644
index 0000000000000000000000000000000000000000..6e3f370dc9243d9076236c0399857c0914f123bf
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/lib/faye/eventsource.js
@@ -0,0 +1,131 @@
+var Stream      = require('stream').Stream,
+    util        = require('util'),
+    driver      = require('websocket-driver'),
+    Headers     = require('websocket-driver/lib/websocket/driver/headers'),
+    API         = require('./websocket/api'),
+    EventTarget = require('./websocket/api/event_target'),
+    Event       = require('./websocket/api/event');
+
+var EventSource = function(request, response, options) {
+  this.writable = true;
+  options = options || {};
+
+  this._stream = response.socket;
+  this._ping   = options.ping  || this.DEFAULT_PING;
+  this._retry  = options.retry || this.DEFAULT_RETRY;
+
+  var scheme       = driver.isSecureRequest(request) ? 'https:' : 'http:';
+  this.url         = scheme + '//' + request.headers.host + request.url;
+  this.lastEventId = request.headers['last-event-id'] || '';
+  this.readyState  = API.CONNECTING;
+
+  var headers = new Headers(),
+      self    = this;
+
+  if (options.headers) {
+    for (var key in options.headers) headers.set(key, options.headers[key]);
+  }
+
+  if (!this._stream || !this._stream.writable) return;
+  process.nextTick(function() { self._open() });
+
+  this._stream.setTimeout(0);
+  this._stream.setNoDelay(true);
+
+  var handshake = 'HTTP/1.1 200 OK\r\n' +
+                  'Content-Type: text/event-stream\r\n' +
+                  'Cache-Control: no-cache, no-store\r\n' +
+                  'Connection: close\r\n' +
+                  headers.toString() +
+                  '\r\n' +
+                  'retry: ' + Math.floor(this._retry * 1000) + '\r\n\r\n';
+
+  this._write(handshake);
+
+  this._stream.on('drain', function() { self.emit('drain') });
+
+  if (this._ping)
+    this._pingTimer = setInterval(function() { self.ping() }, this._ping * 1000);
+
+  ['error', 'end'].forEach(function(event) {
+    self._stream.on(event, function() { self.close() });
+  });
+};
+util.inherits(EventSource, Stream);
+
+EventSource.isEventSource = function(request) {
+  if (request.method !== 'GET') return false;
+  var accept = (request.headers.accept || '').split(/\s*,\s*/);
+  return accept.indexOf('text/event-stream') >= 0;
+};
+
+var instance = {
+  DEFAULT_PING:   10,
+  DEFAULT_RETRY:  5,
+
+  _write: function(chunk) {
+    if (!this.writable) return false;
+    try {
+      return this._stream.write(chunk, 'utf8');
+    } catch (e) {
+      return false;
+    }
+  },
+
+  _open: function() {
+    if (this.readyState !== API.CONNECTING) return;
+
+    this.readyState = API.OPEN;
+
+    var event = new Event('open');
+    event.initEvent('open', false, false);
+    this.dispatchEvent(event);
+  },
+
+  write: function(message) {
+    return this.send(message);
+  },
+
+  end: function(message) {
+    if (message !== undefined) this.write(message);
+    this.close();
+  },
+
+  send: function(message, options) {
+    if (this.readyState > API.OPEN) return false;
+
+    message = String(message).replace(/(\r\n|\r|\n)/g, '$1data: ');
+    options = options || {};
+
+    var frame = '';
+    if (options.event) frame += 'event: ' + options.event + '\r\n';
+    if (options.id)    frame += 'id: '    + options.id    + '\r\n';
+    frame += 'data: ' + message + '\r\n\r\n';
+
+    return this._write(frame);
+  },
+
+  ping: function() {
+    return this._write(':\r\n\r\n');
+  },
+
+  close: function() {
+    if (this.readyState > API.OPEN) return false;
+
+    this.readyState = API.CLOSED;
+    this.writable = false;
+    if (this._pingTimer) clearInterval(this._pingTimer);
+    if (this._stream) this._stream.end();
+
+    var event = new Event('close');
+    event.initEvent('close', false, false);
+    this.dispatchEvent(event);
+
+    return true;
+  }
+};
+
+for (var method in instance) EventSource.prototype[method] = instance[method];
+for (var key in EventTarget) EventSource.prototype[key] = EventTarget[key];
+
+module.exports = EventSource;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/lib/faye/websocket.js b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/lib/faye/websocket.js
new file mode 100644
index 0000000000000000000000000000000000000000..9841c82150b683da1f964802fe0a79daff8fb0d6
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/lib/faye/websocket.js
@@ -0,0 +1,45 @@
+// API references:
+//
+// * http://dev.w3.org/html5/websockets/
+// * http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#interface-eventtarget
+// * http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#interface-event
+
+var util   = require('util'),
+    driver = require('websocket-driver'),
+    API    = require('./websocket/api');
+
+var WebSocket = function(request, socket, body, protocols, options) {
+  options = options || {};
+
+  this._stream = socket;
+  this._driver = driver.http(request, {maxLength: options.maxLength, protocols: protocols});
+
+  var self = this;
+  if (!this._stream || !this._stream.writable) return;
+  if (!this._stream.readable) return this._stream.end();
+
+  var catchup = function() { self._stream.removeListener('data', catchup) };
+  this._stream.on('data', catchup);
+
+  this._driver.io.write(body);
+  API.call(this, options);
+
+  process.nextTick(function() {
+    self._driver.start();
+  });
+};
+util.inherits(WebSocket, API);
+
+WebSocket.isWebSocket = function(request) {
+  return driver.isWebSocket(request);
+};
+
+WebSocket.validateOptions = function(options, validKeys) {
+  driver.validateOptions(options, validKeys);
+};
+
+WebSocket.WebSocket   = WebSocket;
+WebSocket.Client      = require('./websocket/client');
+WebSocket.EventSource = require('./eventsource');
+
+module.exports        = WebSocket;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/lib/faye/websocket/api.js b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/lib/faye/websocket/api.js
new file mode 100644
index 0000000000000000000000000000000000000000..347233f13eb8151b83f02362140716142f549a44
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/lib/faye/websocket/api.js
@@ -0,0 +1,178 @@
+var Stream      = require('stream').Stream,
+    util        = require('util'),
+    driver      = require('websocket-driver'),
+    EventTarget = require('./api/event_target'),
+    Event       = require('./api/event');
+
+var API = function(options) {
+  options = options || {};
+  driver.validateOptions(options, ['headers', 'extensions', 'maxLength', 'ping', 'proxy', 'tls', 'ca']);
+
+  this.readable = this.writable = true;
+
+  var headers = options.headers;
+  if (headers) {
+    for (var name in headers) this._driver.setHeader(name, headers[name]);
+  }
+
+  var extensions = options.extensions;
+  if (extensions) {
+    [].concat(extensions).forEach(this._driver.addExtension, this._driver);
+  }
+
+  this._ping          = options.ping;
+  this._pingId        = 0;
+  this.readyState     = API.CONNECTING;
+  this.bufferedAmount = 0;
+  this.protocol       = '';
+  this.url            = this._driver.url;
+  this.version        = this._driver.version;
+
+  var self = this;
+
+  this._driver.on('open',    function(e) { self._open() });
+  this._driver.on('message', function(e) { self._receiveMessage(e.data) });
+  this._driver.on('close',   function(e) { self._beginClose(e.reason, e.code) });
+
+  this._driver.on('error', function(error) {
+    self._emitError(error.message);
+  });
+  this.on('error', function() {});
+
+  this._driver.messages.on('drain', function() {
+    self.emit('drain');
+  });
+
+  if (this._ping)
+    this._pingTimer = setInterval(function() {
+      self._pingId += 1;
+      self.ping(self._pingId.toString());
+    }, this._ping * 1000);
+
+  this._configureStream();
+
+  if (!this._proxy) {
+    this._stream.pipe(this._driver.io);
+    this._driver.io.pipe(this._stream);
+  }
+};
+util.inherits(API, Stream);
+
+API.CONNECTING = 0;
+API.OPEN       = 1;
+API.CLOSING    = 2;
+API.CLOSED     = 3;
+
+var instance = {
+  write: function(data) {
+    return this.send(data);
+  },
+
+  end: function(data) {
+    if (data !== undefined) this.send(data);
+    this.close();
+  },
+
+  pause: function() {
+    return this._driver.messages.pause();
+  },
+
+  resume: function() {
+    return this._driver.messages.resume();
+  },
+
+  send: function(data) {
+    if (this.readyState > API.OPEN) return false;
+    if (!(data instanceof Buffer)) data = String(data);
+    return this._driver.messages.write(data);
+  },
+
+  ping: function(message, callback) {
+    if (this.readyState > API.OPEN) return false;
+    return this._driver.ping(message, callback);
+  },
+
+  close: function() {
+    if (this.readyState !== API.CLOSED) this.readyState = API.CLOSING;
+    this._driver.close();
+  },
+
+  _configureStream: function() {
+    var self = this;
+
+    this._stream.setTimeout(0);
+    this._stream.setNoDelay(true);
+
+    ['close', 'end'].forEach(function(event) {
+      this._stream.on(event, function() { self._finalizeClose() });
+    }, this);
+
+    this._stream.on('error', function(error) {
+      self._emitError('Network error: ' + self.url + ': ' + error.message);
+      self._finalizeClose();
+    });
+  },
+
+ _open: function() {
+    if (this.readyState !== API.CONNECTING) return;
+
+    this.readyState = API.OPEN;
+    this.protocol = this._driver.protocol || '';
+
+    var event = new Event('open');
+    event.initEvent('open', false, false);
+    this.dispatchEvent(event);
+  },
+
+  _receiveMessage: function(data) {
+    if (this.readyState > API.OPEN) return false;
+
+    if (this.readable) this.emit('data', data);
+
+    var event = new Event('message', {data: data});
+    event.initEvent('message', false, false);
+    this.dispatchEvent(event);
+  },
+
+  _emitError: function(message) {
+    if (this.readyState >= API.CLOSING) return;
+
+    var event = new Event('error', {message: message});
+    event.initEvent('error', false, false);
+    this.dispatchEvent(event);
+  },
+
+  _beginClose: function(reason, code) {
+    if (this.readyState === API.CLOSED) return;
+    this.readyState = API.CLOSING;
+
+    if (this._stream) {
+      this._stream.end();
+      if (!this._stream.readable) this._finalizeClose();
+    }
+    this._closeParams = [reason, code];
+  },
+
+  _finalizeClose: function() {
+    if (this.readyState === API.CLOSED) return;
+    this.readyState = API.CLOSED;
+
+    if (this._pingTimer) clearInterval(this._pingTimer);
+    if (this._stream) this._stream.end();
+
+    if (this.readable) this.emit('end');
+    this.readable = this.writable = false;
+
+    var reason = this._closeParams ? this._closeParams[0] : '',
+        code   = this._closeParams ? this._closeParams[1] : 1006;
+
+    var event = new Event('close', {code: code, reason: reason});
+    event.initEvent('close', false, false);
+    this.dispatchEvent(event);
+  }
+};
+
+for (var method in instance) API.prototype[method] = instance[method];
+for (var key in EventTarget) API.prototype[key] = EventTarget[key];
+
+module.exports = API;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/lib/faye/websocket/api/event.js b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/lib/faye/websocket/api/event.js
new file mode 100644
index 0000000000000000000000000000000000000000..384458095317ee277b2a0f69d8a5234ff3c1f95d
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/lib/faye/websocket/api/event.js
@@ -0,0 +1,20 @@
+var Event = function(eventType, options) {
+  this.type = eventType;
+  for (var key in options)
+    this[key] = options[key];
+};
+
+Event.prototype.initEvent = function(eventType, canBubble, cancelable) {
+  this.type       = eventType;
+  this.bubbles    = canBubble;
+  this.cancelable = cancelable;
+};
+
+Event.prototype.stopPropagation = function() {};
+Event.prototype.preventDefault  = function() {};
+
+Event.CAPTURING_PHASE = 1;
+Event.AT_TARGET       = 2;
+Event.BUBBLING_PHASE  = 3;
+
+module.exports = Event;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/lib/faye/websocket/api/event_target.js b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/lib/faye/websocket/api/event_target.js
new file mode 100644
index 0000000000000000000000000000000000000000..6c4b8697714d627bc7932e4e2a674e298dc4f6e9
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/lib/faye/websocket/api/event_target.js
@@ -0,0 +1,28 @@
+var Event = require('./event');
+
+var EventTarget = {
+  onopen:     null,
+  onmessage:  null,
+  onerror:    null,
+  onclose:    null,
+
+  addEventListener: function(eventType, listener, useCapture) {
+    this.on(eventType, listener);
+  },
+
+  removeEventListener: function(eventType, listener, useCapture) {
+    this.removeListener(eventType, listener);
+  },
+
+  dispatchEvent: function(event) {
+    event.target = event.currentTarget = this;
+    event.eventPhase = Event.AT_TARGET;
+
+    if (this['on' + event.type])
+      this['on' + event.type](event);
+
+    this.emit(event.type, event);
+  }
+};
+
+module.exports = EventTarget;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/lib/faye/websocket/client.js b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/lib/faye/websocket/client.js
new file mode 100644
index 0000000000000000000000000000000000000000..7974119f55890a66e76c31eca6b74dedec5db408
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/lib/faye/websocket/client.js
@@ -0,0 +1,84 @@
+var util   = require('util'),
+    net    = require('net'),
+    tls    = require('tls'),
+    crypto = require('crypto'),
+    url    = require('url'),
+    driver = require('websocket-driver'),
+    API    = require('./api'),
+    Event  = require('./api/event');
+
+var DEFAULT_PORTS    = {'http:': 80, 'https:': 443, 'ws:':80, 'wss:': 443},
+    SECURE_PROTOCOLS = ['https:', 'wss:'];
+
+var Client = function(_url, protocols, options) {
+  options = options || {};
+
+  this.url     = _url;
+  this._driver = driver.client(this.url, {maxLength: options.maxLength, protocols: protocols});
+
+  ['open', 'error'].forEach(function(event) {
+    this._driver.on(event, function() {
+      self.headers    = self._driver.headers;
+      self.statusCode = self._driver.statusCode;
+    });
+  }, this);
+
+  var proxy     = options.proxy || {},
+      endpoint  = url.parse(proxy.origin || this.url),
+      port      = endpoint.port || DEFAULT_PORTS[endpoint.protocol],
+      secure    = SECURE_PROTOCOLS.indexOf(endpoint.protocol) >= 0,
+      onConnect = function() { self._onConnect() },
+      originTLS = options.tls || {},
+      socketTLS = proxy.origin ? (proxy.tls || {}) : originTLS,
+      self      = this;
+
+  originTLS.ca = originTLS.ca || options.ca;
+
+  this._stream = secure
+               ? tls.connect(port, endpoint.hostname, socketTLS, onConnect)
+               : net.connect(port, endpoint.hostname, onConnect);
+
+  if (proxy.origin) this._configureProxy(proxy, originTLS);
+
+  API.call(this, options);
+};
+util.inherits(Client, API);
+
+Client.prototype._onConnect = function() {
+  var worker = this._proxy || this._driver;
+  worker.start();
+};
+
+Client.prototype._configureProxy = function(proxy, originTLS) {
+  var uri    = url.parse(this.url),
+      secure = SECURE_PROTOCOLS.indexOf(uri.protocol) >= 0,
+      self   = this,
+      name;
+
+  this._proxy = this._driver.proxy(proxy.origin);
+
+  if (proxy.headers) {
+    for (name in proxy.headers) this._proxy.setHeader(name, proxy.headers[name]);
+  }
+
+  this._proxy.pipe(this._stream, {end: false});
+  this._stream.pipe(this._proxy);
+
+  this._proxy.on('connect', function() {
+    if (secure) {
+      var options = {socket: self._stream, servername: uri.hostname};
+      for (name in originTLS) options[name] = originTLS[name];
+      self._stream = tls.connect(options);
+      self._configureStream();
+    }
+    self._driver.io.pipe(self._stream);
+    self._stream.pipe(self._driver.io);
+    self._driver.start();
+  });
+
+  this._proxy.on('error', function(error) {
+    self._driver.emit('error', error);
+  });
+};
+
+module.exports = Client;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/package.json b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..c0ee85aba2daaac587b21bda93584d72ba45ed04
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/faye-websocket/package.json
@@ -0,0 +1,77 @@
+{
+  "_args": [
+    [
+      {
+        "raw": "faye-websocket@https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.9.3.tgz",
+        "scope": null,
+        "escapedName": "faye-websocket",
+        "name": "faye-websocket",
+        "rawSpec": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.9.3.tgz",
+        "spec": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.9.3.tgz",
+        "type": "remote"
+      },
+      "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin"
+    ]
+  ],
+  "_from": "faye-websocket@0.9.3",
+  "_id": "faye-websocket@0.9.3",
+  "_inCache": true,
+  "_location": "/firebase-admin/faye-websocket",
+  "_phantomChildren": {},
+  "_requested": {
+    "raw": "faye-websocket@https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.9.3.tgz",
+    "scope": null,
+    "escapedName": "faye-websocket",
+    "name": "faye-websocket",
+    "rawSpec": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.9.3.tgz",
+    "spec": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.9.3.tgz",
+    "type": "remote"
+  },
+  "_requiredBy": [
+    "/firebase-admin"
+  ],
+  "_resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.9.3.tgz",
+  "_shasum": "482a505b0df0ae626b969866d3bd740cdb962e83",
+  "_shrinkwrap": null,
+  "_spec": "faye-websocket@https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.9.3.tgz",
+  "_where": "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin",
+  "author": {
+    "name": "James Coglan",
+    "email": "jcoglan@gmail.com",
+    "url": "http://jcoglan.com/"
+  },
+  "bugs": {
+    "url": "http://github.com/faye/faye-websocket-node/issues"
+  },
+  "dependencies": {
+    "websocket-driver": ">=0.5.1"
+  },
+  "description": "Standards-compliant WebSocket server and client",
+  "devDependencies": {
+    "jstest": "",
+    "pace": "",
+    "permessage-deflate": ""
+  },
+  "engines": {
+    "node": ">=0.4.0"
+  },
+  "homepage": "http://github.com/faye/faye-websocket-node",
+  "keywords": [
+    "websocket",
+    "eventsource"
+  ],
+  "license": "MIT",
+  "main": "./lib/faye/websocket",
+  "name": "faye-websocket",
+  "optionalDependencies": {},
+  "readme": "# faye-websocket\n\n* Travis CI build: [![Build\n  status](https://secure.travis-ci.org/faye/faye-websocket-node.svg)](http://travis-ci.org/faye/faye-websocket-node)\n* Autobahn tests: [server](http://faye.jcoglan.com/autobahn/servers/),\n  [client](http://faye.jcoglan.com/autobahn/clients/)\n\nThis is a general-purpose WebSocket implementation extracted from the\n[Faye](http://faye.jcoglan.com) project. It provides classes for easily building\nWebSocket servers and clients in Node. It does not provide a server itself, but\nrather makes it easy to handle WebSocket connections within an existing\n[Node](http://nodejs.org/) application. It does not provide any abstraction\nother than the standard [WebSocket API](http://dev.w3.org/html5/websockets/).\n\nIt also provides an abstraction for handling\n[EventSource](http://dev.w3.org/html5/eventsource/) connections, which are\none-way connections that allow the server to push data to the client. They are\nbased on streaming HTTP responses and can be easier to access via proxies than\nWebSockets.\n\n\n## Installation\n\n```\n$ npm install faye-websocket\n```\n\n\n## Handling WebSocket connections in Node\n\nYou can handle WebSockets on the server side by listening for HTTP Upgrade\nrequests, and creating a new socket for the request. This socket object exposes\nthe usual WebSocket methods for receiving and sending messages. For example this\nis how you'd implement an echo server:\n\n```js\nvar WebSocket = require('faye-websocket'),\n    http      = require('http');\n\nvar server = http.createServer();\n\nserver.on('upgrade', function(request, socket, body) {\n  if (WebSocket.isWebSocket(request)) {\n    var ws = new WebSocket(request, socket, body);\n    \n    ws.on('message', function(event) {\n      ws.send(event.data);\n    });\n    \n    ws.on('close', function(event) {\n      console.log('close', event.code, event.reason);\n      ws = null;\n    });\n  }\n});\n\nserver.listen(8000);\n```\n\n`WebSocket` objects are also duplex streams, so you could replace the\n`ws.on('message', ...)` line with:\n\n```js\n    ws.pipe(ws);\n```\n\nNote that under certain circumstances (notably a draft-76 client connecting\nthrough an HTTP proxy), the WebSocket handshake will not be complete after you\ncall `new WebSocket()` because the server will not have received the entire\nhandshake from the client yet. In this case, calls to `ws.send()` will buffer\nthe message in memory until the handshake is complete, at which point any\nbuffered messages will be sent to the client.\n\nIf you need to detect when the WebSocket handshake is complete, you can use the\n`onopen` event.\n\nIf the connection's protocol version supports it, you can call `ws.ping()` to\nsend a ping message and wait for the client's response. This method takes a\nmessage string, and an optional callback that fires when a matching pong message\nis received. It returns `true` iff a ping message was sent. If the client does\nnot support ping/pong, this method sends no data and returns `false`.\n\n```js\nws.ping('Mic check, one, two', function() {\n  // fires when pong is received\n});\n```\n\n\n## Using the WebSocket client\n\nThe client supports both the plain-text `ws` protocol and the encrypted `wss`\nprotocol, and has exactly the same interface as a socket you would use in a web\nbrowser. On the wire it identifies itself as `hybi-13`.\n\n```js\nvar WebSocket = require('faye-websocket'),\n    ws        = new WebSocket.Client('ws://www.example.com/');\n\nws.on('open', function(event) {\n  console.log('open');\n  ws.send('Hello, world!');\n});\n\nws.on('message', function(event) {\n  console.log('message', event.data);\n});\n\nws.on('close', function(event) {\n  console.log('close', event.code, event.reason);\n  ws = null;\n});\n```\n\nThe WebSocket client also lets you inspect the status and headers of the\nhandshake response via its `statusCode` and `headers` properties.\n\nTo connect via a proxy, set the `proxy` option to the HTTP origin of the proxy,\nincluding any authorization information, custom headers and TLS config you\nrequire. Only the `origin` setting is required.\n\n```js\nvar ws = new WebSocket.Client('ws://www.example.com/', null, {\n  proxy: {\n    origin:  'http://username:password@proxy.example.com',\n    headers: {'User-Agent': 'node'},\n    tls:     {cert: fs.readFileSync('client.crt')}\n  }\n});\n```\n\nThe `tls` value is a Node 'TLS options' object that will be passed to\n[`tls.connect()`](http://nodejs.org/api/tls.html#tls_tls_connect_options_callback).\n\n\n## Subprotocol negotiation\n\nThe WebSocket protocol allows peers to select and identify the application\nprotocol to use over the connection. On the client side, you can set which\nprotocols the client accepts by passing a list of protocol names when you\nconstruct the socket:\n\n```js\nvar ws = new WebSocket.Client('ws://www.example.com/', ['irc', 'amqp']);\n```\n\nOn the server side, you can likewise pass in the list of protocols the server\nsupports after the other constructor arguments:\n\n```js\nvar ws = new WebSocket(request, socket, body, ['irc', 'amqp']);\n```\n\nIf the client and server agree on a protocol, both the client- and server-side\nsocket objects expose the selected protocol through the `ws.protocol` property.\n\n\n## Protocol extensions\n\nfaye-websocket is based on the\n[websocket-extensions](https://github.com/faye/websocket-extensions-node)\nframework that allows extensions to be negotiated via the\n`Sec-WebSocket-Extensions` header. To add extensions to a connection, pass an\narray of extensions to the `:extensions` option. For example, to add\n[permessage-deflate](https://github.com/faye/permessage-deflate-node):\n\n```js\nvar deflate = require('permessage-deflate');\n\nvar ws = new WebSocket(request, socket, body, null, {extensions: [deflate]});\n```\n\n\n## Initialization options\n\nBoth the server- and client-side classes allow an options object to be passed in\nat initialization time, for example:\n\n```js\nvar ws = new WebSocket(request, socket, body, protocols, options);\nvar ws = new WebSocket.Client(url, protocols, options);\n```\n\n`protocols` is an array of subprotocols as described above, or `null`.\n`options` is an optional object containing any of these fields:\n\n* `extensions` - an array of\n  [websocket-extensions](https://github.com/faye/websocket-extensions-node)\n  compatible extensions, as described above\n* `headers` - an object containing key-value pairs representing HTTP headers to\n  be sent during the handshake process\n* `maxLength` - the maximum allowed size of incoming message frames, in bytes.\n  The default value is `2^26 - 1`, or 1 byte short of 64 MiB.\n* `ping` - an integer that sets how often the WebSocket should send ping frames,\n  measured in seconds\n\nThe client accepts some additional options:\n\n* `proxy` - settings for a proxy as described above\n* `tls` - a Node 'TLS options' object containing TLS settings for the origin\n  server, this will be passed to\n  [`tls.connect()`](http://nodejs.org/api/tls.html#tls_tls_connect_options_callback)\n* `ca` - (legacy) a shorthand for passing `{tls: {ca: value}}`\n\n\n## WebSocket API\n\nBoth server- and client-side `WebSocket` objects support the following API.\n\n* <b>`on('open', function(event) {})`</b> fires when the socket connection is\n  established. Event has no attributes.\n* <b>`on('message', function(event) {})`</b> fires when the socket receives a\n  message. Event has one attribute, <b>`data`</b>, which is either a `String`\n  (for text frames) or a `Buffer` (for binary frames).\n* <b>`on('error', function(event) {})`</b> fires when there is a protocol error\n  due to bad data sent by the other peer. This event is purely informational,\n  you do not need to implement error recover.\n* <b>`on('close', function(event) {})`</b> fires when either the client or the\n  server closes the connection. Event has two optional attributes, <b>`code`</b>\n  and <b>`reason`</b>, that expose the status code and message sent by the peer\n  that closed the connection.\n* <b>`send(message)`</b> accepts either a `String` or a `Buffer` and sends a\n  text or binary message over the connection to the other peer.\n* <b>`ping(message = '', function() {})`</b> sends a ping frame with an optional\n  message and fires the callback when a matching pong is received.\n* <b>`close(code, reason)`</b> closes the connection, sending the given status\n  code and reason text, both of which are optional.\n* <b>`version`</b> is a string containing the version of the `WebSocket`\n  protocol the connection is using.\n* <b>`protocol`</b> is a string (which may be empty) identifying the subprotocol\n  the socket is using.\n\n\n## Handling EventSource connections in Node\n\nEventSource connections provide a very similar interface, although because they\nonly allow the server to send data to the client, there is no `onmessage` API.\nEventSource allows the server to push text messages to the client, where each\nmessage has an optional event-type and ID.\n\n```js\nvar WebSocket   = require('faye-websocket'),\n    EventSource = WebSocket.EventSource,\n    http        = require('http');\n\nvar server = http.createServer();\n\nserver.on('request', function(request, response) {\n  if (EventSource.isEventSource(request)) {\n    var es = new EventSource(request, response);\n    console.log('open', es.url, es.lastEventId);\n    \n    // Periodically send messages\n    var loop = setInterval(function() { es.send('Hello') }, 1000);\n    \n    es.on('close', function() {\n      clearInterval(loop);\n      es = null;\n    });\n  \n  } else {\n    // Normal HTTP request\n    response.writeHead(200, {'Content-Type': 'text/plain'});\n    response.end('Hello');\n  }\n});\n\nserver.listen(8000);\n```\n\nThe `send` method takes two optional parameters, `event` and `id`. The default\nevent-type is `'message'` with no ID. For example, to send a `notification`\nevent with ID `99`:\n\n```js\nes.send('Breaking News!', {event: 'notification', id: '99'});\n```\n\nThe `EventSource` object exposes the following properties:\n\n* <b>`url`</b> is a string containing the URL the client used to create the\n  EventSource.\n* <b>`lastEventId`</b> is a string containing the last event ID received by the\n  client. You can use this when the client reconnects after a dropped connection\n  to determine which messages need resending.\n\nWhen you initialize an EventSource with ` new EventSource()`, you can pass\nconfiguration options after the `response` parameter. Available options are:\n\n* <b>`headers`</b> is an object containing custom headers to be set on the\n  EventSource response.\n* <b>`retry`</b> is a number that tells the client how long (in seconds) it\n  should wait after a dropped connection before attempting to reconnect.\n* <b>`ping`</b> is a number that tells the server how often (in seconds) to send\n  'ping' packets to the client to keep the connection open, to defeat timeouts\n  set by proxies. The client will ignore these messages.\n\nFor example, this creates a connection that allows access from any origin, pings\nevery 15 seconds and is retryable every 10 seconds if the connection is broken:\n\n```js\nvar es = new EventSource(request, response, {\n  headers: {'Access-Control-Allow-Origin': '*'},\n  ping:    15,\n  retry:   10\n});\n```\n\nYou can send a ping message at any time by calling `es.ping()`. Unlike\nWebSocket, the client does not send a response to this; it is merely to send\nsome data over the wire to keep the connection alive.\n\n\n## License\n\n(The MIT License)\n\nCopyright (c) 2010-2015 James Coglan\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the 'Software'), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n",
+  "readmeFilename": "README.md",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/faye/faye-websocket-node.git"
+  },
+  "scripts": {
+    "test": "jstest spec/runner.js"
+  },
+  "version": "0.9.3"
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/.npmignore b/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/.npmignore
new file mode 100644
index 0000000000000000000000000000000000000000..7e1574dc5c3c81d41c152e95b3c538613e69f19f
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/.npmignore
@@ -0,0 +1,18 @@
+.idea
+*.iml
+npm-debug.log
+dump.rdb
+node_modules
+results.tap
+results.xml
+npm-shrinkwrap.json
+config.json
+.DS_Store
+*/.DS_Store
+*/*/.DS_Store
+._*
+*/._*
+*/*/._*
+coverage.*
+lib-cov
+complexity.md
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/.travis.yml b/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..7a64dd2210cb10d8cbe178cebf5f9adf59380d2f
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/.travis.yml
@@ -0,0 +1,7 @@
+language: node_js
+
+node_js:
+  - 0.10
+  - 4.0
+
+sudo: false
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/CONTRIBUTING.md b/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/CONTRIBUTING.md
new file mode 100644
index 0000000000000000000000000000000000000000..892836159ba3c787e7502ce70ed9c5ffe5f9d023
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/CONTRIBUTING.md
@@ -0,0 +1 @@
+Please view our [hapijs contributing guide](https://github.com/hapijs/hapi/blob/master/CONTRIBUTING.md).
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/LICENSE b/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..5530904255022c91f7bc5e09b0aa3dc0307d451d
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/LICENSE
@@ -0,0 +1,31 @@
+Copyright (c) 2011-2014, Walmart and other contributors.
+Copyright (c) 2011, Yahoo Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * The names of any contributors may not be used to endorse or promote
+      products derived from this software without specific prior written
+      permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+                                  *   *   *
+
+The complete list of contributors can be found at: https://github.com/hapijs/hapi/graphs/contributors
+Portions of this project were initially based on the Yahoo! Inc. Postmile project,
+published at https://github.com/yahoo/postmile.
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/README.md b/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..92c4912c7e7c6c231d76fbcec3e0573f2ba41fd9
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/README.md
@@ -0,0 +1,584 @@
+![hoek Logo](https://raw.github.com/hapijs/hoek/master/images/hoek.png)
+
+Utility methods for the hapi ecosystem. This module is not intended to solve every problem for everyone, but rather as a central place to store hapi-specific methods. If you're looking for a general purpose utility module, check out [lodash](https://github.com/lodash/lodash) or [underscore](https://github.com/jashkenas/underscore).
+
+[![Build Status](https://secure.travis-ci.org/hapijs/hoek.svg)](http://travis-ci.org/hapijs/hoek)
+
+Lead Maintainer: [Nathan LaFreniere](https://github.com/nlf)
+
+# Table of Contents
+
+* [Introduction](#introduction "Introduction")
+* [Object](#object "Object")
+  * [clone](#cloneobj "clone")
+  * [cloneWithShallow](#clonewithshallowobj-keys "cloneWithShallow")
+  * [merge](#mergetarget-source-isnulloverride-ismergearrays "merge")
+  * [applyToDefaults](#applytodefaultsdefaults-options-isnulloverride "applyToDefaults")
+  * [applyToDefaultsWithShallow](#applytodefaultswithshallowdefaults-options-keys "applyToDefaultsWithShallow")
+  * [deepEqual](#deepequala-b "deepEqual")
+  * [unique](#uniquearray-key "unique")
+  * [mapToObject](#maptoobjectarray-key "mapToObject")
+  * [intersect](#intersectarray1-array2 "intersect")
+  * [contain](#containref-values-options "contain")
+  * [flatten](#flattenarray-target "flatten")
+  * [reach](#reachobj-chain-options "reach")
+  * [reachTemplate](#reachtemplateobj-template-options "reachTemplate")
+  * [transform](#transformobj-transform-options "transform")
+  * [shallow](#shallowobj "shallow")
+  * [stringify](#stringifyobj "stringify")
+* [Timer](#timer "Timer")
+* [Bench](#bench "Bench")
+* [Binary Encoding/Decoding](#binary-encodingdecoding "Binary Encoding/Decoding")
+  * [base64urlEncode](#base64urlencodevalue "binary64urlEncode")
+  * [base64urlDecode](#base64urldecodevalue "binary64urlDecode")
+* [Escaping Characters](#escaping-characters "Escaping Characters")
+  * [escapeHtml](#escapehtmlstring "escapeHtml")
+  * [escapeHeaderAttribute](#escapeheaderattributeattribute "escapeHeaderAttribute")
+  * [escapeRegex](#escaperegexstring "escapeRegex")
+* [Errors](#errors "Errors")
+  * [assert](#assertcondition-message "assert")
+  * [abort](#abortmessage "abort")
+  * [displayStack](#displaystackslice "displayStack")
+  * [callStack](#callstackslice "callStack")
+* [Function](#function "Function")
+  * [nextTick](#nexttickfn "nextTick")
+  * [once](#oncefn "once")
+  * [ignore](#ignore "ignore")
+* [Miscellaneous](#miscellaneous "Miscellaneous")
+  * [uniqueFilename](#uniquefilenamepath-extension "uniqueFilename")
+  * [isAbsolutePath](#isabsolutepathpath-platform "isAbsolutePath")
+  * [isInteger](#isintegervalue "isInteger")
+
+
+
+# Introduction
+
+The *Hoek* library contains some common functions used within the hapi ecosystem. It comes with useful methods for Arrays (clone, merge, applyToDefaults), Objects (removeKeys, copy), Asserting and more.
+
+For example, to use Hoek to set configuration with default options:
+```javascript
+var Hoek = require('hoek');
+
+var default = {url : "www.github.com", port : "8000", debug : true};
+
+var config = Hoek.applyToDefaults(default, {port : "3000", admin : true});
+
+// In this case, config would be { url: 'www.github.com', port: '3000', debug: true, admin: true }
+```
+
+Under each of the sections (such as Array), there are subsections which correspond to Hoek methods. Each subsection will explain how to use the corresponding method. In each js excerpt below, the `var Hoek = require('hoek');` is omitted for brevity.
+
+## Object
+
+Hoek provides several helpful methods for objects and arrays.
+
+### clone(obj)
+
+This method is used to clone an object or an array. A *deep copy* is made (duplicates everything, including values that are objects, as well as non-enumerable properties).
+
+```javascript
+
+var nestedObj = {
+        w: /^something$/ig,
+        x: {
+            a: [1, 2, 3],
+            b: 123456,
+            c: new Date()
+        },
+        y: 'y',
+        z: new Date()
+    };
+
+var copy = Hoek.clone(nestedObj);
+
+copy.x.b = 100;
+
+console.log(copy.y);        // results in 'y'
+console.log(nestedObj.x.b); // results in 123456
+console.log(copy.x.b);      // results in 100
+```
+
+### cloneWithShallow(obj, keys)
+keys is an array of key names to shallow copy
+
+This method is also used to clone an object or array, however any keys listed in the `keys` array are shallow copied while those not listed are deep copied.
+
+```javascript
+
+var nestedObj = {
+        w: /^something$/ig,
+        x: {
+            a: [1, 2, 3],
+            b: 123456,
+            c: new Date()
+        },
+        y: 'y',
+        z: new Date()
+    };
+
+var copy = Hoek.cloneWithShallow(nestedObj, ['x']);
+
+copy.x.b = 100;
+
+console.log(copy.y);        // results in 'y'
+console.log(nestedObj.x.b); // results in 100
+console.log(copy.x.b);      // results in 100
+```
+
+### merge(target, source, isNullOverride, isMergeArrays)
+isNullOverride, isMergeArrays default to true
+
+Merge all the properties of source into target, source wins in conflict, and by default null and undefined from source are applied.
+Merge is destructive where the target is modified. For non destructive merge, use `applyToDefaults`.
+
+
+```javascript
+
+var target = {a: 1, b : 2};
+var source = {a: 0, c: 5};
+var source2 = {a: null, c: 5};
+
+Hoek.merge(target, source);         // results in {a: 0, b: 2, c: 5}
+Hoek.merge(target, source2);        // results in {a: null, b: 2, c: 5}
+Hoek.merge(target, source2, false); // results in {a: 1, b: 2, c: 5}
+
+var targetArray = [1, 2, 3];
+var sourceArray = [4, 5];
+
+Hoek.merge(targetArray, sourceArray);              // results in [1, 2, 3, 4, 5]
+Hoek.merge(targetArray, sourceArray, true, false); // results in [4, 5]
+```
+
+### applyToDefaults(defaults, options, isNullOverride)
+isNullOverride defaults to false
+
+Apply options to a copy of the defaults
+
+```javascript
+
+var defaults = { host: "localhost", port: 8000 };
+var options = { port: 8080 };
+
+var config = Hoek.applyToDefaults(defaults, options); // results in { host: "localhost", port: 8080 }
+```
+
+Apply options with a null value to a copy of the defaults
+
+```javascript
+
+var defaults = { host: "localhost", port: 8000 };
+var options = { host: null, port: 8080 };
+
+var config = Hoek.applyToDefaults(defaults, options, true); // results in { host: null, port: 8080 }
+```
+
+### applyToDefaultsWithShallow(defaults, options, keys)
+keys is an array of key names to shallow copy
+
+Apply options to a copy of the defaults. Keys specified in the last parameter are shallow copied from options instead of merged.
+
+```javascript
+
+var defaults = {
+        server: {
+            host: "localhost",
+            port: 8000
+        },
+        name: 'example'
+    };
+
+var options = { server: { port: 8080 } };
+
+var config = Hoek.applyToDefaultsWithShallow(defaults, options, ['server']); // results in { server: { port: 8080 }, name: 'example' }
+```
+
+### deepEqual(b, a, [options])
+
+Performs a deep comparison of the two values including support for circular dependencies, prototype, and properties. To skip prototype comparisons, use `options.prototype = false`
+
+```javascript
+Hoek.deepEqual({ a: [1, 2], b: 'string', c: { d: true } }, { a: [1, 2], b: 'string', c: { d: true } }); //results in true
+Hoek.deepEqual(Object.create(null), {}, { prototype: false }); //results in true
+Hoek.deepEqual(Object.create(null), {}); //results in false
+```
+
+### unique(array, key)
+
+Remove duplicate items from Array
+
+```javascript
+
+var array = [1, 2, 2, 3, 3, 4, 5, 6];
+
+var newArray = Hoek.unique(array);    // results in [1,2,3,4,5,6]
+
+array = [{id: 1}, {id: 1}, {id: 2}];
+
+newArray = Hoek.unique(array, "id");  // results in [{id: 1}, {id: 2}]
+```
+
+### mapToObject(array, key)
+
+Convert an Array into an Object
+
+```javascript
+
+var array = [1,2,3];
+var newObject = Hoek.mapToObject(array);   // results in [{"1": true}, {"2": true}, {"3": true}]
+
+array = [{id: 1}, {id: 2}];
+newObject = Hoek.mapToObject(array, "id"); // results in [{"id": 1}, {"id": 2}]
+```
+
+### intersect(array1, array2)
+
+Find the common unique items in two arrays
+
+```javascript
+
+var array1 = [1, 2, 3];
+var array2 = [1, 4, 5];
+
+var newArray = Hoek.intersect(array1, array2); // results in [1]
+```
+
+### contain(ref, values, [options])
+
+Tests if the reference value contains the provided values where:
+- `ref` - the reference string, array, or object.
+- `values` - a single or array of values to find within the `ref` value. If `ref` is an object, `values` can be a key name,
+  an array of key names, or an object with key-value pairs to compare.
+- `options` - an optional object with the following optional settings:
+    - `deep` - if `true`, performed a deep comparison of the values.
+    - `once` - if `true`, allows only one occurrence of each value.
+    - `only` - if `true`, does not allow values not explicitly listed.
+    - `part` - if `true`, allows partial match of the values (at least one must always match).
+
+Note: comparing a string to overlapping values will result in failed comparison (e.g. `contain('abc', ['ab', 'bc'])`).
+Also, if an object key's value does not match the provided value, `false` is returned even when `part` is specified.
+
+```javascript
+Hoek.contain('aaa', 'a', { only: true });							// true
+Hoek.contain([{ a: 1 }], [{ a: 1 }], { deep: true });				// true
+Hoek.contain([1, 2, 2], [1, 2], { once: true });					// false
+Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1, d: 4 }, { part: true }); // true
+```
+
+### flatten(array, [target])
+
+Flatten an array
+
+```javascript
+
+var array = [1, [2, 3]];
+
+var flattenedArray = Hoek.flatten(array); // results in [1, 2, 3]
+
+array = [1, [2, 3]];
+target = [4, [5]];
+
+flattenedArray = Hoek.flatten(array, target); // results in [4, [5], 1, 2, 3]
+```
+
+### reach(obj, chain, [options])
+
+Converts an object key chain string to reference
+
+- `options` - optional settings
+    - `separator` - string to split chain path on, defaults to '.'
+    - `default` - value to return if the path or value is not present, default is `undefined`
+    - `strict` - if `true`, will throw an error on missing member, default is `false`
+    - `functions` - if `true` allow traversing functions for properties. `false` will throw an error if a function is part of the chain.
+
+A chain including negative numbers will work like negative indices on an
+array.
+
+If chain is `null`, `undefined` or `false`, the object itself will be returned.
+
+```javascript
+
+var chain = 'a.b.c';
+var obj = {a : {b : { c : 1}}};
+
+Hoek.reach(obj, chain); // returns 1
+
+var chain = 'a.b.-1';
+var obj = {a : {b : [2,3,6]}};
+
+Hoek.reach(obj, chain); // returns 6
+```
+
+### reachTemplate(obj, template, [options])
+
+Replaces string parameters (`{name}`) with their corresponding object key values by applying the
+(`reach()`)[#reachobj-chain-options] method where:
+
+- `obj` - the context object used for key lookup.
+- `template` - a string containing `{}` parameters.
+- `options` - optional (`reach()`)[#reachobj-chain-options] options.
+
+```javascript
+
+var chain = 'a.b.c';
+var obj = {a : {b : { c : 1}}};
+
+Hoek.reachTemplate(obj, '1+{a.b.c}=2'); // returns '1+1=2'
+```
+
+### transform(obj, transform, [options])
+
+Transforms an existing object into a new one based on the supplied `obj` and `transform` map. `options` are the same as the `reach` options. The first argument can also be an array of objects. In that case the method will return an array of transformed objects.
+
+```javascript
+var source = {
+    address: {
+        one: '123 main street',
+        two: 'PO Box 1234'
+    },
+    title: 'Warehouse',
+    state: 'CA'
+};
+
+var result = Hoek.transform(source, {
+    'person.address.lineOne': 'address.one',
+    'person.address.lineTwo': 'address.two',
+    'title': 'title',
+    'person.address.region': 'state'
+});
+// Results in
+// {
+//     person: {
+//         address: {
+//             lineOne: '123 main street',
+//             lineTwo: 'PO Box 1234',
+//             region: 'CA'
+//         }
+//     },
+//     title: 'Warehouse'
+// }
+```
+
+### shallow(obj)
+
+Performs a shallow copy by copying the references of all the top level children where:
+- `obj` - the object to be copied.
+
+```javascript
+var shallow = Hoek.shallow({ a: { b: 1 } });
+```
+
+### stringify(obj)
+
+Converts an object to string using the built-in `JSON.stringify()` method with the difference that any errors are caught
+and reported back in the form of the returned string. Used as a shortcut for displaying information to the console (e.g. in
+error message) without the need to worry about invalid conversion.
+
+```javascript
+var a = {};
+a.b = a;
+Hoek.stringify(a);		// Returns '[Cannot display object: Converting circular structure to JSON]'
+```
+
+# Timer
+
+A Timer object. Initializing a new timer object sets the ts to the number of milliseconds elapsed since 1 January 1970 00:00:00 UTC.
+
+```javascript
+
+var timerObj = new Hoek.Timer();
+console.log("Time is now: " + timerObj.ts);
+console.log("Elapsed time from initialization: " + timerObj.elapsed() + 'milliseconds');
+```
+
+
+# Bench
+
+Same as Timer with the exception that `ts` stores the internal node clock which is not related to `Date.now()` and cannot be used to display
+human-readable timestamps. More accurate for benchmarking or internal timers.
+
+# Binary Encoding/Decoding
+
+### base64urlEncode(value)
+
+Encodes value in Base64 or URL encoding
+
+### base64urlDecode(value)
+
+Decodes data in Base64 or URL encoding.
+# Escaping Characters
+
+Hoek provides convenient methods for escaping html characters. The escaped characters are as followed:
+
+```javascript
+
+internals.htmlEscaped = {
+    '&': '&amp;',
+    '<': '&lt;',
+    '>': '&gt;',
+    '"': '&quot;',
+    "'": '&#x27;',
+    '`': '&#x60;'
+};
+```
+
+### escapeHtml(string)
+
+```javascript
+
+var string = '<html> hey </html>';
+var escapedString = Hoek.escapeHtml(string); // returns &lt;html&gt; hey &lt;/html&gt;
+```
+
+### escapeHeaderAttribute(attribute)
+
+Escape attribute value for use in HTTP header
+
+```javascript
+
+var a = Hoek.escapeHeaderAttribute('I said "go w\\o me"');  //returns I said \"go w\\o me\"
+```
+
+
+### escapeRegex(string)
+
+Escape string for Regex construction
+
+```javascript
+
+var a = Hoek.escapeRegex('4^f$s.4*5+-_?%=#!:@|~\\/`"(>)[<]d{}s,');  // returns 4\^f\$s\.4\*5\+\-_\?%\=#\!\:@\|~\\\/`"\(>\)\[<\]d\{\}s\,
+```
+
+# Errors
+
+### assert(condition, message)
+
+```javascript
+
+var a = 1, b = 2;
+
+Hoek.assert(a === b, 'a should equal b');  // Throws 'a should equal b'
+```
+
+Note that you may also pass an already created Error object as the second parameter, and `assert` will throw that object.
+
+```javascript
+
+var a = 1, b = 2;
+
+Hoek.assert(a === b, new Error('a should equal b')); // Throws the given error object
+```
+
+### abort(message)
+
+First checks if `process.env.NODE_ENV === 'test'`, and if so, throws error message. Otherwise,
+displays most recent stack and then exits process.
+
+
+
+### displayStack(slice)
+
+Displays the trace stack
+
+```javascript
+
+var stack = Hoek.displayStack();
+console.log(stack); // returns something like:
+
+[ 'null (/Users/user/Desktop/hoek/test.js:4:18)',
+  'Module._compile (module.js:449:26)',
+  'Module._extensions..js (module.js:467:10)',
+  'Module.load (module.js:356:32)',
+  'Module._load (module.js:312:12)',
+  'Module.runMain (module.js:492:10)',
+  'startup.processNextTick.process._tickCallback (node.js:244:9)' ]
+```
+
+### callStack(slice)
+
+Returns a trace stack array.
+
+```javascript
+
+var stack = Hoek.callStack();
+console.log(stack);  // returns something like:
+
+[ [ '/Users/user/Desktop/hoek/test.js', 4, 18, null, false ],
+  [ 'module.js', 449, 26, 'Module._compile', false ],
+  [ 'module.js', 467, 10, 'Module._extensions..js', false ],
+  [ 'module.js', 356, 32, 'Module.load', false ],
+  [ 'module.js', 312, 12, 'Module._load', false ],
+  [ 'module.js', 492, 10, 'Module.runMain', false ],
+  [ 'node.js',
+    244,
+    9,
+    'startup.processNextTick.process._tickCallback',
+    false ] ]
+```
+
+## Function
+
+### nextTick(fn)
+
+Returns a new function that wraps `fn` in `process.nextTick`.
+
+```javascript
+
+var myFn = function () {
+    console.log('Do this later');
+};
+
+var nextFn = Hoek.nextTick(myFn);
+
+nextFn();
+console.log('Do this first');
+
+// Results in:
+//
+// Do this first
+// Do this later
+```
+
+### once(fn)
+
+Returns a new function that can be run multiple times, but makes sure `fn` is only run once.
+
+```javascript
+
+var myFn = function () {
+    console.log('Ran myFn');
+};
+
+var onceFn = Hoek.once(myFn);
+onceFn(); // results in "Ran myFn"
+onceFn(); // results in undefined
+```
+
+### ignore
+
+A simple no-op function. It does nothing at all.
+
+## Miscellaneous
+
+### uniqueFilename(path, extension)
+`path` to prepend with the randomly generated file name. `extension` is the optional file extension, defaults to `''`.
+
+Returns a randomly generated file name at the specified `path`. The result is a fully resolved path to a file.
+
+```javascript
+var result = Hoek.uniqueFilename('./test/modules', 'txt'); // results in "full/path/test/modules/{random}.txt"
+```
+
+### isAbsolutePath(path, [platform])
+
+Determines whether `path` is an absolute path. Returns `true` or `false`.
+
+- `path` - A file path to test for whether it is absolute or not.
+- `platform` - An optional parameter used for specifying the platform. Defaults to `process.platform`.
+
+### isInteger(value)
+
+Check `value` to see if it is an integer.  Returns true/false.
+
+```javascript
+var result = Hoek.isInteger('23')
+```
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/images/hoek.png b/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/images/hoek.png
new file mode 100644
index 0000000000000000000000000000000000000000..6ccfcb12be76a7a8331428c87337b20b901e869c
Binary files /dev/null and b/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/images/hoek.png differ
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/lib/escape.js b/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/lib/escape.js
new file mode 100644
index 0000000000000000000000000000000000000000..9ecde6666b1263339b563df9a9ce177ba83600c6
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/lib/escape.js
@@ -0,0 +1,132 @@
+// Declare internals
+
+var internals = {};
+
+
+exports.escapeJavaScript = function (input) {
+
+    if (!input) {
+        return '';
+    }
+
+    var escaped = '';
+
+    for (var i = 0, il = input.length; i < il; ++i) {
+
+        var charCode = input.charCodeAt(i);
+
+        if (internals.isSafe(charCode)) {
+            escaped += input[i];
+        }
+        else {
+            escaped += internals.escapeJavaScriptChar(charCode);
+        }
+    }
+
+    return escaped;
+};
+
+
+exports.escapeHtml = function (input) {
+
+    if (!input) {
+        return '';
+    }
+
+    var escaped = '';
+
+    for (var i = 0, il = input.length; i < il; ++i) {
+
+        var charCode = input.charCodeAt(i);
+
+        if (internals.isSafe(charCode)) {
+            escaped += input[i];
+        }
+        else {
+            escaped += internals.escapeHtmlChar(charCode);
+        }
+    }
+
+    return escaped;
+};
+
+
+internals.escapeJavaScriptChar = function (charCode) {
+
+    if (charCode >= 256) {
+        return '\\u' + internals.padLeft('' + charCode, 4);
+    }
+
+    var hexValue = new Buffer(String.fromCharCode(charCode), 'ascii').toString('hex');
+    return '\\x' + internals.padLeft(hexValue, 2);
+};
+
+
+internals.escapeHtmlChar = function (charCode) {
+
+    var namedEscape = internals.namedHtml[charCode];
+    if (typeof namedEscape !== 'undefined') {
+        return namedEscape;
+    }
+
+    if (charCode >= 256) {
+        return '&#' + charCode + ';';
+    }
+
+    var hexValue = new Buffer(String.fromCharCode(charCode), 'ascii').toString('hex');
+    return '&#x' + internals.padLeft(hexValue, 2) + ';';
+};
+
+
+internals.padLeft = function (str, len) {
+
+    while (str.length < len) {
+        str = '0' + str;
+    }
+
+    return str;
+};
+
+
+internals.isSafe = function (charCode) {
+
+    return (typeof internals.safeCharCodes[charCode] !== 'undefined');
+};
+
+
+internals.namedHtml = {
+    '38': '&amp;',
+    '60': '&lt;',
+    '62': '&gt;',
+    '34': '&quot;',
+    '160': '&nbsp;',
+    '162': '&cent;',
+    '163': '&pound;',
+    '164': '&curren;',
+    '169': '&copy;',
+    '174': '&reg;'
+};
+
+
+internals.safeCharCodes = (function () {
+
+    var safe = {};
+
+    for (var i = 32; i < 123; ++i) {
+
+        if ((i >= 97) ||                    // a-z
+            (i >= 65 && i <= 90) ||         // A-Z
+            (i >= 48 && i <= 57) ||         // 0-9
+            i === 32 ||                     // space
+            i === 46 ||                     // .
+            i === 44 ||                     // ,
+            i === 45 ||                     // -
+            i === 58 ||                     // :
+            i === 95) {                     // _
+
+            safe[i] = null;
+        }
+    }
+
+    return safe;
+}());
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/lib/index.js b/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/lib/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..9a5ffe18f4cd1f7fd03bb2c8227a40705fc138dc
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/lib/index.js
@@ -0,0 +1,993 @@
+// Load modules
+
+var Crypto = require('crypto');
+var Path = require('path');
+var Util = require('util');
+var Escape = require('./escape');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Clone object or array
+
+exports.clone = function (obj, seen) {
+
+    if (typeof obj !== 'object' ||
+        obj === null) {
+
+        return obj;
+    }
+
+    seen = seen || { orig: [], copy: [] };
+
+    var lookup = seen.orig.indexOf(obj);
+    if (lookup !== -1) {
+        return seen.copy[lookup];
+    }
+
+    var newObj;
+    var cloneDeep = false;
+
+    if (!Array.isArray(obj)) {
+        if (Buffer.isBuffer(obj)) {
+            newObj = new Buffer(obj);
+        }
+        else if (obj instanceof Date) {
+            newObj = new Date(obj.getTime());
+        }
+        else if (obj instanceof RegExp) {
+            newObj = new RegExp(obj);
+        }
+        else {
+            var proto = Object.getPrototypeOf(obj);
+            if (proto &&
+                proto.isImmutable) {
+
+                newObj = obj;
+            }
+            else {
+                newObj = Object.create(proto);
+                cloneDeep = true;
+            }
+        }
+    }
+    else {
+        newObj = [];
+        cloneDeep = true;
+    }
+
+    seen.orig.push(obj);
+    seen.copy.push(newObj);
+
+    if (cloneDeep) {
+        var keys = Object.getOwnPropertyNames(obj);
+        for (var i = 0, il = keys.length; i < il; ++i) {
+            var key = keys[i];
+            var descriptor = Object.getOwnPropertyDescriptor(obj, key);
+            if (descriptor &&
+                (descriptor.get ||
+                 descriptor.set)) {
+
+                Object.defineProperty(newObj, key, descriptor);
+            }
+            else {
+                newObj[key] = exports.clone(obj[key], seen);
+            }
+        }
+    }
+
+    return newObj;
+};
+
+
+// Merge all the properties of source into target, source wins in conflict, and by default null and undefined from source are applied
+/*eslint-disable */
+exports.merge = function (target, source, isNullOverride /* = true */, isMergeArrays /* = true */) {
+/*eslint-enable */
+    exports.assert(target && typeof target === 'object', 'Invalid target value: must be an object');
+    exports.assert(source === null || source === undefined || typeof source === 'object', 'Invalid source value: must be null, undefined, or an object');
+
+    if (!source) {
+        return target;
+    }
+
+    if (Array.isArray(source)) {
+        exports.assert(Array.isArray(target), 'Cannot merge array onto an object');
+        if (isMergeArrays === false) {                                                  // isMergeArrays defaults to true
+            target.length = 0;                                                          // Must not change target assignment
+        }
+
+        for (var i = 0, il = source.length; i < il; ++i) {
+            target.push(exports.clone(source[i]));
+        }
+
+        return target;
+    }
+
+    var keys = Object.keys(source);
+    for (var k = 0, kl = keys.length; k < kl; ++k) {
+        var key = keys[k];
+        var value = source[key];
+        if (value &&
+            typeof value === 'object') {
+
+            if (!target[key] ||
+                typeof target[key] !== 'object' ||
+                (Array.isArray(target[key]) ^ Array.isArray(value)) ||
+                value instanceof Date ||
+                Buffer.isBuffer(value) ||
+                value instanceof RegExp) {
+
+                target[key] = exports.clone(value);
+            }
+            else {
+                exports.merge(target[key], value, isNullOverride, isMergeArrays);
+            }
+        }
+        else {
+            if (value !== null &&
+                value !== undefined) {                              // Explicit to preserve empty strings
+
+                target[key] = value;
+            }
+            else if (isNullOverride !== false) {                    // Defaults to true
+                target[key] = value;
+            }
+        }
+    }
+
+    return target;
+};
+
+
+// Apply options to a copy of the defaults
+
+exports.applyToDefaults = function (defaults, options, isNullOverride) {
+
+    exports.assert(defaults && typeof defaults === 'object', 'Invalid defaults value: must be an object');
+    exports.assert(!options || options === true || typeof options === 'object', 'Invalid options value: must be true, falsy or an object');
+
+    if (!options) {                                                 // If no options, return null
+        return null;
+    }
+
+    var copy = exports.clone(defaults);
+
+    if (options === true) {                                         // If options is set to true, use defaults
+        return copy;
+    }
+
+    return exports.merge(copy, options, isNullOverride === true, false);
+};
+
+
+// Clone an object except for the listed keys which are shallow copied
+
+exports.cloneWithShallow = function (source, keys) {
+
+    if (!source ||
+        typeof source !== 'object') {
+
+        return source;
+    }
+
+    var storage = internals.store(source, keys);    // Move shallow copy items to storage
+    var copy = exports.clone(source);               // Deep copy the rest
+    internals.restore(copy, source, storage);       // Shallow copy the stored items and restore
+    return copy;
+};
+
+
+internals.store = function (source, keys) {
+
+    var storage = {};
+    for (var i = 0, il = keys.length; i < il; ++i) {
+        var key = keys[i];
+        var value = exports.reach(source, key);
+        if (value !== undefined) {
+            storage[key] = value;
+            internals.reachSet(source, key, undefined);
+        }
+    }
+
+    return storage;
+};
+
+
+internals.restore = function (copy, source, storage) {
+
+    var keys = Object.keys(storage);
+    for (var i = 0, il = keys.length; i < il; ++i) {
+        var key = keys[i];
+        internals.reachSet(copy, key, storage[key]);
+        internals.reachSet(source, key, storage[key]);
+    }
+};
+
+
+internals.reachSet = function (obj, key, value) {
+
+    var path = key.split('.');
+    var ref = obj;
+    for (var i = 0, il = path.length; i < il; ++i) {
+        var segment = path[i];
+        if (i + 1 === il) {
+            ref[segment] = value;
+        }
+
+        ref = ref[segment];
+    }
+};
+
+
+// Apply options to defaults except for the listed keys which are shallow copied from option without merging
+
+exports.applyToDefaultsWithShallow = function (defaults, options, keys) {
+
+    exports.assert(defaults && typeof defaults === 'object', 'Invalid defaults value: must be an object');
+    exports.assert(!options || options === true || typeof options === 'object', 'Invalid options value: must be true, falsy or an object');
+    exports.assert(keys && Array.isArray(keys), 'Invalid keys');
+
+    if (!options) {                                                 // If no options, return null
+        return null;
+    }
+
+    var copy = exports.cloneWithShallow(defaults, keys);
+
+    if (options === true) {                                         // If options is set to true, use defaults
+        return copy;
+    }
+
+    var storage = internals.store(options, keys);   // Move shallow copy items to storage
+    exports.merge(copy, options, false, false);     // Deep copy the rest
+    internals.restore(copy, options, storage);      // Shallow copy the stored items and restore
+    return copy;
+};
+
+
+// Deep object or array comparison
+
+exports.deepEqual = function (obj, ref, options, seen) {
+
+    options = options || { prototype: true };
+
+    var type = typeof obj;
+
+    if (type !== typeof ref) {
+        return false;
+    }
+
+    if (type !== 'object' ||
+        obj === null ||
+        ref === null) {
+
+        if (obj === ref) {                                                      // Copied from Deep-eql, copyright(c) 2013 Jake Luer, jake@alogicalparadox.com, MIT Licensed, https://github.com/chaijs/deep-eql
+            return obj !== 0 || 1 / obj === 1 / ref;        // -0 / +0
+        }
+
+        return obj !== obj && ref !== ref;                  // NaN
+    }
+
+    seen = seen || [];
+    if (seen.indexOf(obj) !== -1) {
+        return true;                            // If previous comparison failed, it would have stopped execution
+    }
+
+    seen.push(obj);
+
+    if (Array.isArray(obj)) {
+        if (!Array.isArray(ref)) {
+            return false;
+        }
+
+        if (!options.part && obj.length !== ref.length) {
+            return false;
+        }
+
+        for (var i = 0, il = obj.length; i < il; ++i) {
+            if (options.part) {
+                var found = false;
+                for (var r = 0, rl = ref.length; r < rl; ++r) {
+                    if (exports.deepEqual(obj[i], ref[r], options, seen)) {
+                        found = true;
+                        break;
+                    }
+                }
+
+                return found;
+            }
+
+            if (!exports.deepEqual(obj[i], ref[i], options, seen)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    if (Buffer.isBuffer(obj)) {
+        if (!Buffer.isBuffer(ref)) {
+            return false;
+        }
+
+        if (obj.length !== ref.length) {
+            return false;
+        }
+
+        for (var j = 0, jl = obj.length; j < jl; ++j) {
+            if (obj[j] !== ref[j]) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    if (obj instanceof Date) {
+        return (ref instanceof Date && obj.getTime() === ref.getTime());
+    }
+
+    if (obj instanceof RegExp) {
+        return (ref instanceof RegExp && obj.toString() === ref.toString());
+    }
+
+    if (options.prototype) {
+        if (Object.getPrototypeOf(obj) !== Object.getPrototypeOf(ref)) {
+            return false;
+        }
+    }
+
+    var keys = Object.getOwnPropertyNames(obj);
+
+    if (!options.part && keys.length !== Object.getOwnPropertyNames(ref).length) {
+        return false;
+    }
+
+    for (var k = 0, kl = keys.length; k < kl; ++k) {
+        var key = keys[k];
+        var descriptor = Object.getOwnPropertyDescriptor(obj, key);
+        if (descriptor.get) {
+            if (!exports.deepEqual(descriptor, Object.getOwnPropertyDescriptor(ref, key), options, seen)) {
+                return false;
+            }
+        }
+        else if (!exports.deepEqual(obj[key], ref[key], options, seen)) {
+            return false;
+        }
+    }
+
+    return true;
+};
+
+
+// Remove duplicate items from array
+
+exports.unique = function (array, key) {
+
+    var index = {};
+    var result = [];
+
+    for (var i = 0, il = array.length; i < il; ++i) {
+        var id = (key ? array[i][key] : array[i]);
+        if (index[id] !== true) {
+
+            result.push(array[i]);
+            index[id] = true;
+        }
+    }
+
+    return result;
+};
+
+
+// Convert array into object
+
+exports.mapToObject = function (array, key) {
+
+    if (!array) {
+        return null;
+    }
+
+    var obj = {};
+    for (var i = 0, il = array.length; i < il; ++i) {
+        if (key) {
+            if (array[i][key]) {
+                obj[array[i][key]] = true;
+            }
+        }
+        else {
+            obj[array[i]] = true;
+        }
+    }
+
+    return obj;
+};
+
+
+// Find the common unique items in two arrays
+
+exports.intersect = function (array1, array2, justFirst) {
+
+    if (!array1 || !array2) {
+        return [];
+    }
+
+    var common = [];
+    var hash = (Array.isArray(array1) ? exports.mapToObject(array1) : array1);
+    var found = {};
+    for (var i = 0, il = array2.length; i < il; ++i) {
+        if (hash[array2[i]] && !found[array2[i]]) {
+            if (justFirst) {
+                return array2[i];
+            }
+
+            common.push(array2[i]);
+            found[array2[i]] = true;
+        }
+    }
+
+    return (justFirst ? null : common);
+};
+
+
+// Test if the reference contains the values
+
+exports.contain = function (ref, values, options) {
+
+    /*
+        string -> string(s)
+        array -> item(s)
+        object -> key(s)
+        object -> object (key:value)
+    */
+
+    var valuePairs = null;
+    if (typeof ref === 'object' &&
+        typeof values === 'object' &&
+        !Array.isArray(ref) &&
+        !Array.isArray(values)) {
+
+        valuePairs = values;
+        values = Object.keys(values);
+    }
+    else {
+        values = [].concat(values);
+    }
+
+    options = options || {};            // deep, once, only, part
+
+    exports.assert(arguments.length >= 2, 'Insufficient arguments');
+    exports.assert(typeof ref === 'string' || typeof ref === 'object', 'Reference must be string or an object');
+    exports.assert(values.length, 'Values array cannot be empty');
+
+    var compare, compareFlags;
+    if (options.deep) {
+        compare = exports.deepEqual;
+
+        var hasOnly = options.hasOwnProperty('only'), hasPart = options.hasOwnProperty('part');
+
+        compareFlags = {
+            prototype: hasOnly ? options.only : hasPart ? !options.part : false,
+            part: hasOnly ? !options.only : hasPart ? options.part : true
+        };
+    }
+    else {
+        compare = function (a, b) {
+
+            return a === b;
+        };
+    }
+
+    var misses = false;
+    var matches = new Array(values.length);
+    for (var i = 0, il = matches.length; i < il; ++i) {
+        matches[i] = 0;
+    }
+
+    if (typeof ref === 'string') {
+        var pattern = '(';
+        for (i = 0, il = values.length; i < il; ++i) {
+            var value = values[i];
+            exports.assert(typeof value === 'string', 'Cannot compare string reference to non-string value');
+            pattern += (i ? '|' : '') + exports.escapeRegex(value);
+        }
+
+        var regex = new RegExp(pattern + ')', 'g');
+        var leftovers = ref.replace(regex, function ($0, $1) {
+
+            var index = values.indexOf($1);
+            ++matches[index];
+            return '';          // Remove from string
+        });
+
+        misses = !!leftovers;
+    }
+    else if (Array.isArray(ref)) {
+        for (i = 0, il = ref.length; i < il; ++i) {
+            for (var j = 0, jl = values.length, matched = false; j < jl && matched === false; ++j) {
+                matched = compare(values[j], ref[i], compareFlags) && j;
+            }
+
+            if (matched !== false) {
+                ++matches[matched];
+            }
+            else {
+                misses = true;
+            }
+        }
+    }
+    else {
+        var keys = Object.keys(ref);
+        for (i = 0, il = keys.length; i < il; ++i) {
+            var key = keys[i];
+            var pos = values.indexOf(key);
+            if (pos !== -1) {
+                if (valuePairs &&
+                    !compare(valuePairs[key], ref[key], compareFlags)) {
+
+                    return false;
+                }
+
+                ++matches[pos];
+            }
+            else {
+                misses = true;
+            }
+        }
+    }
+
+    var result = false;
+    for (i = 0, il = matches.length; i < il; ++i) {
+        result = result || !!matches[i];
+        if ((options.once && matches[i] > 1) ||
+            (!options.part && !matches[i])) {
+
+            return false;
+        }
+    }
+
+    if (options.only &&
+        misses) {
+
+        return false;
+    }
+
+    return result;
+};
+
+
+// Flatten array
+
+exports.flatten = function (array, target) {
+
+    var result = target || [];
+
+    for (var i = 0, il = array.length; i < il; ++i) {
+        if (Array.isArray(array[i])) {
+            exports.flatten(array[i], result);
+        }
+        else {
+            result.push(array[i]);
+        }
+    }
+
+    return result;
+};
+
+
+// Convert an object key chain string ('a.b.c') to reference (object[a][b][c])
+
+exports.reach = function (obj, chain, options) {
+
+    if (chain === false ||
+        chain === null ||
+        typeof chain === 'undefined') {
+
+        return obj;
+    }
+
+    options = options || {};
+    if (typeof options === 'string') {
+        options = { separator: options };
+    }
+
+    var path = chain.split(options.separator || '.');
+    var ref = obj;
+    for (var i = 0, il = path.length; i < il; ++i) {
+        var key = path[i];
+        if (key[0] === '-' && Array.isArray(ref)) {
+            key = key.slice(1, key.length);
+            key = ref.length - key;
+        }
+
+        if (!ref ||
+            !ref.hasOwnProperty(key) ||
+            (typeof ref !== 'object' && options.functions === false)) {         // Only object and function can have properties
+
+            exports.assert(!options.strict || i + 1 === il, 'Missing segment', key, 'in reach path ', chain);
+            exports.assert(typeof ref === 'object' || options.functions === true || typeof ref !== 'function', 'Invalid segment', key, 'in reach path ', chain);
+            ref = options.default;
+            break;
+        }
+
+        ref = ref[key];
+    }
+
+    return ref;
+};
+
+
+exports.reachTemplate = function (obj, template, options) {
+
+    return template.replace(/{([^}]+)}/g, function ($0, chain) {
+
+        var value = exports.reach(obj, chain, options);
+        return (value === undefined || value === null ? '' : value);
+    });
+};
+
+
+exports.formatStack = function (stack) {
+
+    var trace = [];
+    for (var i = 0, il = stack.length; i < il; ++i) {
+        var item = stack[i];
+        trace.push([item.getFileName(), item.getLineNumber(), item.getColumnNumber(), item.getFunctionName(), item.isConstructor()]);
+    }
+
+    return trace;
+};
+
+
+exports.formatTrace = function (trace) {
+
+    var display = [];
+
+    for (var i = 0, il = trace.length; i < il; ++i) {
+        var row = trace[i];
+        display.push((row[4] ? 'new ' : '') + row[3] + ' (' + row[0] + ':' + row[1] + ':' + row[2] + ')');
+    }
+
+    return display;
+};
+
+
+exports.callStack = function (slice) {
+
+    // http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi
+
+    var v8 = Error.prepareStackTrace;
+    Error.prepareStackTrace = function (err, stack) {
+
+        return stack;
+    };
+
+    var capture = {};
+    Error.captureStackTrace(capture, arguments.callee);     /*eslint no-caller:0 */
+    var stack = capture.stack;
+
+    Error.prepareStackTrace = v8;
+
+    var trace = exports.formatStack(stack);
+
+    if (slice) {
+        return trace.slice(slice);
+    }
+
+    return trace;
+};
+
+
+exports.displayStack = function (slice) {
+
+    var trace = exports.callStack(slice === undefined ? 1 : slice + 1);
+
+    return exports.formatTrace(trace);
+};
+
+
+exports.abortThrow = false;
+
+
+exports.abort = function (message, hideStack) {
+
+    if (process.env.NODE_ENV === 'test' || exports.abortThrow === true) {
+        throw new Error(message || 'Unknown error');
+    }
+
+    var stack = '';
+    if (!hideStack) {
+        stack = exports.displayStack(1).join('\n\t');
+    }
+    console.log('ABORT: ' + message + '\n\t' + stack);
+    process.exit(1);
+};
+
+
+exports.assert = function (condition /*, msg1, msg2, msg3 */) {
+
+    if (condition) {
+        return;
+    }
+
+    if (arguments.length === 2 && arguments[1] instanceof Error) {
+        throw arguments[1];
+    }
+
+    var msgs = [];
+    for (var i = 1, il = arguments.length; i < il; ++i) {
+        if (arguments[i] !== '') {
+            msgs.push(arguments[i]);            // Avoids Array.slice arguments leak, allowing for V8 optimizations
+        }
+    }
+
+    msgs = msgs.map(function (msg) {
+
+        return typeof msg === 'string' ? msg : msg instanceof Error ? msg.message : exports.stringify(msg);
+    });
+    throw new Error(msgs.join(' ') || 'Unknown error');
+};
+
+
+exports.Timer = function () {
+
+    this.ts = 0;
+    this.reset();
+};
+
+
+exports.Timer.prototype.reset = function () {
+
+    this.ts = Date.now();
+};
+
+
+exports.Timer.prototype.elapsed = function () {
+
+    return Date.now() - this.ts;
+};
+
+
+exports.Bench = function () {
+
+    this.ts = 0;
+    this.reset();
+};
+
+
+exports.Bench.prototype.reset = function () {
+
+    this.ts = exports.Bench.now();
+};
+
+
+exports.Bench.prototype.elapsed = function () {
+
+    return exports.Bench.now() - this.ts;
+};
+
+
+exports.Bench.now = function () {
+
+    var ts = process.hrtime();
+    return (ts[0] * 1e3) + (ts[1] / 1e6);
+};
+
+
+// Escape string for Regex construction
+
+exports.escapeRegex = function (string) {
+
+    // Escape ^$.*+-?=!:|\/()[]{},
+    return string.replace(/[\^\$\.\*\+\-\?\=\!\:\|\\\/\(\)\[\]\{\}\,]/g, '\\$&');
+};
+
+
+// Base64url (RFC 4648) encode
+
+exports.base64urlEncode = function (value, encoding) {
+
+    var buf = (Buffer.isBuffer(value) ? value : new Buffer(value, encoding || 'binary'));
+    return buf.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/\=/g, '');
+};
+
+
+// Base64url (RFC 4648) decode
+
+exports.base64urlDecode = function (value, encoding) {
+
+    if (value &&
+        !/^[\w\-]*$/.test(value)) {
+
+        return new Error('Invalid character');
+    }
+
+    try {
+        var buf = new Buffer(value, 'base64');
+        return (encoding === 'buffer' ? buf : buf.toString(encoding || 'binary'));
+    }
+    catch (err) {
+        return err;
+    }
+};
+
+
+// Escape attribute value for use in HTTP header
+
+exports.escapeHeaderAttribute = function (attribute) {
+
+    // Allowed value characters: !#$%&'()*+,-./:;<=>?@[]^_`{|}~ and space, a-z, A-Z, 0-9, \, "
+
+    exports.assert(/^[ \w\!#\$%&'\(\)\*\+,\-\.\/\:;<\=>\?@\[\]\^`\{\|\}~\"\\]*$/.test(attribute), 'Bad attribute value (' + attribute + ')');
+
+    return attribute.replace(/\\/g, '\\\\').replace(/\"/g, '\\"');                             // Escape quotes and slash
+};
+
+
+exports.escapeHtml = function (string) {
+
+    return Escape.escapeHtml(string);
+};
+
+
+exports.escapeJavaScript = function (string) {
+
+    return Escape.escapeJavaScript(string);
+};
+
+
+exports.nextTick = function (callback) {
+
+    return function () {
+
+        var args = arguments;
+        process.nextTick(function () {
+
+            callback.apply(null, args);
+        });
+    };
+};
+
+
+exports.once = function (method) {
+
+    if (method._hoekOnce) {
+        return method;
+    }
+
+    var once = false;
+    var wrapped = function () {
+
+        if (!once) {
+            once = true;
+            method.apply(null, arguments);
+        }
+    };
+
+    wrapped._hoekOnce = true;
+
+    return wrapped;
+};
+
+
+exports.isAbsolutePath = function (path, platform) {
+
+    if (!path) {
+        return false;
+    }
+
+    if (Path.isAbsolute) {                      // node >= 0.11
+        return Path.isAbsolute(path);
+    }
+
+    platform = platform || process.platform;
+
+    // Unix
+
+    if (platform !== 'win32') {
+        return path[0] === '/';
+    }
+
+    // Windows
+
+    return !!/^(?:[a-zA-Z]:[\\\/])|(?:[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/])/.test(path);        // C:\ or \\something\something
+};
+
+
+exports.isInteger = function (value) {
+
+    return (typeof value === 'number' &&
+            parseFloat(value) === parseInt(value, 10) &&
+            !isNaN(value));
+};
+
+
+exports.ignore = function () { };
+
+
+exports.inherits = Util.inherits;
+
+
+exports.format = Util.format;
+
+
+exports.transform = function (source, transform, options) {
+
+    exports.assert(source === null || source === undefined || typeof source === 'object' || Array.isArray(source), 'Invalid source object: must be null, undefined, an object, or an array');
+
+    if (Array.isArray(source)) {
+        var results = [];
+        for (var i = 0, il = source.length; i < il; ++i) {
+            results.push(exports.transform(source[i], transform, options));
+        }
+        return results;
+    }
+
+    var result = {};
+    var keys = Object.keys(transform);
+
+    for (var k = 0, kl = keys.length; k < kl; ++k) {
+        var key = keys[k];
+        var path = key.split('.');
+        var sourcePath = transform[key];
+
+        exports.assert(typeof sourcePath === 'string', 'All mappings must be "." delineated strings');
+
+        var segment;
+        var res = result;
+
+        while (path.length > 1) {
+            segment = path.shift();
+            if (!res[segment]) {
+                res[segment] = {};
+            }
+            res = res[segment];
+        }
+        segment = path.shift();
+        res[segment] = exports.reach(source, sourcePath, options);
+    }
+
+    return result;
+};
+
+
+exports.uniqueFilename = function (path, extension) {
+
+    if (extension) {
+        extension = extension[0] !== '.' ? '.' + extension : extension;
+    }
+    else {
+        extension = '';
+    }
+
+    path = Path.resolve(path);
+    var name = [Date.now(), process.pid, Crypto.randomBytes(8).toString('hex')].join('-') + extension;
+    return Path.join(path, name);
+};
+
+
+exports.stringify = function () {
+
+    try {
+        return JSON.stringify.apply(null, arguments);
+    }
+    catch (err) {
+        return '[Cannot display object: ' + err.message + ']';
+    }
+};
+
+
+exports.shallow = function (source) {
+
+    var target = {};
+    var keys = Object.keys(source);
+    for (var i = 0, il = keys.length; i < il; ++i) {
+        var key = keys[i];
+        target[key] = source[key];
+    }
+
+    return target;
+};
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/package.json b/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..2ed5c3cf1611a222431ecd699164987d7cf5812c
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/package.json
@@ -0,0 +1,71 @@
+{
+  "_args": [
+    [
+      {
+        "raw": "hoek@https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
+        "scope": null,
+        "escapedName": "hoek",
+        "name": "hoek",
+        "rawSpec": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
+        "spec": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
+        "type": "remote"
+      },
+      "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin"
+    ]
+  ],
+  "_from": "hoek@>=2.0.0 <3.0.0",
+  "_id": "hoek@2.16.3",
+  "_inCache": true,
+  "_location": "/firebase-admin/hoek",
+  "_phantomChildren": {},
+  "_requested": {
+    "raw": "hoek@https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
+    "scope": null,
+    "escapedName": "hoek",
+    "name": "hoek",
+    "rawSpec": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
+    "spec": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
+    "type": "remote"
+  },
+  "_requiredBy": [
+    "/firebase-admin",
+    "/firebase-admin/joi",
+    "/firebase-admin/topo"
+  ],
+  "_resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
+  "_shasum": "20bb7403d3cea398e91dc4710a8ff1b8274a25ed",
+  "_shrinkwrap": null,
+  "_spec": "hoek@https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
+  "_where": "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin",
+  "bugs": {
+    "url": "https://github.com/hapijs/hoek/issues"
+  },
+  "dependencies": {},
+  "description": "General purpose node utilities",
+  "devDependencies": {
+    "code": "1.x.x",
+    "lab": "5.x.x"
+  },
+  "engines": {
+    "node": ">=0.10.40"
+  },
+  "homepage": "https://github.com/hapijs/hoek#readme",
+  "keywords": [
+    "utilities"
+  ],
+  "license": "BSD-3-Clause",
+  "main": "lib/index.js",
+  "name": "hoek",
+  "optionalDependencies": {},
+  "readme": "![hoek Logo](https://raw.github.com/hapijs/hoek/master/images/hoek.png)\n\nUtility methods for the hapi ecosystem. This module is not intended to solve every problem for everyone, but rather as a central place to store hapi-specific methods. If you're looking for a general purpose utility module, check out [lodash](https://github.com/lodash/lodash) or [underscore](https://github.com/jashkenas/underscore).\n\n[![Build Status](https://secure.travis-ci.org/hapijs/hoek.svg)](http://travis-ci.org/hapijs/hoek)\n\nLead Maintainer: [Nathan LaFreniere](https://github.com/nlf)\n\n# Table of Contents\n\n* [Introduction](#introduction \"Introduction\")\n* [Object](#object \"Object\")\n  * [clone](#cloneobj \"clone\")\n  * [cloneWithShallow](#clonewithshallowobj-keys \"cloneWithShallow\")\n  * [merge](#mergetarget-source-isnulloverride-ismergearrays \"merge\")\n  * [applyToDefaults](#applytodefaultsdefaults-options-isnulloverride \"applyToDefaults\")\n  * [applyToDefaultsWithShallow](#applytodefaultswithshallowdefaults-options-keys \"applyToDefaultsWithShallow\")\n  * [deepEqual](#deepequala-b \"deepEqual\")\n  * [unique](#uniquearray-key \"unique\")\n  * [mapToObject](#maptoobjectarray-key \"mapToObject\")\n  * [intersect](#intersectarray1-array2 \"intersect\")\n  * [contain](#containref-values-options \"contain\")\n  * [flatten](#flattenarray-target \"flatten\")\n  * [reach](#reachobj-chain-options \"reach\")\n  * [reachTemplate](#reachtemplateobj-template-options \"reachTemplate\")\n  * [transform](#transformobj-transform-options \"transform\")\n  * [shallow](#shallowobj \"shallow\")\n  * [stringify](#stringifyobj \"stringify\")\n* [Timer](#timer \"Timer\")\n* [Bench](#bench \"Bench\")\n* [Binary Encoding/Decoding](#binary-encodingdecoding \"Binary Encoding/Decoding\")\n  * [base64urlEncode](#base64urlencodevalue \"binary64urlEncode\")\n  * [base64urlDecode](#base64urldecodevalue \"binary64urlDecode\")\n* [Escaping Characters](#escaping-characters \"Escaping Characters\")\n  * [escapeHtml](#escapehtmlstring \"escapeHtml\")\n  * [escapeHeaderAttribute](#escapeheaderattributeattribute \"escapeHeaderAttribute\")\n  * [escapeRegex](#escaperegexstring \"escapeRegex\")\n* [Errors](#errors \"Errors\")\n  * [assert](#assertcondition-message \"assert\")\n  * [abort](#abortmessage \"abort\")\n  * [displayStack](#displaystackslice \"displayStack\")\n  * [callStack](#callstackslice \"callStack\")\n* [Function](#function \"Function\")\n  * [nextTick](#nexttickfn \"nextTick\")\n  * [once](#oncefn \"once\")\n  * [ignore](#ignore \"ignore\")\n* [Miscellaneous](#miscellaneous \"Miscellaneous\")\n  * [uniqueFilename](#uniquefilenamepath-extension \"uniqueFilename\")\n  * [isAbsolutePath](#isabsolutepathpath-platform \"isAbsolutePath\")\n  * [isInteger](#isintegervalue \"isInteger\")\n\n\n\n# Introduction\n\nThe *Hoek* library contains some common functions used within the hapi ecosystem. It comes with useful methods for Arrays (clone, merge, applyToDefaults), Objects (removeKeys, copy), Asserting and more.\n\nFor example, to use Hoek to set configuration with default options:\n```javascript\nvar Hoek = require('hoek');\n\nvar default = {url : \"www.github.com\", port : \"8000\", debug : true};\n\nvar config = Hoek.applyToDefaults(default, {port : \"3000\", admin : true});\n\n// In this case, config would be { url: 'www.github.com', port: '3000', debug: true, admin: true }\n```\n\nUnder each of the sections (such as Array), there are subsections which correspond to Hoek methods. Each subsection will explain how to use the corresponding method. In each js excerpt below, the `var Hoek = require('hoek');` is omitted for brevity.\n\n## Object\n\nHoek provides several helpful methods for objects and arrays.\n\n### clone(obj)\n\nThis method is used to clone an object or an array. A *deep copy* is made (duplicates everything, including values that are objects, as well as non-enumerable properties).\n\n```javascript\n\nvar nestedObj = {\n        w: /^something$/ig,\n        x: {\n            a: [1, 2, 3],\n            b: 123456,\n            c: new Date()\n        },\n        y: 'y',\n        z: new Date()\n    };\n\nvar copy = Hoek.clone(nestedObj);\n\ncopy.x.b = 100;\n\nconsole.log(copy.y);        // results in 'y'\nconsole.log(nestedObj.x.b); // results in 123456\nconsole.log(copy.x.b);      // results in 100\n```\n\n### cloneWithShallow(obj, keys)\nkeys is an array of key names to shallow copy\n\nThis method is also used to clone an object or array, however any keys listed in the `keys` array are shallow copied while those not listed are deep copied.\n\n```javascript\n\nvar nestedObj = {\n        w: /^something$/ig,\n        x: {\n            a: [1, 2, 3],\n            b: 123456,\n            c: new Date()\n        },\n        y: 'y',\n        z: new Date()\n    };\n\nvar copy = Hoek.cloneWithShallow(nestedObj, ['x']);\n\ncopy.x.b = 100;\n\nconsole.log(copy.y);        // results in 'y'\nconsole.log(nestedObj.x.b); // results in 100\nconsole.log(copy.x.b);      // results in 100\n```\n\n### merge(target, source, isNullOverride, isMergeArrays)\nisNullOverride, isMergeArrays default to true\n\nMerge all the properties of source into target, source wins in conflict, and by default null and undefined from source are applied.\nMerge is destructive where the target is modified. For non destructive merge, use `applyToDefaults`.\n\n\n```javascript\n\nvar target = {a: 1, b : 2};\nvar source = {a: 0, c: 5};\nvar source2 = {a: null, c: 5};\n\nHoek.merge(target, source);         // results in {a: 0, b: 2, c: 5}\nHoek.merge(target, source2);        // results in {a: null, b: 2, c: 5}\nHoek.merge(target, source2, false); // results in {a: 1, b: 2, c: 5}\n\nvar targetArray = [1, 2, 3];\nvar sourceArray = [4, 5];\n\nHoek.merge(targetArray, sourceArray);              // results in [1, 2, 3, 4, 5]\nHoek.merge(targetArray, sourceArray, true, false); // results in [4, 5]\n```\n\n### applyToDefaults(defaults, options, isNullOverride)\nisNullOverride defaults to false\n\nApply options to a copy of the defaults\n\n```javascript\n\nvar defaults = { host: \"localhost\", port: 8000 };\nvar options = { port: 8080 };\n\nvar config = Hoek.applyToDefaults(defaults, options); // results in { host: \"localhost\", port: 8080 }\n```\n\nApply options with a null value to a copy of the defaults\n\n```javascript\n\nvar defaults = { host: \"localhost\", port: 8000 };\nvar options = { host: null, port: 8080 };\n\nvar config = Hoek.applyToDefaults(defaults, options, true); // results in { host: null, port: 8080 }\n```\n\n### applyToDefaultsWithShallow(defaults, options, keys)\nkeys is an array of key names to shallow copy\n\nApply options to a copy of the defaults. Keys specified in the last parameter are shallow copied from options instead of merged.\n\n```javascript\n\nvar defaults = {\n        server: {\n            host: \"localhost\",\n            port: 8000\n        },\n        name: 'example'\n    };\n\nvar options = { server: { port: 8080 } };\n\nvar config = Hoek.applyToDefaultsWithShallow(defaults, options, ['server']); // results in { server: { port: 8080 }, name: 'example' }\n```\n\n### deepEqual(b, a, [options])\n\nPerforms a deep comparison of the two values including support for circular dependencies, prototype, and properties. To skip prototype comparisons, use `options.prototype = false`\n\n```javascript\nHoek.deepEqual({ a: [1, 2], b: 'string', c: { d: true } }, { a: [1, 2], b: 'string', c: { d: true } }); //results in true\nHoek.deepEqual(Object.create(null), {}, { prototype: false }); //results in true\nHoek.deepEqual(Object.create(null), {}); //results in false\n```\n\n### unique(array, key)\n\nRemove duplicate items from Array\n\n```javascript\n\nvar array = [1, 2, 2, 3, 3, 4, 5, 6];\n\nvar newArray = Hoek.unique(array);    // results in [1,2,3,4,5,6]\n\narray = [{id: 1}, {id: 1}, {id: 2}];\n\nnewArray = Hoek.unique(array, \"id\");  // results in [{id: 1}, {id: 2}]\n```\n\n### mapToObject(array, key)\n\nConvert an Array into an Object\n\n```javascript\n\nvar array = [1,2,3];\nvar newObject = Hoek.mapToObject(array);   // results in [{\"1\": true}, {\"2\": true}, {\"3\": true}]\n\narray = [{id: 1}, {id: 2}];\nnewObject = Hoek.mapToObject(array, \"id\"); // results in [{\"id\": 1}, {\"id\": 2}]\n```\n\n### intersect(array1, array2)\n\nFind the common unique items in two arrays\n\n```javascript\n\nvar array1 = [1, 2, 3];\nvar array2 = [1, 4, 5];\n\nvar newArray = Hoek.intersect(array1, array2); // results in [1]\n```\n\n### contain(ref, values, [options])\n\nTests if the reference value contains the provided values where:\n- `ref` - the reference string, array, or object.\n- `values` - a single or array of values to find within the `ref` value. If `ref` is an object, `values` can be a key name,\n  an array of key names, or an object with key-value pairs to compare.\n- `options` - an optional object with the following optional settings:\n    - `deep` - if `true`, performed a deep comparison of the values.\n    - `once` - if `true`, allows only one occurrence of each value.\n    - `only` - if `true`, does not allow values not explicitly listed.\n    - `part` - if `true`, allows partial match of the values (at least one must always match).\n\nNote: comparing a string to overlapping values will result in failed comparison (e.g. `contain('abc', ['ab', 'bc'])`).\nAlso, if an object key's value does not match the provided value, `false` is returned even when `part` is specified.\n\n```javascript\nHoek.contain('aaa', 'a', { only: true });\t\t\t\t\t\t\t// true\nHoek.contain([{ a: 1 }], [{ a: 1 }], { deep: true });\t\t\t\t// true\nHoek.contain([1, 2, 2], [1, 2], { once: true });\t\t\t\t\t// false\nHoek.contain({ a: 1, b: 2, c: 3 }, { a: 1, d: 4 }, { part: true }); // true\n```\n\n### flatten(array, [target])\n\nFlatten an array\n\n```javascript\n\nvar array = [1, [2, 3]];\n\nvar flattenedArray = Hoek.flatten(array); // results in [1, 2, 3]\n\narray = [1, [2, 3]];\ntarget = [4, [5]];\n\nflattenedArray = Hoek.flatten(array, target); // results in [4, [5], 1, 2, 3]\n```\n\n### reach(obj, chain, [options])\n\nConverts an object key chain string to reference\n\n- `options` - optional settings\n    - `separator` - string to split chain path on, defaults to '.'\n    - `default` - value to return if the path or value is not present, default is `undefined`\n    - `strict` - if `true`, will throw an error on missing member, default is `false`\n    - `functions` - if `true` allow traversing functions for properties. `false` will throw an error if a function is part of the chain.\n\nA chain including negative numbers will work like negative indices on an\narray.\n\nIf chain is `null`, `undefined` or `false`, the object itself will be returned.\n\n```javascript\n\nvar chain = 'a.b.c';\nvar obj = {a : {b : { c : 1}}};\n\nHoek.reach(obj, chain); // returns 1\n\nvar chain = 'a.b.-1';\nvar obj = {a : {b : [2,3,6]}};\n\nHoek.reach(obj, chain); // returns 6\n```\n\n### reachTemplate(obj, template, [options])\n\nReplaces string parameters (`{name}`) with their corresponding object key values by applying the\n(`reach()`)[#reachobj-chain-options] method where:\n\n- `obj` - the context object used for key lookup.\n- `template` - a string containing `{}` parameters.\n- `options` - optional (`reach()`)[#reachobj-chain-options] options.\n\n```javascript\n\nvar chain = 'a.b.c';\nvar obj = {a : {b : { c : 1}}};\n\nHoek.reachTemplate(obj, '1+{a.b.c}=2'); // returns '1+1=2'\n```\n\n### transform(obj, transform, [options])\n\nTransforms an existing object into a new one based on the supplied `obj` and `transform` map. `options` are the same as the `reach` options. The first argument can also be an array of objects. In that case the method will return an array of transformed objects.\n\n```javascript\nvar source = {\n    address: {\n        one: '123 main street',\n        two: 'PO Box 1234'\n    },\n    title: 'Warehouse',\n    state: 'CA'\n};\n\nvar result = Hoek.transform(source, {\n    'person.address.lineOne': 'address.one',\n    'person.address.lineTwo': 'address.two',\n    'title': 'title',\n    'person.address.region': 'state'\n});\n// Results in\n// {\n//     person: {\n//         address: {\n//             lineOne: '123 main street',\n//             lineTwo: 'PO Box 1234',\n//             region: 'CA'\n//         }\n//     },\n//     title: 'Warehouse'\n// }\n```\n\n### shallow(obj)\n\nPerforms a shallow copy by copying the references of all the top level children where:\n- `obj` - the object to be copied.\n\n```javascript\nvar shallow = Hoek.shallow({ a: { b: 1 } });\n```\n\n### stringify(obj)\n\nConverts an object to string using the built-in `JSON.stringify()` method with the difference that any errors are caught\nand reported back in the form of the returned string. Used as a shortcut for displaying information to the console (e.g. in\nerror message) without the need to worry about invalid conversion.\n\n```javascript\nvar a = {};\na.b = a;\nHoek.stringify(a);\t\t// Returns '[Cannot display object: Converting circular structure to JSON]'\n```\n\n# Timer\n\nA Timer object. Initializing a new timer object sets the ts to the number of milliseconds elapsed since 1 January 1970 00:00:00 UTC.\n\n```javascript\n\nvar timerObj = new Hoek.Timer();\nconsole.log(\"Time is now: \" + timerObj.ts);\nconsole.log(\"Elapsed time from initialization: \" + timerObj.elapsed() + 'milliseconds');\n```\n\n\n# Bench\n\nSame as Timer with the exception that `ts` stores the internal node clock which is not related to `Date.now()` and cannot be used to display\nhuman-readable timestamps. More accurate for benchmarking or internal timers.\n\n# Binary Encoding/Decoding\n\n### base64urlEncode(value)\n\nEncodes value in Base64 or URL encoding\n\n### base64urlDecode(value)\n\nDecodes data in Base64 or URL encoding.\n# Escaping Characters\n\nHoek provides convenient methods for escaping html characters. The escaped characters are as followed:\n\n```javascript\n\ninternals.htmlEscaped = {\n    '&': '&amp;',\n    '<': '&lt;',\n    '>': '&gt;',\n    '\"': '&quot;',\n    \"'\": '&#x27;',\n    '`': '&#x60;'\n};\n```\n\n### escapeHtml(string)\n\n```javascript\n\nvar string = '<html> hey </html>';\nvar escapedString = Hoek.escapeHtml(string); // returns &lt;html&gt; hey &lt;/html&gt;\n```\n\n### escapeHeaderAttribute(attribute)\n\nEscape attribute value for use in HTTP header\n\n```javascript\n\nvar a = Hoek.escapeHeaderAttribute('I said \"go w\\\\o me\"');  //returns I said \\\"go w\\\\o me\\\"\n```\n\n\n### escapeRegex(string)\n\nEscape string for Regex construction\n\n```javascript\n\nvar a = Hoek.escapeRegex('4^f$s.4*5+-_?%=#!:@|~\\\\/`\"(>)[<]d{}s,');  // returns 4\\^f\\$s\\.4\\*5\\+\\-_\\?%\\=#\\!\\:@\\|~\\\\\\/`\"\\(>\\)\\[<\\]d\\{\\}s\\,\n```\n\n# Errors\n\n### assert(condition, message)\n\n```javascript\n\nvar a = 1, b = 2;\n\nHoek.assert(a === b, 'a should equal b');  // Throws 'a should equal b'\n```\n\nNote that you may also pass an already created Error object as the second parameter, and `assert` will throw that object.\n\n```javascript\n\nvar a = 1, b = 2;\n\nHoek.assert(a === b, new Error('a should equal b')); // Throws the given error object\n```\n\n### abort(message)\n\nFirst checks if `process.env.NODE_ENV === 'test'`, and if so, throws error message. Otherwise,\ndisplays most recent stack and then exits process.\n\n\n\n### displayStack(slice)\n\nDisplays the trace stack\n\n```javascript\n\nvar stack = Hoek.displayStack();\nconsole.log(stack); // returns something like:\n\n[ 'null (/Users/user/Desktop/hoek/test.js:4:18)',\n  'Module._compile (module.js:449:26)',\n  'Module._extensions..js (module.js:467:10)',\n  'Module.load (module.js:356:32)',\n  'Module._load (module.js:312:12)',\n  'Module.runMain (module.js:492:10)',\n  'startup.processNextTick.process._tickCallback (node.js:244:9)' ]\n```\n\n### callStack(slice)\n\nReturns a trace stack array.\n\n```javascript\n\nvar stack = Hoek.callStack();\nconsole.log(stack);  // returns something like:\n\n[ [ '/Users/user/Desktop/hoek/test.js', 4, 18, null, false ],\n  [ 'module.js', 449, 26, 'Module._compile', false ],\n  [ 'module.js', 467, 10, 'Module._extensions..js', false ],\n  [ 'module.js', 356, 32, 'Module.load', false ],\n  [ 'module.js', 312, 12, 'Module._load', false ],\n  [ 'module.js', 492, 10, 'Module.runMain', false ],\n  [ 'node.js',\n    244,\n    9,\n    'startup.processNextTick.process._tickCallback',\n    false ] ]\n```\n\n## Function\n\n### nextTick(fn)\n\nReturns a new function that wraps `fn` in `process.nextTick`.\n\n```javascript\n\nvar myFn = function () {\n    console.log('Do this later');\n};\n\nvar nextFn = Hoek.nextTick(myFn);\n\nnextFn();\nconsole.log('Do this first');\n\n// Results in:\n//\n// Do this first\n// Do this later\n```\n\n### once(fn)\n\nReturns a new function that can be run multiple times, but makes sure `fn` is only run once.\n\n```javascript\n\nvar myFn = function () {\n    console.log('Ran myFn');\n};\n\nvar onceFn = Hoek.once(myFn);\nonceFn(); // results in \"Ran myFn\"\nonceFn(); // results in undefined\n```\n\n### ignore\n\nA simple no-op function. It does nothing at all.\n\n## Miscellaneous\n\n### uniqueFilename(path, extension)\n`path` to prepend with the randomly generated file name. `extension` is the optional file extension, defaults to `''`.\n\nReturns a randomly generated file name at the specified `path`. The result is a fully resolved path to a file.\n\n```javascript\nvar result = Hoek.uniqueFilename('./test/modules', 'txt'); // results in \"full/path/test/modules/{random}.txt\"\n```\n\n### isAbsolutePath(path, [platform])\n\nDetermines whether `path` is an absolute path. Returns `true` or `false`.\n\n- `path` - A file path to test for whether it is absolute or not.\n- `platform` - An optional parameter used for specifying the platform. Defaults to `process.platform`.\n\n### isInteger(value)\n\nCheck `value` to see if it is an integer.  Returns true/false.\n\n```javascript\nvar result = Hoek.isInteger('23')\n```\n",
+  "readmeFilename": "README.md",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/hapijs/hoek.git"
+  },
+  "scripts": {
+    "test": "lab -a code -t 100 -L",
+    "test-cov-html": "lab -a code -t 100 -L -r html -o coverage.html"
+  },
+  "version": "2.16.3"
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/test/escaper.js b/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/test/escaper.js
new file mode 100644
index 0000000000000000000000000000000000000000..a5d048f7bcbca3c4c436b442c523aff702909aaa
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/test/escaper.js
@@ -0,0 +1,88 @@
+// Load modules
+
+var Code = require('code');
+var Hoek = require('../lib');
+var Lab = require('lab');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var lab = exports.lab = Lab.script();
+var describe = lab.experiment;
+var it = lab.test;
+var expect = Code.expect;
+
+
+describe('escapeJavaScript()', function () {
+
+    it('encodes / characters', function (done) {
+
+        var encoded = Hoek.escapeJavaScript('<script>alert(1)</script>');
+        expect(encoded).to.equal('\\x3cscript\\x3ealert\\x281\\x29\\x3c\\x2fscript\\x3e');
+        done();
+    });
+
+    it('encodes \' characters', function (done) {
+
+        var encoded = Hoek.escapeJavaScript('something(\'param\')');
+        expect(encoded).to.equal('something\\x28\\x27param\\x27\\x29');
+        done();
+    });
+
+    it('encodes large unicode characters with the correct padding', function (done) {
+
+        var encoded = Hoek.escapeJavaScript(String.fromCharCode(500) + String.fromCharCode(1000));
+        expect(encoded).to.equal('\\u0500\\u1000');
+        done();
+    });
+
+    it('doesn\'t throw an exception when passed null', function (done) {
+
+        var encoded = Hoek.escapeJavaScript(null);
+        expect(encoded).to.equal('');
+        done();
+    });
+});
+
+describe('escapeHtml()', function () {
+
+    it('encodes / characters', function (done) {
+
+        var encoded = Hoek.escapeHtml('<script>alert(1)</script>');
+        expect(encoded).to.equal('&lt;script&gt;alert&#x28;1&#x29;&lt;&#x2f;script&gt;');
+        done();
+    });
+
+    it('encodes < and > as named characters', function (done) {
+
+        var encoded = Hoek.escapeHtml('<script><>');
+        expect(encoded).to.equal('&lt;script&gt;&lt;&gt;');
+        done();
+    });
+
+    it('encodes large unicode characters', function (done) {
+
+        var encoded = Hoek.escapeHtml(String.fromCharCode(500) + String.fromCharCode(1000));
+        expect(encoded).to.equal('&#500;&#1000;');
+        done();
+    });
+
+    it('doesn\'t throw an exception when passed null', function (done) {
+
+        var encoded = Hoek.escapeHtml(null);
+        expect(encoded).to.equal('');
+        done();
+    });
+
+    it('encodes {} characters', function (done) {
+
+        var encoded = Hoek.escapeHtml('{}');
+        expect(encoded).to.equal('&#x7b;&#x7d;');
+        done();
+    });
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/test/index.js b/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/test/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..1e8ef620f361a2c6d425ebc4ff6858487c396aa4
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/test/index.js
@@ -0,0 +1,2513 @@
+// Load modules
+
+var Fs = require('fs');
+var Path = require('path');
+var Code = require('code');
+var Hoek = require('../lib');
+var Lab = require('lab');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var lab = exports.lab = Lab.script();
+var describe = lab.experiment;
+var it = lab.test;
+var expect = Code.expect;
+
+
+var nestedObj = {
+    v: [7, 8, 9],
+    w: /^something$/igm,
+    x: {
+        a: [1, 2, 3],
+        b: 123456,
+        c: new Date(),
+        d: /hi/igm,
+        e: /hello/
+    },
+    y: 'y',
+    z: new Date(1378775452757)
+};
+
+var dupsArray = [nestedObj, { z: 'z' }, nestedObj];
+var reducedDupsArray = [nestedObj, { z: 'z' }];
+
+describe('clone()', function () {
+
+    it('clones a nested object', function (done) {
+
+        var a = nestedObj;
+        var b = Hoek.clone(a);
+
+        expect(a).to.deep.equal(b);
+        expect(a.z.getTime()).to.equal(b.z.getTime());
+        done();
+    });
+
+    it('clones a null object', function (done) {
+
+        var b = Hoek.clone(null);
+
+        expect(b).to.equal(null);
+        done();
+    });
+
+    it('should not convert undefined properties to null', function (done) {
+
+        var obj = { something: undefined };
+        var b = Hoek.clone(obj);
+
+        expect(typeof b.something).to.equal('undefined');
+        done();
+    });
+
+    it('should not throw on circular reference', function (done) {
+
+        var a = {};
+        a.x = a;
+
+        var test = function () {
+
+            var b = Hoek.clone(a);
+        };
+
+        expect(test).to.not.throw();
+        done();
+    });
+
+    it('clones circular reference', function (done) {
+
+        var x = {
+            'z': new Date()
+        };
+        x.y = x;
+
+        var b = Hoek.clone(x);
+        expect(Object.keys(b.y)).to.deep.equal(Object.keys(x));
+        expect(b.z).to.not.equal(x.z);
+        expect(b.y).to.not.equal(x.y);
+        expect(b.y.z).to.not.equal(x.y.z);
+        expect(b.y).to.equal(b);
+        expect(b.y.y.y.y).to.equal(b);
+        done();
+    });
+
+    it('clones an object with a null prototype', function (done) {
+
+        var obj = Object.create(null);
+        var b = Hoek.clone(obj);
+
+        expect(b).to.deep.equal(obj);
+        done();
+    });
+
+    it('clones deeply nested object', function (done) {
+
+        var a = {
+            x: {
+                y: {
+                    a: [1, 2, 3],
+                    b: 123456,
+                    c: new Date(),
+                    d: /hi/igm,
+                    e: /hello/
+                }
+            }
+        };
+
+        var b = Hoek.clone(a);
+
+        expect(a).to.deep.equal(b);
+        expect(a.x.y.c.getTime()).to.equal(b.x.y.c.getTime());
+        done();
+    });
+
+    it('clones arrays', function (done) {
+
+        var a = [1, 2, 3];
+
+        var b = Hoek.clone(a);
+
+        expect(a).to.deep.equal(b);
+        done();
+    });
+
+    it('performs actual copy for shallow keys (no pass by reference)', function (done) {
+
+        var x = Hoek.clone(nestedObj);
+        var y = Hoek.clone(nestedObj);
+
+        // Date
+        expect(x.z).to.not.equal(nestedObj.z);
+        expect(x.z).to.not.equal(y.z);
+
+        // Regex
+        expect(x.w).to.not.equal(nestedObj.w);
+        expect(x.w).to.not.equal(y.w);
+
+        // Array
+        expect(x.v).to.not.equal(nestedObj.v);
+        expect(x.v).to.not.equal(y.v);
+
+        // Immutable(s)
+        x.y = 5;
+        expect(x.y).to.not.equal(nestedObj.y);
+        expect(x.y).to.not.equal(y.y);
+
+        done();
+    });
+
+    it('performs actual copy for deep keys (no pass by reference)', function (done) {
+
+        var x = Hoek.clone(nestedObj);
+        var y = Hoek.clone(nestedObj);
+
+        expect(x.x.c).to.not.equal(nestedObj.x.c);
+        expect(x.x.c).to.not.equal(y.x.c);
+
+        expect(x.x.c.getTime()).to.equal(nestedObj.x.c.getTime());
+        expect(x.x.c.getTime()).to.equal(y.x.c.getTime());
+        done();
+    });
+
+    it('copies functions with properties', function (done) {
+
+        var a = {
+            x: function () {
+
+                return 1;
+            },
+            y: {}
+        };
+        a.x.z = 'string in function';
+        a.x.v = function () {
+
+            return 2;
+        };
+        a.y.u = a.x;
+
+        var b = Hoek.clone(a);
+        expect(b.x()).to.equal(1);
+        expect(b.x.v()).to.equal(2);
+        expect(b.y.u).to.equal(b.x);
+        expect(b.x.z).to.equal('string in function');
+        done();
+    });
+
+    it('should copy a buffer', function (done) {
+
+        var tls = {
+            key: new Buffer([1, 2, 3, 4, 5]),
+            cert: new Buffer([1, 2, 3, 4, 5, 6, 10])
+        };
+
+        var copiedTls = Hoek.clone(tls);
+        expect(Buffer.isBuffer(copiedTls.key)).to.equal(true);
+        expect(JSON.stringify(copiedTls.key)).to.equal(JSON.stringify(tls.key));
+        expect(Buffer.isBuffer(copiedTls.cert)).to.equal(true);
+        expect(JSON.stringify(copiedTls.cert)).to.equal(JSON.stringify(tls.cert));
+        done();
+    });
+
+    it('clones an object with a prototype', function (done) {
+
+        var Obj = function () {
+
+            this.a = 5;
+        };
+
+        Obj.prototype.b = function () {
+
+            return 'c';
+        };
+
+        var a = new Obj();
+        var b = Hoek.clone(a);
+
+        expect(b.a).to.equal(5);
+        expect(b.b()).to.equal('c');
+        expect(a).to.deep.equal(b);
+        done();
+    });
+
+    it('reuses cloned Date object', function (done) {
+
+        var obj = {
+            a: new Date()
+        };
+
+        obj.b = obj.a;
+
+        var copy = Hoek.clone(obj);
+        expect(copy.a).to.equal(copy.b);
+        done();
+    });
+
+    it('shallow copies an object with a prototype and isImmutable flag', function (done) {
+
+        var Obj = function () {
+
+            this.value = 5;
+        };
+
+        Obj.prototype.b = function () {
+
+            return 'c';
+        };
+
+        Obj.prototype.isImmutable = true;
+
+        var obj = {
+            a: new Obj()
+        };
+
+        var copy = Hoek.clone(obj);
+
+        expect(obj.a.value).to.equal(5);
+        expect(copy.a.value).to.equal(5);
+        expect(copy.a.b()).to.equal('c');
+        expect(obj.a).to.equal(copy.a);
+        done();
+    });
+
+    it('clones an object with property getter without executing it', function (done) {
+
+        var obj = {};
+        var value = 1;
+        var execCount = 0;
+
+        Object.defineProperty(obj, 'test', {
+            enumerable: true,
+            configurable: true,
+            get: function () {
+
+                ++execCount;
+                return value;
+            }
+        });
+
+        var copy = Hoek.clone(obj);
+        expect(execCount).to.equal(0);
+        expect(copy.test).to.equal(1);
+        expect(execCount).to.equal(1);
+        done();
+    });
+
+    it('clones an object with property getter and setter', function (done) {
+
+        var obj = {
+            _test: 0
+        };
+
+        Object.defineProperty(obj, 'test', {
+            enumerable: true,
+            configurable: true,
+            get: function () {
+
+                return this._test;
+            },
+            set: function (value) {
+
+                this._test = value - 1;
+            }
+        });
+
+        var copy = Hoek.clone(obj);
+        expect(copy.test).to.equal(0);
+        copy.test = 5;
+        expect(copy.test).to.equal(4);
+        done();
+    });
+
+    it('clones an object with only property setter', function (done) {
+
+        var obj = {
+            _test: 0
+        };
+
+        Object.defineProperty(obj, 'test', {
+            enumerable: true,
+            configurable: true,
+            set: function (value) {
+
+                this._test = value - 1;
+            }
+        });
+
+        var copy = Hoek.clone(obj);
+        expect(copy._test).to.equal(0);
+        copy.test = 5;
+        expect(copy._test).to.equal(4);
+        done();
+    });
+
+    it('clones an object with non-enumerable properties', function (done) {
+
+        var obj = {
+            _test: 0
+        };
+
+        Object.defineProperty(obj, 'test', {
+            enumerable: false,
+            configurable: true,
+            set: function (value) {
+
+                this._test = value - 1;
+            }
+        });
+
+        var copy = Hoek.clone(obj);
+        expect(copy._test).to.equal(0);
+        copy.test = 5;
+        expect(copy._test).to.equal(4);
+        done();
+    });
+
+    it('clones an object where getOwnPropertyDescriptor returns undefined', function (done) {
+
+        var oldGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
+        var obj = { a: 'b' };
+        Object.getOwnPropertyDescriptor = function () {
+
+            return undefined;
+        };
+
+        var copy = Hoek.clone(obj);
+        Object.getOwnPropertyDescriptor = oldGetOwnPropertyDescriptor;
+        expect(copy).to.deep.equal(obj);
+        done();
+    });
+});
+
+describe('merge()', function () {
+
+    it('deep copies source items', function (done) {
+
+        var target = {
+            b: 3,
+            d: []
+        };
+
+        var source = {
+            c: {
+                d: 1
+            },
+            d: [{ e: 1 }]
+        };
+
+        Hoek.merge(target, source);
+        expect(target.c).to.not.equal(source.c);
+        expect(target.c).to.deep.equal(source.c);
+        expect(target.d).to.not.equal(source.d);
+        expect(target.d[0]).to.not.equal(source.d[0]);
+        expect(target.d).to.deep.equal(source.d);
+        done();
+    });
+
+    it('merges array over an object', function (done) {
+
+        var a = {
+            x: ['n', 'm']
+        };
+
+        var b = {
+            x: {
+                n: '1',
+                m: '2'
+            }
+        };
+
+        Hoek.merge(b, a);
+        expect(a.x[0]).to.equal('n');
+        expect(a.x.n).to.not.exist();
+        done();
+    });
+
+    it('merges object over an array', function (done) {
+
+        var a = {
+            x: ['n', 'm']
+        };
+
+        var b = {
+            x: {
+                n: '1',
+                m: '2'
+            }
+        };
+
+        Hoek.merge(a, b);
+        expect(a.x.n).to.equal('1');
+        expect(a.x[0]).to.not.exist();
+        done();
+    });
+
+    it('does not throw if source is null', function (done) {
+
+        var a = {};
+        var b = null;
+        var c = null;
+
+        expect(function () {
+
+            c = Hoek.merge(a, b);
+        }).to.not.throw();
+
+        expect(c).to.equal(a);
+        done();
+    });
+
+    it('does not throw if source is undefined', function (done) {
+
+        var a = {};
+        var b;
+        var c = null;
+
+        expect(function () {
+
+            c = Hoek.merge(a, b);
+        }).to.not.throw();
+
+        expect(c).to.equal(a);
+        done();
+    });
+
+    it('throws if source is not an object', function (done) {
+
+        expect(function () {
+
+            var a = {};
+            var b = 0;
+
+            Hoek.merge(a, b);
+        }).to.throw('Invalid source value: must be null, undefined, or an object');
+        done();
+    });
+
+    it('throws if target is not an object', function (done) {
+
+        expect(function () {
+
+            var a = 0;
+            var b = {};
+
+            Hoek.merge(a, b);
+        }).to.throw('Invalid target value: must be an object');
+        done();
+    });
+
+    it('throws if target is not an array and source is', function (done) {
+
+        expect(function () {
+
+            var a = {};
+            var b = [1, 2];
+
+            Hoek.merge(a, b);
+        }).to.throw('Cannot merge array onto an object');
+        done();
+    });
+
+    it('returns the same object when merging arrays', function (done) {
+
+        var a = [];
+        var b = [1, 2];
+
+        expect(Hoek.merge(a, b)).to.equal(a);
+        done();
+    });
+
+    it('combines an empty object with a non-empty object', function (done) {
+
+        var a = {};
+        var b = nestedObj;
+
+        var c = Hoek.merge(a, b);
+        expect(a).to.deep.equal(b);
+        expect(c).to.deep.equal(b);
+        done();
+    });
+
+    it('overrides values in target', function (done) {
+
+        var a = { x: 1, y: 2, z: 3, v: 5, t: 'test', m: 'abc' };
+        var b = { x: null, z: 4, v: 0, t: { u: 6 }, m: '123' };
+
+        var c = Hoek.merge(a, b);
+        expect(c.x).to.equal(null);
+        expect(c.y).to.equal(2);
+        expect(c.z).to.equal(4);
+        expect(c.v).to.equal(0);
+        expect(c.m).to.equal('123');
+        expect(c.t).to.deep.equal({ u: 6 });
+        done();
+    });
+
+    it('overrides values in target (flip)', function (done) {
+
+        var a = { x: 1, y: 2, z: 3, v: 5, t: 'test', m: 'abc' };
+        var b = { x: null, z: 4, v: 0, t: { u: 6 }, m: '123' };
+
+        var d = Hoek.merge(b, a);
+        expect(d.x).to.equal(1);
+        expect(d.y).to.equal(2);
+        expect(d.z).to.equal(3);
+        expect(d.v).to.equal(5);
+        expect(d.m).to.equal('abc');
+        expect(d.t).to.deep.equal('test');
+        done();
+    });
+
+    it('retains Date properties', function (done) {
+
+        var a = { x: new Date(1378776452757) };
+
+        var b = Hoek.merge({}, a);
+        expect(a.x.getTime()).to.equal(b.x.getTime());
+        done();
+    });
+
+    it('retains Date properties when merging keys', function (done) {
+
+        var a = { x: new Date(1378776452757) };
+
+        var b = Hoek.merge({ x: {} }, a);
+        expect(a.x.getTime()).to.equal(b.x.getTime());
+        done();
+    });
+
+    it('overrides Buffer', function (done) {
+
+        var a = { x: new Buffer('abc') };
+
+        var b = Hoek.merge({ x: {} }, a);
+        expect(a.x.toString()).to.equal('abc');
+        done();
+    });
+});
+
+describe('applyToDefaults()', function () {
+
+    var defaults = {
+        a: 1,
+        b: 2,
+        c: {
+            d: 3,
+            e: [5, 6]
+        },
+        f: 6,
+        g: 'test'
+    };
+
+    it('throws when target is null', function (done) {
+
+        expect(function () {
+
+            Hoek.applyToDefaults(null, {});
+        }).to.throw('Invalid defaults value: must be an object');
+        done();
+    });
+
+    it('returns null if options is false', function (done) {
+
+        var result = Hoek.applyToDefaults(defaults, false);
+        expect(result).to.equal(null);
+        done();
+    });
+
+    it('returns null if options is null', function (done) {
+
+        var result = Hoek.applyToDefaults(defaults, null);
+        expect(result).to.equal(null);
+        done();
+    });
+
+    it('returns null if options is undefined', function (done) {
+
+        var result = Hoek.applyToDefaults(defaults, undefined);
+        expect(result).to.equal(null);
+        done();
+    });
+
+    it('returns a copy of defaults if options is true', function (done) {
+
+        var result = Hoek.applyToDefaults(defaults, true);
+        expect(result).to.deep.equal(defaults);
+        done();
+    });
+
+    it('applies object to defaults', function (done) {
+
+        var obj = {
+            a: null,
+            c: {
+                e: [4]
+            },
+            f: 0,
+            g: {
+                h: 5
+            }
+        };
+
+        var result = Hoek.applyToDefaults(defaults, obj);
+        expect(result.c.e).to.deep.equal([4]);
+        expect(result.a).to.equal(1);
+        expect(result.b).to.equal(2);
+        expect(result.f).to.equal(0);
+        expect(result.g).to.deep.equal({ h: 5 });
+        done();
+    });
+
+    it('applies object to defaults with null', function (done) {
+
+        var obj = {
+            a: null,
+            c: {
+                e: [4]
+            },
+            f: 0,
+            g: {
+                h: 5
+            }
+        };
+
+        var result = Hoek.applyToDefaults(defaults, obj, true);
+        expect(result.c.e).to.deep.equal([4]);
+        expect(result.a).to.equal(null);
+        expect(result.b).to.equal(2);
+        expect(result.f).to.equal(0);
+        expect(result.g).to.deep.equal({ h: 5 });
+        done();
+    });
+});
+
+describe('cloneWithShallow()', function () {
+
+    it('deep clones except for listed keys', function (done) {
+
+        var source = {
+            a: {
+                b: 5
+            },
+            c: {
+                d: 6
+            }
+        };
+
+        var copy = Hoek.cloneWithShallow(source, ['c']);
+        expect(copy).to.deep.equal(source);
+        expect(copy).to.not.equal(source);
+        expect(copy.a).to.not.equal(source.a);
+        expect(copy.b).to.equal(source.b);
+        done();
+    });
+
+    it('returns immutable value', function (done) {
+
+        expect(Hoek.cloneWithShallow(5)).to.equal(5);
+        done();
+    });
+
+    it('returns null value', function (done) {
+
+        expect(Hoek.cloneWithShallow(null)).to.equal(null);
+        done();
+    });
+
+    it('returns undefined value', function (done) {
+
+        expect(Hoek.cloneWithShallow(undefined)).to.equal(undefined);
+        done();
+    });
+
+    it('deep clones except for listed keys (including missing keys)', function (done) {
+
+        var source = {
+            a: {
+                b: 5
+            },
+            c: {
+                d: 6
+            }
+        };
+
+        var copy = Hoek.cloneWithShallow(source, ['c', 'v']);
+        expect(copy).to.deep.equal(source);
+        expect(copy).to.not.equal(source);
+        expect(copy.a).to.not.equal(source.a);
+        expect(copy.b).to.equal(source.b);
+        done();
+    });
+});
+
+describe('applyToDefaultsWithShallow()', function () {
+
+    it('shallow copies the listed keys from options without merging', function (done) {
+
+        var defaults = {
+            a: {
+                b: 5,
+                e: 3
+            },
+            c: {
+                d: 7,
+                g: 1
+            }
+        };
+
+        var options = {
+            a: {
+                b: 4
+            },
+            c: {
+                d: 6,
+                f: 7
+            }
+        };
+
+        var merged = Hoek.applyToDefaultsWithShallow(defaults, options, ['a']);
+        expect(merged).to.deep.equal({ a: { b: 4 }, c: { d: 6, g: 1, f: 7 } });
+        expect(merged.a).to.equal(options.a);
+        expect(merged.a).to.not.equal(defaults.a);
+        expect(merged.c).to.not.equal(options.c);
+        expect(merged.c).to.not.equal(defaults.c);
+        done();
+    });
+
+    it('shallow copies the nested keys (override)', function (done) {
+
+        var defaults = {
+            a: {
+                b: 5
+            },
+            c: {
+                d: 7,
+                g: 1
+            }
+        };
+
+        var options = {
+            a: {
+                b: 4
+            },
+            c: {
+                d: 6,
+                g: {
+                    h: 8
+                }
+            }
+        };
+
+        var merged = Hoek.applyToDefaultsWithShallow(defaults, options, ['c.g']);
+        expect(merged).to.deep.equal({ a: { b: 4 }, c: { d: 6, g: { h: 8 } } });
+        expect(merged.c.g).to.equal(options.c.g);
+        done();
+    });
+
+    it('shallow copies the nested keys (missing)', function (done) {
+
+        var defaults = {
+            a: {
+                b: 5
+            }
+        };
+
+        var options = {
+            a: {
+                b: 4
+            },
+            c: {
+                g: {
+                    h: 8
+                }
+            }
+        };
+
+        var merged = Hoek.applyToDefaultsWithShallow(defaults, options, ['c.g']);
+        expect(merged).to.deep.equal({ a: { b: 4 }, c: { g: { h: 8 } } });
+        expect(merged.c.g).to.equal(options.c.g);
+        done();
+    });
+
+    it('shallow copies the nested keys (override)', function (done) {
+
+        var defaults = {
+            a: {
+                b: 5
+            },
+            c: {
+                g: {
+                    d: 7
+                }
+            }
+        };
+
+        var options = {
+            a: {
+                b: 4
+            },
+            c: {
+                g: {
+                    h: 8
+                }
+            }
+        };
+
+        var merged = Hoek.applyToDefaultsWithShallow(defaults, options, ['c.g']);
+        expect(merged).to.deep.equal({ a: { b: 4 }, c: { g: { h: 8 } } });
+        expect(merged.c.g).to.equal(options.c.g);
+        done();
+    });
+
+    it('shallow copies the nested keys (deeper)', function (done) {
+
+        var defaults = {
+            a: {
+                b: 5
+            }
+        };
+
+        var options = {
+            a: {
+                b: 4
+            },
+            c: {
+                g: {
+                    r: {
+                        h: 8
+                    }
+                }
+            }
+        };
+
+        var merged = Hoek.applyToDefaultsWithShallow(defaults, options, ['c.g.r']);
+        expect(merged).to.deep.equal({ a: { b: 4 }, c: { g: { r: { h: 8 } } } });
+        expect(merged.c.g.r).to.equal(options.c.g.r);
+        done();
+    });
+
+    it('shallow copies the nested keys (not present)', function (done) {
+
+        var defaults = {
+            a: {
+                b: 5
+            }
+        };
+
+        var options = {
+            a: {
+                b: 4
+            },
+            c: {
+                g: {
+                    r: {
+                        h: 8
+                    }
+                }
+            }
+        };
+
+        var merged = Hoek.applyToDefaultsWithShallow(defaults, options, ['x.y']);
+        expect(merged).to.deep.equal({ a: { b: 4 }, c: { g: { r: { h: 8 } } } });
+        done();
+    });
+
+    it('shallow copies the listed keys in the defaults', function (done) {
+
+        var defaults = {
+            a: {
+                b: 1
+            }
+        };
+
+        var merged = Hoek.applyToDefaultsWithShallow(defaults, {}, ['a']);
+        expect(merged.a).to.equal(defaults.a);
+        done();
+    });
+
+    it('shallow copies the listed keys in the defaults (true)', function (done) {
+
+        var defaults = {
+            a: {
+                b: 1
+            }
+        };
+
+        var merged = Hoek.applyToDefaultsWithShallow(defaults, true, ['a']);
+        expect(merged.a).to.equal(defaults.a);
+        done();
+    });
+
+    it('returns null on false', function (done) {
+
+        var defaults = {
+            a: {
+                b: 1
+            }
+        };
+
+        var merged = Hoek.applyToDefaultsWithShallow(defaults, false, ['a']);
+        expect(merged).to.equal(null);
+        done();
+    });
+
+    it('throws on missing defaults', function (done) {
+
+        expect(function () {
+
+            Hoek.applyToDefaultsWithShallow(null, {}, ['a']);
+        }).to.throw('Invalid defaults value: must be an object');
+        done();
+    });
+
+    it('throws on invalid defaults', function (done) {
+
+        expect(function () {
+
+            Hoek.applyToDefaultsWithShallow('abc', {}, ['a']);
+        }).to.throw('Invalid defaults value: must be an object');
+        done();
+    });
+
+    it('throws on invalid options', function (done) {
+
+        expect(function () {
+
+            Hoek.applyToDefaultsWithShallow({}, 'abc', ['a']);
+        }).to.throw('Invalid options value: must be true, falsy or an object');
+        done();
+    });
+
+    it('throws on missing keys', function (done) {
+
+        expect(function () {
+
+            Hoek.applyToDefaultsWithShallow({}, true);
+        }).to.throw('Invalid keys');
+        done();
+    });
+
+    it('throws on invalid keys', function (done) {
+
+        expect(function () {
+
+            Hoek.applyToDefaultsWithShallow({}, true, 'a');
+        }).to.throw('Invalid keys');
+        done();
+    });
+});
+
+describe('deepEqual()', function () {
+
+    it('compares simple values', function (done) {
+
+        expect(Hoek.deepEqual('x', 'x')).to.be.true();
+        expect(Hoek.deepEqual('x', 'y')).to.be.false();
+        expect(Hoek.deepEqual('x1', 'x')).to.be.false();
+        expect(Hoek.deepEqual(-0, +0)).to.be.false();
+        expect(Hoek.deepEqual(-0, -0)).to.be.true();
+        expect(Hoek.deepEqual(+0, +0)).to.be.true();
+        expect(Hoek.deepEqual(+0, -0)).to.be.false();
+        expect(Hoek.deepEqual(1, 1)).to.be.true();
+        expect(Hoek.deepEqual(0, 0)).to.be.true();
+        expect(Hoek.deepEqual(-1, 1)).to.be.false();
+        expect(Hoek.deepEqual(NaN, 0)).to.be.false();
+        expect(Hoek.deepEqual(NaN, NaN)).to.be.true();
+        done();
+    });
+
+    it('compares different types', function (done) {
+
+        expect(Hoek.deepEqual([], 5)).to.be.false();
+        expect(Hoek.deepEqual(5, [])).to.be.false();
+        expect(Hoek.deepEqual({}, null)).to.be.false();
+        expect(Hoek.deepEqual(null, {})).to.be.false();
+        expect(Hoek.deepEqual('abc', {})).to.be.false();
+        expect(Hoek.deepEqual({}, 'abc')).to.be.false();
+        done();
+    });
+
+    it('compares empty structures', function (done) {
+
+        expect(Hoek.deepEqual([], [])).to.be.true();
+        expect(Hoek.deepEqual({}, {})).to.be.true();
+        expect(Hoek.deepEqual([], {})).to.be.false();
+        done();
+    });
+
+    it('compares empty arguments object', function (done) {
+
+        var compare = function () {
+
+            expect(Hoek.deepEqual([], arguments)).to.be.false();
+        };
+
+        compare();
+        done();
+    });
+
+    it('compares empty arguments objects', function (done) {
+
+        var compare = function () {
+
+            var arg1 = arguments;
+
+            var inner = function () {
+
+                expect(Hoek.deepEqual(arg1, arguments)).to.be.false(); // callee is not the same
+            };
+
+            inner();
+        };
+
+        compare();
+        done();
+    });
+
+    it('compares dates', function (done) {
+
+        expect(Hoek.deepEqual(new Date(2015, 1, 1), new Date(2015, 1, 1))).to.be.true();
+        expect(Hoek.deepEqual(new Date(100), new Date(101))).to.be.false();
+        expect(Hoek.deepEqual(new Date(), {})).to.be.false();
+        done();
+    });
+
+    it('compares regular expressions', function (done) {
+
+        expect(Hoek.deepEqual(/\s/, new RegExp('\\\s'))).to.be.true();
+        expect(Hoek.deepEqual(/\s/g, /\s/g)).to.be.true();
+        expect(Hoek.deepEqual(/a/, {})).to.be.false();
+        expect(Hoek.deepEqual(/\s/g, /\s/i)).to.be.false();
+        expect(Hoek.deepEqual(/a/g, /b/g)).to.be.false();
+        done();
+    });
+
+    it('compares arrays', function (done) {
+
+        expect(Hoek.deepEqual([[1]], [[1]])).to.be.true();
+        expect(Hoek.deepEqual([1, 2, 3], [1, 2, 3])).to.be.true();
+        expect(Hoek.deepEqual([1, 2, 3], [1, 3, 2])).to.be.false();
+        expect(Hoek.deepEqual([1, 2, 3], [1, 2])).to.be.false();
+        expect(Hoek.deepEqual([1], [1])).to.be.true();
+        done();
+    });
+
+    it('compares buffers', function (done) {
+
+        expect(Hoek.deepEqual(new Buffer([1, 2, 3]), new Buffer([1, 2, 3]))).to.be.true();
+        expect(Hoek.deepEqual(new Buffer([1, 2, 3]), new Buffer([1, 3, 2]))).to.be.false();
+        expect(Hoek.deepEqual(new Buffer([1, 2, 3]), new Buffer([1, 2]))).to.be.false();
+        expect(Hoek.deepEqual(new Buffer([1, 2, 3]), {})).to.be.false();
+        expect(Hoek.deepEqual(new Buffer([1, 2, 3]), [1, 2, 3])).to.be.false();
+        done();
+    });
+
+    it('compares objects', function (done) {
+
+        expect(Hoek.deepEqual({ a: 1, b: 2, c: 3 }, { a: 1, b: 2, c: 3 })).to.be.true();
+        expect(Hoek.deepEqual({ foo: 'bar' }, { foo: 'baz' })).to.be.false();
+        expect(Hoek.deepEqual({ foo: { bar: 'foo' } }, { foo: { bar: 'baz' } })).to.be.false();
+        done();
+    });
+
+    it('handles circular dependency', function (done) {
+
+        var a = {};
+        a.x = a;
+
+        var b = Hoek.clone(a);
+        expect(Hoek.deepEqual(a, b)).to.be.true();
+        done();
+    });
+
+    it('compares an object with property getter without executing it', function (done) {
+
+        var obj = {};
+        var value = 1;
+        var execCount = 0;
+
+        Object.defineProperty(obj, 'test', {
+            enumerable: true,
+            configurable: true,
+            get: function () {
+
+                ++execCount;
+                return value;
+            }
+        });
+
+        var copy = Hoek.clone(obj);
+        expect(Hoek.deepEqual(obj, copy)).to.be.true();
+        expect(execCount).to.equal(0);
+        expect(copy.test).to.equal(1);
+        expect(execCount).to.equal(1);
+        done();
+    });
+
+    it('compares objects with property getters', function (done) {
+
+        var obj = {};
+        Object.defineProperty(obj, 'test', {
+            enumerable: true,
+            configurable: true,
+            get: function () {
+
+                return 1;
+            }
+        });
+
+        var ref = {};
+        Object.defineProperty(ref, 'test', {
+            enumerable: true,
+            configurable: true,
+            get: function () {
+
+                return 2;
+            }
+        });
+
+        expect(Hoek.deepEqual(obj, ref)).to.be.false();
+        done();
+    });
+
+    it('compares object prototypes', function (done) {
+
+        var Obj = function () {
+
+            this.a = 5;
+        };
+
+        Obj.prototype.b = function () {
+
+            return this.a;
+        };
+
+        var Ref = function () {
+
+            this.a = 5;
+        };
+
+        Ref.prototype.b = function () {
+
+            return this.a;
+        };
+
+        expect(Hoek.deepEqual(new Obj(), new Ref())).to.be.false();
+        expect(Hoek.deepEqual(new Obj(), new Obj())).to.be.true();
+        expect(Hoek.deepEqual(new Ref(), new Ref())).to.be.true();
+        done();
+    });
+
+    it('compares plain objects', function (done) {
+
+        var a = Object.create(null);
+        var b = Object.create(null);
+
+        a.b = 'c';
+        b.b = 'c';
+
+        expect(Hoek.deepEqual(a, b)).to.be.true();
+        expect(Hoek.deepEqual(a, { b: 'c' })).to.be.false();
+        done();
+    });
+
+    it('compares an object with an empty object', function (done) {
+
+        var a = { a: 1, b: 2 };
+
+        expect(Hoek.deepEqual({}, a)).to.be.false();
+        expect(Hoek.deepEqual(a, {})).to.be.false();
+        done();
+    });
+
+    it('compares an object ignoring the prototype', function (done) {
+
+        var a = Object.create(null);
+        var b = {};
+
+        expect(Hoek.deepEqual(a, b, { prototype: false })).to.be.true();
+        done();
+    });
+
+    it('compares an object ignoring the prototype recursively', function (done) {
+
+        var a = [Object.create(null)];
+        var b = [{}];
+
+        expect(Hoek.deepEqual(a, b, { prototype: false })).to.be.true();
+        done();
+    });
+});
+
+describe('unique()', function () {
+
+    it('ensures uniqueness within array of objects based on subkey', function (done) {
+
+        var a = Hoek.unique(dupsArray, 'x');
+        expect(a).to.deep.equal(reducedDupsArray);
+        done();
+    });
+
+    it('removes duplicated without key', function (done) {
+
+        expect(Hoek.unique([1, 2, 3, 4, 2, 1, 5])).to.deep.equal([1, 2, 3, 4, 5]);
+        done();
+    });
+});
+
+describe('mapToObject()', function () {
+
+    it('returns null on null array', function (done) {
+
+        var a = Hoek.mapToObject(null);
+        expect(a).to.equal(null);
+        done();
+    });
+
+    it('converts basic array to existential object', function (done) {
+
+        var keys = [1, 2, 3, 4];
+        var a = Hoek.mapToObject(keys);
+        for (var i in keys) {
+            expect(a[keys[i]]).to.equal(true);
+        }
+        done();
+    });
+
+    it('converts array of objects to existential object', function (done) {
+
+        var keys = [{ x: 1 }, { x: 2 }, { x: 3 }, { y: 4 }];
+        var subkey = 'x';
+        var a = Hoek.mapToObject(keys, subkey);
+        expect(a).to.deep.equal({ 1: true, 2: true, 3: true });
+        done();
+    });
+});
+
+describe('intersect()', function () {
+
+    it('returns the common objects of two arrays', function (done) {
+
+        var array1 = [1, 2, 3, 4, 4, 5, 5];
+        var array2 = [5, 4, 5, 6, 7];
+        var common = Hoek.intersect(array1, array2);
+        expect(common.length).to.equal(2);
+        done();
+    });
+
+    it('returns just the first common object of two arrays', function (done) {
+
+        var array1 = [1, 2, 3, 4, 4, 5, 5];
+        var array2 = [5, 4, 5, 6, 7];
+        var common = Hoek.intersect(array1, array2, true);
+        expect(common).to.equal(5);
+        done();
+    });
+
+    it('returns null when no common and returning just the first common object of two arrays', function (done) {
+
+        var array1 = [1, 2, 3, 4, 4, 5, 5];
+        var array2 = [6, 7];
+        var common = Hoek.intersect(array1, array2, true);
+        expect(common).to.equal(null);
+        done();
+    });
+
+    it('returns an empty array if either input is null', function (done) {
+
+        expect(Hoek.intersect([1], null).length).to.equal(0);
+        expect(Hoek.intersect(null, [1]).length).to.equal(0);
+        done();
+    });
+
+    it('returns the common objects of object and array', function (done) {
+
+        var array1 = [1, 2, 3, 4, 4, 5, 5];
+        var array2 = [5, 4, 5, 6, 7];
+        var common = Hoek.intersect(Hoek.mapToObject(array1), array2);
+        expect(common.length).to.equal(2);
+        done();
+    });
+});
+
+describe('contain()', function () {
+
+    it('tests strings', function (done) {
+
+        expect(Hoek.contain('abc', 'ab')).to.be.true();
+        expect(Hoek.contain('abc', 'abc', { only: true })).to.be.true();
+        expect(Hoek.contain('aaa', 'a', { only: true })).to.be.true();
+        expect(Hoek.contain('abc', 'b', { once: true })).to.be.true();
+        expect(Hoek.contain('abc', ['a', 'c'])).to.be.true();
+        expect(Hoek.contain('abc', ['a', 'd'], { part: true })).to.be.true();
+
+        expect(Hoek.contain('abc', 'ac')).to.be.false();
+        expect(Hoek.contain('abcd', 'abc', { only: true })).to.be.false();
+        expect(Hoek.contain('aab', 'a', { only: true })).to.be.false();
+        expect(Hoek.contain('abb', 'b', { once: true })).to.be.false();
+        expect(Hoek.contain('abc', ['a', 'd'])).to.be.false();
+        expect(Hoek.contain('abc', ['ab', 'bc'])).to.be.false();                      // Overlapping values not supported
+        done();
+    });
+
+    it('tests arrays', function (done) {
+
+        expect(Hoek.contain([1, 2, 3], 1)).to.be.true();
+        expect(Hoek.contain([{ a: 1 }], { a: 1 }, { deep: true })).to.be.true();
+        expect(Hoek.contain([1, 2, 3], [1, 2])).to.be.true();
+        expect(Hoek.contain([{ a: 1 }], [{ a: 1 }], { deep: true })).to.be.true();
+        expect(Hoek.contain([1, 1, 2], [1, 2], { only: true })).to.be.true();
+        expect(Hoek.contain([1, 2], [1, 2], { once: true })).to.be.true();
+        expect(Hoek.contain([1, 2, 3], [1, 4], { part: true })).to.be.true();
+        expect(Hoek.contain([[1], [2]], [[1]], { deep: true })).to.be.true();
+
+        expect(Hoek.contain([1, 2, 3], 4)).to.be.false();
+        expect(Hoek.contain([{ a: 1 }], { a: 2 }, { deep: true })).to.be.false();
+        expect(Hoek.contain([{ a: 1 }], { a: 1 })).to.be.false();
+        expect(Hoek.contain([1, 2, 3], [4, 5])).to.be.false();
+        expect(Hoek.contain([[3], [2]], [[1]])).to.be.false();
+        expect(Hoek.contain([[1], [2]], [[1]])).to.be.false();
+        expect(Hoek.contain([{ a: 1 }], [{ a: 2 }], { deep: true })).to.be.false();
+        expect(Hoek.contain([1, 3, 2], [1, 2], { only: true })).to.be.false();
+        expect(Hoek.contain([1, 2, 2], [1, 2], { once: true })).to.be.false();
+        expect(Hoek.contain([0, 2, 3], [1, 4], { part: true })).to.be.false();
+        done();
+    });
+
+    it('tests objects', function (done) {
+
+        expect(Hoek.contain({ a: 1, b: 2, c: 3 }, 'a')).to.be.true();
+        expect(Hoek.contain({ a: 1, b: 2, c: 3 }, ['a', 'c'])).to.be.true();
+        expect(Hoek.contain({ a: 1, b: 2, c: 3 }, ['a', 'b', 'c'], { only: true })).to.be.true();
+        expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1 })).to.be.true();
+        expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1, c: 3 })).to.be.true();
+        expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1, d: 4 }, { part: true })).to.be.true();
+        expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1, b: 2, c: 3 }, { only: true })).to.be.true();
+        expect(Hoek.contain({ a: [1], b: [2], c: [3] }, { a: [1], c: [3] }, { deep: true })).to.be.true();
+        expect(Hoek.contain({ a: [{ b: 1 }, { c: 2 }, { d: 3, e: 4 }] }, { a: [{ b: 1 }, { d: 3 }] }, { deep: true })).to.be.true();
+        expect(Hoek.contain({ a: [{ b: 1 }, { c: 2 }, { d: 3, e: 4 }] }, { a: [{ b: 1 }, { d: 3 }] }, { deep: true, part: true })).to.be.true();
+        expect(Hoek.contain({ a: [{ b: 1 }, { c: 2 }, { d: 3, e: 4 }] }, { a: [{ b: 1 }, { d: 3 }] }, { deep: true, part: false })).to.be.false();
+        expect(Hoek.contain({ a: [{ b: 1 }, { c: 2 }, { d: 3, e: 4 }] }, { a: [{ b: 1 }, { d: 3 }] }, { deep: true, only: true })).to.be.false();
+        expect(Hoek.contain({ a: [{ b: 1 }, { c: 2 }, { d: 3, e: 4 }] }, { a: [{ b: 1 }, { d: 3 }] }, { deep: true, only: false })).to.be.true();
+
+        expect(Hoek.contain({ a: 1, b: 2, c: 3 }, 'd')).to.be.false();
+        expect(Hoek.contain({ a: 1, b: 2, c: 3 }, ['a', 'd'])).to.be.false();
+        expect(Hoek.contain({ a: 1, b: 2, c: 3, d: 4 }, ['a', 'b', 'c'], { only: true })).to.be.false();
+        expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 2 })).to.be.false();
+        expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 2, b: 2 }, { part: true })).to.be.false();             // part does not ignore bad value
+        expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1, d: 3 })).to.be.false();
+        expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1, d: 4 })).to.be.false();
+        expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1, b: 2 }, { only: true })).to.be.false();
+        expect(Hoek.contain({ a: [1], b: [2], c: [3] }, { a: [1], c: [3] })).to.be.false();
+        expect(Hoek.contain({ a: { b: { c: 1, d: 2 } } }, { a: { b: { c: 1 } } })).to.be.false();
+        expect(Hoek.contain({ a: { b: { c: 1, d: 2 } } }, { a: { b: { c: 1 } } }, { deep: true })).to.be.true();
+        expect(Hoek.contain({ a: { b: { c: 1, d: 2 } } }, { a: { b: { c: 1 } } }, { deep: true, only: true })).to.be.false();
+        expect(Hoek.contain({ a: { b: { c: 1, d: 2 } } }, { a: { b: { c: 1 } } }, { deep: true, only: false })).to.be.true();
+        expect(Hoek.contain({ a: { b: { c: 1, d: 2 } } }, { a: { b: { c: 1 } } }, { deep: true, part: true })).to.be.true();
+        expect(Hoek.contain({ a: { b: { c: 1, d: 2 } } }, { a: { b: { c: 1 } } }, { deep: true, part: false })).to.be.false();
+
+        // Getter check
+        var Foo = function (bar) {
+
+            this.bar = bar;
+        };
+
+        Object.defineProperty(Foo.prototype, 'baz', {
+            enumerable: true,
+            get: function () {
+
+                return this.bar;
+            }
+        });
+
+        expect(Hoek.contain({ a: new Foo('b') }, { a: new Foo('b') }, { deep: true })).to.be.true();
+        expect(Hoek.contain({ a: new Foo('b') }, { a: new Foo('b') }, { deep: true, part: true })).to.be.true();
+        expect(Hoek.contain({ a: new Foo('b') }, { a: { baz: 'b' } }, { deep: true })).to.be.true();
+        expect(Hoek.contain({ a: new Foo('b') }, { a: { baz: 'b' } }, { deep: true, only: true })).to.be.false();
+        expect(Hoek.contain({ a: new Foo('b') }, { a: { baz: 'b' } }, { deep: true, part: false })).to.be.false();
+        expect(Hoek.contain({ a: new Foo('b') }, { a: { baz: 'b' } }, { deep: true, part: true })).to.be.true();
+
+        done();
+    });
+});
+
+describe('flatten()', function () {
+
+    it('returns a flat array', function (done) {
+
+        var result = Hoek.flatten([1, 2, [3, 4, [5, 6], [7], 8], [9], [10, [11, 12]], 13]);
+        expect(result.length).to.equal(13);
+        expect(result).to.deep.equal([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]);
+        done();
+    });
+});
+
+describe('reach()', function () {
+
+    var obj = {
+        a: {
+            b: {
+                c: {
+                    d: 1,
+                    e: 2
+                },
+                f: 'hello'
+            },
+            g: {
+                h: 3
+            }
+        },
+        i: function () { },
+        j: null,
+        k: [4, 8, 9, 1]
+    };
+
+    obj.i.x = 5;
+
+    it('returns object itself', function (done) {
+
+        expect(Hoek.reach(obj, null)).to.equal(obj);
+        expect(Hoek.reach(obj, false)).to.equal(obj);
+        expect(Hoek.reach(obj)).to.equal(obj);
+        done();
+    });
+
+    it('returns first value of array', function (done) {
+
+        expect(Hoek.reach(obj, 'k.0')).to.equal(4);
+        done();
+    });
+
+    it('returns last value of array using negative index', function (done) {
+
+        expect(Hoek.reach(obj, 'k.-2')).to.equal(9);
+        done();
+    });
+
+    it('returns a valid member', function (done) {
+
+        expect(Hoek.reach(obj, 'a.b.c.d')).to.equal(1);
+        done();
+    });
+
+    it('returns a valid member with separator override', function (done) {
+
+        expect(Hoek.reach(obj, 'a/b/c/d', '/')).to.equal(1);
+        done();
+    });
+
+    it('returns undefined on null object', function (done) {
+
+        expect(Hoek.reach(null, 'a.b.c.d')).to.equal(undefined);
+        done();
+    });
+
+    it('returns undefined on missing object member', function (done) {
+
+        expect(Hoek.reach(obj, 'a.b.c.d.x')).to.equal(undefined);
+        done();
+    });
+
+    it('returns undefined on missing function member', function (done) {
+
+        expect(Hoek.reach(obj, 'i.y', { functions: true })).to.equal(undefined);
+        done();
+    });
+
+    it('throws on missing member in strict mode', function (done) {
+
+        expect(function () {
+
+            Hoek.reach(obj, 'a.b.c.o.x', { strict: true });
+        }).to.throw('Missing segment o in reach path  a.b.c.o.x');
+
+        done();
+    });
+
+    it('returns undefined on invalid member', function (done) {
+
+        expect(Hoek.reach(obj, 'a.b.c.d-.x')).to.equal(undefined);
+        done();
+    });
+
+    it('returns function member', function (done) {
+
+        expect(typeof Hoek.reach(obj, 'i')).to.equal('function');
+        done();
+    });
+
+    it('returns function property', function (done) {
+
+        expect(Hoek.reach(obj, 'i.x')).to.equal(5);
+        done();
+    });
+
+    it('returns null', function (done) {
+
+        expect(Hoek.reach(obj, 'j')).to.equal(null);
+        done();
+    });
+
+    it('throws on function property when functions not allowed', function (done) {
+
+        expect(function () {
+
+            Hoek.reach(obj, 'i.x', { functions: false });
+        }).to.throw('Invalid segment x in reach path  i.x');
+
+        done();
+    });
+
+    it('will return a default value if property is not found', function (done) {
+
+        expect(Hoek.reach(obj, 'a.b.q', { default: 'defaultValue' })).to.equal('defaultValue');
+        done();
+    });
+
+    it('will return a default value if path is not found', function (done) {
+
+        expect(Hoek.reach(obj, 'q', { default: 'defaultValue' })).to.equal('defaultValue');
+        done();
+    });
+
+    it('allows a falsey value to be used as the default value', function (done) {
+
+        expect(Hoek.reach(obj, 'q', { default: '' })).to.equal('');
+        done();
+    });
+});
+
+describe('reachTemplate()', function () {
+
+    it('applies object to template', function (done) {
+
+        var obj = {
+            a: {
+                b: {
+                    c: {
+                        d: 1
+                    }
+                }
+            },
+            j: null,
+            k: [4, 8, 9, 1]
+        };
+
+        var template = '{k.0}:{k.-2}:{a.b.c.d}:{x.y}:{j}';
+
+        expect(Hoek.reachTemplate(obj, template)).to.equal('4:9:1::');
+        done();
+    });
+
+    it('applies object to template (options)', function (done) {
+
+        var obj = {
+            a: {
+                b: {
+                    c: {
+                        d: 1
+                    }
+                }
+            },
+            j: null,
+            k: [4, 8, 9, 1]
+        };
+
+        var template = '{k/0}:{k/-2}:{a/b/c/d}:{x/y}:{j}';
+
+        expect(Hoek.reachTemplate(obj, template, '/')).to.equal('4:9:1::');
+        done();
+    });
+});
+
+describe('callStack()', function () {
+
+    it('returns the full call stack', function (done) {
+
+        var stack = Hoek.callStack();
+        expect(stack[0][0]).to.contain('index.js');
+        expect(stack[0][2]).to.equal(26);
+        done();
+    });
+});
+
+describe('displayStack ()', function () {
+
+    it('returns the full call stack for display', function (done) {
+
+        var stack = Hoek.displayStack();
+        expect(stack[0]).to.contain(Path.normalize('/test/index.js') + ':');
+        done();
+    });
+
+    it('includes constructor functions correctly', function (done) {
+
+        var Something = function (next) {
+
+            next();
+        };
+
+        var something = new Something(function () {
+
+            var stack = Hoek.displayStack();
+            expect(stack[1]).to.contain('new Something');
+            done();
+        });
+    });
+});
+
+describe('abort()', function () {
+
+    it('exits process when not in test mode', function (done) {
+
+        var env = process.env.NODE_ENV;
+        var write = process.stdout.write;
+        var exit = process.exit;
+
+        process.env.NODE_ENV = 'nottatest';
+        process.stdout.write = function () { };
+        process.exit = function (state) {
+
+            process.exit = exit;
+            process.env.NODE_ENV = env;
+            process.stdout.write = write;
+
+            expect(state).to.equal(1);
+            done();
+        };
+
+        Hoek.abort('Boom');
+    });
+
+    it('throws when not in test mode and abortThrow is true', function (done) {
+
+        var env = process.env.NODE_ENV;
+        process.env.NODE_ENV = 'nottatest';
+        Hoek.abortThrow = true;
+
+        var fn = function () {
+
+            Hoek.abort('my error message');
+        };
+
+        expect(fn).to.throw('my error message');
+        Hoek.abortThrow = false;
+        process.env.NODE_ENV = env;
+
+        done();
+    });
+
+    it('respects hideStack argument', function (done) {
+
+        var env = process.env.NODE_ENV;
+        var write = process.stdout.write;
+        var exit = process.exit;
+        var output = '';
+
+        process.exit = function () { };
+        process.env.NODE_ENV = '';
+        process.stdout.write = function (message) {
+
+            output = message;
+        };
+
+        Hoek.abort('my error message', true);
+
+        process.env.NODE_ENV = env;
+        process.stdout.write = write;
+        process.exit = exit;
+
+        expect(output).to.equal('ABORT: my error message\n\t\n');
+
+        done();
+    });
+
+    it('throws in test mode', function (done) {
+
+        var env = process.env.NODE_ENV;
+        process.env.NODE_ENV = 'test';
+
+        expect(function () {
+
+            Hoek.abort('my error message', true);
+        }).to.throw('my error message');
+
+        process.env.NODE_ENV = env;
+        done();
+    });
+
+    it('throws in test mode with default message', function (done) {
+
+        var env = process.env.NODE_ENV;
+        process.env.NODE_ENV = 'test';
+
+        expect(function () {
+
+            Hoek.abort('', true);
+        }).to.throw('Unknown error');
+
+        process.env.NODE_ENV = env;
+        done();
+    });
+
+    it('defaults to showing stack', function (done) {
+
+        var env = process.env.NODE_ENV;
+        var write = process.stdout.write;
+        var exit = process.exit;
+        var output = '';
+
+        process.exit = function () { };
+        process.env.NODE_ENV = '';
+        process.stdout.write = function (message) {
+
+            output = message;
+        };
+
+        Hoek.abort('my error message');
+
+        process.env.NODE_ENV = env;
+        process.stdout.write = write;
+        process.exit = exit;
+
+        expect(output).to.contain('index.js');
+
+        done();
+    });
+});
+
+describe('assert()', function () {
+
+    it('throws an Error when using assert in a test', function (done) {
+
+        var fn = function () {
+
+            Hoek.assert(false, 'my error message');
+        };
+
+        expect(fn).to.throw('my error message');
+        done();
+    });
+
+    it('throws an Error when using assert in a test with no message', function (done) {
+
+        var fn = function () {
+
+            Hoek.assert(false);
+        };
+
+        expect(fn).to.throw('Unknown error');
+        done();
+    });
+
+    it('throws an Error when using assert in a test with multipart message', function (done) {
+
+        var fn = function () {
+
+            Hoek.assert(false, 'This', 'is', 'my message');
+        };
+
+        expect(fn).to.throw('This is my message');
+        done();
+    });
+
+    it('throws an Error when using assert in a test with multipart message (empty)', function (done) {
+
+        var fn = function () {
+
+            Hoek.assert(false, 'This', 'is', '', 'my message');
+        };
+
+        expect(fn).to.throw('This is my message');
+        done();
+    });
+
+    it('throws an Error when using assert in a test with object message', function (done) {
+
+        var fn = function () {
+
+            Hoek.assert(false, 'This', 'is', { spinal: 'tap' });
+        };
+
+        expect(fn).to.throw('This is {"spinal":"tap"}');
+        done();
+    });
+
+    it('throws an Error when using assert in a test with multipart string and error messages', function (done) {
+
+        var fn = function () {
+
+            Hoek.assert(false, 'This', 'is', new Error('spinal'), new Error('tap'));
+        };
+
+        expect(fn).to.throw('This is spinal tap');
+        done();
+    });
+
+    it('throws an Error when using assert in a test with error object message', function (done) {
+
+        var fn = function () {
+
+            Hoek.assert(false, new Error('This is spinal tap'));
+        };
+
+        expect(fn).to.throw('This is spinal tap');
+        done();
+    });
+
+    it('throws the same Error that is passed to it if there is only one error passed', function (done) {
+
+        var error = new Error('ruh roh');
+        var error2 = new Error('ruh roh');
+
+        var fn = function () {
+
+            Hoek.assert(false, error);
+        };
+
+        try {
+            fn();
+        } catch (err) {
+            expect(error).to.equal(error);  // should be the same reference
+            expect(error).to.not.equal(error2); // error with the same message should not match
+        }
+
+        done();
+    });
+});
+
+describe('Timer', function () {
+
+    it('returns time elapsed', function (done) {
+
+        var timer = new Hoek.Timer();
+        setTimeout(function () {
+
+            expect(timer.elapsed()).to.be.above(9);
+            done();
+        }, 12);
+    });
+});
+
+describe('Bench', function () {
+
+    it('returns time elapsed', function (done) {
+
+        var timer = new Hoek.Bench();
+        setTimeout(function () {
+
+            expect(timer.elapsed()).to.be.above(9);
+            done();
+        }, 12);
+    });
+});
+
+describe('escapeRegex()', function () {
+
+    it('escapes all special regular expression characters', function (done) {
+
+        var a = Hoek.escapeRegex('4^f$s.4*5+-_?%=#!:@|~\\/`"(>)[<]d{}s,');
+        expect(a).to.equal('4\\^f\\$s\\.4\\*5\\+\\-_\\?%\\=#\\!\\:@\\|~\\\\\\/`"\\(>\\)\\[<\\]d\\{\\}s\\,');
+        done();
+    });
+});
+
+describe('Base64Url', function () {
+
+    var base64str = 'AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0-P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn-AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq-wsbKztLW2t7i5uru8vb6_wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t_g4eLj5OXm5-jp6uvs7e7v8PHy8_T19vf4-fr7_P3-_w';
+    var str = unescape('%00%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%20%21%22%23%24%25%26%27%28%29*+%2C-./0123456789%3A%3B%3C%3D%3E%3F@ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D%7E%7F%80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF');
+
+    describe('base64urlEncode()', function () {
+
+        it('should base64 URL-safe a string', function (done) {
+
+            expect(Hoek.base64urlEncode(str)).to.equal(base64str);
+            done();
+        });
+
+        it('encodes a buffer', function (done) {
+
+            expect(Hoek.base64urlEncode(new Buffer(str, 'binary'))).to.equal(base64str);
+            done();
+        });
+
+        it('should base64 URL-safe a hex string', function (done) {
+
+            var buffer = new Buffer(str, 'binary');
+            expect(Hoek.base64urlEncode(buffer.toString('hex'), 'hex')).to.equal(base64str);
+            done();
+        });
+
+        it('works on larger input strings', function (done) {
+
+            var input = Fs.readFileSync(Path.join(__dirname, 'index.js')).toString();
+            var encoded = Hoek.base64urlEncode(input);
+
+            expect(encoded).to.not.contain('+');
+            expect(encoded).to.not.contain('/');
+
+            var decoded = Hoek.base64urlDecode(encoded);
+
+            expect(decoded).to.equal(input);
+            done();
+        });
+    });
+
+    describe('base64urlDecode()', function () {
+
+        it('should un-base64 URL-safe a string', function (done) {
+
+            expect(Hoek.base64urlDecode(base64str)).to.equal(str);
+            done();
+        });
+
+        it('should un-base64 URL-safe a string into hex', function (done) {
+
+            expect(Hoek.base64urlDecode(base64str, 'hex')).to.equal(new Buffer(str, 'binary').toString('hex'));
+            done();
+        });
+
+        it('should un-base64 URL-safe a string and return a buffer', function (done) {
+
+            var buf = Hoek.base64urlDecode(base64str, 'buffer');
+            expect(buf instanceof Buffer).to.equal(true);
+            expect(buf.toString('binary')).to.equal(str);
+            done();
+        });
+
+        it('returns error on undefined input', function (done) {
+
+            expect(Hoek.base64urlDecode().message).to.exist();
+            done();
+        });
+
+        it('returns error on invalid input', function (done) {
+
+            expect(Hoek.base64urlDecode('*').message).to.exist();
+            done();
+        });
+    });
+});
+
+describe('escapeHeaderAttribute()', function () {
+
+    it('should not alter ascii values', function (done) {
+
+        var a = Hoek.escapeHeaderAttribute('My Value');
+        expect(a).to.equal('My Value');
+        done();
+    });
+
+    it('escapes all special HTTP header attribute characters', function (done) {
+
+        var a = Hoek.escapeHeaderAttribute('I said go!!!#"' + String.fromCharCode(92));
+        expect(a).to.equal('I said go!!!#\\"\\\\');
+        done();
+    });
+
+    it('throws on large unicode characters', function (done) {
+
+        var fn = function () {
+
+            Hoek.escapeHeaderAttribute('this is a test' + String.fromCharCode(500) + String.fromCharCode(300));
+        };
+
+        expect(fn).to.throw(Error);
+        done();
+    });
+
+    it('throws on CRLF to prevent response splitting', function (done) {
+
+        var fn = function () {
+
+            Hoek.escapeHeaderAttribute('this is a test\r\n');
+        };
+
+        expect(fn).to.throw(Error);
+        done();
+    });
+});
+
+describe('escapeHtml()', function () {
+
+    it('escapes all special HTML characters', function (done) {
+
+        var a = Hoek.escapeHtml('&<>"\'`');
+        expect(a).to.equal('&amp;&lt;&gt;&quot;&#x27;&#x60;');
+        done();
+    });
+
+    it('returns empty string on falsy input', function (done) {
+
+        var a = Hoek.escapeHtml('');
+        expect(a).to.equal('');
+        done();
+    });
+
+    it('returns unchanged string on no reserved input', function (done) {
+
+        var a = Hoek.escapeHtml('abc');
+        expect(a).to.equal('abc');
+        done();
+    });
+});
+
+describe('nextTick()', function () {
+
+    it('calls the provided callback on nextTick', function (done) {
+
+        var a = 0;
+
+        var inc = function (step, next) {
+
+            a += step;
+            next();
+        };
+
+        var ticked = Hoek.nextTick(inc);
+
+        ticked(5, function () {
+
+            expect(a).to.equal(6);
+            done();
+        });
+
+        expect(a).to.equal(0);
+        inc(1, function () {
+
+            expect(a).to.equal(1);
+        });
+    });
+});
+
+describe('once()', function () {
+
+    it('allows function to only execute once', function (done) {
+
+        var gen = 0;
+        var add = function (x) {
+
+            gen += x;
+        };
+
+        add(5);
+        expect(gen).to.equal(5);
+        add = Hoek.once(add);
+        add(5);
+        expect(gen).to.equal(10);
+        add(5);
+        expect(gen).to.equal(10);
+        done();
+    });
+
+    it('double once wraps one time', function (done) {
+
+        var method = function () { };
+        method = Hoek.once(method);
+        method.x = 1;
+        method = Hoek.once(method);
+        expect(method.x).to.equal(1);
+        done();
+    });
+});
+
+describe('isAbsoltePath()', function () {
+
+    it('identifies if path is absolute on Unix without node support', { parallel: false }, function (done) {
+
+        var orig = Path.isAbsolute;
+        Path.isAbsolute = undefined;
+
+        expect(Hoek.isAbsolutePath('')).to.equal(false);
+        expect(Hoek.isAbsolutePath('a')).to.equal(false);
+        expect(Hoek.isAbsolutePath('./a')).to.equal(false);
+        expect(Hoek.isAbsolutePath('/a')).to.equal(true);
+        expect(Hoek.isAbsolutePath('/')).to.equal(true);
+
+        Path.isAbsolute = orig;
+
+        done();
+    });
+
+    it('identifies if path is absolute with fake node support', { parallel: false }, function (done) {
+
+        var orig = Path.isAbsolute;
+        Path.isAbsolute = function (path) {
+
+            return path[0] === '/';
+        };
+
+        expect(Hoek.isAbsolutePath('', 'linux')).to.equal(false);
+        expect(Hoek.isAbsolutePath('a', 'linux')).to.equal(false);
+        expect(Hoek.isAbsolutePath('./a', 'linux')).to.equal(false);
+        expect(Hoek.isAbsolutePath('/a', 'linux')).to.equal(true);
+        expect(Hoek.isAbsolutePath('/', 'linux')).to.equal(true);
+
+        Path.isAbsolute = orig;
+
+        done();
+    });
+
+    it('identifies if path is absolute on Windows without node support', { parallel: false }, function (done) {
+
+        var orig = Path.isAbsolute;
+        Path.isAbsolute = undefined;
+
+        expect(Hoek.isAbsolutePath('//server/file', 'win32')).to.equal(true);
+        expect(Hoek.isAbsolutePath('//server/file', 'win32')).to.equal(true);
+        expect(Hoek.isAbsolutePath('\\\\server\\file', 'win32')).to.equal(true);
+        expect(Hoek.isAbsolutePath('C:/Users/', 'win32')).to.equal(true);
+        expect(Hoek.isAbsolutePath('C:\\Users\\', 'win32')).to.equal(true);
+        expect(Hoek.isAbsolutePath('C:cwd/another', 'win32')).to.equal(false);
+        expect(Hoek.isAbsolutePath('C:cwd\\another', 'win32')).to.equal(false);
+        expect(Hoek.isAbsolutePath('directory/directory', 'win32')).to.equal(false);
+        expect(Hoek.isAbsolutePath('directory\\directory', 'win32')).to.equal(false);
+
+        Path.isAbsolute = orig;
+
+        done();
+    });
+});
+
+describe('isInteger()', function () {
+
+    it('validates integers', function (done) {
+
+        expect(Hoek.isInteger(0)).to.equal(true);
+        expect(Hoek.isInteger(1)).to.equal(true);
+        expect(Hoek.isInteger(1394035612500)).to.equal(true);
+        expect(Hoek.isInteger('0')).to.equal(false);
+        expect(Hoek.isInteger(1.0)).to.equal(true);
+        expect(Hoek.isInteger(1.1)).to.equal(false);
+        done();
+    });
+});
+
+describe('ignore()', function () {
+
+    it('exists', function (done) {
+
+        expect(Hoek.ignore).to.exist();
+        expect(typeof Hoek.ignore).to.equal('function');
+        done();
+    });
+});
+
+describe('inherits()', function () {
+
+    it('exists', function (done) {
+
+        expect(Hoek.inherits).to.exist();
+        expect(typeof Hoek.inherits).to.equal('function');
+        done();
+    });
+});
+
+describe('format()', function () {
+
+    it('exists', function (done) {
+
+        expect(Hoek.format).to.exist();
+        expect(typeof Hoek.format).to.equal('function');
+        done();
+    });
+
+    it('is a reference to Util.format', function (done) {
+
+        expect(Hoek.format('hello %s', 'world')).to.equal('hello world');
+        done();
+    });
+});
+
+describe('transform()', function () {
+
+    var source = {
+        address: {
+            one: '123 main street',
+            two: 'PO Box 1234'
+        },
+        zip: {
+            code: 3321232,
+            province: null
+        },
+        title: 'Warehouse',
+        state: 'CA'
+    };
+
+    var sourcesArray = [{
+        address: {
+            one: '123 main street',
+            two: 'PO Box 1234'
+        },
+        zip: {
+            code: 3321232,
+            province: null
+        },
+        title: 'Warehouse',
+        state: 'CA'
+    }, {
+        address: {
+            one: '456 market street',
+            two: 'PO Box 5678'
+        },
+        zip: {
+            code: 9876,
+            province: null
+        },
+        title: 'Garage',
+        state: 'NY'
+    }];
+
+    it('transforms an object based on the input object', function (done) {
+
+        var result = Hoek.transform(source, {
+            'person.address.lineOne': 'address.one',
+            'person.address.lineTwo': 'address.two',
+            'title': 'title',
+            'person.address.region': 'state',
+            'person.address.zip': 'zip.code',
+            'person.address.location': 'zip.province'
+        });
+
+        expect(result).to.deep.equal({
+            person: {
+                address: {
+                    lineOne: '123 main street',
+                    lineTwo: 'PO Box 1234',
+                    region: 'CA',
+                    zip: 3321232,
+                    location: null
+                }
+            },
+            title: 'Warehouse'
+        });
+
+        done();
+    });
+
+    it('transforms an array of objects based on the input object', function (done) {
+
+        var result = Hoek.transform(sourcesArray, {
+            'person.address.lineOne': 'address.one',
+            'person.address.lineTwo': 'address.two',
+            'title': 'title',
+            'person.address.region': 'state',
+            'person.address.zip': 'zip.code',
+            'person.address.location': 'zip.province'
+        });
+
+        expect(result).to.deep.equal([
+            {
+                person: {
+                    address: {
+                        lineOne: '123 main street',
+                        lineTwo: 'PO Box 1234',
+                        region: 'CA',
+                        zip: 3321232,
+                        location: null
+                    }
+                },
+                title: 'Warehouse'
+            },
+            {
+                person: {
+                    address: {
+                        lineOne: '456 market street',
+                        lineTwo: 'PO Box 5678',
+                        region: 'NY',
+                        zip: 9876,
+                        location: null
+                    }
+                },
+                title: 'Garage'
+            }
+        ]);
+
+        done();
+    });
+
+    it('uses the reach options passed into it', function (done) {
+
+        var schema = {
+            'person.address.lineOne': 'address-one',
+            'person.address.lineTwo': 'address-two',
+            'title': 'title',
+            'person.address.region': 'state',
+            'person.prefix': 'person-title',
+            'person.zip': 'zip-code'
+        };
+        var options = {
+            separator: '-',
+            default: 'unknown'
+        };
+        var result = Hoek.transform(source, schema, options);
+
+        expect(result).to.deep.equal({
+            person: {
+                address: {
+                    lineOne: '123 main street',
+                    lineTwo: 'PO Box 1234',
+                    region: 'CA'
+                },
+                prefix: 'unknown',
+                zip: 3321232
+            },
+            title: 'Warehouse'
+        });
+
+        done();
+    });
+
+    it('works to create shallow objects', function (done) {
+
+        var result = Hoek.transform(source, {
+            lineOne: 'address.one',
+            lineTwo: 'address.two',
+            title: 'title',
+            region: 'state',
+            province: 'zip.province'
+        });
+
+        expect(result).to.deep.equal({
+            lineOne: '123 main street',
+            lineTwo: 'PO Box 1234',
+            title: 'Warehouse',
+            region: 'CA',
+            province: null
+        });
+
+        done();
+    });
+
+    it('only allows strings in the map', function (done) {
+
+        expect(function () {
+
+            var result = Hoek.transform(source, {
+                lineOne: {}
+            });
+        }).to.throw('All mappings must be "." delineated strings');
+
+        done();
+    });
+
+    it('throws an error on invalid arguments', function (done) {
+
+        expect(function () {
+
+            var result = Hoek.transform(NaN, {});
+        }).to.throw('Invalid source object: must be null, undefined, an object, or an array');
+
+        done();
+    });
+
+    it('is safe to pass null', function (done) {
+
+        var result = Hoek.transform(null, {});
+        expect(result).to.deep.equal({});
+
+        done();
+    });
+
+    it('is safe to pass undefined', function (done) {
+
+        var result = Hoek.transform(undefined, {});
+        expect(result).to.deep.equal({});
+
+        done();
+    });
+});
+
+describe('uniqueFilename()', function () {
+
+    it('generates a random file path', function (done) {
+
+        var result = Hoek.uniqueFilename('./test/modules');
+
+        expect(result).to.exist();
+        expect(result).to.be.a.string();
+        expect(result).to.contain('test/modules');
+        done();
+    });
+
+    it('is random enough to use in fast loops', function (done) {
+
+        var results = [];
+
+        for (var i = 0; i < 10; ++i) {
+            results[i] = Hoek.uniqueFilename('./test/modules');
+        }
+
+        var filter = results.filter(function (item, index, array) {
+
+            return array.indexOf(item) === index;
+        });
+
+        expect(filter.length).to.equal(10);
+        expect(results.length).to.equal(10);
+        done();
+
+    });
+
+    it('combines the random elements with a supplied character', function (done) {
+
+        var result = Hoek.uniqueFilename('./test', 'txt');
+
+        expect(result).to.contain('test/');
+        expect(result).to.contain('.txt');
+
+        done();
+    });
+
+    it('accepts extensions with a "." in it', function (done) {
+
+        var result = Hoek.uniqueFilename('./test', '.mp3');
+
+        expect(result).to.contain('test/');
+        expect(result).to.contain('.mp3');
+
+        done();
+    });
+});
+
+describe('stringify()', function (done) {
+
+    it('converts object to string', function (done) {
+
+        var obj = { a: 1 };
+        expect(Hoek.stringify(obj)).to.equal('{"a":1}');
+        done();
+    });
+
+    it('returns error in result string', function (done) {
+
+        var obj = { a: 1 };
+        obj.b = obj;
+        expect(Hoek.stringify(obj)).to.equal('[Cannot display object: Converting circular structure to JSON]');
+        done();
+    });
+});
+
+describe('shallow()', function (done) {
+
+    it('shallow copies an object', function (done) {
+
+        var obj = {
+            a: 5,
+            b: {
+                c: 6
+            }
+        };
+
+        var shallow = Hoek.shallow(obj);
+        expect(shallow).to.not.equal(obj);
+        expect(shallow).to.deep.equal(obj);
+        expect(shallow.b).to.equal(obj.b);
+        done();
+    });
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/test/modules/ignore.txt b/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/test/modules/ignore.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/test/modules/test1.js b/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/test/modules/test1.js
new file mode 100644
index 0000000000000000000000000000000000000000..fa4e06abe0a02696daf6f5cb27e854e7c5404fe7
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/test/modules/test1.js
@@ -0,0 +1 @@
+exports.x = 1;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/test/modules/test2.js b/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/test/modules/test2.js
new file mode 100644
index 0000000000000000000000000000000000000000..88e9166e860ebc85b4e7215d492c80668fe84f25
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/test/modules/test2.js
@@ -0,0 +1 @@
+exports.y = 2;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/test/modules/test3.js b/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/test/modules/test3.js
new file mode 100644
index 0000000000000000000000000000000000000000..670e724a6e6463ca0ce02615e3ebb24335d886e1
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/hoek/test/modules/test3.js
@@ -0,0 +1 @@
+exports.z = 3;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/.npmignore b/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/.npmignore
new file mode 100644
index 0000000000000000000000000000000000000000..1f3b66abb3fc8b77067c9af1f080fa4ac1e5548e
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/.npmignore
@@ -0,0 +1,3 @@
+/coverage.html
+/coverage.lcov
+/node_modules
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/.travis.yml b/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..8f451e6ddf1a469d95e534b3640bc46ea5687a3e
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/.travis.yml
@@ -0,0 +1,5 @@
+language: node_js
+node_js:
+  - "0.10"
+  - "4.0"
+sudo: false
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/LICENSE b/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..89dc9294e1da5cb6ddf2a11f4c709f74349d73fe
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/LICENSE
@@ -0,0 +1,13 @@
+Copyright © 2008-2011, Dominic Sayers
+Copyright © 2013-2014, GlobeSherpa
+Copyright © 2014-2015, Eli Skeggs
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+- Neither the name of Dominic Sayers nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/Makefile b/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..c2adcd18e2698f5fd2e851fb346fc35f34b1f478
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/Makefile
@@ -0,0 +1,4 @@
+test:
+	npm test
+
+.PHONY: test
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/README.md b/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..14b5efba737ad8bfda8c96de9c9f745b6f970b2f
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/README.md
@@ -0,0 +1,95 @@
+isemail
+=======
+
+Node email address validation library
+
+[![Build Status](https://travis-ci.org/hapijs/isemail.png)](https://travis-ci.org/hapijs/isemail)
+[![Coverage Status](https://coveralls.io/repos/hapijs/isemail/badge.png?branch=master)](https://coveralls.io/r/hapijs/isemail?branch=master)
+
+Lead Maintainer: [Eli Skeggs](https://github.com/skeggse)
+
+This first version of `isemail` is a port of the PHP `is_email` function by Dominic Sayers.
+
+Install
+-------
+
+```sh
+$ npm install isemail
+```
+
+Test
+----
+
+The tests were pulled from is_email's extensive [test suite][tests] on October 15, 2013. Many thanks to the contributors! Additional tests have been added to increase code coverage and verify edge-cases.
+
+Run any of the following.
+
+```sh
+$ lab
+$ npm test
+$ make test
+```
+
+_remember to_ `npm install`!
+
+API
+---
+
+### isEmail(email, [options], [callback])
+
+Determines whether the `email` is valid or not, for various definitions thereof. Optionally accepts an `options` object and a `callback` function. Options may include `errorLevel` and `checkDNS`. The `callback` function will always be called if specified, and the result of the operation supplied as the only parameter to the callback function. If `isEmail` is not asked to check for the existence of the domain (`checkDNS`), it will also synchronously return the result of the operation.
+
+Use `errorLevel` to specify the type of result for `isEmail`. Passing a `false` literal will result in a true or false boolean indicating whether the email address is sufficiently defined for use in sending an email. Passing a `true` literal will result in a more granular numeric status, with zero being a perfectly valid email address. Passing a number will return `0` if the numeric status is below the `errorLevel` and the numeric status otherwise.
+
+The `tldWhitelist` option can be either an object lookup table or an array of valid top-level domains. If the email address has a top-level domain that is not in the whitelist, the email will be marked as invalid.
+
+The `minDomainAtoms` option is an optional positive integer that specifies the minimum number of domain atoms that must be included for the email address to be considered valid. Be careful with the option, as some top-level domains, like `io`, directly support email addresses. To better handle fringe cases like the `io` TLD, use the `checkDNS` parameter, which will only allow email addresses for domains which have an MX record.
+
+#### Examples
+
+```js
+$ node
+> var isEmail = require('isemail');
+undefined
+> var log = console.log.bind(console, 'result');
+undefined
+> isEmail('test@iana.org');
+true
+> isEmail('test@iana.org', log);
+result true
+true
+> isEmail('test@iana.org', {checkDNS: true});
+undefined
+> isEmail('test@iana.org', {checkDNS: true}, log);
+undefined
+result true
+> isEmail('test@iana.org', {errorLevel: true});
+0
+> isEmail('test@iana.org', {errorLevel: true}, log);
+result 0
+0
+> isEmail('test@e.com');
+true
+> isEmail('test@e.com', {checkDNS: true, errorLevel: true}, log);
+undefined
+result 6
+> isEmail('test@e.com', {checkDNS: true, errorLevel: 7}, log);
+undefined
+result 0
+> isEmail('test@e.com', {checkDNS: true, errorLevel: 6}, log);
+undefined
+result 6
+```
+
+TODO
+====
+
+Add tests for library usage, not just functionality comparisons.
+Future versions will improve upon the current version, optimizing it for efficient usage and DRYing the code.
+
+License
+=======
+
+[BSD License](http://www.opensource.org/licenses/bsd-license.php)
+
+[tests]: http://isemail.info/_system/is_email/test/?all‎ "is_email test suite"
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/index.js b/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..67292e487057cec0fbfa4c01d29146bac74d1c76
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/index.js
@@ -0,0 +1 @@
+module.exports = require('./lib/isemail');
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/lib/isemail.js b/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/lib/isemail.js
new file mode 100644
index 0000000000000000000000000000000000000000..f7a558ec2991160aff98e244d455c73dbab863c5
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/lib/isemail.js
@@ -0,0 +1,1394 @@
+/**
+ * To validate an email address according to RFCs 5321, 5322 and others
+ *
+ * Copyright © 2008-2011, Dominic Sayers
+ * Test schema documentation Copyright © 2011, Daniel Marschall
+ * Port for Node.js Copyright © 2013-2014, GlobeSherpa
+ *              and Copyright © 2014-2015, Eli Skeggs
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright notice,
+ *     this list of conditions and the following disclaimer in the documentation
+ *     and/or other materials provided with the distribution.
+ *   - Neither the name of Dominic Sayers nor the names of its contributors may
+ *     be used to endorse or promote products derived from this software without
+ *     specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @author      Dominic Sayers <dominic@sayers.cc>
+ * @author      Eli Skeggs <skeggse@gmail.com>
+ * @copyright   2008-2011 Dominic Sayers
+ * @copyright   2013-2014 GlobeSherpa
+ * @copyright   2014-2015 Eli Skeggs
+ * @license     http://www.opensource.org/licenses/bsd-license.php BSD License
+ * @link        http://www.dominicsayers.com/isemail
+ * @link        https://github.com/hapijs/isemail
+ * @version     1.2.0 Drop Node 0.8, fix style, switch to lab/code
+ */
+
+var Dns = require('dns');
+
+var internals = {
+    defaultThreshold: 16,
+    maxIPv6Groups: 8,
+    categories: {
+        valid: 1,
+        dnsWarn: 7,
+        rfc5321: 15,
+        cfws: 31,
+        deprecated: 63,
+        rfc5322: 127,
+        error: 255
+    },
+
+    diagnoses: {
+        // Address is valid
+        valid: 0,
+
+        // Address is valid, but the DNS check failed
+        dnsWarnNoMXRecord: 5,
+        dnsWarnNoRecord: 6,
+
+        // Address is valid for SMTP but has unusual elements
+        rfc5321TLD: 9,
+        rfc5321TLDNumeric: 10,
+        rfc5321QuotedString: 11,
+        rfc5321AddressLiteral: 12,
+
+        // Address is valid for message, but must be modified for envelope
+        cfwsComment: 17,
+        cfwsFWS: 18,
+
+        // Address contains deprecated elements, but may still be valid in some contexts
+        deprecatedLocalPart: 33,
+        deprecatedFWS: 34,
+        deprecatedQTEXT: 35,
+        deprecatedQP: 36,
+        deprecatedComment: 37,
+        deprecatedCTEXT: 38,
+        deprecatedIPv6: 39,
+        deprecatedCFWSNearAt: 49,
+
+        // Address is only valid according to broad definition in RFC 5322, but is otherwise invalid
+        rfc5322Domain: 65,
+        rfc5322TooLong: 66,
+        rfc5322LocalTooLong: 67,
+        rfc5322DomainTooLong: 68,
+        rfc5322LabelTooLong: 69,
+        rfc5322DomainLiteral: 70,
+        rfc5322DomainLiteralOBSDText: 71,
+        rfc5322IPv6GroupCount: 72,
+        rfc5322IPv62x2xColon: 73,
+        rfc5322IPv6BadCharacter: 74,
+        rfc5322IPv6MaxGroups: 75,
+        rfc5322IPv6ColonStart: 76,
+        rfc5322IPv6ColonEnd: 77,
+
+        // Address is invalid for any purpose
+        errExpectingDTEXT: 129,
+        errNoLocalPart: 130,
+        errNoDomain: 131,
+        errConsecutiveDots: 132,
+        errATEXTAfterCFWS: 133,
+        errATEXTAfterQS: 134,
+        errATEXTAfterDomainLiteral: 135,
+        errExpectingQPair: 136,
+        errExpectingATEXT: 137,
+        errExpectingQTEXT: 138,
+        errExpectingCTEXT: 139,
+        errBackslashEnd: 140,
+        errDotStart: 141,
+        errDotEnd: 142,
+        errDomainHyphenStart: 143,
+        errDomainHyphenEnd: 144,
+        errUnclosedQuotedString: 145,
+        errUnclosedComment: 146,
+        errUnclosedDomainLiteral: 147,
+        errFWSCRLFx2: 148,
+        errFWSCRLFEnd: 149,
+        errCRNoLF: 150,
+        errUnknownTLD: 160,
+        errDomainTooShort: 161
+    },
+
+    components: {
+        localpart: 0,
+        domain: 1,
+        literal: 2,
+        contextComment: 3,
+        contextFWS: 4,
+        contextQuotedString: 5,
+        contextQuotedPair: 6
+    }
+};
+
+// $lab:coverage:off$
+internals.defer = typeof process !== 'undefined' && process && typeof process.nextTick === 'function' ?
+    process.nextTick.bind(process) :
+    function (callback) {
+
+        return setTimeout(callback, 0);
+    };
+// $lab:coverage:on$
+
+
+// US-ASCII visible characters not valid for atext
+// (http://tools.ietf.org/html/rfc5322#section-3.2.3)
+var SPECIALS = '()<>[]:;@\\,."';
+
+// A silly little optimized function generator
+var optimizeLookup = function optimizeLookup (string) {
+
+    var lookup = new Array(0x100);
+
+    for (var i = 0xff; i >= 0; --i) {
+        lookup[i] = false;
+    }
+
+    for (var il = string.length; i < il; ++i) {
+        lookup[string.charCodeAt(i)] = true;
+    }
+
+    var body = 'return function (code) {\n';
+    body += '  return lookup[code];\n';
+    body += '}';
+    return (new Function('lookup', body))(lookup);
+};
+
+
+var specialsLookup = optimizeLookup(SPECIALS);
+
+// This matches valid IPv4 addresses from the end of a string
+var IPv4_REGEX =
+    /\b(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/;
+var IPv6_REGEX = /^[a-fA-F\d]{0,4}$/;
+var IPv6_REGEX_TEST = IPv6_REGEX.test.bind(IPv6_REGEX);
+
+var hasOwn = Object.prototype.hasOwnProperty;
+
+/**
+ * Check that an email address conforms to RFCs 5321, 5322 and others
+ *
+ * We distinguish clearly between a Mailbox as defined by RFC 5321 and an
+ * addr-spec as defined by RFC 5322. Depending on the context, either can be
+ * regarded as a valid email address. The RFC 5321 Mailbox specification is
+ * more restrictive (comments, white space and obsolete forms are not allowed).
+ *
+ * @param {string} email The email address to check.
+ * @param {Object} options The (optional) options:
+ *   {boolean} checkDNS If true then will check DNS for MX records. If
+ *     true this call to isEmail _will_ be asynchronous.
+ *   {*} errorLevel Determines the boundary between valid and invalid
+ *     addresses. Status codes above this number will be returned as-is, status
+ *     codes below will be returned as valid. Thus the calling program can
+ *     simply look for diagnoses.valid if it is only interested in whether an
+ *     address is valid or not. The errorLevel will determine how "picky"
+ *     isEmail() is about the address. If omitted or passed as false then
+ *     isEmail() will return true or false rather than an integer error or
+ *     warning. NB Note the difference between errorLevel = false and
+ *     errorLevel = 0.
+ * @param {function(number|boolean)} callback The (optional) callback handler.
+ * @return {*}
+ */
+var isEmail = function isEmail (email, options, callback) {
+
+    if (typeof options === 'function') {
+        callback = options;
+        options = {};
+    }
+
+    if (!options) {
+        options = {};
+    }
+
+    if (typeof callback !== 'function') {
+        if (options.checkDNS) {
+            throw new TypeError('expected callback function for checkDNS option');
+        }
+
+        callback = null;
+    }
+
+    var diagnose;
+    var threshold;
+
+    if (typeof options.errorLevel === 'number') {
+        diagnose = true;
+        threshold = options.errorLevel;
+    }
+    else {
+        diagnose = !!options.errorLevel;
+        threshold = internals.diagnoses.valid;
+    }
+
+    if (options.tldWhitelist) {
+        if (typeof options.tldWhitelist === 'string') {
+            options.tldWhitelist = [options.tldWhitelist];
+        } else if (typeof options.tldWhitelist !== 'object') {
+            throw new TypeError('expected array or object tldWhitelist');
+        }
+    }
+
+    if (options.minDomainAtoms && (options.minDomainAtoms !== ((+options.minDomainAtoms) | 0) || options.minDomainAtoms < 0)) {
+        throw new TypeError('expected positive integer minDomainAtoms');
+    }
+
+    var maxResult = internals.diagnoses.valid;
+
+    var updateResult = function updateResult (value) {
+
+        if (value > maxResult) {
+            maxResult = value;
+        }
+    };
+
+    var context = {
+        now: internals.components.localpart,
+        prev: internals.components.localpart,
+        stack: [internals.components.localpart]
+    };
+
+    var token;
+    var prevToken = '';
+    var charCode = 0;
+
+    var parseData = {
+        local: '',
+        domain: ''
+    };
+    var atomData = {
+        locals: [''],
+        domains: ['']
+    };
+
+    var elementCount = 0;
+    var elementLength = 0;
+    var crlfCount = 0;
+
+    var hyphenFlag = false;
+    var assertEnd = false;
+
+    var emailLength = email.length;
+
+    for (var i = 0, il = emailLength; i < il; ++i) {
+        // Token is used outside the loop, must declare similarly
+        token = email[i];
+
+        switch (context.now) {
+            // Local-part
+            case internals.components.localpart:
+                // http://tools.ietf.org/html/rfc5322#section-3.4.1
+                //   local-part      =   dot-atom / quoted-string / obs-local-part
+                //
+                //   dot-atom        =   [CFWS] dot-atom-text [CFWS]
+                //
+                //   dot-atom-text   =   1*atext *("." 1*atext)
+                //
+                //   quoted-string   =   [CFWS]
+                //                       DQUOTE *([FWS] qcontent) [FWS] DQUOTE
+                //                       [CFWS]
+                //
+                //   obs-local-part  =   word *("." word)
+                //
+                //   word            =   atom / quoted-string
+                //
+                //   atom            =   [CFWS] 1*atext [CFWS]
+                switch (token) {
+                    // Comment
+                    case '(':
+                        if (elementLength === 0) {
+                            // Comments are OK at the beginning of an element
+                            updateResult(elementCount === 0 ? internals.diagnoses.cfwsComment : internals.diagnoses.deprecatedComment);
+                        }
+                        else {
+                            updateResult(internals.diagnoses.cfwsComment);
+                             // Cannot start a comment in an element, should be end
+                            assertEnd = true;
+                        }
+
+                        context.stack.push(context.now);
+                        context.now = internals.components.contextComment;
+                        break;
+
+                    // Next dot-atom element
+                    case '.':
+                        if (elementLength === 0) {
+                            // Another dot, already?
+                            updateResult(elementCount === 0 ? internals.diagnoses.errDotStart : internals.diagnoses.errConsecutiveDots);
+                        }
+                        else {
+                            // The entire local-part can be a quoted string for RFC 5321; if one atom is quoted it's an RFC 5322 obsolete form
+                            if (assertEnd) {
+                                updateResult(internals.diagnoses.deprecatedLocalPart);
+                            }
+
+                            // CFWS & quoted strings are OK again now we're at the beginning of an element (although they are obsolete forms)
+                            assertEnd = false;
+                            elementLength = 0;
+                            ++elementCount;
+                            parseData.local += token;
+                            atomData.locals[elementCount] = '';
+                        }
+
+                        break;
+
+                    // Quoted string
+                    case '"':
+                        if (elementLength === 0) {
+                            // The entire local-part can be a quoted string for RFC 5321; if one atom is quoted it's an RFC 5322 obsolete form
+                            updateResult(elementCount === 0 ? internals.diagnoses.rfc5321QuotedString : internals.diagnoses.deprecatedLocalPart);
+
+                            parseData.local += token;
+                            atomData.locals[elementCount] += token;
+                            ++elementLength;
+
+                            // Quoted string must be the entire element
+                            assertEnd = true;
+                            context.stack.push(context.now);
+                            context.now = internals.components.contextQuotedString;
+                        }
+                        else {
+                            updateResult(internals.diagnoses.errExpectingATEXT);
+                        }
+
+                        break;
+
+                    // Folding white space
+                    case '\r':
+                        if (emailLength === ++i || email[i] !== '\n') {
+                            // Fatal error
+                            updateResult(internals.diagnoses.errCRNoLF);
+                            break;
+                        }
+
+                        // Fallthrough
+
+                    case ' ':
+                    case '\t':
+                        if (elementLength === 0) {
+                            updateResult(elementCount === 0 ? internals.diagnoses.cfwsFWS : internals.diagnoses.deprecatedFWS);
+                        }
+                        else {
+                            // We can't start FWS in the middle of an element, better be end
+                            assertEnd = true;
+                        }
+
+                        context.stack.push(context.now);
+                        context.now = internals.components.contextFWS;
+                        prevToken = token;
+                        break;
+
+                    case '@':
+                        // At this point we should have a valid local-part
+                        // $lab:coverage:off$
+                        if (context.stack.length !== 1) {
+                            throw new Error('unexpected item on context stack');
+                        }
+                        // $lab:coverage:on$
+
+                        if (parseData.local.length === 0) {
+                            // Fatal error
+                            updateResult(internals.diagnoses.errNoLocalPart);
+                        }
+                        else if (elementLength === 0) {
+                            // Fatal error
+                            updateResult(internals.diagnoses.errDotEnd);
+                        }
+                        // http://tools.ietf.org/html/rfc5321#section-4.5.3.1.1 the maximum total length of a user name or other local-part is 64
+                        //    octets
+                        else if (parseData.local.length > 64) {
+                            updateResult(internals.diagnoses.rfc5322LocalTooLong);
+                        }
+                        // http://tools.ietf.org/html/rfc5322#section-3.4.1 comments and folding white space SHOULD NOT be used around "@" in the
+                        //    addr-spec
+                        //
+                        // http://tools.ietf.org/html/rfc2119
+                        // 4. SHOULD NOT this phrase, or the phrase "NOT RECOMMENDED" mean that there may exist valid reasons in particular
+                        //    circumstances when the particular behavior is acceptable or even useful, but the full implications should be understood
+                        //    and the case carefully weighed before implementing any behavior described with this label.
+                        else if (context.prev === internals.components.contextComment || context.prev === internals.components.contextFWS) {
+                            updateResult(internals.diagnoses.deprecatedCFWSNearAt);
+                        }
+
+                        // Clear everything down for the domain parsing
+                        context.now = internals.components.domain;
+                        context.stack[0] = internals.components.domain;
+                        elementCount = 0;
+                        elementLength = 0;
+                        assertEnd = false; // CFWS can only appear at the end of the element
+                        break;
+
+                    // ATEXT
+                    default:
+                        // http://tools.ietf.org/html/rfc5322#section-3.2.3
+                        //    atext = ALPHA / DIGIT / ; Printable US-ASCII
+                        //            "!" / "#" /     ;  characters not including
+                        //            "$" / "%" /     ;  specials.  Used for atoms.
+                        //            "&" / "'" /
+                        //            "*" / "+" /
+                        //            "-" / "/" /
+                        //            "=" / "?" /
+                        //            "^" / "_" /
+                        //            "`" / "{" /
+                        //            "|" / "}" /
+                        //            "~"
+                        if (assertEnd) {
+                            // We have encountered atext where it is no longer valid
+                            switch (context.prev) {
+                                case internals.components.contextComment:
+                                case internals.components.contextFWS:
+                                    updateResult(internals.diagnoses.errATEXTAfterCFWS);
+                                    break;
+
+                                case internals.components.contextQuotedString:
+                                    updateResult(internals.diagnoses.errATEXTAfterQS);
+                                    break;
+
+                                // $lab:coverage:off$
+                                default:
+                                    throw new Error('more atext found where none is allowed, but unrecognized prev context: ' + context.prev);
+                                // $lab:coverage:on$
+                            }
+                        }
+                        else {
+                            context.prev = context.now;
+                            charCode = token.charCodeAt(0);
+
+                            // Especially if charCode == 10
+                            if (charCode < 33 || charCode > 126 || specialsLookup(charCode)) {
+
+                                // Fatal error
+                                updateResult(internals.diagnoses.errExpectingATEXT);
+                            }
+
+                            parseData.local += token;
+                            atomData.locals[elementCount] += token;
+                            ++elementLength;
+                        }
+                }
+
+                break;
+
+            case internals.components.domain:
+                // http://tools.ietf.org/html/rfc5322#section-3.4.1
+                //   domain          =   dot-atom / domain-literal / obs-domain
+                //
+                //   dot-atom        =   [CFWS] dot-atom-text [CFWS]
+                //
+                //   dot-atom-text   =   1*atext *("." 1*atext)
+                //
+                //   domain-literal  =   [CFWS] "[" *([FWS] dtext) [FWS] "]" [CFWS]
+                //
+                //   dtext           =   %d33-90 /          ; Printable US-ASCII
+                //                       %d94-126 /         ;  characters not including
+                //                       obs-dtext          ;  "[", "]", or "\"
+                //
+                //   obs-domain      =   atom *("." atom)
+                //
+                //   atom            =   [CFWS] 1*atext [CFWS]
+
+                // http://tools.ietf.org/html/rfc5321#section-4.1.2
+                //   Mailbox        = Local-part "@" ( Domain / address-literal )
+                //
+                //   Domain         = sub-domain *("." sub-domain)
+                //
+                //   address-literal  = "[" ( IPv4-address-literal /
+                //                    IPv6-address-literal /
+                //                    General-address-literal ) "]"
+                //                    ; See Section 4.1.3
+
+                // http://tools.ietf.org/html/rfc5322#section-3.4.1
+                //      Note: A liberal syntax for the domain portion of addr-spec is
+                //      given here.  However, the domain portion contains addressing
+                //      information specified by and used in other protocols (e.g.,
+                //      [RFC1034], [RFC1035], [RFC1123], [RFC5321]).  It is therefore
+                //      incumbent upon implementations to conform to the syntax of
+                //      addresses for the context in which they are used.
+                //
+                // is_email() author's note: it's not clear how to interpret this in
+                // he context of a general email address validator. The conclusion I
+                // have reached is this: "addressing information" must comply with
+                // RFC 5321 (and in turn RFC 1035), anything that is "semantically
+                // invisible" must comply only with RFC 5322.
+                switch (token) {
+                    // Comment
+                    case '(':
+                        if (elementLength === 0) {
+                            // Comments at the start of the domain are deprecated in the text, comments at the start of a subdomain are obs-domain
+                            // http://tools.ietf.org/html/rfc5322#section-3.4.1
+                            updateResult(elementCount === 0 ? internals.diagnoses.deprecatedCFWSNearAt : internals.diagnoses.deprecatedComment);
+                        }
+                        else {
+                            // We can't start a comment mid-element, better be at the end
+                            assertEnd = true;
+                            updateResult(internals.diagnoses.cfwsComment);
+                        }
+
+                        context.stack.push(context.now);
+                        context.now = internals.components.contextComment;
+                        break;
+
+                    // Next dot-atom element
+                    case '.':
+                        if (elementLength === 0) {
+                            // Another dot, already? Fatal error.
+                            updateResult(elementCount === 0 ? internals.diagnoses.errDotStart : internals.diagnoses.errConsecutiveDots);
+                        }
+                        else if (hyphenFlag) {
+                            // Previous subdomain ended in a hyphen. Fatal error.
+                            updateResult(internals.diagnoses.errDomainHyphenEnd);
+                        }
+                        else if (elementLength > 63) {
+                            // Nowhere in RFC 5321 does it say explicitly that the domain part of a Mailbox must be a valid domain according to the
+                            // DNS standards set out in RFC 1035, but this *is* implied in several places. For instance, wherever the idea of host
+                            // routing is discussed the RFC says that the domain must be looked up in the DNS. This would be nonsense unless the
+                            // domain was designed to be a valid DNS domain. Hence we must conclude that the RFC 1035 restriction on label length
+                            // also applies to RFC 5321 domains.
+                            //
+                            // http://tools.ietf.org/html/rfc1035#section-2.3.4
+                            // labels          63 octets or less
+
+                            updateResult(internals.diagnoses.rfc5322LabelTooLong);
+                        }
+
+                        // CFWS is OK again now we're at the beginning of an element (although
+                        // it may be obsolete CFWS)
+                        assertEnd = false;
+                        elementLength = 0;
+                        ++elementCount;
+                        atomData.domains[elementCount] = '';
+                        parseData.domain += token;
+
+                        break;
+
+                    // Domain literal
+                    case '[':
+                        if (parseData.domain.length === 0) {
+                            // Domain literal must be the only component
+                            assertEnd = true;
+                            ++elementLength;
+                            context.stack.push(context.now);
+                            context.now = internals.components.literal;
+                            parseData.domain += token;
+                            atomData.domains[elementCount] += token;
+                            parseData.literal = '';
+                        }
+                        else {
+                            // Fatal error
+                            updateResult(internals.diagnoses.errExpectingATEXT);
+                        }
+
+                        break;
+
+                    // Folding white space
+                    case '\r':
+                        if (emailLength === ++i || email[i] !== '\n') {
+                            // Fatal error
+                            updateResult(internals.diagnoses.errCRNoLF);
+                            break;
+                        }
+
+                        // Fallthrough
+
+                    case ' ':
+                    case '\t':
+                        if (elementLength === 0) {
+                            updateResult(elementCount === 0 ? internals.diagnoses.deprecatedCFWSNearAt : internals.diagnoses.deprecatedFWS);
+                        }
+                        else {
+                            // We can't start FWS in the middle of an element, so this better be the end
+                            updateResult(internals.diagnoses.cfwsFWS);
+                            assertEnd = true;
+                        }
+
+                        context.stack.push(context.now);
+                        context.now = internals.components.contextFWS;
+                        prevToken = token;
+                        break;
+
+                    // This must be ATEXT
+                    default:
+                        // RFC 5322 allows any atext...
+                        // http://tools.ietf.org/html/rfc5322#section-3.2.3
+                        //    atext = ALPHA / DIGIT / ; Printable US-ASCII
+                        //            "!" / "#" /     ;  characters not including
+                        //            "$" / "%" /     ;  specials.  Used for atoms.
+                        //            "&" / "'" /
+                        //            "*" / "+" /
+                        //            "-" / "/" /
+                        //            "=" / "?" /
+                        //            "^" / "_" /
+                        //            "`" / "{" /
+                        //            "|" / "}" /
+                        //            "~"
+
+                        // But RFC 5321 only allows letter-digit-hyphen to comply with DNS rules
+                        //   (RFCs 1034 & 1123)
+                        // http://tools.ietf.org/html/rfc5321#section-4.1.2
+                        //   sub-domain     = Let-dig [Ldh-str]
+                        //
+                        //   Let-dig        = ALPHA / DIGIT
+                        //
+                        //   Ldh-str        = *( ALPHA / DIGIT / "-" ) Let-dig
+                        //
+                        if (assertEnd) {
+                            // We have encountered ATEXT where it is no longer valid
+                            switch (context.prev) {
+                                case internals.components.contextComment:
+                                case internals.components.contextFWS:
+                                    updateResult(internals.diagnoses.errATEXTAfterCFWS);
+                                    break;
+
+                                case internals.components.literal:
+                                    updateResult(internals.diagnoses.errATEXTAfterDomainLiteral);
+                                    break;
+
+                                // $lab:coverage:off$
+                                default:
+                                    throw new Error('more atext found where none is allowed, but unrecognized prev context: ' + context.prev);
+                                // $lab:coverage:on$
+                            }
+                        }
+
+                        charCode = token.charCodeAt(0);
+                        // Assume this token isn't a hyphen unless we discover it is
+                        hyphenFlag = false;
+
+                        if (charCode < 33 || charCode > 126 || specialsLookup(charCode)) {
+                            // Fatal error
+                            updateResult(internals.diagnoses.errExpectingATEXT);
+                        }
+                        else if (token === '-') {
+                            if (elementLength === 0) {
+                                // Hyphens cannot be at the beginning of a subdomain, fatal error
+                                updateResult(internals.diagnoses.errDomainHyphenStart);
+                            }
+
+                            hyphenFlag = true;
+                        }
+                        // Check if it's a neither a number nor a latin letter
+                        else if (charCode < 48 || charCode > 122 || (charCode > 57 && charCode < 65) || (charCode > 90 && charCode < 97)) {
+                            // This is not an RFC 5321 subdomain, but still OK by RFC 5322
+                            updateResult(internals.diagnoses.rfc5322Domain);
+                        }
+
+                        parseData.domain += token;
+                        atomData.domains[elementCount] += token;
+                        ++elementLength;
+                }
+
+                break;
+
+            // Domain literal
+            case internals.components.literal:
+                // http://tools.ietf.org/html/rfc5322#section-3.4.1
+                //   domain-literal  =   [CFWS] "[" *([FWS] dtext) [FWS] "]" [CFWS]
+                //
+                //   dtext           =   %d33-90 /          ; Printable US-ASCII
+                //                       %d94-126 /         ;  characters not including
+                //                       obs-dtext          ;  "[", "]", or "\"
+                //
+                //   obs-dtext       =   obs-NO-WS-CTL / quoted-pair
+                switch (token) {
+                    // End of domain literal
+                    case ']':
+                        if (maxResult < internals.categories.deprecated) {
+                            // Could be a valid RFC 5321 address literal, so let's check
+
+                            // http://tools.ietf.org/html/rfc5321#section-4.1.2
+                            //   address-literal  = "[" ( IPv4-address-literal /
+                            //                    IPv6-address-literal /
+                            //                    General-address-literal ) "]"
+                            //                    ; See Section 4.1.3
+                            //
+                            // http://tools.ietf.org/html/rfc5321#section-4.1.3
+                            //   IPv4-address-literal  = Snum 3("."  Snum)
+                            //
+                            //   IPv6-address-literal  = "IPv6:" IPv6-addr
+                            //
+                            //   General-address-literal  = Standardized-tag ":" 1*dcontent
+                            //
+                            //   Standardized-tag  = Ldh-str
+                            //                     ; Standardized-tag MUST be specified in a
+                            //                     ; Standards-Track RFC and registered with IANA
+                            //
+                            //   dcontent      = %d33-90 / ; Printable US-ASCII
+                            //                 %d94-126 ; excl. "[", "\", "]"
+                            //
+                            //   Snum          = 1*3DIGIT
+                            //                 ; representing a decimal integer
+                            //                 ; value in the range 0 through 255
+                            //
+                            //   IPv6-addr     = IPv6-full / IPv6-comp / IPv6v4-full / IPv6v4-comp
+                            //
+                            //   IPv6-hex      = 1*4HEXDIG
+                            //
+                            //   IPv6-full     = IPv6-hex 7(":" IPv6-hex)
+                            //
+                            //   IPv6-comp     = [IPv6-hex *5(":" IPv6-hex)] "::"
+                            //                 [IPv6-hex *5(":" IPv6-hex)]
+                            //                 ; The "::" represents at least 2 16-bit groups of
+                            //                 ; zeros.  No more than 6 groups in addition to the
+                            //                 ; "::" may be present.
+                            //
+                            //   IPv6v4-full   = IPv6-hex 5(":" IPv6-hex) ":" IPv4-address-literal
+                            //
+                            //   IPv6v4-comp   = [IPv6-hex *3(":" IPv6-hex)] "::"
+                            //                 [IPv6-hex *3(":" IPv6-hex) ":"]
+                            //                 IPv4-address-literal
+                            //                 ; The "::" represents at least 2 16-bit groups of
+                            //                 ; zeros.  No more than 4 groups in addition to the
+                            //                 ; "::" and IPv4-address-literal may be present.
+
+                            var index = -1;
+                            var addressLiteral = parseData.literal;
+                            var matchesIP = IPv4_REGEX.exec(addressLiteral);
+
+                            // Maybe extract IPv4 part from the end of the address-literal
+                            if (matchesIP) {
+                                index = matchesIP.index;
+                                if (index !== 0) {
+                                    // Convert IPv4 part to IPv6 format for futher testing
+                                    addressLiteral = addressLiteral.slice(0, index) + '0:0';
+                                }
+                            }
+
+                            if (index === 0) {
+                                // Nothing there except a valid IPv4 address, so...
+                                updateResult(internals.diagnoses.rfc5321AddressLiteral);
+                            }
+                            else if (addressLiteral.slice(0, 5).toLowerCase() !== 'ipv6:') {
+                                updateResult(internals.diagnoses.rfc5322DomainLiteral);
+                            }
+                            else {
+                                var match = addressLiteral.slice(5);
+                                var maxGroups = internals.maxIPv6Groups;
+                                var groups = match.split(':');
+                                index = match.indexOf('::');
+
+                                if (!~index) {
+                                    // Need exactly the right number of groups
+                                    if (groups.length !== maxGroups) {
+                                        updateResult(internals.diagnoses.rfc5322IPv6GroupCount);
+                                    }
+                                }
+                                else if (index !== match.lastIndexOf('::')) {
+                                    updateResult(internals.diagnoses.rfc5322IPv62x2xColon);
+                                }
+                                else {
+                                    if (index === 0 || index === match.length - 2) {
+                                        // RFC 4291 allows :: at the start or end of an address with 7 other groups in addition
+                                        ++maxGroups;
+                                    }
+
+                                    if (groups.length > maxGroups) {
+                                        updateResult(internals.diagnoses.rfc5322IPv6MaxGroups);
+                                    }
+                                    else if (groups.length === maxGroups) {
+                                        // Eliding a single "::"
+                                        updateResult(internals.diagnoses.deprecatedIPv6);
+                                    }
+                                }
+
+                                // IPv6 testing strategy
+                                if (match[0] === ':' && match[1] !== ':') {
+                                    updateResult(internals.diagnoses.rfc5322IPv6ColonStart);
+                                }
+                                else if (match[match.length - 1] === ':' && match[match.length - 2] !== ':') {
+                                    updateResult(internals.diagnoses.rfc5322IPv6ColonEnd);
+                                }
+                                else if (groups.every(IPv6_REGEX_TEST)) {
+                                    updateResult(internals.diagnoses.rfc5321AddressLiteral);
+                                }
+                                else {
+                                    updateResult(internals.diagnoses.rfc5322IPv6BadCharacter);
+                                }
+                            }
+                        }
+                        else {
+                            updateResult(internals.diagnoses.rfc5322DomainLiteral);
+                        }
+
+                        parseData.domain += token;
+                        atomData.domains[elementCount] += token;
+                        ++elementLength;
+                        context.prev = context.now;
+                        context.now = context.stack.pop();
+                        break;
+
+                    case '\\':
+                        updateResult(internals.diagnoses.rfc5322DomainLiteralOBSDText);
+                        context.stack.push(context.now);
+                        context.now = internals.components.contextQuotedPair;
+                        break;
+
+                    // Folding white space
+                    case '\r':
+                        if (emailLength === ++i || email[i] !== '\n') {
+                            updateResult(internals.diagnoses.errCRNoLF);
+                            break;
+                        }
+
+                        // Fallthrough
+
+                    case ' ':
+                    case '\t':
+                        updateResult(internals.diagnoses.cfwsFWS);
+
+                        context.stack.push(context.now);
+                        context.now = internals.components.contextFWS;
+                        prevToken = token;
+                        break;
+
+                    // DTEXT
+                    default:
+                        // http://tools.ietf.org/html/rfc5322#section-3.4.1
+                        //   dtext         =   %d33-90 /  ; Printable US-ASCII
+                        //                     %d94-126 / ;  characters not including
+                        //                     obs-dtext  ;  "[", "]", or "\"
+                        //
+                        //   obs-dtext     =   obs-NO-WS-CTL / quoted-pair
+                        //
+                        //   obs-NO-WS-CTL =   %d1-8 /    ; US-ASCII control
+                        //                     %d11 /     ;  characters that do not
+                        //                     %d12 /     ;  include the carriage
+                        //                     %d14-31 /  ;  return, line feed, and
+                        //                     %d127      ;  white space characters
+                        charCode = token.charCodeAt(0);
+
+                        // '\r', '\n', ' ', and '\t' have already been parsed above
+                        if (charCode > 127 || charCode === 0 || token === '[') {
+                            // Fatal error
+                            updateResult(internals.diagnoses.errExpectingDTEXT);
+                            break;
+                        }
+                        else if (charCode < 33 || charCode === 127) {
+                            updateResult(internals.diagnoses.rfc5322DomainLiteralOBSDText);
+                        }
+
+                        parseData.literal += token;
+                        parseData.domain += token;
+                        atomData.domains[elementCount] += token;
+                        ++elementLength;
+                }
+
+                break;
+
+            // Quoted string
+            case internals.components.contextQuotedString:
+                // http://tools.ietf.org/html/rfc5322#section-3.2.4
+                //   quoted-string = [CFWS]
+                //                   DQUOTE *([FWS] qcontent) [FWS] DQUOTE
+                //                   [CFWS]
+                //
+                //   qcontent      = qtext / quoted-pair
+                switch (token) {
+                    // Quoted pair
+                    case '\\':
+                        context.stack.push(context.now);
+                        context.now = internals.components.contextQuotedPair;
+                        break;
+
+                    // Folding white space. Spaces are allowed as regular characters inside a quoted string - it's only FWS if we include '\t' or '\r\n'
+                    case '\r':
+                        if (emailLength === ++i || email[i] !== '\n') {
+                            // Fatal error
+                            updateResult(internals.diagnoses.errCRNoLF);
+                            break;
+                        }
+
+                        // Fallthrough
+
+                    case '\t':
+                        // http://tools.ietf.org/html/rfc5322#section-3.2.2
+                        //   Runs of FWS, comment, or CFWS that occur between lexical tokens in
+                        //   a structured header field are semantically interpreted as a single
+                        //   space character.
+
+                        // http://tools.ietf.org/html/rfc5322#section-3.2.4
+                        //   the CRLF in any FWS/CFWS that appears within the quoted-string [is]
+                        //   semantically "invisible" and therefore not part of the
+                        //   quoted-string
+
+                        parseData.local += ' ';
+                        atomData.locals[elementCount] += ' ';
+                        ++elementLength;
+
+                        updateResult(internals.diagnoses.cfwsFWS);
+                        context.stack.push(context.now);
+                        context.now = internals.components.contextFWS;
+                        prevToken = token;
+                        break;
+
+                    // End of quoted string
+                    case '"':
+                        parseData.local += token;
+                        atomData.locals[elementCount] += token;
+                        ++elementLength;
+                        context.prev = context.now;
+                        context.now = context.stack.pop();
+                        break;
+
+                    // QTEXT
+                    default:
+                        // http://tools.ietf.org/html/rfc5322#section-3.2.4
+                        //   qtext          =   %d33 /             ; Printable US-ASCII
+                        //                      %d35-91 /          ;  characters not including
+                        //                      %d93-126 /         ;  "\" or the quote character
+                        //                      obs-qtext
+                        //
+                        //   obs-qtext      =   obs-NO-WS-CTL
+                        //
+                        //   obs-NO-WS-CTL  =   %d1-8 /            ; US-ASCII control
+                        //                      %d11 /             ;  characters that do not
+                        //                      %d12 /             ;  include the carriage
+                        //                      %d14-31 /          ;  return, line feed, and
+                        //                      %d127              ;  white space characters
+                        charCode = token.charCodeAt(0);
+
+                        if (charCode > 127 || charCode === 0 || charCode === 10) {
+                            updateResult(internals.diagnoses.errExpectingQTEXT);
+                        }
+                        else if (charCode < 32 || charCode === 127) {
+                            updateResult(internals.diagnoses.deprecatedQTEXT);
+                        }
+
+                        parseData.local += token;
+                        atomData.locals[elementCount] += token;
+                        ++elementLength;
+                }
+
+                // http://tools.ietf.org/html/rfc5322#section-3.4.1
+                //   If the string can be represented as a dot-atom (that is, it contains
+                //   no characters other than atext characters or "." surrounded by atext
+                //   characters), then the dot-atom form SHOULD be used and the quoted-
+                //   string form SHOULD NOT be used.
+
+                break;
+            // Quoted pair
+            case internals.components.contextQuotedPair:
+                // http://tools.ietf.org/html/rfc5322#section-3.2.1
+                //   quoted-pair     =   ("\" (VCHAR / WSP)) / obs-qp
+                //
+                //   VCHAR           =  %d33-126   ; visible (printing) characters
+                //   WSP             =  SP / HTAB  ; white space
+                //
+                //   obs-qp          =   "\" (%d0 / obs-NO-WS-CTL / LF / CR)
+                //
+                //   obs-NO-WS-CTL   =   %d1-8 /   ; US-ASCII control
+                //                       %d11 /    ;  characters that do not
+                //                       %d12 /    ;  include the carriage
+                //                       %d14-31 / ;  return, line feed, and
+                //                       %d127     ;  white space characters
+                //
+                // i.e. obs-qp       =  "\" (%d0-8, %d10-31 / %d127)
+                charCode = token.charCodeAt(0);
+
+                if (charCode > 127) {
+                    // Fatal error
+                    updateResult(internals.diagnoses.errExpectingQPair);
+                }
+                else if ((charCode < 31 && charCode !== 9) || charCode === 127) {
+                    // ' ' and '\t' are allowed
+                    updateResult(internals.diagnoses.deprecatedQP);
+                }
+
+                // At this point we know where this qpair occurred so we could check to see if the character actually needed to be quoted at all.
+                // http://tools.ietf.org/html/rfc5321#section-4.1.2
+                //   the sending system SHOULD transmit the form that uses the minimum quoting possible.
+
+                context.prev = context.now;
+                // End of qpair
+                context.now = context.stack.pop();
+                token = '\\' + token;
+
+                switch (context.now) {
+                    case internals.components.contextComment:
+                        break;
+
+                    case internals.components.contextQuotedString:
+                        parseData.local += token;
+                        atomData.locals[elementCount] += token;
+
+                        // The maximum sizes specified by RFC 5321 are octet counts, so we must include the backslash
+                        elementLength += 2;
+                        break;
+
+                    case internals.components.literal:
+                        parseData.domain += token;
+                        atomData.domains[elementCount] += token;
+
+                        // The maximum sizes specified by RFC 5321 are octet counts, so we must include the backslash
+                        elementLength += 2;
+                        break;
+
+                    // $lab:coverage:off$
+                    default:
+                        throw new Error('quoted pair logic invoked in an invalid context: ' + context.now);
+                    // $lab:coverage:on$
+                }
+                break;
+
+            // Comment
+            case internals.components.contextComment:
+                // http://tools.ietf.org/html/rfc5322#section-3.2.2
+                //   comment  = "(" *([FWS] ccontent) [FWS] ")"
+                //
+                //   ccontent = ctext / quoted-pair / comment
+                switch (token) {
+                    // Nested comment
+                    case '(':
+                        // Nested comments are ok
+                        context.stack.push(context.now);
+                        context.now = internals.components.contextComment;
+                        break;
+
+                    // End of comment
+                    case ')':
+                        context.prev = context.now;
+                        context.now = context.stack.pop();
+                        break;
+
+                    // Quoted pair
+                    case '\\':
+                        context.stack.push(context.now);
+                        context.now = internals.components.contextQuotedPair;
+                        break;
+
+                    // Folding white space
+                    case '\r':
+                        if (emailLength === ++i || email[i] !== '\n') {
+                            // Fatal error
+                            updateResult(internals.diagnoses.errCRNoLF);
+                            break;
+                        }
+
+                        // Fallthrough
+
+                    case ' ':
+                    case '\t':
+                        updateResult(internals.diagnoses.cfwsFWS);
+
+                        context.stack.push(context.now);
+                        context.now = internals.components.contextFWS;
+                        prevToken = token;
+                        break;
+
+                    // CTEXT
+                    default:
+                        // http://tools.ietf.org/html/rfc5322#section-3.2.3
+                        //   ctext         = %d33-39 /  ; Printable US-ASCII
+                        //                   %d42-91 /  ;  characters not including
+                        //                   %d93-126 / ;  "(", ")", or "\"
+                        //                   obs-ctext
+                        //
+                        //   obs-ctext     = obs-NO-WS-CTL
+                        //
+                        //   obs-NO-WS-CTL = %d1-8 /    ; US-ASCII control
+                        //                   %d11 /     ;  characters that do not
+                        //                   %d12 /     ;  include the carriage
+                        //                   %d14-31 /  ;  return, line feed, and
+                        //                   %d127      ;  white space characters
+                        charCode = token.charCodeAt(0);
+
+                        if (charCode > 127 || charCode === 0 || charCode === 10) {
+                            // Fatal error
+                            updateResult(internals.diagnoses.errExpectingCTEXT);
+                            break;
+                        }
+                        else if (charCode < 32 || charCode === 127) {
+                            updateResult(internals.diagnoses.deprecatedCTEXT);
+                        }
+                }
+
+                break;
+
+            // Folding white space
+            case internals.components.contextFWS:
+                // http://tools.ietf.org/html/rfc5322#section-3.2.2
+                //   FWS     =   ([*WSP CRLF] 1*WSP) /  obs-FWS
+                //                                   ; Folding white space
+
+                // But note the erratum:
+                // http://www.rfc-editor.org/errata_search.php?rfc=5322&eid=1908:
+                //   In the obsolete syntax, any amount of folding white space MAY be
+                //   inserted where the obs-FWS rule is allowed.  This creates the
+                //   possibility of having two consecutive "folds" in a line, and
+                //   therefore the possibility that a line which makes up a folded header
+                //   field could be composed entirely of white space.
+                //
+                //   obs-FWS =   1*([CRLF] WSP)
+
+                if (prevToken === '\r') {
+                    if (token === '\r') {
+                        // Fatal error
+                        updateResult(internals.diagnoses.errFWSCRLFx2);
+                        break;
+                    }
+
+                    if (++crlfCount > 1) {
+                        // Multiple folds => obsolete FWS
+                        updateResult(internals.diagnoses.deprecatedFWS);
+                    }
+                    else {
+                        crlfCount = 1;
+                    }
+                }
+
+                switch (token) {
+                    case '\r':
+                        if (emailLength === ++i || email[i] !== '\n') {
+                            // Fatal error
+                            updateResult(internals.diagnoses.errCRNoLF);
+                        }
+
+                        break;
+
+                    case ' ':
+                    case '\t':
+                        break;
+
+                    default:
+                        if (prevToken === '\r') {
+                            // Fatal error
+                            updateResult(internals.diagnoses.errFWSCRLFEnd);
+                        }
+
+                        crlfCount = 0;
+
+                        // End of FWS
+                        context.prev = context.now;
+                        context.now = context.stack.pop();
+
+                        // Look at this token again in the parent context
+                        --i;
+                }
+
+                prevToken = token;
+                break;
+
+            // Unexpected context
+            // $lab:coverage:off$
+            default:
+                throw new Error('unknown context: ' + context.now);
+            // $lab:coverage:on$
+        } // Primary state machine
+
+        if (maxResult > internals.categories.rfc5322) {
+            // Fatal error, no point continuing
+            break;
+        }
+    } // Token loop
+
+    // Check for errors
+    if (maxResult < internals.categories.rfc5322) {
+        // Fatal errors
+        if (context.now === internals.components.contextQuotedString) {
+            updateResult(internals.diagnoses.errUnclosedQuotedString);
+        }
+        else if (context.now === internals.components.contextQuotedPair) {
+            updateResult(internals.diagnoses.errBackslashEnd);
+        }
+        else if (context.now === internals.components.contextComment) {
+            updateResult(internals.diagnoses.errUnclosedComment);
+        }
+        else if (context.now === internals.components.literal) {
+            updateResult(internals.diagnoses.errUnclosedDomainLiteral);
+        }
+        else if (token === '\r') {
+            updateResult(internals.diagnoses.errFWSCRLFEnd);
+        }
+        else if (parseData.domain.length === 0) {
+            updateResult(internals.diagnoses.errNoDomain);
+        }
+        else if (elementLength === 0) {
+            updateResult(internals.diagnoses.errDotEnd);
+        }
+        else if (hyphenFlag) {
+            updateResult(internals.diagnoses.errDomainHyphenEnd);
+        }
+
+        // Other errors
+        else if (parseData.domain.length > 255) {
+            // http://tools.ietf.org/html/rfc5321#section-4.5.3.1.2
+            //   The maximum total length of a domain name or number is 255 octets.
+            updateResult(internals.diagnoses.rfc5322DomainTooLong);
+        }
+        else if (parseData.local.length + parseData.domain.length + /* '@' */ 1 > 254) {
+            // http://tools.ietf.org/html/rfc5321#section-4.1.2
+            //   Forward-path   = Path
+            //
+            //   Path           = "<" [ A-d-l ":" ] Mailbox ">"
+            //
+            // http://tools.ietf.org/html/rfc5321#section-4.5.3.1.3
+            //   The maximum total length of a reverse-path or forward-path is 256 octets (including the punctuation and element separators).
+            //
+            // Thus, even without (obsolete) routing information, the Mailbox can only be 254 characters long. This is confirmed by this verified
+            // erratum to RFC 3696:
+            //
+            // http://www.rfc-editor.org/errata_search.php?rfc=3696&eid=1690
+            //   However, there is a restriction in RFC 2821 on the length of an address in MAIL and RCPT commands of 254 characters.  Since
+            //   addresses that do not fit in those fields are not normally useful, the upper limit on address lengths should normally be considered
+            //   to be 254.
+            updateResult(internals.diagnoses.rfc5322TooLong);
+        }
+        else if (elementLength > 63) {
+            // http://tools.ietf.org/html/rfc1035#section-2.3.4
+            // labels   63 octets or less
+            updateResult(internals.diagnoses.rfc5322LabelTooLong);
+        }
+        else if (options.minDomainAtoms && atomData.domains.length < options.minDomainAtoms) {
+            updateResult(internals.diagnoses.errDomainTooShort);
+        }
+        else if (options.tldWhitelist) {
+            var tldAtom = atomData.domains[elementCount];
+            if (Array.isArray(options.tldWhitelist)) {
+                var tldValid = false;
+                for (i = 0, il = options.tldWhitelist.length; i < il; ++i) {
+                    if (tldAtom === options.tldWhitelist[i]) {
+                        tldValid = true;
+                        break;
+                    }
+                }
+
+                if (!tldValid) {
+                    updateResult(internals.diagnoses.errUnknownTLD);
+                }
+            }
+            else if (!hasOwn.call(options.tldWhitelist, tldAtom)) {
+                updateResult(internals.diagnoses.errUnknownTLD);
+            }
+        }
+    } // Check for errors
+
+    var dnsPositive = false;
+    var finishImmediately = false;
+
+    var finish = function finish () {
+
+        if (!dnsPositive && maxResult < internals.categories.dnsWarn) {
+            // Per RFC 5321, domain atoms are limited to letter-digit-hyphen, so we only need to check code <= 57 to check for a digit
+            var code = atomData.domains[elementCount].charCodeAt(0);
+            if (code <= 57) {
+                updateResult(internals.diagnoses.rfc5321TLDNumeric);
+            }
+            else if (elementCount === 0) {
+                updateResult(internals.diagnoses.rfc5321TLD);
+            }
+        }
+
+        if (maxResult < threshold) {
+            maxResult = internals.diagnoses.valid;
+        }
+
+        var finishResult = diagnose ? maxResult : maxResult < internals.defaultThreshold;
+
+        if (callback) {
+            if (finishImmediately) {
+                callback(finishResult);
+            } else {
+                internals.defer(callback.bind(null, finishResult));
+            }
+        }
+
+        return finishResult;
+    }; // Finish
+
+    if (options.checkDNS && maxResult < internals.categories.dnsWarn) {
+        // http://tools.ietf.org/html/rfc5321#section-2.3.5
+        //   Names that can be resolved to MX RRs or address (i.e., A or AAAA) RRs (as discussed in Section 5) are permitted, as are CNAME RRs whose
+        //   targets can be resolved, in turn, to MX or address RRs.
+        //
+        // http://tools.ietf.org/html/rfc5321#section-5.1
+        //   The lookup first attempts to locate an MX record associated with the name.  If a CNAME record is found, the resulting name is processed
+        //   as if it were the initial name. ... If an empty list of MXs is returned, the address is treated as if it was associated with an implicit
+        //   MX RR, with a preference of 0, pointing to that host.
+        //
+        // isEmail() author's note: We will regard the existence of a CNAME to be sufficient evidence of the domain's existence. For performance
+        // reasons we will not repeat the DNS lookup for the CNAME's target, but we will raise a warning because we didn't immediately find an MX
+        // record.
+        if (elementCount === 0) {
+            // Checking TLD DNS only works if you explicitly check from the root
+            parseData.domain += '.';
+        }
+
+        var dnsDomain = parseData.domain;
+        Dns.resolveMx(dnsDomain, function resolveDNS (err, mxRecords) {
+
+            // If we have a fatal error, then we must assume that there are no records
+            if (err && err.code !== Dns.NODATA) {
+                updateResult(internals.diagnoses.dnsWarnNoRecord);
+                return finish();
+            }
+
+            if (mxRecords && mxRecords.length) {
+                dnsPositive = true;
+                return finish();
+            }
+
+            var count = 3;
+            var done = false;
+            updateResult(internals.diagnoses.dnsWarnNoMXRecord);
+
+            var handleRecords = function handleRecords (err, records) {
+
+                if (done) {
+                    return;
+                }
+
+                --count;
+
+                if (records && records.length) {
+                    done = true;
+                    return finish();
+                }
+
+                if (count === 0) {
+                    // No usable records for the domain can be found
+                    updateResult(internals.diagnoses.dnsWarnNoRecord);
+                    done = true;
+                    finish();
+                }
+            };
+
+            Dns.resolveCname(dnsDomain, handleRecords);
+            Dns.resolve4(dnsDomain, handleRecords);
+            Dns.resolve6(dnsDomain, handleRecords);
+        });
+
+        finishImmediately = true;
+    }
+    else {
+        var result = finish();
+        finishImmediately = true;
+        return result;
+    } // CheckDNS
+};
+
+
+isEmail.diagnoses = (function exportDiagnoses () {
+
+    var diag = {};
+    for (var key in internals.diagnoses) {
+        diag[key] = internals.diagnoses[key];
+    }
+    return diag;
+})();
+
+module.exports = isEmail;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/package.json b/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..7ca0c94829f2b223beeb30a30d236ad91c8739db
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/package.json
@@ -0,0 +1,81 @@
+{
+  "_args": [
+    [
+      {
+        "raw": "isemail@https://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz",
+        "scope": null,
+        "escapedName": "isemail",
+        "name": "isemail",
+        "rawSpec": "https://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz",
+        "spec": "https://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz",
+        "type": "remote"
+      },
+      "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin"
+    ]
+  ],
+  "_from": "isemail@>=1.0.0 <2.0.0",
+  "_id": "isemail@1.2.0",
+  "_inCache": true,
+  "_location": "/firebase-admin/isemail",
+  "_phantomChildren": {},
+  "_requested": {
+    "raw": "isemail@https://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz",
+    "scope": null,
+    "escapedName": "isemail",
+    "name": "isemail",
+    "rawSpec": "https://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz",
+    "spec": "https://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz",
+    "type": "remote"
+  },
+  "_requiredBy": [
+    "/firebase-admin",
+    "/firebase-admin/joi"
+  ],
+  "_resolved": "https://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz",
+  "_shasum": "be03df8cc3e29de4d2c5df6501263f1fa4595e9a",
+  "_shrinkwrap": null,
+  "_spec": "isemail@https://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz",
+  "_where": "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin",
+  "author": {
+    "name": "Eli Skeggs",
+    "email": "skeggse@gmail.com"
+  },
+  "bugs": {
+    "url": "https://github.com/hapijs/isemail/issues"
+  },
+  "dependencies": {},
+  "description": "validate an email address according to RFCs 5321, 5322, and others",
+  "devDependencies": {
+    "code": "^1.5.0",
+    "lab": "^5.16.1"
+  },
+  "engines": {
+    "node": ">=0.10"
+  },
+  "homepage": "https://github.com/hapijs/isemail",
+  "keywords": [
+    "isemail",
+    "validation",
+    "check",
+    "checking",
+    "verification",
+    "email",
+    "address",
+    "email address"
+  ],
+  "license": "BSD-2-Clause",
+  "main": "./index",
+  "name": "isemail",
+  "optionalDependencies": {},
+  "readme": "isemail\r\n=======\r\n\r\nNode email address validation library\r\n\r\n[![Build Status](https://travis-ci.org/hapijs/isemail.png)](https://travis-ci.org/hapijs/isemail)\r\n[![Coverage Status](https://coveralls.io/repos/hapijs/isemail/badge.png?branch=master)](https://coveralls.io/r/hapijs/isemail?branch=master)\r\n\r\nLead Maintainer: [Eli Skeggs](https://github.com/skeggse)\r\n\r\nThis first version of `isemail` is a port of the PHP `is_email` function by Dominic Sayers.\r\n\r\nInstall\r\n-------\r\n\r\n```sh\r\n$ npm install isemail\r\n```\r\n\r\nTest\r\n----\r\n\r\nThe tests were pulled from is_email's extensive [test suite][tests] on October 15, 2013. Many thanks to the contributors! Additional tests have been added to increase code coverage and verify edge-cases.\r\n\r\nRun any of the following.\r\n\r\n```sh\r\n$ lab\r\n$ npm test\r\n$ make test\r\n```\r\n\r\n_remember to_ `npm install`!\r\n\r\nAPI\r\n---\r\n\r\n### isEmail(email, [options], [callback])\r\n\r\nDetermines whether the `email` is valid or not, for various definitions thereof. Optionally accepts an `options` object and a `callback` function. Options may include `errorLevel` and `checkDNS`. The `callback` function will always be called if specified, and the result of the operation supplied as the only parameter to the callback function. If `isEmail` is not asked to check for the existence of the domain (`checkDNS`), it will also synchronously return the result of the operation.\r\n\r\nUse `errorLevel` to specify the type of result for `isEmail`. Passing a `false` literal will result in a true or false boolean indicating whether the email address is sufficiently defined for use in sending an email. Passing a `true` literal will result in a more granular numeric status, with zero being a perfectly valid email address. Passing a number will return `0` if the numeric status is below the `errorLevel` and the numeric status otherwise.\r\n\r\nThe `tldWhitelist` option can be either an object lookup table or an array of valid top-level domains. If the email address has a top-level domain that is not in the whitelist, the email will be marked as invalid.\r\n\r\nThe `minDomainAtoms` option is an optional positive integer that specifies the minimum number of domain atoms that must be included for the email address to be considered valid. Be careful with the option, as some top-level domains, like `io`, directly support email addresses. To better handle fringe cases like the `io` TLD, use the `checkDNS` parameter, which will only allow email addresses for domains which have an MX record.\r\n\r\n#### Examples\r\n\r\n```js\r\n$ node\r\n> var isEmail = require('isemail');\r\nundefined\r\n> var log = console.log.bind(console, 'result');\r\nundefined\r\n> isEmail('test@iana.org');\r\ntrue\r\n> isEmail('test@iana.org', log);\r\nresult true\r\ntrue\r\n> isEmail('test@iana.org', {checkDNS: true});\r\nundefined\r\n> isEmail('test@iana.org', {checkDNS: true}, log);\r\nundefined\r\nresult true\r\n> isEmail('test@iana.org', {errorLevel: true});\r\n0\r\n> isEmail('test@iana.org', {errorLevel: true}, log);\r\nresult 0\r\n0\r\n> isEmail('test@e.com');\r\ntrue\r\n> isEmail('test@e.com', {checkDNS: true, errorLevel: true}, log);\r\nundefined\r\nresult 6\r\n> isEmail('test@e.com', {checkDNS: true, errorLevel: 7}, log);\r\nundefined\r\nresult 0\r\n> isEmail('test@e.com', {checkDNS: true, errorLevel: 6}, log);\r\nundefined\r\nresult 6\r\n```\r\n\r\nTODO\r\n====\r\n\r\nAdd tests for library usage, not just functionality comparisons.\r\nFuture versions will improve upon the current version, optimizing it for efficient usage and DRYing the code.\r\n\r\nLicense\r\n=======\r\n\r\n[BSD License](http://www.opensource.org/licenses/bsd-license.php)\r\n\r\n[tests]: http://isemail.info/_system/is_email/test/?all‎ \"is_email test suite\"\r\n",
+  "readmeFilename": "README.md",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/hapijs/isemail.git"
+  },
+  "scripts": {
+    "test": "lab -r console -o stdout -r lcov -o coverage.lcov -a code -L",
+    "test-cov-html": "lab -r html -o coverage.html -a code"
+  },
+  "version": "1.2.0"
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/test/isemail.js b/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/test/isemail.js
new file mode 100644
index 0000000000000000000000000000000000000000..b260da49ae771154d042ed142dacfee00db0741c
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/test/isemail.js
@@ -0,0 +1,175 @@
+var Lab = require('lab');
+var Code = require('code');
+var IsEmail = require('..');
+var Tests = require('./tests.json');
+
+var internals = {
+    defaultThreshold: 16
+};
+
+// Test shortcuts
+var isEmail = IsEmail;
+var lab = exports.lab = Lab.script();
+var before = lab.before;
+var after = lab.after;
+var describe = lab.describe;
+var it = lab.it;
+var expect = Code.expect;
+
+// Diagnoses
+var diag = isEmail.diagnoses;
+
+// Expectations
+var expectations = Tests.map(function mapper (value) {
+
+    value[1] = diag[value[1]];
+    return value;
+});
+
+// Null characters aren't supported in JSON
+expectations.push(['test@[\0', diag.errExpectingDTEXT]);
+expectations.push(['(\0)test@example.com', diag.errExpectingCTEXT]);
+
+var tldExpectations = [
+    ['shouldbe@invalid', diag.errUnknownTLD],
+    ['shouldbe@example.com', diag.valid]
+];
+
+describe('isEmail', function () {
+
+    it('should check options.tldWhitelist', function (done) {
+
+        expect(isEmail('person@top', {
+            tldWhitelist: 'top',
+            checkDNS: false
+        })).to.equal(true);
+
+        expect(isEmail('person@top', {
+            tldWhitelist: ['com'],
+            checkDNS: false
+        })).to.equal(false);
+
+        expect(function () {
+
+            isEmail('', {
+                tldWhitelist: 77
+            });
+        }).to.throw(/tldWhitelist/);
+        done();
+    });
+
+    it('should check options.minDomainAtoms', function (done) {
+
+        expect(function () {
+
+            isEmail('person@top', {
+                minDomainAtoms: -1
+            });
+        }).to.throw(/minDomainAtoms/);
+
+        expect(function () {
+
+            isEmail('person@top', {
+                minDomainAtoms: 1.5
+            });
+        }).to.throw(/minDomainAtoms/);
+        done();
+    });
+
+    it('should use options.errorLevel', function (done) {
+
+        expect(isEmail('person@123', {
+            errorLevel: diag.rfc5321TLDNumeric + 1
+        })).to.equal(0);
+
+        expect(isEmail('person@123', {
+            errorLevel: diag.rfc5321TLDNumeric
+        })).to.equal(diag.rfc5321TLDNumeric);
+        done();
+    });
+
+    it('should ensure callback provided with checkDNS', function (done) {
+
+        expect(function () {
+
+            isEmail('person@top', {
+                checkDNS: true
+            });
+        }).to.throw(/(?=.*\bcheckDNS\b)(?=.*\bcallback\b)/);
+        done();
+    });
+
+    it('should handle omitted options', function (done) {
+
+        expect(isEmail(expectations[0][0])).to.equal(expectations[0][1] < internals.defaultThreshold);
+        done();
+    });
+
+    it('should handle omitted options with callback', function (done) {
+
+        isEmail(expectations[0][0], function (res) {
+
+            expect(res).to.equal(expectations[0][1] < internals.defaultThreshold);
+            done();
+        });
+    });
+
+    expectations.forEach(function (obj, i) {
+
+        var email = obj[0], result = obj[1];
+        it('should handle test ' + (i + 1), function (done) {
+
+            isEmail(email, {
+                errorLevel: 0,
+                checkDNS: true
+            }, function (res) {
+
+                expect(res).to.equal(result);
+                done();
+            });
+        });
+    });
+
+    tldExpectations.forEach(function (obj, i) {
+
+        var email = obj[0];
+        var result = obj[1];
+
+        it('should handle tld test ' + (i + 1), function (done) {
+
+            expect(isEmail(email, {
+                errorLevel: 0,
+                tldWhitelist: {
+                    com: true
+                }
+            })).to.equal(result);
+
+            expect(isEmail(email, {
+                errorLevel: 0,
+                tldWhitelist: ['com']
+            })).to.equal(result);
+
+            done();
+        });
+    });
+
+    it('should handle domain atom test 1', function (done) {
+
+        expect(isEmail('shouldbe@invalid', {
+            errorLevel: 0,
+            minDomainAtoms: 2
+        })).to.equal(diag.errDomainTooShort);
+
+        done();
+    });
+
+    it('should handle domain atom test 2', function (done) {
+
+        expect(isEmail('valid@example.com', {
+            errorLevel: 0,
+            minDomainAtoms: 2
+        })).to.equal(diag.valid);
+
+        done();
+    });
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/test/mocha.opts b/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/test/mocha.opts
new file mode 100644
index 0000000000000000000000000000000000000000..270053104b55a760eed90d5c255b8ed27a1d9df3
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/test/mocha.opts
@@ -0,0 +1,2 @@
+--reporter dot
+--check-leaks
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/test/tests.json b/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/test/tests.json
new file mode 100644
index 0000000000000000000000000000000000000000..e710b893dca88f1586c628c0a276288715650b06
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/isemail/test/tests.json
@@ -0,0 +1,187 @@
+[
+    ["", "errNoDomain"],
+    ["\r", "errCRNoLF"],
+    ["test", "errNoDomain"],
+    ["@", "errNoLocalPart"],
+    ["test@", "errNoDomain"],
+    ["test@io", "valid"],
+    ["@io", "errNoLocalPart"],
+    ["@iana.org", "errNoLocalPart"],
+    ["test@iana.org", "valid"],
+    ["test@nominet.org.uk", "valid"],
+    ["test@about.museum", "valid"],
+    ["a@iana.org", "valid"],
+    ["test@e.com", "dnsWarnNoRecord"],
+    ["test@iana.a", "dnsWarnNoRecord"],
+    ["test.test@iana.org", "valid"],
+    [".test@iana.org", "errDotStart"],
+    ["test.@iana.org", "errDotEnd"],
+    ["test..iana.org", "errConsecutiveDots"],
+    ["test_exa-mple.com", "errNoDomain"],
+    ["!#$%&`*+/=?^`{|}~@iana.org", "valid"],
+    ["test\\@test@iana.org", "errExpectingATEXT"],
+    ["123@iana.org", "valid"],
+    ["test@123.com", "valid"],
+    ["test@iana.123", "rfc5321TLDNumeric"],
+    ["test@255.255.255.255", "rfc5321TLDNumeric"],
+    ["abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm@iana.org", "valid"],
+    ["abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklmn@iana.org", "rfc5322LocalTooLong"],
+    ["test@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm", "rfc5322LabelTooLong"],
+    ["test@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.com", "dnsWarnNoRecord"],
+    ["test@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm.com", "rfc5322LabelTooLong"],
+    ["test@mason-dixon.com", "valid"],
+    ["test@-iana.org", "errDomainHyphenStart"],
+    ["test@iana-.com", "errDomainHyphenEnd"],
+    ["test@iana.co-uk", "dnsWarnNoRecord"],
+    ["test@.iana.org", "errDotStart"],
+    ["test@iana.org.", "errDotEnd"],
+    ["test@iana..com", "errConsecutiveDots"],
+    ["a@a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v", "dnsWarnNoRecord"],
+    ["abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghi", "dnsWarnNoRecord"],
+    ["abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghij", "rfc5322TooLong"],
+    ["a@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.hij", "rfc5322TooLong"],
+    ["a@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.hijk", "rfc5322DomainTooLong"],
+    ["\"\r", "errCRNoLF"],
+    ["\"test\"@iana.org", "rfc5321QuotedString"],
+    ["\"\"@iana.org", "rfc5321QuotedString"],
+    ["\"\"\"@iana.org", "errExpectingATEXT"],
+    ["\"\\a\"@iana.org", "rfc5321QuotedString"],
+    ["\"\\\"\"@iana.org", "rfc5321QuotedString"],
+    ["\"\\\"@iana.org", "errUnclosedQuotedString"],
+    ["\"\\\\\"@iana.org", "rfc5321QuotedString"],
+    ["test\"@iana.org", "errExpectingATEXT"],
+    ["\"test@iana.org", "errUnclosedQuotedString"],
+    ["\"test\"test@iana.org", "errATEXTAfterQS"],
+    ["test\"text\"@iana.org", "errExpectingATEXT"],
+    ["\"test\"\"test\"@iana.org", "errExpectingATEXT"],
+    ["\"test\".\"test\"@iana.org", "deprecatedLocalPart"],
+    ["\"test\\ test\"@iana.org", "rfc5321QuotedString"],
+    ["\"test\".test@iana.org", "deprecatedLocalPart"],
+    ["\"test\u0000\"@iana.org", "errExpectingQTEXT"],
+    ["\"test\\\u0000\"@iana.org", "deprecatedQP"],
+    ["\"test\r\n test\"@iana.org", "cfwsFWS"],
+    ["\"abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz abcdefghj\"@iana.org", "rfc5322LocalTooLong"],
+    ["\"abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz abcdefg\\h\"@iana.org", "rfc5322LocalTooLong"],
+    ["test@[255.255.255.255]", "rfc5321AddressLiteral"],
+    ["test@a[255.255.255.255]", "errExpectingATEXT"],
+    ["test@[255.255.255]", "rfc5322DomainLiteral"],
+    ["test@[255.255.255.255.255]", "rfc5322DomainLiteral"],
+    ["test@[255.255.255.256]", "rfc5322DomainLiteral"],
+    ["test@[1111:2222:3333:4444:5555:6666:7777:8888]", "rfc5322DomainLiteral"],
+    ["test@[IPv6:1111:2222:3333:4444:5555:6666:7777]", "rfc5322IPv6GroupCount"],
+    ["test@[IPv6:1111:2222:3333:4444:5555:6666:7777:8888]", "rfc5321AddressLiteral"],
+    ["test@[IPv6:1111:2222:3333:4444:5555:6666:7777:8888:9999]", "rfc5322IPv6GroupCount"],
+    ["test@[IPv6:1111:2222:3333:4444:5555:6666:7777:888G]", "rfc5322IPv6BadCharacter"],
+    ["test@[IPv6:1111:2222:3333:4444:5555:6666::8888]", "deprecatedIPv6"],
+    ["test@[IPv6:1111:2222:3333:4444:5555::8888]", "rfc5321AddressLiteral"],
+    ["test@[IPv6:1111:2222:3333:4444:5555:6666::7777:8888]", "rfc5322IPv6MaxGroups"],
+    ["test@[IPv6::3333:4444:5555:6666:7777:8888]", "rfc5322IPv6ColonStart"],
+    ["test@[IPv6:::3333:4444:5555:6666:7777:8888]", "rfc5321AddressLiteral"],
+    ["test@[IPv6:1111::4444:5555::8888]", "rfc5322IPv62x2xColon"],
+    ["test@[IPv6:::]", "rfc5321AddressLiteral"],
+    ["test@[IPv6:1111:2222:3333:4444:5555:255.255.255.255]", "rfc5322IPv6GroupCount"],
+    ["test@[IPv6:1111:2222:3333:4444:5555:6666:255.255.255.255]", "rfc5321AddressLiteral"],
+    ["test@[IPv6:1111:2222:3333:4444:5555:6666:7777:255.255.255.255]", "rfc5322IPv6GroupCount"],
+    ["test@[IPv6:1111:2222:3333:4444::255.255.255.255]", "rfc5321AddressLiteral"],
+    ["test@[IPv6:1111:2222:3333:4444:5555:6666::255.255.255.255]", "rfc5322IPv6MaxGroups"],
+    ["test@[IPv6:1111:2222:3333:4444:::255.255.255.255]", "rfc5322IPv62x2xColon"],
+    ["test@[IPv6::255.255.255.255]", "rfc5322IPv6ColonStart"],
+    [" test @iana.org", "deprecatedCFWSNearAt"],
+    ["test@ iana .com", "deprecatedCFWSNearAt"],
+    ["test . test@iana.org", "deprecatedFWS"],
+    ["\r\n test@iana.org", "cfwsFWS"],
+    ["\r\n \r\n test@iana.org", "deprecatedFWS"],
+    ["(\r", "errCRNoLF"],
+    ["(comment)test@iana.org", "cfwsComment"],
+    ["((comment)test@iana.org", "errUnclosedComment"],
+    ["(comment(comment))test@iana.org", "cfwsComment"],
+    ["test@(comment)iana.org", "deprecatedCFWSNearAt"],
+    ["test(comment)@iana.org", "deprecatedCFWSNearAt"],
+    ["test(comment)test@iana.org", "errATEXTAfterCFWS"],
+    ["test@(comment)[255.255.255.255]", "deprecatedCFWSNearAt"],
+    ["(comment)abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm@iana.org", "cfwsComment"],
+    ["test@(comment)abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.com", "deprecatedCFWSNearAt"],
+    ["(comment)test@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghik.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghik.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.abcdefghijklmnopqrstuvwxyzabcdefghijk.abcdefghijklmnopqrstu", "cfwsComment"],
+    ["test@iana.org\n", "errExpectingATEXT"],
+    ["test@xn--hxajbheg2az3al.xn--jxalpdlp", "dnsWarnNoRecord"],
+    ["xn--test@iana.org", "valid"],
+    ["test@iana.org-", "errDomainHyphenEnd"],
+    ["\"test@iana.org", "errUnclosedQuotedString"],
+    ["(test@iana.org", "errUnclosedComment"],
+    ["test@(iana.org", "errUnclosedComment"],
+    ["test@[1.2.3.4", "errUnclosedDomainLiteral"],
+    ["\"test\\\"@iana.org", "errUnclosedQuotedString"],
+    ["(comment\\)test@iana.org", "errUnclosedComment"],
+    ["test@iana.org(comment\\)", "errUnclosedComment"],
+    ["test@iana.org(comment\\", "errBackslashEnd"],
+    ["test@[RFC-5322-domain-literal]", "rfc5322DomainLiteral"],
+    ["test@[RFC-5322]-domain-literal]", "errATEXTAfterDomainLiteral"],
+    ["test@[RFC-5322-[domain-literal]", "errExpectingDTEXT"],
+    ["test@[€", "errExpectingDTEXT"],
+    ["test@[\u0007]", "rfc5322DomainLiteralOBSDText"],
+    ["test@[RFC-5322-\\\u0007-domain-literal]", "rfc5322DomainLiteralOBSDText"],
+    ["test@[RFC-5322-\\\t-domain-literal]", "rfc5322DomainLiteralOBSDText"],
+    ["test@[RFC-5322-\\]-domain-literal]", "rfc5322DomainLiteralOBSDText"],
+    ["test@[RFC-5322--domain-literal]", "rfc5322DomainLiteralOBSDText"],
+    ["test@[RFC-5322-domain-literal\\]", "errUnclosedDomainLiteral"],
+    ["test@[RFC-5322-domain-literal\\", "errBackslashEnd"],
+    ["test@[RFC 5322 domain literal]", "rfc5322DomainLiteral"],
+    ["test@[RFC-5322-domain-literal] (comment)", "rfc5322DomainLiteral"],
+    ["@iana.org", "errExpectingATEXT"],
+    ["test@.org", "errExpectingATEXT"],
+    ["\"\"@iana.org", "deprecatedQTEXT"],
+    ["\"€\"@iana.org", "errExpectingQTEXT"],
+    ["\"\\\"@iana.org", "deprecatedQP"],
+    ["()test@iana.org", "deprecatedCTEXT"],
+    ["(€)test@iana.org", "errExpectingCTEXT"],
+    ["test@iana.org\r", "errCRNoLF"],
+    ["\rtest@iana.org", "errCRNoLF"],
+    ["\"\rtest\"@iana.org", "errCRNoLF"],
+    ["(\r)test@iana.org", "errCRNoLF"],
+    ["test@iana.org(\r)", "errCRNoLF"],
+    ["\ntest@iana.org", "errExpectingATEXT"],
+    ["\"\n\"@iana.org", "errExpectingQTEXT"],
+    ["\"\\\n\"@iana.org", "deprecatedQP"],
+    ["(\n)test@iana.org", "errExpectingCTEXT"],
+    ["\u0007@iana.org", "errExpectingATEXT"],
+    ["test@\u0007.org", "errExpectingATEXT"],
+    ["\"\u0007\"@iana.org", "deprecatedQTEXT"],
+    ["\"\\\u0007\"@iana.org", "deprecatedQP"],
+    ["(\u0007)test@iana.org", "deprecatedCTEXT"],
+    ["\r\ntest@iana.org", "errFWSCRLFEnd"],
+    ["\r\n \r\ntest@iana.org", "errFWSCRLFEnd"],
+    [" \r\ntest@iana.org", "errFWSCRLFEnd"],
+    [" \r\n test@iana.org", "cfwsFWS"],
+    [" \r\n \r\ntest@iana.org", "errFWSCRLFEnd"],
+    [" \r\n\r\ntest@iana.org", "errFWSCRLFx2"],
+    [" \r\n\r\n test@iana.org", "errFWSCRLFx2"],
+    ["test@iana.org\r\n ", "cfwsFWS"],
+    ["test@iana.org\r\n \r\n ", "deprecatedFWS"],
+    ["test@iana.org\r\n", "errFWSCRLFEnd"],
+    ["test@iana.org \r", "errCRNoLF"],
+    ["test@iana.org\r\n \r\n", "errFWSCRLFEnd"],
+    ["test@iana.org \r\n", "errFWSCRLFEnd"],
+    ["test@iana.org \r\n ", "cfwsFWS"],
+    ["test@iana.org \r\n \r\n", "errFWSCRLFEnd"],
+    ["test@iana.org \r\n\r\n", "errFWSCRLFx2"],
+    ["test@iana.org \r\n\r\n ", "errFWSCRLFx2"],
+    ["test@iana. org", "deprecatedFWS"],
+    ["test@[\r", "errCRNoLF"],
+    ["test@[\r\n", "errFWSCRLFEnd"],
+    [" test@iana.org", "cfwsFWS"],
+    ["test@iana.org ", "cfwsFWS"],
+    ["test@[IPv6:1::2:]", "rfc5322IPv6ColonEnd"],
+    ["\"test\\©\"@iana.org", "errExpectingQPair"],
+    ["test@iana/icann.org", "rfc5322Domain"],
+    ["test@iana!icann.org", "rfc5322Domain"],
+    ["test@iana?icann.org", "rfc5322Domain"],
+    ["test@iana^icann.org", "rfc5322Domain"],
+    ["test@iana{icann}.org", "rfc5322Domain"],
+    ["test.(comment)test@iana.org", "deprecatedComment"],
+    ["test@iana.(comment)org", "deprecatedComment"],
+    ["test@iana(comment)iana.org", "errATEXTAfterCFWS"],
+    ["(comment\r\n comment)test@iana.org", "cfwsFWS"],
+    ["test@org", "rfc5321TLD"],
+    ["test@example.com", "dnsWarnNoMXRecord"],
+    ["test@nic.no", "dnsWarnNoRecord"]
+]
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/.eslintignore b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/.eslintignore
new file mode 100644
index 0000000000000000000000000000000000000000..e4acc6a03b89a0923ea682381d1499e4d8a5b9fb
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/.eslintignore
@@ -0,0 +1,2 @@
+examples
+sandbox.js
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/.npmignore b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/.npmignore
new file mode 100644
index 0000000000000000000000000000000000000000..20fb4d8a62360856ddaefdfbef420469ff1058e7
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/.npmignore
@@ -0,0 +1,21 @@
+.c9
+.idea
+.project
+*.iml
+npm-debug.log
+dump.rdb
+node_modules
+results.tap
+results.xml
+npm-shrinkwrap.json
+config.json
+.DS_Store
+*/.DS_Store
+*/*/.DS_Store
+._*
+*/._*
+*/*/._*
+coverage.*
+lib-cov
+complexity.md
+sandbox.js
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/.travis.yml b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/.travis.yml
new file mode 100755
index 0000000000000000000000000000000000000000..009a025dae9b0bf3d4f510fdcdd79410151d0e2e
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/.travis.yml
@@ -0,0 +1,9 @@
+language: node_js
+
+node_js:
+  - "0.10"
+  - "4.0"
+  - "4"
+  - "5"
+
+sudo: false
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/API.md b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/API.md
new file mode 100755
index 0000000000000000000000000000000000000000..994c17efcf7f0b261d6495ecfe3d4d88180f32c1
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/API.md
@@ -0,0 +1,1515 @@
+<!-- version -->
+# 6.10.1 API Reference
+<!-- versionstop -->
+
+<img src="https://raw.github.com/hapijs/joi/master/images/validation.png" align="right" />
+
+<!-- toc -->
+
+- [Joi](#joi)
+  - [`validate(value, schema, [options], [callback])`](#validatevalue-schema-options-callback)
+  - [`compile(schema)`](#compileschema)
+  - [`assert(value, schema, [message])`](#assertvalue-schema-message)
+  - [`attempt(value, schema, [message])`](#attemptvalue-schema-message)
+  - [`isRef(ref)`](#isrefref)
+  - [`any`](#any)
+    - [`any.allow(value)`](#anyallowvalue)
+    - [`any.valid(value)` - aliases: `only`, `equal`](#anyvalidvalue---aliases-only-equal)
+    - [`any.invalid(value)` - aliases: `disallow`, `not`](#anyinvalidvalue---aliases-disallow-not)
+    - [`any.required()`](#anyrequired)
+    - [`any.optional()`](#anyoptional)
+    - [`any.forbidden()`](#anyforbidden)
+    - [`any.strip()`](#anystrip)
+    - [`any.description(desc)`](#anydescriptiondesc)
+    - [`any.notes(notes)`](#anynotesnotes)
+    - [`any.tags(tags)`](#anytagstags)
+    - [`any.meta(meta)`](#anymetameta)
+    - [`any.example(value)`](#anyexamplevalue)
+    - [`any.unit(name)`](#anyunitname)
+    - [`any.options(options)`](#anyoptionsoptions)
+    - [`any.strict(isStrict)`](#anystrictisstrict)
+    - [`any.default([value, [description]])`](#anydefaultvalue-description)
+    - [`any.concat(schema)`](#anyconcatschema)
+    - [`any.when(ref, options)`](#anywhenref-options)
+    - [`any.label(name)`](#anylabelname)
+    - [`any.raw(isRaw)`](#anyrawisraw)
+    - [`any.empty(schema)`](#anyemptyschema)
+  - [`array`](#array)
+    - [`array.sparse(enabled)`](#arraysparseenabled)
+    - [`array.single(enabled)`](#arraysingleenabled)
+    - [`array.items(type)`](#arrayitemstype)
+    - [`array.ordered(type)`](#arrayorderedtype)
+    - [`array.min(limit)`](#arrayminlimit)
+    - [`array.max(limit)`](#arraymaxlimit)
+    - [`array.length(limit)`](#arraylengthlimit)
+    - [`array.unique()`](#arrayunique)
+  - [`boolean`](#boolean)
+  - [`binary`](#binary)
+    - [`binary.encoding(encoding)`](#binaryencodingencoding)
+    - [`binary.min(limit)`](#binaryminlimit)
+    - [`binary.max(limit)`](#binarymaxlimit)
+    - [`binary.length(limit)`](#binarylengthlimit)
+  - [`date`](#date)
+    - [`date.min(date)`](#datemindate)
+    - [`date.max(date)`](#datemaxdate)
+    - [`date.format(format)`](#dateformatformat)
+    - [`date.iso()`](#dateiso)
+  - [`func`](#func)
+  - [`number`](#number)
+    - [`number.min(limit)`](#numberminlimit)
+    - [`number.max(limit)`](#numbermaxlimit)
+    - [`number.greater(limit)`](#numbergreaterlimit)
+    - [`number.less(limit)`](#numberlesslimit)
+    - [`number.integer()`](#numberinteger)
+    - [`number.precision(limit)`](#numberprecisionlimit)
+    - [`number.multiple(base)`](#numbermultiplebase)
+    - [`number.positive()`](#numberpositive)
+    - [`number.negative()`](#numbernegative)
+  - [`object`](#object)
+    - [`object.keys([schema])`](#objectkeysschema)
+      - [`{} notation`](#-notation)
+      - [`Joi.object([schema]) notation`](#joiobjectschema-notation)
+      - [`Joi.object().keys([schema]) notation`](#joiobjectkeysschema-notation)
+    - [`object.min(limit)`](#objectminlimit)
+    - [`object.max(limit)`](#objectmaxlimit)
+    - [`object.length(limit)`](#objectlengthlimit)
+    - [`object.pattern(regex, schema)`](#objectpatternregex-schema)
+    - [`object.and(peers)`](#objectandpeers)
+    - [`object.nand(peers)`](#objectnandpeers)
+    - [`object.or(peers)`](#objectorpeers)
+    - [`object.xor(peers)`](#objectxorpeers)
+    - [`object.with(key, peers)`](#objectwithkey-peers)
+    - [`object.without(key, peers)`](#objectwithoutkey-peers)
+    - [`object.rename(from, to, [options])`](#objectrenamefrom-to-options)
+    - [`object.assert(ref, schema, [message])`](#objectassertref-schema-message)
+    - [`object.unknown([allow])`](#objectunknownallow)
+    - [`object.type(constructor, [name])`](#objecttypeconstructor-name)
+    - [`object.requiredKeys(children)`](#objectrequiredkeyschildren)
+    - [`object.optionalKeys(children)`](#objectoptionalkeyschildren)
+  - [`string`](#string)
+    - [`string.insensitive()`](#stringinsensitive)
+    - [`string.min(limit, [encoding])`](#stringminlimit-encoding)
+    - [`string.max(limit, [encoding])`](#stringmaxlimit-encoding)
+    - [`string.creditCard()`](#stringcreditcard)
+    - [`string.length(limit, [encoding])`](#stringlengthlimit-encoding)
+    - [`string.regex(pattern, [name])`](#stringregexpattern-name)
+    - [`string.replace(pattern, replacement)`](#stringreplacepattern-replacement)
+    - [`string.alphanum()`](#stringalphanum)
+    - [`string.token()`](#stringtoken)
+    - [`string.email([options])`](#stringemailoptions)
+    - [`string.ip([options])`](#stringipoptions)
+    - [`string.uri([options])`](#stringurioptions)
+    - [`string.guid()`](#stringguid)
+    - [`string.hex()`](#stringhex)
+    - [`string.hostname()`](#stringhostname)
+    - [`string.lowercase()`](#stringlowercase)
+    - [`string.uppercase()`](#stringuppercase)
+    - [`string.trim()`](#stringtrim)
+    - [`string.isoDate()`](#stringisodate)
+  - [`alternatives`](#alternatives)
+    - [`alternatives.try(schemas)`](#alternativestryschemas)
+    - [`alternatives.when(ref, options)`](#alternativeswhenref-options)
+  - [`ref(key, [options])`](#refkey-options)
+- [Errors](#errors)
+
+<!-- tocstop -->
+
+## Joi
+
+### `validate(value, schema, [options], [callback])`
+
+Validates a value using the given schema and options where:
+- `value` - the value being validated.
+- `schema` - the validation schema. Can be a **joi** type object or a plain object where every key is assigned a **joi** type object.
+- `options` - an optional object with the following optional keys:
+  - `abortEarly` - when `true`, stops validation on the first error, otherwise returns all the errors found. Defaults to `true`.
+  - `convert` - when `true`, attempts to cast values to the required types (e.g. a string to a number). Defaults to `true`.
+  - `allowUnknown` - when `true`, allows object to contain unknown keys which are ignored. Defaults to `false`.
+  - `skipFunctions` - when `true`, ignores unknown keys with a function value. Defaults to `false`.
+  - `stripUnknown` - when `true`, unknown keys are deleted (only when value is an object or an array). Defaults to `false`.
+  - `language` - overrides individual error messages, when `'label'` is set, it overrides the key name in the error message. Defaults to no override (`{}`).
+  - `presence` - sets the default presence requirements. Supported modes: `'optional'`, `'required'`, and `'forbidden'`.
+    Defaults to `'optional'`.
+  - `context` - provides an external data set to be used in [references](#refkey-options). Can only be set as an external option to
+    `validate()` and not using `any.options()`.
+  - `noDefaults` - when `true`, do not apply default values. Defaults to `false`.
+- `callback` - the optional synchronous callback method using the signature `function(err, value)` where:
+  - `err` - if validation failed, the [error](#errors) reason, otherwise `null`.
+  - `value` - the validated value with any type conversions and other modifiers applied (the input is left unchanged). `value` can be
+    incomplete if validation failed and `abortEarly` is `true`. If callback is not provided, then returns an object with [error](#errors)
+    and value properties.
+
+```javascript
+var schema = {
+    a: Joi.number()
+};
+
+var value = {
+    a: '123'
+};
+
+Joi.validate(value, schema, function (err, value) { });
+// err -> null
+// value.a -> 123 (number, not string)
+
+// or
+var result = Joi.validate(value, schema);
+// result.error -> null
+// result.value -> { "a" : 123 }
+```
+
+### `compile(schema)`
+
+Converts literal schema definition to **joi** schema object (or returns the same back if already a **joi** schema object) where:
+- `schema` - the schema definition to compile.
+
+```javascript
+var definition = ['key', 5, { a: true, b: [/^a/, 'boom'] }];
+var schema = Joi.compile(definition);
+
+// Same as:
+
+var schema = Joi.alternatives().try([
+    Joi.string().valid('key'),
+    Joi.number().valid(5),
+    Joi.object().keys({
+        a: Joi.boolean().valid(true),
+        b: Joi.alternatives().try([
+            Joi.string().regex(/^a/),
+            Joi.string().valid('boom')
+        ])
+    })
+]);
+```
+
+### `assert(value, schema, [message])`
+
+Validates a value against a schema and [throws](#errors) if validation fails where:
+- `value` - the value to validate.
+- `schema` - the schema object.
+- `message` - optional message string prefix added in front of the error message. may also be an Error object.
+
+```javascript
+Joi.assert('x', Joi.number());
+```
+
+### `attempt(value, schema, [message])`
+
+Validates a value against a schema, returns valid object, and [throws](#errors) if validation fails where:
+- `value` - the value to validate.
+- `schema` - the schema object.
+- `message` - optional message string prefix added in front of the error message. may also be an Error object.
+
+```javascript
+Joi.attempt('x', Joi.number()); // throws error
+var result = Joi.attempt('4', Joi.number()); // result -> 4
+```
+
+### `isRef(ref)`
+
+Checks whether or not the provided argument is a reference.
+It's especially useful if you want to post-process error messages.
+
+```js
+var ref = Joi.ref('a');
+Joi.isRef(ref); // returns true
+```
+
+### `any`
+
+Generates a schema object that matches any data type.
+
+```javascript
+var any = Joi.any();
+any.validate('a', function (err, value) { });
+```
+
+#### `any.allow(value)`
+
+Whitelists a value where:
+- `value` - the allowed value which can be of any type and will be matched against the validated value before applying any other rules.
+  `value` can be an array of values, or multiple values can be passed as individual arguments. `value` supports [references](#refkey-options).
+
+Note that this whitelist of allowed values is in *addition* to any other permitted values.
+To create an exclusive whitelist of values, see [`any.valid(value)`](#anyvalidvalue).
+
+```javascript
+var schema = {
+    a: Joi.any().allow('a'),
+    b: Joi.any().allow('b', 'B'),
+    c: Joi.any().allow(['c', 'C'])
+};
+```
+
+#### `any.valid(value)` - aliases: `only`, `equal`
+
+Adds the provided values into the allowed whitelist and marks them as the only valid values allowed where:
+- `value` - the allowed value which can be of any type and will be matched against the validated value before applying any other rules.
+  `value` can be an array of values, or multiple values can be passed as individual arguments. `value` supports [references](#refkey-options).
+
+```javascript
+var schema = {
+    a: Joi.any().valid('a'),
+    b: Joi.any().valid('b', 'B'),
+    c: Joi.any().valid(['c', 'C'])
+};
+```
+
+#### `any.invalid(value)` - aliases: `disallow`, `not`
+
+Blacklists a value where:
+- `value` - the forbidden value which can be of any type and will be matched against the validated value before applying any other rules.
+  `value` can be an array of values, or multiple values can be passed as individual arguments. `value` supports [references](#refkey-options).
+
+```javascript
+var schema = {
+    a: Joi.any().invalid('a'),
+    b: Joi.any().invalid('b', 'B'),
+    c: Joi.any().invalid(['c', 'C'])
+};
+```
+
+#### `any.required()`
+
+Marks a key as required which will not allow `undefined` as value. All keys are optional by default.
+
+```javascript
+var schema = Joi.any().required();
+```
+
+#### `any.optional()`
+
+Marks a key as optional which will allow `undefined` as values. Used to annotate the schema for readability as all keys are optional by default.
+
+```javascript
+var schema = Joi.any().optional();
+```
+
+#### `any.forbidden()`
+
+Marks a key as forbidden which will not allow any value except `undefined`. Used to explicitly forbid keys.
+
+```javascript
+var schema = {
+    a: Joi.any().forbidden()
+};
+```
+
+#### `any.strip()`
+
+Marks a key to be removed from a resulting object or array after validation. Used to sanitize output.
+
+```javascript
+var schema = {
+    username: Joi.string(),
+    password: Joi.string().strip()
+};
+
+schema.validate({ username: 'test', password: 'hunter2' }, function (err, value) {
+    // value = { username: 'test' }
+});
+
+var schema = Joi.array().items(Joi.string(), Joi.any().strip());
+
+schema.validate(['one', 'two', true, false, 1, 2], function (err, value) {
+    // value = ['one', 'two']
+});
+```
+
+#### `any.description(desc)`
+
+Annotates the key where:
+- `desc` - the description string.
+
+```javascript
+var schema = Joi.any().description('this key will match anything you give it');
+```
+
+#### `any.notes(notes)`
+
+Annotates the key where:
+- `notes` - the notes string or array of strings.
+
+```javascript
+var schema = Joi.any().notes(['this is special', 'this is important']);
+```
+
+#### `any.tags(tags)`
+
+Annotates the key where:
+- `tags` - the tag string or array of strings.
+
+```javascript
+var schema = Joi.any().tags(['api', 'user']);
+```
+
+#### `any.meta(meta)`
+
+Attaches metadata to the key where:
+- `meta` - the meta object to attach.
+
+```javascript
+var schema = Joi.any().meta({ index: true });
+```
+
+#### `any.example(value)`
+
+Annotates the key where:
+- `value` - an example value.
+
+If the example fails to pass validation, the function will throw.
+
+```javascript
+var schema = Joi.string().min(4).example('abcd');
+```
+
+#### `any.unit(name)`
+
+Annotates the key where:
+- `name` - the unit name of the value.
+
+```javascript
+var schema = Joi.number().unit('milliseconds');
+```
+
+#### `any.options(options)`
+
+Overrides the global `validate()` options for the current key and any sub-key where:
+- `options` - an object with the same optional keys as [`Joi.validate(value, schema, options, callback)`](#validatevalue-schema-options-callback).
+
+```javascript
+var schema = Joi.any().options({ convert: false });
+```
+
+#### `any.strict(isStrict)`
+
+Strict mode sets the `options.convert` options to `false` which prevent type casting for the current key and any child keys.
+- `isStrict` - whether strict mode is enabled or not. Defaults to true.
+
+```javascript
+var schema = Joi.any().strict();
+```
+
+#### `any.default([value, [description]])`
+
+Sets a default value if the original value is undefined where:
+- `value` - the value.
+  - `value` supports [references](#refkey-options).
+  - `value` may also be a function which returns the default value. If `value` is specified as a function that accepts a single parameter, that parameter will be a context object that can be used to derive the resulting value. **This clones the object however, which incurs some overhead so if you don't need access to the context define your method so that it does not accept any parameters**.
+  - without any `value`, `default` has no effect, except for `object` that will then create nested defaults (applying inner defaults of that object).
+
+Note that if `value` is an object, any changes to the object after `default()` is called will change the reference
+and any future assignment.
+
+Additionally, when specifying a method you must either have a `description` property on your method or the second parameter is required.
+
+```javascript
+var generateUsername = function (context) {
+
+  return context.firstname.toLowerCase() + '-' + context.lastname.toLowerCase();
+};
+generateUsername.description = 'generated username';
+
+var schema = {
+    username: Joi.string().default(generateUsername),
+    firstname: Joi.string(),
+    lastname: Joi.string(),
+    created: Joi.date().default(Date.now, 'time of creation'),
+    status: Joi.string().default('registered')
+};
+
+Joi.validate({
+    firstname: 'Jane',
+    lastname: 'Doe'
+}, schema, function (err, value) {
+
+    // value.status === 'registered'
+    // value.username === 'jane-doe'
+    // value.created will be the time of validation
+});
+```
+
+#### `any.concat(schema)`
+
+Returns a new type that is the result of adding the rules of one type to another where:
+- `schema` - a **joi** type to merge into the current schema. Can only be of the same type as the context type or `any`. If applied to an `any` type, the schema can be any other schema.
+
+```javascript
+var a = Joi.string().valid('a');
+var b = Joi.string().valid('b');
+var ab = a.concat(b);
+```
+
+#### `any.when(ref, options)`
+
+Converts the type into an [`alternatives`](#alternatives) type where the conditions are merged into the type definition where:
+- `ref` - the key name or [reference](#refkey-options).
+- `options` - an object with:
+    - `is` - the required condition **joi** type.
+    - `then` - the alternative schema type if the condition is true. Required if `otherwise` is missing.
+    - `otherwise` - the alternative schema type if the condition is false. Required if `then` is missing.
+
+```javascript
+var schema = {
+    a: Joi.any().valid('x').when('b', { is: 5, then: Joi.valid('y'), otherwise: Joi.valid('z') }),
+    b: Joi.any()
+};
+```
+
+Alternatively, if you want to specify a specific type such as `string`, `array`, etc, you can do so like this:
+
+```javascript
+var schema = {
+    a: Joi.valid('a', 'b', 'other'),
+    other: Joi.string()
+        .when('a', { is: 'other', then: Joi.required() }),
+};
+```
+
+#### `any.label(name)`
+
+Overrides the key name in error messages.
+- `name` - the name of the key.
+
+```javascript
+var schema = {
+    first_name: Joi.string().label('First Name')
+};
+```
+
+#### `any.raw(isRaw)`
+
+Outputs the original untouched value instead of the casted value.
+- `isRaw` - whether to enable raw mode or not. Defaults to true.
+
+```javascript
+var schema = {
+    timestamp: Joi.date().format('YYYYMMDD').raw()
+};
+```
+
+#### `any.empty(schema)`
+
+Considers anything that matches the schema to be empty (`undefined`).
+- `schema` - any object or joi schema to match. An undefined schema unsets that rule.
+
+```js
+var schema = Joi.string().empty('');
+schema.validate(''); // returns { error: null, value: undefined }
+schema = schema.empty();
+schema.validate(''); // returns { error: "value" is not allowed to be empty, value: '' }
+```
+
+### `array`
+
+Generates a schema object that matches an array data type. Note that undefined values inside arrays are not allowed by default but can be by using `sparse()`.
+
+Supports the same methods of the [`any()`](#any) type.
+
+```javascript
+var array = Joi.array().items(Joi.string().valid('a', 'b'));
+array.validate(['a', 'b', 'a'], function (err, value) { });
+```
+
+#### `array.sparse(enabled)`
+
+Allow this array to be sparse. `enabled` can be used with a falsy value to go back to the default behavior.
+
+```javascript
+var schema = Joi.array().sparse(); // undefined values are now allowed
+schema = schema.sparse(false); // undefined values are now denied
+```
+
+#### `array.single(enabled)`
+
+Allow single values to be checked against rules as if it were provided as an array.
+
+`enabled` can be used with a falsy value to go back to the default behavior.
+
+```javascript
+var schema = Joi.array().items(Joi.number()).single();
+schema.validate([4]); // returns `{ error: null, value: [ 4 ] }`
+schema.validate(4); // returns `{ error: null, value: [ 4 ] }`
+```
+
+#### `array.items(type)`
+
+List the types allowed for the array values where:
+- `type` - a **joi** schema object to validate each array item against. `type` can be an array of values, or multiple values can be passed as individual arguments.
+
+If a given type is `.required()` then there must be a matching item in the array.
+If a type is `.forbidden()` then it cannot appear in the array.
+Required items can be added multiple times to signify that multiple items must be found.
+Errors will contain the number of items that didn't match. Any unmatched item having a [label](#anylabelname) will be mentioned explicitly.
+
+```javascript
+var schema = Joi.array().items(Joi.string(), Joi.number()); // array may contain strings and numbers
+var schema = Joi.array().items(Joi.string().required(), Joi.string().required()); // array must contain at least two strings
+var schema = Joi.array().items(Joi.string().valid('not allowed').forbidden(), Joi.string()); // array may contain strings, but none of those strings can match 'not allowed'
+var schema = Joi.array().items(Joi.string().label('My string').required(), Joi.number().required()); // If this fails it can result in `[ValidationError: "value" does not contain [My string] and 1 other required value(s)]`
+```
+
+#### `array.ordered(type)`
+
+List the types in sequence order for the array values where:
+- `type` - a **joi** schema object to validate against each array item in sequence order. `type` can be an array of values, or multiple values can be passed as individual arguments.
+
+If a given type is `.required()` then there must be a matching item with the same index position in the array.
+Errors will contain the number of items that didn't match. Any unmatched item having a [label](#anylabelname) will be mentioned explicitly.
+
+```javascript
+var schema = Joi.array().ordered(Joi.string().required(), Joi.number().required()); // array must have first item as string and second item as number
+var schema = Joi.array().ordered(Joi.string().required()).items(Joi.number().required()); // array must have first item as string and 1 or more subsequent items as number
+var schema = Joi.array().ordered(Joi.string().required(), Joi.number()); // array must have first item as string and optionally second item as number
+```
+
+#### `array.min(limit)`
+
+Specifies the minimum number of items in the array where:
+- `limit` - the lowest number of array items allowed.
+
+```javascript
+var schema = Joi.array().min(2);
+```
+
+#### `array.max(limit)`
+
+Specifies the maximum number of items in the array where:
+- `limit` - the highest number of array items allowed.
+
+```javascript
+var schema = Joi.array().max(10);
+```
+
+#### `array.length(limit)`
+
+Specifies the exact number of items in the array where:
+- `limit` - the number of array items allowed.
+
+```javascript
+var schema = Joi.array().length(5);
+```
+
+#### `array.unique()`
+
+Requires the array values to be unique.
+
+Be aware that a deep equality is performed on elements of the array having a type of `object`, a performance penalty is to be expected for this kind of operation.
+
+```javascript
+var schema = Joi.array().unique();
+```
+
+### `boolean`
+
+Generates a schema object that matches a boolean data type (as well as the strings 'true', 'false', 'yes', 'no', 'on' or 'off'). Can also be called via `bool()`.
+
+Supports the same methods of the [`any()`](#any) type.
+
+```javascript
+var boolean = Joi.boolean();
+boolean.validate(true, function (err, value) { });
+```
+
+### `binary`
+
+Generates a schema object that matches a Buffer data type (as well as the strings which will be converted to Buffers).
+
+Supports the same methods of the [`any()`](#any) type.
+
+```javascript
+var schema = Joi.binary();
+```
+
+#### `binary.encoding(encoding)`
+
+Sets the string encoding format if a string input is converted to a buffer where:
+- `encoding` - the encoding scheme.
+
+```javascript
+var schema = Joi.binary().encoding('base64');
+```
+
+#### `binary.min(limit)`
+
+Specifies the minimum length of the buffer where:
+- `limit` - the lowest size of the buffer.
+
+```javascript
+var schema = Joi.binary().min(2);
+```
+
+#### `binary.max(limit)`
+
+Specifies the maximum length of the buffer where:
+- `limit` - the highest size of the buffer.
+
+```javascript
+var schema = Joi.binary().max(10);
+```
+
+#### `binary.length(limit)`
+
+Specifies the exact length of the buffer:
+- `limit` - the size of buffer allowed.
+
+```javascript
+var schema = Joi.binary().length(5);
+```
+
+### `date`
+
+Generates a schema object that matches a date type (as well as a JavaScript date string or number of milliseconds).
+
+Supports the same methods of the [`any()`](#any) type.
+
+```javascript
+var date = Joi.date();
+date.validate('12-21-2012', function (err, value) { });
+```
+
+#### `date.min(date)`
+
+Specifies the oldest date allowed where:
+- `date` - the oldest date allowed.
+
+```javascript
+var schema = Joi.date().min('1-1-1974');
+```
+
+Notes: `'now'` can be passed in lieu of `date` so as to always compare relatively to the current date, allowing to explicitly ensure a date is either in the past or in the future.
+
+```javascript
+var schema = Joi.date().min('now');
+```
+
+It can also be a reference to another field.
+
+```javascript
+var schema = Joi.object({
+  from: Joi.date().required(),
+  to: Joi.date().min(Joi.ref('from')).required()
+});
+```
+
+#### `date.max(date)`
+
+Specifies the latest date allowed where:
+- `date` - the latest date allowed.
+
+```javascript
+var schema = Joi.date().max('12-31-2020');
+```
+
+Notes: `'now'` can be passed in lieu of `date` so as to always compare relatively to the current date, allowing to explicitly ensure a date is either in the past or in the future.
+
+```javascript
+var schema = Joi.date().max('now');
+```
+
+It can also be a reference to another field.
+
+```javascript
+var schema = Joi.object({
+  from: Joi.date().max(Joi.ref('to')).required(),
+  to: Joi.date().required()
+});
+```
+
+#### `date.format(format)`
+
+Specifies the allowed date format:
+- `format` - string or array of strings that follow the `moment.js` [format](http://momentjs.com/docs/#/parsing/string-format/).
+
+```javascript
+var schema = Joi.date().format('YYYY/MM/DD');
+```
+
+#### `date.iso()`
+
+Requires the string value to be in valid ISO 8601 date format.
+
+```javascript
+var schema = Joi.date().iso();
+```
+
+### `func`
+
+Generates a schema object that matches a function type.
+
+Supports the same methods of the [`object()`](#object) type. Note that validating a function keys will cause the function
+to be cloned. While the function will retain its prototype and closure, it will lose its `length` property value (will be
+set to `0`).
+
+```javascript
+var func = Joi.func();
+func.validate(function () {}, function (err, value) { });
+```
+
+### `number`
+
+Generates a schema object that matches a number data type (as well as strings that can be converted to numbers).
+
+`Infinity` and `-Infinity` are invalid by default, you can change that behavior by calling `allow(Infinity, -Infinity)`.
+
+Supports the same methods of the [`any()`](#any) type.
+
+```javascript
+var number = Joi.number();
+number.validate(5, function (err, value) { });
+```
+
+#### `number.min(limit)`
+
+Specifies the minimum value where:
+- `limit` - the minimum value allowed.
+
+```javascript
+var schema = Joi.number().min(2);
+```
+
+It can also be a reference to another field.
+
+```javascript
+var schema = Joi.object({
+  min: Joi.number().required(),
+  max: Joi.number().min(Joi.ref('min')).required()
+});
+```
+
+#### `number.max(limit)`
+
+Specifies the maximum value where:
+- `limit` - the maximum value allowed.
+
+```javascript
+var schema = Joi.number().max(10);
+```
+
+It can also be a reference to another field.
+
+```javascript
+var schema = Joi.object({
+  min: Joi.number().max(Joi.ref('max')).required(),
+  max: Joi.number().required()
+});
+```
+
+#### `number.greater(limit)`
+
+Specifies that the value must be greater than `limit`.
+
+```javascript
+var schema = Joi.number().greater(5);
+```
+
+```javascript
+var schema = Joi.object({
+  min: Joi.number().required(),
+  max: Joi.number().greater(Joi.ref('min')).required()
+});
+```
+
+#### `number.less(limit)`
+
+Specifies that the value must be less than `limit`.
+
+```javascript
+var schema = Joi.number().less(10);
+```
+
+It can also be a reference to another field.
+
+```javascript
+var schema = Joi.object({
+  min: Joi.number().less(Joi.ref('max')).required(),
+  max: Joi.number().required()
+});
+```
+
+#### `number.integer()`
+
+Requires the number to be an integer (no floating point).
+
+```javascript
+var schema = Joi.number().integer();
+```
+
+#### `number.precision(limit)`
+
+Specifies the maximum number of decimal places where:
+- `limit` - the maximum number of decimal places allowed.
+
+```javascript
+var schema = Joi.number().precision(2);
+```
+
+#### `number.multiple(base)`
+
+Specifies that the value must be a multiple of `base`:
+
+```javascript
+var schema = Joi.number().multiple(3);
+```
+
+#### `number.positive()`
+
+Requires the number to be positive.
+
+```javascript
+var schema = Joi.number().positive();
+```
+
+#### `number.negative()`
+
+Requires the number to be negative.
+
+```javascript
+var schema = Joi.number().negative();
+```
+
+### `object`
+
+Generates a schema object that matches an object data type (as well as JSON strings that parsed into objects). Defaults
+to allowing any child key.
+
+Supports the same methods of the [`any()`](#any) type.
+
+```javascript
+var object = Joi.object().keys({
+    a: Joi.number().min(1).max(10).integer(),
+    b: 'some string'
+});
+
+object.validate({ a: 5 }, function (err, value) { });
+```
+
+#### `object.keys([schema])`
+
+Sets or extends the allowed object keys where:
+- `schema` - optional object where each key is assigned a **joi** type object. If `schema` is `{}` no keys allowed.
+  If `schema` is `null` or `undefined`, any key allowed. If `schema` is an object with keys, the keys are added to any
+  previously defined keys (but narrows the selection if all keys previously allowed). Defaults to 'undefined' which
+  allows any child key.
+
+```javascript
+var base = Joi.object().keys({
+    a: Joi.number(),
+    b: Joi.string()
+});
+// Validate keys a, b and c.
+var extended = base.keys({
+    c: Joi.boolean()
+});
+```
+
+Notes: We have three different ways to define a schema for performing a validation
+
+- Using the plain JS object notation:
+```javascript
+var schema = {
+    a: Joi.string(),
+    b: Joi.number()
+};
+```
+- Using the `Joi.object([schema])` notation
+```javascript
+var schema = Joi.object({
+    a: Joi.string(),
+    b: Joi.number()
+});
+```
+- Using the `Joi.object().keys([schema])` notation
+```javascript
+var schema = Joi.object().keys({
+    a: Joi.string(),
+    b: Joi.number()
+});
+```
+
+While all these three objects defined above will result in the same validation object, there are some differences in using one or another:
+
+##### `{} notation`
+
+When using the `{}` notation, you are just defining a plain JS object, which isn't a schema object.
+You can pass it to the validation method but you can't call `validate()` method of the object because it's just a plain JS object.
+
+Besides, passing the `{}` object to the `validate()` method each time, will perform an expensive schema compilation operation on every validation.
+
+##### `Joi.object([schema]) notation`
+
+Using `Joi.object([schema])` will return a schema object, so you can call the `validate()` method directly, e.g:
+
+```javascript
+var schema = Joi.object({
+    a: Joi.boolean()
+});
+
+schema.validate(true, function (err, value) {
+    console.log('err: ', err);
+});
+```
+
+When you use `Joi.object([schema])`, it gets compiled the first time, so you can pass it to the `validate()` method multiple times and no overhead is added.
+
+Another benefits of using `Joi.object([schema])` instead of a plain JS object is that you can set any options on the object like allowing unknown keys, e.g:
+
+```javascript
+var schema = Joi.object({
+    arg: Joi.string().valid('firstname', 'lastname', 'title', 'company', 'jobtitle'),
+    value: Joi.string(),
+}).pattern(/firstname|lastname/, Joi.string().min(2));
+```
+
+##### `Joi.object().keys([schema]) notation`
+
+This is basically the same as `Joi.object([schema])`, but using `Joi.object().keys([schema])` is more useful when you want to add more keys (e.g. call `keys()` multiple times). If you are only adding one set of keys, you can skip the `keys()` method and just use `object()` directly.
+
+Some people like to use `keys()` to make the code more explicit (this is style only).
+
+
+#### `object.min(limit)`
+
+Specifies the minimum number of keys in the object where:
+- `limit` - the lowest number of keys allowed.
+
+```javascript
+var schema = Joi.object().min(2);
+```
+
+#### `object.max(limit)`
+
+Specifies the maximum number of keys in the object where:
+- `limit` - the highest number of object keys allowed.
+
+```javascript
+var schema = Joi.object().max(10);
+```
+
+#### `object.length(limit)`
+
+Specifies the exact number of keys in the object where:
+- `limit` - the number of object keys allowed.
+
+```javascript
+var schema = Joi.object().length(5);
+```
+
+#### `object.pattern(regex, schema)`
+
+Specify validation rules for unknown keys matching a pattern where:
+- `regex` - a regular expression tested against the unknown key names.
+- `schema` - the schema object matching keys much validate against.
+
+```javascrip
+var schema = Joi.object({
+    a: Joi.string()
+}).pattern(/\w\d/, Joi.boolean());
+```
+
+#### `object.and(peers)`
+
+Defines an all-or-nothing relationship between keys where if one of the peers is present, all of them are required as
+well where:
+- `peers` - the key names of which if one present, all are required. `peers` can be a single string value, an
+  array of string values, or each peer provided as an argument.
+
+```javascript
+var schema = Joi.object().keys({
+    a: Joi.any(),
+    b: Joi.any()
+}).and('a', 'b');
+```
+
+#### `object.nand(peers)`
+
+Defines a relationship between keys where not all peers can be present at the
+same time where:
+- `peers` - the key names of which if one present, the others may not all be present. `peers` can be a single string value, an
+  array of string values, or each peer provided as an argument.
+
+```javascript
+var schema = Joi.object().keys({
+    a: Joi.any(),
+    b: Joi.any()
+}).nand('a', 'b');
+```
+
+#### `object.or(peers)`
+
+Defines a relationship between keys where one of the peers is required (and more than one is allowed) where:
+- `peers` - the key names of which at least one must appear. `peers` can be a single string value, an
+  array of string values, or each peer provided as an argument.
+
+```javascript
+var schema = Joi.object().keys({
+    a: Joi.any(),
+    b: Joi.any()
+}).or('a', 'b');
+```
+
+#### `object.xor(peers)`
+
+Defines an exclusive relationship between a set of keys where one of them is required but not at the same time where:
+- `peers` - the exclusive key names that must not appear together but where one of them is required. `peers` can be a single string value, an
+  array of string values, or each peer provided as an argument.
+
+```javascript
+var schema = Joi.object().keys({
+    a: Joi.any(),
+    b: Joi.any()
+}).xor('a', 'b');
+```
+
+#### `object.with(key, peers)`
+
+Requires the presence of other keys whenever the specified key is present where:
+- `key` - the reference key.
+- `peers` - the required peer key names that must appear together with `key`. `peers` can be a single string value or an array of string values.
+
+Note that unlike [`object.and()`](#objectandpeers), `with()` creates a dependency only between the `key` and each of the `peers`, not
+between the `peers` themselves.
+
+```javascript
+var schema = Joi.object().keys({
+    a: Joi.any(),
+    b: Joi.any()
+}).with('a', 'b');
+```
+
+#### `object.without(key, peers)`
+
+Forbids the presence of other keys whenever the specified is present where:
+- `key` - the reference key.
+- `peers` - the forbidden peer key names that must not appear together with `key`. `peers` can be a single string value or an array of string values.
+
+```javascript
+var schema = Joi.object().keys({
+    a: Joi.any(),
+    b: Joi.any()
+}).without('a', ['b']);
+```
+
+#### `object.rename(from, to, [options])`
+
+Renames a key to another name (deletes the renamed key) where:
+- `from` - the original key name.
+- `to` - the new key name.
+- `options` - an optional object with the following optional keys:
+    - `alias` - if `true`, does not delete the old key name, keeping both the new and old keys in place. Defaults to `false`.
+    - `multiple` - if `true`, allows renaming multiple keys to the same destination where the last rename wins. Defaults to `false`.
+    - `override` - if `true`, allows renaming a key over an existing key. Defaults to `false`.
+    - `ignoreUndefined` - if `true`, skip renaming of a key if it's undefined. Defaults to `false`.
+
+Keys are renamed before any other validation rules are applied.
+
+```javascript
+var object = Joi.object().keys({
+    a: Joi.number()
+}).rename('b', 'a');
+
+object.validate({ b: 5 }, function (err, value) { });
+```
+
+#### `object.assert(ref, schema, [message])`
+
+Verifies an assertion where:
+- `ref` - the key name or [reference](#refkey-options).
+- `schema` - the validation rules required to satisfy the assertion. If the `schema` includes references, they are resolved against
+  the object value, not the value of the `ref` target.
+- `message` - optional human-readable message used when the assertion fails. Defaults to 'failed to pass the assertion test'.
+
+```javascript
+var schema = Joi.object().keys({
+    a: {
+        b: Joi.string(),
+        c: Joi.number()
+    },
+    d: {
+        e: Joi.any()
+    }
+}).assert('d.e', Joi.ref('a.c'), 'equal to a.c');
+```
+
+#### `object.unknown([allow])`
+
+Overrides the handling of unknown keys for the scope of the current object only (does not apply to children) where:
+- `allow` - if `false`, unknown keys are not allowed, otherwise unknown keys are ignored.
+
+```javascript
+var schema = Joi.object({ a: Joi.any() }).unknown();
+```
+
+#### `object.type(constructor, [name])`
+
+Requires the object to be an instance of a given constructor where:
+- `constructor` - the constructor function that the object must be an instance of.
+- `name` - an alternate name to use in validation errors. This is useful when the constructor function does not have a name.
+
+```javascript
+var schema = Joi.object().type(RegExp);
+```
+
+#### `object.requiredKeys(children)`
+
+Sets the specified children to required.
+- `children` - can be a single string value, an array of string values, or each child provided as an argument.
+
+```javascript
+var schema = Joi.object().keys({ a: { b: Joi.number() }, c: { d: Joi.string() } });
+var requiredSchema = schema.requiredKeys('', 'a.b', 'c', 'c.d');
+```
+
+Note that in this example `''` means the current object, `a` is not required but `b` is, as well as `c` and `d`.
+
+#### `object.optionalKeys(children)`
+
+Sets the specified children to optional.
+- `children` - can be a single string value, an array of string values, or each child provided as an argument.
+
+```javascript
+var schema = Joi.object().keys({ a: { b: Joi.number().required() }, c: { d: Joi.string().required() } });
+var requiredSchema = schema.optionalKeys('a.b', 'c.d');
+```
+
+The behavior is exactly the same as `requiredKeys`.
+
+### `string`
+
+Generates a schema object that matches a string data type. Note that empty strings are not allowed by default and must be enabled with `allow('')`.
+
+Supports the same methods of the [`any()`](#any) type.
+
+```javascript
+var schema = Joi.string().min(1).max(10);
+schema.validate('12345', function (err, value) { });
+```
+
+#### `string.insensitive()`
+
+Allows the value to match any whitelist of blacklist item in a case insensitive comparison.
+
+```javascript
+var schema = Joi.string().valid('a').insensitive();
+```
+
+#### `string.min(limit, [encoding])`
+
+Specifies the minimum number string characters where:
+- `limit` - the minimum number of string characters required.
+- `encoding` - is specified, the string length is calculated in bytes using the provided encoding.
+
+```javascript
+var schema = Joi.string().min(2);
+```
+
+It can also be a reference to another field.
+
+```javascript
+var schema = Joi.object({
+  min: Joi.string().required(),
+  value: Joi.string().min(Joi.ref('min'), 'utf8').required()
+});
+```
+
+#### `string.max(limit, [encoding])`
+
+Specifies the maximum number of string characters where:
+- `limit` - the maximum number of string characters allowed.
+- `encoding` - is specified, the string length is calculated in bytes using the provided encoding.
+
+```javascript
+var schema = Joi.string().max(10);
+```
+
+It can also be a reference to another field.
+
+```javascript
+var schema = Joi.object({
+  max: Joi.string().required(),
+  value: Joi.string().max(Joi.ref('max'), 'utf8').required()
+});
+```
+
+#### `string.creditCard()`
+
+Requires the number to be a credit card number (Using [Lunh
+Algorithm](http://en.wikipedia.org/wiki/Luhn_algorithm)).
+
+```javascript
+var schema = Joi.string().creditCard();
+```
+
+#### `string.length(limit, [encoding])`
+
+Specifies the exact string length required where:
+- `limit` - the required string length.
+- `encoding` - is specified, the string length is calculated in bytes using the provided encoding.
+
+```javascript
+var schema = Joi.string().length(5);
+```
+
+It can also be a reference to another field.
+
+```javascript
+var schema = Joi.object({
+  length: Joi.string().required(),
+  value: Joi.string().length(Joi.ref('length'), 'utf8').required()
+});
+```
+
+#### `string.regex(pattern, [name])`
+
+Defines a regular expression rule where:
+- `pattern` - a regular expression object the string value must match against.
+- `name` - optional name for patterns (useful with multiple patterns). Defaults to 'required'.
+
+```javascript
+var schema = Joi.string().regex(/^[abc]+$/);
+```
+
+#### `string.replace(pattern, replacement)`
+
+Replace characters matching the given _pattern_ with the specified
+_replacement_ string where:
+- `pattern` - a regular expression object to match against, or a string of which _all_ occurrences will be replaced.
+- `replacement` - the string that will replace the pattern.
+
+
+```javascript
+var schema = Joi.string().replace(/b/gi, 'x');
+schema.validate('abBc', function (err, value) {
+  // here value will be 'axxc'
+});
+```
+
+When `pattern` is a _string_ all its occurrences will be replaced.
+
+#### `string.alphanum()`
+
+Requires the string value to only contain a-z, A-Z, and 0-9.
+
+```javascript
+var schema = Joi.string().alphanum();
+```
+
+#### `string.token()`
+
+Requires the string value to only contain a-z, A-Z, 0-9, and underscore _.
+
+```javascript
+var schema = Joi.string().token();
+```
+
+#### `string.email([options])`
+
+Requires the string value to be a valid email address.
+
+- `options` - optional settings:
+    - `errorLevel` - Numerical threshold at which an email address is considered invalid.
+    - `tldWhitelist` - Specifies a list of acceptable TLDs.
+    - `minDomainAtoms` - Number of atoms required for the domain. Be careful since some domains, such as `io`, directly allow email.
+
+```javascript
+var schema = Joi.string().email();
+```
+
+#### `string.ip([options])`
+
+Requires the string value to be a valid ip address.
+
+- `options` - optional settings:
+    - `version` - One or more IP address versions to validate against. Valid values: `ipv4`, `ipv6`, `ipvfuture`
+    - `cidr` - Used to determine if a CIDR is allowed or not. Valid values: `optional`, `required`, `forbidden`
+
+```javascript
+// Accept only ipv4 and ipv6 addresses with a CIDR
+var schema = Joi.string().ip({
+  version: [
+    'ipv4',
+    'ipv6'
+  ],
+  cidr: 'required'
+});
+```
+
+#### `string.uri([options])`
+
+Requires the string value to be a valid [RFC 3986](http://tools.ietf.org/html/rfc3986) URI.
+
+- `options` - optional settings:
+    - `scheme` - Specifies one or more acceptable Schemes, should only include the scheme name. Can be an Array or String (strings are automatically escaped for use in a Regular Expression).
+
+```javascript
+// Accept git or git http/https
+var schema = Joi.string().uri({
+  scheme: [
+    'git',
+    /git\+https?/
+  ]
+});
+```
+
+#### `string.guid()`
+
+Requires the string value to be a valid GUID.
+
+```javascript
+var schema = Joi.string().guid();
+```
+
+#### `string.hex()`
+
+Requires the string value to be a valid hexadecimal string.
+
+```javascript
+var schema = Joi.string().hex();
+```
+
+#### `string.hostname()`
+
+Requires the string value to be a valid hostname as per [RFC1123](http://tools.ietf.org/html/rfc1123).
+
+```javascript
+var schema = Joi.string().hostname();
+```
+
+#### `string.lowercase()`
+
+Requires the string value to be all lowercase. If the validation `convert` option is on (enabled by default), the string
+will be forced to lowercase.
+
+```javascript
+var schema = Joi.string().lowercase();
+```
+
+#### `string.uppercase()`
+
+Requires the string value to be all uppercase. If the validation `convert` option is on (enabled by default), the string
+will be forced to uppercase.
+
+```javascript
+var schema = Joi.string().uppercase();
+```
+
+#### `string.trim()`
+
+Requires the string value to contain no whitespace before or after. If the validation `convert` option is on (enabled by
+default), the string will be trimmed.
+
+```javascript
+var schema = Joi.string().trim();
+```
+
+#### `string.isoDate()`
+
+Requires the string value to be in valid ISO 8601 date format.
+
+```js
+var schema = Joi.string().isoDate();
+```
+
+### `alternatives`
+
+Generates a type that will match one of the provided alternative schemas via the [`try()`](#alternativestryschemas)
+method. If no schemas are added, the type will not match any value except for `undefined`.
+
+Supports the same methods of the [`any()`](#any) type.
+
+Alternatives can be expressed using the shorter `[]` notation.
+
+```javascript
+var alt = Joi.alternatives().try(Joi.number(), Joi.string());
+// Same as [Joi.number(), Joi.string()]
+```
+
+#### `alternatives.try(schemas)`
+
+Adds an alternative schema type for attempting to match against the validated value where:
+- `schema` - an array of alternative **joi** types. Also supports providing each type as a separate argument.
+
+```javascript
+var alt = Joi.alternatives().try(Joi.number(), Joi.string());
+alt.validate('a', function (err, value) { });
+```
+
+#### `alternatives.when(ref, options)`
+
+Adds a conditional alternative schema type based on another key (not the same as `any.when()`) value where:
+- `ref` - the key name or [reference](#refkey-options).
+- `options` - an object with:
+    - `is` - the required condition **joi** type.
+    - `then` - the alternative schema type to **try** if the condition is true. Required if `otherwise` is missing.
+    - `otherwise` - the alternative schema type to **try** if the condition is false. Required if `then` is missing.
+
+```javascript
+var schema = {
+    a: Joi.alternatives().when('b', { is: 5, then: Joi.string(), otherwise: Joi.number() }),
+    b: Joi.any()
+};
+```
+
+Note that `when()` only adds additional alternatives to try and does not impact the overall type. Setting
+a `required()` rule on a single alternative will not apply to the overall key. For example,
+this definition of `a`:
+
+```javascript
+var schema = {
+    a: Joi.alternatives().when('b', { is: true, then: Joi.required() }),
+    b: Joi.boolean()
+};
+```
+
+Does not turn `a` into a required key when `b` is `true`. Instead, it tells the validator to try and match the
+value to anything that's not `undefined`. However, since `Joi.alternatives()` by itself allows `undefined`, the rule
+does not accomplish turning `a` to a required value. This rule is the same as `Joi.alternatives([Joi.required()])`
+when `b` is `true` which will allow any value including `undefined`.
+
+To accomplish the desired result above use:
+
+```javascript
+var schema = {
+    a: Joi.when('b', { is: true, then: Joi.required() }),
+    b: Joi.boolean()
+};
+```
+
+### `ref(key, [options])`
+
+Generates a reference to the value of the named key. References are resolved at validation time and in order of dependency
+so that if one key validation depends on another, the dependent key is validated second after the reference is validated.
+References support the following arguments:
+- `key` - the reference target. References cannot point up the object tree, only to sibling keys, but they can point to
+  their siblings' children (e.g. 'a.b.c') using the `.` separator. If a `key` starts with `$` is signifies a context reference
+  which is looked up in the `context` option object.
+- `options` - optional settings:
+    - `separator` - overrides the default `.` hierarchy separator.
+    - `contextPrefix` - overrides the default `$` context prefix signifier.
+
+Note that references can only be used where explicitly supported such as in `valid()` or `invalid()` rules. If upwards
+(parents) references are needed, use [`object.assert()`](#objectassertref-schema-message).
+
+```javascript
+var schema = Joi.object().keys({
+    a: Joi.ref('b.c'),
+    b: {
+        c: Joi.any()
+    },
+    c: Joi.ref('$x')
+});
+
+Joi.validate({ a: 5, b: { c: 5 } }, schema, { context: { x: 5 } }, function (err, value) {});
+```
+
+## Errors
+
+Joi throws classical javascript `Error`s containing :
+- `name` - `ValidationError`.
+- `details` - an array of errors :
+    - `message` - string with a description of the error.
+    - `path` - dotted path to the key where the error happened.
+    - `type` - type of the error.
+    - `context` - object providing context of the error.
+- `annotate` - function that returns a string with an annotated version of the object pointing at the places where errors occured.
+- `_object` - the original object to validate.
\ No newline at end of file
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/CONTRIBUTING.md b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/CONTRIBUTING.md
new file mode 100755
index 0000000000000000000000000000000000000000..713d376a409b00626641740841bdac6b1192d6a6
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/CONTRIBUTING.md
@@ -0,0 +1,14 @@
+# How to contribute
+We welcome contributions from the community and are pleased to have them.  Please follow this guide when logging issues or making code changes.
+
+## Logging Issues
+All issues should be created using the [new issue form](https://github.com/hapijs/joi/issues/new).  Clearly describe the issue including steps to reproduce if there are any.  Also, make sure to indicate the earliest version that has the issue being reported.
+
+## Patching Code
+Code changes are welcome and should follow the guidelines below.
+
+* Fork the repository on GitHub.
+* Fix the issue ensuring that your code follows the [style guide](https://github.com/hapijs/contrib/blob/master/Style.md).
+* Add tests for your new code ensuring that you have 100% code coverage (we can help you reach 100% but will not merge without it).
+    * Run `npm test` to generate a report of test coverage
+* [Pull requests](http://help.github.com/send-pull-requests/) should be made to the [master branch](https://github.com/hapijs/joi/tree/master).
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/LICENSE b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/LICENSE
new file mode 100755
index 0000000000000000000000000000000000000000..03afbde32ac5414128ede5bc87f2932bfd9f2d68
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/LICENSE
@@ -0,0 +1,28 @@
+Copyright (c) 2012-2014, Walmart and other contributors.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * The names of any contributors may not be used to endorse or promote
+      products derived from this software without specific prior written
+      permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+                                  *   *   *
+
+The complete list of contributors can be found at: https://github.com/hapijs/joi/graphs/contributors
\ No newline at end of file
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/README.md b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..21d603b8106f2c5c628e565b7f1ed216451f6992
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/README.md
@@ -0,0 +1,90 @@
+![joi Logo](https://raw.github.com/hapijs/joi/master/images/joi.png)
+
+Object schema description language and validator for JavaScript objects.
+
+[![npm version](https://badge.fury.io/js/joi.svg)](http://badge.fury.io/js/joi)
+[![Build Status](https://secure.travis-ci.org/hapijs/joi.svg)](http://travis-ci.org/hapijs/joi)
+[![Dependencies Status](https://david-dm.org/hapijs/joi.svg)](https://david-dm.org/hapijs/joi)
+[![DevDependencies Status](https://david-dm.org/hapijs/joi/dev-status.svg)](https://david-dm.org/hapijs/joi#info=devDependencies)
+
+[![Join the chat at https://gitter.im/hapijs/joi](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/hapijs/joi?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+
+Lead Maintainer: [Nicolas Morel](https://github.com/marsup)
+
+# Example
+
+```javascript
+var Joi = require('joi');
+
+var schema = Joi.object().keys({
+    username: Joi.string().alphanum().min(3).max(30).required(),
+    password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/),
+    access_token: [Joi.string(), Joi.number()],
+    birthyear: Joi.number().integer().min(1900).max(2013),
+    email: Joi.string().email()
+}).with('username', 'birthyear').without('password', 'access_token');
+
+Joi.validate({ username: 'abc', birthyear: 1994 }, schema, function (err, value) { });  // err === null -> valid
+```
+
+The above schema defines the following constraints:
+* `username`
+    * a required string
+    * must contain only alphanumeric characters
+    * at least 3 characters long but no more than 30
+    * must be accompanied by `birthyear`
+* `password`
+    * an optional string
+    * must satisfy the custom regex
+    * cannot appear together with `access_token`
+* `access_token`
+    * an optional, unconstrained string or number
+* `birthyear`
+    * an integer between 1900 and 2013
+* `email`
+    * a valid email address string
+
+# Usage
+
+Usage is a two steps process. First, a schema is constructed using the provided types and constraints:
+
+```javascript
+var schema = {
+    a: Joi.string()
+};
+```
+
+Note that **joi** schema objects are immutable which means every additional rule added (e.g. `.min(5)`) will return a
+new schema object.
+
+Then the value is validated against the schema:
+
+```javascript
+Joi.validate({ a: 'a string' }, schema, function (err, value) { });
+```
+
+If the value is valid, `null` is returned, otherwise an `Error` object.
+
+The schema can be a plain JavaScript object where every key is assigned a **joi** type, or it can be a **joi** type directly:
+
+```javascript
+var schema = Joi.string().min(10);
+```
+
+If the schema is a **joi** type, the `schema.validate(value, callback)` can be called directly on the type. When passing a non-type schema object,
+the module converts it internally to an object() type equivalent to:
+
+```javascript
+var schema = Joi.object().keys({
+    a: Joi.string()
+});
+```
+
+When validating a schema:
+
+* Keys are optional by default.
+* Strings are utf-8 encoded by default.
+* Rules are defined in an additive fashion and evaluated in order after whitelist and blacklist checks.
+
+# API
+See the [API Reference](API.md).
\ No newline at end of file
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/examples/conditionalRequire.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/examples/conditionalRequire.js
new file mode 100644
index 0000000000000000000000000000000000000000..d17f849fc318ea47b715f89b88f6e8bc2eabb5d0
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/examples/conditionalRequire.js
@@ -0,0 +1,43 @@
+// This is an example of a survey to obtain the reputation of Parisians
+// It contains examples of how to conditionally require keys based on values of other keys
+
+var Joi = require('../');
+
+// This is a valid value for integer rating 1 - 5
+var intRating = Joi.number().integer().min(1).max(5);
+
+var schema = Joi.object().keys({
+    // Do you know any French people? yes or no (required)
+    q1: Joi.boolean().required(),
+    // Do you know any Parisians? yes or no (required if answered yes in q1)
+    q2: Joi.boolean()
+        .when('q1', { is: true, then: Joi.required() }),
+    // How many french in paris do you know? 1-6, 6-10, 11-50 or 50+ (required if answered yes in q2)
+    q3: Joi.string()
+        .when('q2', { is: true, then: Joi.valid('1-5', '6-10', '11-50', '50+').required() }),
+    // Rate 20% of most friendly Parisians, from how many people you know answered in q3, individually on 1-5 rating
+    q4: Joi.array()
+        .when('q3', {is: '1-5', then: Joi.array().min(0).max(1).items(intRating).required() })
+        .when('q3', {is: '6-10', then: Joi.array().min(1).max(2).items(intRating).required() })
+        .when('q3', {is: '11-50', then: Joi.array().min(2).max(10).items(intRating).required() })
+        .when('q3', {is: '50+', then: Joi.array().min(10).items(intRating).required() }),
+    // Rate remaining 80% of Parisians, from how many people you know answered in q3, individually on 1-5 rating
+    q5: Joi.array()
+        .when('q3', {is: '1-5', then: Joi.array().min(1).max(4).items(intRating).required() })
+        .when('q3', {is: '6-10', then: Joi.array().min(4).max(8).items(intRating).required() })
+        .when('q3', {is: '11-50', then: Joi.array().min(8).max(40).items(intRating).required() })
+        .when('q3', {is: '50+', then: Joi.array().min(40).items(intRating).required().required() }),
+    // Rate the reputation of Parisians in general, 1-5 rating
+    q6: intRating.required()
+});
+
+var response = {
+	q1: true,
+	q2: true,
+	q3: '1-5',
+	q4: [5],
+	q5: [1],
+	q6: 2
+};
+
+Joi.assert(response, schema);
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/examples/customMessage.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/examples/customMessage.js
new file mode 100755
index 0000000000000000000000000000000000000000..38cd28ac3bff1b646a5d574fa159f4b82bd70485
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/examples/customMessage.js
@@ -0,0 +1,22 @@
+var Joi = require('../');
+
+
+var schema = Joi.object().options({ abortEarly: false }).keys({
+    email: Joi.string().email().required().label('User Email'),
+    password: Joi.string().min(8).required(),
+    password_confirmation: Joi.any().valid(Joi.ref('password')).required().options({ language: { any: { allowOnly: 'must match password' }, label: 'Password Confirmation' } }).label('This label is not used because language.label takes precedence'),
+    first_name: Joi.string().required(),
+    last_name: Joi.string().required(),
+    company: Joi.string().optional()
+});
+
+
+var data = {
+    email: 'not_a_valid_email_to_show_custom_label',
+    password: 'abcd1234',
+    password_confirmation: 'abc1',
+    first_name: 'Joe',
+    last_name: 'Doe'
+};
+
+Joi.assert(data, schema);
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/examples/multipleWhen.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/examples/multipleWhen.js
new file mode 100755
index 0000000000000000000000000000000000000000..b13cba9ce14fcc2370959c98131bd884d3cd3a11
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/examples/multipleWhen.js
@@ -0,0 +1,17 @@
+var Joi = require('../');
+
+
+var schema = {
+    type: Joi.string().required(),
+    subtype: Joi.alternatives()
+        .when('type', {is: 'video', then: Joi.valid('mp4', 'wav')})
+        .when('type', {is: 'audio', then: Joi.valid('mp3')})
+        .when('type', {is: 'image', then: Joi.valid('jpg', 'png')})
+        .when('type', {is: 'pdf'  , then: Joi.valid('document')})
+};
+
+
+Joi.assert({ type: 'video', subtype: 'mp4' }, schema); // Pass
+Joi.assert({ type: 'video', subtype: 'wav' }, schema); // Pass
+Joi.assert({ type: 'other', subtype: 'something' }, schema); // Fail
+Joi.assert({ type: 'audio', subtype: 'mp4' }, schema); // Fail
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/generate-readme-toc.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/generate-readme-toc.js
new file mode 100644
index 0000000000000000000000000000000000000000..c2db5d3c816dfa8c59ac97e658e0064486024898
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/generate-readme-toc.js
@@ -0,0 +1,21 @@
+var Toc = require('markdown-toc');
+var Fs = require('fs');
+var Package = require('./package.json');
+
+var filename = './API.md';
+
+var api = Fs.readFileSync(filename, 'utf8');
+var tocOptions = {
+    bullets: '-',
+    slugify: function (text) {
+
+        return text.toLowerCase()
+            .replace(/\s/g, '-')
+            .replace(/[^\w-]/g, '');
+    }
+};
+
+var output = Toc.insert(api, tocOptions)
+    .replace(/<!-- version -->(.|\n)*<!-- versionstop -->/, '<!-- version -->\n# ' + Package.version + ' API Reference\n<!-- versionstop -->');
+
+Fs.writeFileSync(filename, output);
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/images/joi.png b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/images/joi.png
new file mode 100755
index 0000000000000000000000000000000000000000..d240833802bcd4e4e0becde614466a3f36f09480
Binary files /dev/null and b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/images/joi.png differ
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/images/validation.png b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/images/validation.png
new file mode 100755
index 0000000000000000000000000000000000000000..380ee5213d4b4b27b3e5f925a477cdac302d198b
Binary files /dev/null and b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/images/validation.png differ
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/alternatives.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/alternatives.js
new file mode 100755
index 0000000000000000000000000000000000000000..9f1778e11813797e8834d4612f1105e20304c48a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/alternatives.js
@@ -0,0 +1,152 @@
+// Load modules
+
+var Hoek = require('hoek');
+var Any = require('./any');
+var Cast = require('./cast');
+var Ref = require('./ref');
+var Errors = require('./errors');
+
+
+// Declare internals
+
+var internals = {};
+
+
+internals.Alternatives = function () {
+
+    Any.call(this);
+    this._type = 'alternatives';
+    this._invalids.remove(null);
+
+    this._inner.matches = [];
+};
+
+Hoek.inherits(internals.Alternatives, Any);
+
+
+internals.Alternatives.prototype._base = function (value, state, options) {
+
+    var errors = [];
+    for (var i = 0, il = this._inner.matches.length; i < il; ++i) {
+        var item = this._inner.matches[i];
+        var schema = item.schema;
+        if (!schema) {
+            var failed = item.is._validate(item.ref(state.parent, options), null, options, state.parent).errors;
+            schema = failed ? item.otherwise : item.then;
+            if (!schema) {
+                continue;
+            }
+        }
+
+        var result = schema._validate(value, state, options);
+        if (!result.errors) {     // Found a valid match
+            return result;
+        }
+
+        errors = errors.concat(result.errors);
+    }
+
+    return { errors: errors.length ? errors : Errors.create('alternatives.base', null, state, options) };
+};
+
+
+internals.Alternatives.prototype.try = function (/* schemas */) {
+
+
+    var schemas = Hoek.flatten(Array.prototype.slice.call(arguments));
+    Hoek.assert(schemas.length, 'Cannot add other alternatives without at least one schema');
+
+    var obj = this.clone();
+
+    for (var i = 0, il = schemas.length; i < il; ++i) {
+        var cast = Cast.schema(schemas[i]);
+        if (cast._refs.length) {
+            obj._refs = obj._refs.concat(cast._refs);
+        }
+        obj._inner.matches.push({ schema: cast });
+    }
+
+    return obj;
+};
+
+
+internals.Alternatives.prototype.when = function (ref, options) {
+
+    Hoek.assert(Ref.isRef(ref) || typeof ref === 'string', 'Invalid reference:', ref);
+    Hoek.assert(options, 'Missing options');
+    Hoek.assert(typeof options === 'object', 'Invalid options');
+    Hoek.assert(options.hasOwnProperty('is'), 'Missing "is" directive');
+    Hoek.assert(options.then !== undefined || options.otherwise !== undefined, 'options must have at least one of "then" or "otherwise"');
+
+    var obj = this.clone();
+    var is = Cast.schema(options.is);
+
+    if (options.is === null || !options.is.isJoi) {
+
+        // Only apply required if this wasn't already a schema, we'll suppose people know what they're doing
+        is = is.required();
+    }
+
+    var item = {
+        ref: Cast.ref(ref),
+        is: is,
+        then: options.then !== undefined ? Cast.schema(options.then) : undefined,
+        otherwise: options.otherwise !== undefined ? Cast.schema(options.otherwise) : undefined
+    };
+
+    Ref.push(obj._refs, item.ref);
+    obj._refs = obj._refs.concat(item.is._refs);
+
+    if (item.then && item.then._refs) {
+        obj._refs = obj._refs.concat(item.then._refs);
+    }
+
+    if (item.otherwise && item.otherwise._refs) {
+        obj._refs = obj._refs.concat(item.otherwise._refs);
+    }
+
+    obj._inner.matches.push(item);
+
+    return obj;
+};
+
+
+internals.Alternatives.prototype.describe = function () {
+
+    var description = Any.prototype.describe.call(this);
+    var alternatives = [];
+    for (var i = 0, il = this._inner.matches.length; i < il; ++i) {
+        var item = this._inner.matches[i];
+        if (item.schema) {
+
+            // try()
+
+            alternatives.push(item.schema.describe());
+        }
+        else {
+
+            // when()
+
+            var when = {
+                ref: item.ref.toString(),
+                is: item.is.describe()
+            };
+
+            if (item.then) {
+                when.then = item.then.describe();
+            }
+
+            if (item.otherwise) {
+                when.otherwise = item.otherwise.describe();
+            }
+
+            alternatives.push(when);
+        }
+    }
+
+    description.alternatives = alternatives;
+    return description;
+};
+
+
+module.exports = new internals.Alternatives();
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/any.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/any.js
new file mode 100755
index 0000000000000000000000000000000000000000..f63bc4dd6893e5cf321c12009890f2b9934b6f56
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/any.js
@@ -0,0 +1,899 @@
+// Load modules
+
+var Hoek = require('hoek');
+var Ref = require('./ref');
+var Errors = require('./errors');
+var Alternatives = null;                // Delay-loaded to prevent circular dependencies
+var Cast = null;
+
+
+// Declare internals
+
+var internals = {};
+
+
+internals.defaults = {
+    abortEarly: true,
+    convert: true,
+    allowUnknown: false,
+    skipFunctions: false,
+    stripUnknown: false,
+    language: {},
+    presence: 'optional',
+    raw: false,
+    strip: false,
+    noDefaults: false
+
+    // context: null
+};
+
+
+internals.checkOptions = function (options) {
+
+    var optionType = {
+        abortEarly: 'boolean',
+        convert: 'boolean',
+        allowUnknown: 'boolean',
+        skipFunctions: 'boolean',
+        stripUnknown: 'boolean',
+        language: 'object',
+        presence: ['string', 'required', 'optional', 'forbidden', 'ignore'],
+        raw: 'boolean',
+        context: 'object',
+        strip: 'boolean',
+        noDefaults: 'boolean'
+    };
+
+    var keys = Object.keys(options);
+    for (var k = 0, kl = keys.length; k < kl; ++k) {
+        var key = keys[k];
+        var opt = optionType[key];
+        var type = opt;
+        var values = null;
+
+        if (Array.isArray(opt)) {
+            type = opt[0];
+            values = opt.slice(1);
+        }
+
+        Hoek.assert(type, 'unknown key ' + key);
+        Hoek.assert(typeof options[key] === type, key + ' should be of type ' + type);
+        if (values) {
+            Hoek.assert(values.indexOf(options[key]) >= 0, key + ' should be one of ' + values.join(', '));
+        }
+    }
+};
+
+
+module.exports = internals.Any = function () {
+
+    Cast = Cast || require('./cast');
+
+    this.isJoi = true;
+    this._type = 'any';
+    this._settings = null;
+    this._valids = new internals.Set();
+    this._invalids = new internals.Set();
+    this._tests = [];
+    this._refs = [];
+    this._flags = { /*
+        presence: 'optional',                   // optional, required, forbidden, ignore
+        allowOnly: false,
+        allowUnknown: undefined,
+        default: undefined,
+        forbidden: false,
+        encoding: undefined,
+        insensitive: false,
+        trim: false,
+        case: undefined,                        // upper, lower
+        empty: undefined,
+        func: false
+    */ };
+
+    this._description = null;
+    this._unit = null;
+    this._notes = [];
+    this._tags = [];
+    this._examples = [];
+    this._meta = [];
+
+    this._inner = {};                           // Hash of arrays of immutable objects
+};
+
+
+internals.Any.prototype.isImmutable = true;     // Prevents Hoek from deep cloning schema objects
+
+
+internals.Any.prototype.clone = function () {
+
+    var obj = Object.create(Object.getPrototypeOf(this));
+
+    obj.isJoi = true;
+    obj._type = this._type;
+    obj._settings = internals.concatSettings(this._settings);
+    obj._valids = Hoek.clone(this._valids);
+    obj._invalids = Hoek.clone(this._invalids);
+    obj._tests = this._tests.slice();
+    obj._refs = this._refs.slice();
+    obj._flags = Hoek.clone(this._flags);
+
+    obj._description = this._description;
+    obj._unit = this._unit;
+    obj._notes = this._notes.slice();
+    obj._tags = this._tags.slice();
+    obj._examples = this._examples.slice();
+    obj._meta = this._meta.slice();
+
+    obj._inner = {};
+    var inners = Object.keys(this._inner);
+    for (var i = 0, il = inners.length; i < il; ++i) {
+        var key = inners[i];
+        obj._inner[key] = this._inner[key] ? this._inner[key].slice() : null;
+    }
+
+    return obj;
+};
+
+
+internals.Any.prototype.concat = function (schema) {
+
+    Hoek.assert(schema && schema.isJoi, 'Invalid schema object');
+    Hoek.assert(this._type === 'any' || schema._type === 'any' || schema._type === this._type, 'Cannot merge type', this._type, 'with another type:', schema._type);
+
+    var obj = this.clone();
+
+    if (this._type === 'any' && schema._type !== 'any') {
+
+        // Reset values as if we were "this"
+        var tmpObj = schema.clone();
+        var keysToRestore = ['_settings', '_valids', '_invalids', '_tests', '_refs', '_flags', '_description', '_unit',
+            '_notes', '_tags', '_examples', '_meta', '_inner'];
+
+        for (var j = 0, jl = keysToRestore.length; j < jl; ++j) {
+            tmpObj[keysToRestore[j]] = obj[keysToRestore[j]];
+        }
+
+        obj = tmpObj;
+    }
+
+    obj._settings = obj._settings ? internals.concatSettings(obj._settings, schema._settings) : schema._settings;
+    obj._valids.merge(schema._valids, schema._invalids);
+    obj._invalids.merge(schema._invalids, schema._valids);
+    obj._tests = obj._tests.concat(schema._tests);
+    obj._refs = obj._refs.concat(schema._refs);
+    Hoek.merge(obj._flags, schema._flags);
+
+    obj._description = schema._description || obj._description;
+    obj._unit = schema._unit || obj._unit;
+    obj._notes = obj._notes.concat(schema._notes);
+    obj._tags = obj._tags.concat(schema._tags);
+    obj._examples = obj._examples.concat(schema._examples);
+    obj._meta = obj._meta.concat(schema._meta);
+
+    var inners = Object.keys(schema._inner);
+    var isObject = obj._type === 'object';
+    for (var i = 0, il = inners.length; i < il; ++i) {
+        var key = inners[i];
+        var source = schema._inner[key];
+        if (source) {
+            var target = obj._inner[key];
+            if (target) {
+                if (isObject && key === 'children') {
+                    var keys = {};
+
+                    for (var k = 0, kl = target.length; k < kl; ++k) {
+                        keys[target[k].key] = k;
+                    }
+
+                    for (k = 0, kl = source.length; k < kl; ++k) {
+                        var sourceKey = source[k].key;
+                        if (keys[sourceKey] >= 0) {
+                            target[keys[sourceKey]] = {
+                                key: sourceKey,
+                                schema: target[keys[sourceKey]].schema.concat(source[k].schema)
+                            };
+                        }
+                        else {
+                            target.push(source[k]);
+                        }
+                    }
+                }
+                else {
+                    obj._inner[key] = obj._inner[key].concat(source);
+                }
+            }
+            else {
+                obj._inner[key] = source.slice();
+            }
+        }
+    }
+
+    return obj;
+};
+
+
+internals.Any.prototype._test = function (name, arg, func) {
+
+    Hoek.assert(!this._flags.allowOnly, 'Cannot define rules when valid values specified');
+
+    var obj = this.clone();
+    obj._tests.push({ func: func, name: name, arg: arg });
+    return obj;
+};
+
+
+internals.Any.prototype.options = function (options) {
+
+    Hoek.assert(!options.context, 'Cannot override context');
+    internals.checkOptions(options);
+
+    var obj = this.clone();
+    obj._settings = internals.concatSettings(obj._settings, options);
+    return obj;
+};
+
+
+internals.Any.prototype.strict = function (isStrict) {
+
+    var obj = this.clone();
+    obj._settings = obj._settings || {};
+    obj._settings.convert = isStrict === undefined ? false : !isStrict;
+    return obj;
+};
+
+
+internals.Any.prototype.raw = function (isRaw) {
+
+    var obj = this.clone();
+    obj._settings = obj._settings || {};
+    obj._settings.raw = isRaw === undefined ? true : isRaw;
+    return obj;
+};
+
+
+internals.Any.prototype._allow = function () {
+
+    var values = Hoek.flatten(Array.prototype.slice.call(arguments));
+    for (var i = 0, il = values.length; i < il; ++i) {
+        var value = values[i];
+
+        Hoek.assert(value !== undefined, 'Cannot call allow/valid/invalid with undefined');
+        this._invalids.remove(value);
+        this._valids.add(value, this._refs);
+    }
+};
+
+
+internals.Any.prototype.allow = function () {
+
+    var obj = this.clone();
+    obj._allow.apply(obj, arguments);
+    return obj;
+};
+
+
+internals.Any.prototype.valid = internals.Any.prototype.only = internals.Any.prototype.equal = function () {
+
+    Hoek.assert(!this._tests.length, 'Cannot set valid values when rules specified');
+
+    var obj = this.allow.apply(this, arguments);
+    obj._flags.allowOnly = true;
+    return obj;
+};
+
+
+internals.Any.prototype.invalid = internals.Any.prototype.disallow = internals.Any.prototype.not = function (value) {
+
+    var obj = this.clone();
+    var values = Hoek.flatten(Array.prototype.slice.call(arguments));
+    for (var i = 0, il = values.length; i < il; ++i) {
+        value = values[i];
+
+        Hoek.assert(value !== undefined, 'Cannot call allow/valid/invalid with undefined');
+        obj._valids.remove(value);
+        obj._invalids.add(value, this._refs);
+    }
+
+    return obj;
+};
+
+
+internals.Any.prototype.required = internals.Any.prototype.exist = function () {
+
+    var obj = this.clone();
+    obj._flags.presence = 'required';
+    return obj;
+};
+
+
+internals.Any.prototype.optional = function () {
+
+    var obj = this.clone();
+    obj._flags.presence = 'optional';
+    return obj;
+};
+
+
+internals.Any.prototype.forbidden = function () {
+
+    var obj = this.clone();
+    obj._flags.presence = 'forbidden';
+    return obj;
+};
+
+
+internals.Any.prototype.strip = function () {
+
+    var obj = this.clone();
+    obj._flags.strip = true;
+    return obj;
+};
+
+
+internals.Any.prototype.applyFunctionToChildren = function (children, fn, args, root) {
+
+    children = [].concat(children);
+
+    if (children.length !== 1 || children[0] !== '') {
+        root = root ? (root + '.') : '';
+
+        var extraChildren = (children[0] === '' ? children.slice(1) : children).map(function (child) {
+
+            return root + child;
+        });
+
+        throw new Error('unknown key(s) ' + extraChildren.join(', '));
+    }
+
+    return this[fn].apply(this, args);
+};
+
+
+internals.Any.prototype.default = function (value, description) {
+
+    if (typeof value === 'function' &&
+        !Ref.isRef(value)) {
+
+        if (!value.description &&
+            description) {
+
+            value.description = description;
+        }
+
+        if (!this._flags.func) {
+            Hoek.assert(typeof value.description === 'string' && value.description.length > 0, 'description must be provided when default value is a function');
+        }
+    }
+
+    var obj = this.clone();
+    obj._flags.default = value;
+    Ref.push(obj._refs, value);
+    return obj;
+};
+
+
+internals.Any.prototype.empty = function (schema) {
+
+    var obj;
+    if (schema === undefined) {
+        obj = this.clone();
+        obj._flags.empty = undefined;
+    }
+    else {
+        schema = Cast.schema(schema);
+
+        obj = this.clone();
+        obj._flags.empty = schema;
+    }
+
+    return obj;
+};
+
+
+internals.Any.prototype.when = function (ref, options) {
+
+    Hoek.assert(options && typeof options === 'object', 'Invalid options');
+    Hoek.assert(options.then !== undefined || options.otherwise !== undefined, 'options must have at least one of "then" or "otherwise"');
+
+    var then = options.then ? this.concat(Cast.schema(options.then)) : this;
+    var otherwise = options.otherwise ? this.concat(Cast.schema(options.otherwise)) : this;
+
+    Alternatives = Alternatives || require('./alternatives');
+    var obj = Alternatives.when(ref, { is: options.is, then: then, otherwise: otherwise });
+    obj._flags.presence = 'ignore';
+    return obj;
+};
+
+
+internals.Any.prototype.description = function (desc) {
+
+    Hoek.assert(desc && typeof desc === 'string', 'Description must be a non-empty string');
+
+    var obj = this.clone();
+    obj._description = desc;
+    return obj;
+};
+
+
+internals.Any.prototype.notes = function (notes) {
+
+    Hoek.assert(notes && (typeof notes === 'string' || Array.isArray(notes)), 'Notes must be a non-empty string or array');
+
+    var obj = this.clone();
+    obj._notes = obj._notes.concat(notes);
+    return obj;
+};
+
+
+internals.Any.prototype.tags = function (tags) {
+
+    Hoek.assert(tags && (typeof tags === 'string' || Array.isArray(tags)), 'Tags must be a non-empty string or array');
+
+    var obj = this.clone();
+    obj._tags = obj._tags.concat(tags);
+    return obj;
+};
+
+internals.Any.prototype.meta = function (meta) {
+
+    Hoek.assert(meta !== undefined, 'Meta cannot be undefined');
+
+    var obj = this.clone();
+    obj._meta = obj._meta.concat(meta);
+    return obj;
+};
+
+
+internals.Any.prototype.example = function (value) {
+
+    Hoek.assert(arguments.length, 'Missing example');
+    var result = this._validate(value, null, internals.defaults);
+    Hoek.assert(!result.errors, 'Bad example:', result.errors && Errors.process(result.errors, value));
+
+    var obj = this.clone();
+    obj._examples = obj._examples.concat(value);
+    return obj;
+};
+
+
+internals.Any.prototype.unit = function (name) {
+
+    Hoek.assert(name && typeof name === 'string', 'Unit name must be a non-empty string');
+
+    var obj = this.clone();
+    obj._unit = name;
+    return obj;
+};
+
+
+internals._try = function (fn, arg) {
+
+    var err;
+    var result;
+
+    try {
+        result = fn.call(null, arg);
+    } catch (e) {
+        err = e;
+    }
+
+    return {
+        value: result,
+        error: err
+    };
+};
+
+
+internals.Any.prototype._validate = function (value, state, options, reference) {
+
+    var self = this;
+    var originalValue = value;
+
+    // Setup state and settings
+
+    state = state || { key: '', path: '', parent: null, reference: reference };
+
+    if (this._settings) {
+        options = internals.concatSettings(options, this._settings);
+    }
+
+    var errors = [];
+    var finish = function () {
+
+        var finalValue;
+
+        if (!self._flags.strip) {
+            if (value !== undefined) {
+                finalValue = options.raw ? originalValue : value;
+            }
+            else if (options.noDefaults) {
+                finalValue = originalValue;
+            }
+            else if (Ref.isRef(self._flags.default)) {
+                finalValue = self._flags.default(state.parent, options);
+            }
+            else if (typeof self._flags.default === 'function' &&
+                    !(self._flags.func && !self._flags.default.description)) {
+
+                var arg;
+
+                if (state.parent !== null &&
+                    self._flags.default.length > 0) {
+
+                    arg = Hoek.clone(state.parent);
+                }
+
+                var defaultValue = internals._try(self._flags.default, arg);
+                finalValue = defaultValue.value;
+                if (defaultValue.error) {
+                    errors.push(Errors.create('any.default', defaultValue.error, state, options));
+                }
+            }
+            else {
+                finalValue = Hoek.clone(self._flags.default);
+            }
+        }
+
+        return {
+            value: finalValue,
+            errors: errors.length ? errors : null
+        };
+    };
+
+    // Check presence requirements
+
+    var presence = this._flags.presence || options.presence;
+    if (presence === 'optional') {
+        if (value === undefined) {
+            var isDeepDefault = this._flags.hasOwnProperty('default') && this._flags.default === undefined;
+            if (isDeepDefault && this._type === 'object') {
+                value = {};
+            }
+            else {
+                return finish();
+            }
+        }
+    }
+    else if (presence === 'required' &&
+            value === undefined) {
+
+        errors.push(Errors.create('any.required', null, state, options));
+        return finish();
+    }
+    else if (presence === 'forbidden') {
+        if (value === undefined) {
+            return finish();
+        }
+
+        errors.push(Errors.create('any.unknown', null, state, options));
+        return finish();
+    }
+
+    if (this._flags.empty && !this._flags.empty._validate(value, null, internals.defaults).errors) {
+        value = undefined;
+        return finish();
+    }
+
+    // Check allowed and denied values using the original value
+
+    if (this._valids.has(value, state, options, this._flags.insensitive)) {
+        return finish();
+    }
+
+    if (this._invalids.has(value, state, options, this._flags.insensitive)) {
+        errors.push(Errors.create(value === '' ? 'any.empty' : 'any.invalid', null, state, options));
+        if (options.abortEarly ||
+            value === undefined) {          // No reason to keep validating missing value
+
+            return finish();
+        }
+    }
+
+    // Convert value and validate type
+
+    if (this._base) {
+        var base = this._base.call(this, value, state, options);
+        if (base.errors) {
+            value = base.value;
+            errors = errors.concat(base.errors);
+            return finish();                            // Base error always aborts early
+        }
+
+        if (base.value !== value) {
+            value = base.value;
+
+            // Check allowed and denied values using the converted value
+
+            if (this._valids.has(value, state, options, this._flags.insensitive)) {
+                return finish();
+            }
+
+            if (this._invalids.has(value, state, options, this._flags.insensitive)) {
+                errors.push(Errors.create('any.invalid', null, state, options));
+                if (options.abortEarly) {
+                    return finish();
+                }
+            }
+        }
+    }
+
+    // Required values did not match
+
+    if (this._flags.allowOnly) {
+        errors.push(Errors.create('any.allowOnly', { valids: this._valids.values({ stripUndefined: true }) }, state, options));
+        if (options.abortEarly) {
+            return finish();
+        }
+    }
+
+    // Helper.validate tests
+
+    for (var i = 0, il = this._tests.length; i < il; ++i) {
+        var test = this._tests[i];
+        var err = test.func.call(this, value, state, options);
+        if (err) {
+            errors.push(err);
+            if (options.abortEarly) {
+                return finish();
+            }
+        }
+    }
+
+    return finish();
+};
+
+
+internals.Any.prototype._validateWithOptions = function (value, options, callback) {
+
+    if (options) {
+        internals.checkOptions(options);
+    }
+
+    var settings = internals.concatSettings(internals.defaults, options);
+    var result = this._validate(value, null, settings);
+    var errors = Errors.process(result.errors, value);
+
+    if (callback) {
+        return callback(errors, result.value);
+    }
+
+    return { error: errors, value: result.value };
+};
+
+
+internals.Any.prototype.validate = function (value, callback) {
+
+    var result = this._validate(value, null, internals.defaults);
+    var errors = Errors.process(result.errors, value);
+
+    if (callback) {
+        return callback(errors, result.value);
+    }
+
+    return { error: errors, value: result.value };
+};
+
+
+internals.Any.prototype.describe = function () {
+
+    var description = {
+        type: this._type
+    };
+
+    var flags = Object.keys(this._flags);
+    if (flags.length) {
+        if (this._flags.empty) {
+            description.flags = {};
+            for (var f = 0, fl = flags.length; f < fl; ++f) {
+                var flag = flags[f];
+                description.flags[flag] = flag === 'empty' ? this._flags[flag].describe() : this._flags[flag];
+            }
+        }
+        else {
+            description.flags = this._flags;
+        }
+    }
+
+    if (this._description) {
+        description.description = this._description;
+    }
+
+    if (this._notes.length) {
+        description.notes = this._notes;
+    }
+
+    if (this._tags.length) {
+        description.tags = this._tags;
+    }
+
+    if (this._meta.length) {
+        description.meta = this._meta;
+    }
+
+    if (this._examples.length) {
+        description.examples = this._examples;
+    }
+
+    if (this._unit) {
+        description.unit = this._unit;
+    }
+
+    var valids = this._valids.values();
+    if (valids.length) {
+        description.valids = valids;
+    }
+
+    var invalids = this._invalids.values();
+    if (invalids.length) {
+        description.invalids = invalids;
+    }
+
+    description.rules = [];
+
+    for (var i = 0, il = this._tests.length; i < il; ++i) {
+        var validator = this._tests[i];
+        var item = { name: validator.name };
+        if (validator.arg !== void 0) {
+            item.arg = validator.arg;
+        }
+        description.rules.push(item);
+    }
+
+    if (!description.rules.length) {
+        delete description.rules;
+    }
+
+    var label = Hoek.reach(this._settings, 'language.label');
+    if (label) {
+        description.label = label;
+    }
+
+    return description;
+};
+
+internals.Any.prototype.label = function (name) {
+
+    Hoek.assert(name && typeof name === 'string', 'Label name must be a non-empty string');
+
+    var obj = this.clone();
+    var options = { language: { label: name } };
+
+    // If language.label is set, it should override this label
+    obj._settings = internals.concatSettings(options, obj._settings);
+    return obj;
+};
+
+
+// Set
+
+internals.Set = function () {
+
+    this._set = [];
+};
+
+
+internals.Set.prototype.add = function (value, refs) {
+
+    Hoek.assert(value === null || value === undefined || value instanceof Date || Buffer.isBuffer(value) || Ref.isRef(value) || (typeof value !== 'function' && typeof value !== 'object'), 'Value cannot be an object or function');
+
+    if (typeof value !== 'function' &&
+        this.has(value, null, null, false)) {
+
+        return;
+    }
+
+    Ref.push(refs, value);
+    this._set.push(value);
+};
+
+
+internals.Set.prototype.merge = function (add, remove) {
+
+    for (var i = 0, il = add._set.length; i < il; ++i) {
+        this.add(add._set[i]);
+    }
+
+    for (i = 0, il = remove._set.length; i < il; ++i) {
+        this.remove(remove._set[i]);
+    }
+};
+
+
+internals.Set.prototype.remove = function (value) {
+
+    this._set = this._set.filter(function (item) {
+
+        return value !== item;
+    });
+};
+
+
+internals.Set.prototype.has = function (value, state, options, insensitive) {
+
+    for (var i = 0, il = this._set.length; i < il; ++i) {
+        var items = this._set[i];
+
+        if (Ref.isRef(items)) {
+            items = items(state.reference || state.parent, options);
+        }
+
+        if (!Array.isArray(items)) {
+            items = [items];
+        }
+
+        for (var j = 0, jl = items.length; j < jl; ++j) {
+            var item = items[j];
+            if (typeof value !== typeof item) {
+                continue;
+            }
+
+            if (value === item ||
+                (value instanceof Date && item instanceof Date && value.getTime() === item.getTime()) ||
+                (insensitive && typeof value === 'string' && value.toLowerCase() === item.toLowerCase()) ||
+                (Buffer.isBuffer(value) && Buffer.isBuffer(item) && value.length === item.length && value.toString('binary') === item.toString('binary'))) {
+
+                return true;
+            }
+        }
+    }
+
+    return false;
+};
+
+
+internals.Set.prototype.values = function (options) {
+
+    if (options && options.stripUndefined) {
+        var values = [];
+
+        for (var i = 0, il = this._set.length; i < il; ++i) {
+            var item = this._set[i];
+            if (item !== undefined) {
+                values.push(item);
+            }
+        }
+
+        return values;
+    }
+
+    return this._set.slice();
+};
+
+
+internals.concatSettings = function (target, source) {
+
+    // Used to avoid cloning context
+
+    if (!target &&
+        !source) {
+
+        return null;
+    }
+
+    var key, obj = {};
+
+    if (target) {
+        var tKeys = Object.keys(target);
+        for (var i = 0, il = tKeys.length; i < il; ++i) {
+            key = tKeys[i];
+            obj[key] = target[key];
+        }
+    }
+
+    if (source) {
+        var sKeys = Object.keys(source);
+        for (var j = 0, jl = sKeys.length; j < jl; ++j) {
+            key = sKeys[j];
+            if (key !== 'language' ||
+                !obj.hasOwnProperty(key)) {
+
+                obj[key] = source[key];
+            }
+            else {
+                obj[key] = Hoek.applyToDefaults(obj[key], source[key]);
+            }
+        }
+    }
+
+    return obj;
+};
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/array.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/array.js
new file mode 100755
index 0000000000000000000000000000000000000000..9299ceea7698f304b86d85f8c6d8bbce506e2b5e
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/array.js
@@ -0,0 +1,517 @@
+// Load modules
+
+var Any = require('./any');
+var Cast = require('./cast');
+var Errors = require('./errors');
+var Hoek = require('hoek');
+
+
+// Declare internals
+
+var internals = {};
+
+
+internals.fastSplice = function (arr, i) {
+
+    var il = arr.length;
+    var pos = i;
+
+    while (pos < il) {
+        arr[pos++] = arr[pos];
+    }
+
+    --arr.length;
+};
+
+
+internals.Array = function () {
+
+    Any.call(this);
+    this._type = 'array';
+    this._inner.items = [];
+    this._inner.ordereds = [];
+    this._inner.inclusions = [];
+    this._inner.exclusions = [];
+    this._inner.requireds = [];
+    this._flags.sparse = false;
+};
+
+Hoek.inherits(internals.Array, Any);
+
+
+internals.Array.prototype._base = function (value, state, options) {
+
+    var result = {
+        value: value
+    };
+
+    if (typeof value === 'string' &&
+        options.convert) {
+
+        try {
+            var converted = JSON.parse(value);
+            if (Array.isArray(converted)) {
+                result.value = converted;
+            }
+        }
+        catch (e) { }
+    }
+
+    var isArray = Array.isArray(result.value);
+    var wasArray = isArray;
+    if (options.convert && this._flags.single && !isArray) {
+        result.value = [result.value];
+        isArray = true;
+    }
+
+    if (!isArray) {
+        result.errors = Errors.create('array.base', null, state, options);
+        return result;
+    }
+
+    if (this._inner.inclusions.length ||
+        this._inner.exclusions.length ||
+        !this._flags.sparse) {
+
+        // Clone the array so that we don't modify the original
+        if (wasArray) {
+            result.value = result.value.slice(0);
+        }
+
+        result.errors = internals.checkItems.call(this, result.value, wasArray, state, options);
+
+        if (result.errors && wasArray && options.convert && this._flags.single) {
+
+            // Attempt a 2nd pass by putting the array inside one.
+            var previousErrors = result.errors;
+
+            result.value = [result.value];
+            result.errors = internals.checkItems.call(this, result.value, wasArray, state, options);
+
+            if (result.errors) {
+
+                // Restore previous errors and value since this didn't validate either.
+                result.errors = previousErrors;
+                result.value = result.value[0];
+            }
+        }
+    }
+
+    return result;
+};
+
+
+internals.checkItems = function (items, wasArray, state, options) {
+
+    var errors = [];
+    var errored;
+
+    var requireds = this._inner.requireds.slice();
+    var ordereds = this._inner.ordereds.slice();
+    var inclusions = this._inner.inclusions.concat(requireds);
+
+    for (var v = 0, vl = items.length; v < vl; ++v) {
+        errored = false;
+        var item = items[v];
+        var isValid = false;
+        var localState = { key: v, path: (state.path ? state.path + '.' : '') + v, parent: items, reference: state.reference };
+        var res;
+
+        // Sparse
+
+        if (!this._flags.sparse && item === undefined) {
+            errors.push(Errors.create('array.sparse', null, { key: state.key, path: localState.path }, options));
+
+            if (options.abortEarly) {
+                return errors;
+            }
+
+            continue;
+        }
+
+        // Exclusions
+
+        for (var i = 0, il = this._inner.exclusions.length; i < il; ++i) {
+            res = this._inner.exclusions[i]._validate(item, localState, {});                // Not passing options to use defaults
+
+            if (!res.errors) {
+                errors.push(Errors.create(wasArray ? 'array.excludes' : 'array.excludesSingle', { pos: v, value: item }, { key: state.key, path: localState.path }, options));
+                errored = true;
+
+                if (options.abortEarly) {
+                    return errors;
+                }
+
+                break;
+            }
+        }
+
+        if (errored) {
+            continue;
+        }
+
+        // Ordered
+        if (this._inner.ordereds.length) {
+            if (ordereds.length > 0) {
+                var ordered = ordereds.shift();
+                res = ordered._validate(item, localState, options);
+                if (!res.errors) {
+                    if (ordered._flags.strip) {
+                        internals.fastSplice(items, v);
+                        --v;
+                        --vl;
+                    }
+                    else {
+                        items[v] = res.value;
+                    }
+                }
+                else {
+                    errors.push(Errors.create('array.ordered', { pos: v, reason: res.errors, value: item }, { key: state.key, path: localState.path }, options));
+                    if (options.abortEarly) {
+                        return errors;
+                    }
+                }
+                continue;
+            }
+            else if (!this._inner.items.length) {
+                errors.push(Errors.create('array.orderedLength', { pos: v, limit: this._inner.ordereds.length }, { key: state.key, path: localState.path }, options));
+                if (options.abortEarly) {
+                    return errors;
+                }
+                continue;
+            }
+        }
+
+        // Requireds
+
+        var requiredChecks = [];
+        for (i = 0, il = requireds.length; i < il; ++i) {
+            res = requiredChecks[i] = requireds[i]._validate(item, localState, options);
+            if (!res.errors) {
+                items[v] = res.value;
+                isValid = true;
+                internals.fastSplice(requireds, i);
+                --i;
+                --il;
+                break;
+            }
+        }
+
+        if (isValid) {
+            continue;
+        }
+
+        // Inclusions
+
+        for (i = 0, il = inclusions.length; i < il; ++i) {
+            var inclusion = inclusions[i];
+
+            // Avoid re-running requireds that already didn't match in the previous loop
+            var previousCheck = requireds.indexOf(inclusion);
+            if (previousCheck !== -1) {
+                res = requiredChecks[previousCheck];
+            }
+            else {
+                res = inclusion._validate(item, localState, options);
+
+                if (!res.errors) {
+                    if (inclusion._flags.strip) {
+                        internals.fastSplice(items, v);
+                        --v;
+                        --vl;
+                    }
+                    else {
+                        items[v] = res.value;
+                    }
+                    isValid = true;
+                    break;
+                }
+            }
+
+            // Return the actual error if only one inclusion defined
+            if (il === 1) {
+                if (options.stripUnknown) {
+                    internals.fastSplice(items, v);
+                    --v;
+                    --vl;
+                    isValid = true;
+                    break;
+                }
+
+                errors.push(Errors.create(wasArray ? 'array.includesOne' : 'array.includesOneSingle', { pos: v, reason: res.errors, value: item }, { key: state.key, path: localState.path }, options));
+                errored = true;
+
+                if (options.abortEarly) {
+                    return errors;
+                }
+
+                break;
+            }
+        }
+
+        if (errored) {
+            continue;
+        }
+
+        if (this._inner.inclusions.length && !isValid) {
+            if (options.stripUnknown) {
+                internals.fastSplice(items, v);
+                --v;
+                --vl;
+                continue;
+            }
+
+            errors.push(Errors.create(wasArray ? 'array.includes' : 'array.includesSingle', { pos: v, value: item }, { key: state.key, path: localState.path }, options));
+
+            if (options.abortEarly) {
+                return errors;
+            }
+        }
+    }
+
+    if (requireds.length) {
+        internals.fillMissedErrors(errors, requireds, state, options);
+    }
+
+    if (ordereds.length) {
+        internals.fillOrderedErrors(errors, ordereds, state, options);
+    }
+
+    return errors.length ? errors : null;
+};
+
+internals.fillMissedErrors = function (errors, requireds, state, options) {
+
+    var knownMisses = [];
+    var unknownMisses = 0;
+    for (var i = 0, il = requireds.length; i < il; ++i) {
+        var label = Hoek.reach(requireds[i], '_settings.language.label');
+        if (label) {
+            knownMisses.push(label);
+        }
+        else {
+            ++unknownMisses;
+        }
+    }
+
+    if (knownMisses.length) {
+        if (unknownMisses) {
+            errors.push(Errors.create('array.includesRequiredBoth', { knownMisses: knownMisses, unknownMisses: unknownMisses }, { key: state.key, path: state.patk }, options));
+        }
+        else {
+            errors.push(Errors.create('array.includesRequiredKnowns', { knownMisses: knownMisses }, { key: state.key, path: state.path }, options));
+        }
+    }
+    else {
+        errors.push(Errors.create('array.includesRequiredUnknowns', { unknownMisses: unknownMisses }, { key: state.key, path: state.path }, options));
+    }
+};
+
+internals.fillOrderedErrors = function (errors, ordereds, state, options) {
+
+    var requiredOrdereds = [];
+
+    for (var i = 0, il = ordereds.length; i < il; ++i) {
+        var presence = Hoek.reach(ordereds[i], '_flags.presence');
+        if (presence === 'required') {
+            requiredOrdereds.push(ordereds[i]);
+        }
+    }
+
+    if (requiredOrdereds.length) {
+        internals.fillMissedErrors(errors, requiredOrdereds, state, options);
+    }
+};
+
+internals.Array.prototype.describe = function () {
+
+    var description = Any.prototype.describe.call(this);
+
+    if (this._inner.ordereds.length) {
+        description.orderedItems = [];
+
+        for (var o = 0, ol = this._inner.ordereds.length; o < ol; ++o) {
+            description.orderedItems.push(this._inner.ordereds[o].describe());
+        }
+    }
+
+    if (this._inner.items.length) {
+        description.items = [];
+
+        for (var i = 0, il = this._inner.items.length; i < il; ++i) {
+            description.items.push(this._inner.items[i].describe());
+        }
+    }
+
+    return description;
+};
+
+
+internals.Array.prototype.items = function () {
+
+    var obj = this.clone();
+
+    Hoek.flatten(Array.prototype.slice.call(arguments)).forEach(function (type, index) {
+
+        try {
+            type = Cast.schema(type);
+        }
+        catch (castErr) {
+            if (castErr.hasOwnProperty('path')) {
+                castErr.path = index + '.' + castErr.path;
+            }
+            else {
+                castErr.path = index;
+            }
+            castErr.message += '(' + castErr.path + ')';
+            throw castErr;
+        }
+
+        obj._inner.items.push(type);
+
+        if (type._flags.presence === 'required') {
+            obj._inner.requireds.push(type);
+        }
+        else if (type._flags.presence === 'forbidden') {
+            obj._inner.exclusions.push(type.optional());
+        }
+        else {
+            obj._inner.inclusions.push(type);
+        }
+    });
+
+    return obj;
+};
+
+
+internals.Array.prototype.ordered = function () {
+
+    var obj = this.clone();
+
+    Hoek.flatten(Array.prototype.slice.call(arguments)).forEach(function (type, index) {
+
+        try {
+            type = Cast.schema(type);
+        }
+        catch (castErr) {
+            if (castErr.hasOwnProperty('path')) {
+                castErr.path = index + '.' + castErr.path;
+            }
+            else {
+                castErr.path = index;
+            }
+            castErr.message += '(' + castErr.path + ')';
+            throw castErr;
+        }
+        obj._inner.ordereds.push(type);
+    });
+
+    return obj;
+};
+
+
+internals.Array.prototype.min = function (limit) {
+
+    Hoek.assert(Hoek.isInteger(limit) && limit >= 0, 'limit must be a positive integer');
+
+    return this._test('min', limit, function (value, state, options) {
+
+        if (value.length >= limit) {
+            return null;
+        }
+
+        return Errors.create('array.min', { limit: limit, value: value }, state, options);
+    });
+};
+
+
+internals.Array.prototype.max = function (limit) {
+
+    Hoek.assert(Hoek.isInteger(limit) && limit >= 0, 'limit must be a positive integer');
+
+    return this._test('max', limit, function (value, state, options) {
+
+        if (value.length <= limit) {
+            return null;
+        }
+
+        return Errors.create('array.max', { limit: limit, value: value }, state, options);
+    });
+};
+
+
+internals.Array.prototype.length = function (limit) {
+
+    Hoek.assert(Hoek.isInteger(limit) && limit >= 0, 'limit must be a positive integer');
+
+    return this._test('length', limit, function (value, state, options) {
+
+        if (value.length === limit) {
+            return null;
+        }
+
+        return Errors.create('array.length', { limit: limit, value: value }, state, options);
+    });
+};
+
+
+internals.Array.prototype.unique = function () {
+
+    return this._test('unique', undefined, function (value, state, options) {
+
+        var found = {
+            string: {},
+            number: {},
+            undefined: {},
+            boolean: {},
+            object: [],
+            function: []
+        };
+
+        for (var i = 0, il = value.length; i < il; ++i) {
+            var item = value[i];
+            var type = typeof item;
+            var records = found[type];
+
+            // All available types are supported, so it's not possible to reach 100% coverage without ignoring this line.
+            // I still want to keep the test for future js versions with new types (eg. Symbol).
+            if (/* $lab:coverage:off$ */ records /* $lab:coverage:on$ */) {
+                if (Array.isArray(records)) {
+                    for (var r = 0, rl = records.length; r < rl; ++r) {
+                        if (Hoek.deepEqual(records[r], item)) {
+                            return Errors.create('array.unique', { pos: i, value: item }, state, options);
+                        }
+                    }
+
+                    records.push(item);
+                }
+                else {
+                    if (records[item]) {
+                        return Errors.create('array.unique', { pos: i, value: item }, state, options);
+                    }
+
+                    records[item] = true;
+                }
+            }
+        }
+    });
+};
+
+
+internals.Array.prototype.sparse = function (enabled) {
+
+    var obj = this.clone();
+    obj._flags.sparse = enabled === undefined ? true : !!enabled;
+    return obj;
+};
+
+
+internals.Array.prototype.single = function (enabled) {
+
+    var obj = this.clone();
+    obj._flags.single = enabled === undefined ? true : !!enabled;
+    return obj;
+};
+
+
+module.exports = new internals.Array();
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/binary.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/binary.js
new file mode 100755
index 0000000000000000000000000000000000000000..ee8b1e2d1f17da81e7680192d3cd86523604469c
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/binary.js
@@ -0,0 +1,98 @@
+// Load modules
+
+var Any = require('./any');
+var Errors = require('./errors');
+var Hoek = require('hoek');
+
+
+// Declare internals
+
+var internals = {};
+
+
+internals.Binary = function () {
+
+    Any.call(this);
+    this._type = 'binary';
+};
+
+Hoek.inherits(internals.Binary, Any);
+
+
+internals.Binary.prototype._base = function (value, state, options) {
+
+    var result = {
+        value: value
+    };
+
+    if (typeof value === 'string' &&
+        options.convert) {
+
+        try {
+            var converted = new Buffer(value, this._flags.encoding);
+            result.value = converted;
+        }
+        catch (e) { }
+    }
+
+    result.errors = Buffer.isBuffer(result.value) ? null : Errors.create('binary.base', null, state, options);
+    return result;
+};
+
+
+internals.Binary.prototype.encoding = function (encoding) {
+
+    Hoek.assert(Buffer.isEncoding(encoding), 'Invalid encoding:', encoding);
+
+    var obj = this.clone();
+    obj._flags.encoding = encoding;
+    return obj;
+};
+
+
+internals.Binary.prototype.min = function (limit) {
+
+    Hoek.assert(Hoek.isInteger(limit) && limit >= 0, 'limit must be a positive integer');
+
+    return this._test('min', limit, function (value, state, options) {
+
+        if (value.length >= limit) {
+            return null;
+        }
+
+        return Errors.create('binary.min', { limit: limit, value: value }, state, options);
+    });
+};
+
+
+internals.Binary.prototype.max = function (limit) {
+
+    Hoek.assert(Hoek.isInteger(limit) && limit >= 0, 'limit must be a positive integer');
+
+    return this._test('max', limit, function (value, state, options) {
+
+        if (value.length <= limit) {
+            return null;
+        }
+
+        return Errors.create('binary.max', { limit: limit, value: value }, state, options);
+    });
+};
+
+
+internals.Binary.prototype.length = function (limit) {
+
+    Hoek.assert(Hoek.isInteger(limit) && limit >= 0, 'limit must be a positive integer');
+
+    return this._test('length', limit, function (value, state, options) {
+
+        if (value.length === limit) {
+            return null;
+        }
+
+        return Errors.create('binary.length', { limit: limit, value: value }, state, options);
+    });
+};
+
+
+module.exports = new internals.Binary();
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/boolean.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/boolean.js
new file mode 100755
index 0000000000000000000000000000000000000000..9e4f4b72d330d1dc29bf53d763e1fb20383e2bb3
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/boolean.js
@@ -0,0 +1,41 @@
+// Load modules
+
+var Any = require('./any');
+var Errors = require('./errors');
+var Hoek = require('hoek');
+
+
+// Declare internals
+
+var internals = {};
+
+
+internals.Boolean = function () {
+
+    Any.call(this);
+    this._type = 'boolean';
+};
+
+Hoek.inherits(internals.Boolean, Any);
+
+
+internals.Boolean.prototype._base = function (value, state, options) {
+
+    var result = {
+        value: value
+    };
+
+    if (typeof value === 'string' &&
+        options.convert) {
+
+        var lower = value.toLowerCase();
+        result.value = (lower === 'true' || lower === 'yes' || lower === 'on' ? true
+                                                                              : (lower === 'false' || lower === 'no' || lower === 'off' ? false : value));
+    }
+
+    result.errors = (typeof result.value === 'boolean') ? null : Errors.create('boolean.base', null, state, options);
+    return result;
+};
+
+
+module.exports = new internals.Boolean();
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/cast.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/cast.js
new file mode 100755
index 0000000000000000000000000000000000000000..88f7e14014398e9bee37141cd857fcfb856889e5
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/cast.js
@@ -0,0 +1,75 @@
+// Load modules
+
+var Hoek = require('hoek');
+var Ref = require('./ref');
+
+// Type modules are delay-loaded to prevent circular dependencies
+
+
+// Declare internals
+
+var internals = {
+    any: null,
+    date: require('./date'),
+    string: require('./string'),
+    number: require('./number'),
+    boolean: require('./boolean'),
+    alt: null,
+    object: null
+};
+
+
+exports.schema = function (config) {
+
+    internals.any = internals.any || new (require('./any'))();
+    internals.alt = internals.alt || require('./alternatives');
+    internals.object = internals.object || require('./object');
+
+    if (config &&
+        typeof config === 'object') {
+
+        if (config.isJoi) {
+            return config;
+        }
+
+        if (Array.isArray(config)) {
+            return internals.alt.try(config);
+        }
+
+        if (config instanceof RegExp) {
+            return internals.string.regex(config);
+        }
+
+        if (config instanceof Date) {
+            return internals.date.valid(config);
+        }
+
+        return internals.object.keys(config);
+    }
+
+    if (typeof config === 'string') {
+        return internals.string.valid(config);
+    }
+
+    if (typeof config === 'number') {
+        return internals.number.valid(config);
+    }
+
+    if (typeof config === 'boolean') {
+        return internals.boolean.valid(config);
+    }
+
+    if (Ref.isRef(config)) {
+        return internals.any.valid(config);
+    }
+
+    Hoek.assert(config === null, 'Invalid schema content:', config);
+
+    return internals.any.valid(null);
+};
+
+
+exports.ref = function (id) {
+
+    return Ref.isRef(id) ? id : Ref.create(id);
+};
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/date.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/date.js
new file mode 100755
index 0000000000000000000000000000000000000000..79957fd08f1af406ae7e3bb56ab5be1feb022a53
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/date.js
@@ -0,0 +1,168 @@
+// Load modules
+
+var Any = require('./any');
+var Errors = require('./errors');
+var Ref = require('./ref');
+var Hoek = require('hoek');
+var Moment = require('moment');
+
+
+// Declare internals
+
+var internals = {};
+
+internals.isoDate = /^(?:\d{4}(?!\d{2}\b))(?:(-?)(?:(?:0[1-9]|1[0-2])(?:\1(?:[12]\d|0[1-9]|3[01]))?|W(?:[0-4]\d|5[0-2])(?:-?[1-7])?|(?:00[1-9]|0[1-9]\d|[12]\d{2}|3(?:[0-5]\d|6[1-6])))(?![T]$|[T][\d]+Z$)(?:[T\s](?:(?:(?:[01]\d|2[0-3])(?:(:?)[0-5]\d)?|24\:?00)(?:[.,]\d+(?!:))?)(?:\2[0-5]\d(?:[.,]\d+)?)?(?:[Z]|(?:[+-])(?:[01]\d|2[0-3])(?::?[0-5]\d)?)?)?)?$/;
+internals.invalidDate = new Date('');
+internals.isIsoDate = (function () {
+
+    var isoString = internals.isoDate.toString();
+
+    return function (date) {
+
+        return date && (date.toString() === isoString);
+    };
+})();
+
+internals.Date = function () {
+
+    Any.call(this);
+    this._type = 'date';
+};
+
+Hoek.inherits(internals.Date, Any);
+
+
+internals.Date.prototype._base = function (value, state, options) {
+
+    var result = {
+        value: (options.convert && internals.toDate(value, this._flags.format)) || value
+    };
+
+    if (result.value instanceof Date && !isNaN(result.value.getTime())) {
+        result.errors = null;
+    }
+    else {
+        result.errors = Errors.create(internals.isIsoDate(this._flags.format) ? 'date.isoDate' : 'date.base', null, state, options);
+    }
+
+    return result;
+};
+
+
+internals.toDate = function (value, format) {
+
+    if (value instanceof Date) {
+        return value;
+    }
+
+    if (typeof value === 'string' ||
+        Hoek.isInteger(value)) {
+
+        if (typeof value === 'string' &&
+            /^[+-]?\d+$/.test(value)) {
+
+            value = parseInt(value, 10);
+        }
+
+        var date;
+        if (format) {
+            if (internals.isIsoDate(format)) {
+                date = format.test(value) ? new Date(value) : internals.invalidDate;
+            }
+            else {
+                date = Moment(value, format, true);
+                date = date.isValid() ? date.toDate() : internals.invalidDate;
+            }
+        }
+        else {
+            date = new Date(value);
+        }
+
+        if (!isNaN(date.getTime())) {
+            return date;
+        }
+    }
+
+    return null;
+};
+
+
+internals.compare = function (type, compare) {
+
+    return function (date) {
+
+        var isNow = date === 'now';
+        var isRef = Ref.isRef(date);
+
+        if (!isNow && !isRef) {
+            date = internals.toDate(date);
+        }
+
+        Hoek.assert(date, 'Invalid date format');
+
+        return this._test(type, date, function (value, state, options) {
+
+            var compareTo;
+            if (isNow) {
+                compareTo = Date.now();
+            }
+            else if (isRef) {
+                compareTo = internals.toDate(date(state.parent, options));
+
+                if (!compareTo) {
+                    return Errors.create('date.ref', { ref: date.key }, state, options);
+                }
+
+                compareTo = compareTo.getTime();
+            }
+            else {
+                compareTo = date.getTime();
+            }
+
+            if (compare(value.getTime(), compareTo)) {
+                return null;
+            }
+
+            return Errors.create('date.' + type, { limit: new Date(compareTo) }, state, options);
+        });
+    };
+};
+
+
+internals.Date.prototype.min = internals.compare('min', function (value, date) {
+
+    return value >= date;
+});
+
+
+internals.Date.prototype.max = internals.compare('max', function (value, date) {
+
+    return value <= date;
+});
+
+
+internals.Date.prototype.format = function (format) {
+
+    Hoek.assert(typeof format === 'string' || (Array.isArray(format) && format.every(function (f) {
+
+        return typeof f === 'string';
+    })), 'Invalid format.');
+
+    var obj = this.clone();
+    obj._flags.format = format;
+    return obj;
+};
+
+internals.Date.prototype.iso = function () {
+
+    var obj = this.clone();
+    obj._flags.format = internals.isoDate;
+    return obj;
+};
+
+internals.Date.prototype._isIsoDate = function (value) {
+
+    return internals.isoDate.test(value);
+};
+
+module.exports = new internals.Date();
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/errors.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/errors.js
new file mode 100755
index 0000000000000000000000000000000000000000..566bfc6426e4831188fc0faad0bc8d77cbf2e8e0
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/errors.js
@@ -0,0 +1,297 @@
+// Load modules
+
+var Hoek = require('hoek');
+var Language = require('./language');
+
+
+// Declare internals
+
+var internals = {};
+
+internals.stringify = function (value, wrapArrays) {
+
+    var type = typeof value;
+
+    if (value === null) {
+        return 'null';
+    }
+
+    if (type === 'string') {
+        return value;
+    }
+
+    if (value instanceof internals.Err || type === 'function') {
+        return value.toString();
+    }
+
+    if (type === 'object') {
+        if (Array.isArray(value)) {
+            var partial = '';
+
+            for (var i = 0, il = value.length; i < il; ++i) {
+                partial += (partial.length ? ', ' : '') + internals.stringify(value[i], wrapArrays);
+            }
+
+            return wrapArrays ? '[' + partial + ']' : partial;
+        }
+
+        return value.toString();
+    }
+
+    return JSON.stringify(value);
+};
+
+internals.Err = function (type, context, state, options) {
+
+    this.type = type;
+    this.context = context || {};
+    this.context.key = state.key;
+    this.path = state.path;
+    this.options = options;
+};
+
+
+internals.Err.prototype.toString = function () {
+
+    var self = this;
+
+    var localized = this.options.language;
+
+    if (localized.label) {
+        this.context.key = localized.label;
+    }
+    else if (this.context.key === '' || this.context.key === null) {
+        this.context.key = localized.root || Language.errors.root;
+    }
+
+    var format = Hoek.reach(localized, this.type) || Hoek.reach(Language.errors, this.type);
+    var hasKey = /\{\{\!?key\}\}/.test(format);
+    var skipKey = format.length > 2 && format[0] === '!' && format[1] === '!';
+
+    if (skipKey) {
+        format = format.slice(2);
+    }
+
+    if (!hasKey && !skipKey) {
+        format = (Hoek.reach(localized, 'key') || Hoek.reach(Language.errors, 'key')) + format;
+    }
+
+    var wrapArrays = Hoek.reach(localized, 'messages.wrapArrays');
+    if (typeof wrapArrays !== 'boolean') {
+        wrapArrays = Language.errors.messages.wrapArrays;
+    }
+
+    var message = format.replace(/\{\{(\!?)([^}]+)\}\}/g, function ($0, isSecure, name) {
+
+        var value = Hoek.reach(self.context, name);
+        var normalized = internals.stringify(value, wrapArrays);
+        return (isSecure ? Hoek.escapeHtml(normalized) : normalized);
+    });
+
+    return message;
+};
+
+
+exports.create = function (type, context, state, options) {
+
+    return new internals.Err(type, context, state, options);
+};
+
+
+exports.process = function (errors, object) {
+
+    if (!errors || !errors.length) {
+        return null;
+    }
+
+    // Construct error
+
+    var message = '';
+    var details = [];
+
+    var processErrors = function (localErrors, parent) {
+
+        for (var i = 0, il = localErrors.length; i < il; ++i) {
+            var item = localErrors[i];
+
+            var detail = {
+                message: item.toString(),
+                path: internals.getPath(item),
+                type: item.type,
+                context: item.context
+            };
+
+            if (!parent) {
+                message += (message ? '. ' : '') + detail.message;
+            }
+
+            // Do not push intermediate errors, we're only interested in leafs
+            if (item.context.reason && item.context.reason.length) {
+                processErrors(item.context.reason, item.path);
+            }
+            else {
+                details.push(detail);
+            }
+        }
+    };
+
+    processErrors(errors);
+
+    var error = new Error(message);
+    error.name = 'ValidationError';
+    error.details = details;
+    error._object = object;
+    error.annotate = internals.annotate;
+    return error;
+};
+
+
+internals.getPath = function (item) {
+
+    var recursePath = function (it) {
+
+        var reachedItem = Hoek.reach(it, 'context.reason.0');
+        if (reachedItem && reachedItem.context) {
+            return recursePath(reachedItem);
+        }
+
+        return it.path;
+    };
+
+    return recursePath(item) || item.context.key;
+};
+
+
+// Inspired by json-stringify-safe
+internals.safeStringify = function (obj, spaces) {
+
+    return JSON.stringify(obj, internals.serializer(), spaces);
+};
+
+internals.serializer = function () {
+
+    var cycleReplacer = function (key, value) {
+
+        if (stack[0] === value) {
+            return '[Circular ~]';
+        }
+
+        return '[Circular ~.' + keys.slice(0, stack.indexOf(value)).join('.') + ']';
+    };
+
+    var keys = [], stack = [];
+
+    return function (key, value) {
+
+        if (stack.length > 0) {
+            var thisPos = stack.indexOf(this);
+            if (~thisPos) {
+                stack.length = thisPos + 1;
+                keys.length = thisPos + 1;
+                keys[thisPos] = key;
+            }
+            else {
+                stack.push(this);
+                keys.push(key);
+            }
+
+            if (~stack.indexOf(value)) {
+                value = cycleReplacer.call(this, key, value);
+            }
+        }
+        else {
+            stack.push(value);
+        }
+
+        if (Array.isArray(value) && value.placeholders) {
+            var placeholders = value.placeholders;
+            var arrWithPlaceholders = [];
+            for (var i = 0, il = value.length; i < il; ++i) {
+                if (placeholders[i]) {
+                    arrWithPlaceholders.push(placeholders[i]);
+                }
+                arrWithPlaceholders.push(value[i]);
+            }
+
+            value = arrWithPlaceholders;
+        }
+
+        return value;
+    };
+};
+
+
+internals.annotate = function () {
+
+    var obj = Hoek.clone(this._object || {});
+
+    var lookup = {};
+    var el = this.details.length;
+    for (var e = el - 1; e >= 0; --e) {        // Reverse order to process deepest child first
+        var pos = el - e;
+        var error = this.details[e];
+        var path = error.path.split('.');
+        var ref = obj;
+        for (var i = 0, il = path.length; i < il && ref; ++i) {
+            var seg = path[i];
+            if (i + 1 < il) {
+                ref = ref[seg];
+            }
+            else {
+                var value = ref[seg];
+                if (Array.isArray(ref)) {
+                    var arrayLabel = '_$idx$_' + (e + 1) + '_$end$_';
+                    if (!ref.placeholders) {
+                        ref.placeholders = {};
+                    }
+
+                    if (ref.placeholders[seg]) {
+                        ref.placeholders[seg] = ref.placeholders[seg].replace('_$end$_', ', ' + (e + 1) + '_$end$_');
+                    }
+                    else {
+                        ref.placeholders[seg] = arrayLabel;
+                    }
+                } else {
+                    if (value !== undefined) {
+                        delete ref[seg];
+                        var objectLabel = seg + '_$key$_' + pos + '_$end$_';
+                        ref[objectLabel] = value;
+                        lookup[error.path] = objectLabel;
+                    }
+                    else if (lookup[error.path]) {
+                        var replacement = lookup[error.path];
+                        var appended = replacement.replace('_$end$_', ', ' + pos + '_$end$_');
+                        ref[appended] = ref[replacement];
+                        lookup[error.path] = appended;
+                        delete ref[replacement];
+                    }
+                    else {
+                        ref['_$miss$_' + seg + '|' + pos + '_$end$_'] = '__missing__';
+                    }
+                }
+            }
+        }
+    }
+
+    var message = internals.safeStringify(obj, 2)
+        .replace(/_\$key\$_([, \d]+)_\$end\$_\"/g, function ($0, $1) {
+
+            return '" \u001b[31m[' + $1 + ']\u001b[0m';
+        }).replace(/\"_\$miss\$_([^\|]+)\|(\d+)_\$end\$_\"\: \"__missing__\"/g, function ($0, $1, $2) {
+
+            return '\u001b[41m"' + $1 + '"\u001b[0m\u001b[31m [' + $2 + ']: -- missing --\u001b[0m';
+        }).replace(/\s*\"_\$idx\$_([, \d]+)_\$end\$_\",?\n(.*)/g, function ($0, $1, $2) {
+
+            return '\n' + $2 + ' \u001b[31m[' + $1 + ']\u001b[0m';
+        });
+
+    message += '\n\u001b[31m';
+
+    for (e = 0; e < el; ++e) {
+        message += '\n[' + (e + 1) + '] ' + this.details[e].message;
+    }
+
+    message += '\u001b[0m';
+
+    return message;
+};
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/index.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/index.js
new file mode 100755
index 0000000000000000000000000000000000000000..50f87b4f78bd6093a3de1f7d5fc138b5c0ff7b46
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/index.js
@@ -0,0 +1,152 @@
+// Load modules
+
+var Any = require('./any');
+var Cast = require('./cast');
+var Ref = require('./ref');
+
+
+// Declare internals
+
+var internals = {
+    alternatives: require('./alternatives'),
+    array: require('./array'),
+    boolean: require('./boolean'),
+    binary: require('./binary'),
+    date: require('./date'),
+    number: require('./number'),
+    object: require('./object'),
+    string: require('./string')
+};
+
+
+internals.root = function () {
+
+    var any = new Any();
+
+    var root = any.clone();
+    root.any = function () {
+
+        return any;
+    };
+
+    root.alternatives = root.alt = function () {
+
+        return arguments.length ? internals.alternatives.try.apply(internals.alternatives, arguments) : internals.alternatives;
+    };
+
+    root.array = function () {
+
+        return internals.array;
+    };
+
+    root.boolean = root.bool = function () {
+
+        return internals.boolean;
+    };
+
+    root.binary = function () {
+
+        return internals.binary;
+    };
+
+    root.date = function () {
+
+        return internals.date;
+    };
+
+    root.func = function () {
+
+        return internals.object._func();
+    };
+
+    root.number = function () {
+
+        return internals.number;
+    };
+
+    root.object = function () {
+
+        return arguments.length ? internals.object.keys.apply(internals.object, arguments) : internals.object;
+    };
+
+    root.string = function () {
+
+        return internals.string;
+    };
+
+    root.ref = function () {
+
+        return Ref.create.apply(null, arguments);
+    };
+
+    root.isRef = function (ref) {
+
+        return Ref.isRef(ref);
+    };
+
+    root.validate = function (value /*, [schema], [options], callback */) {
+
+        var last = arguments[arguments.length - 1];
+        var callback = typeof last === 'function' ? last : null;
+
+        var count = arguments.length - (callback ? 1 : 0);
+        if (count === 1) {
+            return any.validate(value, callback);
+        }
+
+        var options = count === 3 ? arguments[2] : {};
+        var schema = root.compile(arguments[1]);
+
+        return schema._validateWithOptions(value, options, callback);
+    };
+
+    root.describe = function () {
+
+        var schema = arguments.length ? root.compile(arguments[0]) : any;
+        return schema.describe();
+    };
+
+    root.compile = function (schema) {
+
+        try {
+            return Cast.schema(schema);
+        }
+        catch (err) {
+            if (err.hasOwnProperty('path')) {
+                err.message += '(' + err.path + ')';
+            }
+            throw err;
+        }
+    };
+
+    root.assert = function (value, schema, message) {
+
+        root.attempt(value, schema, message);
+    };
+
+    root.attempt = function (value, schema, message) {
+
+        var result = root.validate(value, schema);
+        var error = result.error;
+        if (error) {
+            if (!message) {
+                error.message = error.annotate();
+                throw error;
+            }
+
+            if (!(message instanceof Error)) {
+                error.message = message + ' ' + error.annotate();
+                throw error;
+            }
+
+            throw message;
+        }
+
+        return result.value;
+    };
+
+    return root;
+};
+
+
+module.exports = internals.root();
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/language.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/language.js
new file mode 100755
index 0000000000000000000000000000000000000000..110e3c164b2d072e0d084a011004f8247eafb7a3
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/language.js
@@ -0,0 +1,125 @@
+// Load modules
+
+
+// Declare internals
+
+var internals = {};
+
+
+exports.errors = {
+    root: 'value',
+    key: '"{{!key}}" ',
+    messages: {
+        wrapArrays: true
+    },
+    any: {
+        unknown: 'is not allowed',
+        invalid: 'contains an invalid value',
+        empty: 'is not allowed to be empty',
+        required: 'is required',
+        allowOnly: 'must be one of {{valids}}',
+        default: 'threw an error when running default method'
+    },
+    alternatives: {
+        base: 'not matching any of the allowed alternatives'
+    },
+    array: {
+        base: 'must be an array',
+        includes: 'at position {{pos}} does not match any of the allowed types',
+        includesSingle: 'single value of "{{!key}}" does not match any of the allowed types',
+        includesOne: 'at position {{pos}} fails because {{reason}}',
+        includesOneSingle: 'single value of "{{!key}}" fails because {{reason}}',
+        includesRequiredUnknowns: 'does not contain {{unknownMisses}} required value(s)',
+        includesRequiredKnowns: 'does not contain {{knownMisses}}',
+        includesRequiredBoth: 'does not contain {{knownMisses}} and {{unknownMisses}} other required value(s)',
+        excludes: 'at position {{pos}} contains an excluded value',
+        excludesSingle: 'single value of "{{!key}}" contains an excluded value',
+        min: 'must contain at least {{limit}} items',
+        max: 'must contain less than or equal to {{limit}} items',
+        length: 'must contain {{limit}} items',
+        ordered: 'at position {{pos}} fails because {{reason}}',
+        orderedLength: 'at position {{pos}} fails because array must contain at most {{limit}} items',
+        sparse: 'must not be a sparse array',
+        unique: 'position {{pos}} contains a duplicate value'
+    },
+    boolean: {
+        base: 'must be a boolean'
+    },
+    binary: {
+        base: 'must be a buffer or a string',
+        min: 'must be at least {{limit}} bytes',
+        max: 'must be less than or equal to {{limit}} bytes',
+        length: 'must be {{limit}} bytes'
+    },
+    date: {
+        base: 'must be a number of milliseconds or valid date string',
+        min: 'must be larger than or equal to "{{limit}}"',
+        max: 'must be less than or equal to "{{limit}}"',
+        isoDate: 'must be a valid ISO 8601 date',
+        ref: 'references "{{ref}}" which is not a date'
+    },
+    function: {
+        base: 'must be a Function'
+    },
+    object: {
+        base: 'must be an object',
+        child: 'child "{{!key}}" fails because {{reason}}',
+        min: 'must have at least {{limit}} children',
+        max: 'must have less than or equal to {{limit}} children',
+        length: 'must have {{limit}} children',
+        allowUnknown: 'is not allowed',
+        with: 'missing required peer "{{peer}}"',
+        without: 'conflict with forbidden peer "{{peer}}"',
+        missing: 'must contain at least one of {{peers}}',
+        xor: 'contains a conflict between exclusive peers {{peers}}',
+        or: 'must contain at least one of {{peers}}',
+        and: 'contains {{present}} without its required peers {{missing}}',
+        nand: '!!"{{main}}" must not exist simultaneously with {{peers}}',
+        assert: '!!"{{ref}}" validation failed because "{{ref}}" failed to {{message}}',
+        rename: {
+            multiple: 'cannot rename child "{{from}}" because multiple renames are disabled and another key was already renamed to "{{to}}"',
+            override: 'cannot rename child "{{from}}" because override is disabled and target "{{to}}" exists'
+        },
+        type: 'must be an instance of "{{type}}"'
+    },
+    number: {
+        base: 'must be a number',
+        min: 'must be larger than or equal to {{limit}}',
+        max: 'must be less than or equal to {{limit}}',
+        less: 'must be less than {{limit}}',
+        greater: 'must be greater than {{limit}}',
+        float: 'must be a float or double',
+        integer: 'must be an integer',
+        negative: 'must be a negative number',
+        positive: 'must be a positive number',
+        precision: 'must have no more than {{limit}} decimal places',
+        ref: 'references "{{ref}}" which is not a number',
+        multiple: 'must be a multiple of {{multiple}}'
+    },
+    string: {
+        base: 'must be a string',
+        min: 'length must be at least {{limit}} characters long',
+        max: 'length must be less than or equal to {{limit}} characters long',
+        length: 'length must be {{limit}} characters long',
+        alphanum: 'must only contain alpha-numeric characters',
+        token: 'must only contain alpha-numeric and underscore characters',
+        regex: {
+            base: 'with value "{{!value}}" fails to match the required pattern: {{pattern}}',
+            name: 'with value "{{!value}}" fails to match the {{name}} pattern'
+        },
+        email: 'must be a valid email',
+        uri: 'must be a valid uri',
+        uriCustomScheme: 'must be a valid uri with a scheme matching the {{scheme}} pattern',
+        isoDate: 'must be a valid ISO 8601 date',
+        guid: 'must be a valid GUID',
+        hex: 'must only contain hexadecimal characters',
+        hostname: 'must be a valid hostname',
+        lowercase: 'must only contain lowercase characters',
+        uppercase: 'must only contain uppercase characters',
+        trim: 'must not have leading or trailing whitespace',
+        creditCard: 'must be a credit card',
+        ref: 'references "{{ref}}" which is not a number',
+        ip: 'must be a valid ip address with a {{cidr}} CIDR',
+        ipVersion: 'must be a valid ip address of one of the following versions {{version}} with a {{cidr}} CIDR'
+    }
+};
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/number.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/number.js
new file mode 100755
index 0000000000000000000000000000000000000000..b2a8be3886e1cf8ebdf6fd9d0c8cf9d593f2494d
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/number.js
@@ -0,0 +1,184 @@
+// Load modules
+
+var Any = require('./any');
+var Ref = require('./ref');
+var Errors = require('./errors');
+var Hoek = require('hoek');
+
+
+// Declare internals
+
+var internals = {};
+
+
+internals.Number = function () {
+
+    Any.call(this);
+    this._type = 'number';
+    this._invalids.add(Infinity);
+    this._invalids.add(-Infinity);
+};
+
+Hoek.inherits(internals.Number, Any);
+
+internals.compare = function (type, compare) {
+
+    return function (limit) {
+
+        var isRef = Ref.isRef(limit);
+        var isNumber = typeof limit === 'number' && !isNaN(limit);
+
+        Hoek.assert(isNumber || isRef, 'limit must be a number or reference');
+
+        return this._test(type, limit, function (value, state, options) {
+
+            var compareTo;
+            if (isRef) {
+                compareTo = limit(state.parent, options);
+
+                if (!(typeof compareTo === 'number' && !isNaN(compareTo))) {
+                    return Errors.create('number.ref', { ref: limit.key }, state, options);
+                }
+            }
+            else {
+                compareTo = limit;
+            }
+
+            if (compare(value, compareTo)) {
+                return null;
+            }
+
+            return Errors.create('number.' + type, { limit: compareTo, value: value }, state, options);
+        });
+    };
+};
+
+
+internals.Number.prototype._base = function (value, state, options) {
+
+    var result = {
+        errors: null,
+        value: value
+    };
+
+    if (typeof value === 'string' &&
+        options.convert) {
+
+        var number = parseFloat(value);
+        result.value = (isNaN(number) || !isFinite(value)) ? NaN : number;
+    }
+
+    var isNumber = typeof result.value === 'number' && !isNaN(result.value);
+
+    if (options.convert && 'precision' in this._flags && isNumber) {
+
+        // This is conceptually equivalent to using toFixed but it should be much faster
+        var precision = Math.pow(10, this._flags.precision);
+        result.value = Math.round(result.value * precision) / precision;
+    }
+
+    result.errors = isNumber ? null : Errors.create('number.base', null, state, options);
+    return result;
+};
+
+
+internals.Number.prototype.min = internals.compare('min', function (value, limit) {
+
+    return value >= limit;
+});
+
+
+internals.Number.prototype.max = internals.compare('max', function (value, limit) {
+
+    return value <= limit;
+});
+
+
+internals.Number.prototype.greater = internals.compare('greater', function (value, limit) {
+
+    return value > limit;
+});
+
+
+internals.Number.prototype.less = internals.compare('less', function (value, limit) {
+
+    return value < limit;
+});
+
+
+internals.Number.prototype.multiple = function (base) {
+
+    Hoek.assert(Hoek.isInteger(base), 'multiple must be an integer');
+    Hoek.assert(base > 0, 'multiple must be greater than 0');
+
+    return this._test('multiple', base, function (value, state, options) {
+
+        if (value % base === 0) {
+            return null;
+        }
+
+        return Errors.create('number.multiple', { multiple: base, value: value }, state, options);
+    });
+};
+
+
+internals.Number.prototype.integer = function () {
+
+    return this._test('integer', undefined, function (value, state, options) {
+
+        return Hoek.isInteger(value) ? null : Errors.create('number.integer', { value: value }, state, options);
+    });
+};
+
+
+internals.Number.prototype.negative = function () {
+
+    return this._test('negative', undefined, function (value, state, options) {
+
+        if (value < 0) {
+            return null;
+        }
+
+        return Errors.create('number.negative', { value: value }, state, options);
+    });
+};
+
+
+internals.Number.prototype.positive = function () {
+
+    return this._test('positive', undefined, function (value, state, options) {
+
+        if (value > 0) {
+            return null;
+        }
+
+        return Errors.create('number.positive', { value: value }, state, options);
+    });
+};
+
+
+internals.precisionRx = /(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/;
+
+
+internals.Number.prototype.precision = function (limit) {
+
+    Hoek.assert(Hoek.isInteger(limit), 'limit must be an integer');
+    Hoek.assert(!('precision' in this._flags), 'precision already set');
+
+    var obj = this._test('precision', limit, function (value, state, options){
+
+        var places = value.toString().match(internals.precisionRx);
+        var decimals = Math.max((places[1] ? places[1].length : 0) - (places[2] ? parseInt(places[2], 10) : 0), 0);
+        if (decimals <= limit) {
+            return null;
+        }
+
+        return Errors.create('number.precision', { limit: limit, value: value }, state, options);
+    });
+
+    obj._flags.precision = limit;
+    return obj;
+};
+
+
+module.exports = new internals.Number();
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/object.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/object.js
new file mode 100755
index 0000000000000000000000000000000000000000..1e15c985c6b37dc1b8c37120aa3f074634aad3d0
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/object.js
@@ -0,0 +1,754 @@
+// Load modules
+
+var Hoek = require('hoek');
+var Topo = require('topo');
+var Any = require('./any');
+var Cast = require('./cast');
+var Errors = require('./errors');
+
+
+// Declare internals
+
+var internals = {};
+
+
+internals.Object = function () {
+
+    Any.call(this);
+    this._type = 'object';
+    this._inner.children = null;
+    this._inner.renames = [];
+    this._inner.dependencies = [];
+    this._inner.patterns = [];
+};
+
+Hoek.inherits(internals.Object, Any);
+
+
+internals.Object.prototype._base = function (value, state, options) {
+
+    var item, key, localState, result;
+    var target = value;
+    var errors = [];
+    var finish = function () {
+
+        return {
+            value: target,
+            errors: errors.length ? errors : null
+        };
+    };
+
+    if (typeof value === 'string' &&
+        options.convert) {
+
+        try {
+            value = JSON.parse(value);
+        }
+        catch (parseErr) { }
+    }
+
+    var type = this._flags.func ? 'function' : 'object';
+    if (!value ||
+        typeof value !== type ||
+        Array.isArray(value)) {
+
+        errors.push(Errors.create(type + '.base', null, state, options));
+        return finish();
+    }
+
+    // Skip if there are no other rules to test
+
+    if (!this._inner.renames.length &&
+        !this._inner.dependencies.length &&
+        !this._inner.children &&                    // null allows any keys
+        !this._inner.patterns.length) {
+
+        target = value;
+        return finish();
+    }
+
+    // Ensure target is a local copy (parsed) or shallow copy
+
+    if (target === value) {
+        if (type === 'object') {
+            target = Object.create(Object.getPrototypeOf(value));
+        }
+        else {
+            target = function () {
+
+                return value.apply(this, arguments);
+            };
+
+            target.prototype = Hoek.clone(value.prototype);
+        }
+
+        var valueKeys = Object.keys(value);
+        for (var t = 0, tl = valueKeys.length; t < tl; ++t) {
+            target[valueKeys[t]] = value[valueKeys[t]];
+        }
+    }
+    else {
+        target = value;
+    }
+
+    // Rename keys
+
+    var renamed = {};
+    for (var r = 0, rl = this._inner.renames.length; r < rl; ++r) {
+        item = this._inner.renames[r];
+
+        if (item.options.ignoreUndefined && target[item.from] === undefined) {
+            continue;
+        }
+
+        if (!item.options.multiple &&
+            renamed[item.to]) {
+
+            errors.push(Errors.create('object.rename.multiple', { from: item.from, to: item.to }, state, options));
+            if (options.abortEarly) {
+                return finish();
+            }
+        }
+
+        if (Object.prototype.hasOwnProperty.call(target, item.to) &&
+            !item.options.override &&
+            !renamed[item.to]) {
+
+            errors.push(Errors.create('object.rename.override', { from: item.from, to: item.to }, state, options));
+            if (options.abortEarly) {
+                return finish();
+            }
+        }
+
+        if (target[item.from] === undefined) {
+            delete target[item.to];
+        }
+        else {
+            target[item.to] = target[item.from];
+        }
+
+        renamed[item.to] = true;
+
+        if (!item.options.alias) {
+            delete target[item.from];
+        }
+    }
+
+    // Validate schema
+
+    if (!this._inner.children &&            // null allows any keys
+        !this._inner.patterns.length &&
+        !this._inner.dependencies.length) {
+
+        return finish();
+    }
+
+    var unprocessed = Hoek.mapToObject(Object.keys(target));
+
+    if (this._inner.children) {
+        for (var i = 0, il = this._inner.children.length; i < il; ++i) {
+            var child = this._inner.children[i];
+            key = child.key;
+            item = target[key];
+
+            delete unprocessed[key];
+
+            localState = { key: key, path: (state.path || '') + (state.path && key ? '.' : '') + key, parent: target, reference: state.reference };
+            result = child.schema._validate(item, localState, options);
+            if (result.errors) {
+                errors.push(Errors.create('object.child', { key: key, reason: result.errors }, localState, options));
+
+                if (options.abortEarly) {
+                    return finish();
+                }
+            }
+
+            if (child.schema._flags.strip || (result.value === undefined && result.value !== item)) {
+                delete target[key];
+            }
+            else if (result.value !== undefined) {
+                target[key] = result.value;
+            }
+        }
+    }
+
+    // Unknown keys
+
+    var unprocessedKeys = Object.keys(unprocessed);
+    if (unprocessedKeys.length &&
+        this._inner.patterns.length) {
+
+        for (i = 0, il = unprocessedKeys.length; i < il; ++i) {
+            key = unprocessedKeys[i];
+
+            for (var p = 0, pl = this._inner.patterns.length; p < pl; ++p) {
+                var pattern = this._inner.patterns[p];
+
+                if (pattern.regex.test(key)) {
+                    delete unprocessed[key];
+
+                    item = target[key];
+                    localState = { key: key, path: (state.path ? state.path + '.' : '') + key, parent: target, reference: state.reference };
+                    result = pattern.rule._validate(item, localState, options);
+                    if (result.errors) {
+                        errors.push(Errors.create('object.child', { key: key, reason: result.errors }, localState, options));
+
+                        if (options.abortEarly) {
+                            return finish();
+                        }
+                    }
+
+                    if (result.value !== undefined) {
+                        target[key] = result.value;
+                    }
+                }
+            }
+        }
+
+        unprocessedKeys = Object.keys(unprocessed);
+    }
+
+    if ((this._inner.children || this._inner.patterns.length) && unprocessedKeys.length) {
+        if (options.stripUnknown ||
+            options.skipFunctions) {
+
+            for (var k = 0, kl = unprocessedKeys.length; k < kl; ++k) {
+                key = unprocessedKeys[k];
+
+                if (options.stripUnknown) {
+                    delete target[key];
+                    delete unprocessed[key];
+                }
+                else if (typeof target[key] === 'function') {
+                    delete unprocessed[key];
+                }
+            }
+
+            unprocessedKeys = Object.keys(unprocessed);
+        }
+
+        if (unprocessedKeys.length &&
+            (this._flags.allowUnknown !== undefined ? !this._flags.allowUnknown : !options.allowUnknown)) {
+
+            for (var e = 0, el = unprocessedKeys.length; e < el; ++e) {
+                errors.push(Errors.create('object.allowUnknown', null, { key: unprocessedKeys[e], path: state.path + (state.path ? '.' : '') + unprocessedKeys[e] }, options));
+            }
+        }
+    }
+
+    // Validate dependencies
+
+    for (var d = 0, dl = this._inner.dependencies.length; d < dl; ++d) {
+        var dep = this._inner.dependencies[d];
+        var err = internals[dep.type](dep.key !== null && value[dep.key], dep.peers, target, { key: dep.key, path: (state.path || '') + (dep.key ? '.' + dep.key : '') }, options);
+        if (err) {
+            errors.push(err);
+            if (options.abortEarly) {
+                return finish();
+            }
+        }
+    }
+
+    return finish();
+};
+
+
+internals.Object.prototype._func = function () {
+
+    var obj = this.clone();
+    obj._flags.func = true;
+    return obj;
+};
+
+
+internals.Object.prototype.keys = function (schema) {
+
+    Hoek.assert(schema === null || schema === undefined || typeof schema === 'object', 'Object schema must be a valid object');
+    Hoek.assert(!schema || !schema.isJoi, 'Object schema cannot be a joi schema');
+
+    var obj = this.clone();
+
+    if (!schema) {
+        obj._inner.children = null;
+        return obj;
+    }
+
+    var children = Object.keys(schema);
+
+    if (!children.length) {
+        obj._inner.children = [];
+        return obj;
+    }
+
+    var topo = new Topo();
+    var child;
+    if (obj._inner.children) {
+        for (var i = 0, il = obj._inner.children.length; i < il; ++i) {
+            child = obj._inner.children[i];
+
+            // Only add the key if we are not going to replace it later
+            if (children.indexOf(child.key) === -1) {
+                topo.add(child, { after: child._refs, group: child.key });
+            }
+        }
+    }
+
+    for (var c = 0, cl = children.length; c < cl; ++c) {
+        var key = children[c];
+        child = schema[key];
+        try {
+            var cast = Cast.schema(child);
+            topo.add({ key: key, schema: cast }, { after: cast._refs, group: key });
+        }
+        catch (castErr) {
+            if (castErr.hasOwnProperty('path')) {
+                castErr.path = key + '.' + castErr.path;
+            }
+            else {
+                castErr.path = key;
+            }
+            throw castErr;
+        }
+    }
+
+    obj._inner.children = topo.nodes;
+
+    return obj;
+};
+
+
+internals.Object.prototype.unknown = function (allow) {
+
+    var obj = this.clone();
+    obj._flags.allowUnknown = (allow !== false);
+    return obj;
+};
+
+
+internals.Object.prototype.length = function (limit) {
+
+    Hoek.assert(Hoek.isInteger(limit) && limit >= 0, 'limit must be a positive integer');
+
+    return this._test('length', limit, function (value, state, options) {
+
+        if (Object.keys(value).length === limit) {
+            return null;
+        }
+
+        return Errors.create('object.length', { limit: limit }, state, options);
+    });
+};
+
+
+internals.Object.prototype.min = function (limit) {
+
+    Hoek.assert(Hoek.isInteger(limit) && limit >= 0, 'limit must be a positive integer');
+
+    return this._test('min', limit, function (value, state, options) {
+
+        if (Object.keys(value).length >= limit) {
+            return null;
+        }
+
+        return Errors.create('object.min', { limit: limit }, state, options);
+    });
+};
+
+
+internals.Object.prototype.max = function (limit) {
+
+    Hoek.assert(Hoek.isInteger(limit) && limit >= 0, 'limit must be a positive integer');
+
+    return this._test('max', limit, function (value, state, options) {
+
+        if (Object.keys(value).length <= limit) {
+            return null;
+        }
+
+        return Errors.create('object.max', { limit: limit }, state, options);
+    });
+};
+
+
+internals.Object.prototype.pattern = function (pattern, schema) {
+
+    Hoek.assert(pattern instanceof RegExp, 'Invalid regular expression');
+    Hoek.assert(schema !== undefined, 'Invalid rule');
+
+    pattern = new RegExp(pattern.source, pattern.ignoreCase ? 'i' : undefined);         // Future version should break this and forbid unsupported regex flags
+
+    try {
+        schema = Cast.schema(schema);
+    }
+    catch (castErr) {
+        if (castErr.hasOwnProperty('path')) {
+            castErr.message += '(' + castErr.path + ')';
+        }
+
+        throw castErr;
+    }
+
+
+    var obj = this.clone();
+    obj._inner.patterns.push({ regex: pattern, rule: schema });
+    return obj;
+};
+
+
+internals.Object.prototype.with = function (key, peers) {
+
+    return this._dependency('with', key, peers);
+};
+
+
+internals.Object.prototype.without = function (key, peers) {
+
+    return this._dependency('without', key, peers);
+};
+
+
+internals.Object.prototype.xor = function () {
+
+    var peers = Hoek.flatten(Array.prototype.slice.call(arguments));
+    return this._dependency('xor', null, peers);
+};
+
+
+internals.Object.prototype.or = function () {
+
+    var peers = Hoek.flatten(Array.prototype.slice.call(arguments));
+    return this._dependency('or', null, peers);
+};
+
+
+internals.Object.prototype.and = function () {
+
+    var peers = Hoek.flatten(Array.prototype.slice.call(arguments));
+    return this._dependency('and', null, peers);
+};
+
+
+internals.Object.prototype.nand = function () {
+
+    var peers = Hoek.flatten(Array.prototype.slice.call(arguments));
+    return this._dependency('nand', null, peers);
+};
+
+
+internals.Object.prototype.requiredKeys = function (children) {
+
+    children = Hoek.flatten(Array.prototype.slice.call(arguments));
+    return this.applyFunctionToChildren(children, 'required');
+};
+
+
+internals.Object.prototype.optionalKeys = function (children) {
+
+    children = Hoek.flatten(Array.prototype.slice.call(arguments));
+    return this.applyFunctionToChildren(children, 'optional');
+};
+
+
+internals.renameDefaults = {
+    alias: false,                   // Keep old value in place
+    multiple: false,                // Allow renaming multiple keys into the same target
+    override: false                 // Overrides an existing key
+};
+
+
+internals.Object.prototype.rename = function (from, to, options) {
+
+    Hoek.assert(typeof from === 'string', 'Rename missing the from argument');
+    Hoek.assert(typeof to === 'string', 'Rename missing the to argument');
+    Hoek.assert(to !== from, 'Cannot rename key to same name:', from);
+
+    for (var i = 0, il = this._inner.renames.length; i < il; ++i) {
+        Hoek.assert(this._inner.renames[i].from !== from, 'Cannot rename the same key multiple times');
+    }
+
+    var obj = this.clone();
+
+    obj._inner.renames.push({
+        from: from,
+        to: to,
+        options: Hoek.applyToDefaults(internals.renameDefaults, options || {})
+    });
+
+    return obj;
+};
+
+
+internals.groupChildren = function (children) {
+
+    children.sort();
+
+    var grouped = {};
+
+    for (var c = 0, lc = children.length; c < lc; c++) {
+        var child = children[c];
+        Hoek.assert(typeof child === 'string', 'children must be strings');
+        var group = child.split('.')[0];
+        var childGroup = grouped[group] = (grouped[group] || []);
+        childGroup.push(child.substring(group.length + 1));
+    }
+
+    return grouped;
+};
+
+
+internals.Object.prototype.applyFunctionToChildren = function (children, fn, args, root) {
+
+    children = [].concat(children);
+    Hoek.assert(children.length > 0, 'expected at least one children');
+
+    var groupedChildren = internals.groupChildren(children);
+    var obj;
+
+    if ('' in groupedChildren) {
+        obj = this[fn].apply(this, args);
+        delete groupedChildren[''];
+    }
+    else {
+        obj = this.clone();
+    }
+
+    if (obj._inner.children) {
+        root = root ? (root + '.') : '';
+
+        for (var i = 0, il = obj._inner.children.length; i < il; ++i) {
+            var child = obj._inner.children[i];
+            var group = groupedChildren[child.key];
+
+            if (group) {
+                obj._inner.children[i] = {
+                    key: child.key,
+                    _refs: child._refs,
+                    schema: child.schema.applyFunctionToChildren(group, fn, args, root + child.key)
+                };
+
+                delete groupedChildren[child.key];
+            }
+        }
+    }
+
+    var remaining = Object.keys(groupedChildren);
+    Hoek.assert(remaining.length === 0, 'unknown key(s)', remaining.join(', '));
+
+    return obj;
+};
+
+
+internals.Object.prototype._dependency = function (type, key, peers) {
+
+    peers = [].concat(peers);
+    for (var i = 0, li = peers.length; i < li; i++) {
+        Hoek.assert(typeof peers[i] === 'string', type, 'peers must be a string or array of strings');
+    }
+
+    var obj = this.clone();
+    obj._inner.dependencies.push({ type: type, key: key, peers: peers });
+    return obj;
+};
+
+
+internals.with = function (value, peers, parent, state, options) {
+
+    if (value === undefined) {
+        return null;
+    }
+
+    for (var i = 0, il = peers.length; i < il; ++i) {
+        var peer = peers[i];
+        if (!Object.prototype.hasOwnProperty.call(parent, peer) ||
+            parent[peer] === undefined) {
+
+            return Errors.create('object.with', { peer: peer }, state, options);
+        }
+    }
+
+    return null;
+};
+
+
+internals.without = function (value, peers, parent, state, options) {
+
+    if (value === undefined) {
+        return null;
+    }
+
+    for (var i = 0, il = peers.length; i < il; ++i) {
+        var peer = peers[i];
+        if (Object.prototype.hasOwnProperty.call(parent, peer) &&
+            parent[peer] !== undefined) {
+
+            return Errors.create('object.without', { peer: peer }, state, options);
+        }
+    }
+
+    return null;
+};
+
+
+internals.xor = function (value, peers, parent, state, options) {
+
+    var present = [];
+    for (var i = 0, il = peers.length; i < il; ++i) {
+        var peer = peers[i];
+        if (Object.prototype.hasOwnProperty.call(parent, peer) &&
+            parent[peer] !== undefined) {
+
+            present.push(peer);
+        }
+    }
+
+    if (present.length === 1) {
+        return null;
+    }
+
+    if (present.length === 0) {
+        return Errors.create('object.missing', { peers: peers }, state, options);
+    }
+
+    return Errors.create('object.xor', { peers: peers }, state, options);
+};
+
+
+internals.or = function (value, peers, parent, state, options) {
+
+    for (var i = 0, il = peers.length; i < il; ++i) {
+        var peer = peers[i];
+        if (Object.prototype.hasOwnProperty.call(parent, peer) &&
+            parent[peer] !== undefined) {
+            return null;
+        }
+    }
+
+    return Errors.create('object.missing', { peers: peers }, state, options);
+};
+
+
+internals.and = function (value, peers, parent, state, options) {
+
+    var missing = [];
+    var present = [];
+    var count = peers.length;
+    for (var i = 0; i < count; ++i) {
+        var peer = peers[i];
+        if (!Object.prototype.hasOwnProperty.call(parent, peer) ||
+            parent[peer] === undefined) {
+
+            missing.push(peer);
+        }
+        else {
+            present.push(peer);
+        }
+    }
+
+    var aon = (missing.length === count || present.length === count);
+    return !aon ? Errors.create('object.and', { present: present, missing: missing }, state, options) : null;
+};
+
+
+internals.nand = function (value, peers, parent, state, options) {
+
+    var present = [];
+    for (var i = 0, il = peers.length; i < il; ++i) {
+        var peer = peers[i];
+        if (Object.prototype.hasOwnProperty.call(parent, peer) &&
+            parent[peer] !== undefined) {
+
+            present.push(peer);
+        }
+    }
+
+    var values = Hoek.clone(peers);
+    var main = values.splice(0, 1)[0];
+    var allPresent = (present.length === peers.length);
+    return allPresent ? Errors.create('object.nand', { main: main, peers: values }, state, options) : null;
+};
+
+
+internals.Object.prototype.describe = function (shallow) {
+
+    var description = Any.prototype.describe.call(this);
+
+    if (this._inner.children &&
+        !shallow) {
+
+        description.children = {};
+        for (var i = 0, il = this._inner.children.length; i < il; ++i) {
+            var child = this._inner.children[i];
+            description.children[child.key] = child.schema.describe();
+        }
+    }
+
+    if (this._inner.dependencies.length) {
+        description.dependencies = Hoek.clone(this._inner.dependencies);
+    }
+
+    if (this._inner.patterns.length) {
+        description.patterns = [];
+
+        for (var p = 0, pl = this._inner.patterns.length; p < pl; ++p) {
+            var pattern = this._inner.patterns[p];
+            description.patterns.push({ regex: pattern.regex.toString(), rule: pattern.rule.describe() });
+        }
+    }
+
+    return description;
+};
+
+
+internals.Object.prototype.assert = function (ref, schema, message) {
+
+    ref = Cast.ref(ref);
+    Hoek.assert(ref.isContext || ref.depth > 1, 'Cannot use assertions for root level references - use direct key rules instead');
+    message = message || 'pass the assertion test';
+
+    var cast;
+    try {
+        cast = Cast.schema(schema);
+    }
+    catch (castErr) {
+        if (castErr.hasOwnProperty('path')) {
+            castErr.message += '(' + castErr.path + ')';
+        }
+
+        throw castErr;
+    }
+
+    var key = ref.path[ref.path.length - 1];
+    var path = ref.path.join('.');
+
+    return this._test('assert', { cast: cast, ref: ref }, function (value, state, options) {
+
+        var result = cast._validate(ref(value), null, options, value);
+        if (!result.errors) {
+            return null;
+        }
+
+        var localState = Hoek.merge({}, state);
+        localState.key = key;
+        localState.path = path;
+        return Errors.create('object.assert', { ref: localState.path, message: message }, localState, options);
+    });
+};
+
+
+internals.Object.prototype.type = function (constructor, name) {
+
+    Hoek.assert(typeof constructor === 'function', 'type must be a constructor function');
+    name = name || constructor.name;
+
+    return this._test('type', name, function (value, state, options) {
+
+        if (value instanceof constructor) {
+            return null;
+        }
+
+        return Errors.create('object.type', { type: name }, state, options);
+    });
+};
+
+
+module.exports = new internals.Object();
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/ref.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/ref.js
new file mode 100755
index 0000000000000000000000000000000000000000..c87c483ed07d1df83934ce672fcbb06dad913ad9
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/ref.js
@@ -0,0 +1,51 @@
+// Load modules
+
+var Hoek = require('hoek');
+
+
+// Declare internals
+
+var internals = {};
+
+
+exports.create = function (key, options) {
+
+    Hoek.assert(typeof key === 'string', 'Invalid reference key:', key);
+
+    var settings = Hoek.clone(options);         // options can be reused and modified
+
+    var ref = function (value, validationOptions) {
+
+        return Hoek.reach(ref.isContext ? validationOptions.context : value, ref.key, settings);
+    };
+
+    ref.isContext = (key[0] === ((settings && settings.contextPrefix) || '$'));
+    ref.key = (ref.isContext ? key.slice(1) : key);
+    ref.path = ref.key.split((settings && settings.separator) || '.');
+    ref.depth = ref.path.length;
+    ref.root = ref.path[0];
+    ref.isJoi = true;
+
+    ref.toString = function () {
+
+        return (ref.isContext ? 'context:' : 'ref:') + ref.key;
+    };
+
+    return ref;
+};
+
+
+exports.isRef = function (ref) {
+
+    return typeof ref === 'function' && ref.isJoi;
+};
+
+
+exports.push = function (array, ref) {
+
+    if (exports.isRef(ref) &&
+        !ref.isContext) {
+
+        array.push(ref.root);
+    }
+};
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/string.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/string.js
new file mode 100755
index 0000000000000000000000000000000000000000..68edef94d049dff8e4debede116b7d851df97ff4
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/string.js
@@ -0,0 +1,468 @@
+// Load modules
+
+var Net = require('net');
+var Hoek = require('hoek');
+var Isemail = require('isemail');
+var Any = require('./any');
+var Ref = require('./ref');
+var JoiDate = require('./date');
+var Errors = require('./errors');
+var Uri = require('./string/uri');
+var Ip = require('./string/ip');
+
+// Declare internals
+
+var internals = {
+    uriRegex: Uri.createUriRegex(),
+    ipRegex: Ip.createIpRegex(['ipv4', 'ipv6', 'ipvfuture'], 'optional')
+};
+
+internals.String = function () {
+
+    Any.call(this);
+    this._type = 'string';
+    this._invalids.add('');
+};
+
+Hoek.inherits(internals.String, Any);
+
+internals.compare = function (type, compare) {
+
+    return function (limit, encoding) {
+
+        var isRef = Ref.isRef(limit);
+
+        Hoek.assert((Hoek.isInteger(limit) && limit >= 0) || isRef, 'limit must be a positive integer or reference');
+        Hoek.assert(!encoding || Buffer.isEncoding(encoding), 'Invalid encoding:', encoding);
+
+        return this._test(type, limit, function (value, state, options) {
+
+            var compareTo;
+            if (isRef) {
+                compareTo = limit(state.parent, options);
+
+                if (!Hoek.isInteger(compareTo)) {
+                    return Errors.create('string.ref', { ref: limit.key }, state, options);
+                }
+            }
+            else {
+                compareTo = limit;
+            }
+
+            if (compare(value, compareTo, encoding)) {
+                return null;
+            }
+
+            return Errors.create('string.' + type, { limit: compareTo, value: value, encoding: encoding }, state, options);
+        });
+    };
+};
+
+internals.String.prototype._base = function (value, state, options) {
+
+    if (typeof value === 'string' &&
+        options.convert) {
+
+        if (this._flags.case) {
+            value = (this._flags.case === 'upper' ? value.toLocaleUpperCase() : value.toLocaleLowerCase());
+        }
+
+        if (this._flags.trim) {
+            value = value.trim();
+        }
+
+        if (this._inner.replacements) {
+
+            for (var r = 0, rl = this._inner.replacements.length; r < rl; ++r) {
+                var replacement = this._inner.replacements[r];
+                value = value.replace(replacement.pattern, replacement.replacement);
+            }
+        }
+    }
+
+    return {
+        value: value,
+        errors: (typeof value === 'string') ? null : Errors.create('string.base', { value: value }, state, options)
+    };
+};
+
+
+internals.String.prototype.insensitive = function () {
+
+    var obj = this.clone();
+    obj._flags.insensitive = true;
+    return obj;
+};
+
+
+internals.String.prototype.min = internals.compare('min', function (value, limit, encoding) {
+
+    var length = encoding ? Buffer.byteLength(value, encoding) : value.length;
+    return length >= limit;
+});
+
+
+internals.String.prototype.max = internals.compare('max', function (value, limit, encoding) {
+
+    var length = encoding ? Buffer.byteLength(value, encoding) : value.length;
+    return length <= limit;
+});
+
+
+internals.String.prototype.creditCard = function () {
+
+    return this._test('creditCard', undefined, function (value, state, options) {
+
+        var i = value.length;
+        var sum = 0;
+        var mul = 1;
+        var char;
+
+        while (i--) {
+            char = value.charAt(i) * mul;
+            sum += char - (char > 9) * 9;
+            mul ^= 3;
+        }
+
+        var check = (sum % 10 === 0) && (sum > 0);
+        return check ? null : Errors.create('string.creditCard', { value: value }, state, options);
+    });
+};
+
+internals.String.prototype.length = internals.compare('length', function (value, limit, encoding) {
+
+    var length = encoding ? Buffer.byteLength(value, encoding) : value.length;
+    return length === limit;
+});
+
+
+internals.String.prototype.regex = function (pattern, name) {
+
+    Hoek.assert(pattern instanceof RegExp, 'pattern must be a RegExp');
+
+    pattern = new RegExp(pattern.source, pattern.ignoreCase ? 'i' : undefined);         // Future version should break this and forbid unsupported regex flags
+
+    return this._test('regex', pattern, function (value, state, options) {
+
+        if (pattern.test(value)) {
+            return null;
+        }
+
+        return Errors.create((name ? 'string.regex.name' : 'string.regex.base'), { name: name, pattern: pattern, value: value }, state, options);
+    });
+};
+
+
+internals.String.prototype.alphanum = function () {
+
+    return this._test('alphanum', undefined, function (value, state, options) {
+
+        if (/^[a-zA-Z0-9]+$/.test(value)) {
+            return null;
+        }
+
+        return Errors.create('string.alphanum', { value: value }, state, options);
+    });
+};
+
+
+internals.String.prototype.token = function () {
+
+    return this._test('token', undefined, function (value, state, options) {
+
+        if (/^\w+$/.test(value)) {
+            return null;
+        }
+
+        return Errors.create('string.token', { value: value }, state, options);
+    });
+};
+
+
+internals.String.prototype.email = function (isEmailOptions) {
+
+    if (isEmailOptions) {
+        Hoek.assert(typeof isEmailOptions === 'object', 'email options must be an object');
+        Hoek.assert(typeof isEmailOptions.checkDNS === 'undefined', 'checkDNS option is not supported');
+        Hoek.assert(typeof isEmailOptions.tldWhitelist === 'undefined' ||
+            typeof isEmailOptions.tldWhitelist === 'object', 'tldWhitelist must be an array or object');
+        Hoek.assert(typeof isEmailOptions.minDomainAtoms === 'undefined' ||
+            Hoek.isInteger(isEmailOptions.minDomainAtoms) && isEmailOptions.minDomainAtoms > 0,
+            'minDomainAtoms must be a positive integer');
+        Hoek.assert(typeof isEmailOptions.errorLevel === 'undefined' || typeof isEmailOptions.errorLevel === 'boolean' ||
+            (Hoek.isInteger(isEmailOptions.errorLevel) && isEmailOptions.errorLevel >= 0),
+            'errorLevel must be a non-negative integer or boolean');
+    }
+
+    return this._test('email', isEmailOptions, function (value, state, options) {
+
+        try {
+            var result = Isemail(value, isEmailOptions);
+            if (result === true || result === 0) {
+                return null;
+            }
+        }
+        catch (e) {}
+
+        return Errors.create('string.email', { value: value }, state, options);
+    });
+};
+
+
+internals.String.prototype.ip = function (ipOptions) {
+
+    var regex = internals.ipRegex;
+    ipOptions = ipOptions || {};
+    Hoek.assert(typeof ipOptions === 'object', 'options must be an object');
+
+    if (ipOptions.cidr) {
+        Hoek.assert(typeof ipOptions.cidr === 'string', 'cidr must be a string');
+        ipOptions.cidr = ipOptions.cidr.toLowerCase();
+
+        Hoek.assert(ipOptions.cidr in Ip.cidrs, 'cidr must be one of ' + Object.keys(Ip.cidrs).join(', '));
+
+        // If we only received a `cidr` setting, create a regex for it. But we don't need to create one if `cidr` is "optional" since that is the default
+        if (!ipOptions.version && ipOptions.cidr !== 'optional') {
+            regex = Ip.createIpRegex(['ipv4', 'ipv6', 'ipvfuture'], ipOptions.cidr);
+        }
+    }
+    else {
+
+        // Set our default cidr strategy
+        ipOptions.cidr = 'optional';
+    }
+
+    if (ipOptions.version) {
+        if (!Array.isArray(ipOptions.version)) {
+            ipOptions.version = [ipOptions.version];
+        }
+
+        Hoek.assert(ipOptions.version.length >= 1, 'version must have at least 1 version specified');
+
+        var versions = [];
+        for (var i = 0, il = ipOptions.version.length; i < il; ++i) {
+            var version = ipOptions.version[i];
+            Hoek.assert(typeof version === 'string', 'version at position ' + i + ' must be a string');
+            version = version.toLowerCase();
+            Hoek.assert(Ip.versions[version], 'version at position ' + i + ' must be one of ' + Object.keys(Ip.versions).join(', '));
+            versions.push(version);
+        }
+
+        // Make sure we have a set of versions
+        versions = Hoek.unique(versions);
+
+        regex = Ip.createIpRegex(versions, ipOptions.cidr);
+    }
+
+    return this._test('ip', ipOptions, function (value, state, options) {
+
+        if (regex.test(value)) {
+            return null;
+        }
+
+        if (versions) {
+            return Errors.create('string.ipVersion', { value: value, cidr: ipOptions.cidr, version: versions }, state, options);
+        }
+
+        return Errors.create('string.ip', { value: value, cidr: ipOptions.cidr }, state, options);
+    });
+};
+
+
+internals.String.prototype.uri = function (uriOptions) {
+
+    var customScheme = '',
+        regex = internals.uriRegex;
+
+    if (uriOptions) {
+        Hoek.assert(typeof uriOptions === 'object', 'options must be an object');
+
+        if (uriOptions.scheme) {
+            Hoek.assert(uriOptions.scheme instanceof RegExp || typeof uriOptions.scheme === 'string' || Array.isArray(uriOptions.scheme), 'scheme must be a RegExp, String, or Array');
+
+            if (!Array.isArray(uriOptions.scheme)) {
+                uriOptions.scheme = [uriOptions.scheme];
+            }
+
+            Hoek.assert(uriOptions.scheme.length >= 1, 'scheme must have at least 1 scheme specified');
+
+            // Flatten the array into a string to be used to match the schemes.
+            for (var i = 0, il = uriOptions.scheme.length; i < il; ++i) {
+                var scheme = uriOptions.scheme[i];
+                Hoek.assert(scheme instanceof RegExp || typeof scheme === 'string', 'scheme at position ' + i + ' must be a RegExp or String');
+
+                // Add OR separators if a value already exists
+                customScheme += customScheme ? '|' : '';
+
+                // If someone wants to match HTTP or HTTPS for example then we need to support both RegExp and String so we don't escape their pattern unknowingly.
+                if (scheme instanceof RegExp) {
+                    customScheme += scheme.source;
+                }
+                else {
+                    Hoek.assert(/[a-zA-Z][a-zA-Z0-9+-\.]*/.test(scheme), 'scheme at position ' + i + ' must be a valid scheme');
+                    customScheme += Hoek.escapeRegex(scheme);
+                }
+            }
+        }
+    }
+
+    if (customScheme) {
+        regex = Uri.createUriRegex(customScheme);
+    }
+
+    return this._test('uri', uriOptions, function (value, state, options) {
+
+        if (regex.test(value)) {
+            return null;
+        }
+
+        if (customScheme) {
+            return Errors.create('string.uriCustomScheme', { scheme: customScheme, value: value }, state, options);
+        }
+
+        return Errors.create('string.uri', { value: value }, state, options);
+    });
+};
+
+
+internals.String.prototype.isoDate = function () {
+
+    return this._test('isoDate', undefined, function (value, state, options) {
+
+        if (JoiDate._isIsoDate(value)) {
+            return null;
+        }
+
+        return Errors.create('string.isoDate', { value: value }, state, options);
+    });
+};
+
+
+internals.String.prototype.guid = function () {
+
+    var regex = /^[A-F0-9]{8}(?:-?[A-F0-9]{4}){3}-?[A-F0-9]{12}$/i;
+    var regex2 = /^\{[A-F0-9]{8}(?:-?[A-F0-9]{4}){3}-?[A-F0-9]{12}\}$/i;
+
+    return this._test('guid', undefined, function (value, state, options) {
+
+        if (regex.test(value) || regex2.test(value)) {
+            return null;
+        }
+
+        return Errors.create('string.guid', { value: value }, state, options);
+    });
+};
+
+
+internals.String.prototype.hex = function () {
+
+    var regex = /^[a-f0-9]+$/i;
+
+    return this._test('hex', regex, function (value, state, options) {
+
+        if (regex.test(value)) {
+            return null;
+        }
+
+        return Errors.create('string.hex', { value: value }, state, options);
+    });
+};
+
+
+internals.String.prototype.hostname = function () {
+
+    var regex = /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/;
+
+    return this._test('hostname', undefined, function (value, state, options) {
+
+        if ((value.length <= 255 && regex.test(value)) ||
+            Net.isIPv6(value)) {
+
+            return null;
+        }
+
+        return Errors.create('string.hostname', { value: value }, state, options);
+    });
+};
+
+
+internals.String.prototype.lowercase = function () {
+
+    var obj = this._test('lowercase', undefined, function (value, state, options) {
+
+        if (options.convert ||
+            value === value.toLocaleLowerCase()) {
+
+            return null;
+        }
+
+        return Errors.create('string.lowercase', { value: value }, state, options);
+    });
+
+    obj._flags.case = 'lower';
+    return obj;
+};
+
+
+internals.String.prototype.uppercase = function () {
+
+    var obj = this._test('uppercase', undefined, function (value, state, options) {
+
+        if (options.convert ||
+            value === value.toLocaleUpperCase()) {
+
+            return null;
+        }
+
+        return Errors.create('string.uppercase', { value: value }, state, options);
+    });
+
+    obj._flags.case = 'upper';
+    return obj;
+};
+
+
+internals.String.prototype.trim = function () {
+
+    var obj = this._test('trim', undefined, function (value, state, options) {
+
+        if (options.convert ||
+            value === value.trim()) {
+
+            return null;
+        }
+
+        return Errors.create('string.trim', { value: value }, state, options);
+    });
+
+    obj._flags.trim = true;
+    return obj;
+};
+
+
+internals.String.prototype.replace = function (pattern, replacement) {
+
+    if (typeof pattern === 'string') {
+        pattern = new RegExp(Hoek.escapeRegex(pattern), 'g');
+    }
+
+    Hoek.assert(pattern instanceof RegExp, 'pattern must be a RegExp');
+    Hoek.assert(typeof replacement === 'string', 'replacement must be a String');
+
+    // This can not be considere a test like trim, we can't "reject"
+    // anything from this rule, so just clone the current object
+    var obj = this.clone();
+
+    if (!obj._inner.replacements) {
+        obj._inner.replacements = [];
+    }
+
+    obj._inner.replacements.push({
+        pattern: pattern,
+        replacement: replacement
+    });
+
+    return obj;
+};
+
+module.exports = new internals.String();
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/string/ip.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/string/ip.js
new file mode 100644
index 0000000000000000000000000000000000000000..f086c5b5ff271cc225d65a529f7cb3ad78ea3f2a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/string/ip.js
@@ -0,0 +1,32 @@
+var RFC3986 = require('./rfc3986');
+
+var internals = {
+    Ip: {
+        cidrs: {
+            required: '\\/(?:' + RFC3986.cidr + ')',
+            optional: '(?:\\/(?:' + RFC3986.cidr + '))?',
+            forbidden: ''
+        },
+        versions: {
+            ipv4: RFC3986.IPv4address,
+            ipv6: RFC3986.IPv6address,
+            ipvfuture: RFC3986.IPvFuture
+        }
+    }
+};
+
+internals.Ip.createIpRegex = function (versions, cidr) {
+
+    var regex;
+    for (var i = 0, il = versions.length; i < il; ++i) {
+        var version = versions[i];
+        if (!regex) {
+            regex = '^(?:' + internals.Ip.versions[version];
+        }
+        regex += '|' + internals.Ip.versions[version];
+    }
+
+    return new RegExp(regex + ')' + internals.Ip.cidrs[cidr] + '$');
+};
+
+module.exports = internals.Ip;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/string/rfc3986.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/string/rfc3986.js
new file mode 100644
index 0000000000000000000000000000000000000000..b5ca375f29220b2ca9eab33d4dde31d2cf834fd2
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/string/rfc3986.js
@@ -0,0 +1,174 @@
+var internals = {
+    rfc3986: {}
+};
+
+/**
+ * elements separated by forward slash ("/") are alternatives.
+ */
+var or = '|';
+
+/**
+ * DIGIT = %x30-39 ; 0-9
+ */
+var digit = '0-9';
+var digitOnly = '[' + digit + ']';
+
+/**
+ * ALPHA = %x41-5A / %x61-7A   ; A-Z / a-z
+ */
+var alpha = 'a-zA-Z';
+var alphaOnly = '[' + alpha + ']';
+
+/**
+ * cidr       = DIGIT                ; 0-9
+ *            / %x31-32 DIGIT         ; 10-29
+ *            / "3" %x30-32           ; 30-32
+ */
+internals.rfc3986.cidr = digitOnly + or + '[1-2]' + digitOnly + or + '3' + '[0-2]';
+
+/**
+ * HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
+ */
+var hexDigit = digit + 'A-Fa-f',
+    hexDigitOnly = '[' + hexDigit + ']';
+
+/**
+ * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+ */
+var unreserved = alpha + digit + '-\\._~';
+
+/**
+ * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
+ */
+var subDelims = '!\\$&\'\\(\\)\\*\\+,;=';
+
+/**
+ * pct-encoded = "%" HEXDIG HEXDIG
+ */
+var pctEncoded = '%' + hexDigit;
+
+/**
+ * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+ */
+var pchar = unreserved + pctEncoded + subDelims + ':@';
+var pcharOnly = '[' + pchar + ']';
+
+/**
+ * Rule to support zero-padded addresses.
+ */
+var zeroPad = '0?';
+
+/**
+ * dec-octet   = DIGIT                 ; 0-9
+ *            / %x31-39 DIGIT         ; 10-99
+ *            / "1" 2DIGIT            ; 100-199
+ *            / "2" %x30-34 DIGIT     ; 200-249
+ *            / "25" %x30-35          ; 250-255
+ */
+var decOctect = '(?:' + zeroPad + zeroPad + digitOnly + or + zeroPad + '[1-9]' + digitOnly + or + '1' + digitOnly + digitOnly + or + '2' + '[0-4]' + digitOnly + or + '25' + '[0-5])';
+
+/**
+ * IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
+ */
+internals.rfc3986.IPv4address = '(?:' + decOctect + '\\.){3}' + decOctect;
+
+/**
+ * h16 = 1*4HEXDIG ; 16 bits of address represented in hexadecimal
+ * ls32 = ( h16 ":" h16 ) / IPv4address ; least-significant 32 bits of address
+ * IPv6address =                            6( h16 ":" ) ls32
+ *             /                       "::" 5( h16 ":" ) ls32
+ *             / [               h16 ] "::" 4( h16 ":" ) ls32
+ *             / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
+ *             / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
+ *             / [ *3( h16 ":" ) h16 ] "::"    h16 ":"   ls32
+ *             / [ *4( h16 ":" ) h16 ] "::"              ls32
+ *             / [ *5( h16 ":" ) h16 ] "::"              h16
+ *             / [ *6( h16 ":" ) h16 ] "::"
+ */
+var h16 = hexDigitOnly + '{1,4}';
+var ls32 = '(?:' + h16 + ':' + h16 + '|' + internals.rfc3986.IPv4address + ')';
+var IPv6SixHex = '(?:' + h16 + ':){6}' + ls32;
+var IPv6FiveHex = '::(?:' + h16 + ':){5}' + ls32;
+var IPv6FourHex = h16 + '::(?:' + h16 + ':){4}' + ls32;
+var IPv6ThreeHex = '(?:' + h16 + ':){0,1}' + h16 + '::(?:' + h16 + ':){3}' + ls32;
+var IPv6TwoHex = '(?:' + h16 + ':){0,2}' + h16 + '::(?:' + h16 + ':){2}' + ls32;
+var IPv6OneHex = '(?:' + h16 + ':){0,3}' + h16 + '::' + h16 + ':' + ls32;
+var IPv6NoneHex = '(?:' + h16 + ':){0,4}' + h16 + '::' + ls32;
+var IPv6NoneHex2 = '(?:' + h16 + ':){0,5}' + h16 + '::' + h16;
+var IPv6NoneHex3 = '(?:' + h16 + ':){0,6}' + h16 + '::';
+internals.rfc3986.IPv6address = '(?:' + IPv6SixHex + or + IPv6FiveHex + or + IPv6FourHex + or + IPv6ThreeHex + or + IPv6TwoHex + or + IPv6OneHex + or + IPv6NoneHex + or + IPv6NoneHex2 + or + IPv6NoneHex3 + ')';
+
+/**
+ * IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
+ */
+internals.rfc3986.IPvFuture = 'v' + hexDigitOnly + '+\\.[' + unreserved + subDelims + ':]+';
+
+/**
+ * scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+ */
+internals.rfc3986.scheme = alphaOnly + '[' + alpha + digit + '+-\\.]*';
+
+/**
+ * userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
+ */
+var userinfo = '[' + unreserved + pctEncoded + subDelims + ':]*';
+
+/**
+ * IP-literal = "[" ( IPv6address / IPvFuture  ) "]"
+ */
+var IPLiteral = '\\[(?:' + internals.rfc3986.IPv6address + or + internals.rfc3986.IPvFuture + ')\\]';
+
+/**
+ * reg-name = *( unreserved / pct-encoded / sub-delims )
+ */
+var regName = '[' + unreserved + pctEncoded + subDelims + ']{0,255}';
+
+/**
+ * host = IP-literal / IPv4address / reg-name
+ */
+var host = '(?:' + IPLiteral + or + internals.rfc3986.IPv4address + or + regName + ')';
+
+/**
+ * port = *DIGIT
+ */
+var port = digitOnly + '*';
+
+/**
+ * authority   = [ userinfo "@" ] host [ ":" port ]
+ */
+var authority = '(?:' + userinfo + '@)?' + host + '(?::' + port + ')?';
+
+/**
+ * segment       = *pchar
+ * segment-nz    = 1*pchar
+ * path          = path-abempty    ; begins with "/" or is empty
+ *               / path-absolute   ; begins with "/" but not "//"
+ *               / path-noscheme   ; begins with a non-colon segment
+ *               / path-rootless   ; begins with a segment
+ *               / path-empty      ; zero characters
+ * path-abempty  = *( "/" segment )
+ * path-absolute = "/" [ segment-nz *( "/" segment ) ]
+ * path-rootless = segment-nz *( "/" segment )
+ */
+var segment = pcharOnly + '*';
+var segmentNz = pcharOnly + '+';
+var pathAbEmpty = '(?:\\/' + segment + ')*';
+var pathAbsolute = '\\/(?:' + segmentNz + pathAbEmpty + ')?';
+var pathRootless = segmentNz + pathAbEmpty;
+
+/**
+ * hier-part = "//" authority path
+ */
+internals.rfc3986.hierPart = '(?:\\/\\/' + authority + pathAbEmpty + or + pathAbsolute + or + pathRootless + ')';
+
+/**
+ * query = *( pchar / "/" / "?" )
+ */
+internals.rfc3986.query = '[' + pchar + '\\/\\?]*(?=#|$)'; //Finish matching either at the fragment part or end of the line.
+
+/**
+ * fragment = *( pchar / "/" / "?" )
+ */
+internals.rfc3986.fragment = '[' + pchar + '\\/\\?]*';
+
+module.exports = internals.rfc3986;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/string/uri.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/string/uri.js
new file mode 100644
index 0000000000000000000000000000000000000000..abb9d113896ed21181b6d102dcb204a8a76fbf10
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/lib/string/uri.js
@@ -0,0 +1,24 @@
+var RFC3986 = require('./rfc3986');
+
+var internals = {
+    Uri: {
+        createUriRegex: function (optionalScheme) {
+
+            var scheme = RFC3986.scheme;
+
+            // If we were passed a scheme, use it instead of the generic one
+            if (optionalScheme) {
+
+                // Have to put this in a non-capturing group to handle the OR statements
+                scheme = '(?:' + optionalScheme + ')';
+            }
+
+            /**
+             * URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
+             */
+            return new RegExp('^' + scheme + ':' + RFC3986.hierPart + '(?:\\?' + RFC3986.query + ')?' + '(?:#' + RFC3986.fragment + ')?$');
+        }
+    }
+};
+
+module.exports = internals.Uri;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/package.json b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..a550111ca0dc37d46c69957a0d4ca67f9e8d5daf
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/package.json
@@ -0,0 +1,81 @@
+{
+  "_args": [
+    [
+      {
+        "raw": "joi@https://registry.npmjs.org/joi/-/joi-6.10.1.tgz",
+        "scope": null,
+        "escapedName": "joi",
+        "name": "joi",
+        "rawSpec": "https://registry.npmjs.org/joi/-/joi-6.10.1.tgz",
+        "spec": "https://registry.npmjs.org/joi/-/joi-6.10.1.tgz",
+        "type": "remote"
+      },
+      "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin"
+    ]
+  ],
+  "_from": "joi@>=6.10.1 <7.0.0",
+  "_id": "joi@6.10.1",
+  "_inCache": true,
+  "_location": "/firebase-admin/joi",
+  "_phantomChildren": {},
+  "_requested": {
+    "raw": "joi@https://registry.npmjs.org/joi/-/joi-6.10.1.tgz",
+    "scope": null,
+    "escapedName": "joi",
+    "name": "joi",
+    "rawSpec": "https://registry.npmjs.org/joi/-/joi-6.10.1.tgz",
+    "spec": "https://registry.npmjs.org/joi/-/joi-6.10.1.tgz",
+    "type": "remote"
+  },
+  "_requiredBy": [
+    "/firebase-admin",
+    "/firebase-admin/jsonwebtoken"
+  ],
+  "_resolved": "https://registry.npmjs.org/joi/-/joi-6.10.1.tgz",
+  "_shasum": "4d50c318079122000fe5f16af1ff8e1917b77e06",
+  "_shrinkwrap": null,
+  "_spec": "joi@https://registry.npmjs.org/joi/-/joi-6.10.1.tgz",
+  "_where": "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin",
+  "bugs": {
+    "url": "https://github.com/hapijs/joi/issues"
+  },
+  "dependencies": {
+    "hoek": "2.x.x",
+    "isemail": "1.x.x",
+    "moment": "2.x.x",
+    "topo": "1.x.x"
+  },
+  "description": "Object schema validation",
+  "devDependencies": {
+    "code": "1.x.x",
+    "lab": "6.x.x",
+    "markdown-toc": "0.11.x"
+  },
+  "engines": {
+    "node": ">=0.10.40",
+    "npm": ">=2.0.0"
+  },
+  "homepage": "https://github.com/hapijs/joi#readme",
+  "keywords": [
+    "hapi",
+    "schema",
+    "validation"
+  ],
+  "license": "BSD-3-Clause",
+  "main": "lib/index.js",
+  "name": "joi",
+  "optionalDependencies": {},
+  "readme": "![joi Logo](https://raw.github.com/hapijs/joi/master/images/joi.png)\n\nObject schema description language and validator for JavaScript objects.\n\n[![npm version](https://badge.fury.io/js/joi.svg)](http://badge.fury.io/js/joi)\n[![Build Status](https://secure.travis-ci.org/hapijs/joi.svg)](http://travis-ci.org/hapijs/joi)\n[![Dependencies Status](https://david-dm.org/hapijs/joi.svg)](https://david-dm.org/hapijs/joi)\n[![DevDependencies Status](https://david-dm.org/hapijs/joi/dev-status.svg)](https://david-dm.org/hapijs/joi#info=devDependencies)\n\n[![Join the chat at https://gitter.im/hapijs/joi](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/hapijs/joi?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)\n\nLead Maintainer: [Nicolas Morel](https://github.com/marsup)\n\n# Example\n\n```javascript\nvar Joi = require('joi');\n\nvar schema = Joi.object().keys({\n    username: Joi.string().alphanum().min(3).max(30).required(),\n    password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/),\n    access_token: [Joi.string(), Joi.number()],\n    birthyear: Joi.number().integer().min(1900).max(2013),\n    email: Joi.string().email()\n}).with('username', 'birthyear').without('password', 'access_token');\n\nJoi.validate({ username: 'abc', birthyear: 1994 }, schema, function (err, value) { });  // err === null -> valid\n```\n\nThe above schema defines the following constraints:\n* `username`\n    * a required string\n    * must contain only alphanumeric characters\n    * at least 3 characters long but no more than 30\n    * must be accompanied by `birthyear`\n* `password`\n    * an optional string\n    * must satisfy the custom regex\n    * cannot appear together with `access_token`\n* `access_token`\n    * an optional, unconstrained string or number\n* `birthyear`\n    * an integer between 1900 and 2013\n* `email`\n    * a valid email address string\n\n# Usage\n\nUsage is a two steps process. First, a schema is constructed using the provided types and constraints:\n\n```javascript\nvar schema = {\n    a: Joi.string()\n};\n```\n\nNote that **joi** schema objects are immutable which means every additional rule added (e.g. `.min(5)`) will return a\nnew schema object.\n\nThen the value is validated against the schema:\n\n```javascript\nJoi.validate({ a: 'a string' }, schema, function (err, value) { });\n```\n\nIf the value is valid, `null` is returned, otherwise an `Error` object.\n\nThe schema can be a plain JavaScript object where every key is assigned a **joi** type, or it can be a **joi** type directly:\n\n```javascript\nvar schema = Joi.string().min(10);\n```\n\nIf the schema is a **joi** type, the `schema.validate(value, callback)` can be called directly on the type. When passing a non-type schema object,\nthe module converts it internally to an object() type equivalent to:\n\n```javascript\nvar schema = Joi.object().keys({\n    a: Joi.string()\n});\n```\n\nWhen validating a schema:\n\n* Keys are optional by default.\n* Strings are utf-8 encoded by default.\n* Rules are defined in an additive fashion and evaluated in order after whitelist and blacklist checks.\n\n# API\nSee the [API Reference](API.md).",
+  "readmeFilename": "README.md",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/hapijs/joi.git"
+  },
+  "scripts": {
+    "test": "lab -t 100 -a code -L",
+    "test-cov-html": "lab -r html -o coverage.html -a code",
+    "toc": "node generate-readme-toc.js",
+    "version": "npm run toc && git add API.md"
+  },
+  "version": "6.10.1"
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/alternatives.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/alternatives.js
new file mode 100755
index 0000000000000000000000000000000000000000..5ad3e688afb9eca93407894fdef28f190493dbe3
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/alternatives.js
@@ -0,0 +1,488 @@
+// Load modules
+
+var Lab = require('lab');
+var Code = require('code');
+var Joi = require('..');
+var Helper = require('./helper');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var lab = exports.lab = Lab.script();
+var describe = lab.describe;
+var it = lab.it;
+var expect = Code.expect;
+
+
+describe('alternatives', function () {
+
+    it('fails when no alternatives are provided', function (done) {
+
+        Joi.alternatives().validate('a', function (err, value) {
+
+            expect(err).to.exist();
+            expect(err.message).to.equal('"value" not matching any of the allowed alternatives');
+            done();
+        });
+    });
+
+    it('allows undefined when no alternatives are provided', function (done) {
+
+        Joi.alternatives().validate(undefined, function (err, value) {
+
+            expect(err).to.not.exist();
+            done();
+        });
+    });
+
+    it('applies modifiers when higher priority converts', function (done) {
+
+        var schema = Joi.object({
+            a: [
+                Joi.number(),
+                Joi.string()
+            ]
+        });
+
+        schema.validate({ a: '5' }, function (err, value) {
+
+            expect(err).to.not.exist();
+            expect(value.a).to.equal(5);
+            done();
+        });
+    });
+
+    it('applies modifiers when lower priority valid is a match', function (done) {
+
+        var schema = Joi.object({
+            a: [
+                Joi.number(),
+                Joi.valid('5')
+            ]
+        });
+
+        schema.validate({ a: '5' }, function (err, value) {
+
+            expect(err).to.not.exist();
+            expect(value.a).to.equal(5);
+            done();
+        });
+    });
+
+    it('does not apply modifier if alternative fails', function (done) {
+
+        var schema = Joi.object({
+            a: [
+                Joi.object({ c: Joi.any(), d: Joi.number() }).rename('b', 'c'),
+                { b: Joi.any(), d: Joi.string() }
+            ]
+        });
+
+        var input = { a: { b: 'any', d: 'string' } };
+        schema.validate(input, function (err, value) {
+
+            expect(err).to.not.exist();
+            expect(value.a.b).to.equal('any');
+            done();
+        });
+    });
+
+    describe('#try', function () {
+
+        it('throws when missing alternatives', function (done) {
+
+            expect(function () {
+
+                Joi.alternatives().try();
+            }).to.throw('Cannot add other alternatives without at least one schema');
+            done();
+        });
+    });
+
+    describe('#when', function () {
+
+        it('throws on invalid ref (not string)', function (done) {
+
+            expect(function () {
+
+                Joi.alternatives().when(5, { is: 6, then: Joi.number() });
+            }).to.throw('Invalid reference: 5');
+            done();
+        });
+
+        it('validates conditional alternatives', function (done) {
+
+            var schema = {
+                a: Joi.alternatives().when('b', { is: 5, then: 'x', otherwise: 'y' })
+                                     .try('z'),
+                b: Joi.any()
+            };
+
+            Helper.validate(schema, [
+                [{ a: 'x', b: 5 }, true],
+                [{ a: 'x', b: 6 }, false],
+                [{ a: 'y', b: 5 }, false],
+                [{ a: 'y', b: 6 }, true],
+                [{ a: 'z', b: 5 }, true],
+                [{ a: 'z', b: 6 }, true]
+            ], done);
+        });
+
+        it('validates conditional alternatives (empty key)', function (done) {
+
+            var schema = {
+                a: Joi.alternatives().when('', { is: 5, then: 'x', otherwise: 'y' })
+                                     .try('z'),
+                '': Joi.any()
+            };
+
+            Helper.validate(schema, [
+                [{ a: 'x', '': 5 }, true],
+                [{ a: 'x', '': 6 }, false],
+                [{ a: 'y', '': 5 }, false],
+                [{ a: 'y', '': 6 }, true],
+                [{ a: 'z', '': 5 }, true],
+                [{ a: 'z', '': 6 }, true]
+            ], done);
+        });
+
+        it('validates only then', function (done) {
+
+            var schema = {
+                a: Joi.alternatives().when(Joi.ref('b'), { is: 5, then: 'x' })
+                                     .try('z'),
+                b: Joi.any()
+            };
+
+            Helper.validate(schema, [
+                [{ a: 'x', b: 5 }, true],
+                [{ a: 'x', b: 6 }, false],
+                [{ a: 'y', b: 5 }, false],
+                [{ a: 'y', b: 6 }, false],
+                [{ a: 'z', b: 5 }, true],
+                [{ a: 'z', b: 6 }, true]
+            ], done);
+        });
+
+        it('validates only otherwise', function (done) {
+
+            var schema = {
+                a: Joi.alternatives().when('b', { is: 5, otherwise: 'y' })
+                                     .try('z'),
+                b: Joi.any()
+            };
+
+            Helper.validate(schema, [
+                [{ a: 'x', b: 5 }, false],
+                [{ a: 'x', b: 6 }, false],
+                [{ a: 'y', b: 5 }, false],
+                [{ a: 'y', b: 6 }, true],
+                [{ a: 'z', b: 5 }, true],
+                [{ a: 'z', b: 6 }, true]
+            ], done);
+        });
+
+        it('validates when is is null', function (done) {
+
+            var schema = {
+                a: Joi.alternatives().when('b', { is: null, then: 'x', otherwise: Joi.number() }),
+                b: Joi.any()
+            };
+
+            Helper.validate(schema, [
+                [{ a: 1 }, true],
+                [{ a: 'y' }, false],
+                [{ a: 'x', b: null }, true],
+                [{ a: 'y', b: null }, false],
+                [{ a: 1, b: null }, false]
+            ], done);
+        });
+
+        it('validates when is has ref', function (done) {
+
+            var schema = {
+                a: Joi.alternatives().when('b', { is: Joi.ref('c'), then: 'x' }),
+                b: Joi.any(),
+                c: Joi.number()
+            };
+
+            Helper.validate(schema, [
+                [{ a: 'x', b: 5, c: '5' }, true],
+                [{ a: 'x', b: 5, c: '1' }, false],
+                [{ a: 'x', b: '5', c: '5' }, false],
+                [{ a: 'y', b: 5, c: 5 }, false],
+                [{ a: 'y' }, false]
+            ], done);
+        });
+
+        it('validates when then has ref', function (done) {
+
+            var schema = {
+                a: Joi.alternatives().when('b', { is: 5, then: Joi.ref('c') }),
+                b: Joi.any(),
+                c: Joi.number()
+            };
+
+            Helper.validate(schema, [
+                [{ a: 'x', b: 5, c: '1' }, false],
+                [{ a: 1, b: 5, c: '1' }, true],
+                [{ a: '1', b: 5, c: '1' }, false]
+            ], done);
+        });
+
+        it('validates when otherwise has ref', function (done) {
+
+            var schema = {
+                a: Joi.alternatives().when('b', { is: 6, otherwise: Joi.ref('c') }),
+                b: Joi.any(),
+                c: Joi.number()
+            };
+
+            Helper.validate(schema, [
+                [{ a: 'x', b: 5, c: '1' }, false],
+                [{ a: 1, b: 5, c: '1' }, true],
+                [{ a: '1', b: 5, c: '1' }, false]
+            ], done);
+        });
+
+        it('validates when empty value', function (done) {
+
+            var schema = {
+                a: Joi.alternatives().when('b', { is: true, then: Joi.required() }),
+                b: Joi.boolean().default(false)
+            };
+
+            Helper.validate(schema, [
+                [{ b: false }, true],
+                [{ b: true }, true]           // true because required() only applies to the one alternative
+            ], done);
+        });
+
+        it('validates when missing value', function (done) {
+
+            var schema = Joi.object({
+                a: Joi.alternatives().when('b', { is: 5, then: Joi.optional(), otherwise: Joi.required() }).required(),
+                b: Joi.number()
+            });
+
+            Helper.validate(schema, [
+                [{ a: 1 }, true],
+                [{}, false],
+                [{ b: 1 }, false],
+                [{ a: 1, b: 1 }, true],
+                [{ a: 1, b: 5 }, true],
+                [{ b: 5 }, false]
+            ], done);
+        });
+    });
+
+    describe('#describe', function () {
+
+        it('describes when', function (done) {
+
+            var schema = {
+                a: Joi.alternatives().when('b', { is: 5, then: 'x', otherwise: 'y' })
+                                     .try('z'),
+                b: Joi.any()
+            };
+
+            var outcome = {
+                type: 'object',
+                children: {
+                    b: {
+                        type: 'any'
+                    },
+                    a: {
+                        type: 'alternatives',
+                        alternatives: [
+                            {
+                                ref: 'ref:b',
+                                is: {
+                                    type: 'number',
+                                    flags: {
+                                        allowOnly: true,
+                                        presence: 'required'
+                                    },
+                                    valids: [5],
+                                    invalids: [Infinity, -Infinity]
+                                },
+                                then: {
+                                    type: 'string',
+                                    flags: {
+                                        allowOnly: true
+                                    },
+                                    valids: ['x'],
+                                    invalids: ['']
+                                },
+                                otherwise: {
+                                    type: 'string',
+                                    flags: {
+                                        allowOnly: true
+                                    },
+                                    valids: ['y'],
+                                    invalids: ['']
+                                }
+                            },
+                            {
+                                type: 'string',
+                                flags: {
+                                    allowOnly: true
+                                },
+                                valids: ['z'],
+                                invalids: ['']
+                            }
+                        ]
+                    }
+                }
+            };
+
+            expect(Joi.describe(schema)).to.deep.equal(outcome);
+            done();
+        });
+
+        it('describes when (only then)', function (done) {
+
+            var schema = {
+                a: Joi.alternatives().when('b', { is: 5, then: 'x' })
+                                     .try('z'),
+                b: Joi.any()
+            };
+
+            var outcome = {
+                type: 'object',
+                children: {
+                    b: {
+                        type: 'any'
+                    },
+                    a: {
+                        type: 'alternatives',
+                        alternatives: [
+                            {
+                                ref: 'ref:b',
+                                is: {
+                                    type: 'number',
+                                    flags: {
+                                        allowOnly: true,
+                                        presence: 'required'
+                                    },
+                                    valids: [5],
+                                    invalids: [Infinity, -Infinity]
+                                },
+                                then: {
+                                    type: 'string',
+                                    flags: {
+                                        allowOnly: true
+                                    },
+                                    valids: ['x'],
+                                    invalids: ['']
+                                }
+                            },
+                            {
+                                type: 'string',
+                                flags: {
+                                    allowOnly: true
+                                },
+                                valids: ['z'],
+                                invalids: ['']
+                            }
+                        ]
+                    }
+                }
+            };
+
+            expect(Joi.describe(schema)).to.deep.equal(outcome);
+            done();
+        });
+
+        it('describes when (only otherwise)', function (done) {
+
+            var schema = {
+                a: Joi.alternatives().when('b', { is: 5, otherwise: 'y' })
+                                     .try('z'),
+                b: Joi.any()
+            };
+
+            var outcome = {
+                type: 'object',
+                children: {
+                    b: {
+                        type: 'any'
+                    },
+                    a: {
+                        type: 'alternatives',
+                        alternatives: [
+                            {
+                                ref: 'ref:b',
+                                is: {
+                                    type: 'number',
+                                    flags: {
+                                        allowOnly: true,
+                                        presence: 'required'
+                                    },
+                                    valids: [5],
+                                    invalids: [Infinity, -Infinity]
+                                },
+                                otherwise: {
+                                    type: 'string',
+                                    flags: {
+                                        allowOnly: true
+                                    },
+                                    valids: ['y'],
+                                    invalids: ['']
+                                }
+                            },
+                            {
+                                type: 'string',
+                                flags: {
+                                    allowOnly: true
+                                },
+                                valids: ['z'],
+                                invalids: ['']
+                            }
+                        ]
+                    }
+                }
+            };
+
+            expect(Joi.describe(schema)).to.deep.equal(outcome);
+            done();
+        });
+
+        it('describes inherited fields (from any)', function (done) {
+
+            var schema = Joi.alternatives()
+                .try('a')
+                .description('d')
+                .example('a')
+                .meta('b')
+                .meta('c')
+                .notes('f')
+                .tags('g');
+
+            var outcome = {
+                type: 'alternatives',
+                description: 'd',
+                notes: ['f'],
+                tags: ['g'],
+                meta: ['b', 'c'],
+                examples: ['a'],
+                alternatives: [{
+                    type: 'string',
+                    flags: {
+                        allowOnly: true
+                    },
+                    valids: ['a'],
+                    invalids: ['']
+                }]
+            };
+
+            expect(Joi.describe(schema)).to.deep.equal(outcome);
+            done();
+        });
+    });
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/any.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/any.js
new file mode 100755
index 0000000000000000000000000000000000000000..5b41fd5becd5319815b2c0047265c6055c457f58
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/any.js
@@ -0,0 +1,1595 @@
+// Load modules
+
+var Lab = require('lab');
+var Code = require('code');
+var Joi = require('../lib');
+var Helper = require('./helper');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var lab = exports.lab = Lab.script();
+var describe = lab.describe;
+var it = lab.it;
+var expect = Code.expect;
+
+
+describe('any', function () {
+
+    describe('#equal', function () {
+
+        it('validates valid values', function (done) {
+
+            Helper.validate(Joi.equal(4), [
+                [4, true],
+                [5, false]
+            ], done);
+        });
+    });
+
+    describe('#not', function () {
+
+        it('validates invalid values', function (done) {
+
+            Helper.validate(Joi.not(5), [
+                [4, true],
+                [5, false]
+            ], done);
+        });
+    });
+
+    describe('#exist', function () {
+
+        it('validates required values', function (done) {
+
+            Helper.validate(Joi.exist(), [
+                [4, true],
+                [undefined, false]
+            ], done);
+        });
+    });
+
+    describe('#strict', function () {
+
+        it('validates without converting', function (done) {
+
+            var schema = Joi.object({
+                array: Joi.array().items(Joi.string().min(5), Joi.number().min(3))
+            }).strict();
+
+            Helper.validate(schema, [
+                [{ array: ['12345'] }, true],
+                [{ array: ['1'] }, false],
+                [{ array: [3] }, true],
+                [{ array: ['12345', 3] }, true],
+                [{ array: ['3'] }, false],
+                [{ array: [1] }, false]
+            ], done);
+        });
+
+        it('can be disabled', function (done) {
+
+            var schema = Joi.object({
+                array: Joi.array().items(Joi.string().min(5), Joi.number().min(3))
+            }).strict().strict(false);
+
+            Helper.validate(schema, [
+                [{ array: ['12345'] }, true],
+                [{ array: ['1'] }, false],
+                [{ array: [3] }, true],
+                [{ array: ['12345', 3] }, true],
+                [{ array: ['3'] }, true],
+                [{ array: [1] }, false]
+            ], done);
+        });
+    });
+
+    describe('#options', function () {
+
+        it('adds to existing options', function (done) {
+
+            var schema = Joi.object({ b: Joi.number().strict().options({ convert: true }) });
+            var input = { b: '2' };
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value.b).to.equal(2);
+                done();
+            });
+        });
+
+        it('throws with an invalid option', function (done) {
+
+            expect(function () {
+
+                Joi.any().options({ foo: 'bar' });
+            }).to.throw('unknown key foo');
+            done();
+        });
+
+        it('throws with an invalid option type', function (done) {
+
+            expect(function () {
+
+                Joi.any().options({ convert: 'yes' });
+            }).to.throw('convert should be of type boolean');
+            done();
+        });
+
+        it('throws with an invalid option value', function (done) {
+
+            expect(function () {
+
+                Joi.any().options({ presence: 'yes' });
+            }).to.throw('presence should be one of required, optional, forbidden, ignore');
+            done();
+        });
+
+        it('does not throw with multiple options including presence key', function (done) {
+
+            expect(function () {
+
+                Joi.any().options({ presence: 'optional', raw: true });
+            }).to.not.throw();
+            done();
+        });
+    });
+
+    describe('#label', function () {
+
+        it('adds to existing options', function (done) {
+
+            var schema = Joi.object({ b: Joi.string().email().label('Custom label') });
+            var input = { b: 'not_a_valid_email' };
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.details[0].message).to.equal('"Custom label" must be a valid email');
+                done();
+            });
+        });
+
+        it('throws when label is missing', function (done) {
+
+            expect(function () {
+
+                Joi.label();
+            }).to.throw('Label name must be a non-empty string');
+            done();
+        });
+
+        it('can describe a label', function (done) {
+
+            var schema = Joi.object().label('lbl').describe();
+            expect(schema).to.deep.equal({ type: 'object', label: 'lbl' });
+            done();
+        });
+    });
+
+    describe('#strict', function () {
+
+        it('adds to existing options', function (done) {
+
+            var schema = Joi.object({ b: Joi.number().options({ convert: true }).strict() });
+            var input = { b: '2' };
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.exist();
+                expect(value.b).to.equal('2');
+                done();
+            });
+        });
+    });
+
+    describe('#raw', function () {
+
+        it('gives the raw input', function (done) {
+
+            var tests = [
+                [Joi.array(), '[1,2,3]'],
+                [Joi.binary(), 'abc'],
+                [Joi.boolean(), 'false'],
+                [Joi.date().format('YYYYMMDD'), '19700101'],
+                [Joi.number(), '12'],
+                [Joi.object(), '{ "a": 1 }'],
+                [Joi.any().strict(), 'abc']
+            ];
+
+            tests.forEach(function (test) {
+
+                var baseSchema = test[0];
+                var input = test[1];
+                var schemas = [
+                    baseSchema.raw(),
+                    baseSchema.raw(true),
+                    baseSchema.options({ raw: true })
+                ];
+
+                schemas.forEach(function (schema) {
+
+                    schema.raw().validate(input, function (err, value) {
+
+                        expect(err).to.not.exist();
+                        expect(value).to.equal(input);
+                    });
+                });
+            });
+
+            done();
+        });
+    });
+
+    describe('#default', function () {
+
+        it('sets the value', function (done) {
+
+            var schema = Joi.object({ foo: Joi.string().default('test') });
+            var input = {};
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value.foo).to.equal('test');
+                done();
+            });
+        });
+
+        it('throws when value is a method and no description is provided', function (done) {
+
+            expect(function () {
+
+                Joi.object({
+                    foo: Joi.string().default(function () {
+
+                        return 'test';
+
+                    })
+                });
+            }).to.throw();
+
+            done();
+        });
+
+        it('allows passing description as a property of a default method', function (done) {
+
+            var defaultFn = function () {
+
+                return 'test';
+            };
+            defaultFn.description = 'test';
+
+            expect(function () {
+
+                Joi.object({ foo: Joi.string().default(defaultFn) });
+            }).to.not.throw();
+
+            done();
+        });
+
+        it('sets the value when passing a method', function (done) {
+
+            var schema = Joi.object({
+                foo: Joi.string().default(function () {
+
+                    return 'test';
+                }, 'testing')
+            });
+            var input = {};
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value.foo).to.equal('test');
+                done();
+            });
+        });
+
+        it('executes the default method each time validate is called', function (done) {
+
+            var count = 0;
+            var schema = Joi.object({
+                foo: Joi.number().default(function () {
+
+                    return ++count;
+                }, 'incrementer')
+            });
+            var input = {};
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value.foo).to.equal(1);
+            });
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value.foo).to.equal(2);
+            });
+
+            done();
+        });
+
+        it('passes a clone of the context if the default method accepts an argument', function (done) {
+
+            var schema = Joi.object({
+                foo: Joi.string().default(function (context) {
+
+                    return context.bar + 'ing';
+                }, 'testing'),
+                bar: Joi.string()
+            });
+            var input = { bar: 'test' };
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value.foo).to.equal('testing');
+                done();
+            });
+        });
+
+        it('does not modify the original object when modifying the clone in a default method', function (done) {
+
+            var defaultFn = function (context) {
+
+                context.bar = 'broken';
+                return 'test';
+            };
+            defaultFn.description = 'testing';
+
+            var schema = Joi.object({
+                foo: Joi.string().default(defaultFn),
+                bar: Joi.string()
+            });
+            var input = { bar: 'test' };
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value.bar).to.equal('test');
+                expect(value.foo).to.equal('test');
+                done();
+            });
+        });
+
+        it('passes undefined as the context if the default method has no parent', function (done) {
+
+            var c;
+            var methodCalled = false;
+            var schema = Joi.string().default(function (context) {
+
+                methodCalled = true;
+                c = context;
+                return 'test';
+            }, 'testing');
+
+            schema.validate(undefined, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(methodCalled).to.equal(true);
+                expect(c).to.equal(undefined);
+                expect(value).to.equal('test');
+                done();
+            });
+        });
+
+        it('allows passing a method with no description to default when the object being validated is a function', function (done) {
+
+            var defaultFn = function () {
+
+                return 'just a function';
+            };
+
+            var schema;
+            expect(function () {
+
+                schema = Joi.func().default(defaultFn);
+            }).to.not.throw();
+
+            schema.validate(undefined, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.deep.equal(defaultFn);
+                done();
+            });
+        });
+
+        it('allows passing a method that generates a default method when validating a function', function (done) {
+
+            var defaultFn = function () {
+
+                return 'just a function';
+            };
+
+            var defaultGeneratorFn = function () {
+
+                return defaultFn;
+            };
+            defaultGeneratorFn.description = 'generate a default fn';
+
+            var schema;
+            expect(function () {
+
+                schema = Joi.func().default(defaultGeneratorFn);
+            }).to.not.throw();
+
+            schema.validate(undefined, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.deep.equal(defaultFn);
+                done();
+            });
+        });
+
+        it('allows passing a ref as a default without a description', function (done) {
+
+            var schema = Joi.object({
+                a: Joi.string(),
+                b: Joi.string().default(Joi.ref('a'))
+            });
+
+            schema.validate({ a: 'test' }, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value.a).to.equal('test');
+                expect(value.b).to.equal('test');
+                done();
+            });
+        });
+
+        it('ignores description when passing a ref as a default', function (done) {
+
+            var schema = Joi.object({
+                a: Joi.string(),
+                b: Joi.string().default(Joi.ref('a'), 'this is a ref')
+            });
+
+            schema.validate({ a: 'test' }, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value.a).to.equal('test');
+                expect(value.b).to.equal('test');
+                done();
+            });
+        });
+
+        it('catches errors in default methods', function (done) {
+
+            var defaultFn = function () {
+
+                throw new Error('boom');
+            };
+            defaultFn.description = 'broken method';
+
+            var schema = Joi.string().default(defaultFn);
+
+            schema.validate(undefined, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.details).to.have.length(1);
+                expect(err.details[0].message).to.contain('threw an error when running default method');
+                expect(err.details[0].type).to.equal('any.default');
+                expect(err.details[0].context).to.be.an.instanceof(Error);
+                expect(err.details[0].context.message).to.equal('boom');
+                done();
+            });
+        });
+
+        it('should not overide a value when value is given', function (done) {
+
+            var schema = Joi.object({ foo: Joi.string().default('bar') });
+            var input = { foo: 'test' };
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value.foo).to.equal('test');
+                done();
+            });
+        });
+
+        it('sets value based on condition (outer)', function (done) {
+
+            var schema = Joi.object({
+                a: Joi.boolean(),
+                b: Joi.boolean().default(false).when('a', { is: true, then: Joi.required(), otherwise: Joi.forbidden() })
+            });
+
+            schema.validate({ a: false }, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value.b).to.equal(false);
+                done();
+            });
+        });
+
+        it('sets value based on condition (inner)', function (done) {
+
+            var schema = Joi.object({
+                a: Joi.boolean(),
+                b: Joi.boolean().when('a', { is: true, then: Joi.default(false), otherwise: Joi.forbidden() })
+            });
+
+            schema.validate({ a: true }, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value.b).to.equal(false);
+                done();
+            });
+        });
+
+        it('creates deep defaults', function (done) {
+
+            var schema = Joi.object({
+                a: Joi.number().default(42),
+                b: Joi.object({
+                    c: Joi.boolean().default(true),
+                    d: Joi.string()
+                }).default()
+            }).default();
+
+            Helper.validate(schema, [
+                [undefined, true, null, { a: 42, b: { c: true } }],
+                [{ a: 24 }, true, null, { a: 24, b: { c: true } }]
+            ], done);
+        });
+
+        it('should not affect objects other than object when called without an argument', function (done) {
+
+            var schema = Joi.object({
+                a: Joi.number().default()
+            }).default();
+
+            Helper.validate(schema, [
+                [undefined, true, null, {}],
+                [{ a: 24 }, true, null, { a: 24 }]
+            ], done);
+        });
+
+        it('should set default value as a clone', function (done) {
+
+            var defaultValue = { bar: 'val' };
+            var schema = Joi.object({ foo: Joi.object().default(defaultValue) });
+            var input = {};
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value.foo).to.not.equal(defaultValue);
+                expect(value.foo).to.only.deep.include({ bar: 'val' });
+
+                value.foo.bar = 'mutated';
+
+                schema.validate(input, function (err2, value2) {
+
+                    expect(err2).to.not.exist();
+                    expect(value2.foo).to.not.equal(defaultValue);
+                    expect(value2.foo).to.only.deep.include({ bar: 'val' });
+
+                    done();
+                });
+            });
+        });
+
+        it('should not apply default values if the noDefaults option is enquire', function (done) {
+
+            var schema = Joi.object({
+                a: Joi.string().default('foo'),
+                b: Joi.number()
+            });
+
+            var input = { b: 42 };
+
+            Joi.validate(input, schema, { noDefaults: true }, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value.a).to.not.exist();
+                expect(value.b).to.be.equal(42);
+
+                done();
+            });
+        });
+
+        it('should not apply default values from functions if the noDefaults option is enquire', function (done) {
+
+            var func = function (context) {
+
+                return 'foo';
+            };
+
+            func.description = 'test parameter';
+
+            var schema = Joi.object({
+                a: Joi.string().default(func),
+                b: Joi.number()
+            });
+
+            var input = { b: 42 };
+
+            Joi.validate(input, schema, { noDefaults: true }, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value.a).to.not.exist();
+                expect(value.b).to.be.equal(42);
+
+                done();
+            });
+        });
+
+        it('should not apply default values from references if the noDefaults option is enquire', function (done) {
+
+            var schema = Joi.object({
+                a: Joi.string().default(Joi.ref('b')),
+                b: Joi.number()
+            });
+
+            var input = { b: 42 };
+
+            Joi.validate(input, schema, { noDefaults: true }, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value.a).to.not.exist();
+                expect(value.b).to.be.equal(42);
+
+                done();
+            });
+        });
+    });
+
+    describe('#optional', function () {
+
+        it('validates optional with default required', function (done) {
+
+            var schema = Joi.object({
+                a: Joi.any(),
+                b: Joi.any(),
+                c: {
+                    d: Joi.any()
+                }
+            }).options({ presence: 'required' });
+
+            Helper.validate(schema, [
+                [{ a: 5 }, false],
+                [{ a: 5, b: 6 }, false],
+                [{ a: 5, b: 6, c: {} }, false],
+                [{ a: 5, b: 6, c: { d: 7 } }, true],
+                [{}, false],
+                [{ b: 5 }, false]
+            ], done);
+        });
+    });
+
+    describe('#forbidden', function () {
+
+        it('validates forbidden', function (done) {
+
+            var schema = {
+                a: Joi.number(),
+                b: Joi.forbidden()
+            };
+
+            Helper.validate(schema, [
+                [{ a: 5 }, true],
+                [{ a: 5, b: 6 }, false],
+                [{ a: 'a' }, false],
+                [{}, true],
+                [{ b: undefined }, true],
+                [{ b: null }, false]
+            ], done);
+        });
+    });
+
+    describe('#strip', function () {
+
+        it('validates and returns undefined', function (done) {
+
+            var schema = Joi.string().strip();
+
+            schema.validate('test', function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.not.exist();
+                done();
+            });
+        });
+
+        it('validates and returns an error', function (done) {
+
+            var schema = Joi.string().strip();
+
+            schema.validate(1, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.message).to.equal('"value" must be a string');
+                done();
+            });
+        });
+    });
+
+    describe('#description', function () {
+
+        it('sets the description', function (done) {
+
+            var b = Joi.description('my description');
+            expect(b._description).to.equal('my description');
+            done();
+        });
+
+        it('throws when description is missing', function (done) {
+
+            expect(function () {
+
+                Joi.description();
+            }).to.throw('Description must be a non-empty string');
+            done();
+        });
+    });
+
+    describe('#notes', function () {
+
+        it('sets the notes', function (done) {
+
+            var b = Joi.notes(['a']).notes('my notes');
+            expect(b._notes).to.deep.equal(['a', 'my notes']);
+            done();
+        });
+
+        it('throws when notes are missing', function (done) {
+
+            expect(function () {
+
+                Joi.notes();
+            }).to.throw('Notes must be a non-empty string or array');
+            done();
+        });
+
+        it('throws when notes are invalid', function (done) {
+
+            expect(function () {
+
+                Joi.notes(5);
+            }).to.throw('Notes must be a non-empty string or array');
+            done();
+        });
+    });
+
+    describe('#tags', function () {
+
+        it('sets the tags', function (done) {
+
+            var b = Joi.tags(['tag1', 'tag2']).tags('tag3');
+            expect(b._tags).to.include('tag1');
+            expect(b._tags).to.include('tag2');
+            expect(b._tags).to.include('tag3');
+            done();
+        });
+
+        it('throws when tags are missing', function (done) {
+
+            expect(function () {
+
+                Joi.tags();
+            }).to.throw('Tags must be a non-empty string or array');
+            done();
+        });
+
+        it('throws when tags are invalid', function (done) {
+
+            expect(function () {
+
+                Joi.tags(5);
+            }).to.throw('Tags must be a non-empty string or array');
+            done();
+        });
+    });
+
+    describe('#meta', function () {
+
+        it('sets the meta', function (done) {
+
+            var meta = { prop: 'val', prop2: 3 };
+            var b = Joi.meta(meta);
+            expect(b.describe().meta).to.deep.equal([meta]);
+
+            b = b.meta({ other: true });
+            expect(b.describe().meta).to.deep.equal([meta, {
+                other: true
+            }]);
+
+            done();
+        });
+
+        it('throws when meta is missing', function (done) {
+
+            expect(function () {
+
+                Joi.meta();
+            }).to.throw('Meta cannot be undefined');
+            done();
+        });
+    });
+
+    describe('#example', function () {
+
+        it('sets an example', function (done) {
+
+            var schema = Joi.valid(5, 6, 7).example(5);
+            expect(schema._examples).to.include(5);
+            expect(schema.describe().examples).to.deep.equal([5]);
+            done();
+        });
+
+        it('throws when tags are missing', function (done) {
+
+            expect(function () {
+
+                Joi.example();
+            }).to.throw('Missing example');
+            done();
+        });
+
+        it('throws when example fails own rules', function (done) {
+
+            expect(function () {
+
+                Joi.valid(5, 6, 7).example(4);
+            }).to.throw('Bad example: "value" must be one of [5, 6, 7]');
+            done();
+        });
+    });
+
+    describe('#unit', function () {
+
+        it('sets the unit', function (done) {
+
+            var b = Joi.unit('milliseconds');
+            expect(b._unit).to.equal('milliseconds');
+            expect(b.describe().unit).to.equal('milliseconds');
+            done();
+        });
+
+        it('throws when unit is missing', function (done) {
+
+            expect(function () {
+
+                Joi.unit();
+            }).to.throw('Unit name must be a non-empty string');
+            done();
+        });
+    });
+
+    describe('#_validate', function () {
+
+        it('checks value after conversion', function (done) {
+
+            var schema = Joi.number().invalid(2);
+            Joi.validate('2', schema, { abortEarly: false }, function (err, value) {
+
+                expect(err).to.exist();
+                done();
+            });
+        });
+    });
+
+    describe('#concat', function () {
+
+        it('throws when schema is not any', function (done) {
+
+            expect(function () {
+
+                Joi.string().concat(Joi.number());
+            }).to.throw('Cannot merge type string with another type: number');
+            done();
+        });
+
+        it('throws when schema is missing', function (done) {
+
+            expect(function () {
+
+                Joi.string().concat();
+            }).to.throw('Invalid schema object');
+            done();
+        });
+
+        it('throws when schema is invalid', function (done) {
+
+            expect(function () {
+
+                Joi.string().concat(1);
+            }).to.throw('Invalid schema object');
+            done();
+        });
+
+        it('merges two schemas (settings)', function (done) {
+
+            var a = Joi.number().options({ convert: true });
+            var b = Joi.options({ convert: false });
+
+            Helper.validate(a, [
+                [1, true], ['1', true]
+            ]);
+
+            Helper.validate(a.concat(b), [
+                [1, true], ['1', false]
+            ], done);
+        });
+
+        it('merges two schemas (valid)', function (done) {
+
+            var a = Joi.string().valid('a');
+            var b = Joi.string().valid('b');
+
+            Helper.validate(a, [
+                ['a', true],
+                ['b', false]
+            ]);
+
+            Helper.validate(b, [
+                ['b', true],
+                ['a', false]
+            ]);
+
+            Helper.validate(a.concat(b), [
+                ['a', true],
+                ['b', true]
+            ], done);
+        });
+
+        it('merges two schemas (invalid)', function (done) {
+
+            var a = Joi.string().invalid('a');
+            var b = Joi.invalid('b');
+
+            Helper.validate(a, [
+                ['b', true], ['a', false]
+            ]);
+
+            Helper.validate(b, [
+                ['a', true], ['b', false]
+            ]);
+
+            Helper.validate(a.concat(b), [
+                ['a', false], ['b', false]
+            ], done);
+        });
+
+        it('merges two schemas (valid/invalid)', function (done) {
+
+            var a = Joi.string().valid('a').invalid('b');
+            var b = Joi.string().valid('b').invalid('a');
+
+            Helper.validate(a, [
+                ['a', true],
+                ['b', false]
+            ]);
+
+            Helper.validate(b, [
+                ['b', true],
+                ['a', false]
+            ]);
+
+            Helper.validate(a.concat(b), [
+                ['a', false],
+                ['b', true]
+            ], done);
+        });
+
+        it('merges two schemas (tests)', function (done) {
+
+            var a = Joi.number().min(5);
+            var b = Joi.number().max(10);
+
+            Helper.validate(a, [
+                [4, false], [11, true]
+            ]);
+
+            Helper.validate(b, [
+                [6, true], [11, false]
+            ]);
+
+            Helper.validate(a.concat(b), [
+                [4, false], [6, true], [11, false]
+            ], done);
+        });
+
+        it('merges two schemas (flags)', function (done) {
+
+            var a = Joi.string().valid('a');
+            var b = Joi.string().insensitive();
+
+            Helper.validate(a, [
+                ['a', true], ['A', false], ['b', false]
+            ]);
+
+            Helper.validate(a.concat(b), [
+                ['a', true], ['A', true], ['b', false]
+            ], done);
+        });
+
+        it('overrides and append information', function (done) {
+
+            var a = Joi.description('a').unit('a').tags('a').example('a');
+            var b = Joi.description('b').unit('b').tags('b').example('b');
+
+            var desc = a.concat(b).describe();
+            expect(desc).to.deep.equal({
+                type: 'any',
+                description: 'b',
+                tags: ['a', 'b'],
+                examples: ['a', 'b'],
+                unit: 'b'
+            });
+            done();
+        });
+
+        it('merges two objects (any key + specific key)', function (done) {
+
+            var a = Joi.object();
+            var b = Joi.object({ b: 1 });
+
+            Helper.validate(a, [
+                [{ b: 1 }, true], [{ b: 2 }, true]
+            ]);
+
+            Helper.validate(b, [
+                [{ b: 1 }, true], [{ b: 2 }, false]
+            ]);
+
+            Helper.validate(a.concat(b), [
+                [{ b: 1 }, true], [{ b: 2 }, false]
+            ]);
+
+            Helper.validate(b.concat(a), [
+                [{ b: 1 }, true], [{ b: 2 }, false]
+            ], done);
+        });
+
+        it('merges two objects (no key + any key)', function (done) {
+
+            var a = Joi.object({});
+            var b = Joi.object();
+
+            Helper.validate(a, [
+                [{}, true], [{ b: 2 }, false]
+            ]);
+
+            Helper.validate(b, [
+                [{}, true], [{ b: 2 }, true]
+            ]);
+
+            Helper.validate(a.concat(b), [
+                [{}, true], [{ b: 2 }, false]
+            ]);
+
+            Helper.validate(b.concat(a), [
+                [{}, true], [{ b: 2 }, false]
+            ], done);
+        });
+
+        it('merges two objects (key + key)', function (done) {
+
+            var a = Joi.object({ a: 1 });
+            var b = Joi.object({ b: 2 });
+
+            Helper.validate(a, [
+                [{ a: 1 }, true], [{ b: 2 }, false]
+            ]);
+
+            Helper.validate(b, [
+                [{ a: 1 }, false], [{ b: 2 }, true]
+            ]);
+
+            Helper.validate(a.concat(b), [
+                [{ a: 1 }, true], [{ b: 2 }, true]
+            ]);
+
+            Helper.validate(b.concat(a), [
+                [{ a: 1 }, true], [{ b: 2 }, true]
+            ], done);
+        });
+
+        it('merges two objects (renames)', function (done) {
+
+            var a = Joi.object({ a: 1 }).rename('c', 'a');
+            var b = Joi.object({ b: 2 }).rename('d', 'b');
+
+            a.concat(b).validate({ c: 1, d: 2 }, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.deep.equal({ a: 1, b: 2 });
+                done();
+            });
+        });
+
+        it('merges two objects (deps)', function (done) {
+
+            var a = Joi.object({ a: 1 });
+            var b = Joi.object({ b: 2 }).and('b', 'a');
+
+            a.concat(b).validate({ a: 1, b: 2 }, function (err, value) {
+
+                expect(err).to.not.exist();
+                done();
+            });
+        });
+
+        it('merges two objects (same key)', function (done) {
+
+            var a = Joi.object({ a: 1, b: 2, c: 3 });
+            var b = Joi.object({ b: 1, c: 2, a: 3 });
+
+            var ab = a.concat(b);
+
+            Helper.validate(a, [
+                [{ a: 1, b: 2, c: 3 }, true],
+                [{ a: 3, b: 1, c: 2 }, false]
+            ]);
+
+            Helper.validate(b, [
+                [{ a: 1, b: 2, c: 3 }, false],
+                [{ a: 3, b: 1, c: 2 }, true]
+            ]);
+
+            Helper.validate(ab, [
+                [{ a: 1, b: 2, c: 3 }, true],
+                [{ a: 3, b: 1, c: 2 }, true],
+                [{ a: 1, b: 2, c: 2 }, true],
+                [{ a: 1, b: 2, c: 4 }, false]
+            ], done);
+        });
+
+        it('throws when schema key types do not match', function (done) {
+
+            var a = Joi.object({ a: Joi.number() });
+            var b = Joi.object({ a: Joi.string() });
+
+            expect(function () {
+
+                a.concat(b);
+            }).to.throw('Cannot merge type number with another type: string');
+            done();
+        });
+
+        it('merges two alternatives with references', function (done) {
+
+            var schema = {
+                a: { c: Joi.number() },
+                b: Joi.alternatives(Joi.ref('a.c')).concat(Joi.alternatives(Joi.ref('c'))),
+                c: Joi.number()
+            };
+
+            Helper.validate(schema, [
+                [{ a: {} }, true],
+                [{ a: { c: '5' }, b: 5 }, true],
+                [{ a: { c: '5' }, b: 6, c: '6' }, true],
+                [{ a: { c: '5' }, b: 7, c: '6' }, false]
+            ], done);
+        });
+
+        it('merges meta properly', function (done) {
+
+            var metaA = { a: 1 };
+            var metaB = { b: 1 };
+            var a = Joi.any().meta(metaA);
+            var b = Joi.any().meta(metaB);
+            var c = Joi.any();
+            var d = Joi.any();
+
+            expect(a.concat(b)._meta).to.deep.equal([{ a: 1 }, { b: 1 }]);
+            expect(a.concat(c)._meta).to.deep.equal([metaA]);
+            expect(b.concat(c)._meta).to.deep.equal([metaB]);
+            expect(c.concat(d)._meta).to.deep.equal([]);
+
+            done();
+        });
+
+        it('merges into an any', function (done) {
+
+            var a = Joi.any().required();
+            var b = Joi.number().only(0);
+
+            expect(function () {
+
+                a.concat(b);
+            }).to.not.throw();
+
+            var schema = a.concat(b);
+            expect(schema.validate().error.message).to.equal('"value" is required');
+            expect(schema.validate(1).error.message).to.equal('"value" must be one of [0]');
+
+            done();
+        });
+    });
+
+    describe('#when', function () {
+
+        it('throws when options are invalid', function (done) {
+
+            expect(function () {
+
+                Joi.when('a');
+            }).to.throw('Invalid options');
+            done();
+        });
+
+        it('forks type into alternatives', function (done) {
+
+            var schema = {
+                a: Joi.any(),
+                b: Joi.string().valid('x').when('a', { is: 5, then: Joi.valid('y'), otherwise: Joi.valid('z') })
+            };
+
+            Helper.validate(schema, [
+                [{ a: 5, b: 'x' }, true],
+                [{ a: 5, b: 'y' }, true],
+                [{ a: 5, b: 'z' }, false],
+                [{ a: 1, b: 'x' }, true],
+                [{ a: 1, b: 'y' }, false],
+                [{ a: 1, b: 'z' }, true],
+                [{ a: 5, b: 'a' }, false],
+                [{ b: 'a' }, false]
+            ], done);
+        });
+
+        it('forks type into alternatives (only then)', function (done) {
+
+            var schema = {
+                a: Joi.any(),
+                b: Joi.string().valid('x').when('a', { is: 5, then: Joi.valid('y') })
+            };
+
+            Helper.validate(schema, [
+                [{ a: 5, b: 'x' }, true],
+                [{ a: 5, b: 'y' }, true],
+                [{ a: 5, b: 'z' }, false],
+                [{ a: 1, b: 'x' }, true],
+                [{ a: 1, b: 'y' }, false],
+                [{ a: 1, b: 'z' }, false],
+                [{ a: 5, b: 'a' }, false],
+                [{ b: 'a' }, false]
+            ], done);
+        });
+
+        it('forks type into alternatives (only otherwise)', function (done) {
+
+            var schema = {
+                a: Joi.any(),
+                b: Joi.string().valid('x').when('a', { is: 5, otherwise: Joi.valid('z') })
+            };
+
+            Helper.validate(schema, [
+                [{ a: 5, b: 'x' }, true],
+                [{ a: 5, b: 'y' }, false],
+                [{ a: 5, b: 'z' }, false],
+                [{ a: 1, b: 'x' }, true],
+                [{ a: 1, b: 'y' }, false],
+                [{ a: 1, b: 'z' }, true],
+                [{ a: 5, b: 'a' }, false],
+                [{ b: 'a' }, false]
+            ], done);
+        });
+
+        it('forks type into alternatives (with a schema)', function (done) {
+
+            var schema = {
+                a: Joi.any(),
+                b: Joi.string().valid('x').when('a', { is: Joi.number().only(5).required(), then: Joi.valid('y') })
+            };
+
+            Helper.validate(schema, [
+                [{ a: 5, b: 'x' }, true],
+                [{ a: 5, b: 'y' }, true],
+                [{ a: 5, b: 'z' }, false],
+                [{ a: 1, b: 'x' }, true],
+                [{ a: 1, b: 'y' }, false],
+                [{ a: 1, b: 'z' }, false],
+                [{ a: 5, b: 'a' }, false],
+                [{ b: 'a' }, false]
+            ], done);
+        });
+
+        it('makes peer required', function (done) {
+
+            var schema = {
+                a: Joi.when('b', { is: 5, then: Joi.required() }),
+                b: Joi.any()
+            };
+
+            Helper.validate(schema, [
+                [{ b: 5 }, false],
+                [{ b: 6 }, true],
+                [{ a: 'b' }, true],
+                [{ b: 5, a: 'x' }, true]
+            ], done);
+        });
+    });
+
+    describe('#requiredKeys', function () {
+
+        it('should set keys as required', function (done) {
+
+            var schema = Joi.object({ a: 0, b: 0, c: { d: 0, e: { f: 0 } }, g: { h: 0 } })
+                .requiredKeys('a', 'b', 'c.d', 'c.e.f', 'g');
+            Helper.validate(schema, [
+                [{}, false],
+                [{ a: 0 }, false],
+                [{ a: 0, b: 0 }, false],
+                [{ a: 0, b: 0, g: {} }, true],
+                [{ a: 0, b: 0, c: {}, g: {} }, false],
+                [{ a: 0, b: 0, c: { d: 0 }, g: {} }, true],
+                [{ a: 0, b: 0, c: { d: 0, e: {} }, g: {} }, false],
+                [{ a: 0, b: 0, c: { d: 0, e: { f: 0 } }, g: {} }, true]
+            ], done);
+        });
+
+        it('should work on types other than objects', function (done) {
+
+            var schemas = [Joi.array(), Joi.binary(), Joi.boolean(), Joi.date(), Joi.func(), Joi.number(), Joi.string()];
+            schemas.forEach(function (schema) {
+
+                expect(function () {
+
+                    schema.applyFunctionToChildren([''], 'required');
+                }).to.not.throw();
+
+                expect(function () {
+
+                    schema.applyFunctionToChildren(['', 'a'], 'required');
+                }).to.throw();
+
+                expect(function () {
+
+                    schema.applyFunctionToChildren(['a'], 'required');
+                }).to.throw();
+            });
+
+            done();
+        });
+
+        it('should throw on unknown key', function (done) {
+
+            expect(function () {
+
+                Joi.object({ a: 0, b: 0 }).requiredKeys('a', 'c', 'b', 'd', 'd.e.f');
+            }).to.throw(Error, 'unknown key(s) c, d');
+
+            expect(function () {
+
+                Joi.object({ a: 0, b: 0 }).requiredKeys('a', 'b', 'a.c.d');
+            }).to.throw(Error, 'unknown key(s) a.c.d');
+
+            done();
+        });
+
+        it('should throw on empty object', function (done) {
+
+            expect(function () {
+
+                Joi.object().requiredKeys('a', 'c', 'b', 'd');
+            }).to.throw(Error, 'unknown key(s) a, b, c, d');
+            done();
+        });
+
+        it('should not modify original object', function (done) {
+
+            var schema = Joi.object({ a: 0 });
+            var requiredSchema = schema.requiredKeys('a');
+            schema.validate({}, function (err) {
+
+                expect(err).to.not.exist();
+
+                requiredSchema.validate({}, function (err) {
+
+                    expect(err).to.exist();
+                    done();
+                });
+            });
+        });
+    });
+
+    describe('#optionalKeys', function () {
+
+        it('should set keys as optional', function (done) {
+
+            var schema = Joi.object({ a: Joi.number().required(), b: Joi.number().required() }).optionalKeys('a', 'b');
+            Helper.validate(schema, [
+                [{}, true],
+                [{ a: 0 }, true],
+                [{ a: 0, b: 0 }, true]
+            ], done);
+        });
+    });
+
+    describe('#empty', function () {
+
+        it('should void values when considered empty', function (done) {
+
+            var schema = Joi.string().empty('');
+            Helper.validate(schema, [
+                [undefined, true, null, undefined],
+                ['abc', true, null, 'abc'],
+                ['', true, null, undefined]
+            ], done);
+        });
+
+        it('should override any previous empty', function (done) {
+
+            var schema = Joi.string().empty('').empty('abc');
+            Helper.validate(schema, [
+                [undefined, true, null, undefined],
+                ['abc', true, null, undefined],
+                ['', false, null, '"value" is not allowed to be empty'],
+                ['def', true, null, 'def']
+            ], done);
+        });
+
+        it('should be possible to reset the empty value', function (done) {
+
+            var schema = Joi.string().empty('').empty();
+            Helper.validate(schema, [
+                [undefined, true, null, undefined],
+                ['abc', true, null, 'abc'],
+                ['', false, null, '"value" is not allowed to be empty']
+            ], done);
+        });
+
+        it('should have no effect if only reset is used', function (done) {
+
+            var schema = Joi.string().empty();
+            Helper.validate(schema, [
+                [undefined, true, null, undefined],
+                ['abc', true, null, 'abc'],
+                ['', false, null, '"value" is not allowed to be empty']
+            ], done);
+        });
+
+        it('should work with dependencies', function (done) {
+
+            var schema = Joi.object({
+                a: Joi.string().empty(''),
+                b: Joi.string().empty('')
+            }).or('a', 'b');
+
+            Helper.validate(schema, [
+                [{}, false, null, '"value" must contain at least one of [a, b]'],
+                [{ a: '' }, false, null, '"value" must contain at least one of [a, b]'],
+                [{ a: 'a' }, true, null, { a: 'a' }],
+                [{ a: '', b: 'b' }, true, null, { b: 'b' }]
+            ], done);
+        });
+    });
+
+    describe('Set', function () {
+
+        describe('#add', function () {
+
+            it('throws when adding a non ref function', function (done) {
+
+                expect(function () {
+
+                    Joi.valid(function () { });
+                }).to.throw('Value cannot be an object or function');
+                done();
+            });
+
+            it('throws when adding an object function', function (done) {
+
+                expect(function () {
+
+                    Joi.valid({});
+                }).to.throw('Value cannot be an object or function');
+                done();
+            });
+        });
+
+        describe('#has', function () {
+
+            it('compares date to null', function (done) {
+
+                var any = Joi.any().clone();
+                any._valids.add(null);
+                expect(any._valids.has(new Date())).to.equal(false);
+                done();
+            });
+
+            it('compares buffer to null', function (done) {
+
+                var any = Joi.any().clone();
+                any._valids.add(null);
+                expect(any._valids.has(new Buffer(''))).to.equal(false);
+                done();
+            });
+        });
+
+        describe('#values', function () {
+
+            it('returns array', function (done) {
+
+                var a = Joi.any().valid('x').invalid('y');
+                var b = a.invalid('x');
+                expect(a._valids.values().length).to.equal(1);
+                expect(b._valids.values().length).to.equal(0);
+                expect(a._invalids.values().length).to.equal(1);
+                expect(b._invalids.values().length).to.equal(2);
+                done();
+            });
+
+            it('strips undefined', function (done) {
+
+                var any = Joi.any().clone();
+                any._valids.add(undefined);
+                expect(any._valids.values({ stripUndefined: true })).to.not.include(undefined);
+                done();
+            });
+        });
+
+        describe('#allow', function () {
+
+            it('allows valid values to be set', function (done) {
+
+                expect(function () {
+
+                    Joi.any().allow(true, 1, 'hello', new Date());
+                }).not.to.throw();
+                done();
+            });
+
+            it('throws when passed undefined', function (done) {
+
+                expect(function () {
+
+                    Joi.any().allow(undefined);
+                }).to.throw(Error, 'Cannot call allow/valid/invalid with undefined');
+                done();
+            });
+        });
+
+        describe('#valid', function () {
+
+            it('allows valid values to be set', function (done) {
+
+                expect(function () {
+
+                    Joi.any().valid(true, 1, 'hello', new Date());
+                }).not.to.throw();
+                done();
+            });
+
+            it('throws when passed undefined', function (done) {
+
+                expect(function () {
+
+                    Joi.any().valid(undefined);
+                }).to.throw(Error, 'Cannot call allow/valid/invalid with undefined');
+                done();
+            });
+        });
+
+        describe('#invalid', function () {
+
+            it('allows invalid values to be set', function (done) {
+
+                expect(function () {
+
+                    Joi.any().valid(true, 1, 'hello', new Date());
+                }).not.to.throw();
+                done();
+            });
+
+            it('throws when passed undefined', function (done) {
+
+                expect(function () {
+
+                    Joi.any().invalid(undefined);
+                }).to.throw('Cannot call allow/valid/invalid with undefined');
+                done();
+            });
+        });
+    });
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/array.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/array.js
new file mode 100755
index 0000000000000000000000000000000000000000..aa092c366291277ef2fa40119b3a96f16c14e077
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/array.js
@@ -0,0 +1,1049 @@
+// Load modules
+
+var Lab = require('lab');
+var Code = require('code');
+var Joi = require('../lib');
+var Helper = require('./helper');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var lab = exports.lab = Lab.script();
+var describe = lab.describe;
+var it = lab.it;
+var expect = Code.expect;
+
+
+describe('array', function () {
+
+    it('converts a string to an array', function (done) {
+
+        Joi.array().validate('[1,2,3]', function (err, value) {
+
+            expect(err).to.not.exist();
+            expect(value.length).to.equal(3);
+            done();
+        });
+    });
+
+    it('errors on non-array string', function (done) {
+
+        Joi.array().validate('{ "something": false }', function (err, value) {
+
+            expect(err).to.exist();
+            expect(err.message).to.equal('"value" must be an array');
+            done();
+        });
+    });
+
+    it('errors on number', function (done) {
+
+        Joi.array().validate(3, function (err, value) {
+
+            expect(err).to.exist();
+            expect(value).to.equal(3);
+            done();
+        });
+    });
+
+    it('converts a non-array string with number type', function (done) {
+
+        Joi.array().validate('3', function (err, value) {
+
+            expect(err).to.exist();
+            expect(value).to.equal('3');
+            done();
+        });
+    });
+
+    it('errors on a non-array string', function (done) {
+
+        Joi.array().validate('asdf', function (err, value) {
+
+            expect(err).to.exist();
+            expect(value).to.equal('asdf');
+            done();
+        });
+    });
+
+    describe('#items', function () {
+
+        it('converts members', function (done) {
+
+            var schema = Joi.array().items(Joi.number());
+            var input = ['1', '2', '3'];
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.deep.equal([1, 2, 3]);
+                done();
+            });
+        });
+
+        it('shows path to errors in array items', function (done) {
+
+            expect(function () {
+
+                Joi.array().items({
+                    a: {
+                        b: {
+                            c: {
+                                d: undefined
+                            }
+                        }
+                    }
+                });
+            }).to.throw(Error, 'Invalid schema content: (0.a.b.c.d)');
+
+            expect(function () {
+
+                Joi.array().items({ foo: 'bar' }, undefined);
+            }).to.throw(Error, 'Invalid schema content: (1)');
+
+            done();
+        });
+
+        it('allows zero size', function (done) {
+
+            var schema = Joi.object({
+                test: Joi.array().items(Joi.object({
+                    foo: Joi.string().required()
+                }))
+            });
+            var input = { test: [] };
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.not.exist();
+                done();
+            });
+        });
+
+        it('returns the first error when only one inclusion', function (done) {
+
+            var schema = Joi.object({
+                test: Joi.array().items(Joi.object({
+                    foo: Joi.string().required()
+                }))
+            });
+            var input = { test: [{ foo: 'a' }, { bar: 2 }] };
+
+            schema.validate(input, function (err, value) {
+
+                expect(err.message).to.equal('child "test" fails because ["test" at position 1 fails because [child "foo" fails because ["foo" is required]]]');
+                done();
+            });
+        });
+
+        it('validates multiple types added in two calls', function (done) {
+
+            var schema = Joi.array()
+                .items(Joi.number())
+                .items(Joi.string());
+
+            Helper.validate(schema, [
+                [[1, 2, 3], true],
+                [[50, 100, 1000], true],
+                [[1, 'a', 5, 10], true],
+                [['joi', 'everydaylowprices', 5000], true]
+            ], done);
+        });
+
+        it('validates multiple types with stripUnknown', function (done) {
+
+            var schema = Joi.array().items(Joi.number(), Joi.string()).options({ stripUnknown: true });
+
+            Helper.validate(schema, [
+                [[1, 2, 'a'], true, null, [1, 2, 'a']],
+                [[1, { foo: 'bar' }, 'a', 2], true, null, [1, 'a', 2]]
+            ], done);
+        });
+
+        it('allows forbidden to restrict values', function (done) {
+
+            var schema = Joi.array().items(Joi.string().valid('four').forbidden(), Joi.string());
+            var input = ['one', 'two', 'three', 'four'];
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.message).to.equal('"value" at position 3 contains an excluded value');
+                done();
+            });
+        });
+
+        it('validates that a required value exists', function (done) {
+
+            var schema = Joi.array().items(Joi.string().valid('four').required(), Joi.string());
+            var input = ['one', 'two', 'three'];
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.message).to.equal('"value" does not contain 1 required value(s)');
+                done();
+            });
+        });
+
+        it('validates that a required value exists with abortEarly = false', function (done) {
+
+            var schema = Joi.array().items(Joi.string().valid('four').required(), Joi.string()).options({ abortEarly: false });
+            var input = ['one', 'two', 'three'];
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.message).to.equal('"value" does not contain 1 required value(s)');
+                done();
+            });
+        });
+
+        it('does not re-run required tests that have already been matched', function (done) {
+
+            var schema = Joi.array().items(Joi.string().valid('four').required(), Joi.string());
+            var input = ['one', 'two', 'three', 'four', 'four', 'four'];
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.deep.equal(input);
+                done();
+            });
+        });
+
+        it('does not re-run required tests that have already failed', function (done) {
+
+            var schema = Joi.array().items(Joi.string().valid('four').required(), Joi.boolean().required(), Joi.number());
+            var input = ['one', 'two', 'three', 'four', 'four', 'four'];
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.message).to.equal('"value" at position 0 does not match any of the allowed types');
+                done();
+            });
+        });
+
+        it('can require duplicates of the same schema and fail', function (done) {
+
+            var schema = Joi.array().items(Joi.string().valid('four').required(), Joi.string().valid('four').required(), Joi.string());
+            var input = ['one', 'two', 'three', 'four'];
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.message).to.equal('"value" does not contain 1 required value(s)');
+                done();
+            });
+        });
+
+        it('can require duplicates of the same schema and pass', function (done) {
+
+            var schema = Joi.array().items(Joi.string().valid('four').required(), Joi.string().valid('four').required(), Joi.string());
+            var input = ['one', 'two', 'three', 'four', 'four'];
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.deep.equal(input);
+                done();
+            });
+        });
+
+        it('continues to validate after a required match', function (done) {
+
+            var schema = Joi.array().items(Joi.string().required(), Joi.boolean());
+            var input = [true, 'one', false, 'two'];
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.deep.equal(input);
+                done();
+            });
+        });
+
+        it('can use a label on a required parameter', function (done) {
+
+            var schema = Joi.array().items(Joi.string().required().label('required string'), Joi.boolean());
+            var input = [true, false];
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.message).to.equal('"value" does not contain [required string]');
+                done();
+            });
+        });
+
+        it('can use a label on one required parameter, and no label on another', function (done) {
+
+            var schema = Joi.array().items(Joi.string().required().label('required string'), Joi.string().required(), Joi.boolean());
+            var input = [true, false];
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.message).to.equal('"value" does not contain [required string] and 1 other required value(s)');
+                done();
+            });
+        });
+
+        it('can strip matching items', function (done) {
+
+            var schema = Joi.array().items(Joi.string(), Joi.any().strip());
+            schema.validate(['one', 'two', 3, 4], function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.deep.equal(['one', 'two']);
+                done();
+            });
+        });
+    });
+
+    describe('#min', function () {
+
+        it('validates array size', function (done) {
+
+            var schema = Joi.array().min(2);
+            Helper.validate(schema, [
+                [[1, 2], true],
+                [[1], false]
+            ], done);
+        });
+
+        it('throws when limit is not a number', function (done) {
+
+            expect(function () {
+
+                Joi.array().min('a');
+            }).to.throw('limit must be a positive integer');
+            done();
+        });
+
+        it('throws when limit is not an integer', function (done) {
+
+            expect(function () {
+
+                Joi.array().min(1.2);
+            }).to.throw('limit must be a positive integer');
+            done();
+        });
+    });
+
+    describe('#max', function () {
+
+        it('validates array size', function (done) {
+
+            var schema = Joi.array().max(1);
+            Helper.validate(schema, [
+                [[1, 2], false],
+                [[1], true]
+            ], done);
+        });
+
+        it('throws when limit is not a number', function (done) {
+
+            expect(function () {
+
+                Joi.array().max('a');
+            }).to.throw('limit must be a positive integer');
+            done();
+        });
+
+        it('throws when limit is not an integer', function (done) {
+
+            expect(function () {
+
+                Joi.array().max(1.2);
+            }).to.throw('limit must be a positive integer');
+            done();
+        });
+    });
+
+    describe('#length', function () {
+
+        it('validates array size', function (done) {
+
+            var schema = Joi.array().length(2);
+            Helper.validate(schema, [
+                [[1, 2], true],
+                [[1], false]
+            ], done);
+        });
+
+        it('throws when limit is not a number', function (done) {
+
+            expect(function () {
+
+                Joi.array().length('a');
+            }).to.throw('limit must be a positive integer');
+            done();
+        });
+
+        it('throws when limit is not an integer', function (done) {
+
+            expect(function () {
+
+                Joi.array().length(1.2);
+            }).to.throw('limit must be a positive integer');
+            done();
+        });
+    });
+
+    describe('#validate', function () {
+
+        it('should, by default, allow undefined, allow empty array', function (done) {
+
+            Helper.validate(Joi.array(), [
+                [undefined, true],
+                [[], true]
+            ], done);
+        });
+
+        it('should, when .required(), deny undefined', function (done) {
+
+            Helper.validate(Joi.array().required(), [
+                [undefined, false]
+            ], done);
+        });
+
+        it('allows empty arrays', function (done) {
+
+            Helper.validate(Joi.array(), [
+                [undefined, true],
+                [[], true]
+            ], done);
+        });
+
+        it('excludes values when items are forbidden', function (done) {
+
+            Helper.validate(Joi.array().items(Joi.string().forbidden()), [
+                [['2', '1'], false],
+                [['1'], false],
+                [[2], true]
+            ], done);
+        });
+
+        it('allows types to be forbidden', function (done) {
+
+            var schema = Joi.array().items(Joi.number().forbidden());
+
+            var n = [1, 2, 'hippo'];
+            schema.validate(n, function (err, value) {
+
+                expect(err).to.exist();
+
+                var m = ['x', 'y', 'z'];
+                schema.validate(m, function (err2, value2) {
+
+                    expect(err2).to.not.exist();
+                    done();
+                });
+            });
+        });
+
+        it('validates array of Numbers', function (done) {
+
+            Helper.validate(Joi.array().items(Joi.number()), [
+                [[1, 2, 3], true],
+                [[50, 100, 1000], true],
+                [['a', 1, 2], false],
+                [['1', '2', 4], true]
+            ], done);
+        });
+
+        it('validates array of mixed Numbers & Strings', function (done) {
+
+            Helper.validate(Joi.array().items(Joi.number(), Joi.string()), [
+                [[1, 2, 3], true],
+                [[50, 100, 1000], true],
+                [[1, 'a', 5, 10], true],
+                [['joi', 'everydaylowprices', 5000], true]
+            ], done);
+        });
+
+        it('validates array of objects with schema', function (done) {
+
+            Helper.validate(Joi.array().items(Joi.object({ h1: Joi.number().required() })), [
+                [[{ h1: 1 }, { h1: 2 }, { h1: 3 }], true],
+                [[{ h2: 1, h3: 'somestring' }, { h1: 2 }, { h1: 3 }], false],
+                [[1, 2, [1]], false]
+            ], done);
+        });
+
+        it('errors on array of unallowed mixed types (Array)', function (done) {
+
+            Helper.validate(Joi.array().items(Joi.number()), [
+                [[1, 2, 3], true],
+                [[1, 2, [1]], false]
+            ], done);
+        });
+
+        it('errors on invalid number rule using includes', function (done) {
+
+            var schema = Joi.object({
+                arr: Joi.array().items(Joi.number().integer())
+            });
+
+            var input = { arr: [1, 2, 2.1] };
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.message).to.equal('child "arr" fails because ["arr" at position 2 fails because ["2" must be an integer]]');
+                done();
+            });
+        });
+
+        it('validates an array within an object', function (done) {
+
+            var schema = Joi.object({
+                array: Joi.array().items(Joi.string().min(5), Joi.number().min(3))
+            }).options({ convert: false });
+
+            Helper.validate(schema, [
+                [{ array: ['12345'] }, true],
+                [{ array: ['1'] }, false],
+                [{ array: [3] }, true],
+                [{ array: ['12345', 3] }, true]
+            ], done);
+        });
+
+        it('should not change original value', function (done) {
+
+            var schema = Joi.array().items(Joi.number()).unique();
+            var input = ['1', '2'];
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.deep.equal([1, 2]);
+                expect(input).to.deep.equal(['1', '2']);
+                done();
+            });
+        });
+
+        it('should have multiple errors if abort early is false', function (done) {
+
+            var schema = Joi.array().items(Joi.number(), Joi.object()).items(Joi.boolean().forbidden());
+            var input = [1, undefined, true, 'a'];
+
+            Joi.validate(input, schema, { abortEarly: false }, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err).to.have.length(4);
+                expect(err.details).to.deep.equal([{
+                    message: '"value" must not be a sparse array',
+                    path: '1',
+                    type: 'array.sparse',
+                    context: {
+                        key: 'value'
+                    }
+                }, {
+                    message: '"value" at position 2 contains an excluded value',
+                    path: '2',
+                    type: 'array.excludes',
+                    context: {
+                        pos: 2,
+                        key: 'value',
+                        value: true
+                    }
+                }, {
+                    message: '"value" at position 3 does not match any of the allowed types',
+                    path: '3',
+                    type: 'array.includes',
+                    context: {
+                        pos: 3,
+                        key: 'value',
+                        value: 'a'
+                    }
+                }]);
+                done();
+            });
+        });
+    });
+
+    describe('#describe', function () {
+
+        it('returns an empty description when no rules are applied', function (done) {
+
+            var schema = Joi.array();
+            var desc = schema.describe();
+            expect(desc).to.deep.equal({
+                type: 'array',
+                flags: { sparse: false }
+            });
+            done();
+        });
+
+        it('returns an updated description when sparse rule is applied', function (done) {
+
+            var schema = Joi.array().sparse();
+            var desc = schema.describe();
+            expect(desc).to.deep.equal({
+                type: 'array',
+                flags: { sparse: true }
+            });
+            done();
+        });
+
+        it('returns an items array only if items are specified', function (done) {
+
+            var schema = Joi.array().items().max(5);
+            var desc = schema.describe();
+            expect(desc.items).to.not.exist();
+            done();
+        });
+
+        it('returns a recursively defined array of items when specified', function (done) {
+
+            var schema = Joi.array()
+                .items(Joi.number(), Joi.string())
+                .items(Joi.boolean().forbidden())
+                .ordered(Joi.number(), Joi.string())
+                .ordered(Joi.string().required());
+            var desc = schema.describe();
+            expect(desc.items).to.have.length(3);
+            expect(desc).to.deep.equal({
+                type: 'array',
+                flags: { sparse: false },
+                orderedItems: [{ type: 'number', invalids: [Infinity, -Infinity] }, { type: 'string', invalids: [''] }, { type: 'string', invalids: [''], flags: { presence: 'required' } }],
+                items: [{ type: 'number', invalids: [Infinity, -Infinity] }, { type: 'string', invalids: [''] }, { type: 'boolean', flags: { presence: 'forbidden' } }]
+            });
+
+            done();
+        });
+    });
+
+    describe('#unique', function () {
+
+        it('errors if duplicate numbers, strings, objects, binaries, functions, dates and booleans', function (done) {
+
+            var buffer = new Buffer('hello world');
+            var func = function () {};
+            var now = new Date();
+            var schema = Joi.array().sparse().unique();
+
+            Helper.validate(schema, [
+                [[2, 2], false],
+                [[02, 2], false], // eslint-disable-line no-octal
+                [[0x2, 2], false],
+                [['duplicate', 'duplicate'], false],
+                [[{ a: 'b' }, { a: 'b' }], false],
+                [[buffer, buffer], false],
+                [[func, func], false],
+                [[now, now], false],
+                [[true, true], false],
+                [[undefined, undefined], false]
+            ], done);
+        });
+
+        it('ignores duplicates if they are of different types', function (done) {
+
+            var schema = Joi.array().unique();
+
+            Helper.validate(schema, [
+                [[2, '2'], true]
+            ], done);
+        });
+
+        it('validates without duplicates', function (done) {
+
+            var buffer = new Buffer('hello world');
+            var buffer2 = new Buffer('Hello world');
+            var func = function () {};
+            var func2 = function () {};
+            var now = new Date();
+            var now2 = new Date(+now + 100);
+            var schema = Joi.array().unique();
+
+            Helper.validate(schema, [
+                [[1, 2], true],
+                [['s1', 's2'], true],
+                [[{ a: 'b' }, { a: 'c' }], true],
+                [[buffer, buffer2], true],
+                [[func, func2], true],
+                [[now, now2], true],
+                [[true, false], true]
+            ], done);
+        });
+    });
+
+    describe('#sparse', function () {
+
+        it('errors on undefined value', function (done) {
+
+            var schema = Joi.array().items(Joi.number());
+
+            Helper.validate(schema, [
+                [[undefined], false],
+                [[2, undefined], false]
+            ], done);
+        });
+
+        it('validates on undefined value with sparse', function (done) {
+
+            var schema = Joi.array().items(Joi.number()).sparse();
+
+            Helper.validate(schema, [
+                [[undefined], true],
+                [[2, undefined], true]
+            ], done);
+        });
+
+        it('switches the sparse flag', function (done) {
+
+            var schema = Joi.array().sparse();
+            var desc = schema.describe();
+            expect(desc).to.deep.equal({
+                type: 'array',
+                flags: { sparse: true }
+            });
+            done();
+        });
+
+        it('switches the sparse flag with explicit value', function (done) {
+
+            var schema = Joi.array().sparse(true);
+            var desc = schema.describe();
+            expect(desc).to.deep.equal({
+                type: 'array',
+                flags: { sparse: true }
+            });
+            done();
+        });
+
+        it('switches the sparse flag back', function (done) {
+
+            var schema = Joi.array().sparse().sparse(false);
+            var desc = schema.describe();
+            expect(desc).to.deep.equal({
+                type: 'array',
+                flags: { sparse: false }
+            });
+            done();
+        });
+    });
+
+    describe('#single', function () {
+
+        it('should allow a single element', function (done) {
+
+            var schema = Joi.array().items(Joi.number()).items(Joi.boolean().forbidden()).single();
+
+            Helper.validate(schema, [
+                [[1, 2, 3], true],
+                [1, true],
+                [['a'], false, null, '"value" at position 0 fails because ["0" must be a number]'],
+                ['a', false, null, 'single value of "value" fails because ["0" must be a number]'],
+                [true, false, null, 'single value of "value" contains an excluded value']
+            ], done);
+        });
+
+        it('should allow a single element with multiple types', function (done) {
+
+            var schema = Joi.array().items(Joi.number(), Joi.string()).single();
+
+            Helper.validate(schema, [
+                [[1, 2, 3], true],
+                [1, true],
+                [[1, 'a'], true],
+                ['a', true],
+                [true, false, null, 'single value of "value" does not match any of the allowed types']
+            ], done);
+        });
+
+        it('should allow nested arrays', function (done) {
+
+            var schema = Joi.array().items(Joi.array().items(Joi.number())).single();
+
+            Helper.validate(schema, [
+                [[[1], [2], [3]], true],
+                [[1, 2, 3], true],
+                [[['a']], false, null, '"value" at position 0 fails because ["0" at position 0 fails because ["0" must be a number]]'],
+                [['a'], false, null, '"value" at position 0 fails because ["0" must be an array]'],
+                ['a', false, null, 'single value of "value" fails because ["0" must be an array]'],
+                [1, false, null, 'single value of "value" fails because ["0" must be an array]'],
+                [true, false, null, 'single value of "value" fails because ["0" must be an array]']
+            ], done);
+        });
+
+        it('should allow nested arrays with multiple types', function (done) {
+
+            var schema = Joi.array().items(Joi.array().items(Joi.number(), Joi.boolean())).single();
+
+            Helper.validate(schema, [
+                [[[1, true]], true],
+                [[1, true], true],
+                [[[1, 'a']], false, null, '"value" at position 0 fails because ["0" at position 1 does not match any of the allowed types]'],
+                [[1, 'a'], false, null, '"value" at position 0 fails because ["0" must be an array]']
+            ], done);
+        });
+
+        it('switches the single flag with explicit value', function (done) {
+
+            var schema = Joi.array().single(true);
+            var desc = schema.describe();
+            expect(desc).to.deep.equal({
+                type: 'array',
+                flags: { sparse: false, single: true }
+            });
+            done();
+        });
+
+        it('switches the single flag back', function (done) {
+
+            var schema = Joi.array().single().single(false);
+            var desc = schema.describe();
+            expect(desc).to.deep.equal({
+                type: 'array',
+                flags: { sparse: false, single: false }
+            });
+            done();
+        });
+    });
+
+    describe('#options', function () {
+
+        it('respects stripUnknown', function (done) {
+
+            var schema = Joi.array().items(Joi.string()).options({ stripUnknown: true });
+            schema.validate(['one', 'two', 3, 4, true, false], function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.deep.equal(['one', 'two']);
+                done();
+            });
+        });
+    });
+
+    describe('#ordered', function () {
+
+        it('shows path to errors in array ordered items', function (done) {
+
+            expect(function () {
+
+                Joi.array().ordered({
+                    a: {
+                        b: {
+                            c: {
+                                d: undefined
+                            }
+                        }
+                    }
+                });
+            }).to.throw(Error, 'Invalid schema content: (0.a.b.c.d)');
+
+            expect(function () {
+
+                Joi.array().ordered({ foo: 'bar' }, undefined);
+            }).to.throw(Error, 'Invalid schema content: (1)');
+
+            done();
+        });
+
+        it('validates input against items in order', function (done) {
+
+            var schema = Joi.array().ordered([Joi.string().required(), Joi.number().required()]);
+            var input = ['s1', 2];
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.deep.equal(['s1', 2]);
+                done();
+            });
+        });
+
+        it('validates input with optional item', function (done) {
+
+            var schema = Joi.array().ordered([Joi.string().required(), Joi.number().required(), Joi.number()]);
+            var input = ['s1', 2, 3];
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.deep.equal(['s1', 2, 3]);
+                done();
+            });
+        });
+
+        it('validates input without optional item', function (done) {
+
+            var schema = Joi.array().ordered([Joi.string().required(), Joi.number().required(), Joi.number()]);
+            var input = ['s1', 2];
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.deep.equal(['s1', 2]);
+                done();
+            });
+        });
+
+        it('validates input without optional item', function (done) {
+
+            var schema = Joi.array().ordered([Joi.string().required(), Joi.number().required(), Joi.number()]).sparse(true);
+            var input = ['s1', 2, undefined];
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.deep.equal(['s1', 2, undefined]);
+                done();
+            });
+        });
+
+        it('validates input without optional item in a sparse array', function (done) {
+
+            var schema = Joi.array().ordered([Joi.string().required(), Joi.number(), Joi.number().required()]).sparse(true);
+            var input = ['s1', undefined, 3];
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.deep.equal(['s1', undefined, 3]);
+                done();
+            });
+        });
+
+        it('validates when input matches ordered items and matches regular items', function (done) {
+
+            var schema = Joi.array().ordered([Joi.string().required(), Joi.number().required()]).items(Joi.number());
+            var input = ['s1', 2, 3, 4, 5];
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.deep.equal(['s1', 2, 3, 4, 5]);
+                done();
+            });
+        });
+
+        it('errors when input does not match ordered items', function (done) {
+
+            var schema = Joi.array().ordered([Joi.number().required(), Joi.string().required()]);
+            var input = ['s1', 2];
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.message).to.equal('"value" at position 0 fails because ["0" must be a number]');
+                done();
+            });
+        });
+
+        it('errors when input has more items than ordered items', function (done) {
+
+            var schema = Joi.array().ordered([Joi.number().required(), Joi.string().required()]);
+            var input = [1, 's2', 3];
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.message).to.equal('"value" at position 2 fails because array must contain at most 2 items');
+                done();
+            });
+        });
+
+        it('errors when input has more items than ordered items with abortEarly = false', function (done) {
+
+            var schema = Joi.array().ordered([Joi.string(), Joi.number()]).options({ abortEarly: false });
+            var input = [1, 2, 3, 4, 5];
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.message).to.equal('"value" at position 0 fails because ["0" must be a string]. "value" at position 2 fails because array must contain at most 2 items. "value" at position 3 fails because array must contain at most 2 items. "value" at position 4 fails because array must contain at most 2 items');
+                expect(err.details).to.have.length(4);
+                done();
+            });
+        });
+
+        it('errors when input has less items than ordered items', function (done) {
+
+            var schema = Joi.array().ordered([Joi.number().required(), Joi.string().required()]);
+            var input = [1];
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.message).to.equal('"value" does not contain 1 required value(s)');
+                done();
+            });
+        });
+
+        it('errors when input matches ordered items but not matches regular items', function (done) {
+
+            var schema = Joi.array().ordered([Joi.string().required(), Joi.number().required()]).items(Joi.number()).options({ abortEarly: false });
+            var input = ['s1', 2, 3, 4, 's5'];
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.message).to.equal('"value" at position 4 fails because ["4" must be a number]');
+                done();
+            });
+        });
+
+        it('errors when input does not match ordered items but matches regular items', function (done) {
+
+            var schema = Joi.array().ordered([Joi.string(), Joi.number()]).items(Joi.number()).options({ abortEarly: false });
+            var input = [1, 2, 3, 4, 5];
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.message).to.equal('"value" at position 0 fails because ["0" must be a string]');
+                done();
+            });
+        });
+
+        it('errors when input does not match ordered items not matches regular items', function (done) {
+
+            var schema = Joi.array().ordered([Joi.string(), Joi.number()]).items(Joi.string()).options({ abortEarly: false });
+            var input = [1, 2, 3, 4, 5];
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.message).to.equal('"value" at position 0 fails because ["0" must be a string]. "value" at position 2 fails because ["2" must be a string]. "value" at position 3 fails because ["3" must be a string]. "value" at position 4 fails because ["4" must be a string]');
+                expect(err.details).to.have.length(4);
+                done();
+            });
+        });
+
+        it('errors but continues when abortEarly is set to false', function (done) {
+
+            var schema = Joi.array().ordered([Joi.number().required(), Joi.string().required()]).options({ abortEarly: false });
+            var input = ['s1', 2];
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.message).to.equal('"value" at position 0 fails because ["0" must be a number]. "value" at position 1 fails because ["1" must be a string]');
+                expect(err.details).to.have.length(2);
+                done();
+            });
+        });
+
+        it('strips item', function (done) {
+
+            var schema = Joi.array().ordered([Joi.string().required(), Joi.number().strip(), Joi.number().required()]);
+            var input = ['s1', 2, 3];
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.deep.equal(['s1', 3]);
+                done();
+            });
+        });
+
+        it('strips multiple items', function (done) {
+
+            var schema = Joi.array().ordered([Joi.string().strip(), Joi.number(), Joi.number().strip()]);
+            var input = ['s1', 2, 3];
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.deep.equal([2]);
+                done();
+            });
+        });
+    });
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/binary.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/binary.js
new file mode 100755
index 0000000000000000000000000000000000000000..a1695f0bb43cea484e7490f103c1827233494784
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/binary.js
@@ -0,0 +1,188 @@
+// Load modules
+
+var Lab = require('lab');
+var Code = require('code');
+var Joi = require('../lib');
+var Helper = require('./helper');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var lab = exports.lab = Lab.script();
+var describe = lab.describe;
+var it = lab.it;
+var expect = Code.expect;
+
+
+describe('binary', function () {
+
+    it('converts a string to a buffer', function (done) {
+
+        Joi.binary().validate('test', function (err, value) {
+
+            expect(err).to.not.exist();
+            expect(value instanceof Buffer).to.equal(true);
+            expect(value.length).to.equal(4);
+            expect(value.toString('utf8')).to.equal('test');
+            done();
+        });
+    });
+
+    it('validates allowed buffer content', function (done) {
+
+        var hello = new Buffer('hello');
+        var schema = Joi.binary().valid(hello);
+
+        Helper.validate(schema, [
+            ['hello', true],
+            [hello, true],
+            [new Buffer('hello'), true],
+            ['goodbye', false],
+            [new Buffer('goodbye'), false],
+            [new Buffer('HELLO'), false]
+        ], done);
+    });
+
+    describe('#validate', function () {
+
+        it('returns an error when a non-buffer or non-string is used', function (done) {
+
+            Joi.binary().validate(5, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.message).to.equal('"value" must be a buffer or a string');
+                done();
+            });
+        });
+
+        it('accepts a buffer object', function (done) {
+
+            Joi.binary().validate(new Buffer('hello world'), function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value.toString('utf8')).to.equal('hello world');
+                done();
+            });
+        });
+    });
+
+    describe('#encoding', function () {
+
+        it('applies encoding', function (done) {
+
+            var schema = Joi.binary().encoding('base64');
+            var input = new Buffer('abcdef');
+            schema.validate(input.toString('base64'), function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value instanceof Buffer).to.equal(true);
+                expect(value.toString()).to.equal('abcdef');
+                done();
+            });
+        });
+
+        it('throws when encoding is invalid', function (done) {
+
+            expect(function () {
+
+                Joi.binary().encoding('base6');
+            }).to.throw('Invalid encoding: base6');
+            done();
+        });
+    });
+
+    describe('#min', function () {
+
+        it('validates buffer size', function (done) {
+
+            var schema = Joi.binary().min(5);
+            Helper.validate(schema, [
+                [new Buffer('testing'), true],
+                [new Buffer('test'), false]
+            ], done);
+        });
+
+        it('throws when min is not a number', function (done) {
+
+            expect(function () {
+
+                Joi.binary().min('a');
+            }).to.throw('limit must be a positive integer');
+            done();
+        });
+
+        it('throws when min is not an integer', function (done) {
+
+            expect(function () {
+
+                Joi.binary().min(1.2);
+            }).to.throw('limit must be a positive integer');
+            done();
+        });
+    });
+
+    describe('#max', function () {
+
+        it('validates buffer size', function (done) {
+
+            var schema = Joi.binary().max(5);
+            Helper.validate(schema, [
+                [new Buffer('testing'), false],
+                [new Buffer('test'), true]
+            ], done);
+        });
+
+        it('throws when max is not a number', function (done) {
+
+            expect(function () {
+
+                Joi.binary().max('a');
+            }).to.throw('limit must be a positive integer');
+            done();
+        });
+
+        it('throws when max is not an integer', function (done) {
+
+            expect(function () {
+
+                Joi.binary().max(1.2);
+            }).to.throw('limit must be a positive integer');
+            done();
+        });
+    });
+
+    describe('#length', function () {
+
+        it('validates buffer size', function (done) {
+
+            var schema = Joi.binary().length(4);
+            Helper.validate(schema, [
+                [new Buffer('test'), true],
+                [new Buffer('testing'), false]
+            ], done);
+        });
+
+        it('throws when length is not a number', function (done) {
+
+            expect(function () {
+
+                Joi.binary().length('a');
+            }).to.throw('limit must be a positive integer');
+            done();
+        });
+
+        it('throws when length is not an integer', function (done) {
+
+            expect(function () {
+
+                Joi.binary().length(1.2);
+            }).to.throw('limit must be a positive integer');
+            done();
+        });
+    });
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/boolean.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/boolean.js
new file mode 100755
index 0000000000000000000000000000000000000000..fdabbaaee99a9b5742eac26826963f40f9aea88f
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/boolean.js
@@ -0,0 +1,129 @@
+// Load modules
+
+var Lab = require('lab');
+var Code = require('code');
+var Joi = require('../lib');
+var Helper = require('./helper');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var lab = exports.lab = Lab.script();
+var describe = lab.describe;
+var it = lab.it;
+var expect = Code.expect;
+
+
+describe('boolean', function () {
+
+    it('converts a string to a boolean', function (done) {
+
+        Joi.boolean().validate('true', function (err, value) {
+
+            expect(err).to.not.exist();
+            expect(value).to.equal(true);
+            done();
+        });
+    });
+
+    it('errors on a number', function (done) {
+
+        Joi.boolean().validate(1, function (err, value) {
+
+            expect(err).to.exist();
+            expect(value).to.equal(1);
+            done();
+        });
+    });
+
+    describe('#validate', function () {
+
+        it('converts string values and validates', function (done) {
+
+            var rule = Joi.boolean();
+            Helper.validate(rule, [
+                ['1234', false],
+                [false, true],
+                [true, true],
+                [null, false],
+                ['on', true],
+                ['off', true],
+                ['true', true],
+                ['false', true],
+                ['yes', true],
+                ['no', true]
+            ], done);
+        });
+
+        it('should handle work with required', function (done) {
+
+            var rule = Joi.boolean().required();
+            Helper.validate(rule, [
+                ['1234', false],
+                ['true', true],
+                [false, true],
+                [true, true],
+                [null, false]
+            ], done);
+        });
+
+        it('should handle work with allow', function (done) {
+
+            var rule = Joi.boolean().allow(false);
+            Helper.validate(rule, [
+                ['1234', false],
+                [false, true],
+                [null, false]
+            ], done);
+        });
+
+        it('should handle work with invalid', function (done) {
+
+            var rule = Joi.boolean().invalid(false);
+            Helper.validate(rule, [
+                ['1234', false],
+                [false, false],
+                [true, true],
+                [null, false]
+            ], done);
+        });
+
+        it('should handle work with invalid and null allowed', function (done) {
+
+            var rule = Joi.boolean().invalid(false).allow(null);
+            Helper.validate(rule, [
+                ['1234', false],
+                [false, false],
+                [true, true],
+                [null, true]
+            ], done);
+        });
+
+        it('should handle work with allow and invalid', function (done) {
+
+            var rule = Joi.boolean().invalid(true).allow(false);
+            Helper.validate(rule, [
+                ['1234', false],
+                [false, true],
+                [true, false],
+                [null, false]
+            ], done);
+        });
+
+        it('should handle work with allow, invalid, and null allowed', function (done) {
+
+            var rule = Joi.boolean().invalid(true).allow(false).allow(null);
+            Helper.validate(rule, [
+                ['1234', false],
+                [false, true],
+                [true, false],
+                [null, true]
+            ], done);
+        });
+    });
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/date.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/date.js
new file mode 100755
index 0000000000000000000000000000000000000000..28856ac0eb8ab18f5cacc8d994e226c4a74be7bc
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/date.js
@@ -0,0 +1,338 @@
+// Load modules
+
+var Lab = require('lab');
+var Code = require('code');
+var Joi = require('../lib');
+var Helper = require('./helper');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var lab = exports.lab = Lab.script();
+var describe = lab.describe;
+var it = lab.it;
+var expect = Code.expect;
+
+
+describe('date', function () {
+
+    it('fails on boolean', function (done) {
+
+        var schema = Joi.date();
+        Helper.validate(schema, [
+            [true, false],
+            [false, false]
+        ], done);
+    });
+
+    it('matches specific date', function (done) {
+
+        var now = Date.now();
+        Joi.date().valid(new Date(now)).validate(new Date(now), function (err, value) {
+
+            expect(err).to.not.exist();
+            done();
+        });
+    });
+
+    it('errors on invalid input and convert disabled', function (done) {
+
+        Joi.date().options({ convert: false }).validate('1-1-2013 UTC', function (err, value) {
+
+            expect(err).to.exist();
+            expect(err.message).to.equal('"value" must be a number of milliseconds or valid date string');
+            done();
+        });
+    });
+
+    it('validates date', function (done) {
+
+        Joi.date().validate(new Date(), function (err, value) {
+
+            expect(err).to.not.exist();
+            done();
+        });
+    });
+
+    it('validates millisecond date as a string', function (done) {
+
+        var now = new Date();
+        var mili = now.getTime();
+
+        Joi.date().validate(mili.toString(), function (err, value) {
+
+            expect(err).to.not.exist();
+            expect(value).to.deep.equal(now);
+            done();
+        });
+    });
+
+    describe('#validate', function () {
+
+        describe('min', function () {
+
+            it('validates min', function (done) {
+
+                Helper.validate(Joi.date().min('1-1-2000 UTC'), [
+                    ['1-1-2001 UTC', true],
+                    ['1-1-2000 UTC', true],
+                    [0, false],
+                    ['0', false],
+                    ['-1', false],
+                    ['1-1-1999 UTC', false]
+                ], done);
+            });
+
+            it('accepts "now" as the min date', function (done) {
+
+                var future = new Date(Date.now() + 1000000);
+
+                Joi.date().min('now').validate(future, function (err, value) {
+
+                    expect(err).to.not.exist();
+                    expect(value).to.deep.equal(future);
+                    done();
+                });
+            });
+
+            it('errors if .min("now") is used with a past date', function (done) {
+
+                var past = new Date(Date.now() - 1000000);
+
+                Joi.date().min('now').validate(past, function (err, value) {
+
+                    expect(err).to.exist();
+                    done();
+                });
+            });
+
+            it('accepts references as min date', function (done) {
+
+                var schema = Joi.object({ a: Joi.date(), b: Joi.date().min(Joi.ref('a')) });
+                var now = Date.now();
+
+                Helper.validate(schema, [
+                    [{ a: now, b: now }, true],
+                    [{ a: now, b: now + 1e3 }, true],
+                    [{ a: now, b: now - 1e3 }, false]
+                ], done);
+            });
+
+            it('accepts context references as min date', function (done) {
+
+                var schema = Joi.object({ b: Joi.date().min(Joi.ref('$a')) });
+                var now = Date.now();
+
+                Helper.validate(schema, [
+                    [{ b: now }, true, { context: { a: now } }],
+                    [{ b: now + 1e3 }, true, { context: { a: now } }],
+                    [{ b: now - 1e3 }, false, { context: { a: now } }]
+                ], done);
+            });
+
+            it('errors if reference is not a date', function (done) {
+
+                var schema = Joi.object({ a: Joi.string(), b: Joi.date().min(Joi.ref('a')) });
+                var now = Date.now();
+
+                Helper.validate(schema, [
+                    [{ a: 'abc', b: now }, false, null, 'child "b" fails because ["b" references "a" which is not a date]'],
+                    [{ a: '123', b: now }, true],
+                    [{ a: (now + 1e3).toString(), b: now }, false, null, /^child "b" fails because \["b" must be larger than or equal to/]
+                ], done);
+            });
+
+            it('errors if context reference is not a date', function (done) {
+
+                var schema = Joi.object({ b: Joi.date().min(Joi.ref('$a')) });
+                var now = Date.now();
+
+                Helper.validate(schema, [
+                    [{ b: now }, false, { context: { a: 'abc' } }, 'child "b" fails because ["b" references "a" which is not a date]'],
+                    [{ b: now }, false, { context: { a: (now + 1e3).toString() } }, /^child "b" fails because \["b" must be larger than or equal to/]
+                ], done);
+            });
+        });
+
+        describe('max', function () {
+
+            it('validates max', function (done) {
+
+                Helper.validate(Joi.date().max('1-1-1970 UTC'), [
+                    ['1-1-1971 UTC', false],
+                    ['1-1-1970 UTC', true],
+                    [0, true],
+                    [1, false],
+                    ['0', true],
+                    ['-1', true],
+                    ['1-1-2014 UTC', false]
+                ], done);
+            });
+
+            it('accepts "now" as the max date', function (done) {
+
+                var past = new Date(Date.now() - 1000000);
+
+                Joi.date().max('now').validate(past, function (err, value) {
+
+                    expect(err).to.not.exist();
+                    expect(value).to.deep.equal(past);
+                    done();
+                });
+            });
+
+            it('errors if .max("now") is used with a future date', function (done) {
+
+                var future = new Date(Date.now() + 1000000);
+
+                Joi.date().max('now').validate(future, function (err, value) {
+
+                    expect(err).to.exist();
+                    done();
+                });
+            });
+
+            it('accepts references as max date', function (done) {
+
+                var schema = Joi.object({ a: Joi.date(), b: Joi.date().max(Joi.ref('a')) });
+                var now = Date.now();
+
+                Helper.validate(schema, [
+                    [{ a: now, b: now }, true],
+                    [{ a: now, b: now + 1e3 }, false],
+                    [{ a: now, b: now - 1e3 }, true]
+                ], done);
+            });
+
+            it('accepts references as max date', function (done) {
+
+                var schema = Joi.object({ b: Joi.date().max(Joi.ref('$a')) });
+                var now = Date.now();
+
+                Helper.validate(schema, [
+                    [{ b: now }, true, { context: { a: now } }],
+                    [{ b: now + 1e3 }, false, { context: { a: now } }],
+                    [{ b: now - 1e3 }, true, { context: { a: now } }]
+                ], done);
+            });
+
+            it('errors if reference is not a date', function (done) {
+
+                var schema = Joi.object({ a: Joi.string(), b: Joi.date().max(Joi.ref('a')) });
+                var now = Date.now();
+
+                Helper.validate(schema, [
+                    [{ a: 'abc', b: new Date() }, false, null, 'child "b" fails because ["b" references "a" which is not a date]'],
+                    [{ a: '100000000000000', b: now }, true],
+                    [{ a: (now - 1e3).toString(), b: now }, false, null, /^child "b" fails because \["b" must be less than or equal to/]
+                ], done);
+            });
+
+            it('errors if context reference is not a date', function (done) {
+
+                var schema = Joi.object({ b: Joi.date().max(Joi.ref('$a')) });
+                var now = Date.now();
+
+                Helper.validate(schema, [
+                    [{ b: now }, false, { context: { a: 'abc' } }, 'child "b" fails because ["b" references "a" which is not a date]'],
+                    [{ b: now }, true, { context: { a: '100000000000000' } }],
+                    [{ b: now }, false, { context: { a: (now - 1e3).toString() } }, /^child "b" fails because \["b" must be less than or equal to/]
+                ], done);
+            });
+        });
+
+        it('validates only valid dates', function (done) {
+
+            Helper.validate(Joi.date(), [
+                ['1-1-2013 UTC', true],
+                ['not a valid date', false],
+                [new Date('not a valid date'), false]
+            ], done);
+        });
+
+        describe('#iso', function () {
+
+            it('validates isoDate', function (done) {
+
+                Helper.validate(Joi.date().iso(), [
+                    ['2013-06-07T14:21:46.295Z', true],
+                    ['2013-06-07T14:21:46.295Z0', false],
+                    ['2013-06-07T14:21:46.295+07:00', true],
+                    ['2013-06-07T14:21:46.295+07:000', false],
+                    ['2013-06-07T14:21:46.295-07:00', true],
+                    ['2013-06-07T14:21:46Z', true],
+                    ['2013-06-07T14:21:46Z0', false],
+                    ['2013-06-07T14:21:46+07:00', true],
+                    ['2013-06-07T14:21:46-07:00', true],
+                    ['2013-06-07T14:21Z', true],
+                    ['2013-06-07T14:21+07:00', true],
+                    ['2013-06-07T14:21+07:000', false],
+                    ['2013-06-07T14:21-07:00', true],
+                    ['2013-06-07T14:21Z+7:00', false],
+                    ['2013-06-07', true],
+                    ['2013-06-07T', false],
+                    ['2013-06-07T14:21', true],
+                    ['1-1-2013', false]
+                ], done);
+            });
+
+            it('validates isoDate with a friendly error message', function (done) {
+
+                var schema = { item: Joi.date().iso() };
+                Joi.compile(schema).validate({ item: 'something' }, function (err, value) {
+
+                    expect(err.message).to.contain('must be a valid ISO 8601 date');
+                    done();
+                });
+            });
+
+            it('validates isoDate after clone', function (done) {
+
+                var schema = { item: Joi.date().iso().clone() };
+                Joi.compile(schema).validate({ item: '2013-06-07T14:21:46.295Z' }, function (err, value) {
+
+                    expect(err).to.not.exist();
+                    done();
+                });
+            });
+        });
+
+        describe('#format', function () {
+
+            it('validates custom format', function (done) {
+
+                Helper.validate(Joi.date().format('DD#YYYY$MM'), [
+                    ['07#2013$06', true],
+                    ['2013-06-07', false]
+                ], done);
+            });
+
+            it('validates several custom formats', function (done) {
+
+                Helper.validate(Joi.date().format(['DD#YYYY$MM', 'YY|DD|MM']), [
+                    ['13|07|06', true],
+                    ['2013-06-07', false]
+                ], done);
+            });
+
+            it('fails with bad formats', function (done) {
+
+                expect(function () {
+
+                    Joi.date().format(true);
+                }).to.throw('Invalid format.');
+
+                expect(function () {
+
+                    Joi.date().format(['YYYYMMDD', true]);
+                }).to.throw('Invalid format.');
+                done();
+            });
+        });
+    });
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/errors.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/errors.js
new file mode 100755
index 0000000000000000000000000000000000000000..1ed8b9d1807f895ebe851bb03d5fc49a50eccded
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/errors.js
@@ -0,0 +1,459 @@
+// Load modules
+
+var Lab = require('lab');
+var Code = require('code');
+var Joi = require('../lib');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var lab = exports.lab = Lab.script();
+var describe = lab.describe;
+var it = lab.it;
+var expect = Code.expect;
+
+
+describe('errors', function () {
+
+    it('supports custom errors when validating types', function (done) {
+
+        var schema = Joi.object({
+            email: Joi.string().email(),
+            date: Joi.date(),
+            alphanum: Joi.string().alphanum(),
+            min: Joi.string().min(3),
+            max: Joi.string().max(3),
+            required: Joi.string().required(),
+            xor: Joi.string(),
+            renamed: Joi.string().valid('456'),
+            notEmpty: Joi.string().required()
+        }).rename('renamed', 'required').without('required', 'xor').without('xor', 'required');
+
+        var input = {
+            email: 'invalid-email',
+            date: 'invalid-date',
+            alphanum: '\b\n\f\r\t',
+            min: 'ab',
+            max: 'abcd',
+            required: 'hello',
+            xor: '123',
+            renamed: '456',
+            notEmpty: ''
+        };
+
+        var lang = {
+            any: {
+                empty: '3'
+            },
+            date: {
+                base: '18'
+            },
+            string: {
+                base: '13',
+                min: '14',
+                max: '15',
+                alphanum: '16',
+                email: '19'
+            },
+            object: {
+                without: '7',
+                rename: {
+                    override: '11'
+                }
+            }
+        };
+
+        Joi.validate(input, schema, { abortEarly: false, language: lang }, function (err, value) {
+
+            expect(err).to.exist();
+            expect(err.name).to.equal('ValidationError');
+            expect(err.message).to.equal('"value" 11. child "email" fails because ["email" 19]. child "date" fails because ["date" 18]. child "alphanum" fails because ["alphanum" 16]. child "min" fails because ["min" 14]. child "max" fails because ["max" 15]. child "notEmpty" fails because ["notEmpty" 3]. "required" 7. "xor" 7');
+            done();
+        });
+    });
+
+    it('does not prefix with key when language uses context.key', function (done) {
+
+        Joi.valid('sad').options({ language: { any: { allowOnly: 'my hero "{{key}}" is not {{valids}}' } } }).validate(5, function (err, value) {
+
+            expect(err.message).to.equal('my hero "value" is not [sad]');
+            done();
+        });
+    });
+
+    it('escapes unsafe keys', function (done) {
+
+        var schema = {
+            'a()': Joi.number()
+        };
+
+        Joi.validate({ 'a()': 'x' }, schema, function (err, value) {
+
+            expect(err.message).to.equal('child "a&#x28;&#x29;" fails because ["a&#x28;&#x29;" must be a number]');
+
+            Joi.validate({ 'b()': 'x' }, schema, function (err2, value2) {
+
+                expect(err2.message).to.equal('"b&#x28;&#x29;" is not allowed');
+                done();
+            });
+        });
+    });
+
+    it('returns error type in validation error', function (done) {
+
+        var input = {
+            notNumber: '',
+            notString: true,
+            notBoolean: 9
+        };
+
+        var schema = {
+            notNumber: Joi.number().required(),
+            notString: Joi.string().required(),
+            notBoolean: Joi.boolean().required()
+        };
+
+        Joi.validate(input, schema, { abortEarly: false }, function (err, value) {
+
+            expect(err).to.exist();
+            expect(err.details).to.have.length(3);
+            expect(err.details[0].type).to.equal('number.base');
+            expect(err.details[1].type).to.equal('string.base');
+            expect(err.details[2].type).to.equal('boolean.base');
+            done();
+        });
+    });
+
+    it('returns a full path to an error value on an array (items)', function (done) {
+
+        var schema = Joi.array().items(Joi.array().items({ x: Joi.number() }));
+        var input = [
+            [{ x: 1 }],
+            [{ x: 1 }, { x: 'a' }]
+        ];
+
+        schema.validate(input, function (err, value) {
+
+            expect(err).to.exist();
+            expect(err.details[0].path).to.equal('1.1.x');
+            done();
+        });
+    });
+
+    it('returns a full path to an error value on an array (items forbidden)', function (done) {
+
+        var schema = Joi.array().items(Joi.array().items(Joi.object({ x: Joi.string() }).forbidden()));
+        var input = [
+            [{ x: 1 }],
+            [{ x: 1 }, { x: 'a' }]
+        ];
+
+        schema.validate(input, function (err, value) {
+
+            expect(err).to.exist();
+            expect(err.details[0].path).to.equal('1.1');
+            done();
+        });
+    });
+
+    it('returns a full path to an error value on an object', function (done) {
+
+        var schema = {
+            x: Joi.array().items({ x: Joi.number() })
+        };
+
+        var input = {
+            x: [{ x: 1 }, { x: 'a' }]
+        };
+
+        Joi.validate(input, schema, function (err, value) {
+
+            expect(err).to.exist();
+            expect(err.details[0].path).to.equal('x.1.x');
+            done();
+        });
+    });
+
+    it('overrides root key language', function (done) {
+
+        Joi.string().options({ language: { root: 'blah' } }).validate(4, function (err, value) {
+
+            expect(err.message).to.equal('"blah" must be a string');
+            done();
+        });
+    });
+
+    it('overrides label key language', function (done) {
+
+        Joi.string().options({ language: { key: 'my own {{!key}} ' } }).validate(4, function (err, value) {
+
+            expect(err.message).to.equal('my own value must be a string');
+            done();
+        });
+    });
+
+    it('overrides wrapArrays', function (done) {
+
+        Joi.array().items(Joi.boolean()).options({ language: { messages: { wrapArrays: false } } }).validate([4], function (err, value) {
+
+            expect(err.message).to.equal('"value" at position 0 fails because "0" must be a boolean');
+            done();
+        });
+    });
+
+    it('allows html escaping', function (done) {
+
+        Joi.string().options({ language: { root: 'blah', label: 'bleh' } }).validate(4, function (err, value) {
+
+            expect(err.message).to.equal('"bleh" must be a string');
+            done();
+        });
+    });
+
+    it('provides context with the error', function (done) {
+
+        Joi.object({ length: Joi.number().min(3).required() }).validate({ length: 1 }, function (err) {
+
+            expect(err.details).to.deep.equal([{
+                message: '"length" must be larger than or equal to 3',
+                path: 'length',
+                type: 'number.min',
+                context: {
+                    limit: 3,
+                    key: 'length',
+                    value: 1
+                }
+            }]);
+            done();
+        });
+    });
+
+    it('has a name that is ValidationError', function (done) {
+
+        var schema = Joi.number();
+        schema.validate('a', function (validateErr) {
+
+            expect(validateErr).to.exist();
+            expect(validateErr.name).to.be.equal('ValidationError');
+
+            try {
+                Joi.assert('a', schema);
+                throw new Error('should not reach that');
+            }
+            catch (assertErr) {
+                expect(assertErr.name).to.be.equal('ValidationError');
+            }
+
+            try {
+                Joi.assert('a', schema, 'foo');
+                throw new Error('should not reach that');
+            }
+            catch (assertErr) {
+                expect(assertErr.name).to.be.equal('ValidationError');
+            }
+
+            try {
+                Joi.assert('a', schema, new Error('foo'));
+                throw new Error('should not reach that');
+            }
+            catch (assertErr) {
+                expect(assertErr.name).to.equal('Error');
+                done();
+            }
+        });
+    });
+
+    describe('#annotate', function () {
+
+        it('annotates error', function (done) {
+
+            var object = {
+                a: 'm',
+                y: {
+                    b: {
+                        c: 10
+                    }
+                }
+            };
+
+            var schema = {
+                a: Joi.string().valid('a', 'b', 'c', 'd'),
+                y: Joi.object({
+                    u: Joi.string().valid(['e', 'f', 'g', 'h']).required(),
+                    b: Joi.string().valid('i', 'j').allow(false),
+                    d: Joi.object({
+                        x: Joi.string().valid('k', 'l').required(),
+                        c: Joi.number()
+                    })
+                })
+            };
+
+            Joi.validate(object, schema, { abortEarly: false }, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.annotate()).to.equal('{\n  \"y\": {\n    \"b\" \u001b[31m[1]\u001b[0m: {\n      \"c\": 10\n    },\n    \u001b[41m\"u\"\u001b[0m\u001b[31m [2]: -- missing --\u001b[0m\n  },\n  "a" \u001b[31m[3]\u001b[0m: \"m\"\n}\n\u001b[31m\n[1] "a" must be one of [a, b, c, d]\n[2] "u" is required\n[3] "b" must be a string\u001b[0m');
+                done();
+            });
+        });
+
+        it('annotates error within array', function (done) {
+
+            var object = {
+                a: [1, 2, 3, 4, 2, 5]
+            };
+
+            var schema = {
+                a: Joi.array().items(Joi.valid(1, 2))
+            };
+
+            Joi.validate(object, schema, { abortEarly: false }, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.annotate()).to.equal('{\n  \"a\": [\n    1,\n    2,\n    3, \u001b[31m[1]\u001b[0m\n    4, \u001b[31m[2]\u001b[0m\n    2,\n    5 \u001b[31m[3]\u001b[0m\n  ]\n}\n\u001b[31m\n[1] \"2\" must be one of [1, 2]\n[2] \"3\" must be one of [1, 2]\n[3] \"5\" must be one of [1, 2]\u001b[0m');
+                done();
+            });
+        });
+
+        it('annotates error within array multiple times on the same element', function (done) {
+
+            var object = {
+                a: [2, 3, 4]
+            };
+
+            var schema = {
+                a: Joi.array().items(Joi.number().min(4).max(2))
+            };
+
+            Joi.validate(object, schema, { abortEarly: false }, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.annotate()).to.equal('{\n  \"a\": [\n    2, \u001b[31m[1]\u001b[0m\n    3, \u001b[31m[3, 2]\u001b[0m\n    4 \u001b[31m[4]\u001b[0m\n  ]\n}\n\u001b[31m\n[1] \"0\" must be larger than or equal to 4\n[2] \"1\" must be larger than or equal to 4\n[3] \"1\" must be less than or equal to 2\n[4] \"2\" must be less than or equal to 2\u001b[0m');
+                done();
+            });
+        });
+
+        it('annotates error within array when it is an object', function (done) {
+
+            var object = {
+                a: [{ b: 2 }]
+            };
+
+            var schema = {
+                a: Joi.array().items(Joi.number())
+            };
+
+            Joi.validate(object, schema, { abortEarly: false }, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.annotate()).to.equal('{\n  \"a\": [\n    { \u001b[31m[1]\u001b[0m\n      \"b\": 2\n    }\n  ]\n}\n\u001b[31m\n[1] \"0\" must be a number\u001b[0m');
+                done();
+            });
+        });
+
+        it('annotates error within multiple arrays and multiple times on the same element', function (done) {
+
+            var object = {
+                a: [2, 3, 4],
+                b: [2, 3, 4]
+            };
+
+            var schema = {
+                a: Joi.array().items(Joi.number().min(4).max(2)),
+                b: Joi.array().items(Joi.number().min(4).max(2))
+            };
+
+            Joi.validate(object, schema, { abortEarly: false }, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.annotate()).to.equal('{\n  \"a\": [\n    2, \u001b[31m[1]\u001b[0m\n    3, \u001b[31m[3, 2]\u001b[0m\n    4 \u001b[31m[4]\u001b[0m\n  ],\n  \"b\": [\n    2, \u001b[31m[5]\u001b[0m\n    3, \u001b[31m[7, 6]\u001b[0m\n    4 \u001b[31m[8]\u001b[0m\n  ]\n}\n\u001b[31m\n[1] \"0\" must be larger than or equal to 4\n[2] \"1\" must be larger than or equal to 4\n[3] \"1\" must be less than or equal to 2\n[4] \"2\" must be less than or equal to 2\n[5] \"0\" must be larger than or equal to 4\n[6] \"1\" must be larger than or equal to 4\n[7] \"1\" must be less than or equal to 2\n[8] \"2\" must be less than or equal to 2\u001b[0m');
+                done();
+            });
+        });
+
+        it('displays alternatives fail as a single line', function (done) {
+
+            var schema = {
+                x: [
+                    Joi.string(),
+                    Joi.number(),
+                    Joi.date()
+                ]
+            };
+
+            Joi.validate({ x: true }, schema, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.annotate()).to.equal('{\n  \"x\" \u001b[31m[1, 2, 3]\u001b[0m: true\n}\n\u001b[31m\n[1] "x" must be a string\n[2] "x" must be a number\n[3] "x" must be a number of milliseconds or valid date string\u001b[0m');
+                done();
+            });
+        });
+
+        it('annotates circular input', function (done) {
+
+            var schema = {
+                x: Joi.object({
+                    y: Joi.object({
+                        z: Joi.number()
+                    })
+                })
+            };
+
+            var input = {};
+            input.x = input;
+
+            Joi.validate(input, schema, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.annotate()).to.equal('{\n  \"x\" \u001b[31m[1]\u001b[0m: \"[Circular ~]\"\n}\n\u001b[31m\n[1] \"x\" is not allowed\u001b[0m');
+                done();
+            });
+        });
+
+        it('annotates deep circular input', function (done) {
+
+            var schema = {
+                x: Joi.object({
+                    y: Joi.object({
+                        z: Joi.number()
+                    })
+                })
+            };
+
+            var input = { x: { y: {} } };
+            input.x.y.z = input.x.y;
+
+            Joi.validate(input, schema, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.annotate()).to.equal('{\n  \"x\": {\n    \"y\": {\n      \"z\" \u001b[31m[1]\u001b[0m: \"[Circular ~.x.y]\"\n    }\n  }\n}\n\u001b[31m\n[1] \"z\" must be a number\u001b[0m');
+                done();
+            });
+        });
+
+        it('annotates deep circular input with extra keys', function (done) {
+
+            var schema = {
+                x: Joi.object({
+                    y: Joi.object({
+                        z: Joi.number()
+                    })
+                })
+            };
+
+            var input = { x: { y: { z: 1, foo: {} } } };
+            input.x.y.foo = input.x.y;
+
+            Joi.validate(input, schema, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.annotate()).to.equal('{\n  \"x\": {\n    \"y\": {\n      \"z\": 1,\n      \"foo\" \u001b[31m[1]\u001b[0m: \"[Circular ~.x.y]\"\n    }\n  }\n}\n\u001b[31m\n[1] \"foo\" is not allowed\u001b[0m');
+                done();
+            });
+        });
+    });
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/function.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/function.js
new file mode 100755
index 0000000000000000000000000000000000000000..b80879fcd6be2361dd5743acb6fdb816ab8cd57d
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/function.js
@@ -0,0 +1,113 @@
+// Load modules
+
+var Code = require('code');
+var Lab = require('lab');
+var Joi = require('../lib');
+var Helper = require('./helper');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var lab = exports.lab = Lab.script();
+var describe = lab.describe;
+var it = lab.it;
+var expect = Code.expect;
+
+
+describe('func', function () {
+
+    it('validates a function', function (done) {
+
+        Helper.validate(Joi.func().required(), [
+            [function () { }, true],
+            ['', false]
+        ], done);
+    });
+
+    it('validates a function with keys', function (done) {
+
+        var a = function () { };
+        a.a = 'abc';
+
+        var b = function () { };
+        b.a = 123;
+
+        Helper.validate(Joi.func().keys({ a: Joi.string().required() }).required(), [
+            [function () { }, false],
+            [a, true],
+            [b, false],
+            ['', false]
+        ], done);
+    });
+
+    it('keeps validated value as a function', function (done) {
+
+        var schema = Joi.func().keys({ a: Joi.number() });
+
+        var b = 'abc';
+        var value = function () {
+
+            return b;
+        };
+
+        value.a = '123';
+
+        schema.validate(value, function (err, validated) {
+
+            expect(validated).to.be.a.function();
+            expect(validated()).to.equal('abc');
+            expect(validated).to.not.equal(value);
+            done();
+        });
+    });
+
+    it('retains validated value prototype', function (done) {
+
+        var schema = Joi.func().keys({ a: Joi.number() });
+
+        var value = function () {
+
+            this.x = 'o';
+        };
+
+        value.prototype.get = function () {
+
+            return this.x;
+        };
+
+        schema.validate(value, function (err, validated) {
+
+            expect(validated).to.be.a.function();
+            var p = new validated();
+            expect(p.get()).to.equal('o');
+            expect(validated).to.not.equal(value);
+            done();
+        });
+    });
+
+    it('keeps validated value as a function (no clone)', function (done) {
+
+        var schema = Joi.func();
+
+        var b = 'abc';
+        var value = function () {
+
+            return b;
+        };
+
+        value.a = '123';
+
+        schema.validate(value, function (err, validated) {
+
+            expect(validated).to.be.a.function();
+            expect(validated()).to.equal('abc');
+            expect(validated).to.equal(value);
+            done();
+        });
+    });
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/helper.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/helper.js
new file mode 100755
index 0000000000000000000000000000000000000000..77d0f805989e4081725935653e33fec2170245eb
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/helper.js
@@ -0,0 +1,63 @@
+// Load modules
+
+var Code = require('code');
+var Joi = require('../');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var expect = Code.expect;
+
+
+exports.validate = function (schema, config, callback) {
+
+    return exports.validateOptions(schema, config, null, callback);
+};
+
+
+exports.validateOptions = function (schema, config, options, callback) {
+
+    var compiled = Joi.compile(schema);
+    for (var i = 0, il = config.length; i < il; ++i) {
+
+        var item = config[i];
+        var result = Joi.validate(item[0], compiled, item[2] || options);
+
+        var err = result.error;
+        var value = result.value;
+
+        if (err !== null && item[1]) {
+            console.log(err);
+        }
+
+        if (err === null && !item[1]) {
+            console.log(item[0]);
+        }
+
+        expect(err === null).to.equal(item[1]);
+
+        if (item.length >= 4) {
+            var comparator = item[3];
+            if (item[1]) {
+                expect(value).to.deep.equal(comparator);
+            }
+            else {
+                if (comparator instanceof RegExp) {
+                    expect(err.message).to.match(comparator);
+                }
+                else {
+                    expect(err.message).to.deep.equal(comparator);
+                }
+            }
+        }
+    }
+
+    if (callback) {
+        callback();
+    }
+};
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/index.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/index.js
new file mode 100755
index 0000000000000000000000000000000000000000..c1601505980cb64499dab1f521d88c36abf67401
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/index.js
@@ -0,0 +1,1692 @@
+// Load modules
+
+var Lab = require('lab');
+var Code = require('code');
+var Joi = require('../lib');
+var Helper = require('./helper');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var lab = exports.lab = Lab.script();
+var describe = lab.describe;
+var it = lab.it;
+var expect = Code.expect;
+
+
+describe('Joi', function () {
+
+    it('validates object', function (done) {
+
+        var schema = Joi.object({
+            a: Joi.number().min(0).max(3),
+            b: Joi.string().valid('a', 'b', 'c'),
+            c: Joi.string().email().optional()
+        }).without('a', 'none');
+
+        var obj = {
+            a: 1,
+            b: 'a',
+            c: 'joe@example.com'
+        };
+
+        schema.validate(obj, function (err, value) {
+
+            expect(err).to.not.exist();
+            done();
+        });
+    });
+
+    it('keeps schema immutable', function (done) {
+
+        var a = Joi.string();
+        var b = a.valid('b');
+
+        Helper.validate(a, [
+            ['a', true],
+            ['b', true],
+            [5, false]
+        ], function () {
+
+            Helper.validate(b, [
+                ['a', false],
+                ['b', true],
+                [5, false]
+            ], done);
+        });
+
+    });
+
+    it('validates null', function (done) {
+
+        Joi.string().validate(null, function (err, value) {
+
+            expect(err).to.exist();
+            expect(err.annotate()).to.equal('{\n  \u001b[41m\"value\"\u001b[0m\u001b[31m [1]: -- missing --\u001b[0m\n}\n\u001b[31m\n[1] "value" must be a string\u001b[0m');
+            done();
+        });
+    });
+
+    it('validates null schema', function (done) {
+
+        Helper.validate(null, [
+            ['a', false],
+            [null, true]
+        ], done);
+    });
+
+    it('validates number literal', function (done) {
+
+        Helper.validate(5, [
+            [6, false],
+            [5, true]
+        ], done);
+    });
+
+    it('validates string literal', function (done) {
+
+        Helper.validate('5', [
+            ['6', false],
+            ['5', true]
+        ], done);
+    });
+
+    it('validates boolean literal', function (done) {
+
+        Helper.validate(true, [
+            [false, false],
+            [true, true]
+        ], done);
+    });
+
+    it('validates date literal', function (done) {
+
+        var now = Date.now();
+        Helper.validate(new Date(now), [
+            [new Date(now), true],
+            [now, true],
+            [now * 2, false]
+        ], done);
+    });
+
+    it('validates complex literal', function (done) {
+
+        var schema = ['key', 5, { a: true, b: [/^a/, 'boom'] }];
+        Helper.validate(schema, [
+            ['key', true],
+            [5, true],
+            ['other', false],
+            [6, false],
+            [{ c: 5 }, false],
+            [{}, true],
+            [{ b: 'abc' }, true],
+            [{ a: true, b: 'boom' }, true],
+            [{ a: 5, b: 'a' }, false]
+        ], done);
+    });
+
+    it('validates a compiled complex literal', function (done) {
+
+        var schema = Joi.compile(['key', 5, { a: true, b: [/^a/, 'boom'] }]);
+        Helper.validate(schema, [
+            ['key', true],
+            [5, true],
+            ['other', false],
+            [6, false],
+            [{ c: 5 }, false],
+            [{}, true],
+            [{ b: 'abc' }, true],
+            [{ a: true, b: 'boom' }, true],
+            [{ a: 5, b: 'a' }, false]
+        ], done);
+    });
+
+    it('validates regex directly', function (done) {
+
+        Joi.compile(/^5$/).validate('5', function (err, value) {
+
+            expect(err).to.not.exist();
+            Joi.compile(/.{2}/).validate('6', function (err2, value2) {
+
+                expect(err2).to.exist();
+                done();
+            });
+        });
+    });
+
+    it('validated with', function (done) {
+
+        var schema = Joi.object({
+            txt: Joi.string(),
+            upc: Joi.string()
+        }).with('txt', 'upc');
+
+        Joi.validate({ txt: 'a' }, schema, { abortEarly: false }, function (err, value) {
+
+            expect(err.message).to.equal('"txt" missing required peer "upc"');
+
+            Helper.validate(schema, [
+                [{ upc: 'test' }, true],
+                [{ txt: 'test' }, false],
+                [{ txt: 'test', upc: null }, false],
+                [{ txt: 'test', upc: '' }, false],
+                [{ txt: 'test', upc: undefined }, false],
+                [{ txt: 'test', upc: 'test' }, true]
+            ], done);
+        });
+    });
+
+    it('validated without', function (done) {
+
+        var schema = Joi.object({
+            txt: Joi.string(),
+            upc: Joi.string()
+        }).without('txt', 'upc');
+
+        Joi.validate({ txt: 'a', upc: 'b' }, schema, { abortEarly: false }, function (err, value) {
+
+            expect(err.message).to.equal('"txt" conflict with forbidden peer "upc"');
+
+            Helper.validate(schema, [
+                [{ upc: 'test' }, true],
+                [{ txt: 'test' }, true],
+                [{ txt: 'test', upc: null }, false],
+                [{ txt: 'test', upc: '' }, false],
+                [{ txt: 'test', upc: undefined }, true],
+                [{ txt: 'test', upc: 'test' }, false]
+            ], done);
+        });
+    });
+
+    it('validates xor', function (done) {
+
+        var schema = Joi.object({
+            txt: Joi.string(),
+            upc: Joi.string()
+        }).xor('txt', 'upc');
+
+        Joi.validate({}, schema, { abortEarly: false }, function (err, value) {
+
+            expect(err.message).to.equal('"value" must contain at least one of [txt, upc]');
+
+            Helper.validate(schema, [
+                [{ upc: null }, false],
+                [{ upc: 'test' }, true],
+                [{ txt: null }, false],
+                [{ txt: 'test' }, true],
+                [{ txt: 'test', upc: null }, false],
+                [{ txt: 'test', upc: '' }, false],
+                [{ txt: '', upc: 'test' }, false],
+                [{ txt: null, upc: 'test' }, false],
+                [{ txt: undefined, upc: 'test' }, true],
+                [{ txt: 'test', upc: undefined }, true],
+                [{ txt: 'test', upc: '' }, false],
+                [{ txt: 'test', upc: null }, false],
+                [{ txt: '', upc: undefined }, false],
+                [{ txt: '', upc: '' }, false],
+                [{ txt: 'test', upc: 'test' }, false]
+            ], done);
+        });
+    });
+
+    it('validates multiple peers xor', function (done) {
+
+        var schema = Joi.object({
+            txt: Joi.string(),
+            upc: Joi.string(),
+            code: Joi.string()
+        }).xor('txt', 'upc', 'code');
+
+        Helper.validate(schema, [
+            [{ upc: 'test' }, true],
+            [{ txt: 'test' }, true],
+            [{}, false]
+        ], done);
+    });
+
+    it('validates xor with number types', function (done) {
+
+        var schema = Joi.object({
+            code: Joi.number(),
+            upc: Joi.number()
+        }).xor('code', 'upc');
+
+        Helper.validate(schema, [
+            [{ upc: 123 }, true],
+            [{ code: 456 }, true],
+            [{ code: 456, upc: 123 }, false],
+            [{}, false]
+        ], done);
+    });
+
+    it('validates xor when empty value of peer allowed', function (done) {
+
+        var schema = Joi.object({
+            code: Joi.string(),
+            upc: Joi.string().allow('')
+        }).xor('code', 'upc');
+
+        Helper.validate(schema, [
+            [{ upc: '' }, true],
+            [{ upc: '123' }, true],
+            [{ code: '456' }, true],
+            [{ code: '456', upc: '' }, false],
+            [{}, false]
+        ], done);
+    });
+
+    it('validates or', function (done) {
+
+        var schema = Joi.object({
+            txt: Joi.string(),
+            upc: Joi.string().allow(null, ''),
+            code: Joi.number()
+        }).or('txt', 'upc', 'code');
+
+        Joi.validate({}, schema, { abortEarly: false }, function (err, value) {
+
+            expect(err.message).to.equal('"value" must contain at least one of [txt, upc, code]');
+
+            Helper.validate(schema, [
+                [{ upc: null }, true],
+                [{ upc: 'test' }, true],
+                [{ txt: null }, false],
+                [{ txt: 'test' }, true],
+                [{ code: null }, false],
+                [{ code: 123 }, true],
+                [{ txt: 'test', upc: null }, true],
+                [{ txt: 'test', upc: '' }, true],
+                [{ txt: '', upc: 'test' }, false],
+                [{ txt: null, upc: 'test' }, false],
+                [{ txt: undefined, upc: 'test' }, true],
+                [{ txt: 'test', upc: undefined }, true],
+                [{ txt: 'test', upc: '' }, true],
+                [{ txt: 'test', upc: null }, true],
+                [{ txt: '', upc: undefined }, false],
+                [{ txt: '', upc: undefined, code: 999 }, false],
+                [{ txt: '', upc: undefined, code: undefined }, false],
+                [{ txt: '', upc: '' }, false],
+                [{ txt: 'test', upc: 'test' }, true],
+                [{ txt: 'test', upc: 'test', code: 322 }, true]
+            ], done);
+        });
+    });
+
+    it('validates and', function (done) {
+
+        var schema = Joi.object({
+            txt: Joi.string(),
+            upc: Joi.string().allow(null, ''),
+            code: Joi.number()
+        }).and('txt', 'upc', 'code');
+
+        Joi.validate({ txt: 'x' }, schema, { abortEarly: false }, function (err, value) {
+
+            expect(err.message).to.equal('"value" contains [txt] without its required peers [upc, code]');
+
+            Helper.validate(schema, [
+                [{}, true],
+                [{ upc: null }, false],
+                [{ upc: 'test' }, false],
+                [{ txt: null }, false],
+                [{ txt: 'test' }, false],
+                [{ code: null }, false],
+                [{ code: 123 }, false],
+                [{ txt: 'test', upc: null }, false],
+                [{ txt: 'test', upc: '' }, false],
+                [{ txt: '', upc: 'test' }, false],
+                [{ txt: null, upc: 'test' }, false],
+                [{ txt: undefined, upc: 'test' }, false],
+                [{ txt: 'test', upc: undefined }, false],
+                [{ txt: 'test', upc: '' }, false],
+                [{ txt: 'test', upc: null }, false],
+                [{ txt: '', upc: undefined }, false],
+                [{ txt: '', upc: undefined, code: 999 }, false],
+                [{ txt: '', upc: undefined, code: undefined }, false],
+                [{ txt: '', upc: '' }, false],
+                [{ txt: 'test', upc: 'test' }, false],
+                [{ txt: 'test', upc: 'test', code: 322 }, true],
+                [{ txt: 'test', upc: null, code: 322 }, true]
+            ], done);
+        });
+    });
+
+    it('validates nand()', function (done) {
+
+        var schema = Joi.object({
+            txt: Joi.string(),
+            upc: Joi.string().allow(null, ''),
+            code: Joi.number()
+        }).nand('txt', 'upc', 'code');
+
+        Joi.validate({ txt: 'x', upc: 'y', code: 123 }, schema, { abortEarly: false }, function (err, value) {
+
+            expect(err.message).to.equal('"txt" must not exist simultaneously with [upc, code]');
+
+            Helper.validate(schema, [
+                [{}, true],
+                [{ upc: null }, true],
+                [{ upc: 'test' }, true],
+                [{ txt: 'test' }, true],
+                [{ code: 123 }, true],
+                [{ txt: 'test', upc: null }, true],
+                [{ txt: 'test', upc: '' }, true],
+                [{ txt: undefined, upc: 'test' }, true],
+                [{ txt: 'test', upc: undefined }, true],
+                [{ txt: 'test', upc: '' }, true],
+                [{ txt: 'test', upc: null }, true],
+                [{ txt: 'test', upc: undefined, code: 999 }, true],
+                [{ txt: 'test', upc: 'test' }, true],
+                [{ txt: 'test', upc: 'test', code: 322 }, false],
+                [{ txt: 'test', upc: null, code: 322 }, false]
+            ], done);
+        });
+    });
+
+    it('validates an array of valid types', function (done) {
+
+        var schema = Joi.object({
+            auth: [
+                Joi.object({
+                    mode: Joi.string().valid('required', 'optional', 'try').allow(null)
+                }).allow(null),
+                Joi.string(),
+                Joi.boolean()
+            ]
+        });
+
+        schema.validate({ auth: { mode: 'none' } }, function (err, value) {
+
+            expect(err).to.exist();
+            expect(err.message).to.equal('child "auth" fails because [child "mode" fails because ["mode" must be one of [required, optional, try, null]], "auth" must be a string, "auth" must be a boolean]');
+
+            Helper.validate(schema, [
+                [{ auth: { mode: 'try' } }, true],
+                [{ something: undefined }, false],
+                [{ auth: { something: undefined } }, false],
+                [{ auth: null }, true],
+                [{ auth: undefined }, true],
+                [{}, true],
+                [{ auth: true }, true],
+                [{ auth: 123 }, false]
+            ], done);
+        });
+    });
+
+    it('validates alternatives', function (done) {
+
+        var schema = Joi.object({
+            auth: Joi.alternatives(
+                Joi.object({
+                    mode: Joi.string().valid('required', 'optional', 'try').allow(null)
+                }).allow(null),
+                Joi.string(),
+                Joi.boolean()
+            )
+        });
+
+        schema.validate({ auth: { mode: 'none' } }, function (err, value) {
+
+            expect(err).to.exist();
+            expect(err.message).to.equal('child "auth" fails because [child "mode" fails because ["mode" must be one of [required, optional, try, null]], "auth" must be a string, "auth" must be a boolean]');
+
+            Helper.validate(schema, [
+                [{ auth: { mode: 'try' } }, true],
+                [{ something: undefined }, false],
+                [{ auth: { something: undefined } }, false],
+                [{ auth: null }, true],
+                [{ auth: undefined }, true],
+                [{}, true],
+                [{ auth: true }, true],
+                [{ auth: 123 }, false]
+            ], done);
+        });
+    });
+
+    it('validates required alternatives', function (done) {
+
+        var schema = {
+            a: Joi.alternatives(
+                Joi.string().required(),
+                Joi.boolean().required()
+            )
+        };
+
+        Helper.validate(schema, [
+            [{ a: null }, false],
+            [{ a: undefined }, true],
+            [{}, true],
+            [{ a: true }, true],
+            [{ a: 'true' }, true],
+            [{ a: 123 }, false],
+            [{ a: { c: 1 } }, false],
+            [{ b: undefined }, false]
+        ], done);
+    });
+
+    it('validates required [] alternatives', function (done) {
+
+        var schema = {
+            a: [
+                Joi.string().required(),
+                Joi.boolean().required()
+            ]
+        };
+
+        Helper.validate(schema, [
+            [{ a: null }, false],
+            [{ a: undefined }, true],
+            [{}, true],
+            [{ a: true }, true],
+            [{ a: 'true' }, true],
+            [{ a: 123 }, false],
+            [{ a: { c: 1 } }, false],
+            [{ b: undefined }, false]
+        ], done);
+    });
+
+    it('validates an array of string with valid', function (done) {
+
+        var schema = {
+            brand: Joi.array().items(Joi.string().valid('amex', 'visa'))
+        };
+
+        Helper.validate(schema, [
+            [{ brand: ['amex'] }, true],
+            [{ brand: ['visa', 'mc'] }, false]
+        ], done);
+    });
+
+    it('validates pre and post convert value', function (done) {
+
+        var schema = Joi.number().valid(5);
+
+        Helper.validate(schema, [
+            [5, true],
+            ['5', true]
+        ], done);
+    });
+
+    it('does not change object when validation fails', function (done) {
+
+        var schema = Joi.object({
+            a: Joi.number().valid(2)
+        });
+
+        var obj = {
+            a: '5'
+        };
+
+        schema.validate(obj, function (err, value) {
+
+            expect(err).to.exist();
+            expect(value.a).to.equal('5');
+            done();
+        });
+    });
+
+    it('does not set optional keys when missing', function (done) {
+
+        var schema = Joi.object({
+            a: Joi.number()
+        });
+
+        var obj = {};
+
+        schema.validate(obj, function (err, value) {
+
+            expect(err).to.not.exist();
+            expect(value.hasOwnProperty('a')).to.equal(false);
+            done();
+        });
+    });
+
+    it('invalidates pre and post convert value', function (done) {
+
+        var schema = Joi.number().invalid(5);
+
+        Helper.validate(schema, [
+            [5, false],
+            ['5', false]
+        ], done);
+    });
+
+    it('invalidates missing peers', function (done) {
+
+        var schema = Joi.object({
+            username: Joi.string(),
+            password: Joi.string()
+        }).with('username', 'password').without('password', 'access_token');
+
+        schema.validate({ username: 'bob' }, function (err, value) {
+
+            expect(err).to.exist();
+            done();
+        });
+    });
+
+    it('validates config where the root item is a joi type', function (done) {
+
+        Joi.boolean().allow(null).validate(true, function (err, value) {
+
+            expect(err).to.be.null();
+            Joi.object().validate({ auth: { mode: 'try' } }, function (err2, value2) {
+
+                expect(err2).to.be.null();
+
+                Joi.object().validate(true, function (err3, value3) {
+
+                    expect(err3.message).to.contain('"value" must be an object');
+
+                    Joi.string().validate(true, function (err4, value4) {
+
+                        expect(err4.message).to.contain('"value" must be a string');
+
+                        Joi.string().email().validate('test@test.com', function (err5, value5) {
+
+                            expect(err5).to.be.null();
+                            Joi.object({ param: Joi.string().required() }).validate({ param: 'item' }, function (err6, value6) {
+
+                                expect(err6).to.be.null();
+                                done();
+                            });
+                        });
+                    });
+                });
+            });
+        });
+    });
+
+    it('converts string to number', function (done) {
+
+        var schema = Joi.object({
+            a: Joi.number()
+        });
+
+        var input = { a: '5' };
+        schema.validate(input, function (err, value) {
+
+            expect(err).to.be.null();
+            expect(value.a).to.equal(5);
+            expect(input.a).to.equal('5');
+            done();
+        });
+    });
+
+    it('allows unknown keys in objects if no schema was given', function (done) {
+
+        Joi.object().validate({ foo: 'bar' }, function (err, value) {
+
+            expect(err).to.not.exist();
+            done();
+        });
+    });
+
+    it('fails on unknown keys in objects if a schema was given', function (done) {
+
+        Joi.object({}).validate({ foo: 'bar' }, function (err, value) {
+
+            expect(err).to.exist();
+            expect(err.message).to.equal('"foo" is not allowed');
+
+            Joi.compile({}).validate({ foo: 'bar' }, function (err2, value2) {
+
+                expect(err2).to.exist();
+                expect(err2.message).to.equal('"foo" is not allowed');
+
+                Joi.compile({ other: Joi.number() }).validate({ foo: 'bar' }, function (err3, value3) {
+
+                    expect(err3).to.exist();
+                    expect(err3.message).to.equal('"foo" is not allowed');
+
+                    done();
+                });
+            });
+        });
+    });
+
+    it('validates an unknown option', function (done) {
+
+        var config = {
+            auth: Joi.object({
+                mode: Joi.string().valid('required', 'optional', 'try').allow(null)
+            }).allow(null)
+        };
+
+        Joi.compile(config).validate({ auth: { unknown: true } }, function (err, value) {
+
+            expect(err).to.not.be.null();
+            expect(err.message).to.contain('"unknown" is not allowed');
+
+            Joi.compile(config).validate({ something: false }, function (err2, value2) {
+
+                expect(err2).to.not.be.null();
+                expect(err2.message).to.contain('"something" is not allowed');
+
+                done();
+            });
+        });
+    });
+
+    it('validates required key with multiple options', function (done) {
+
+        var config = {
+            module: Joi.alternatives([
+                Joi.object({
+                    compile: Joi.func().required(),
+                    execute: Joi.func()
+                }),
+                Joi.string()
+            ]).required()
+        };
+
+        Joi.compile(config).validate({}, function (err, value) {
+
+            expect(err).to.exist();
+            expect(err.message).to.contain('"module" is required');
+
+            Joi.compile(config).validate({ module: 'test' }, function (err2, value2) {
+
+                expect(err2).to.be.null();
+
+                Joi.compile(config).validate({ module: {} }, function (err3, value3) {
+
+                    expect(err3).to.not.be.null();
+                    expect(err3.message).to.contain('"compile" is required');
+                    expect(err3.message).to.contain('"module" must be a string');
+
+                    Joi.compile(config).validate({ module: { compile: function () { } } }, function (err4, value4) {
+
+                        expect(err4).to.be.null();
+                        done();
+                    });
+                });
+            });
+        });
+    });
+
+    it('validates key with required alternatives', function (done) {
+
+        var config = {
+            module: Joi.alt().try(
+                Joi.object({
+                    compile: Joi.func().required(),
+                    execute: Joi.func()
+                }).required(),
+                Joi.string().required()
+            )
+        };
+
+        Joi.compile(config).validate({}, function (err, value) {
+
+            expect(err).to.not.exist();
+            done();
+        });
+    });
+
+    it('validates required key with alternatives', function (done) {
+
+        var config = {
+            module: Joi.alt().try(
+                Joi.object({
+                    compile: Joi.func().required(),
+                    execute: Joi.func()
+                }),
+                Joi.string()
+            ).required()
+        };
+
+        Joi.compile(config).validate({}, function (err, value) {
+
+            expect(err).to.exist();
+            expect(err.message).to.contain('"module" is required');
+            done();
+        });
+    });
+
+    it('does not require optional numbers', function (done) {
+
+        var config = {
+            position: Joi.number(),
+            suggestion: Joi.string()
+        };
+
+        Joi.compile(config).validate({ suggestion: 'something' }, function (err, value) {
+
+            expect(err).to.be.null();
+
+            Joi.compile(config).validate({ position: 1 }, function (err2, value2) {
+
+                expect(err2).to.be.null();
+                done();
+            });
+        });
+    });
+
+    it('does not require optional objects', function (done) {
+
+        var config = {
+            position: Joi.number(),
+            suggestion: Joi.object()
+        };
+
+        Joi.compile(config).validate({ suggestion: {} }, function (err, value) {
+
+            expect(err).to.be.null();
+
+            Joi.compile(config).validate({ position: 1 }, function (err2, value2) {
+
+                expect(err2).to.be.null();
+                done();
+            });
+        });
+    });
+
+    it('validates object successfully when config has an array of types', function (done) {
+
+        var schema = {
+            f: [Joi.number(), Joi.boolean()],
+            g: [Joi.string(), Joi.object()]
+        };
+
+        var obj = {
+            f: true,
+            g: 'test'
+        };
+
+        Joi.compile(schema).validate(obj, function (err, value) {
+
+            expect(err).to.not.exist();
+            done();
+        });
+    });
+
+    it('validates object successfully when config allows for optional key and key is missing', function (done) {
+
+        var schema = {
+            h: Joi.number(),
+            i: Joi.string(),
+            j: Joi.object()
+        };
+
+        var obj = {
+            h: 12,
+            i: 'test'
+        };
+
+        Joi.compile(schema).validate(obj, function (err, value) {
+
+            expect(err).to.not.exist();
+            done();
+        });
+    });
+
+    it('fails validation', function (done) {
+
+        var schema = {
+            a: Joi.number().min(0).max(3),
+            b: Joi.string().valid('a', 'b', 'c'),
+            c: Joi.string().email().optional()
+        };
+
+        var obj = {
+            a: 10,
+            b: 'a',
+            c: 'joe@example.com'
+        };
+
+        Joi.compile(schema).validate(obj, function (err, value) {
+
+            expect(err).to.exist();
+            done();
+        });
+    });
+
+    it('fails validation when the wrong types are supplied', function (done) {
+
+        var schema = {
+            a: Joi.number().min(0).max(3),
+            b: Joi.string().valid('a', 'b', 'c'),
+            c: Joi.string().email().optional()
+        };
+
+        var obj = {
+            a: 'a',
+            b: 'a',
+            c: 'joe@example.com'
+        };
+
+        Joi.compile(schema).validate(obj, function (err, value) {
+
+            expect(err).to.exist();
+            done();
+        });
+    });
+
+    it('fails validation when missing a required parameter', function (done) {
+
+        var obj = {
+            c: 10
+        };
+
+        Joi.compile({ a: Joi.string().required() }).validate(obj, function (err, value) {
+
+            expect(err).to.exist();
+            done();
+        });
+    });
+
+    it('fails validation when missing a required parameter within an object config', function (done) {
+
+        var obj = {
+            a: {}
+        };
+
+        Joi.compile({ a: Joi.object({ b: Joi.string().required() }) }).validate(obj, function (err, value) {
+
+            expect(err).to.exist();
+            done();
+        });
+    });
+
+    it('fails validation when parameter is required to be an object but is given as string', function (done) {
+
+        var obj = {
+            a: 'a string'
+        };
+
+        Joi.compile({ a: Joi.object({ b: Joi.string().required() }) }).validate(obj, function (err, value) {
+
+            expect(err).to.exist();
+            done();
+        });
+    });
+
+    it('validates when parameter is required to be an object and is given correctly as a json string', function (done) {
+
+        var schema = {
+            a: Joi.object({
+                b: Joi.string().required()
+            })
+        };
+
+        var input = {
+            a: '{"b":"string"}'
+        };
+
+        Joi.validate(input, schema, function (err, value) {
+
+            expect(err).to.not.exist();
+            expect(input.a).to.equal('{"b":"string"}');
+            expect(value.a.b).to.equal('string');
+            done();
+        });
+    });
+
+    it('fails validation when parameter is required to be an object but is given as a json string that is incorrect (number instead of string)', function (done) {
+
+        var obj = {
+            a: '{"b":2}'
+        };
+
+        Joi.object({ a: Joi.object({ b: Joi.string().required() }) }).validate(obj, function (err, value) {
+
+            expect(err).to.exist();
+            done();
+        });
+    });
+
+    it('fails validation when parameter is required to be an Array but is given as string', function (done) {
+
+        var obj = {
+            a: 'an array'
+        };
+
+        Joi.object({ a: Joi.array() }).validate(obj, function (err, value) {
+
+            expect(err).to.exist();
+            done();
+        });
+    });
+
+    it('validates when parameter is required to be an Array and is given correctly as a json string', function (done) {
+
+        var obj = {
+            a: '[1,2]'
+        };
+
+        Joi.object({ a: Joi.array() }).validate(obj, function (err, value) {
+
+            expect(err).to.be.null();
+            done();
+        });
+    });
+
+    it('fails validation when parameter is required to be an Array but is given as a json that is incorrect (object instead of array)', function (done) {
+
+        var obj = {
+            a: '{"b":2}'
+        };
+
+        Joi.object({ a: Joi.object({ b: Joi.string().required() }) }).validate(obj, function (err, value) {
+
+            expect(err).to.exist();
+            done();
+        });
+    });
+
+    it('fails validation when config is an array and fails', function (done) {
+
+        var schema = {
+            d: [Joi.string(), Joi.boolean()],
+            e: [Joi.number(), Joi.object()]
+        };
+
+        var obj = {
+            d: 10,
+            e: 'a'
+        };
+
+        Joi.compile(schema).validate(obj, function (err, value) {
+
+            expect(err).to.exist();
+            done();
+        });
+    });
+
+    it('fails validation when config is an array and fails with extra keys', function (done) {
+
+        var schema = {
+            d: [Joi.string(), Joi.boolean()],
+            e: [Joi.number(), Joi.object()]
+        };
+
+        var obj = {
+            a: 10,
+            b: 'a'
+        };
+
+        Joi.compile(schema).validate(obj, function (err, value) {
+
+            expect(err).to.exist();
+            done();
+        });
+    });
+
+    it('fails validation with extra keys', function (done) {
+
+        var schema = {
+            a: Joi.number()
+        };
+
+        var obj = {
+            a: 1,
+            b: 'a'
+        };
+
+        Joi.compile(schema).validate(obj, function (err, value) {
+
+            expect(err).to.exist();
+            done();
+        });
+    });
+
+    it('validates missing optional key with string condition', function (done) {
+
+        var schema = {
+            key: Joi.string().alphanum(false).min(8)
+        };
+
+        Joi.compile(schema).validate({}, function (err, value) {
+
+            expect(err).to.not.exist();
+            done();
+        });
+    });
+
+    it('validates with extra keys and remove them when stripUnknown is set', function (done) {
+
+        var schema = {
+            a: Joi.number().min(0).max(3),
+            b: Joi.string().valid('a', 'b', 'c'),
+            c: Joi.string().email().optional()
+        };
+
+        var obj = {
+            a: 1,
+            b: 'a',
+            d: 'c'
+        };
+
+        Joi.validate(obj, schema, { stripUnknown: true, allowUnknown: true }, function (err, value) {
+
+            expect(err).to.be.null();
+            expect(value).to.deep.equal({ a: 1, b: 'a' });
+            done();
+        });
+    });
+
+    it('validates dependencies when stripUnknown is set', function (done) {
+
+        var schema = Joi.object({
+            a: Joi.number(),
+            b: Joi.string()
+        }).and('a', 'b');
+
+        var obj = {
+            a: 1,
+            foo: 'bar'
+        };
+
+        Joi.validate(obj, schema, { stripUnknown: true }, function (err, value) {
+
+            expect(err).to.exist();
+            expect(err.message).to.equal('"value" contains [a] without its required peers [b]');
+            done();
+        });
+    });
+
+    it('fails to validate with incorrect property when asked to strip unkown keys without aborting early', function (done) {
+
+        var schema = {
+            a: Joi.number().min(0).max(3),
+            b: Joi.string().valid('a', 'b', 'c'),
+            c: Joi.string().email().optional()
+        };
+
+        var obj = {
+            a: 1,
+            b: 'f',
+            d: 'c'
+        };
+
+        Joi.validate(obj, schema, { stripUnknown: true, abortEarly: false }, function (err, value) {
+
+            expect(err).to.exist();
+            done();
+        });
+    });
+
+    it('should pass validation with extra keys when allowUnknown is set', function (done) {
+
+        var schema = {
+            a: Joi.number().min(0).max(3),
+            b: Joi.string().valid('a', 'b', 'c'),
+            c: Joi.string().email().optional()
+        };
+
+        var obj = {
+            a: 1,
+            b: 'a',
+            d: 'c'
+        };
+
+        Joi.validate(obj, schema, { allowUnknown: true }, function (err, value) {
+
+            expect(err).to.be.null();
+            expect(value).to.deep.equal({ a: 1, b: 'a', d: 'c' });
+            done();
+        });
+    });
+
+    it('should pass validation with extra keys set', function (done) {
+
+        var localConfig = Joi.object({
+            a: Joi.number().min(0).max(3),
+            b: Joi.string().valid('a', 'b', 'c')
+        }).options({ allowUnknown: true });
+
+        var obj = {
+            a: 1,
+            b: 'a',
+            d: 'c'
+        };
+
+        localConfig.validate(obj, function (err, value) {
+
+            expect(err).to.be.null();
+            expect(value).to.deep.equal({ a: 1, b: 'a', d: 'c' });
+
+            localConfig.validate(value, function (err2, value2) {
+
+                expect(err2).to.be.null();
+                expect(value2).to.deep.equal({ a: 1, b: 'a', d: 'c' });
+                done();
+            });
+        });
+    });
+
+
+    it('should pass validation with extra keys and remove them when skipExtraKeys is set locally', function (done) {
+
+        var localConfig = Joi.object({
+            a: Joi.number().min(0).max(3),
+            b: Joi.string().valid('a', 'b', 'c')
+        }).options({ stripUnknown: true, allowUnknown: true });
+
+        var obj = {
+            a: 1,
+            b: 'a',
+            d: 'c'
+        };
+
+        localConfig.validate(obj, function (err, value) {
+
+            expect(err).to.be.null();
+            expect(value).to.deep.equal({ a: 1, b: 'a' });
+
+            localConfig.validate(value, function (err2, value2) {
+
+                expect(err2).to.be.null();
+                expect(value2).to.deep.equal({ a: 1, b: 'a' });
+                done();
+            });
+        });
+    });
+
+    it('should work when the skipFunctions setting is enabled', function (done) {
+
+        var schema = Joi.object({ username: Joi.string() }).options({ skipFunctions: true });
+        var input = { username: 'test', func: function () { } };
+        Joi.validate(input, schema, function (err, value) {
+
+            expect(err).to.not.exist();
+            done();
+        });
+    });
+
+    it('should work when the skipFunctions setting is disabled', function (done) {
+
+        var schema = { username: Joi.string() };
+        var input = { username: 'test', func: function () { } };
+
+        Joi.validate(input, schema, { skipFunctions: false }, function (err, value) {
+
+            expect(err).to.exist();
+            expect(err.message).to.contain('"func" is not allowed');
+            done();
+        });
+    });
+
+    it('should not convert values when convert is false', function (done) {
+
+        var schema = {
+            arr: Joi.array().items(Joi.string())
+        };
+
+        var input = { arr: 'foo' };
+        Joi.validate(input, schema, { convert: false }, function (err, value) {
+
+            expect(err).to.exist();
+            done();
+        });
+    });
+
+    it('full errors when abortEarly is false', function (done) {
+
+        var schema = {
+            a: Joi.string(),
+            b: Joi.string()
+        };
+
+        var input = { a: 1, b: 2 };
+
+        Joi.validate(input, schema, function (errOne, valueOne) {
+
+            Joi.validate(input, schema, { abortEarly: false }, function (errFull, valueFull) {
+
+                expect(errOne).to.exist();
+                expect(errFull).to.exist();
+                expect(errFull.details.length).to.be.greaterThan(errOne.details.length);
+                done();
+            });
+        });
+    });
+
+    it('errors multiple times when abortEarly is false in a complex object', function (done) {
+
+        var schema = Joi.object({
+            test: Joi.array().items(Joi.object().keys({
+                foo: Joi.string().required().max(3),
+                bar: Joi.string().max(5)
+            })),
+            test2: Joi.object({
+                test3: Joi.array().items(Joi.object().keys({
+                    foo: Joi.string().required().max(3),
+                    bar: Joi.string().max(5),
+                    baz: Joi.object({
+                        test4: Joi.array().items(Joi.object().keys({
+                            foo: Joi.string().required().max(3),
+                            bar: Joi.string().max(5)
+                        }))
+                    })
+                }))
+            })
+        });
+
+        var input = {
+            test: [{
+                foo: 'test1',
+                bar: 'testfailed'
+            }],
+            test2: {
+                test3: [{
+                    foo: '123'
+                }, {
+                    foo: 'test1',
+                    bar: 'testfailed'
+                }, {
+                    foo: '123',
+                    baz: {
+                        test4: [{
+                            foo: 'test1',
+                            baz: '123'
+                        }]
+                    }
+                }]
+            }
+        };
+
+        Joi.validate(input, schema, { abortEarly: false }, function (err, value) {
+
+            expect(err).to.exist();
+            expect(err.details).to.have.length(6);
+            expect(err.details).to.deep.equal([{
+                message: '"foo" length must be less than or equal to 3 characters long',
+                path: 'test.0.foo',
+                type: 'string.max',
+                context: { limit: 3, value: 'test1', key: 'foo', encoding: undefined }
+            }, {
+                message: '"bar" length must be less than or equal to 5 characters long',
+                path: 'test.0.bar',
+                type: 'string.max',
+                context: { limit: 5, value: 'testfailed', key: 'bar', encoding: undefined }
+            }, {
+                message: '"foo" length must be less than or equal to 3 characters long',
+                path: 'test2.test3.1.foo',
+                type: 'string.max',
+                context: { limit: 3, value: 'test1', key: 'foo', encoding: undefined }
+            }, {
+                message: '"bar" length must be less than or equal to 5 characters long',
+                path: 'test2.test3.1.bar',
+                type: 'string.max',
+                context: { limit: 5, value: 'testfailed', key: 'bar', encoding: undefined }
+            }, {
+                message: '"foo" length must be less than or equal to 3 characters long',
+                path: 'test2.test3.2.baz.test4.0.foo',
+                type: 'string.max',
+                context: { limit: 3, value: 'test1', key: 'foo', encoding: undefined }
+            }, {
+                message: '"baz" is not allowed',
+                path: 'test2.test3.2.baz.test4.0.baz',
+                type: 'object.allowUnknown',
+                context: { key: 'baz' }
+            }]);
+            done();
+        });
+    });
+
+    it('validates using the root any object', function (done) {
+
+        var any = Joi;
+        any.validate('abc', function (err, value) {
+
+            expect(err).to.not.exist();
+            done();
+        });
+    });
+
+    it('validates using the root any object (no callback)', function (done) {
+
+        var any = Joi;
+        var result = any.validate('abc');
+        expect(result.error).to.not.exist();
+        expect(result.value).to.equal('abc');
+        done();
+    });
+
+    it('accepts no options', function (done) {
+
+        Joi.validate('test', Joi.string(), function (err, value) {
+
+            expect(err).to.not.exist();
+            done();
+        });
+    });
+
+    it('accepts no options (no callback)', function (done) {
+
+        var result = Joi.validate('test', Joi.string());
+        expect(result.error).to.not.exist();
+        expect(result.value).to.equal('test');
+        done();
+    });
+
+    it('accepts options', function (done) {
+
+        Joi.validate('5', Joi.number(), { convert: false }, function (err, value) {
+
+            expect(err).to.exist();
+            done();
+        });
+    });
+
+    it('accepts options (no callback)', function (done) {
+
+        var result = Joi.validate('5', Joi.number(), { convert: false });
+        expect(result.error).to.exist();
+        done();
+    });
+
+    it('accepts null options', function (done) {
+
+        Joi.validate('test', Joi.string(), null, function (err, value) {
+
+            expect(err).to.not.exist();
+            done();
+        });
+    });
+
+    it('accepts undefined options', function (done) {
+
+        Joi.validate('test', Joi.string(), undefined, function (err, value) {
+
+            expect(err).to.not.exist();
+            done();
+        });
+    });
+
+    describe('#describe', function () {
+
+        var defaultFn = function () {
+
+            return 'test';
+        };
+        defaultFn.description = 'testing';
+
+        var defaultDescribedFn = function () {
+
+            return 'test';
+        };
+
+        var defaultRef = Joi.ref('xor');
+
+        var schema = Joi.object({
+            sub: {
+                email: Joi.string().email(),
+                date: Joi.date(),
+                child: Joi.object({
+                    alphanum: Joi.string().alphanum()
+                })
+            },
+            min: [Joi.number(), Joi.string().min(3)],
+            max: Joi.string().max(3),
+            required: Joi.string().required(),
+            xor: Joi.string(),
+            renamed: Joi.string().valid('456'),
+            notEmpty: Joi.string().required().description('a').notes('b').tags('c'),
+            empty: Joi.string().empty('').strip(),
+            defaultRef: Joi.string().default(defaultRef, 'not here'),
+            defaultFn: Joi.string().default(defaultFn, 'not here'),
+            defaultDescribedFn: Joi.string().default(defaultDescribedFn, 'described test')
+        }).rename('renamed', 'required').without('required', 'xor').without('xor', 'required');
+
+        var result = {
+            type: 'object',
+            children: {
+                sub: {
+                    type: 'object',
+                    children: {
+                        email: {
+                            type: 'string',
+                            invalids: [''],
+                            rules: [{ name: 'email' }]
+                        },
+                        date: {
+                            type: 'date'
+                        },
+                        child: {
+                            type: 'object',
+                            children: {
+                                alphanum: {
+                                    type: 'string',
+                                    invalids: [''],
+                                    rules: [{ name: 'alphanum' }]
+                                }
+                            }
+                        }
+                    }
+                },
+                min: {
+                    type: 'alternatives',
+                    alternatives: [
+                        {
+                            type: 'number',
+                            invalids: [Infinity, -Infinity]
+                        },
+                        {
+                            type: 'string',
+                            invalids: [''],
+                            rules: [{ name: 'min', arg: 3 }]
+                        }
+                    ]
+                },
+                max: {
+                    type: 'string',
+                    invalids: [''],
+                    rules: [{ name: 'max', arg: 3 }]
+                },
+                required: {
+                    type: 'string',
+                    flags: {
+                        presence: 'required'
+                    },
+                    invalids: ['']
+                },
+                xor: {
+                    type: 'string',
+                    invalids: ['']
+                },
+                renamed: {
+                    type: 'string',
+                    flags: {
+                        allowOnly: true
+                    },
+                    valids: ['456'],
+                    invalids: ['']
+                },
+                notEmpty: {
+                    type: 'string',
+                    flags: {
+                        presence: 'required'
+                    },
+                    description: 'a',
+                    notes: ['b'],
+                    tags: ['c'],
+                    invalids: ['']
+                },
+                empty: {
+                    type: 'string',
+                    flags: {
+                        empty: {
+                            type: 'string',
+                            flags: {
+                                allowOnly: true
+                            },
+                            valids: ['']
+                        },
+                        strip: true
+                    },
+                    invalids: ['']
+                },
+                defaultRef: {
+                    type: 'string',
+                    flags: {
+                        default: defaultRef
+                    },
+                    invalids: ['']
+                },
+                defaultFn: {
+                    type: 'string',
+                    flags: {
+                        default: defaultFn
+                    },
+                    invalids: ['']
+                },
+                defaultDescribedFn: {
+                    type: 'string',
+                    flags: {
+                        default: defaultDescribedFn
+                    },
+                    invalids: ['']
+                }
+            },
+            dependencies: [
+                {
+                    type: 'without',
+                    key: 'required',
+                    peers: ['xor']
+                },
+                {
+                    type: 'without',
+                    key: 'xor',
+                    peers: ['required']
+                }
+            ]
+        };
+
+        it('describes schema (direct)', function (done) {
+
+            var description = schema.describe();
+            expect(description).to.deep.equal(result);
+            expect(description.children.defaultRef.flags.default.description).to.not.exist();
+            expect(description.children.defaultFn.flags.default.description).to.equal('testing');
+            expect(description.children.defaultDescribedFn.flags.default.description).to.equal('described test');
+            done();
+        });
+
+        it('describes schema (root)', function (done) {
+
+            var description = Joi.describe(schema);
+            expect(description).to.deep.equal(result);
+            done();
+        });
+
+        it('describes schema (any)', function (done) {
+
+            var any = Joi;
+            var description = any.describe();
+            expect(description).to.deep.equal({
+                type: 'any'
+            });
+            done();
+        });
+
+        it('describes schema without invalids', function (done) {
+
+            var description = Joi.allow(null).describe();
+            expect(description.invalids).to.not.exist();
+            done();
+        });
+    });
+
+    describe('#assert', function () {
+
+        it('does not have a return value', function (done) {
+
+            var result;
+            expect(function () {
+
+                result = Joi.assert('4', Joi.number());
+            }).to.not.throw();
+            expect(result).to.not.exist();
+            done();
+        });
+    });
+
+    describe('#attempt', function () {
+
+        it('throws on invalid value', function (done) {
+
+            expect(function () {
+
+                Joi.attempt('x', Joi.number());
+            }).to.throw('"x"\n\u001b[31m\n[1] "value" must be a number\u001b[0m');
+            done();
+        });
+
+        it('does not throw on valid value', function (done) {
+
+            expect(function () {
+
+                Joi.attempt('4', Joi.number());
+            }).to.not.throw();
+            done();
+        });
+
+        it('returns validated structure', function (done) {
+
+            var valid;
+            expect(function () {
+
+                valid = Joi.attempt('4', Joi.number());
+            }).to.not.throw();
+            expect(valid).to.equal(4);
+            done();
+        });
+
+        it('throws on invalid value with message', function (done) {
+
+            expect(function () {
+
+                Joi.attempt('x', Joi.number(), 'the reason is');
+            }).to.throw('the reason is "x"\n\u001b[31m\n[1] "value" must be a number\u001b[0m');
+            done();
+        });
+
+        it('throws on invalid value with message as error', function (done) {
+
+            expect(function () {
+
+                Joi.attempt('x', Joi.number(), new Error('invalid value'));
+            }).to.throw('invalid value');
+            done();
+        });
+    });
+
+    describe('#compile', function () {
+
+        it('throws an error on invalid value', function (done) {
+
+            expect(function () {
+
+                Joi.compile(undefined);
+            }).to.throw(Error, 'Invalid schema content: ');
+            done();
+        });
+
+        it('shows path to errors in object', function (done) {
+
+            var schema = {
+                a: {
+                    b: {
+                        c: {
+                            d: undefined
+                        }
+                    }
+                }
+            };
+
+            expect(function () {
+
+                Joi.compile(schema);
+            }).to.throw(Error, 'Invalid schema content: (a.b.c.d)');
+            done();
+        });
+    });
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/number.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/number.js
new file mode 100755
index 0000000000000000000000000000000000000000..5660299225279929b5991208237255e35d3fb338
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/number.js
@@ -0,0 +1,834 @@
+// Load modules
+
+var Lab = require('lab');
+var Code = require('code');
+var Joi = require('../lib');
+var Helper = require('./helper');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var lab = exports.lab = Lab.script();
+var describe = lab.describe;
+var it = lab.it;
+var expect = Code.expect;
+
+
+describe('number', function () {
+
+    it('fails on boolean', function (done) {
+
+        var schema = Joi.number();
+        Helper.validate(schema, [
+            [true, false],
+            [false, false]
+        ], done);
+    });
+
+    describe('#validate', function () {
+
+        it('should, by default, allow undefined', function (done) {
+
+            Helper.validate(Joi.number(), [
+                [undefined, true]
+            ], done);
+        });
+
+        it('should, when .required(), deny undefined', function (done) {
+
+            Helper.validate(Joi.number().required(), [
+                [undefined, false]
+            ], done);
+        });
+
+        it('should return false for denied value', function (done) {
+
+            var text = Joi.number().invalid(50);
+            text.validate(50, function (err, value) {
+
+                expect(err).to.exist();
+                done();
+            });
+        });
+
+        it('should validate integer', function (done) {
+
+            var t = Joi.number().integer();
+            Helper.validate(t, [
+                [100, true],
+                [0, true],
+                [null, false],
+                [1.02, false],
+                [0.01, false]
+            ], done);
+        });
+
+        it('should return false for Infinity', function (done) {
+
+            var t = Joi.number();
+            Helper.validate(t, [
+                [Infinity, false],
+                [-Infinity, false]
+            ], done);
+        });
+
+        it('should return true for allowed Infinity', function (done) {
+
+            var t = Joi.number().allow(Infinity, -Infinity);
+            Helper.validate(t, [
+                [Infinity, true],
+                [-Infinity, true]
+            ], done);
+        });
+
+        it('can accept string numbers', function (done) {
+
+            var t = Joi.number();
+            Helper.validate(t, [
+                ['1', true],
+                ['100', true],
+                ['1e3', true],
+                ['1 some text', false],
+                ['\t\r', false],
+                [' ', false],
+                [' 2', true],
+                ['\t\r43', true],
+                ['43 ', true],
+                ['', false]
+            ], done);
+        });
+
+        it('required validates correctly', function (done) {
+
+            var t = Joi.number().required();
+            Helper.validate(t, [
+                [NaN, false],
+                ['100', true]
+            ], done);
+        });
+
+        it('converts an object string to a number', function (done) {
+
+            var config = { a: Joi.number() };
+            var obj = { a: '123' };
+
+            Joi.compile(config).validate(obj, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value.a).to.equal(123);
+                done();
+            });
+        });
+
+        it('converts a string to a number', function (done) {
+
+            Joi.number().validate('1', function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.equal(1);
+                done();
+            });
+        });
+
+        it('errors on null', function (done) {
+
+            Joi.number().validate(null, function (err, value) {
+
+                expect(err).to.exist();
+                expect(value).to.equal(null);
+                done();
+            });
+        });
+
+        it('should handle combination of min and max', function (done) {
+
+            var rule = Joi.number().min(8).max(10);
+            Helper.validate(rule, [
+                [1, false],
+                [11, false],
+                [8, true],
+                [9, true],
+                [null, false]
+            ], done);
+        });
+
+        it('should handle combination of min, max, and null allowed', function (done) {
+
+            var rule = Joi.number().min(8).max(10).allow(null);
+            Helper.validate(rule, [
+                [1, false],
+                [11, false],
+                [8, true],
+                [9, true],
+                [null, true]
+            ], done);
+        });
+
+        it('should handle combination of min and positive', function (done) {
+
+            var rule = Joi.number().min(-3).positive();
+            Helper.validate(rule, [
+                [1, true],
+                [-2, false],
+                [8, true],
+                [null, false]
+            ], done);
+        });
+
+        it('should handle combination of max and positive', function (done) {
+
+            var rule = Joi.number().max(5).positive();
+            Helper.validate(rule, [
+                [4, true],
+                [-2, false],
+                [8, false],
+                [null, false]
+            ], done);
+        });
+
+        it('should handle combination of min and negative', function (done) {
+
+            var rule = Joi.number().min(-3).negative();
+            Helper.validate(rule, [
+                [4, false],
+                [-2, true],
+                [-4, false],
+                [null, false]
+            ], done);
+        });
+
+        it('should handle combination of negative and positive', function (done) {
+
+            var rule = Joi.number().negative().positive();
+            Helper.validate(rule, [
+                [4, false],
+                [-2, false],
+                [0, false],
+                [null, false]
+            ], done);
+        });
+
+        it('should handle combination of negative and allow', function (done) {
+
+            var rule = Joi.number().negative().allow(1);
+            Helper.validate(rule, [
+                [1, true],
+                [-10, true],
+                [8, false],
+                [0, false],
+                [null, false]
+            ], done);
+        });
+
+        it('should handle combination of positive and allow', function (done) {
+
+            var rule = Joi.number().positive().allow(-1);
+            Helper.validate(rule, [
+                [1, true],
+                [-1, true],
+                [8, true],
+                [-10, false],
+                [null, false]
+            ], done);
+        });
+
+        it('should handle combination of positive, allow, and null allowed', function (done) {
+
+            var rule = Joi.number().positive().allow(-1).allow(null);
+            Helper.validate(rule, [
+                [1, true],
+                [-1, true],
+                [8, true],
+                [-10, false],
+                [null, true]
+            ], done);
+        });
+
+        it('should handle combination of negative, allow, and null allowed', function (done) {
+
+            var rule = Joi.number().negative().allow(1).allow(null);
+            Helper.validate(rule, [
+                [1, true],
+                [-10, true],
+                [8, false],
+                [0, false],
+                [null, true]
+            ], done);
+        });
+
+        it('should handle combination of positive, allow, null allowed, and invalid', function (done) {
+
+            var rule = Joi.number().positive().allow(-1).allow(null).invalid(1);
+            Helper.validate(rule, [
+                [1, false],
+                [-1, true],
+                [8, true],
+                [-10, false],
+                [null, true]
+            ], done);
+        });
+
+        it('should handle combination of negative, allow, null allowed, and invalid', function (done) {
+
+            var rule = Joi.number().negative().allow(1).allow(null).invalid(-5);
+            Helper.validate(rule, [
+                [1, true],
+                [-10, true],
+                [-5, false],
+                [8, false],
+                [0, false],
+                [null, true]
+            ], done);
+        });
+
+        it('should handle combination of min, max, and allow', function (done) {
+
+            var rule = Joi.number().min(8).max(10).allow(1);
+            Helper.validate(rule, [
+                [1, true],
+                [11, false],
+                [8, true],
+                [9, true],
+                [null, false]
+            ], done);
+        });
+
+        it('should handle combination of min, max, allow, and null allowed', function (done) {
+
+            var rule = Joi.number().min(8).max(10).allow(1).allow(null);
+            Helper.validate(rule, [
+                [1, true],
+                [11, false],
+                [8, true],
+                [9, true],
+                [null, true]
+            ], done);
+        });
+
+        it('should handle combination of min, max, allow, and invalid', function (done) {
+
+            var rule = Joi.number().min(8).max(10).allow(1).invalid(9);
+            Helper.validate(rule, [
+                [1, true],
+                [11, false],
+                [8, true],
+                [9, false],
+                [null, false]
+            ], done);
+        });
+
+        it('should handle combination of min, max, allow, invalid, and null allowed', function (done) {
+
+            var rule = Joi.number().min(8).max(10).allow(1).invalid(9).allow(null);
+            Helper.validate(rule, [
+                [1, true],
+                [11, false],
+                [8, true],
+                [9, false],
+                [null, true]
+            ], done);
+        });
+
+        it('should handle combination of min, max, and integer', function (done) {
+
+            var rule = Joi.number().min(8).max(10).integer();
+            Helper.validate(rule, [
+                [1, false],
+                [11, false],
+                [8, true],
+                [9, true],
+                [9.1, false],
+                [null, false]
+            ], done);
+        });
+
+        it('should handle combination of min, max, integer, and allow', function (done) {
+
+            var rule = Joi.number().min(8).max(10).integer().allow(9.1);
+            Helper.validate(rule, [
+                [1, false],
+                [11, false],
+                [8, true],
+                [9, true],
+                [9.1, true],
+                [9.2, false],
+                [null, false]
+            ], done);
+        });
+
+        it('should handle combination of min, max, integer, allow, and invalid', function (done) {
+
+            var rule = Joi.number().min(8).max(10).integer().allow(9.1).invalid(8);
+            Helper.validate(rule, [
+                [1, false],
+                [11, false],
+                [8, false],
+                [9, true],
+                [9.1, true],
+                [9.2, false],
+                [null, false]
+            ], done);
+        });
+
+        it('should handle combination of min, max, integer, allow, invalid, and null allowed', function (done) {
+
+            var rule = Joi.number().min(8).max(10).integer().allow(9.1).invalid(8).allow(null);
+            Helper.validate(rule, [
+                [1, false],
+                [11, false],
+                [8, false],
+                [9, true],
+                [9.1, true],
+                [9.2, false],
+                [null, true]
+            ], done);
+        });
+
+        it('should handle limiting the number of decimal places', function (done) {
+
+            var rule = Joi.number().precision(1).options({ convert: false });
+            Helper.validate(rule, [
+                [1, true],
+                [9.1, true],
+                [9.21, false],
+                [9.9999, false],
+                [9.999e99, true],
+                [9.9e-99, false],
+                [9.9e3, true],
+                [null, false]
+            ], done);
+        });
+
+        it('should handle combination of min, max, integer, allow, invalid, null allowed and precision', function (done) {
+
+            var rule = Joi.number().min(8).max(10).integer().allow(9.1).invalid(8).allow(null).precision(1).options({ convert: false });
+            Helper.validate(rule, [
+                [1, false],
+                [11, false],
+                [8, false],
+                [9, true],
+                [9.1, true],
+                [9.11, false],
+                [9.2, false],
+                [9.22, false],
+                [null, true]
+            ], done);
+        });
+
+        it('should handle combination of greater and less', function (done) {
+
+            var rule = Joi.number().greater(5).less(10);
+            Helper.validate(rule, [
+                [0, false],
+                [11, false],
+                [5, false],
+                [10, false],
+                [8, true],
+                [5.01, true],
+                [9.99, true],
+                [null, false]
+            ], done);
+        });
+
+        it('should handle combination of greater, less, and integer', function (done) {
+
+            var rule = Joi.number().integer().greater(5).less(10);
+            Helper.validate(rule, [
+                [0, false],
+                [11, false],
+                [5, false],
+                [10, false],
+                [6, true],
+                [9, true],
+                [5.01, false],
+                [9.99, false]
+            ], done);
+        });
+
+        it('should handle combination of greater, less, and null allowed', function (done) {
+
+            var rule = Joi.number().greater(5).less(10).allow(null);
+            Helper.validate(rule, [
+                [0, false],
+                [11, false],
+                [5, false],
+                [10, false],
+                [8, true],
+                [5.01, true],
+                [9.99, true],
+                [null, true]
+            ], done);
+        });
+
+        it('should handle combination of greater, less, invalid, and allow', function (done) {
+
+            var rule = Joi.number().greater(5).less(10).invalid(6).allow(-3);
+            Helper.validate(rule, [
+                [0, false],
+                [11, false],
+                [5, false],
+                [10, false],
+                [6, false],
+                [8, true],
+                [5.01, true],
+                [9.99, true],
+                [-3, true],
+                [null, false]
+            ], done);
+        });
+    });
+
+    it('should instantiate separate copies on invocation', function (done) {
+
+        var result1 = Joi.number().min(5);
+        var result2 = Joi.number().max(5);
+
+        expect(Object.keys(result1)).to.not.equal(Object.keys(result2));
+        done();
+    });
+
+    it('should show resulting object with #valueOf', function (done) {
+
+        var result = Joi.number().min(5);
+        expect(result.valueOf()).to.exist();
+        done();
+    });
+
+    describe('error message', function () {
+
+        it('should display correctly for int type', function (done) {
+
+            var t = Joi.number().integer();
+            Joi.compile(t).validate('1.1', function (err, value) {
+
+                expect(err.message).to.contain('integer');
+                done();
+            });
+        });
+    });
+
+    describe('#min', function () {
+
+        it('throws when limit is not a number', function (done) {
+
+            expect(function () {
+
+                Joi.number().min('a');
+            }).to.throw('limit must be a number or reference');
+            done();
+        });
+
+        it('supports 64bit numbers', function (done) {
+
+            var schema = Joi.number().min(1394035612500);
+            var input = 1394035612552;
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.equal(input);
+                done();
+            });
+        });
+
+        it('accepts references as min value', function (done) {
+
+            var schema = Joi.object({ a: Joi.number(), b: Joi.number().min(Joi.ref('a')) });
+
+            Helper.validate(schema, [
+                [{ a: 42, b: 1337 }, true],
+                [{ a: 1337, b: 42 }, false],
+                [{ a: '1337', b: 42 }, false, null, 'child "b" fails because ["b" must be larger than or equal to 1337]'],
+                [{ a: 2.4, b: 4.2 }, true],
+                [{ a: 4.2, b: 4.20000001 }, true],
+                [{ a: 4.20000001, b: 4.2 }, false],
+                [{ a: 4.2, b: 2.4 }, false, null, 'child "b" fails because ["b" must be larger than or equal to 4.2]']
+            ], done);
+        });
+
+        it('accepts context references as min value', function (done) {
+
+            var schema = Joi.object({ b: Joi.number().min(Joi.ref('$a')) });
+
+            Helper.validate(schema, [
+                [{ b: 1337 }, true, { context: { a: 42 } }],
+                [{ b: 42 }, false, { context: { a: 1337 } }],
+                [{ b: 4.2 }, true, { context: { a: 2.4 } }],
+                [{ b: 4.20000001 }, true, { context: { a: 4.2 } }],
+                [{ b: 4.2 }, false, { context: { a: 4.20000001 } }],
+                [{ b: 2.4 }, false, { context: { a: 4.2 } }, 'child "b" fails because ["b" must be larger than or equal to 4.2]']
+            ], done);
+        });
+
+        it('errors if reference is not a number', function (done) {
+
+            var schema = Joi.object({ a: Joi.string(), b: Joi.number().min(Joi.ref('a')) });
+
+            Helper.validate(schema, [
+                [{ a: 'abc', b: 42 }, false, null, 'child "b" fails because ["b" references "a" which is not a number]']
+            ], done);
+        });
+
+        it('errors if context reference is not a number', function (done) {
+
+            var schema = Joi.object({ b: Joi.number().min(Joi.ref('$a')) });
+
+            Helper.validate(schema, [
+                [{ b: 42 }, false, { context: { a: 'abc' } }, 'child "b" fails because ["b" references "a" which is not a number]']
+            ], done);
+        });
+    });
+
+    describe('#max', function () {
+
+        it('throws when limit is not a number', function (done) {
+
+            expect(function () {
+
+                Joi.number().max('a');
+            }).to.throw('limit must be a number or reference');
+            done();
+        });
+
+        it('accepts references as max value', function (done) {
+
+            var schema = Joi.object({ a: Joi.number(), b: Joi.number().max(Joi.ref('a')) });
+
+            Helper.validate(schema, [
+                [{ a: 1337, b: 42 }, true],
+                [{ a: 42, b: 1337 }, false],
+                [{ a: '42', b: 1337 }, false, null, 'child "b" fails because ["b" must be less than or equal to 42]'],
+                [{ a: 4.2, b: 2.4 }, true],
+                [{ a: 4.2, b: 4.20000001 }, false],
+                [{ a: 4.20000001, b: 4.2 }, true],
+                [{ a: 2.4, b: 4.2 }, false, null, 'child "b" fails because ["b" must be less than or equal to 2.4]']
+            ], done);
+        });
+
+        it('accepts context references as max value', function (done) {
+
+            var schema = Joi.object({ b: Joi.number().max(Joi.ref('$a')) });
+
+            Helper.validate(schema, [
+                [{ b: 42 }, true, { context: { a: 1337 } }],
+                [{ b: 1337 }, false, { context: { a: 42 } }],
+                [{ b: 2.4 }, true, { context: { a: 4.2 } }],
+                [{ b: 4.20000001 }, false, { context: { a: 4.2 } }],
+                [{ b: 4.2 }, true, { context: { a: 4.20000001 } }],
+                [{ b: 4.2 }, false, { context: { a: 2.4 } }, 'child "b" fails because ["b" must be less than or equal to 2.4]']
+            ], done);
+        });
+
+        it('errors if reference is not a number', function (done) {
+
+            var schema = Joi.object({ a: Joi.string(), b: Joi.number().max(Joi.ref('a')) });
+
+            Helper.validate(schema, [
+                [{ a: 'abc', b: 42 }, false, null, 'child "b" fails because ["b" references "a" which is not a number]']
+            ], done);
+        });
+
+        it('errors if context reference is not a number', function (done) {
+
+            var schema = Joi.object({ b: Joi.number().max(Joi.ref('$a')) });
+
+            Helper.validate(schema, [
+                [{ b: 42 }, false, { context: { a: 'abc' } }, 'child "b" fails because ["b" references "a" which is not a number]']
+            ], done);
+        });
+    });
+
+    describe('#less', function () {
+
+        it('throws when limit is not a number', function (done) {
+
+            expect(function () {
+
+                Joi.number().less('a');
+            }).to.throw('limit must be a number or reference');
+            done();
+        });
+
+        it('accepts references as less value', function (done) {
+
+            var schema = Joi.object({ a: Joi.number(), b: Joi.number().less(Joi.ref('a')) });
+
+            Helper.validate(schema, [
+                [{ a: 1337, b: 42 }, true],
+                [{ a: 42, b: 1337 }, false],
+                [{ a: '42', b: 1337 }, false, null, 'child "b" fails because ["b" must be less than 42]'],
+                [{ a: 4.2, b: 2.4 }, true],
+                [{ a: 4.2, b: 4.20000001 }, false],
+                [{ a: 4.20000001, b: 4.2 }, true],
+                [{ a: 2.4, b: 4.2 }, false, null, 'child "b" fails because ["b" must be less than 2.4]']
+            ], done);
+        });
+
+        it('accepts context references as less value', function (done) {
+
+            var schema = Joi.object({ b: Joi.number().less(Joi.ref('$a')) });
+
+            Helper.validate(schema, [
+                [{ b: 42 }, true, { context: { a: 1337 } }],
+                [{ b: 1337 }, false, { context: { a: 42 } }],
+                [{ b: 2.4 }, true, { context: { a: 4.2 } }],
+                [{ b: 4.20000001 }, false, { context: { a: 4.2 } }],
+                [{ b: 4.2 }, true, { context: { a: 4.20000001 } }],
+                [{ b: 4.2 }, false, { context: { a: 2.4 } }, 'child "b" fails because ["b" must be less than 2.4]']
+            ], done);
+        });
+
+        it('errors if reference is not a number', function (done) {
+
+            var schema = Joi.object({ a: Joi.string(), b: Joi.number().less(Joi.ref('a')) });
+
+            Helper.validate(schema, [
+                [{ a: 'abc', b: 42 }, false, null, 'child "b" fails because ["b" references "a" which is not a number]']
+            ], done);
+        });
+
+        it('errors if context reference is not a number', function (done) {
+
+            var schema = Joi.object({ a: Joi.string(), b: Joi.number().less(Joi.ref('$a')) });
+
+            Helper.validate(schema, [
+                [{ b: 42 }, false, { context: { a: 'abc' } }, 'child "b" fails because ["b" references "a" which is not a number]']
+            ], done);
+        });
+    });
+
+    describe('#greater', function () {
+
+        it('throws when limit is not a number', function (done) {
+
+            expect(function () {
+
+                Joi.number().greater('a');
+            }).to.throw('limit must be a number or reference');
+            done();
+        });
+
+        it('accepts references as greater value', function (done) {
+
+            var schema = Joi.object({ a: Joi.number(), b: Joi.number().greater(Joi.ref('a')) });
+
+            Helper.validate(schema, [
+                [{ a: 42, b: 1337 }, true],
+                [{ a: 1337, b: 42 }, false],
+                [{ a: '1337', b: 42 }, false, null, 'child "b" fails because ["b" must be greater than 1337]'],
+                [{ a: 2.4, b: 4.2 }, true],
+                [{ a: 4.2, b: 4.20000001 }, true],
+                [{ a: 4.20000001, b: 4.2 }, false],
+                [{ a: 4.2, b: 2.4 }, false, null, 'child "b" fails because ["b" must be greater than 4.2]']
+            ], done);
+        });
+
+        it('accepts context references as greater value', function (done) {
+
+            var schema = Joi.object({ b: Joi.number().greater(Joi.ref('$a')) });
+
+            Helper.validate(schema, [
+                [{ b: 1337 }, true, { context: { a: 42 } }],
+                [{ b: 42 }, false, { context: { a: 1337 } }],
+                [{ b: 4.2 }, true, { context: { a: 2.4 } }],
+                [{ b: 4.20000001 }, true, { context: { a: 4.2 } }],
+                [{ b: 4.2 }, false, { context: { a: 4.20000001 } }],
+                [{ b: 2.4 }, false, { context: { a: 4.2 } }, 'child "b" fails because ["b" must be greater than 4.2]']
+            ], done);
+        });
+
+        it('errors if reference is not a number', function (done) {
+
+            var schema = Joi.object({ a: Joi.string(), b: Joi.number().greater(Joi.ref('a')) });
+
+            Helper.validate(schema, [
+                [{ a: 'abc', b: 42 }, false, null, 'child "b" fails because ["b" references "a" which is not a number]']
+            ], done);
+        });
+
+        it('errors if context reference is not a number', function (done) {
+
+            var schema = Joi.object({ b: Joi.number().greater(Joi.ref('$a')) });
+
+            Helper.validate(schema, [
+                [{ b: 42 }, false, { context: { a: 'abc' } }, 'child "b" fails because ["b" references "a" which is not a number]']
+            ], done);
+        });
+    });
+
+    describe('#precision', function () {
+
+        it('converts numbers', function (done) {
+
+            var rule = Joi.number().precision(4);
+            Helper.validate(rule, [
+                [1.5, true, null, 1.5],
+                [0.12345, true, null, 0.1235],
+                [123456, true, null, 123456],
+                [123456.123456, true, null, 123456.1235],
+                ['123456.123456', true, null, 123456.1235],
+                ['abc', false],
+                [NaN, false]
+            ], done);
+        });
+    });
+
+    describe('#describe', function () {
+
+        it('should describe a minimum of 0', function (done) {
+
+            var schema = Joi.number().min(0);
+            expect(schema.describe()).to.deep.equal({
+                type: 'number',
+                invalids: [Infinity, -Infinity],
+                rules: [
+                    {
+                        name: 'min',
+                        arg: 0
+                    }
+                ]
+            });
+            done();
+        });
+    });
+
+    describe('#multiple', function () {
+
+        it('throws when multiple is not a number', function (done) {
+
+            expect(function () {
+
+                Joi.number().multiple('a');
+            }).to.throw('multiple must be an integer');
+            done();
+        });
+
+        it('throws when multiple is 0', function (done) {
+
+            expect(function () {
+
+                Joi.number().multiple(0);
+            }).to.throw('multiple must be greater than 0');
+            done();
+        });
+
+        it('should handle multiples correctly', function (done) {
+
+            var rule = Joi.number().multiple(3);
+            Helper.validate(rule, [
+                [0, true], // 0 is a multiple of every integer
+                [3, true],
+                [4, false],
+                [9, true],
+                ['a', false],
+                [9.1, false],
+                [8.9, false]
+            ], done);
+        });
+    });
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/object.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/object.js
new file mode 100644
index 0000000000000000000000000000000000000000..3aca1cc08a65f23852924d493f61f298174b556e
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/object.js
@@ -0,0 +1,1309 @@
+// Load modules
+
+var Lab = require('lab');
+var Code = require('code');
+var Joi = require('../lib');
+var Helper = require('./helper');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var lab = exports.lab = Lab.script();
+var describe = lab.describe;
+var it = lab.it;
+var expect = Code.expect;
+
+
+describe('object', function () {
+
+    it('converts a json string to an object', function (done) {
+
+        Joi.object().validate('{"hi":true}', function (err, value) {
+
+            expect(err).to.not.exist();
+            expect(value.hi).to.equal(true);
+            done();
+        });
+    });
+
+    it('errors on non-object string', function (done) {
+
+        Joi.object().validate('a string', function (err, value) {
+
+            expect(err).to.exist();
+            expect(value).to.equal('a string');
+            done();
+        });
+    });
+
+    it('validates an object', function (done) {
+
+        var schema = Joi.object().required();
+        Helper.validate(schema, [
+            [{}, true],
+            [{ hi: true }, true],
+            ['', false]
+        ], done);
+    });
+
+    it('return object reference when no rules specified', function (done) {
+
+        var schema = Joi.object({
+            a: Joi.object()
+        });
+
+        var item = { x: 5 };
+        schema.validate({ a: item }, function (err, value) {
+
+            expect(value.a).to.equal(item);
+            done();
+        });
+    });
+
+    it('retains ignored values', function (done) {
+
+        var schema = Joi.object();
+        schema.validate({ a: 5 }, function (err, value) {
+
+            expect(value.a).to.equal(5);
+            done();
+        });
+    });
+
+    it('retains skipped values', function (done) {
+
+        var schema = Joi.object({ b: 5 }).unknown(true);
+        schema.validate({ b: '5', a: 5 }, function (err, value) {
+
+            expect(value.a).to.equal(5);
+            expect(value.b).to.equal(5);
+            done();
+        });
+    });
+
+    it('allows any key when schema is undefined', function (done) {
+
+        Joi.object().validate({ a: 4 }, function (err, value) {
+
+            expect(err).to.not.exist();
+
+            Joi.object(undefined).validate({ a: 4 }, function (err2, value2) {
+
+                expect(err2).to.not.exist();
+                done();
+            });
+        });
+    });
+
+    it('allows any key when schema is null', function (done) {
+
+        Joi.object(null).validate({ a: 4 }, function (err, value) {
+
+            expect(err).to.not.exist();
+            done();
+        });
+    });
+
+    it('throws on invalid object schema', function (done) {
+
+        expect(function () {
+
+            Joi.object(4);
+        }).to.throw('Object schema must be a valid object');
+        done();
+    });
+
+    it('throws on joi object schema', function (done) {
+
+        expect(function () {
+
+            Joi.object(Joi.object());
+        }).to.throw('Object schema cannot be a joi schema');
+        done();
+    });
+
+    it('skips conversion when value is undefined', function (done) {
+
+        Joi.object({ a: Joi.object() }).validate(undefined, function (err, value) {
+
+            expect(err).to.not.exist();
+            expect(value).to.not.exist();
+            done();
+        });
+    });
+
+    it('errors on array', function (done) {
+
+        Joi.object().validate([1, 2, 3], function (err, value) {
+
+            expect(err).to.exist();
+            done();
+        });
+    });
+
+    it('should prevent extra keys from existing by default', function (done) {
+
+        var schema = Joi.object({ item: Joi.string().required() }).required();
+        Helper.validate(schema, [
+            [{ item: 'something' }, true],
+            [{ item: 'something', item2: 'something else' }, false],
+            ['', false]
+        ], done);
+    });
+
+    it('should validate count when min is set', function (done) {
+
+        var schema = Joi.object().min(3);
+        Helper.validate(schema, [
+            [{ item: 'something' }, false],
+            [{ item: 'something', item2: 'something else' }, false],
+            [{ item: 'something', item2: 'something else', item3: 'something something else' }, true],
+            ['', false]
+        ], done);
+    });
+
+    it('should validate count when max is set', function (done) {
+
+        var schema = Joi.object().max(2);
+        Helper.validate(schema, [
+            [{ item: 'something' }, true],
+            [{ item: 'something', item2: 'something else' }, true],
+            [{ item: 'something', item2: 'something else', item3: 'something something else' }, false],
+            ['', false]
+        ], done);
+    });
+
+    it('should validate count when min and max is set', function (done) {
+
+        var schema = Joi.object().max(3).min(2);
+        Helper.validate(schema, [
+            [{ item: 'something' }, false],
+            [{ item: 'something', item2: 'something else' }, true],
+            [{ item: 'something', item2: 'something else', item3: 'something something else' }, true],
+            [{ item: 'something', item2: 'something else', item3: 'something something else', item4: 'item4' }, false],
+            ['', false]
+        ], done);
+    });
+
+    it('should validate count when length is set', function (done) {
+
+        var schema = Joi.object().length(2);
+        Helper.validate(schema, [
+            [{ item: 'something' }, false],
+            [{ item: 'something', item2: 'something else' }, true],
+            [{ item: 'something', item2: 'something else', item3: 'something something else' }, false],
+            ['', false]
+        ], done);
+    });
+
+    it('should validate constructor when type is set', function (done) {
+
+        var schema = Joi.object().type(RegExp);
+        Helper.validate(schema, [
+            [{ item: 'something' }, false],
+            ['', false],
+            [new Date(), false],
+            [/abcd/, true],
+            [new RegExp(), true]
+        ], done);
+    });
+
+    it('should traverse an object and validate all properties in the top level', function (done) {
+
+        var schema = Joi.object({
+            num: Joi.number()
+        });
+
+        Helper.validate(schema, [
+            [{ num: 1 }, true],
+            [{ num: [1, 2, 3] }, false]
+        ], done);
+    });
+
+    it('should traverse an object and child objects and validate all properties', function (done) {
+
+        var schema = Joi.object({
+            num: Joi.number(),
+            obj: Joi.object({
+                item: Joi.string()
+            })
+        });
+
+        Helper.validate(schema, [
+            [{ num: 1 }, true],
+            [{ num: [1, 2, 3] }, false],
+            [{ num: 1, obj: { item: 'something' } }, true],
+            [{ num: 1, obj: { item: 123 } }, false]
+        ], done);
+    });
+
+    it('should traverse an object several levels', function (done) {
+
+        var schema = Joi.object({
+            obj: Joi.object({
+                obj: Joi.object({
+                    obj: Joi.object({
+                        item: Joi.boolean()
+                    })
+                })
+            })
+        });
+
+        Helper.validate(schema, [
+            [{ num: 1 }, false],
+            [{ obj: {} }, true],
+            [{ obj: { obj: {} } }, true],
+            [{ obj: { obj: { obj: {} } } }, true],
+            [{ obj: { obj: { obj: { item: true } } } }, true],
+            [{ obj: { obj: { obj: { item: 10 } } } }, false]
+        ], done);
+    });
+
+    it('should traverse an object several levels with required levels', function (done) {
+
+        var schema = Joi.object({
+            obj: Joi.object({
+                obj: Joi.object({
+                    obj: Joi.object({
+                        item: Joi.boolean()
+                    })
+                }).required()
+            })
+        });
+
+        Helper.validate(schema, [
+            [null, false],
+            [undefined, true],
+            [{}, true],
+            [{ obj: {} }, false],
+            [{ obj: { obj: {} } }, true],
+            [{ obj: { obj: { obj: {} } } }, true],
+            [{ obj: { obj: { obj: { item: true } } } }, true],
+            [{ obj: { obj: { obj: { item: 10 } } } }, false]
+        ], done);
+    });
+
+    it('should traverse an object several levels with required levels (without Joi.obj())', function (done) {
+
+        var schema = {
+            obj: {
+                obj: {
+                    obj: {
+                        item: Joi.boolean().required()
+                    }
+                }
+            }
+        };
+
+        Helper.validate(schema, [
+            [null, false],
+            [undefined, true],
+            [{}, true],
+            [{ obj: {} }, true],
+            [{ obj: { obj: {} } }, true],
+            [{ obj: { obj: { obj: {} } } }, false],
+            [{ obj: { obj: { obj: { item: true } } } }, true],
+            [{ obj: { obj: { obj: { item: 10 } } } }, false]
+        ], done);
+    });
+
+    it('errors on unknown keys when functions allows', function (done) {
+
+        var schema = Joi.object({ a: Joi.number() }).options({ skipFunctions: true });
+        var obj = { a: 5, b: 'value' };
+        schema.validate(obj, function (err, value) {
+
+            expect(err).to.exist();
+            done();
+        });
+    });
+
+    it('validates both valid() and with()', function (done) {
+
+        var schema = Joi.object({
+            first: Joi.valid('value'),
+            second: Joi.any()
+        }).with('first', 'second');
+
+        Helper.validate(schema, [
+            [{ first: 'value' }, false]
+        ], done);
+    });
+
+    it('validates referenced arrays in valid()', function (done) {
+
+        var schema = Joi.object({
+            foo: Joi.valid(Joi.ref('$x'))
+        });
+
+        Helper.validate(schema, [
+            [{ foo: 'bar' }, true, { context: { x: 'bar' } }],
+            [{ foo: 'bar' }, true, { context: { x: ['baz', 'bar'] } }],
+            [{ foo: 'bar' }, false, { context: { x: 'baz' } }],
+            [{ foo: 'bar' }, false, { context: { x: ['baz', 'qux'] } }],
+            [{ foo: 'bar' }, false]
+        ], done);
+    });
+
+    it('errors on unknown nested keys with the correct path', function (done) {
+
+        var schema = Joi.object({ a: Joi.object().keys({}) });
+        var obj = { a: { b: 'value' } };
+        schema.validate(obj, function (err, value) {
+
+            expect(err).to.exist();
+            expect(err.details[0].path).to.equal('a.b');
+            done();
+        });
+    });
+
+    it('errors on unknown nested keys with the correct path at the root level', function (done) {
+
+        var schema = Joi.object({ a: Joi.object().keys({}) });
+        var obj = { c: 'hello' };
+        schema.validate(obj, function (err, value) {
+
+            expect(err).to.exist();
+            expect(err.details[0].path).to.equal('c');
+            done();
+        });
+    });
+
+    it('should work on prototype-less objects', function (done) {
+
+        var input = Object.create(null);
+        var schema = Joi.object().keys({
+            a: Joi.number()
+        });
+
+        input.a = 1337;
+
+        Joi.validate(input, schema, function (err) {
+
+            expect(err).to.not.exist();
+            done();
+        });
+    });
+
+    it('should be able to use rename safely with a fake hasOwnProperty', function (done) {
+
+        var input = { a: 1, hasOwnProperty: 'foo' };
+        var schema = Joi.object().rename('b', 'a');
+
+        Joi.validate(input, schema, function (err) {
+
+            expect(err.message).to.equal('"value" cannot rename child "b" because override is disabled and target "a" exists');
+            done();
+        });
+    });
+
+    it('should be able to use object.with() safely with a fake hasOwnProperty', function (done) {
+
+        var input = { a: 1, hasOwnProperty: 'foo' };
+        var schema = Joi.object({ a: 1 }).with('a', 'b');
+
+        Joi.validate(input, schema, function (err) {
+
+            expect(err.message).to.equal('"hasOwnProperty" is not allowed. "a" missing required peer "b"');
+            done();
+        });
+    });
+
+    describe('#keys', function () {
+
+        it('allows any key', function (done) {
+
+            var a = Joi.object({ a: 4 });
+            var b = a.keys();
+            a.validate({ b: 3 }, function (err, value) {
+
+                expect(err).to.exist();
+                b.validate({ b: 3 }, function (err2, value2) {
+
+                    expect(err2).to.not.exist();
+                    done();
+                });
+            });
+        });
+
+        it('forbids all keys', function (done) {
+
+            var a = Joi.object();
+            var b = a.keys({});
+            a.validate({ b: 3 }, function (err, value) {
+
+                expect(err).to.not.exist();
+                b.validate({ b: 3 }, function (err2, value2) {
+
+                    expect(err2).to.exist();
+                    done();
+                });
+            });
+        });
+
+        it('adds to existing keys', function (done) {
+
+            var a = Joi.object({ a: 1 });
+            var b = a.keys({ b: 2 });
+            a.validate({ a: 1, b: 2 }, function (err, value) {
+
+                expect(err).to.exist();
+                b.validate({ a: 1, b: 2 }, function (err2, value2) {
+
+                    expect(err2).to.not.exist();
+                    done();
+                });
+            });
+        });
+
+        it('overrides existing keys', function (done) {
+
+            var a = Joi.object({ a: 1 });
+            var b = a.keys({ a: Joi.string() });
+
+            Helper.validate(a, [
+                [{ a: 1 }, true, null, { a: 1 }],
+                [{ a: '1' }, true, null, { a: 1 }],
+                [{ a: '2' }, false, null, 'child "a" fails because ["a" must be one of [1]]']
+            ], function () {
+
+                Helper.validate(b, [
+                    [{ a: 1 }, false, null, 'child "a" fails because ["a" must be a string]'],
+                    [{ a: '1' }, true, null, { a: '1' }]
+                ], done);
+            });
+        });
+
+        it('strips keys flagged with strip', function (done) {
+
+            var schema = Joi.object({
+                a: Joi.string().strip(),
+                b: Joi.string()
+            });
+            schema.validate({ a: 'test', b: 'test' }, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value.a).to.not.exist();
+                expect(value.b).to.equal('test');
+                done();
+            });
+        });
+
+        it('does not alter the original object when stripping keys', function (done) {
+
+            var schema = Joi.object({
+                a: Joi.string().strip(),
+                b: Joi.string()
+            });
+
+            var valid = {
+                a: 'test',
+                b: 'test'
+            };
+
+            schema.validate(valid, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value.a).to.not.exist();
+                expect(valid.a).to.equal('test');
+                expect(value.b).to.equal('test');
+                expect(valid.b).to.equal('test');
+                done();
+            });
+        });
+
+        it('should strip from an alternative', function (done) {
+
+            var schema = Joi.object({
+                a: [Joi.boolean().strip()]
+            });
+
+            var valid = {
+                a: true
+            };
+
+            schema.validate(valid, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.deep.equal({});
+                done();
+            });
+        });
+    });
+
+    describe('#unknown', function () {
+
+        it('allows local unknown without applying to children', function (done) {
+
+            var schema = Joi.object({
+                a: {
+                    b: Joi.number()
+                }
+            }).unknown();
+
+            Helper.validate(schema, [
+                [{ a: { b: 5 } }, true],
+                [{ a: { b: 'x' } }, false],
+                [{ a: { b: 5 }, c: 'ignore' }, true],
+                [{ a: { b: 5, c: 'ignore' } }, false]
+            ], done);
+        });
+
+        it('forbids local unknown without applying to children', function (done) {
+
+            var schema = Joi.object({
+                a: Joi.object({
+                    b: Joi.number()
+                }).unknown()
+            }).options({ allowUnknown: false });
+
+            Helper.validate(schema, [
+                [{ a: { b: 5 } }, true],
+                [{ a: { b: 'x' } }, false],
+                [{ a: { b: 5 }, c: 'ignore' }, false],
+                [{ a: { b: 5, c: 'ignore' } }, true]
+            ], done);
+        });
+    });
+
+    describe('#rename', function () {
+
+        it('allows renaming multiple times with multiple enabled', function (done) {
+
+            var schema = Joi.object({
+                test: Joi.string()
+            }).rename('test1', 'test').rename('test2', 'test', { multiple: true });
+
+            Joi.compile(schema).validate({ test1: 'a', test2: 'b' }, function (err, value) {
+
+                expect(err).to.not.exist();
+                done();
+            });
+        });
+
+        it('errors renaming multiple times with multiple disabled', function (done) {
+
+            var schema = Joi.object({
+                test: Joi.string()
+            }).rename('test1', 'test').rename('test2', 'test');
+
+            Joi.compile(schema).validate({ test1: 'a', test2: 'b' }, function (err, value) {
+
+                expect(err.message).to.equal('"value" cannot rename child "test2" because multiple renames are disabled and another key was already renamed to "test"');
+                done();
+            });
+        });
+
+        it('errors multiple times when abortEarly is false', function (done) {
+
+            Joi.object().rename('a', 'b').rename('c', 'b').rename('d', 'b').options({ abortEarly: false }).validate({ a: 1, c: 1, d: 1 }, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.message).to.equal('"value" cannot rename child "c" because multiple renames are disabled and another key was already renamed to "b". "value" cannot rename child "d" because multiple renames are disabled and another key was already renamed to "b"');
+                done();
+            });
+        });
+
+        it('aliases a key', function (done) {
+
+            var schema = Joi.object({
+                a: Joi.number(),
+                b: Joi.number()
+            }).rename('a', 'b', { alias: true });
+
+            var obj = { a: 10 };
+
+            Joi.compile(schema).validate(obj, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value.a).to.equal(10);
+                expect(value.b).to.equal(10);
+                done();
+            });
+        });
+
+        it('with override disabled should not allow overwriting existing value', function (done) {
+
+            var schema = Joi.object({
+                test1: Joi.string()
+            }).rename('test', 'test1');
+
+            schema.validate({ test: 'b', test1: 'a' }, function (err, value) {
+
+                expect(err.message).to.equal('"value" cannot rename child "test" because override is disabled and target "test1" exists');
+                done();
+            });
+        });
+
+        it('with override enabled should allow overwriting existing value', function (done) {
+
+            var schema = Joi.object({
+                test1: Joi.string()
+            }).rename('test', 'test1', { override: true });
+
+            schema.validate({ test: 'b', test1: 'a' }, function (err, value) {
+
+                expect(err).to.not.exist();
+                done();
+            });
+        });
+
+        it('renames when data is nested in an array via items', function (done) {
+
+            var schema = {
+                arr: Joi.array().items(Joi.object({
+                    one: Joi.string(),
+                    two: Joi.string()
+                }).rename('uno', 'one').rename('dos', 'two'))
+            };
+
+            var data = { arr: [{ uno: '1', dos: '2' }] };
+            Joi.object(schema).validate(data, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value.arr[0].one).to.equal('1');
+                expect(value.arr[0].two).to.equal('2');
+                done();
+            });
+        });
+
+        it('applies rename and validation in the correct order regardless of key order', function (done) {
+
+            var schema1 = Joi.object({
+                a: Joi.number()
+            }).rename('b', 'a');
+
+            var input1 = { b: '5' };
+
+            schema1.validate(input1, function (err1, value1) {
+
+                expect(err1).to.not.exist();
+                expect(value1.b).to.not.exist();
+                expect(value1.a).to.equal(5);
+
+                var schema2 = Joi.object({ a: Joi.number(), b: Joi.any() }).rename('b', 'a');
+                var input2 = { b: '5' };
+
+                schema2.validate(input2, function (err2, value2) {
+
+                    expect(err2).to.not.exist();
+                    expect(value2.b).to.not.exist();
+                    expect(value2.a).to.equal(5);
+
+                    done();
+                });
+            });
+        });
+
+        it('sets the default value after key is renamed', function (done) {
+
+            var schema = Joi.object({
+                foo2: Joi.string().default('test')
+            }).rename('foo', 'foo2');
+
+            var input = {};
+
+            Joi.validate(input, schema, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value.foo2).to.equal('test');
+
+                done();
+            });
+        });
+
+        it('should be able to rename keys that are empty strings', function (done) {
+
+            var schema = Joi.object().rename('', 'notEmpty');
+            var input = {
+                '': 'something'
+            };
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value['']).to.not.exist();
+                expect(value.notEmpty).to.equal('something');
+                done();
+            });
+        });
+
+        it('should not create new keys when they key in question does not exist', function (done) {
+
+            var schema = Joi.object().rename('b', '_b');
+
+            var input = {
+                a: 'something'
+            };
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(Object.keys(value)).to.include('a');
+                expect(value.a).to.equal('something');
+                done();
+            });
+        });
+
+        it('should remove a key with override if from does not exist', function (done) {
+
+            var schema = Joi.object().rename('b', 'a', { override: true });
+
+            var input = {
+                a: 'something'
+            };
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.deep.equal({});
+                done();
+            });
+        });
+
+        it('should ignore a key with ignoredUndefined if from does not exist', function (done){
+
+            var schema = Joi.object().rename('b', 'a', { ignoreUndefined: true });
+
+            var input = {
+                a: 'something'
+            };
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.deep.equal({ a: 'something' });
+                done();
+            });
+        });
+
+        it('shouldn\'t delete a key with override and ignoredUndefined if from does not exist', function (done){
+
+            var schema = Joi.object().rename('b', 'a', { ignoreUndefined: true, override: true });
+
+            var input = {
+                a: 'something'
+            };
+
+            schema.validate(input, function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.deep.equal({ a: 'something' });
+                done();
+            });
+        });
+    });
+
+    describe('#describe', function () {
+
+        it('return empty description when no schema defined', function (done) {
+
+            var schema = Joi.object();
+            var desc = schema.describe();
+            expect(desc).to.deep.equal({
+                type: 'object'
+            });
+            done();
+        });
+
+        it('respects the shallow parameter', function (done) {
+
+            var schema = Joi.object({
+                name: Joi.string(),
+                child: Joi.object({
+                    name: Joi.string()
+                })
+            });
+
+            expect(Object.keys(schema.describe(true))).to.not.include('children');
+            expect(Object.keys(schema.describe())).to.include('children');
+
+            done();
+        });
+
+        it('describes patterns', function (done) {
+
+            var schema = Joi.object({
+                a: Joi.string()
+            }).pattern(/\w\d/i, Joi.boolean());
+
+            expect(schema.describe()).to.deep.equal({
+                type: 'object',
+                children: {
+                    a: {
+                        type: 'string',
+                        invalids: ['']
+                    }
+                },
+                patterns: [
+                    {
+                        regex: '/\\w\\d/i',
+                        rule: {
+                            type: 'boolean'
+                        }
+                    }
+                ]
+            });
+
+            done();
+        });
+    });
+
+    describe('#length', function () {
+
+        it('throws when length is not a number', function (done) {
+
+            expect(function () {
+
+                Joi.object().length('a');
+            }).to.throw('limit must be a positive integer');
+            done();
+        });
+    });
+
+    describe('#min', function () {
+
+        it('throws when limit is not a number', function (done) {
+
+            expect(function () {
+
+                Joi.object().min('a');
+            }).to.throw('limit must be a positive integer');
+            done();
+        });
+    });
+
+    describe('#max', function () {
+
+        it('throws when limit is not a number', function (done) {
+
+            expect(function () {
+
+                Joi.object().max('a');
+            }).to.throw('limit must be a positive integer');
+            done();
+        });
+    });
+
+    describe('#pattern', function () {
+
+        it('shows path to errors in schema', function (done) {
+
+            expect(function () {
+
+                Joi.object().pattern(/.*/, {
+                    a: {
+                        b: {
+                            c: {
+                                d: undefined
+                            }
+                        }
+                    }
+                });
+            }).to.throw(Error, 'Invalid schema content: (a.b.c.d)');
+
+            expect(function () {
+
+                Joi.object().pattern(/.*/, function () {
+
+                });
+            }).to.throw(Error, 'Invalid schema content: ');
+
+            done();
+        });
+
+        it('validates unknown keys using a pattern', function (done) {
+
+            var schema = Joi.object({
+                a: Joi.number()
+            }).pattern(/\d+/, Joi.boolean()).pattern(/\w\w+/, 'x');
+
+            Joi.validate({ bb: 'y', 5: 'x' }, schema, { abortEarly: false }, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.message).to.equal('child "5" fails because ["5" must be a boolean]. child "bb" fails because ["bb" must be one of [x]]');
+
+                Helper.validate(schema, [
+                    [{ a: 5 }, true],
+                    [{ a: 'x' }, false],
+                    [{ b: 'x' }, false],
+                    [{ bb: 'x' }, true],
+                    [{ 5: 'x' }, false],
+                    [{ 5: false }, true],
+                    [{ 5: undefined }, true]
+                ], done);
+            });
+        });
+
+        it('validates unknown keys using a pattern (nested)', function (done) {
+
+            var schema = {
+                x: Joi.object({
+                    a: Joi.number()
+                }).pattern(/\d+/, Joi.boolean()).pattern(/\w\w+/, 'x')
+            };
+
+            Joi.validate({ x: { bb: 'y', 5: 'x' } }, schema, { abortEarly: false }, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.message).to.equal('child "x" fails because [child "5" fails because ["5" must be a boolean], child "bb" fails because ["bb" must be one of [x]]]');
+                done();
+            });
+        });
+
+        it('errors when using a pattern on empty schema with unknown(false) and pattern mismatch', function (done) {
+
+            var schema = Joi.object().pattern(/\d/, Joi.number()).unknown(false);
+
+            Joi.validate({ a: 5 }, schema, { abortEarly: false }, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.message).to.equal('"a" is not allowed');
+                done();
+            });
+        });
+
+        it('removes global flag from patterns', function (done) {
+
+            var schema = Joi.object().pattern(/a/g, Joi.number());
+
+            Joi.validate({ a1: 5, a2: 6 }, schema, function (err, value) {
+
+                expect(err).to.not.exist();
+                done();
+            });
+        });
+    });
+
+    describe('#with', function () {
+
+        it('should throw an error when a parameter is not a string', function (done) {
+
+            try {
+                Joi.object().with({});
+                var error = false;
+            }
+            catch (e) {
+                error = true;
+            }
+            expect(error).to.equal(true);
+
+            try {
+                Joi.object().with(123);
+                error = false;
+            }
+            catch (e) {
+                error = true;
+            }
+            expect(error).to.equal(true);
+            done();
+        });
+
+        it('should validate correctly when key is an empty string', function (done) {
+
+            var schema = Joi.object().with('', 'b');
+            Helper.validate(schema, [
+                [{ c: 'hi', d: 'there' }, true]
+            ]);
+            done();
+        });
+    });
+
+    describe('#without', function () {
+
+        it('should throw an error when a parameter is not a string', function (done) {
+
+            try {
+                Joi.object().without({});
+                var error = false;
+            }
+            catch (e) {
+                error = true;
+            }
+            expect(error).to.equal(true);
+
+            try {
+                Joi.object().without(123);
+                error = false;
+            }
+            catch (e) {
+                error = true;
+            }
+            expect(error).to.equal(true);
+
+
+            done();
+        });
+
+        it('should validate correctly when key is an empty string', function (done) {
+
+            var schema = Joi.object().without('', 'b');
+            Helper.validate(schema, [
+                [{ a: 'hi', b: 'there' }, true]
+            ]);
+            done();
+        });
+    });
+
+    describe('#xor', function () {
+
+        it('should throw an error when a parameter is not a string', function (done) {
+
+            try {
+                Joi.object().xor({});
+                var error = false;
+            }
+            catch (e) {
+                error = true;
+            }
+            expect(error).to.equal(true);
+
+            try {
+                Joi.object().xor(123);
+                error = false;
+            }
+            catch (e) {
+                error = true;
+            }
+            expect(error).to.equal(true);
+            done();
+        });
+    });
+
+    describe('#or', function () {
+
+        it('should throw an error when a parameter is not a string', function (done) {
+
+            try {
+                Joi.object().or({});
+                var error = false;
+            }
+            catch (e) {
+                error = true;
+            }
+            expect(error).to.equal(true);
+
+            try {
+                Joi.object().or(123);
+                error = false;
+            }
+            catch (e) {
+                error = true;
+            }
+            expect(error).to.equal(true);
+            done();
+        });
+
+        it('errors multiple levels deep', function (done) {
+
+            Joi.object({
+                a: {
+                    b: Joi.object().or('x', 'y')
+                }
+            }).validate({ a: { b: { c: 1 } } }, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.details[0].path).to.equal('a.b');
+                expect(err.message).to.equal('child "a" fails because [child "b" fails because ["value" must contain at least one of [x, y]]]');
+                done();
+            });
+        });
+    });
+
+    describe('#assert', function () {
+
+        it('shows path to errors in schema', function (done) {
+
+            expect(function () {
+
+                Joi.object().assert('a.b', {
+                    a: {
+                        b: {
+                            c: {
+                                d: undefined
+                            }
+                        }
+                    }
+                });
+            }).to.throw(Error, 'Invalid schema content: (a.b.c.d)');
+            done();
+        });
+
+        it('shows errors in schema', function (done) {
+
+            expect(function () {
+
+                Joi.object().assert('a.b', undefined);
+            }).to.throw(Error, 'Invalid schema content: ');
+            done();
+        });
+
+        it('validates upwards reference', function (done) {
+
+            var schema = Joi.object({
+                a: {
+                    b: Joi.string(),
+                    c: Joi.number()
+                },
+                d: {
+                    e: Joi.any()
+                }
+            }).assert(Joi.ref('d/e', { separator: '/' }), Joi.ref('a.c'), 'equal to a.c');
+
+            schema.validate({ a: { b: 'x', c: 5 }, d: { e: 6 } }, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.message).to.equal('"d.e" validation failed because "d.e" failed to equal to a.c');
+
+                Helper.validate(schema, [
+                    [{ a: { b: 'x', c: 5 }, d: { e: 5 } }, true]
+                ], done);
+            });
+        });
+
+        it('validates upwards reference with implicit context', function (done) {
+
+            var schema = Joi.object({
+                a: {
+                    b: Joi.string(),
+                    c: Joi.number()
+                },
+                d: {
+                    e: Joi.any()
+                }
+            }).assert('d.e', Joi.ref('a.c'), 'equal to a.c');
+
+            schema.validate({ a: { b: 'x', c: 5 }, d: { e: 6 } }, function (err, value) {
+
+                expect(err).to.exist();
+                expect(err.message).to.equal('"d.e" validation failed because "d.e" failed to equal to a.c');
+
+                Helper.validate(schema, [
+                    [{ a: { b: 'x', c: 5 }, d: { e: 5 } }, true]
+                ], done);
+            });
+        });
+
+        it('throws when context is at root level', function (done) {
+
+            expect(function () {
+
+                Joi.object({
+                    a: {
+                        b: Joi.string(),
+                        c: Joi.number()
+                    },
+                    d: {
+                        e: Joi.any()
+                    }
+                }).assert('a', Joi.ref('d.e'), 'equal to d.e');
+            }).to.throw('Cannot use assertions for root level references - use direct key rules instead');
+            done();
+        });
+
+        it('allows root level context ref', function (done) {
+
+            expect(function () {
+
+                Joi.object({
+                    a: {
+                        b: Joi.string(),
+                        c: Joi.number()
+                    },
+                    d: {
+                        e: Joi.any()
+                    }
+                }).assert('$a', Joi.ref('d.e'), 'equal to d.e');
+            }).to.not.throw();
+            done();
+        });
+
+        it('provides a default message for failed assertions', function (done) {
+
+            var schema = Joi.object({
+                a: {
+                    b: Joi.string(),
+                    c: Joi.number()
+                },
+                d: {
+                    e: Joi.any()
+                }
+            }).assert('d.e', Joi.boolean());
+
+            schema.validate({
+                d: {
+                    e: []
+                }
+            }, function (err) {
+
+                expect(err).to.exist();
+                expect(err.message).to.equal('"d.e" validation failed because "d.e" failed to pass the assertion test');
+                done();
+            });
+        });
+    });
+
+    describe('#type', function () {
+
+        it('uses constructor name for default type name', function (done) {
+
+            var Foo = function Foo () {};
+
+            var schema = Joi.object().type(Foo);
+            schema.validate({}, function (err) {
+
+                expect(err).to.exist();
+                expect(err.message).to.equal('"value" must be an instance of "Foo"');
+                done();
+            });
+        });
+
+        it('uses custom type name if supplied', function (done) {
+
+            var Foo = function () {};
+
+            var schema = Joi.object().type(Foo, 'Bar');
+            schema.validate({}, function (err) {
+
+                expect(err).to.exist();
+                expect(err.message).to.equal('"value" must be an instance of "Bar"');
+                done();
+            });
+        });
+
+        it('overrides constructor name with custom name', function (done) {
+
+            var Foo = function Foo () {};
+
+            var schema = Joi.object().type(Foo, 'Bar');
+            schema.validate({}, function (err) {
+
+                expect(err).to.exist();
+                expect(err.message).to.equal('"value" must be an instance of "Bar"');
+                done();
+            });
+        });
+
+        it('throws when constructor is not a function', function (done) {
+
+            expect(function () {
+
+                Joi.object().type('');
+            }).to.throw('type must be a constructor function');
+            done();
+        });
+
+        it('uses the constructor name in the schema description', function (done) {
+
+            var description = Joi.object().type(RegExp).describe();
+
+            expect(description.rules).to.deep.include({ name: 'type', arg: 'RegExp' });
+            done();
+        });
+    });
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/ref.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/ref.js
new file mode 100755
index 0000000000000000000000000000000000000000..feefc0b94089405215596a6b529a4989513600e2
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/ref.js
@@ -0,0 +1,387 @@
+// Load modules
+
+var Lab = require('lab');
+var Code = require('code');
+var Joi = require('../lib');
+var Helper = require('./helper');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var lab = exports.lab = Lab.script();
+var describe = lab.describe;
+var it = lab.it;
+var expect = Code.expect;
+
+
+describe('ref', function () {
+
+    it('uses ref as a valid value', function (done) {
+
+        var schema = Joi.object({
+            a: Joi.ref('b'),
+            b: Joi.any()
+        });
+
+        schema.validate({ a: 5, b: 6 }, function (err, value) {
+
+            expect(err).to.exist();
+            expect(err.message).to.equal('child "a" fails because ["a" must be one of [ref:b]]');
+
+            Helper.validate(schema, [
+                [{ a: 5 }, false],
+                [{ b: 5 }, true],
+                [{ a: 5, b: 5 }, true],
+                [{ a: '5', b: '5' }, true]
+            ], done);
+        });
+    });
+
+    it('uses ref as a valid value (empty key)', function (done) {
+
+        var schema = Joi.object({
+            a: Joi.ref(''),
+            '': Joi.any()
+        });
+
+        schema.validate({ a: 5, '': 6 }, function (err, value) {
+
+            expect(err).to.exist();
+            expect(err.message).to.equal('child "a" fails because ["a" must be one of [ref:]]');
+
+            Helper.validate(schema, [
+                [{ a: 5 }, false],
+                [{ '': 5 }, true],
+                [{ a: 5, '': 5 }, true],
+                [{ a: '5', '': '5' }, true]
+            ], done);
+        });
+    });
+
+    it('uses ref with nested keys as a valid value', function (done) {
+
+        var schema = Joi.object({
+            a: Joi.ref('b.c'),
+            b: {
+                c: Joi.any()
+            }
+        });
+
+        schema.validate({ a: 5, b: { c: 6 } }, function (err, value) {
+
+            expect(err).to.exist();
+            expect(err.message).to.equal('child "a" fails because ["a" must be one of [ref:b.c]]');
+
+            Helper.validate(schema, [
+                [{ a: 5 }, false],
+                [{ b: { c: 5 } }, true],
+                [{ a: 5, b: 5 }, false],
+                [{ a: '5', b: { c: '5' } }, true]
+            ], done);
+        });
+    });
+
+    it('uses ref with combined nested keys in sub child', function (done) {
+
+        var ref = Joi.ref('b.c');
+        expect(ref.root).to.equal('b');
+
+        var schema = Joi.object({
+            a: ref,
+            b: {
+                c: Joi.any()
+            }
+        });
+
+        var input = { a: 5, b: { c: 5 } };
+        schema.validate(input, function (err, value) {
+
+            expect(err).to.not.exist();
+
+            var parent = Joi.object({
+                e: schema
+            });
+
+            parent.validate({ e: input }, function (err2, value2) {
+
+                expect(err2).to.not.exist();
+                done();
+            });
+        });
+    });
+
+    it('uses ref reach options', function (done) {
+
+        var ref = Joi.ref('b/c', { separator: '/' });
+        expect(ref.root).to.equal('b');
+
+        var schema = Joi.object({
+            a: ref,
+            b: {
+                c: Joi.any()
+            }
+        });
+
+        schema.validate({ a: 5, b: { c: 5 } }, function (err, value) {
+
+            expect(err).to.not.exist();
+            done();
+        });
+    });
+
+    it('ignores the order in which keys are defined', function (done) {
+
+        var ab = Joi.object({
+            a: {
+                c: Joi.number()
+            },
+            b: Joi.ref('a.c')
+        });
+
+        ab.validate({ a: { c: '5' }, b: 5 }, function (err, value) {
+
+            expect(err).to.not.exist();
+
+            var ba = Joi.object({
+                b: Joi.ref('a.c'),
+                a: {
+                    c: Joi.number()
+                }
+            });
+
+            ba.validate({ a: { c: '5' }, b: 5 }, function (err2, value2) {
+
+                expect(err2).to.not.exist();
+                done();
+            });
+        });
+    });
+
+    it('uses ref as default value', function (done) {
+
+        var schema = Joi.object({
+            a: Joi.default(Joi.ref('b')),
+            b: Joi.any()
+        });
+
+        schema.validate({ b: 6 }, function (err, value) {
+
+            expect(err).to.not.exist();
+            expect(value).to.deep.equal({ a: 6, b: 6 });
+            done();
+        });
+    });
+
+    it('uses ref as default value regardless of order', function (done) {
+
+        var ab = Joi.object({
+            a: Joi.default(Joi.ref('b')),
+            b: Joi.number()
+        });
+
+        ab.validate({ b: '6' }, function (err, value) {
+
+            expect(err).to.not.exist();
+            expect(value).to.deep.equal({ a: 6, b: 6 });
+
+            var ba = Joi.object({
+                b: Joi.number(),
+                a: Joi.default(Joi.ref('b'))
+            });
+
+            ba.validate({ b: '6' }, function (err2, value2) {
+
+                expect(err2).to.not.exist();
+                expect(value2).to.deep.equal({ a: 6, b: 6 });
+                done();
+            });
+        });
+    });
+
+    it('ignores the order in which keys are defined with alternatives', function (done) {
+
+        var a = { c: Joi.number() };
+        var b = [Joi.ref('a.c'), Joi.ref('c')];
+        var c = Joi.number();
+
+        Helper.validate({ a: a, b: b, c: c }, [
+            [{ a: {} }, true],
+            [{ a: { c: '5' }, b: 5 }, true],
+            [{ a: { c: '5' }, b: 6, c: '6' }, true],
+            [{ a: { c: '5' }, b: 7, c: '6' }, false]
+        ]);
+
+        Helper.validate({ b: b, a: a, c: c }, [
+            [{ a: {} }, true],
+            [{ a: { c: '5' }, b: 5 }, true],
+            [{ a: { c: '5' }, b: 6, c: '6' }, true],
+            [{ a: { c: '5' }, b: 7, c: '6' }, false]
+        ]);
+
+        Helper.validate({ b: b, c: c, a: a }, [
+            [{ a: {} }, true],
+            [{ a: { c: '5' }, b: 5 }, true],
+            [{ a: { c: '5' }, b: 6, c: '6' }, true],
+            [{ a: { c: '5' }, b: 7, c: '6' }, false]
+        ]);
+
+        Helper.validate({ a: a, c: c, b: b }, [
+            [{ a: {} }, true],
+            [{ a: { c: '5' }, b: 5 }, true],
+            [{ a: { c: '5' }, b: 6, c: '6' }, true],
+            [{ a: { c: '5' }, b: 7, c: '6' }, false]
+        ]);
+
+        Helper.validate({ c: c, a: a, b: b }, [
+            [{ a: {} }, true],
+            [{ a: { c: '5' }, b: 5 }, true],
+            [{ a: { c: '5' }, b: 6, c: '6' }, true],
+            [{ a: { c: '5' }, b: 7, c: '6' }, false]
+        ]);
+
+        Helper.validate({ c: c, b: b, a: a }, [
+            [{ a: {} }, true],
+            [{ a: { c: '5' }, b: 5 }, true],
+            [{ a: { c: '5' }, b: 6, c: '6' }, true],
+            [{ a: { c: '5' }, b: 7, c: '6' }, false]
+        ], done);
+    });
+
+    it('uses context as default value', function (done) {
+
+        var schema = Joi.object({
+            a: Joi.default(Joi.ref('$x')),
+            b: Joi.any()
+        });
+
+        Joi.validate({ b: 6 }, schema, { context: { x: 22 } }, function (err, value) {
+
+            expect(err).to.not.exist();
+            expect(value).to.deep.equal({ a: 22, b: 6 });
+            done();
+        });
+    });
+
+    it('uses context as default value with custom prefix', function (done) {
+
+        var schema = Joi.object({
+            a: Joi.default(Joi.ref('%x', { contextPrefix: '%' })),
+            b: Joi.any()
+        });
+
+        Joi.validate({ b: 6 }, schema, { context: { x: 22 } }, function (err, value) {
+
+            expect(err).to.not.exist();
+            expect(value).to.deep.equal({ a: 22, b: 6 });
+            done();
+        });
+    });
+
+    it('uses context as a valid value', function (done) {
+
+        var schema = Joi.object({
+            a: Joi.ref('$x'),
+            b: Joi.any()
+        });
+
+        Joi.validate({ a: 5, b: 6 }, schema, { context: { x: 22 } }, function (err, value) {
+
+            expect(err).to.exist();
+            expect(err.message).to.equal('child "a" fails because ["a" must be one of [context:x]]');
+
+            Helper.validateOptions(schema, [
+                [{ a: 5 }, false],
+                [{ a: 22 }, true],
+                [{ b: 5 }, true],
+                [{ a: 22, b: 5 }, true],
+                [{ a: '22', b: '5' }, false]
+            ], { context: { x: 22 } }, done);
+        });
+    });
+
+    it('uses context in when condition', function (done) {
+
+        var schema = {
+            a: Joi.boolean().when('$x', { is: Joi.exist(), otherwise: Joi.forbidden() })
+        };
+
+        Helper.validate(schema, [
+            [{}, true],
+            [{ a: 'x' }, false],
+            [{ a: true }, false],
+            [{}, true, { context: {} }],
+            [{ a: 'x' }, false, { context: {} }],
+            [{ a: true }, false, { context: {} }],
+            [{}, true, { context: { x: 1 } }],
+            [{ a: 'x' }, false, { context: { x: 1 } }],
+            [{ a: true }, true, { context: { x: 1 } }]
+        ], done);
+    });
+
+    it('uses nested context in when condition', function (done) {
+
+        var schema = {
+            a: Joi.boolean().when('$x.y', { is: Joi.exist(), otherwise: Joi.forbidden() })
+        };
+
+        Helper.validate(schema, [
+            [{}, true],
+            [{ a: 'x' }, false],
+            [{ a: true }, false],
+            [{}, true, { context: {} }],
+            [{ a: 'x' }, false, { context: {} }],
+            [{ a: true }, false, { context: {} }],
+            [{}, true, { context: { x: 1 } }],
+            [{ a: 'x' }, false, { context: { x: 1 } }],
+            [{ a: true }, false, { context: { x: 1 } }],
+            [{}, true, { context: { x: {} } }],
+            [{ a: 'x' }, false, { context: { x: {} } }],
+            [{ a: true }, false, { context: { x: {} } }],
+            [{}, true, { context: { x: { y: 1 } } }],
+            [{ a: 'x' }, false, { context: { x: { y: 1 } } }],
+            [{ a: true }, true, { context: { x: { y: 1 } } }]
+        ], done);
+    });
+
+    it('describes schema with ref', function (done) {
+
+        var desc = Joi.compile(Joi.ref('a.b')).describe();
+        expect(Joi.isRef(desc.valids[0])).to.be.true();
+        done();
+    });
+
+    describe('#create', function () {
+
+        it('throws when key is missing', function (done) {
+
+            expect(function () {
+
+                Joi.ref(5);
+            }).to.throw('Invalid reference key: 5');
+            done();
+        });
+
+        it('finds root with default separator', function (done) {
+
+            expect(Joi.ref('a.b.c').root).to.equal('a');
+            done();
+        });
+
+        it('finds root with default separator and options', function (done) {
+
+            expect(Joi.ref('a.b.c', {}).root).to.equal('a');
+            done();
+        });
+
+        it('finds root with custom separator', function (done) {
+
+            expect(Joi.ref('a+b+c', { separator: '+' }).root).to.equal('a');
+            done();
+        });
+    });
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/string.js b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/string.js
new file mode 100755
index 0000000000000000000000000000000000000000..c3c6d06382f9a220662c2337a4dd99583c7c490b
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/joi/test/string.js
@@ -0,0 +1,3035 @@
+// Load modules
+
+var Lab = require('lab');
+var Code = require('code');
+var Joi = require('../lib');
+var Helper = require('./helper');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var lab = exports.lab = Lab.script();
+var describe = lab.describe;
+var it = lab.it;
+var expect = Code.expect;
+
+
+describe('string', function () {
+
+    it('fails on boolean', function (done) {
+
+        var schema = Joi.string();
+        Helper.validate(schema, [
+            [true, false],
+            [false, false]
+        ], done);
+    });
+
+    describe('#valid', function () {
+
+        it('should throw error on input not matching type', function (done) {
+
+            expect(function () {
+
+                Joi.string().valid({});
+            }).to.throw();
+            done();
+        });
+
+        it('should not throw on input matching type', function (done) {
+
+            expect(function () {
+
+                Joi.string().valid('joi');
+            }).to.not.throw();
+            done();
+        });
+
+        it('validates case sensitive values', function (done) {
+
+            Helper.validate(Joi.string().valid('a', 'b'), [
+                ['a', true],
+                ['b', true],
+                ['A', false],
+                ['B', false]
+            ], done);
+        });
+
+        it('validates case insensitive values', function (done) {
+
+            Helper.validate(Joi.string().valid('a', 'b').insensitive(), [
+                ['a', true],
+                ['b', true],
+                ['A', true],
+                ['B', true],
+                [4, false]
+            ], done);
+        });
+
+        it('validates case insensitive values with non-strings', function (done) {
+
+            Helper.validate(Joi.string().valid('a', 'b', 5).insensitive(), [
+                ['a', true],
+                ['b', true],
+                ['A', true],
+                ['B', true],
+                [4, false],
+                [5, true]
+            ], done);
+        });
+    });
+
+    describe('#invalid', function () {
+
+        it('should throw error on input not matching type', function (done) {
+
+            expect(function () {
+
+                Joi.string().invalid({});
+            }).to.throw();
+            done();
+        });
+
+        it('should not throw on input matching type', function (done) {
+
+            expect(function () {
+
+                Joi.string().invalid('joi');
+            }).to.not.throw();
+            done();
+        });
+
+        it('invalidates case sensitive values', function (done) {
+
+            Helper.validate(Joi.string().invalid('a', 'b'), [
+                ['a', false],
+                ['b', false],
+                ['A', true],
+                ['B', true]
+            ], done);
+        });
+
+        it('invalidates case insensitive values', function (done) {
+
+            Helper.validate(Joi.string().invalid('a', 'b').insensitive(), [
+                ['a', false],
+                ['b', false],
+                ['A', false],
+                ['B', false]
+            ], done);
+        });
+    });
+
+    describe('#min', function () {
+
+        it('throws when limit is not a number', function (done) {
+
+            expect(function () {
+
+                Joi.string().min('a');
+            }).to.throw('limit must be a positive integer or reference');
+            done();
+        });
+
+        it('throws when limit is not an integer', function (done) {
+
+            expect(function () {
+
+                Joi.string().min(1.2);
+            }).to.throw('limit must be a positive integer or reference');
+            done();
+        });
+
+        it('throws when limit is not a positive integer', function (done) {
+
+            expect(function () {
+
+                Joi.string().min(-1);
+            }).to.throw('limit must be a positive integer or reference');
+            done();
+        });
+
+        it('enforces a limit using byte count', function (done) {
+
+            var schema = Joi.string().min(2, 'utf8');
+            Helper.validate(schema, [
+                ['\u00bd', true],
+                ['a', false]
+            ], done);
+        });
+
+        it('accepts references as min length', function (done) {
+
+            var schema = Joi.object({ a: Joi.number(), b: Joi.string().min(Joi.ref('a'), 'utf8') });
+            Helper.validate(schema, [
+                [{ a: 2, b: '\u00bd' }, true],
+                [{ a: 2, b: 'a' }, false],
+                [{ a: 2, b: 'a' }, false, null, 'child "b" fails because ["b" length must be at least 2 characters long]']
+            ], done);
+        });
+
+        it('accepts context references as min length', function (done) {
+
+            var schema = Joi.object({ b: Joi.string().min(Joi.ref('$a'), 'utf8') });
+            Helper.validate(schema, [
+                [{ b: '\u00bd' }, true, { context: { a: 2 } }],
+                [{ b: 'a' }, false, { context: { a: 2 } }],
+                [{ b: 'a' }, false, { context: { a: 2 } }, 'child "b" fails because ["b" length must be at least 2 characters long]']
+            ], done);
+        });
+
+        it('errors if reference is not a number', function (done) {
+
+            var schema = Joi.object({ a: Joi.any(), b: Joi.string().min(Joi.ref('a'), 'utf8') });
+
+            Helper.validate(schema, [
+                [{ a: 'Hi there', b: '\u00bd' }, false, null, 'child "b" fails because ["b" references "a" which is not a number]']
+            ], done);
+        });
+
+        it('errors if context reference is not a number', function (done) {
+
+            var schema = Joi.object({ b: Joi.string().min(Joi.ref('$a'), 'utf8') });
+
+            Helper.validate(schema, [
+                [{ b: '\u00bd' }, false, { context: { a: 'Hi there' } }, 'child "b" fails because ["b" references "a" which is not a number]']
+            ], done);
+        });
+    });
+
+    describe('#max', function () {
+
+        it('throws when limit is not a number', function (done) {
+
+            expect(function () {
+
+                Joi.string().max('a');
+            }).to.throw('limit must be a positive integer or reference');
+            done();
+        });
+
+        it('throws when limit is not an integer', function (done) {
+
+            expect(function () {
+
+                Joi.string().max(1.2);
+            }).to.throw('limit must be a positive integer or reference');
+            done();
+        });
+
+        it('throws when limit is not a positive integer', function (done) {
+
+            expect(function () {
+
+                Joi.string().max(-1);
+            }).to.throw('limit must be a positive integer or reference');
+            done();
+        });
+
+        it('enforces a limit using byte count', function (done) {
+
+            var schema = Joi.string().max(1, 'utf8');
+            Helper.validate(schema, [
+                ['\u00bd', false],
+                ['a', true]
+            ], done);
+        });
+
+        it('accepts references as min length', function (done) {
+
+            var schema = Joi.object({ a: Joi.number(), b: Joi.string().max(Joi.ref('a'), 'utf8') });
+            Helper.validate(schema, [
+                [{ a: 2, b: '\u00bd' }, true],
+                [{ a: 2, b: 'three' }, false],
+                [{ a: 2, b: 'three' }, false, null, 'child "b" fails because ["b" length must be less than or equal to 2 characters long]']
+            ], done);
+        });
+
+        it('accepts context references as min length', function (done) {
+
+            var schema = Joi.object({ b: Joi.string().max(Joi.ref('$a'), 'utf8') });
+            Helper.validate(schema, [
+                [{ b: '\u00bd' }, true, { context: { a: 2 } }],
+                [{ b: 'three' }, false, { context: { a: 2 } }],
+                [{ b: 'three' }, false, { context: { a: 2 } }, 'child "b" fails because ["b" length must be less than or equal to 2 characters long]']
+            ], done);
+        });
+
+        it('errors if reference is not a number', function (done) {
+
+            var schema = Joi.object({ a: Joi.any(), b: Joi.string().max(Joi.ref('a'), 'utf8') });
+
+            Helper.validate(schema, [
+                [{ a: 'Hi there', b: '\u00bd' }, false, null, 'child "b" fails because ["b" references "a" which is not a number]']
+            ], done);
+        });
+
+        it('errors if context reference is not a number', function (done) {
+
+            var schema = Joi.object({ b: Joi.string().max(Joi.ref('$a'), 'utf8') });
+
+            Helper.validate(schema, [
+                [{ b: '\u00bd' }, false, { context: { a: 'Hi there' } }, 'child "b" fails because ["b" references "a" which is not a number]']
+            ], done);
+        });
+    });
+
+    describe('#creditCard', function () {
+
+        it('should validate credit card', function (done) {
+
+            var t = Joi.string().creditCard();
+            t.validate('4111111111111112', function (err, value) {
+
+                expect(err.message).to.equal('"value" must be a credit card');
+
+                Helper.validate(t, [
+                    ['378734493671000', true],  // american express
+                    ['371449635398431', true],  // american express
+                    ['378282246310005', true],  // american express
+                    ['341111111111111', true],  // american express
+                    ['5610591081018250', true], // australian bank
+                    ['5019717010103742', true], // dankort pbs
+                    ['38520000023237', true],   // diners club
+                    ['30569309025904', true],   // diners club
+                    ['6011000990139424', true], // discover
+                    ['6011111111111117', true], // discover
+                    ['6011601160116611', true], // discover
+                    ['3566002020360505', true], // jbc
+                    ['3530111333300000', true], // jbc
+                    ['5105105105105100', true], // mastercard
+                    ['5555555555554444', true], // mastercard
+                    ['5431111111111111', true], // mastercard
+                    ['6331101999990016', true], // switch/solo paymentech
+                    ['4222222222222', true],    // visa
+                    ['4012888888881881', true], // visa
+                    ['4111111111111111', true], // visa
+                    ['4111111111111112', false],
+                    [null, false]
+                ], done);
+            });
+        });
+    });
+
+    describe('#length', function () {
+
+        it('throws when limit is not a number', function (done) {
+
+            expect(function () {
+
+                Joi.string().length('a');
+            }).to.throw('limit must be a positive integer or reference');
+            done();
+        });
+
+        it('throws when limit is not an integer', function (done) {
+
+            expect(function () {
+
+                Joi.string().length(1.2);
+            }).to.throw('limit must be a positive integer or reference');
+            done();
+        });
+
+        it('throws when limit is not a positive integer', function (done) {
+
+            expect(function () {
+
+                Joi.string().length(-42);
+            }).to.throw('limit must be a positive integer or reference');
+            done();
+        });
+
+        it('enforces a limit using byte count', function (done) {
+
+            var schema = Joi.string().length(2, 'utf8');
+            Helper.validate(schema, [
+                ['\u00bd', true],
+                ['a', false]
+            ], done);
+        });
+
+        it('accepts references as length', function (done) {
+
+            var schema = Joi.object({ a: Joi.number(), b: Joi.string().length(Joi.ref('a'), 'utf8') });
+            Helper.validate(schema, [
+                [{ a: 2, b: '\u00bd' }, true],
+                [{ a: 2, b: 'a' }, false],
+                [{ a: 2, b: 'a' }, false, null, 'child "b" fails because ["b" length must be 2 characters long]']
+            ], done);
+        });
+
+        it('accepts context references as length', function (done) {
+
+            var schema = Joi.object({ b: Joi.string().length(Joi.ref('$a'), 'utf8') });
+            Helper.validate(schema, [
+                [{ b: '\u00bd' }, true, { context: { a: 2 } }],
+                [{ b: 'a' }, false, { context: { a: 2 } }],
+                [{ b: 'a' }, false, { context: { a: 2 } }, 'child "b" fails because ["b" length must be 2 characters long]']
+            ], done);
+        });
+
+        it('errors if reference is not a number', function (done) {
+
+            var schema = Joi.object({ a: Joi.any(), b: Joi.string().length(Joi.ref('a'), 'utf8') });
+
+            Helper.validate(schema, [
+                [{ a: 'Hi there', b: '\u00bd' }, false, null, 'child "b" fails because ["b" references "a" which is not a number]']
+            ], done);
+        });
+
+        it('errors if context reference is not a number', function (done) {
+
+            var schema = Joi.object({ a: Joi.any(), b: Joi.string().length(Joi.ref('$a'), 'utf8') });
+
+            Helper.validate(schema, [
+                [{ b: '\u00bd' }, false, { context: { a: 'Hi there' } }, 'child "b" fails because ["b" references "a" which is not a number]']
+            ], done);
+        });
+    });
+
+    describe('#email', function () {
+
+        it('throws when options are not an object', function (done) {
+
+            expect(function () {
+
+                var emailOptions = true;
+                Joi.string().email(emailOptions);
+            }).to.throw('email options must be an object');
+            done();
+        });
+
+        it('throws when checkDNS option is enabled', function (done) {
+
+            expect(function () {
+
+                var emailOptions = { checkDNS: true };
+                Joi.string().email(emailOptions);
+            }).to.throw('checkDNS option is not supported');
+            done();
+        });
+
+        it('throws when tldWhitelist is not an array or object', function (done) {
+
+            expect(function () {
+
+                var emailOptions = { tldWhitelist: 'domain.tld' };
+                Joi.string().email(emailOptions);
+            }).to.throw('tldWhitelist must be an array or object');
+            done();
+        });
+
+        it('throws when minDomainAtoms is not a number', function (done) {
+
+            expect(function () {
+
+                var emailOptions = { minDomainAtoms: '1' };
+                Joi.string().email(emailOptions);
+            }).to.throw('minDomainAtoms must be a positive integer');
+            done();
+        });
+
+        it('throws when minDomainAtoms is not an integer', function (done) {
+
+            expect(function () {
+
+                var emailOptions = { minDomainAtoms: 1.2 };
+                Joi.string().email(emailOptions);
+            }).to.throw('minDomainAtoms must be a positive integer');
+            done();
+        });
+
+        it('throws when minDomainAtoms is not positive', function (done) {
+
+            expect(function () {
+
+                var emailOptions = { minDomainAtoms: 0 };
+                Joi.string().email(emailOptions);
+            }).to.throw('minDomainAtoms must be a positive integer');
+            done();
+        });
+
+        it('does not throw when minDomainAtoms is a positive integer', function (done) {
+
+            expect(function () {
+
+                var emailOptions = { minDomainAtoms: 1 };
+                Joi.string().email(emailOptions);
+            }).to.not.throw();
+            done();
+        });
+
+        it('throws when errorLevel is not an integer or boolean', function (done) {
+
+            expect(function () {
+
+                var emailOptions = { errorLevel: 1.2 };
+                Joi.string().email(emailOptions);
+            }).to.throw('errorLevel must be a non-negative integer or boolean');
+            done();
+        });
+
+        it('throws when errorLevel is negative', function (done) {
+
+            expect(function () {
+
+                var emailOptions = { errorLevel: -1 };
+                Joi.string().email(emailOptions);
+            }).to.throw('errorLevel must be a non-negative integer or boolean');
+            done();
+        });
+
+        it('does not throw when errorLevel is 0', function (done) {
+
+            expect(function () {
+
+                var emailOptions = { errorLevel: 0 };
+                Joi.string().email(emailOptions);
+            }).to.not.throw();
+            done();
+        });
+    });
+
+    describe('#hostname', function () {
+
+        it('validates hostnames', function (done) {
+
+            var schema = Joi.string().hostname();
+            Helper.validate(schema, [
+                ['www.example.com', true],
+                ['domain.local', true],
+                ['3domain.local', true],
+                ['hostname', true],
+                ['host:name', false],
+                ['-', false],
+                ['2387628', true],
+                ['01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789', false],
+                ['::1', true],
+                ['0:0:0:0:0:0:0:1', true],
+                ['0:?:0:0:0:0:0:1', false]
+            ], done);
+        });
+    });
+
+    describe('#lowercase', function () {
+
+        it('only allows strings that are entirely lowercase', function (done) {
+
+            var schema = Joi.string().lowercase();
+            Helper.validateOptions(schema, [
+                ['this is all lowercase', true],
+                ['5', true],
+                ['lower\tcase', true],
+                ['Uppercase', false],
+                ['MixEd cAsE', false],
+                [1, false]
+            ], { convert: false }, done);
+        });
+
+        it('coerce string to lowercase before validation', function (done) {
+
+            var schema = Joi.string().lowercase();
+            schema.validate('UPPER TO LOWER', function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.equal('upper to lower');
+                done();
+            });
+        });
+
+        it('should work in combination with a trim', function (done) {
+
+            var schema = Joi.string().lowercase().trim();
+            Helper.validate(schema, [
+                [' abc', true],
+                [' ABC', true],
+                ['ABC', true],
+                [1, false]
+            ], done);
+        });
+
+        it('should work in combination with a replacement', function (done) {
+
+            var schema = Joi.string().lowercase().replace(/\s+/g, ' ');
+            Helper.validate(schema, [
+                ['a\r b\n c', true, null, 'a b c'],
+                ['A\t B  C', true, null, 'a b c'],
+                ['ABC', true, null, 'abc'],
+                [1, false]
+            ], done);
+        });
+    });
+
+    describe('#uppercase', function () {
+
+        it('only allow strings that are entirely uppercase', function (done) {
+
+            var schema = Joi.string().uppercase();
+            Helper.validateOptions(schema, [
+                ['THIS IS ALL UPPERCASE', true],
+                ['5', true],
+                ['UPPER\nCASE', true],
+                ['lOWERCASE', false],
+                ['MixEd cAsE', false],
+                [1, false]
+            ], { convert: false }, done);
+        });
+
+        it('coerce string to uppercase before validation', function (done) {
+
+            var schema = Joi.string().uppercase();
+            schema.validate('lower to upper', function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.equal('LOWER TO UPPER');
+                done();
+            });
+        });
+
+        it('works in combination with a forced trim', function (done) {
+
+            var schema = Joi.string().uppercase().trim();
+            Helper.validate(schema, [
+                [' abc', true],
+                [' ABC', true],
+                ['ABC', true],
+                [1, false]
+            ], done);
+        });
+
+        it('works in combination with a forced replacement', function (done) {
+
+            var schema = Joi.string().uppercase().replace(/\s+/g, ' ');
+            Helper.validate(schema, [
+                ['a\r b\n c', true, null, 'A B C'],
+                ['A\t B  C', true, null, 'A B C'],
+                ['ABC', true, null, 'ABC'],
+                [1, false]
+            ], done);
+        });
+    });
+
+    describe('#trim', function () {
+
+        it('only allow strings that have no leading or trailing whitespace', function (done) {
+
+            var schema = Joi.string().trim();
+            Helper.validateOptions(schema, [
+                [' something', false],
+                ['something ', false],
+                ['something\n', false],
+                ['some thing', true],
+                ['something', true]
+            ], { convert: false }, done);
+        });
+
+        it('removes leading and trailing whitespace before validation', function (done) {
+
+            var schema = Joi.string().trim();
+            schema.validate(' trim this ', function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.equal('trim this');
+                done();
+            });
+        });
+
+        it('removes leading and trailing whitespace before validation', function (done) {
+
+            var schema = Joi.string().trim().allow('');
+            schema.validate('     ', function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.equal('');
+                done();
+            });
+        });
+
+        it('should work in combination with min', function (done) {
+
+            var schema = Joi.string().min(4).trim();
+            Helper.validate(schema, [
+                [' a ', false],
+                ['abc ', false],
+                ['abcd ', true]
+            ], done);
+        });
+
+        it('should work in combination with max', function (done) {
+
+            var schema = Joi.string().max(4).trim();
+            Helper.validate(schema, [
+                [' abcde ', false],
+                ['abc ', true],
+                ['abcd ', true]
+            ], done);
+        });
+
+        it('should work in combination with length', function (done) {
+
+            var schema = Joi.string().length(4).trim();
+            Helper.validate(schema, [
+                [' ab ', false],
+                ['abc ', false],
+                ['abcd ', true]
+            ], done);
+        });
+
+        it('should work in combination with a case change', function (done) {
+
+            var schema = Joi.string().trim().lowercase();
+            Helper.validate(schema, [
+                [' abc', true],
+                [' ABC', true],
+                ['ABC', true]
+            ], done);
+        });
+    });
+
+    describe('#replace', function () {
+
+        it('successfully replaces the first occurrence of the expression', function (done) {
+
+            var schema = Joi.string().replace(/\s+/, ''); // no "g" flag
+            Helper.validateOptions(schema, [
+                ['\tsomething', true, null, 'something'],
+                ['something\r', true, null, 'something'],
+                ['something  ', true, null, 'something'],
+                ['some  thing', true, null, 'something'],
+                ['so me thing', true, null, 'some thing'] // first occurrence!
+            ], { convert: true }, done);
+        });
+
+        it('successfully replaces all occurrences of the expression', function (done) {
+
+            var schema = Joi.string().replace(/\s+/g, ''); // has "g" flag
+            Helper.validateOptions(schema, [
+                ['\tsomething', true, null, 'something'],
+                ['something\r', true, null, 'something'],
+                ['something  ', true, null, 'something'],
+                ['some  thing', true, null, 'something'],
+                ['so me thing', true, null, 'something']
+            ], { convert: true }, done);
+        });
+
+        it('successfully replaces all occurrences of a string pattern', function (done) {
+
+            var schema = Joi.string().replace('foo', 'X'); // has "g" flag
+            Helper.validateOptions(schema, [
+                ['foobarfoobazfoo', true, null, 'XbarXbazX']
+            ], { convert: true }, done);
+        });
+
+        it('successfully replaces multiple times', function (done) {
+
+            var schema = Joi.string().replace(/a/g, 'b').replace(/b/g, 'c');
+            schema.validate('a quick brown fox', function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.equal('c quick crown fox');
+                done();
+            });
+        });
+
+        it('should work in combination with trim', function (done) {
+
+            // The string below is the name "Yamada Tarou" separated by a
+            // carriage return, a "full width" ideographic space and a newline
+
+            var schema = Joi.string().trim().replace(/\s+/g, ' ');
+            schema.validate(' \u5C71\u7530\r\u3000\n\u592A\u90CE ', function (err, value) {
+
+                expect(err).to.not.exist();
+                expect(value).to.equal('\u5C71\u7530 \u592A\u90CE');
+                done();
+            });
+        });
+
+        it('should work in combination with min', function (done) {
+
+            var schema = Joi.string().min(4).replace(/\s+/g, ' ');
+            Helper.validate(schema, [
+                ['   a   ', false],
+                ['abc    ', true, null, 'abc '],
+                ['a\t\rbc', true, null, 'a bc']
+            ], done);
+        });
+
+        it('should work in combination with max', function (done) {
+
+            var schema = Joi.string().max(5).replace(/ CHANGE ME /g, '-b-');
+            Helper.validate(schema, [
+                ['a CHANGE ME c', true, null, 'a-b-c'],
+                ['a-b-c', true, null, 'a-b-c'] // nothing changes here!
+            ], done);
+        });
+
+        it('should work in combination with length', function (done) {
+
+            var schema = Joi.string().length(5).replace(/\s+/g, ' ');
+            Helper.validate(schema, [
+                ['a    bc', false],
+                ['a\tb\nc', true, null, 'a b c']
+            ], done);
+        });
+
+    });
+
+    describe('#regex', function () {
+
+        it('should not include a pattern name by default', function (done) {
+
+            var schema = Joi.string().regex(/[a-z]+/).regex(/[0-9]+/);
+            schema.validate('abcd', function (err, value) {
+
+                expect(err.message).to.contain('required pattern');
+                done();
+            });
+        });
+
+        it('should include a pattern name if specified', function (done) {
+
+            var schema = Joi.string().regex(/[a-z]+/, 'letters').regex(/[0-9]+/, 'numbers');
+            schema.validate('abcd', function (err, value) {
+
+                expect(err.message).to.contain('numbers pattern');
+                done();
+            });
+        });
+    });
+
+    describe('#ip', function () {
+
+        var invalidIPs = [
+                ['ASDF', false],
+                ['192.0.2.16:80/30', false],
+                ['192.0.2.16a', false],
+                ['qwerty', false],
+                ['127.0.0.1:8000', false],
+                ['ftp://www.example.com', false],
+                ['Bananas in pajamas are coming down the stairs', false]
+            ],
+            invalidIPv4s = [
+                ['0.0.0.0/33', false],
+                ['256.0.0.0/0', false],
+                ['255.255.255.256/32', false],
+                ['256.0.0.0', false],
+                ['255.255.255.256', false]
+            ],
+            invalidIPv6s = [
+                ['2001:db8::7/33', false],
+                ['1080:0:0:0:8:800:200C:417G', false]
+            ],
+            invalidIPvFutures = [
+                ['v1.09azAZ-._~!$&\'()*+,;=:/33', false],
+                ['v1.09#', false]
+            ],
+            validIPv4sWithCidr = function (success) {
+
+                return [
+                    ['0.0.0.0/32', success],
+                    ['255.255.255.255/0', success],
+                    ['127.0.0.1/0', success],
+                    ['192.168.2.1/0', success],
+                    ['0.0.0.3/2', success],
+                    ['0.0.0.7/3', success],
+                    ['0.0.0.15/4', success],
+                    ['0.0.0.31/5', success],
+                    ['0.0.0.63/6', success],
+                    ['0.0.0.127/7', success],
+                    ['01.020.030.100/7', success],
+                    ['0.0.0.0/0', success],
+                    ['00.00.00.00/0', success],
+                    ['000.000.000.000/32', success]
+                ];
+            },
+            validIPv4sWithoutCidr = function (success) {
+
+                return [
+                    ['0.0.0.0', success],
+                    ['255.255.255.255', success],
+                    ['127.0.0.1', success],
+                    ['192.168.2.1', success],
+                    ['0.0.0.3', success],
+                    ['0.0.0.7', success],
+                    ['0.0.0.15', success],
+                    ['0.0.0.31', success],
+                    ['0.0.0.63', success],
+                    ['0.0.0.127', success],
+                    ['01.020.030.100', success],
+                    ['0.0.0.0', success],
+                    ['00.00.00.00', success],
+                    ['000.000.000.000', success]
+                ];
+            },
+            validIPv6sWithCidr = function (success) {
+
+                return [
+                    ['2001:db8::7/32', success],
+                    ['a:b:c:d:e::1.2.3.4/13', success],
+                    ['FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/0', success],
+                    ['FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/32', success],
+                    ['1080:0:0:0:8:800:200C:417A/27', success]
+                ];
+            },
+            validIPv6sWithoutCidr = function (success) {
+
+                return [
+                    ['2001:db8::7', success],
+                    ['a:b:c:d:e::1.2.3.4', success],
+                    ['FEDC:BA98:7654:3210:FEDC:BA98:7654:3210', success],
+                    ['FEDC:BA98:7654:3210:FEDC:BA98:7654:3210', success],
+                    ['1080:0:0:0:8:800:200C:417A', success]
+                ];
+            },
+            validIPvFuturesWithCidr = function (success) {
+
+                return [
+                    ['v1.09azAZ-._~!$&\'()*+,;=:/32', success]
+                ];
+            },
+            validIPvFuturesWithoutCidr = function (success) {
+
+                return [
+                    ['v1.09azAZ-._~!$&\'()*+,;=:', success]
+                ];
+            };
+
+        it('should validate all ip addresses with optional CIDR by default', function (done) {
+
+            var schema = Joi.string().ip();
+            Helper.validate(schema, []
+                .concat(validIPv4sWithCidr(true))
+                .concat(validIPv4sWithoutCidr(true))
+                .concat(validIPv6sWithCidr(true))
+                .concat(validIPv6sWithoutCidr(true))
+                .concat(validIPvFuturesWithCidr(true))
+                .concat(validIPvFuturesWithoutCidr(true))
+                .concat(invalidIPs)
+                .concat(invalidIPv4s)
+                .concat(invalidIPv6s)
+                .concat(invalidIPvFutures), done);
+        });
+
+        it('should validate all ip addresses with an optional CIDR', function (done) {
+
+            var schema = Joi.string().ip({ cidr: 'optional' });
+            Helper.validate(schema, []
+                .concat(validIPv4sWithCidr(true))
+                .concat(validIPv4sWithoutCidr(true))
+                .concat(validIPv6sWithCidr(true))
+                .concat(validIPv6sWithoutCidr(true))
+                .concat(validIPvFuturesWithCidr(true))
+                .concat(validIPvFuturesWithoutCidr(true))
+                .concat(invalidIPs)
+                .concat(invalidIPv4s)
+                .concat(invalidIPv6s)
+                .concat(invalidIPvFutures), done);
+        });
+
+        it('should validate all ip addresses with a required CIDR', function (done) {
+
+            var schema = Joi.string().ip({ cidr: 'required' });
+            Helper.validate(schema, []
+                .concat(validIPv4sWithCidr(true))
+                .concat(validIPv4sWithoutCidr(false))
+                .concat(validIPv6sWithCidr(true))
+                .concat(validIPv6sWithoutCidr(false))
+                .concat(validIPvFuturesWithCidr(true))
+                .concat(validIPvFuturesWithoutCidr(false))
+                .concat(invalidIPs)
+                .concat(invalidIPv4s)
+                .concat(invalidIPv6s)
+                .concat(invalidIPvFutures), done);
+        });
+
+        it('should validate all ip addresses with a forbidden CIDR', function (done) {
+
+            var schema = Joi.string().ip({ cidr: 'forbidden' });
+            Helper.validate(schema, []
+                .concat(validIPv4sWithCidr(false))
+                .concat(validIPv4sWithoutCidr(true))
+                .concat(validIPv6sWithCidr(false))
+                .concat(validIPv6sWithoutCidr(true))
+                .concat(validIPvFuturesWithCidr(false))
+                .concat(validIPvFuturesWithoutCidr(true))
+                .concat(invalidIPs)
+                .concat(invalidIPv4s)
+                .concat(invalidIPv6s)
+                .concat(invalidIPvFutures), done);
+        });
+
+        it('throws when options is not an object', function (done) {
+
+            expect(function () {
+
+                Joi.string().ip(42);
+            }).to.throw('options must be an object');
+            done();
+        });
+
+        it('throws when options.cidr is not a string', function (done) {
+
+            expect(function () {
+
+                Joi.string().ip({ cidr: 42 });
+            }).to.throw('cidr must be a string');
+            done();
+        });
+
+        it('throws when options.cidr is not a valid value', function (done) {
+
+            expect(function () {
+
+                Joi.string().ip({ cidr: '42' });
+            }).to.throw('cidr must be one of required, optional, forbidden');
+            done();
+        });
+
+        it('throws when options.version is an empty array', function (done) {
+
+            expect(function () {
+
+                Joi.string().ip({ version: [] });
+            }).to.throw('version must have at least 1 version specified');
+            done();
+        });
+
+        it('throws when options.version is not a string', function (done) {
+
+            expect(function () {
+
+                Joi.string().ip({ version: 42 });
+            }).to.throw('version at position 0 must be a string');
+            done();
+        });
+
+        it('throws when options.version is not a valid value', function (done) {
+
+            expect(function () {
+
+                Joi.string().ip({ version: '42' });
+            }).to.throw('version at position 0 must be one of ipv4, ipv6, ipvfuture');
+            done();
+        });
+
+        it('validates ip with a friendly error message', function (done) {
+
+            var schema = { item: Joi.string().ip() };
+            Joi.compile(schema).validate({ item: 'something' }, function (err, value) {
+
+                expect(err.message).to.contain('must be a valid ip address');
+                done();
+            });
+        });
+
+        it('validates ip and cidr presence with a friendly error message', function (done) {
+
+            var schema = { item: Joi.string().ip({ cidr: 'required' }) };
+            Joi.compile(schema).validate({ item: 'something' }, function (err, value) {
+
+                expect(err.message).to.contain('must be a valid ip address with a required CIDR');
+                done();
+            });
+        });
+
+        it('validates custom ip version and cidr presence with a friendly error message', function (done) {
+
+            var schema = { item: Joi.string().ip({ version: 'ipv4', cidr: 'required' }) };
+            Joi.compile(schema).validate({ item: 'something' }, function (err, value) {
+
+                expect(err.message).to.contain('child "item" fails because ["item" must be a valid ip address of one of the following versions [ipv4] with a required CIDR]');
+                done();
+            });
+        });
+
+        describe('#ip({ version: "ipv4" })', function () {
+
+            it('should validate all ipv4 addresses with a default CIDR strategy', function (done) {
+
+                var schema = Joi.string().ip({ version: 'ipv4' });
+                Helper.validate(schema, []
+                    .concat(validIPv4sWithCidr(true))
+                    .concat(validIPv4sWithoutCidr(true))
+                    .concat(validIPv6sWithCidr(false))
+                    .concat(validIPv6sWithoutCidr(false))
+                    .concat(validIPvFuturesWithCidr(false))
+                    .concat(validIPvFuturesWithoutCidr(false))
+                    .concat(invalidIPs)
+                    .concat(invalidIPv4s)
+                    .concat(invalidIPv6s)
+                    .concat(invalidIPvFutures), done);
+            });
+
+            it('should validate all ipv4 addresses with an optional CIDR', function (done) {
+
+                var schema = Joi.string().ip({ version: 'ipv4', cidr: 'optional' });
+                Helper.validate(schema, []
+                    .concat(validIPv4sWithCidr(true))
+                    .concat(validIPv4sWithoutCidr(true))
+                    .concat(validIPv6sWithCidr(false))
+                    .concat(validIPv6sWithoutCidr(false))
+                    .concat(validIPvFuturesWithCidr(false))
+                    .concat(validIPvFuturesWithoutCidr(false))
+                    .concat(invalidIPs)
+                    .concat(invalidIPv4s)
+                    .concat(invalidIPv6s)
+                    .concat(invalidIPvFutures), done);
+            });
+
+            it('should validate all ipv4 addresses with a required CIDR', function (done) {
+
+                var schema = Joi.string().ip({ version: 'ipv4', cidr: 'required' });
+                Helper.validate(schema, []
+                    .concat(validIPv4sWithCidr(true))
+                    .concat(validIPv4sWithoutCidr(false))
+                    .concat(validIPv6sWithCidr(false))
+                    .concat(validIPv6sWithoutCidr(false))
+                    .concat(validIPvFuturesWithCidr(false))
+                    .concat(validIPvFuturesWithoutCidr(false))
+                    .concat(invalidIPs)
+                    .concat(invalidIPv4s)
+                    .concat(invalidIPv6s)
+                    .concat(invalidIPvFutures), done);
+            });
+
+            it('should validate all ipv4 addresses with a forbidden CIDR', function (done) {
+
+                var schema = Joi.string().ip({ version: 'ipv4', cidr: 'forbidden' });
+                Helper.validate(schema, []
+                    .concat(validIPv4sWithCidr(false))
+                    .concat(validIPv4sWithoutCidr(true))
+                    .concat(validIPv6sWithCidr(false))
+                    .concat(validIPv6sWithoutCidr(false))
+                    .concat(validIPvFuturesWithCidr(false))
+                    .concat(validIPvFuturesWithoutCidr(false))
+                    .concat(invalidIPs)
+                    .concat(invalidIPv4s)
+                    .concat(invalidIPv6s)
+                    .concat(invalidIPvFutures), done);
+            });
+        });
+
+        describe('#ip({ version: "ipv6" })', function () {
+
+            it('should validate all ipv6 addresses with a default CIDR strategy', function (done) {
+
+                var schema = Joi.string().ip({ version: 'ipv6' });
+                Helper.validate(schema, []
+                    .concat(validIPv4sWithCidr(false))
+                    .concat(validIPv4sWithoutCidr(false))
+                    .concat(validIPv6sWithCidr(true))
+                    .concat(validIPv6sWithoutCidr(true))
+                    .concat(validIPvFuturesWithCidr(false))
+                    .concat(validIPvFuturesWithoutCidr(false))
+                    .concat(invalidIPs)
+                    .concat(invalidIPv4s)
+                    .concat(invalidIPv6s)
+                    .concat(invalidIPvFutures), done);
+            });
+
+            it('should validate all ipv6 addresses with an optional CIDR', function (done) {
+
+                var schema = Joi.string().ip({ version: 'ipv6', cidr: 'optional' });
+                Helper.validate(schema, []
+                    .concat(validIPv4sWithCidr(false))
+                    .concat(validIPv4sWithoutCidr(false))
+                    .concat(validIPv6sWithCidr(true))
+                    .concat(validIPv6sWithoutCidr(true))
+                    .concat(validIPvFuturesWithCidr(false))
+                    .concat(validIPvFuturesWithoutCidr(false))
+                    .concat(invalidIPs)
+                    .concat(invalidIPv4s)
+                    .concat(invalidIPv6s)
+                    .concat(invalidIPvFutures), done);
+            });
+
+            it('should validate all ipv6 addresses with a required CIDR', function (done) {
+
+                var schema = Joi.string().ip({ version: 'ipv6', cidr: 'required' });
+                Helper.validate(schema, []
+                    .concat(validIPv4sWithCidr(false))
+                    .concat(validIPv4sWithoutCidr(false))
+                    .concat(validIPv6sWithCidr(true))
+                    .concat(validIPv6sWithoutCidr(false))
+                    .concat(validIPvFuturesWithCidr(false))
+                    .concat(validIPvFuturesWithoutCidr(false))
+                    .concat(invalidIPs)
+                    .concat(invalidIPv4s)
+                    .concat(invalidIPv6s)
+                    .concat(invalidIPvFutures), done);
+            });
+
+            it('should validate all ipv6 addresses with a forbidden CIDR', function (done) {
+
+                var schema = Joi.string().ip({ version: 'ipv6', cidr: 'forbidden' });
+                Helper.validate(schema, []
+                    .concat(validIPv4sWithCidr(false))
+                    .concat(validIPv4sWithoutCidr(false))
+                    .concat(validIPv6sWithCidr(false))
+                    .concat(validIPv6sWithoutCidr(true))
+                    .concat(validIPvFuturesWithCidr(false))
+                    .concat(validIPvFuturesWithoutCidr(false))
+                    .concat(invalidIPs)
+                    .concat(invalidIPv4s)
+                    .concat(invalidIPv6s)
+                    .concat(invalidIPvFutures), done);
+            });
+        });
+
+        describe('#ip({ version: "ipvfuture" })', function () {
+
+            it('should validate all ipvfuture addresses with a default CIDR strategy', function (done) {
+
+                var schema = Joi.string().ip({ version: 'ipvfuture' });
+                Helper.validate(schema, []
+                    .concat(validIPv4sWithCidr(false))
+                    .concat(validIPv4sWithoutCidr(false))
+                    .concat(validIPv6sWithCidr(false))
+                    .concat(validIPv6sWithoutCidr(false))
+                    .concat(validIPvFuturesWithCidr(true))
+                    .concat(validIPvFuturesWithoutCidr(true))
+                    .concat(invalidIPs)
+                    .concat(invalidIPv4s)
+                    .concat(invalidIPv6s)
+                    .concat(invalidIPvFutures), done);
+            });
+
+            it('should validate all ipvfuture addresses with an optional CIDR', function (done) {
+
+                var schema = Joi.string().ip({ version: 'ipvfuture', cidr: 'optional' });
+                Helper.validate(schema, []
+                    .concat(validIPv4sWithCidr(false))
+                    .concat(validIPv4sWithoutCidr(false))
+                    .concat(validIPv6sWithCidr(false))
+                    .concat(validIPv6sWithoutCidr(false))
+                    .concat(validIPvFuturesWithCidr(true))
+                    .concat(validIPvFuturesWithoutCidr(true))
+                    .concat(invalidIPs)
+                    .concat(invalidIPv4s)
+                    .concat(invalidIPv6s)
+                    .concat(invalidIPvFutures), done);
+            });
+
+            it('should validate all ipvfuture addresses with a required CIDR', function (done) {
+
+                var schema = Joi.string().ip({ version: 'ipvfuture', cidr: 'required' });
+                Helper.validate(schema, []
+                    .concat(validIPv4sWithCidr(false))
+                    .concat(validIPv4sWithoutCidr(false))
+                    .concat(validIPv6sWithCidr(false))
+                    .concat(validIPv6sWithoutCidr(false))
+                    .concat(validIPvFuturesWithCidr(true))
+                    .concat(validIPvFuturesWithoutCidr(false))
+                    .concat(invalidIPs)
+                    .concat(invalidIPv4s)
+                    .concat(invalidIPv6s)
+                    .concat(invalidIPvFutures), done);
+            });
+
+            it('should validate all ipvfuture addresses with a forbidden CIDR', function (done) {
+
+                var schema = Joi.string().ip({ version: 'ipvfuture', cidr: 'forbidden' });
+                Helper.validate(schema, []
+                    .concat(validIPv4sWithCidr(false))
+                    .concat(validIPv4sWithoutCidr(false))
+                    .concat(validIPv6sWithCidr(false))
+                    .concat(validIPv6sWithoutCidr(false))
+                    .concat(validIPvFuturesWithCidr(false))
+                    .concat(validIPvFuturesWithoutCidr(true))
+                    .concat(invalidIPs)
+                    .concat(invalidIPv4s)
+                    .concat(invalidIPv6s)
+                    .concat(invalidIPvFutures), done);
+            });
+        });
+
+        describe('#ip({ version: [ "ipv4", "ipv6" ] })', function () {
+
+            it('should validate all ipv4 and ipv6 addresses with a default CIDR strategy', function (done) {
+
+                var schema = Joi.string().ip({ version: ['ipv4', 'ipv6'] });
+                Helper.validate(schema, []
+                    .concat(validIPv4sWithCidr(true))
+                    .concat(validIPv4sWithoutCidr(true))
+                    .concat(validIPv6sWithCidr(true))
+                    .concat(validIPv6sWithoutCidr(true))
+                    .concat(validIPvFuturesWithCidr(false))
+                    .concat(validIPvFuturesWithoutCidr(false))
+                    .concat(invalidIPs)
+                    .concat(invalidIPv4s)
+                    .concat(invalidIPv6s)
+                    .concat(invalidIPvFutures), done);
+            });
+
+            it('should validate all ipv4 and ipv6 addresses with an optional CIDR', function (done) {
+
+                var schema = Joi.string().ip({ version: ['ipv4', 'ipv6'], cidr: 'optional' });
+                Helper.validate(schema, []
+                    .concat(validIPv4sWithCidr(true))
+                    .concat(validIPv4sWithoutCidr(true))
+                    .concat(validIPv6sWithCidr(true))
+                    .concat(validIPv6sWithoutCidr(true))
+                    .concat(validIPvFuturesWithCidr(false))
+                    .concat(validIPvFuturesWithoutCidr(false))
+                    .concat(invalidIPs)
+                    .concat(invalidIPv4s)
+                    .concat(invalidIPv6s)
+                    .concat(invalidIPvFutures), done);
+            });
+
+            it('should validate all ipv4 and ipv6 addresses with a required CIDR', function (done) {
+
+                var schema = Joi.string().ip({ version: ['ipv4', 'ipv6'], cidr: 'required' });
+                Helper.validate(schema, []
+                    .concat(validIPv4sWithCidr(true))
+                    .concat(validIPv4sWithoutCidr(false))
+                    .concat(validIPv6sWithCidr(true))
+                    .concat(validIPv6sWithoutCidr(false))
+                    .concat(validIPvFuturesWithCidr(false))
+                    .concat(validIPvFuturesWithoutCidr(false))
+                    .concat(invalidIPs)
+                    .concat(invalidIPv4s)
+                    .concat(invalidIPv6s)
+                    .concat(invalidIPvFutures), done);
+            });
+
+            it('should validate all ipv4 and ipv6 addresses with a forbidden CIDR', function (done) {
+
+                var schema = Joi.string().ip({ version: ['ipv4', 'ipv6'], cidr: 'forbidden' });
+                Helper.validate(schema, []
+                    .concat(validIPv4sWithCidr(false))
+                    .concat(validIPv4sWithoutCidr(true))
+                    .concat(validIPv6sWithCidr(false))
+                    .concat(validIPv6sWithoutCidr(true))
+                    .concat(validIPvFuturesWithCidr(false))
+                    .concat(validIPvFuturesWithoutCidr(false))
+                    .concat(invalidIPs)
+                    .concat(invalidIPv4s)
+                    .concat(invalidIPv6s)
+                    .concat(invalidIPvFutures), done);
+            });
+        });
+    });
+
+    describe('#validate', function () {
+
+        it('should, by default, allow undefined, deny empty string', function (done) {
+
+            Helper.validate(Joi.string(), [
+                [undefined, true],
+                ['', false]
+            ], done);
+        });
+
+        it('should, when .required(), deny undefined, deny empty string', function (done) {
+
+            Helper.validate(Joi.string().required(), [
+                [undefined, false],
+                ['', false]
+            ], done);
+        });
+
+        it('should, when .required(), print a friend error message for an empty string', function (done) {
+
+            var schema = Joi.string().required();
+            Joi.compile(schema).validate('', function (err, value) {
+
+                expect(err.message).to.contain('be empty');
+                done();
+            });
+        });
+
+        it('should, when .required(), validate non-empty strings', function (done) {
+
+            var schema = Joi.string().required();
+            Helper.validate(schema, [
+                ['test', true],
+                ['0', true],
+                [null, false]
+            ], done);
+        });
+
+        it('validates invalid values', function (done) {
+
+            var schema = Joi.string().invalid('a', 'b', 'c');
+            Helper.validate(schema, [
+                ['x', true],
+                ['a', false],
+                ['c', false]
+            ], done);
+        });
+
+        it('should invalidate invalid values', function (done) {
+
+            var schema = Joi.string().valid('a', 'b', 'c');
+            Helper.validate(schema, [
+                ['x', false],
+                ['a', true],
+                ['c', true]
+            ], done);
+        });
+
+        it('validates array arguments correctly', function (done) {
+
+            var schema = Joi.string().valid(['a', 'b', 'c']);
+            Helper.validate(schema, [
+                ['x', false],
+                ['a', true],
+                ['c', true]
+            ], done);
+        });
+
+        it('validates minimum length when min is used', function (done) {
+
+            var schema = Joi.string().min(3);
+            Helper.validate(schema, [
+                ['test', true],
+                ['0', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates minimum length when min is 0', function (done) {
+
+            var schema = Joi.string().min(0).required();
+            Helper.validate(schema, [
+                ['0', true],
+                [null, false],
+                [undefined, false]
+            ], done);
+        });
+
+        it('should return false with minimum length and a null value passed in', function (done) {
+
+            var schema = Joi.string().min(3);
+            Helper.validate(schema, [
+                [null, false]
+            ], done);
+        });
+
+        it('null allowed overrides min length requirement', function (done) {
+
+            var schema = Joi.string().min(3).allow(null);
+            Helper.validate(schema, [
+                [null, true]
+            ], done);
+        });
+
+        it('validates maximum length when max is used', function (done) {
+
+            var schema = Joi.string().max(3);
+            Helper.validate(schema, [
+                ['test', false],
+                ['0', true],
+                [null, false]
+            ], done);
+        });
+
+        it('should return true with max and not required when value is undefined', function (done) {
+
+            var schema = Joi.string().max(3);
+            Helper.validate(schema, [
+                [undefined, true]
+            ], done);
+        });
+
+        it('validates length requirements', function (done) {
+
+            var schema = Joi.string().length(3);
+            Helper.validate(schema, [
+                ['test', false],
+                ['0', false],
+                [null, false],
+                ['abc', true]
+            ], done);
+        });
+
+        it('validates regex', function (done) {
+
+            var schema = Joi.string().regex(/^[0-9][-][a-z]+$/);
+            Helper.validate(schema, [
+                ['van', false],
+                ['0-www', true]
+            ], done);
+        });
+
+        it('validates regex (ignoring global flag)', function (done) {
+
+            var schema = Joi.string().regex(/a/g);
+            Helper.validate(schema, [
+                ['ab', true],
+                ['ac', true]
+            ], done);
+        });
+
+        it('validates token', function (done) {
+
+            var schema = Joi.string().token();
+            Helper.validate(schema, [
+                ['w0rld_of_w4lm4rtl4bs', true],
+                ['w0rld of_w4lm4rtl4bs', false],
+                ['abcd#f?h1j orly?', false]
+            ], done);
+        });
+
+        it('validates alphanum', function (done) {
+
+            var schema = Joi.string().alphanum();
+            Helper.validate(schema, [
+                ['w0rld of w4lm4rtl4bs', false],
+                ['w0rldofw4lm4rtl4bs', true],
+                ['abcd#f?h1j orly?', false]
+            ], done);
+        });
+
+        it('validates email', function (done) {
+
+            var schema = Joi.string().email();
+            Helper.validate(schema, [
+                ['joe@example.com', true],
+                ['"joe"@example.com', true],
+                ['@iaminvalid.com', false],
+                ['joe@[IPv6:2a00:1450:4001:c02::1b]', true],
+                ['12345678901234567890123456789012345678901234567890123456789012345@walmartlabs.com', false],
+                ['123456789012345678901234567890123456789012345678901234567890@12345678901234567890123456789012345678901234567890123456789.12345678901234567890123456789012345678901234567890123456789.12345678901234567890123456789012345678901234567890123456789.12345.toolong.com', false]
+            ], done);
+        });
+
+        it('validates email with tldWhitelist as array', function (done) {
+
+            var schema = Joi.string().email({ tldWhitelist: ['com', 'org'] });
+            Helper.validate(schema, [
+                ['joe@example.com', true],
+                ['joe@example.org', true],
+                ['joe@example.edu', false]
+            ], done);
+        });
+
+        it('validates email with tldWhitelist as object', function (done) {
+
+            var schema = Joi.string().email({ tldWhitelist: { com: true, org: true } });
+            Helper.validate(schema, [
+                ['joe@example.com', true],
+                ['joe@example.org', true],
+                ['joe@example.edu', false]
+            ], done);
+        });
+
+        it('validates email with minDomainAtoms', function (done) {
+
+            var schema = Joi.string().email({ minDomainAtoms: 4 });
+            Helper.validate(schema, [
+                ['joe@example.com', false],
+                ['joe@www.example.com', false],
+                ['joe@sub.www.example.com', true]
+            ], done);
+        });
+
+        it('validates email with errorLevel as boolean', function (done) {
+
+            var schema = Joi.string().email({ errorLevel: false });
+            Helper.validate(schema, [
+                ['joe@example.com', true],
+                ['joe@www.example.com', true],
+                ['joe@localhost', true],
+                ['joe', false]
+            ]);
+
+            schema = Joi.string().email({ errorLevel: true });
+            Helper.validate(schema, [
+                ['joe@example.com', true],
+                ['joe@www.example.com', true],
+                ['joe@localhost', false],
+                ['joe', false]
+            ], done);
+        });
+
+        it('validates email with errorLevel as integer', function (done) {
+
+            var schema = Joi.string().email({ errorLevel: 10 });
+            Helper.validate(schema, [
+                ['joe@example.com', true],
+                ['joe@www.example.com', true],
+                ['joe@localhost', true],
+                ['joe', false]
+            ], done);
+        });
+
+        it('validates email with a friendly error message', function (done) {
+
+            var schema = { item: Joi.string().email() };
+            Joi.compile(schema).validate({ item: 'something' }, function (err, value) {
+
+                expect(err.message).to.contain('must be a valid email');
+                done();
+            });
+        });
+
+        it('should return false for denied value', function (done) {
+
+            var text = Joi.string().invalid('joi');
+            text.validate('joi', function (err, value) {
+
+                expect(err).to.exist();
+                done();
+            });
+        });
+
+        it('should return true for allowed value', function (done) {
+
+            var text = Joi.string().allow('hapi');
+            text.validate('result', function (err, value) {
+
+                expect(err).to.not.exist();
+                done();
+            });
+        });
+
+        it('validates with one validator (min)', function (done) {
+
+            var text = Joi.string().min(3);
+            text.validate('joi', function (err, value) {
+
+                expect(err).to.not.exist();
+                done();
+            });
+        });
+
+        it('validates with two validators (min, required)', function (done) {
+
+            var text = Joi.string().min(3).required();
+            text.validate('joi', function (err, value) {
+
+                expect(err).to.not.exist();
+
+                text.validate('', function (err2, value2) {
+
+                    expect(err2).to.exist();
+                    done();
+                });
+            });
+        });
+
+        it('validates null with allow(null)', function (done) {
+
+            Helper.validate(Joi.string().allow(null), [
+                [null, true]
+            ], done);
+        });
+
+        it('validates "" (empty string) with allow(\'\')', function (done) {
+
+            Helper.validate(Joi.string().allow(''), [
+                ['', true],
+                ['', true]
+            ], done);
+        });
+
+        it('validates combination of required and min', function (done) {
+
+            var rule = Joi.string().required().min(3);
+            Helper.validate(rule, [
+                ['x', false],
+                ['123', true],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of required and max', function (done) {
+
+            var rule = Joi.string().required().max(3);
+            Helper.validate(rule, [
+                ['x', true],
+                ['123', true],
+                ['1234', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of allow(\'\') and min', function (done) {
+
+            var rule = Joi.string().allow('').min(3);
+            Helper.validate(rule, [
+                ['x', false],
+                ['123', true],
+                ['1234', true],
+                ['', true],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of allow(\'\') and max', function (done) {
+
+            var rule = Joi.string().allow('').max(3);
+            Helper.validate(rule, [
+                ['x', true],
+                ['123', true],
+                ['1234', false],
+                ['', true],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of null allowed and max', function (done) {
+
+            var rule = Joi.string().allow(null).max(3);
+            Helper.validate(rule, [
+                ['x', true],
+                ['123', true],
+                ['1234', false],
+                ['', false],
+                [null, true]
+            ], done);
+        });
+
+        it('validates combination of min and max', function (done) {
+
+            var rule = Joi.string().min(2).max(3);
+            Helper.validate(rule, [
+                ['x', false],
+                ['123', true],
+                ['1234', false],
+                ['12', true],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of min, max, and allow(\'\')', function (done) {
+
+            var rule = Joi.string().min(2).max(3).allow('');
+            Helper.validate(rule, [
+                ['x', false],
+                ['123', true],
+                ['1234', false],
+                ['12', true],
+                ['', true],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of min, max, and required', function (done) {
+
+            var rule = Joi.string().min(2).max(3).required();
+            Helper.validate(rule, [
+                ['x', false],
+                ['123', true],
+                ['1234', false],
+                ['12', true],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of min, max, and regex', function (done) {
+
+            var rule = Joi.string().min(2).max(3).regex(/^a/);
+            Helper.validate(rule, [
+                ['x', false],
+                ['123', false],
+                ['1234', false],
+                ['12', false],
+                ['ab', true],
+                ['abc', true],
+                ['abcd', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of min, max, regex, and allow(\'\')', function (done) {
+
+            var rule = Joi.string().min(2).max(3).regex(/^a/).allow('');
+            Helper.validate(rule, [
+                ['x', false],
+                ['123', false],
+                ['1234', false],
+                ['12', false],
+                ['ab', true],
+                ['abc', true],
+                ['abcd', false],
+                ['', true],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of min, max, regex, and required', function (done) {
+
+            var rule = Joi.string().min(2).max(3).regex(/^a/).required();
+            Helper.validate(rule, [
+                ['x', false],
+                ['123', false],
+                ['1234', false],
+                ['12', false],
+                ['ab', true],
+                ['abc', true],
+                ['abcd', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of min, max, and alphanum', function (done) {
+
+            var rule = Joi.string().min(2).max(3).alphanum();
+            Helper.validate(rule, [
+                ['x', false],
+                ['123', true],
+                ['1234', false],
+                ['12', true],
+                ['ab', true],
+                ['abc', true],
+                ['abcd', false],
+                ['*ab', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of min, max, alphanum, and allow(\'\')', function (done) {
+
+            var rule = Joi.string().min(2).max(3).alphanum().allow('');
+            Helper.validate(rule, [
+                ['x', false],
+                ['123', true],
+                ['1234', false],
+                ['12', true],
+                ['ab', true],
+                ['abc', true],
+                ['abcd', false],
+                ['*ab', false],
+                ['', true],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of min, max, alphanum, and required', function (done) {
+
+            var rule = Joi.string().min(2).max(3).alphanum().required();
+            Helper.validate(rule, [
+                ['x', false],
+                ['123', true],
+                ['1234', false],
+                ['12', true],
+                ['ab', true],
+                ['abc', true],
+                ['abcd', false],
+                ['*ab', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of min, max, alphanum, and regex', function (done) {
+
+            var rule = Joi.string().min(2).max(3).alphanum().regex(/^a/);
+            Helper.validate(rule, [
+                ['x', false],
+                ['123', false],
+                ['1234', false],
+                ['12', false],
+                ['ab', true],
+                ['abc', true],
+                ['a2c', true],
+                ['abcd', false],
+                ['*ab', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of min, max, alphanum, required, and regex', function (done) {
+
+            var rule = Joi.string().min(2).max(3).alphanum().required().regex(/^a/);
+            Helper.validate(rule, [
+                ['x', false],
+                ['123', false],
+                ['1234', false],
+                ['12', false],
+                ['ab', true],
+                ['abc', true],
+                ['a2c', true],
+                ['abcd', false],
+                ['*ab', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of min, max, alphanum, allow(\'\'), and regex', function (done) {
+
+            var rule = Joi.string().min(2).max(3).alphanum().allow('').regex(/^a/);
+            Helper.validate(rule, [
+                ['x', false],
+                ['123', false],
+                ['1234', false],
+                ['12', false],
+                ['ab', true],
+                ['abc', true],
+                ['a2c', true],
+                ['abcd', false],
+                ['*ab', false],
+                ['', true],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of email and min', function (done) {
+
+            var rule = Joi.string().email().min(8);
+            Helper.validate(rule, [
+                ['x@x.com', false],
+                ['123@x.com', true],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of email, min, and max', function (done) {
+
+            var rule = Joi.string().email().min(8).max(10);
+            Helper.validate(rule, [
+                ['x@x.com', false],
+                ['123@x.com', true],
+                ['1234@x.com', true],
+                ['12345@x.com', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of email, min, max, and invalid', function (done) {
+
+            var rule = Joi.string().email().min(8).max(10).invalid('123@x.com');
+            Helper.validate(rule, [
+                ['x@x.com', false],
+                ['123@x.com', false],
+                ['1234@x.com', true],
+                ['12345@x.com', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of email, min, max, and allow', function (done) {
+
+            var rule = Joi.string().email().min(8).max(10).allow('x@x.com');
+            Helper.validate(rule, [
+                ['x@x.com', true],
+                ['123@x.com', true],
+                ['1234@x.com', true],
+                ['12345@x.com', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of email, min, max, allow, and invalid', function (done) {
+
+            var rule = Joi.string().email().min(8).max(10).allow('x@x.com').invalid('123@x.com');
+            Helper.validate(rule, [
+                ['x@x.com', true],
+                ['123@x.com', false],
+                ['1234@x.com', true],
+                ['12345@x.com', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of email, min, max, allow, invalid, and allow(\'\')', function (done) {
+
+            var rule = Joi.string().email().min(8).max(10).allow('x@x.com').invalid('123@x.com').allow('');
+            Helper.validate(rule, [
+                ['x@x.com', true],
+                ['123@x.com', false],
+                ['1234@x.com', true],
+                ['12345@x.com', false],
+                ['', true],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of email, min, max, allow, and allow(\'\')', function (done) {
+
+            var rule = Joi.string().email().min(8).max(10).allow('x@x.com').allow('');
+            Helper.validate(rule, [
+                ['x@x.com', true],
+                ['123@x.com', true],
+                ['1234@x.com', true],
+                ['12345@x.com', false],
+                ['', true],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of email, min, max, allow, invalid, and regex', function (done) {
+
+            var rule = Joi.string().email().min(8).max(10).allow('x@x.com').invalid('123@x.com').regex(/^1/);
+            Helper.validate(rule, [
+                ['x@x.com', true],
+                ['123@x.com', false],
+                ['1234@x.com', true],
+                ['12345@x.com', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of email, min, max, allow, invalid, regex, and allow(\'\')', function (done) {
+
+            var rule = Joi.string().email().min(8).max(10).allow('x@x.com').invalid('123@x.com').regex(/^1/).allow('');
+            Helper.validate(rule, [
+                ['x@x.com', true],
+                ['123@x.com', false],
+                ['1234@x.com', true],
+                ['12345@x.com', false],
+                ['', true],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of email, min, max, and allow(\'\')', function (done) {
+
+            var rule = Joi.string().email().min(8).max(10).allow('');
+            Helper.validate(rule, [
+                ['x@x.com', false],
+                ['123@x.com', true],
+                ['1234@x.com', true],
+                ['12345@x.com', false],
+                ['', true],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of email, min, max, and regex', function (done) {
+
+            var rule = Joi.string().email().min(8).max(10).regex(/^1234/);
+            Helper.validate(rule, [
+                ['x@x.com', false],
+                ['123@x.com', false],
+                ['1234@x.com', true],
+                ['12345@x.com', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of email, min, max, regex, and allow(\'\')', function (done) {
+
+            var rule = Joi.string().email().min(8).max(10).regex(/^1234/).allow('');
+            Helper.validate(rule, [
+                ['x@x.com', false],
+                ['123@x.com', false],
+                ['1234@x.com', true],
+                ['12345@x.com', false],
+                ['', true],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of email, min, max, regex, and required', function (done) {
+
+            var rule = Joi.string().email().min(8).max(10).regex(/^1234/).required();
+            Helper.validate(rule, [
+                ['x@x.com', false],
+                ['123@x.com', false],
+                ['1234@x.com', true],
+                ['12345@x.com', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates uri', function (done) {
+
+            // Handful of tests taken from Node: https://github.com/joyent/node/blob/cfcb1de130867197cbc9c6012b7e84e08e53d032/test/simple/test-url.js
+            // Also includes examples from RFC 8936: http://tools.ietf.org/html/rfc3986#page-7
+            var schema = Joi.string().uri();
+
+            Helper.validate(schema, [
+                ['foo://example.com:8042/over/there?name=ferret#nose', true],
+                ['urn:example:animal:ferret:nose', true],
+                ['ftp://ftp.is.co.za/rfc/rfc1808.txt', true],
+                ['http://www.ietf.org/rfc/rfc2396.txt', true],
+                ['ldap://[2001:db8::7]/c=GB?objectClass?one', true],
+                ['mailto:John.Doe@example.com', true],
+                ['news:comp.infosystems.www.servers.unix', true],
+                ['tel:+1-816-555-1212', true],
+                ['telnet://192.0.2.16:80/', true],
+                ['urn:oasis:names:specification:docbook:dtd:xml:4.1.2', true],
+                ['file:///example.txt', true],
+                ['http://asdf:qw%20er@localhost:8000?asdf=12345&asda=fc%2F#bacon', true],
+                ['http://asdf@localhost:8000', true],
+                ['http://[v1.09azAZ-._~!$&\'()*+,;=:]', true],
+                ['http://[a:b:c:d:e::1.2.3.4]', true],
+                ['coap://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]', true],
+                ['http://[1080:0:0:0:8:800:200C:417A]', true],
+                ['http://127.0.0.1:8000/foo?bar', true],
+                ['http://asdf:qwer@localhost:8000', true],
+                ['http://user:pass%3A@localhost:80', true],
+                ['http://localhost:123', true],
+                ['https://localhost:123', true],
+                ['file:///whatever', true],
+                ['mailto:asdf@asdf.com', true],
+                ['ftp://www.example.com', true],
+                ['javascript:alert(\'hello\');', true], // eslint-disable-line no-script-url
+                ['xmpp:isaacschlueter@jabber.org', true],
+                ['f://some.host/path', true],
+                ['http://localhost:18/asdf', true],
+                ['http://localhost:42/asdf?qwer=zxcv', true],
+                ['HTTP://www.example.com/', true],
+                ['HTTP://www.example.com', true],
+                ['http://www.ExAmPlE.com/', true],
+                ['http://user:pw@www.ExAmPlE.com/', true],
+                ['http://USER:PW@www.ExAmPlE.com/', true],
+                ['http://user@www.example.com/', true],
+                ['http://user%3Apw@www.example.com/', true],
+                ['http://x.com/path?that%27s#all,%20folks', true],
+                ['HTTP://X.COM/Y', true],
+                ['http://www.narwhaljs.org/blog/categories?id=news', true],
+                ['http://mt0.google.com/vt/lyrs=m@114&hl=en&src=api&x=2&y=2&z=3&s=', true],
+                ['http://mt0.google.com/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s=', true],
+                ['http://user:pass@mt0.google.com/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s=', true],
+                ['http://_jabber._tcp.google.com:80/test', true],
+                ['http://user:pass@_jabber._tcp.google.com:80/test', true],
+                ['http://[fe80::1]/a/b?a=b#abc', true],
+                ['http://user:password@[3ffe:2a00:100:7031::1]:8080', true],
+                ['coap://[1080:0:0:0:8:800:200C:417A]:61616/', true],
+                ['git+http://github.com/joyent/node.git', true],
+                ['http://bucket_name.s3.amazonaws.com/image.jpg', true],
+                ['dot.test://foo/bar', true],
+                ['svn+ssh://foo/bar', true],
+                ['dash-test://foo/bar', true],
+                ['xmpp:isaacschlueter@jabber.org', true],
+                ['http://atpass:foo%40bar@127.0.0.1:8080/path?search=foo#bar', true],
+                ['javascript:alert(\'hello\');', true], // eslint-disable-line no-script-url
+                ['file://localhost/etc/node/', true],
+                ['file:///etc/node/', true],
+                ['http://USER:PW@www.ExAmPlE.com/', true],
+                ['mailto:local1@domain1?query1', true],
+                ['http://example/a/b?c/../d', true],
+                ['http://example/x%2Fabc', true],
+                ['http://a/b/c/d;p=1/g;x=1/y', true],
+                ['http://a/b/c/g#s/../x', true],
+                ['http://a/b/c/.foo', true],
+                ['http://example.com/b//c//d;p?q#blarg', true],
+                ['g:h', true],
+                ['http://a/b/c/g', true],
+                ['http://a/b/c/g/', true],
+                ['http://a/g', true],
+                ['http://g', true],
+                ['http://a/b/c/d;p?y', true],
+                ['http://a/b/c/g?y', true],
+                ['http://a/b/c/d;p?q#s', true],
+                ['http://a/b/c/g#s', true],
+                ['http://a/b/c/g?y#s', true],
+                ['http://a/b/c/;x', true],
+                ['http://a/b/c/g;x', true],
+                ['http://a/b/c/g;x?y#s', true],
+                ['http://a/b/c/d;p?q', true],
+                ['http://a/b/c/', true],
+                ['http://a/b/', true],
+                ['http://a/b/g', true],
+                ['http://a/', true],
+                ['http://a/g', true],
+                ['http://a/g', true],
+                ['file:/asda', true],
+                ['qwerty', false],
+                ['invalid uri', false],
+                ['1http://google.com', false],
+                ['http://testdomain`,.<>/?\'";{}][++\\|~!@#$%^&*().org', false],
+                ['', false],
+                ['(╯°□°)╯︵ ┻━┻', false],
+                ['one/two/three?value=abc&value2=123#david-rules', false],
+                ['//username:password@test.example.com/one/two/three?value=abc&value2=123#david-rules', false],
+                ['http://a\r" \t\n<\'b:b@c\r\nd/e?f', false]
+            ], done);
+        });
+
+        it('validates uri with a single scheme provided', function (done) {
+
+            var schema = Joi.string().uri({
+                scheme: 'http'
+            });
+
+            Helper.validate(schema, [
+                ['http://google.com', true],
+                ['https://google.com', false],
+                ['ftp://google.com', false],
+                ['file:/asdf', false],
+                ['/path?query=value#hash', false]
+            ], done);
+        });
+
+        it('validates uri with a single regex scheme provided', function (done) {
+
+            var schema = Joi.string().uri({
+                scheme: /https?/
+            });
+
+            Helper.validate(schema, [
+                ['http://google.com', true],
+                ['https://google.com', true],
+                ['ftp://google.com', false],
+                ['file:/asdf', false],
+                ['/path?query=value#hash', false]
+            ], done);
+        });
+
+        it('validates uri with multiple schemes provided', function (done) {
+
+            var schema = Joi.string().uri({
+                scheme: [/https?/, 'ftp', 'file', 'git+http']
+            });
+
+            Helper.validate(schema, [
+                ['http://google.com', true],
+                ['https://google.com', true],
+                ['ftp://google.com', true],
+                ['file:/asdf', true],
+                ['git+http://github.com/hapijs/joi', true],
+                ['/path?query=value#hash', false]
+            ], done);
+        });
+
+        it('validates uri with a friendly error message', function (done) {
+
+            var schema = { item: Joi.string().uri() };
+
+            Joi.compile(schema).validate({ item: 'something invalid' }, function (err, value) {
+
+                expect(err.message).to.contain('must be a valid uri');
+                done();
+            });
+        });
+
+        it('validates uri with a custom scheme with a friendly error message', function (done) {
+
+            var schema = {
+                item: Joi.string().uri({
+                    scheme: 'http'
+                })
+            };
+
+            Joi.compile(schema).validate({ item: 'something invalid' }, function (err, value) {
+
+                expect(err.message).to.contain('must be a valid uri with a scheme matching the http pattern');
+                done();
+            });
+        });
+
+        it('validates uri with a custom array of schemes with a friendly error message', function (done) {
+
+            var schema = {
+                item: Joi.string().uri({
+                    scheme: ['http', /https?/]
+                })
+            };
+
+            Joi.compile(schema).validate({ item: 'something invalid' }, function (err, value) {
+
+                expect(err.message).to.contain('must be a valid uri with a scheme matching the http|https? pattern');
+                done();
+            });
+        });
+
+        it('validates uri treats scheme as optional', function (done) {
+
+            expect(function () {
+
+                Joi.string().uri({});
+            }).to.not.throw();
+
+            done();
+        });
+
+        it('validates uri requires uriOptions as an object with a friendly error message', function (done) {
+
+            expect(function () {
+
+                Joi.string().uri('http');
+            }).to.throw(Error, 'options must be an object');
+
+            done();
+        });
+
+        it('validates uri requires scheme to be a RegExp, String, or Array with a friendly error message', function (done) {
+
+            expect(function () {
+
+                Joi.string().uri({
+                    scheme: {}
+                });
+            }).to.throw(Error, 'scheme must be a RegExp, String, or Array');
+
+            done();
+        });
+
+        it('validates uri requires scheme to not be an empty array', function (done) {
+
+            expect(function () {
+
+                Joi.string().uri({
+                    scheme: []
+                });
+            }).to.throw(Error, 'scheme must have at least 1 scheme specified');
+
+            done();
+        });
+
+        it('validates uri requires scheme to be an Array of schemes to all be valid schemes with a friendly error message', function (done) {
+
+            expect(function () {
+
+                Joi.string().uri({
+                    scheme: [
+                        'http',
+                        '~!@#$%^&*()_'
+                    ]
+                });
+            }).to.throw(Error, 'scheme at position 1 must be a valid scheme');
+
+            done();
+        });
+
+        it('validates uri requires scheme to be an Array of schemes to be strings or RegExp', function (done) {
+
+            expect(function () {
+
+                Joi.string().uri({
+                    scheme: [
+                        'http',
+                        {}
+                    ]
+                });
+            }).to.throw(Error, 'scheme at position 1 must be a RegExp or String');
+
+            done();
+        });
+
+        it('validates uri requires scheme to be a valid String scheme with a friendly error message', function (done) {
+
+            expect(function () {
+
+                Joi.string().uri({
+                    scheme: '~!@#$%^&*()_'
+                });
+            }).to.throw(Error, 'scheme at position 0 must be a valid scheme');
+
+            done();
+        });
+
+        it('validates isoDate', function (done) {
+
+            Helper.validate(Joi.string().isoDate(), [
+                ['2013-06-07T14:21:46.295Z', true],
+                ['2013-06-07T14:21:46.295Z0', false],
+                ['2013-06-07T14:21:46.295+07:00', true],
+                ['2013-06-07T14:21:46.295+07:000', false],
+                ['2013-06-07T14:21:46.295-07:00', true],
+                ['2013-06-07T14:21:46Z', true],
+                ['2013-06-07T14:21:46Z0', false],
+                ['2013-06-07T14:21:46+07:00', true],
+                ['2013-06-07T14:21:46+07:000', false],
+                ['2013-06-07T14:21:46-07:00', true],
+                ['2013-06-07T14:21Z', true],
+                ['2013-06-07T14:21+07:00', true],
+                ['2013-06-07T14:21+07:000', false],
+                ['2013-06-07T14:21-07:00', true],
+                ['2013-06-07T14:21Z+7:00', false],
+                ['2013-06-07', true],
+                ['2013-06-07T', false],
+                ['2013-06-07T14:21', true],
+                ['1-1-2013', false],
+                ['2013-06-07T14.2334,4', true],
+                ['2013-06-07T14,23:34', false],
+                ['2013-06-07T24', false],
+                ['2013-06-07T24:00', true],
+                ['2013-06-07T24:21', false],
+                ['2013-06-07 142146.295', true],
+                ['2013-06-07 146946.295', false],
+                ['2013-06-07 1421,44', true],
+                ['2013-W23', true],
+                ['2013-W23-1', true],
+                ['2013-W2311', false],
+                ['2013-W231', true],
+                ['2013-M231', false],
+                ['2013-W23-1T14:21', true],
+                ['2013-W23-1T14:21:', false],
+                ['2013-W23-1T14:21:46+07:00', true],
+                ['2013-W23-1T14:21:46+07:000', false],
+                ['2013-W23-1T14:21:46-07:00', true],
+                ['2013-184', true],
+                ['2013-1841', false]
+            ], done);
+        });
+
+        it('validates isoDate with a friendly error message', function (done) {
+
+            var schema = { item: Joi.string().isoDate() };
+            Joi.compile(schema).validate({ item: 'something' }, function (err, value) {
+
+                expect(err.message).to.contain('must be a valid ISO 8601 date');
+                done();
+            });
+        });
+
+        it('validates combination of isoDate and min', function (done) {
+
+            var rule = Joi.string().isoDate().min(23);
+            Helper.validate(rule, [
+                ['2013-06-07T14:21:46.295Z', true],
+                ['2013-06-07T14:21:46.295Z0', false],
+                ['2013-06-07T14:21:46.295+07:00', true],
+                ['2013-06-07T14:21:46.295+07:000', false],
+                ['2013-06-07T14:21:46.295-07:00', true],
+                ['2013-06-07T14:21:46Z', false],
+                ['2013-06-07T14:21:46Z0', false],
+                ['2013-06-07T14:21:46+07:00', true],
+                ['2013-06-07T14:21:46-07:00', true],
+                ['2013-06-07T14:21Z', false],
+                ['2013-06-07T14:21+07:00', false],
+                ['2013-06-07T14:21+07:000', false],
+                ['2013-06-07T14:21-07:00', false],
+                ['2013-06-07T14:21Z+7:00', false],
+                ['2013-06-07', false],
+                ['2013-06-07T', false],
+                ['2013-06-07T14:21', false],
+                ['1-1-2013', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of isoDate, min and max', function (done) {
+
+            var rule = Joi.string().isoDate().min(17).max(23);
+            Helper.validate(rule, [
+                ['2013-06-07T14:21:46.295Z', false],
+                ['2013-06-07T14:21:46.295Z0', false],
+                ['2013-06-07T14:21:46.295+07:00', false],
+                ['2013-06-07T14:21:46.295+07:000', false],
+                ['2013-06-07T14:21:46.295-07:00', false],
+                ['2013-06-07T14:21:46Z', true],
+                ['2013-06-07T14:21:46Z0', false],
+                ['2013-06-07T14:21:46+07:00', false],
+                ['2013-06-07T14:21:46-07:00', false],
+                ['2013-06-07T14:21Z', true],
+                ['2013-06-07T14:21+07:00', true],
+                ['2013-06-07T14:21+07:000', false],
+                ['2013-06-07T14:21-07:00', true],
+                ['2013-06-07T14:21Z+7:00', false],
+                ['2013-06-07', false],
+                ['2013-06-07T', false],
+                ['2013-06-07T14:21', false],
+                ['1-1-2013', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of isoDate, min, max and invalid', function (done) {
+
+            var rule = Joi.string().isoDate().min(17).max(23).invalid('2013-06-07T14:21+07:00');
+            Helper.validate(rule, [
+                ['2013-06-07T14:21:46.295Z', false],
+                ['2013-06-07T14:21:46.295Z0', false],
+                ['2013-06-07T14:21:46.295+07:00', false],
+                ['2013-06-07T14:21:46.295+07:000', false],
+                ['2013-06-07T14:21:46.295-07:00', false],
+                ['2013-06-07T14:21:46Z', true],
+                ['2013-06-07T14:21:46Z0', false],
+                ['2013-06-07T14:21:46+07:00', false],
+                ['2013-06-07T14:21:46-07:00', false],
+                ['2013-06-07T14:21Z', true],
+                ['2013-06-07T14:21+07:00', false],
+                ['2013-06-07T14:21+07:000', false],
+                ['2013-06-07T14:21-07:00', true],
+                ['2013-06-07T14:21Z+7:00', false],
+                ['2013-06-07', false],
+                ['2013-06-07T', false],
+                ['2013-06-07T14:21', false],
+                ['1-1-2013', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of isoDate, min, max and allow', function (done) {
+
+            var rule = Joi.string().isoDate().min(17).max(23).allow('2013-06-07T14:21:46.295+07:00');
+            Helper.validate(rule, [
+                ['2013-06-07T14:21:46.295Z', false],
+                ['2013-06-07T14:21:46.295Z0', false],
+                ['2013-06-07T14:21:46.295+07:00', true],
+                ['2013-06-07T14:21:46.295+07:000', false],
+                ['2013-06-07T14:21:46.295-07:00', false],
+                ['2013-06-07T14:21:46Z', true],
+                ['2013-06-07T14:21:46Z0', false],
+                ['2013-06-07T14:21:46+07:00', false],
+                ['2013-06-07T14:21:46-07:00', false],
+                ['2013-06-07T14:21Z', true],
+                ['2013-06-07T14:21+07:00', true],
+                ['2013-06-07T14:21+07:000', false],
+                ['2013-06-07T14:21-07:00', true],
+                ['2013-06-07T14:21Z+7:00', false],
+                ['2013-06-07', false],
+                ['2013-06-07T', false],
+                ['2013-06-07T14:21', false],
+                ['1-1-2013', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of isoDate, min, max, allow and invalid', function (done) {
+
+            var rule = Joi.string().isoDate().min(17).max(23).allow('2013-06-07T14:21:46.295+07:00').invalid('2013-06-07T14:21+07:00');
+            Helper.validate(rule, [
+                ['2013-06-07T14:21:46.295Z', false],
+                ['2013-06-07T14:21:46.295Z0', false],
+                ['2013-06-07T14:21:46.295+07:00', true],
+                ['2013-06-07T14:21:46.295+07:000', false],
+                ['2013-06-07T14:21:46.295-07:00', false],
+                ['2013-06-07T14:21:46Z', true],
+                ['2013-06-07T14:21:46Z0', false],
+                ['2013-06-07T14:21:46+07:00', false],
+                ['2013-06-07T14:21:46-07:00', false],
+                ['2013-06-07T14:21Z', true],
+                ['2013-06-07T14:21+07:00', false],
+                ['2013-06-07T14:21+07:000', false],
+                ['2013-06-07T14:21-07:00', true],
+                ['2013-06-07T14:21Z+7:00', false],
+                ['2013-06-07', false],
+                ['2013-06-07T', false],
+                ['2013-06-07T14:21', false],
+                ['1-1-2013', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of isoDate, min, max, allow, invalid and allow(\'\')', function (done) {
+
+            var rule = Joi.string().isoDate().min(17).max(23).allow('2013-06-07T14:21:46.295+07:00').invalid('2013-06-07T14:21+07:00').allow('');
+            Helper.validate(rule, [
+                ['2013-06-07T14:21:46.295Z', false],
+                ['2013-06-07T14:21:46.295Z0', false],
+                ['2013-06-07T14:21:46.295+07:00', true],
+                ['2013-06-07T14:21:46.295+07:000', false],
+                ['2013-06-07T14:21:46.295-07:00', false],
+                ['2013-06-07T14:21:46Z', true],
+                ['2013-06-07T14:21:46Z0', false],
+                ['2013-06-07T14:21:46+07:00', false],
+                ['2013-06-07T14:21:46-07:00', false],
+                ['2013-06-07T14:21Z', true],
+                ['2013-06-07T14:21+07:00', false],
+                ['2013-06-07T14:21+07:000', false],
+                ['2013-06-07T14:21-07:00', true],
+                ['2013-06-07T14:21Z+7:00', false],
+                ['2013-06-07', false],
+                ['2013-06-07T', false],
+                ['2013-06-07T14:21', false],
+                ['1-1-2013', false],
+                ['', true],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of isoDate, min, max, allow, invalid and allow(\'\')', function (done) {
+
+            var rule = Joi.string().isoDate().min(17).max(23).allow('2013-06-07T14:21:46.295+07:00').allow('');
+            Helper.validate(rule, [
+                ['2013-06-07T14:21:46.295Z', false],
+                ['2013-06-07T14:21:46.295Z0', false],
+                ['2013-06-07T14:21:46.295+07:00', true],
+                ['2013-06-07T14:21:46.295+07:000', false],
+                ['2013-06-07T14:21:46.295-07:00', false],
+                ['2013-06-07T14:21:46Z', true],
+                ['2013-06-07T14:21:46Z0', false],
+                ['2013-06-07T14:21:46+07:00', false],
+                ['2013-06-07T14:21:46-07:00', false],
+                ['2013-06-07T14:21Z', true],
+                ['2013-06-07T14:21+07:00', true],
+                ['2013-06-07T14:21+07:000', false],
+                ['2013-06-07T14:21-07:00', true],
+                ['2013-06-07T14:21Z+7:00', false],
+                ['2013-06-07', false],
+                ['2013-06-07T', false],
+                ['2013-06-07T14:21', false],
+                ['1-1-2013', false],
+                ['', true],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of isoDate, min, max, allow, invalid and regex', function (done) {
+
+            var rule = Joi.string().isoDate().min(17).max(23).allow('2013-06-07T14:21:46.295+07:00').invalid('2013-06-07T14:21Z').regex(/Z$/);
+            Helper.validate(rule, [
+                ['2013-06-07T14:21:46.295Z', false],
+                ['2013-06-07T14:21:46.295Z0', false],
+                ['2013-06-07T14:21:46.295+07:00', true],
+                ['2013-06-07T14:21:46.295+07:000', false],
+                ['2013-06-07T14:21:46.295-07:00', false],
+                ['2013-06-07T14:21:46Z', true],
+                ['2013-06-07T14:21:46Z0', false],
+                ['2013-06-07T14:21:46+07:00', false],
+                ['2013-06-07T14:21:46-07:00', false],
+                ['2013-06-07T14:21Z', false],
+                ['2013-06-07T14:21+07:00', false],
+                ['2013-06-07T14:21+07:000', false],
+                ['2013-06-07T14:21-07:00', false],
+                ['2013-06-07T14:21Z+7:00', false],
+                ['2013-06-07', false],
+                ['2013-06-07T', false],
+                ['2013-06-07T14:21', false],
+                ['1-1-2013', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of isoDate, min, max, allow, invalid, regex and allow(\'\')', function (done) {
+
+            var rule = Joi.string().isoDate().min(17).max(23).allow('2013-06-07T14:21:46.295+07:00').invalid('2013-06-07T14:21Z').regex(/Z$/).allow('');
+            Helper.validate(rule, [
+                ['2013-06-07T14:21:46.295Z', false],
+                ['2013-06-07T14:21:46.295Z0', false],
+                ['2013-06-07T14:21:46.295+07:00', true],
+                ['2013-06-07T14:21:46.295+07:000', false],
+                ['2013-06-07T14:21:46.295-07:00', false],
+                ['2013-06-07T14:21:46Z', true],
+                ['2013-06-07T14:21:46Z0', false],
+                ['2013-06-07T14:21:46+07:00', false],
+                ['2013-06-07T14:21:46-07:00', false],
+                ['2013-06-07T14:21Z', false],
+                ['2013-06-07T14:21+07:00', false],
+                ['2013-06-07T14:21+07:000', false],
+                ['2013-06-07T14:21-07:00', false],
+                ['2013-06-07T14:21Z+7:00', false],
+                ['2013-06-07', false],
+                ['2013-06-07T', false],
+                ['2013-06-07T14:21', false],
+                ['1-1-2013', false],
+                ['', true],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of isoDate, min, max and allow(\'\')', function (done) {
+
+            var rule = Joi.string().isoDate().min(17).max(23).allow('');
+            Helper.validate(rule, [
+                ['2013-06-07T14:21:46.295Z', false],
+                ['2013-06-07T14:21:46.295Z0', false],
+                ['2013-06-07T14:21:46.295+07:00', false],
+                ['2013-06-07T14:21:46.295+07:000', false],
+                ['2013-06-07T14:21:46.295-07:00', false],
+                ['2013-06-07T14:21:46Z', true],
+                ['2013-06-07T14:21:46Z0', false],
+                ['2013-06-07T14:21:46+07:00', false],
+                ['2013-06-07T14:21:46-07:00', false],
+                ['2013-06-07T14:21Z', true],
+                ['2013-06-07T14:21+07:00', true],
+                ['2013-06-07T14:21+07:000', false],
+                ['2013-06-07T14:21-07:00', true],
+                ['2013-06-07T14:21Z+7:00', false],
+                ['2013-06-07', false],
+                ['2013-06-07T', false],
+                ['2013-06-07T14:21', false],
+                ['1-1-2013', false],
+                ['', true],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of isoDate, min, max and regex', function (done) {
+
+            var rule = Joi.string().isoDate().min(17).max(23).regex(/Z$/);
+            Helper.validate(rule, [
+                ['2013-06-07T14:21:46.295Z', false],
+                ['2013-06-07T14:21:46.295Z0', false],
+                ['2013-06-07T14:21:46.295+07:00', false],
+                ['2013-06-07T14:21:46.295+07:000', false],
+                ['2013-06-07T14:21:46.295-07:00', false],
+                ['2013-06-07T14:21:46Z', true],
+                ['2013-06-07T14:21:46Z0', false],
+                ['2013-06-07T14:21:46+07:00', false],
+                ['2013-06-07T14:21:46-07:00', false],
+                ['2013-06-07T14:21Z', true],
+                ['2013-06-07T14:21+07:00', false],
+                ['2013-06-07T14:21+07:000', false],
+                ['2013-06-07T14:21-07:00', false],
+                ['2013-06-07T14:21Z+7:00', false],
+                ['2013-06-07', false],
+                ['2013-06-07T', false],
+                ['2013-06-07T14:21', false],
+                ['1-1-2013', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of isoDate, min, max, regex and allow(\'\')', function (done) {
+
+            var rule = Joi.string().isoDate().min(17).max(23).regex(/Z$/).allow('');
+            Helper.validate(rule, [
+                ['2013-06-07T14:21:46.295Z', false],
+                ['2013-06-07T14:21:46.295Z0', false],
+                ['2013-06-07T14:21:46.295+07:00', false],
+                ['2013-06-07T14:21:46.295+07:000', false],
+                ['2013-06-07T14:21:46.295-07:00', false],
+                ['2013-06-07T14:21:46Z', true],
+                ['2013-06-07T14:21:46Z0', false],
+                ['2013-06-07T14:21:46+07:00', false],
+                ['2013-06-07T14:21:46-07:00', false],
+                ['2013-06-07T14:21Z', true],
+                ['2013-06-07T14:21+07:00', false],
+                ['2013-06-07T14:21+07:000', false],
+                ['2013-06-07T14:21-07:00', false],
+                ['2013-06-07T14:21Z+7:00', false],
+                ['2013-06-07', false],
+                ['2013-06-07T', false],
+                ['2013-06-07T14:21', false],
+                ['1-1-2013', false],
+                ['', true],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of isoDate, min, max, regex and required', function (done) {
+
+            var rule = Joi.string().isoDate().min(17).max(23).regex(/Z$/).required();
+            Helper.validate(rule, [
+                ['2013-06-07T14:21:46.295Z', false],
+                ['2013-06-07T14:21:46.295Z0', false],
+                ['2013-06-07T14:21:46.295+07:00', false],
+                ['2013-06-07T14:21:46.295+07:000', false],
+                ['2013-06-07T14:21:46.295-07:00', false],
+                ['2013-06-07T14:21:46Z', true],
+                ['2013-06-07T14:21:46Z0', false],
+                ['2013-06-07T14:21:46+07:00', false],
+                ['2013-06-07T14:21:46-07:00', false],
+                ['2013-06-07T14:21Z', true],
+                ['2013-06-07T14:21+07:00', false],
+                ['2013-06-07T14:21+07:000', false],
+                ['2013-06-07T14:21-07:00', false],
+                ['2013-06-07T14:21Z+7:00', false],
+                ['2013-06-07', false],
+                ['2013-06-07T', false],
+                ['2013-06-07T14:21', false],
+                ['1-1-2013', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates guid', function (done) {
+
+            Helper.validate(Joi.string().guid(), [
+                ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', true],
+                ['{B59511BD6A5F4DF09ECF562A108D8A2E}', true],
+                ['69593D62-71EA-4548-85E4-04FC71357423', true],
+                ['677E2553DD4D43B09DA77414DB1EB8EA', true],
+                ['{5ba3bba3-729a-4717-88c1-b7c4b7ba80db}', true],
+                ['{7e9081b59a6d4cc1a8c347f69fb4198d}', true],
+                ['0c74f13f-fa83-4c48-9b33-68921dd72463', true],
+                ['b4b2fb69c6244e5eb0698e0c6ec66618', true],
+                ['{283B67B2-430F-4E6F-97E6-19041992-C1B0}', false],
+                ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D', false],
+                ['D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', false]
+            ], done);
+        });
+
+        it('validates guid with a friendly error message', function (done) {
+
+            var schema = { item: Joi.string().guid() };
+            Joi.compile(schema).validate({ item: 'something' }, function (err, value) {
+
+                expect(err.message).to.contain('must be a valid GUID');
+                done();
+            });
+        });
+
+        it('validates combination of guid and min', function (done) {
+
+            var rule = Joi.string().guid().min(36);
+            Helper.validate(rule, [
+                ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', true],
+                ['{B59511BD6A5F4DF09ECF562A108D8A2E}', false],
+                ['69593D62-71EA-4548-85E4-04FC71357423', true],
+                ['677E2553DD4D43B09DA77414DB1EB8EA', false],
+                ['{5ba3bba3-729a-4717-88c1-b7c4b7ba80db}', true],
+                ['{7e9081b59a6d4cc1a8c347f69fb4198d}', false],
+                ['0c74f13f-fa83-4c48-9b33-68921dd72463', true],
+                ['b4b2fb69c6244e5eb0698e0c6ec66618', false],
+                ['{283B67B2-430F-4E6F-97E6-19041992-C1B0}', false],
+                ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D', false],
+                ['D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of guid, min and max', function (done) {
+
+            var rule = Joi.string().guid().min(32).max(34);
+            Helper.validate(rule, [
+                ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', false],
+                ['{B59511BD6A5F4DF09ECF562A108D8A2E}', true],
+                ['69593D62-71EA-4548-85E4-04FC71357423', false],
+                ['677E2553DD4D43B09DA77414DB1EB8EA', true],
+                ['{5ba3bba3-729a-4717-88c1-b7c4b7ba80db}', false],
+                ['{7e9081b59a6d4cc1a8c347f69fb4198d}', true],
+                ['0c74f13f-fa83-4c48-9b33-68921dd72463', false],
+                ['b4b2fb69c6244e5eb0698e0c6ec66618', true],
+                ['{283B67B2-430F-4E6F-97E6-19041992-C1B0}', false],
+                ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D', false],
+                ['D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of guid, min, max and invalid', function (done) {
+
+            var rule = Joi.string().guid().min(32).max(34).invalid('b4b2fb69c6244e5eb0698e0c6ec66618');
+            Helper.validate(rule, [
+                ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', false],
+                ['{B59511BD6A5F4DF09ECF562A108D8A2E}', true],
+                ['69593D62-71EA-4548-85E4-04FC71357423', false],
+                ['677E2553DD4D43B09DA77414DB1EB8EA', true],
+                ['{5ba3bba3-729a-4717-88c1-b7c4b7ba80db}', false],
+                ['{7e9081b59a6d4cc1a8c347f69fb4198d}', true],
+                ['0c74f13f-fa83-4c48-9b33-68921dd72463', false],
+                ['b4b2fb69c6244e5eb0698e0c6ec66618', false],
+                ['{283B67B2-430F-4E6F-97E6-19041992-C1B0}', false],
+                ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D', false],
+                ['D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of guid, min, max and allow', function (done) {
+
+            var rule = Joi.string().guid().min(32).max(34).allow('{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D');
+            Helper.validate(rule, [
+                ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', false],
+                ['{B59511BD6A5F4DF09ECF562A108D8A2E}', true],
+                ['69593D62-71EA-4548-85E4-04FC71357423', false],
+                ['677E2553DD4D43B09DA77414DB1EB8EA', true],
+                ['{5ba3bba3-729a-4717-88c1-b7c4b7ba80db}', false],
+                ['{7e9081b59a6d4cc1a8c347f69fb4198d}', true],
+                ['0c74f13f-fa83-4c48-9b33-68921dd72463', false],
+                ['b4b2fb69c6244e5eb0698e0c6ec66618', true],
+                ['{283B67B2-430F-4E6F-97E6-19041992-C1B0}', false],
+                ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D', true],
+                ['D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of guid, min, max, allow and invalid', function (done) {
+
+            var rule = Joi.string().guid().min(32).max(34).allow('{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D').invalid('b4b2fb69c6244e5eb0698e0c6ec66618');
+            Helper.validate(rule, [
+                ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', false],
+                ['{B59511BD6A5F4DF09ECF562A108D8A2E}', true],
+                ['69593D62-71EA-4548-85E4-04FC71357423', false],
+                ['677E2553DD4D43B09DA77414DB1EB8EA', true],
+                ['{5ba3bba3-729a-4717-88c1-b7c4b7ba80db}', false],
+                ['{7e9081b59a6d4cc1a8c347f69fb4198d}', true],
+                ['0c74f13f-fa83-4c48-9b33-68921dd72463', false],
+                ['b4b2fb69c6244e5eb0698e0c6ec66618', false],
+                ['{283B67B2-430F-4E6F-97E6-19041992-C1B0}', false],
+                ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D', true],
+                ['D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of guid, min, max, allow, invalid and allow(\'\')', function (done) {
+
+            var rule = Joi.string().guid().min(32).max(34).allow('{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D').invalid('b4b2fb69c6244e5eb0698e0c6ec66618').allow('');
+            Helper.validate(rule, [
+                ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', false],
+                ['{B59511BD6A5F4DF09ECF562A108D8A2E}', true],
+                ['69593D62-71EA-4548-85E4-04FC71357423', false],
+                ['677E2553DD4D43B09DA77414DB1EB8EA', true],
+                ['{5ba3bba3-729a-4717-88c1-b7c4b7ba80db}', false],
+                ['{7e9081b59a6d4cc1a8c347f69fb4198d}', true],
+                ['0c74f13f-fa83-4c48-9b33-68921dd72463', false],
+                ['b4b2fb69c6244e5eb0698e0c6ec66618', false],
+                ['{283B67B2-430F-4E6F-97E6-19041992-C1B0}', false],
+                ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D', true],
+                ['D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', false],
+                ['', true],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of guid, min, max, allow and allow(\'\')', function (done) {
+
+            var rule = Joi.string().guid().min(32).max(34).allow('{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D').allow('');
+            Helper.validate(rule, [
+                ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', false],
+                ['{B59511BD6A5F4DF09ECF562A108D8A2E}', true],
+                ['69593D62-71EA-4548-85E4-04FC71357423', false],
+                ['677E2553DD4D43B09DA77414DB1EB8EA', true],
+                ['{5ba3bba3-729a-4717-88c1-b7c4b7ba80db}', false],
+                ['{7e9081b59a6d4cc1a8c347f69fb4198d}', true],
+                ['0c74f13f-fa83-4c48-9b33-68921dd72463', false],
+                ['b4b2fb69c6244e5eb0698e0c6ec66618', true],
+                ['{283B67B2-430F-4E6F-97E6-19041992-C1B0}', false],
+                ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D', true],
+                ['D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', false],
+                ['', true],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of guid, min, max, allow, invalid and regex', function (done) {
+
+            var rule = Joi.string().guid().min(32).max(34).allow('{D1A5279D-B27D-4CD4-A05E-EFDD53D08').invalid('b4b2fb69c6244e5eb0698e0c6ec66618').regex(/^{7e908/);
+            Helper.validate(rule, [
+                ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', false],
+                ['{B59511BD6A5F4DF09ECF562A108D8A2E}', false],
+                ['69593D62-71EA-4548-85E4-04FC71357423', false],
+                ['677E2553DD4D43B09DA77414DB1EB8EA', false],
+                ['{5ba3bba3-729a-4717-88c1-b7c4b7ba80db}', false],
+                ['{7e9081b59a6d4cc1a8c347f69fb4198d}', true],
+                ['0c74f13f-fa83-4c48-9b33-68921dd72463', false],
+                ['b4b2fb69c6244e5eb0698e0c6ec66618', false],
+                ['{283B67B2-430F-4E6F-97E6-19041992-C1B0}', false],
+                ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08', true],
+                ['D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of guid, min, max, allow, invalid, regex and allow(\'\')', function (done) {
+
+            var rule = Joi.string().guid().min(32).max(34).allow('{D1A5279D-B27D-4CD4-A05E-EFDD53D08').invalid('b4b2fb69c6244e5eb0698e0c6ec66618').regex(/^{7e908/).allow('');
+            Helper.validate(rule, [
+                ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', false],
+                ['{B59511BD6A5F4DF09ECF562A108D8A2E}', false],
+                ['69593D62-71EA-4548-85E4-04FC71357423', false],
+                ['677E2553DD4D43B09DA77414DB1EB8EA', false],
+                ['{5ba3bba3-729a-4717-88c1-b7c4b7ba80db}', false],
+                ['{7e9081b59a6d4cc1a8c347f69fb4198d}', true],
+                ['0c74f13f-fa83-4c48-9b33-68921dd72463', false],
+                ['b4b2fb69c6244e5eb0698e0c6ec66618', false],
+                ['{283B67B2-430F-4E6F-97E6-19041992-C1B0}', false],
+                ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08', true],
+                ['D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', false],
+                ['', true],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of guid, min, max and allow(\'\')', function (done) {
+
+            var rule = Joi.string().guid().min(32).max(34).allow('');
+            Helper.validate(rule, [
+                ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', false],
+                ['{B59511BD6A5F4DF09ECF562A108D8A2E}', true],
+                ['69593D62-71EA-4548-85E4-04FC71357423', false],
+                ['677E2553DD4D43B09DA77414DB1EB8EA', true],
+                ['{5ba3bba3-729a-4717-88c1-b7c4b7ba80db}', false],
+                ['{7e9081b59a6d4cc1a8c347f69fb4198d}', true],
+                ['0c74f13f-fa83-4c48-9b33-68921dd72463', false],
+                ['b4b2fb69c6244e5eb0698e0c6ec66618', true],
+                ['{283B67B2-430F-4E6F-97E6-19041992-C1B0}', false],
+                ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D', false],
+                ['D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', false],
+                ['', true],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of guid, min, max and regex', function (done) {
+
+            var rule = Joi.string().guid().min(32).max(34).regex(/^{7e9081/i);
+            Helper.validate(rule, [
+                ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', false],
+                ['{B59511BD6A5F4DF09ECF562A108D8A2E}', false],
+                ['69593D62-71EA-4548-85E4-04FC71357423', false],
+                ['677E2553DD4D43B09DA77414DB1EB8EA', false],
+                ['{5ba3bba3-729a-4717-88c1-b7c4b7ba80db}', false],
+                ['{7e9081b59a6d4cc1a8c347f69fb4198d}', true],
+                ['0c74f13f-fa83-4c48-9b33-68921dd72463', false],
+                ['b4b2fb69c6244e5eb0698e0c6ec66618', false],
+                ['{283B67B2-430F-4E6F-97E6-19041992-C1B0}', false],
+                ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D', false],
+                ['D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of guid, min, max, regex and allow(\'\')', function (done) {
+
+            var rule = Joi.string().guid().min(32).max(34).regex(/^{7e9081/i).allow('');
+            Helper.validate(rule, [
+                ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', false],
+                ['{B59511BD6A5F4DF09ECF562A108D8A2E}', false],
+                ['69593D62-71EA-4548-85E4-04FC71357423', false],
+                ['677E2553DD4D43B09DA77414DB1EB8EA', false],
+                ['{5ba3bba3-729a-4717-88c1-b7c4b7ba80db}', false],
+                ['{7e9081b59a6d4cc1a8c347f69fb4198d}', true],
+                ['0c74f13f-fa83-4c48-9b33-68921dd72463', false],
+                ['b4b2fb69c6244e5eb0698e0c6ec66618', false],
+                ['{283B67B2-430F-4E6F-97E6-19041992-C1B0}', false],
+                ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D', false],
+                ['D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', false],
+                ['', true],
+                [null, false]
+            ], done);
+        });
+
+        it('validates combination of guid, min, max, regex and required', function (done) {
+
+            var rule = Joi.string().guid().min(32).max(34).regex(/^{7e9081/i).required();
+            Helper.validate(rule, [
+                ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', false],
+                ['{B59511BD6A5F4DF09ECF562A108D8A2E}', false],
+                ['69593D62-71EA-4548-85E4-04FC71357423', false],
+                ['677E2553DD4D43B09DA77414DB1EB8EA', false],
+                ['{5ba3bba3-729a-4717-88c1-b7c4b7ba80db}', false],
+                ['{7e9081b59a6d4cc1a8c347f69fb4198d}', true],
+                ['0c74f13f-fa83-4c48-9b33-68921dd72463', false],
+                ['b4b2fb69c6244e5eb0698e0c6ec66618', false],
+                ['{283B67B2-430F-4E6F-97E6-19041992-C1B0}', false],
+                ['{D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D', false],
+                ['D1A5279D-B27D-4CD4-A05E-EFDD53D08E8D}', false],
+                ['', false],
+                [null, false]
+            ], done);
+        });
+
+        it('validates an hexadecimal string', function (done) {
+
+            var rule = Joi.string().hex();
+            Helper.validate(rule, [
+                ['123456789abcdef', true],
+                ['123456789AbCdEf', true],
+                ['123afg', false, null, '"value" must only contain hexadecimal characters']
+            ], done);
+        });
+    });
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/.jshintrc b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/.jshintrc
new file mode 100644
index 0000000000000000000000000000000000000000..2c03a0a23b9ba724f90e190ca331c59662f04777
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/.jshintrc
@@ -0,0 +1,22 @@
+{
+  "evil": true,
+  "regexdash": true,
+  "browser": true,
+  "wsh": true,
+  "trailing": true,
+  "sub": true,
+  "unused": true,
+  "undef": true,
+  "laxcomma": true,
+  "node": true,
+  "browser": false,
+  "esnext": true,
+  "globals": {
+    "describe": true,
+    "it": true,
+    "require": true,
+    "atob": false,
+    "escape": true,
+    "before": true
+  }
+}
\ No newline at end of file
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/.npmignore b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/.npmignore
new file mode 100644
index 0000000000000000000000000000000000000000..28f1ba7565f46fb5074ad9a4f07c4cfc86dff4cc
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/.npmignore
@@ -0,0 +1,2 @@
+node_modules
+.DS_Store
\ No newline at end of file
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/.travis.yml b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..86099fba843a9f2206db412a9087184c0432ec2d
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/.travis.yml
@@ -0,0 +1,6 @@
+language: node_js
+before_install: npm i -g npm@1.4.28
+node_js:
+  - "5"
+  - "4"
+  - "0.12"
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/CHANGELOG.md b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..a3710f8e4c1cd5dc5f5ce67e778aaf17d62aa274
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/CHANGELOG.md
@@ -0,0 +1,285 @@
+# Change Log
+
+
+All notable changes to this project will be documented in this file starting from version **v4.0.0**.
+This project adheres to [Semantic Versioning](http://semver.org/).
+
+## 7.1.7 - 2016-07-29
+
+ - Use lodash.once instead of unlicensed/unmaintained cb ([3ac95ad93ef3068a64e03d8d14deff231b1ed529](https://github.com/auth0/node-jsonwebtoken/commit/3ac95ad93ef3068a64e03d8d14deff231b1ed529))
+
+## 7.1.6 - 2016-07-15
+
+ - fix issue with buffer payload. closes #216 ([6b50ff324b4dfd2cb0e49b666f14a6672d015b22](https://github.com/auth0/node-jsonwebtoken/commit/6b50ff324b4dfd2cb0e49b666f14a6672d015b22)), closes [#216](https://github.com/auth0/node-jsonwebtoken/issues/216)
+
+
+## 7.1.5 - 2016-07-15
+
+ - update jws in package.json ([b6260951eefc68aae5f4ede359210761f901ff7a](https://github.com/auth0/node-jsonwebtoken/commit/b6260951eefc68aae5f4ede359210761f901ff7a))
+
+
+## 7.1.4 - 2016-07-14
+
+ - add redundant test ([bece8816096f324511c3efcb8db0e64b75d757a1](https://github.com/auth0/node-jsonwebtoken/commit/bece8816096f324511c3efcb8db0e64b75d757a1))
+ - fix an issue of double callback on error ([758ca5eeca2f1b06c32c9fce70642bf488b2e52b](https://github.com/auth0/node-jsonwebtoken/commit/758ca5eeca2f1b06c32c9fce70642bf488b2e52b))
+
+## 7.1.2 - 2016-07-12
+
+ - do not stringify the payload when signing async - closes #224 ([084f537d3dfbcef2bea411cc0a1515899cc8aa21](https://github.com/auth0/node-jsonwebtoken/commit/084f537d3dfbcef2bea411cc0a1515899cc8aa21)), closes [#224](https://github.com/auth0/node-jsonwebtoken/issues/224)
+
+## 7.1.1 - 2016-07-12
+
+ - do not mutate options in jwt.verify, closes #227 ([63263a28a268624dab0927b9ad86fffa44a10f84](https://github.com/auth0/node-jsonwebtoken/commit/63263a28a268624dab0927b9ad86fffa44a10f84)), closes [#227](https://github.com/auth0/node-jsonwebtoken/issues/227)
+ - refactor into multiple files ([e11d505207fa33501298300c9accbfb809d8748d](https://github.com/auth0/node-jsonwebtoken/commit/e11d505207fa33501298300c9accbfb809d8748d))
+
+## 7.1.0 - 2016-07-12
+
+ - Exp calculated based on iat. fix #217 ([757a16e0e35ad19f9e456820f55d5d9f3fc76aee](https://github.com/auth0/node-jsonwebtoken/commit/757a16e0e35ad19f9e456820f55d5d9f3fc76aee)), closes [#217](https://github.com/auth0/node-jsonwebtoken/issues/217)
+
+## 7.0.0 - 2016-05-19
+
+ - change jwt.sign to return errors on callback instead of throwing errors ([1e46c5a42aa3dab8478efa4081d8f8f5c5485d56](https://github.com/auth0/node-jsonwebtoken/commit/1e46c5a42aa3dab8478efa4081d8f8f5c5485d56))
+
+## 6.2.0 - 2016-04-29
+
+ - add support for `options.clockTolerance` to `jwt.verify` ([65ddea934f226bf06bc9d6a55be9587515cfc38d](https://github.com/auth0/node-jsonwebtoken/commit/65ddea934f226bf06bc9d6a55be9587515cfc38d))
+
+## 6.1.2 - 2016-04-29
+
+ - fix sign method for node.js 0.12. closes #193 ([9c38374142d3929be3c9314b5e9bc5d963c5955f](https://github.com/auth0/node-jsonwebtoken/commit/9c38374142d3929be3c9314b5e9bc5d963c5955f)), closes [#193](https://github.com/auth0/node-jsonwebtoken/issues/193)
+ - improve async test ([7b0981380ddc40a5f1208df520631785b5ffb85a](https://github.com/auth0/node-jsonwebtoken/commit/7b0981380ddc40a5f1208df520631785b5ffb85a))
+
+## 6.1.0 - 2016-04-27
+
+ - verify unsigned tokens ([ec880791c10ed5ef7c8df7bf28ebb95c810479ed](https://github.com/auth0/node-jsonwebtoken/commit/ec880791c10ed5ef7c8df7bf28ebb95c810479ed))
+
+## 6.0.1 - 2016-04-27
+
+This was an immediate change after publishing 6.0.0.
+
+ - throw error on invalid options when the payload is not an object ([304f1b33075f79ed66f784e27dc4f5307aa39e27](https://github.com/auth0/node-jsonwebtoken/commit/304f1b33075f79ed66f784e27dc4f5307aa39e27))
+
+## 6.0.0 - 2016-04-27
+
+ - Change .sign to standard async callback ([50873c7d45d2733244d5da8afef3d1872e657a60](https://github.com/auth0/node-jsonwebtoken/commit/50873c7d45d2733244d5da8afef3d1872e657a60))
+ - Improved the options for the `sign` method ([53c3987b3cc34e95eb396b26fc9b051276e2f6f9](https://github.com/auth0/node-jsonwebtoken/commit/53c3987b3cc34e95eb396b26fc9b051276e2f6f9))
+
+    -  throw error on invalid options like `expiresIn` when the payload is not an object ([304f1b33075f79ed66f784e27dc4f5307aa39e27](https://github.com/auth0/node-jsonwebtoken/commit/304f1b33075f79ed66f784e27dc4f5307aa39e27))
+    -  `expiresInMinutes` and `expiresInSeconds` are deprecated and no longer supported.
+    -  `notBeforeInMinutes` and `notBeforeInSeconds` are deprecated and no longer supported.
+    -  `options` are strongly validated.
+    -  `options.expiresIn`, `options.notBefore`, `options.audience`, `options.issuer`, `options.subject` and `options.jwtid` are mutually exclusive with `payload.exp`, `payload.nbf`, `payload.aud`, `payload.iss`
+    -  `options.algorithm` is properly validated.
+    -  `options.headers` is renamed to `options.header`.
+
+ - update CHANGELOG to reflect most of the changes. closes #136 ([b87a1a8d2e2533fbfab518765a54f00077918eb7](https://github.com/auth0/node-jsonwebtoken/commit/b87a1a8d2e2533fbfab518765a54f00077918eb7)), closes [#136](https://github.com/auth0/node-jsonwebtoken/issues/136)
+ - update readme ([53a88ecf4494e30e1d62a1cf3cc354650349f486](https://github.com/auth0/node-jsonwebtoken/commit/53a88ecf4494e30e1d62a1cf3cc354650349f486))
+
+## 5.7.0 - 2016-02-16
+
+
+ - add support for validating multiples issuers. closes #163 ([39d9309ae05648dbd72e5fd1993df064ad0e8fa5](https://github.com/auth0/node-jsonwebtoken/commit/39d9309ae05648dbd72e5fd1993df064ad0e8fa5)), closes [#163](https://github.com/auth0/node-jsonwebtoken/issues/163)
+
+
+## 5.6.1 - 2016-02-16
+
+
+ - 5.6.1 ([06d8209d499dbc9a8dd978ab6cbb9c6818fde203](https://github.com/auth0/node-jsonwebtoken/commit/06d8209d499dbc9a8dd978ab6cbb9c6818fde203))
+ - fix wrong error when setting expiration on non-object payload. closes #153 ([7f7d76edfd918d6afc7c7cead888caa42ccaceb4](https://github.com/auth0/node-jsonwebtoken/commit/7f7d76edfd918d6afc7c7cead888caa42ccaceb4)), closes [#153](https://github.com/auth0/node-jsonwebtoken/issues/153)
+
+
+
+## 5.6.0 - 2016-02-16
+
+
+ - added missing validations of sub and jti ([a1affe960d0fc52e9042bcbdedb65734f8855580](https://github.com/auth0/node-jsonwebtoken/commit/a1affe960d0fc52e9042bcbdedb65734f8855580))
+ - Fix tests in jwt.rs.tests.js which causes 4 to fail ([8aedf2b1f575b0d9575c1fc9f2ac7bc868f75ff1](https://github.com/auth0/node-jsonwebtoken/commit/8aedf2b1f575b0d9575c1fc9f2ac7bc868f75ff1))
+ - Update README.md ([349b7cd00229789b138928ca060d3ef015aedaf9](https://github.com/auth0/node-jsonwebtoken/commit/349b7cd00229789b138928ca060d3ef015aedaf9))
+
+
+
+## 5.5.4 - 2016-01-04
+
+
+ - minor ([46552e7c45025c76e3f647680d7539a66bfac612](https://github.com/auth0/node-jsonwebtoken/commit/46552e7c45025c76e3f647680d7539a66bfac612))
+
+
+
+## 5.5.3 - 2016-01-04
+
+
+ - add a console.warn on invalid options for string payloads ([71200f14deba0533d3261266348338fac2d14661](https://github.com/auth0/node-jsonwebtoken/commit/71200f14deba0533d3261266348338fac2d14661))
+ - minor ([65b1f580382dc58dd3da6f47a52713776fd7cdf2](https://github.com/auth0/node-jsonwebtoken/commit/65b1f580382dc58dd3da6f47a52713776fd7cdf2))
+
+
+
+## 5.5.2 - 2016-01-04
+
+
+ - fix signing method with sealed objects, do not modify the params object. closes #147 ([be9c09af83b09c9e72da8b2c6166fa51d92aeab6](https://github.com/auth0/node-jsonwebtoken/commit/be9c09af83b09c9e72da8b2c6166fa51d92aeab6)), closes [#147](https://github.com/auth0/node-jsonwebtoken/issues/147)
+
+
+
+## 5.5.1 - 2016-01-04
+
+
+ - fix nbf verification. fix #152 ([786d37b299c67771b5e71a2ca476666ab0f97d98](https://github.com/auth0/node-jsonwebtoken/commit/786d37b299c67771b5e71a2ca476666ab0f97d98)), closes [#152](https://github.com/auth0/node-jsonwebtoken/issues/152)
+
+
+
+## 5.5.0 - 2015-12-28
+
+
+ - improvements to nbf and jti claims ([46372e928f6d2e7398f9b88022ca617d2a3b0699](https://github.com/auth0/node-jsonwebtoken/commit/46372e928f6d2e7398f9b88022ca617d2a3b0699))
+ - Remove duplicate payload line (fix bug in IE strict mode) ([8163d698e0c5ad8c44817a5dcd42a15d7e9c6bc8](https://github.com/auth0/node-jsonwebtoken/commit/8163d698e0c5ad8c44817a5dcd42a15d7e9c6bc8))
+ - Remove duplicate require('ms') line ([7c00bcbcbf8f7503a1070b394a165eccd41de66f](https://github.com/auth0/node-jsonwebtoken/commit/7c00bcbcbf8f7503a1070b394a165eccd41de66f))
+ - Update README to reflect addition of async sign ([d661d4b6f68eb417834c99b36769444723041ccf](https://github.com/auth0/node-jsonwebtoken/commit/d661d4b6f68eb417834c99b36769444723041ccf))
+
+
+
+## 5.4.0 - 2015-10-02
+
+
+ - deprecate expireInMinutes and expireInSeconds - in favor of expiresIn ([39ecc6f8f310f8462e082f1d53de0b4222b29b6f](https://github.com/auth0/node-jsonwebtoken/commit/39ecc6f8f310f8462e082f1d53de0b4222b29b6f))
+
+
+## 5.3.0 - 2015-10-02
+
+
+ - 5.3.0 ([5d559ced3fbf10c1adae2e5792deda06ea89bcd3](https://github.com/auth0/node-jsonwebtoken/commit/5d559ced3fbf10c1adae2e5792deda06ea89bcd3))
+ - minor ([6e81ff87a3799b0e56db09cbae42a97e784716c4](https://github.com/auth0/node-jsonwebtoken/commit/6e81ff87a3799b0e56db09cbae42a97e784716c4))
+
+
+
+## 5.1.0 - 2015-10-02
+
+
+ - added async signing ([9414fbcb15a1f9cf4fe147d070e9424c547dabba](https://github.com/auth0/node-jsonwebtoken/commit/9414fbcb15a1f9cf4fe147d070e9424c547dabba))
+ - Update README.md ([40b2aaaa843442dfb8ee7b574f0a788177e7c904](https://github.com/auth0/node-jsonwebtoken/commit/40b2aaaa843442dfb8ee7b574f0a788177e7c904))
+
+
+
+## 5.0.5 - 2015-08-19
+
+
+ - add ms dep to package.json ([f13b3fb7f29dff787e7c91ebe2eb5adeeb05f251](https://github.com/auth0/node-jsonwebtoken/commit/f13b3fb7f29dff787e7c91ebe2eb5adeeb05f251))
+ - add note to explain, related to #96 #101 #6 ([dd8969e0e6ed0bcb9cae905d2b1a96476bd85da3](https://github.com/auth0/node-jsonwebtoken/commit/dd8969e0e6ed0bcb9cae905d2b1a96476bd85da3))
+ - add tests for options.headers ([7787dd74e705787c39a871ca29c75a2e0a3948ac](https://github.com/auth0/node-jsonwebtoken/commit/7787dd74e705787c39a871ca29c75a2e0a3948ac))
+ - add tests for verify expires ([d7c5793d98c300603440ab460c11665f661ad3a0](https://github.com/auth0/node-jsonwebtoken/commit/d7c5793d98c300603440ab460c11665f661ad3a0))
+ - add verify option maxAge (with tests) ([49d54e54f7e70b1c53a2e4ee67e116c907d75319](https://github.com/auth0/node-jsonwebtoken/commit/49d54e54f7e70b1c53a2e4ee67e116c907d75319))
+ - fix spelling error in error message ([8078b11b224fa05ac9003ca5aa2c85e9f0128cfb](https://github.com/auth0/node-jsonwebtoken/commit/8078b11b224fa05ac9003ca5aa2c85e9f0128cfb))
+ - Fix typo options.header is not a documented option + ([5feaa5b962ccbddeff054817a410f7b0c1e6ce7f](https://github.com/auth0/node-jsonwebtoken/commit/5feaa5b962ccbddeff054817a410f7b0c1e6ce7f))
+ - update JWT spec link. closes #112 ([f5fa50f797456a12240589161835c7ea30807195](https://github.com/auth0/node-jsonwebtoken/commit/f5fa50f797456a12240589161835c7ea30807195)), closes [#112](https://github.com/auth0/node-jsonwebtoken/issues/112)
+
+
+## 5.0.3 - 2015-07-15
+
+ - Added nbf support ([f26ba4e2fa197a20497632b63ffcd13ae93aacc4](https://github.com/auth0/node-jsonwebtoken/commit/f26ba4e2fa197a20497632b63ffcd13ae93aacc4))
+ - Added support for subject and jwt id ([ab76ec5bc554e2d1e25376ddb7cea711d86af651](https://github.com/auth0/node-jsonwebtoken/commit/ab76ec5bc554e2d1e25376ddb7cea711d86af651))
+ - Fix `this` referring to the global object instead of `module.exports` in `verify()` ([93f554312e37129027fcf4916f48cb8d1b53588c](https://github.com/auth0/node-jsonwebtoken/commit/93f554312e37129027fcf4916f48cb8d1b53588c))
+ - Fix typo, line 139 README, complete option for .decode. ([59c110aeb8c7c1847ef2ffd77702d13627c89e10](https://github.com/auth0/node-jsonwebtoken/commit/59c110aeb8c7c1847ef2ffd77702d13627c89e10))
+ - minor ([61ff1172272b582902313e958058ff22413494af](https://github.com/auth0/node-jsonwebtoken/commit/61ff1172272b582902313e958058ff22413494af))
+
+
+
+## 5.0.2 - 2015-06-15
+
+
+ - fix typo in docs . closes #86 ([3d3413221f36acef4dfd1cbed87f1f3565cd6f84](https://github.com/auth0/node-jsonwebtoken/commit/3d3413221f36acef4dfd1cbed87f1f3565cd6f84)), closes [#86](https://github.com/auth0/node-jsonwebtoken/issues/86)
+
+
+
+## 5.0.1 - 2015-05-15
+
+
+ - Add option to return header and payload when decoding. ([7254e011b59f892d1947e6c11819281adac7069d](https://github.com/auth0/node-jsonwebtoken/commit/7254e011b59f892d1947e6c11819281adac7069d))
+ - Avoid uncaught "SyntaxError: Unexpected token ͧ" error. ([0dc59cd6ee15d83a606acffa7909ee76176ae186](https://github.com/auth0/node-jsonwebtoken/commit/0dc59cd6ee15d83a606acffa7909ee76176ae186))
+ - Document complete option in README. ([ec32b20241a74d9681ea26e1a7024b4642468c00](https://github.com/auth0/node-jsonwebtoken/commit/ec32b20241a74d9681ea26e1a7024b4642468c00))
+ - Fix example in README, silence verbose logging. ([ba3174d10033c41e9c211a38f1cc67f74fbd7f69](https://github.com/auth0/node-jsonwebtoken/commit/ba3174d10033c41e9c211a38f1cc67f74fbd7f69))
+ - Fix link to auth0.com in README ([1b3c5ff72c9bc25e9271646e679f3080f2a042a0](https://github.com/auth0/node-jsonwebtoken/commit/1b3c5ff72c9bc25e9271646e679f3080f2a042a0))
+ - Immediate return if not decoded. ([851bda2b10168f3269c3da6e74d310742f31a193](https://github.com/auth0/node-jsonwebtoken/commit/851bda2b10168f3269c3da6e74d310742f31a193))
+ - Prevent throw on undefined/null secret ([0fdf78d4dbf609455f3277d6169a987aef0384d4](https://github.com/auth0/node-jsonwebtoken/commit/0fdf78d4dbf609455f3277d6169a987aef0384d4))
+ - Removed path from test ([d6240e24186732d368bffe21143becf44c38f0d6](https://github.com/auth0/node-jsonwebtoken/commit/d6240e24186732d368bffe21143becf44c38f0d6))
+ - Simplified checking for missing key ([f1cffd033bffc44f20558eda4a797c3fa2f4ee05](https://github.com/auth0/node-jsonwebtoken/commit/f1cffd033bffc44f20558eda4a797c3fa2f4ee05))
+ - Typo ([ffe68dbe0219bab535c1018448eb4c0b22f1f902](https://github.com/auth0/node-jsonwebtoken/commit/ffe68dbe0219bab535c1018448eb4c0b22f1f902))
+ - Update CHANGELOG.md ([927cce0dad1bc9aad75aeef53e276cf4cfc0d776](https://github.com/auth0/node-jsonwebtoken/commit/927cce0dad1bc9aad75aeef53e276cf4cfc0d776))
+ - Update CHANGELOG.md ([6879e0fdde222995c70a3a69a4af94993d9c667e](https://github.com/auth0/node-jsonwebtoken/commit/6879e0fdde222995c70a3a69a4af94993d9c667e))
+ - Update CHANGELOG.md ([c5596c10e8705727fa13e0394184a606083078bc](https://github.com/auth0/node-jsonwebtoken/commit/c5596c10e8705727fa13e0394184a606083078bc))
+ - Update CHANGELOG.md ([07541f0315f26d179e1cde92732b6124d6869b6f](https://github.com/auth0/node-jsonwebtoken/commit/07541f0315f26d179e1cde92732b6124d6869b6f))
+ - Update CHANGELOG.md ([e6465d48ddd1dc2c3297229b28c78fd5490a2ba9](https://github.com/auth0/node-jsonwebtoken/commit/e6465d48ddd1dc2c3297229b28c78fd5490a2ba9))
+
+## [5.0.0] - 2015-04-11
+
+### Changed
+
+ - [sign] Only set defautl `iat` if the user does not specify that argument.
+
+  https://github.com/auth0/node-jsonwebtoken/commit/e900282a8d2dff1d4dec815f7e6aa7782e867d91
+  https://github.com/auth0/node-jsonwebtoken/commit/35036b188b4ee6b42df553bbb93bc8a6b19eae9d
+  https://github.com/auth0/node-jsonwebtoken/commit/954bd7a312934f03036b6bb6f00edd41f29e54d9
+  https://github.com/auth0/node-jsonwebtoken/commit/24a370080e0b75f11d4717cd2b11b2949d95fc2e
+  https://github.com/auth0/node-jsonwebtoken/commit/a77df6d49d4ec688dfd0a1cc723586bffe753516
+
+### Security
+
+ - [verify] Update to jws@^3.0.0 and renaming `header.alg` mismatch exception to `invalid algorithm` and adding more mismatch tests.
+
+  As `jws@3.0.0` changed the verify method signature to be `jws.verify(signature, algorithm, secretOrKey)`, the token header must be decoded first in order to make sure that the `alg` field matches one of the allowed `options.algorithms`. After that, the now validated `header.alg` is passed to `jws.verify`
+
+ As the order of steps has changed, the error that was thrown when the JWT was invalid is no longer the `jws` one:
+ ```
+ { [Error: Invalid token: no header in signature 'a.b.c'] code: 'MISSING_HEADER', signature: 'a.b.c' }
+ ```
+
+ That old error (removed from jws) has been replaced by a `JsonWebTokenError` with message `invalid token`.
+
+ > Important: versions >= 4.2.2 this library are safe to use but we decided to deprecate everything `< 5.0.0` to prevent security warnings from library `node-jws` when doing `npm install`.
+
+  https://github.com/auth0/node-jsonwebtoken/commit/634b8ed0ff5267dc25da5c808634208af109824e
+  https://github.com/auth0/node-jsonwebtoken/commit/9f24ffd5791febb449d4d03ff58d7807da9b9b7e
+  https://github.com/auth0/node-jsonwebtoken/commit/19e6cc6a1f2fd90356f89b074223b9665f2aa8a2
+  https://github.com/auth0/node-jsonwebtoken/commit/1e4623420159c6410616f02a44ed240f176287a9
+  https://github.com/auth0/node-jsonwebtoken/commit/954bd7a312934f03036b6bb6f00edd41f29e54d9
+  https://github.com/auth0/node-jsonwebtoken/commit/24a370080e0b75f11d4717cd2b11b2949d95fc2e
+  https://github.com/auth0/node-jsonwebtoken/commit/a77df6d49d4ec688dfd0a1cc723586bffe753516
+
+## [4.2.2] - 2015-03-26
+### Fixed
+
+ - [asymmetric-keys] Fix verify for RSAPublicKey formated keys (`jfromaniello - awlayton`)
+  https://github.com/auth0/node-jsonwebtoken/commit/402794663b9521bf602fcc6f2e811e7d3912f9dc
+  https://github.com/auth0/node-jsonwebtoken/commit/8df6aabbc7e1114c8fb3917931078254eb52c222
+
+## [4.2.1] - 2015-03-17
+### Fixed
+
+ - [asymmetric-keys] Fixed issue when public key starts with BEING PUBLIC KEY (https://github.com/auth0/node-jsonwebtoken/issues/70) (`jfromaniello`)
+  https://github.com/auth0/node-jsonwebtoken/commit/7017e74db9b194448ff488b3e16468ada60c4ee5
+
+## [4.2.0] - 2015-03-16
+### Security
+
+ - [asymmetric-keys] Making sure a token signed with an asymmetric key will be verified using a asymmetric key.
+   When the verification part was expecting a token digitally signed with an asymmetric key (RS/ES family) of algorithms an attacker could send a token signed with a symmetric algorithm (HS* family).
+
+  The issue was caused because the same signature was used to verify both type of tokens (`verify` method parameter: `secretOrPublicKey`).
+
+  This change adds a new parameter to the verify called `algorithms`. This can be used to specify a list of supported algorithms, but the default value depends on the secret used: if the secretOrPublicKey contains the string `BEGIN CERTIFICATE` the default is `[ 'RS256','RS384','RS512','ES256','ES384','ES512' ]` otherwise is `[ 'HS256','HS384','HS512' ]`. (`jfromaniello`)
+  https://github.com/auth0/node-jsonwebtoken/commit/c2bf7b2cd7e8daf66298c2d168a008690bc4bdd3
+  https://github.com/auth0/node-jsonwebtoken/commit/1bb584bc382295eeb7ee8c4452a673a77a68b687
+
+## [4.1.0] - 2015-03-10
+### Changed
+- Assume the payload is JSON even when there is no `typ` property. [5290db1](https://github.com/auth0/node-jsonwebtoken/commit/5290db1bd74f74cd38c90b19e2355ef223a4d931)
+
+## [4.0.0] - 2015-03-06
+### Changed
+- The default encoding is now utf8 instead of binary. [92d33bd](https://github.com/auth0/node-jsonwebtoken/commit/92d33bd99a3416e9e5a8897d9ad8ff7d70a00bfd)
+- Add `encoding` as a new option to `sign`. [1fc385e](https://github.com/auth0/node-jsonwebtoken/commit/1fc385ee10bd0018cd1441552dce6c2e5a16375f)
+- Add `ignoreExpiration` to `verify`. [8d4da27](https://github.com/auth0/node-jsonwebtoken/commit/8d4da279e1b351ac71ace276285c9255186d549f)
+- Add `expiresInSeconds` to `sign`. [dd156cc](https://github.com/auth0/node-jsonwebtoken/commit/dd156cc30f17028744e60aec0502897e34609329)
+
+### Fixed
+- Fix wrong error message when the audience doesn't match. [44e3c8d](https://github.com/auth0/node-jsonwebtoken/commit/44e3c8d757e6b4e2a57a69a035f26b4abec3e327)
+- Fix wrong error message when the issuer doesn't match. [44e3c8d](https://github.com/auth0/node-jsonwebtoken/commit/44e3c8d757e6b4e2a57a69a035f26b4abec3e327)
+- Fix wrong `iat` and `exp` values when signing with `noTimestamp`. [331b7bc](https://github.com/auth0/node-jsonwebtoken/commit/331b7bc9cc335561f8806f2c4558e105cb53e0a6)
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/LICENSE b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..bcd1854c4841162bbfc81048e40697bcb81eb5c1
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+ 
+Copyright (c) 2015 Auth0, Inc. <support@auth0.com> (http://auth0.com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/README.md b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..d59766549bab10e2c03f538abfa10152ac7e506b
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/README.md
@@ -0,0 +1,260 @@
+# jsonwebtoken [![Build Status](https://secure.travis-ci.org/auth0/node-jsonwebtoken.svg?branch=master)](http://travis-ci.org/auth0/node-jsonwebtoken)[![Dependency Status](https://david-dm.org/auth0/node-jsonwebtoken.svg)](https://david-dm.org/auth0/node-jsonwebtoken)
+
+
+An implementation of [JSON Web Tokens](https://tools.ietf.org/html/rfc7519).
+
+This was developed against `draft-ietf-oauth-json-web-token-08`. It makes use of [node-jws](https://github.com/brianloveswords/node-jws)
+
+# Install
+
+```bash
+$ npm install jsonwebtoken
+```
+
+# Usage
+
+### jwt.sign(payload, secretOrPrivateKey, options, [callback])
+
+(Asynchronous) If a callback is supplied, callback is called with the `err` or the JWT.
+
+(Synchronous) Returns the JsonWebToken as string
+
+`payload` could be an object literal, buffer or string. *Please note that* `exp` is only set if the payload is an object literal.
+
+`secretOrPrivateKey` is a string or buffer containing either the secret for HMAC algorithms, or the PEM
+encoded private key for RSA and ECDSA.
+
+`options`:
+
+* `algorithm` (default: `HS256`)
+* `expiresIn`: expressed in seconds or a string describing a time span [rauchg/ms](https://github.com/rauchg/ms.js). Eg: `60`, `"2 days"`, `"10h"`, `"7d"`
+* `notBefore`: expressed in seconds or a string describing a time span [rauchg/ms](https://github.com/rauchg/ms.js). Eg: `60`, `"2 days"`, `"10h"`, `"7d"`
+* `audience`
+* `issuer`
+* `jwtid`
+* `subject`
+* `noTimestamp`
+* `header`
+
+If `payload` is not a buffer or a string, it will be coerced into a string using `JSON.stringify`.
+
+There are no default values for `expiresIn`, `notBefore`, `audience`, `subject`, `issuer`. These claims can also be provided in the payload directly with `exp`, `nbf`, `aud` and `sub` respectively, but you can't include in both places.
+
+
+The header can be customized via the `option.header` object.
+
+Generated jwts will include an `iat` (issued at) claim by default unless `noTimestamp` is specified. If `iat` is inserted in the payload, it will be used instead of the real timestamp for calculating other things like `exp` given a timespan in `options.expiresIn`.
+
+Example
+
+```js
+// sign with default (HMAC SHA256)
+var jwt = require('jsonwebtoken');
+var token = jwt.sign({ foo: 'bar' }, 'shhhhh');
+//backdate a jwt 30 seconds
+var older_token = jwt.sign({ foo: 'bar', iat: Math.floor(Date.now() / 1000) - 30 }, 'shhhhh');
+
+// sign with RSA SHA256
+var cert = fs.readFileSync('private.key');  // get private key
+var token = jwt.sign({ foo: 'bar' }, cert, { algorithm: 'RS256'});
+
+// sign asynchronously
+jwt.sign({ foo: 'bar' }, cert, { algorithm: 'RS256' }, function(err, token) {
+  console.log(token);
+});
+```
+
+### jwt.verify(token, secretOrPublicKey, [options, callback])
+
+(Asynchronous) If a callback is supplied, function acts asynchronously. Callback passed the payload decoded if the signature (and optionally expiration, audience, issuer) are valid. If not, it will be passed the error.
+
+(Synchronous) If a callback is not supplied, function acts synchronously. Returns the payload decoded if the signature (and optionally expiration, audience, issuer) are valid. If not, it will throw the error.
+
+`token` is the JsonWebToken string
+
+`secretOrPublicKey` is a string or buffer containing either the secret for HMAC algorithms, or the PEM
+encoded public key for RSA and ECDSA.
+
+`options`
+
+* `algorithms`: List of strings with the names of the allowed algorithms. For instance, `["HS256", "HS384"]`.
+* `audience`: if you want to check audience (`aud`), provide a value here
+* `issuer` (optional): string or array of strings of valid values for the `iss` field.
+* `ignoreExpiration`: if `true` do not validate the expiration of the token.
+* `ignoreNotBefore`...
+* `subject`: if you want to check subject (`sub`), provide a value here
+* `clockTolerance`: number of second to tolerate when checking the `nbf` and `exp` claims, to deal with small clock differences among different servers
+
+
+```js
+// verify a token symmetric - synchronous
+var decoded = jwt.verify(token, 'shhhhh');
+console.log(decoded.foo) // bar
+
+// verify a token symmetric
+jwt.verify(token, 'shhhhh', function(err, decoded) {
+  console.log(decoded.foo) // bar
+});
+
+// invalid token - synchronous
+try {
+  var decoded = jwt.verify(token, 'wrong-secret');
+} catch(err) {
+  // err
+}
+
+// invalid token
+jwt.verify(token, 'wrong-secret', function(err, decoded) {
+  // err
+  // decoded undefined
+});
+
+// verify a token asymmetric
+var cert = fs.readFileSync('public.pem');  // get public key
+jwt.verify(token, cert, function(err, decoded) {
+  console.log(decoded.foo) // bar
+});
+
+// verify audience
+var cert = fs.readFileSync('public.pem');  // get public key
+jwt.verify(token, cert, { audience: 'urn:foo' }, function(err, decoded) {
+  // if audience mismatch, err == invalid audience
+});
+
+// verify issuer
+var cert = fs.readFileSync('public.pem');  // get public key
+jwt.verify(token, cert, { audience: 'urn:foo', issuer: 'urn:issuer' }, function(err, decoded) {
+  // if issuer mismatch, err == invalid issuer
+});
+
+// verify jwt id
+var cert = fs.readFileSync('public.pem');  // get public key
+jwt.verify(token, cert, { audience: 'urn:foo', issuer: 'urn:issuer', jwtid: 'jwtid' }, function(err, decoded) {
+  // if jwt id mismatch, err == invalid jwt id
+});
+
+// verify subject
+var cert = fs.readFileSync('public.pem');  // get public key
+jwt.verify(token, cert, { audience: 'urn:foo', issuer: 'urn:issuer', jwtid: 'jwtid', subject: 'subject' }, function(err, decoded) {
+  // if subject mismatch, err == invalid subject
+});
+
+// alg mismatch
+var cert = fs.readFileSync('public.pem'); // get public key
+jwt.verify(token, cert, { algorithms: ['RS256'] }, function (err, payload) {
+  // if token alg != RS256,  err == invalid signature
+});
+
+```
+
+### jwt.decode(token [, options])
+
+(Synchronous) Returns the decoded payload without verifying if the signature is valid.
+
+__Warning:__ This will __not__ verify whether the signature is valid. You should __not__ use this for untrusted messages. You most likely want to use `jwt.verify` instead.
+
+`token` is the JsonWebToken string
+
+`options`:
+
+* `json`: force JSON.parse on the payload even if the header doesn't contain `"typ":"JWT"`.
+* `complete`: return an object with the decoded payload and header.
+
+Example
+
+```js
+// get the decoded payload ignoring signature, no secretOrPrivateKey needed
+var decoded = jwt.decode(token);
+
+// get the decoded payload and header
+var decoded = jwt.decode(token, {complete: true});
+console.log(decoded.header);
+console.log(decoded.payload)
+```
+
+## Errors & Codes
+Possible thrown errors during verification.
+Error is the first argument of the verification callback.
+
+### TokenExpiredError
+
+Thrown error if the token is expired.
+
+Error object:
+
+* name: 'TokenExpiredError'
+* message: 'jwt expired'
+* expiredAt: [ExpDate]
+
+```js
+jwt.verify(token, 'shhhhh', function(err, decoded) {
+  if (err) {
+    /*
+      err = {
+        name: 'TokenExpiredError',
+        message: 'jwt expired',
+        expiredAt: 1408621000
+      }
+    */
+  }
+});
+```
+
+### JsonWebTokenError
+Error object:
+
+* name: 'JsonWebTokenError'
+* message:
+  * 'jwt malformed'
+  * 'jwt signature is required'
+  * 'invalid signature'
+  * 'jwt audience invalid. expected: [OPTIONS AUDIENCE]'
+  * 'jwt issuer invalid. expected: [OPTIONS ISSUER]'
+  * 'jwt id invalid. expected: [OPTIONS JWT ID]'
+  * 'jwt subject invalid. expected: [OPTIONS SUBJECT]'
+
+```js
+jwt.verify(token, 'shhhhh', function(err, decoded) {
+  if (err) {
+    /*
+      err = {
+        name: 'JsonWebTokenError',
+        message: 'jwt malformed'
+      }
+    */
+  }
+});
+```
+
+## Algorithms supported
+
+Array of supported algorithms. The following algorithms are currently supported.
+
+alg Parameter Value | Digital Signature or MAC Algorithm
+----------------|----------------------------
+HS256 | HMAC using SHA-256 hash algorithm
+HS384 | HMAC using SHA-384 hash algorithm
+HS512 | HMAC using SHA-512 hash algorithm
+RS256 | RSASSA using SHA-256 hash algorithm
+RS384 | RSASSA using SHA-384 hash algorithm
+RS512 | RSASSA using SHA-512 hash algorithm
+ES256 | ECDSA using P-256 curve and SHA-256 hash algorithm
+ES384 | ECDSA using P-384 curve and SHA-384 hash algorithm
+ES512 | ECDSA using P-521 curve and SHA-512 hash algorithm
+none | No digital signature or MAC value included
+
+# TODO
+
+* X.509 certificate chain is not checked
+
+## Issue Reporting
+
+If you have found a bug or if you have a feature request, please report them at this repository issues section. Please do not report security vulnerabilities on the public GitHub issue tracker. The [Responsible Disclosure Program](https://auth0.com/whitehat) details the procedure for disclosing security issues.
+
+## Author
+
+[Auth0](https://auth0.com)
+
+## License
+
+This project is licensed under the MIT license. See the [LICENSE](LICENSE) file for more info.
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/bin/changelog b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/bin/changelog
new file mode 100755
index 0000000000000000000000000000000000000000..32bd74160b48d5e5428ea49f9ddd47d983bb3954
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/bin/changelog
@@ -0,0 +1,28 @@
+#!/usr/bin/env node
+
+var changelog = require('conventional-changelog');
+var semver_regex = /\bv?(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)(?:-[\da-z\-]+(?:\.[\da-z\-]+)*)?(?:\+[\da-z\-]+(?:\.[\da-z\-]+)*)?\b/ig;
+
+const commitPartial = ` - {{header}}
+
+{{~!-- commit hash --}} {{#if @root.linkReferences}}([{{hash}}]({{#if @root.host}}{{@root.host}}/{{/if}}{{#if @root.owner}}{{@root.owner}}/{{/if}}{{@root.repository}}/{{@root.commit}}/{{hash}})){{else}}{{hash~}}{{/if}}
+
+{{~!-- commit references --}}{{#if references}}, closes{{~#each references}} {{#if @root.linkReferences}}[{{#if this.owner}}{{this.owner}}/{{/if}}{{this.repository}}#{{this.issue}}]({{#if @root.host}}{{@root.host}}/{{/if}}{{#if this.repository}}{{#if this.owner}}{{this.owner}}/{{/if}}{{this.repository}}{{else}}{{#if @root.owner}}{{@root.owner}}/{{/if}}{{@root.repository}}{{/if}}/{{@root.issue}}/{{this.issue}}){{else}}{{#if this.owner}}{{this.owner}}/{{/if}}{{this.repository}}#{{this.issue}}{{/if}}{{/each}}{{/if}}
+`;
+
+const headerPartial = `## {{version}}{{#if title}} "{{title}}"{{/if}}{{#if date}} - {{date}}{{/if}}
+`;
+
+changelog({
+  releaseCount: 19,
+  // preset: 'jshint'
+}, null, null, null, {
+  transform: function (commit) {
+    if (commit.header && semver_regex.exec(commit.header)) {
+      return null;
+    }
+    return commit;
+  },
+  commitPartial: commitPartial,
+  headerPartial: headerPartial
+}).pipe(process.stdout);
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/decode.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/decode.js
new file mode 100644
index 0000000000000000000000000000000000000000..783e6e7186889d29fbf0892285339cff196b9a10
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/decode.js
@@ -0,0 +1,30 @@
+var jws = require('jws');
+
+module.exports = function (jwt, options) {
+  options = options || {};
+  var decoded = jws.decode(jwt, options);
+  if (!decoded) { return null; }
+  var payload = decoded.payload;
+
+  //try parse the payload
+  if(typeof payload === 'string') {
+    try {
+      var obj = JSON.parse(payload);
+      if(typeof obj === 'object') {
+        payload = obj;
+      }
+    } catch (e) { }
+  }
+
+  //return header if `complete` option is enabled.  header includes claims
+  //such as `kid` and `alg` used to select the key within a JWKS needed to
+  //verify the signature
+  if (options.complete === true) {
+    return {
+      header: decoded.header,
+      payload: payload,
+      signature: decoded.signature
+    };
+  }
+  return payload;
+};
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/index.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..161eb2dd16688f0a1e0238c74382e3ce1779ee6b
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/index.js
@@ -0,0 +1,8 @@
+module.exports = {
+  decode: require('./decode'),
+  verify: require('./verify'),
+  sign: require('./sign'),
+  JsonWebTokenError: require('./lib/JsonWebTokenError'),
+  NotBeforeError: require('./lib/NotBeforeError'),
+  TokenExpiredError: require('./lib/TokenExpiredError'),
+};
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/lib/JsonWebTokenError.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/lib/JsonWebTokenError.js
new file mode 100644
index 0000000000000000000000000000000000000000..7c4ea0f46f8cc9fdd973d97ba958ceff114ec6de
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/lib/JsonWebTokenError.js
@@ -0,0 +1,12 @@
+var JsonWebTokenError = function (message, error) {
+  Error.call(this, message);
+  Error.captureStackTrace(this, this.constructor);
+  this.name = 'JsonWebTokenError';
+  this.message = message;
+  if (error) this.inner = error;
+};
+
+JsonWebTokenError.prototype = Object.create(Error.prototype);
+JsonWebTokenError.prototype.constructor = JsonWebTokenError;
+
+module.exports = JsonWebTokenError;
\ No newline at end of file
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/lib/NotBeforeError.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/lib/NotBeforeError.js
new file mode 100644
index 0000000000000000000000000000000000000000..7b30084fb993130180d853e358cd693ac308d5fd
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/lib/NotBeforeError.js
@@ -0,0 +1,13 @@
+var JsonWebTokenError = require('./JsonWebTokenError');
+
+var NotBeforeError = function (message, date) {
+  JsonWebTokenError.call(this, message);
+  this.name = 'NotBeforeError';
+  this.date = date;
+};
+
+NotBeforeError.prototype = Object.create(JsonWebTokenError.prototype);
+
+NotBeforeError.prototype.constructor = NotBeforeError;
+
+module.exports = NotBeforeError;
\ No newline at end of file
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/lib/TokenExpiredError.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/lib/TokenExpiredError.js
new file mode 100644
index 0000000000000000000000000000000000000000..abb704f239c590d5d0c498fbc61c394f0de10dc5
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/lib/TokenExpiredError.js
@@ -0,0 +1,13 @@
+var JsonWebTokenError = require('./JsonWebTokenError');
+
+var TokenExpiredError = function (message, expiredAt) {
+  JsonWebTokenError.call(this, message);
+  this.name = 'TokenExpiredError';
+  this.expiredAt = expiredAt;
+};
+
+TokenExpiredError.prototype = Object.create(JsonWebTokenError.prototype);
+
+TokenExpiredError.prototype.constructor = TokenExpiredError;
+
+module.exports = TokenExpiredError;
\ No newline at end of file
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/lib/timespan.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/lib/timespan.js
new file mode 100644
index 0000000000000000000000000000000000000000..e509869082755acb5f339b95594f5a27bf7a2251
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/lib/timespan.js
@@ -0,0 +1,18 @@
+var ms = require('ms');
+
+module.exports = function (time, iat) {
+  var timestamp = iat || Math.floor(Date.now() / 1000);
+
+  if (typeof time === 'string') {
+    var milliseconds = ms(time);
+    if (typeof milliseconds === 'undefined') {
+      return;
+    }
+    return Math.floor(timestamp + milliseconds / 1000);
+  } else if (typeof time === 'number') {
+    return timestamp + time;
+  } else {
+    return;
+  }
+
+};
\ No newline at end of file
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/package.json b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..1502d7de95936d5e13e6df88901f3e289b3f29ed
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/package.json
@@ -0,0 +1,81 @@
+{
+  "_args": [
+    [
+      {
+        "raw": "jsonwebtoken@https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-7.1.9.tgz",
+        "scope": null,
+        "escapedName": "jsonwebtoken",
+        "name": "jsonwebtoken",
+        "rawSpec": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-7.1.9.tgz",
+        "spec": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-7.1.9.tgz",
+        "type": "remote"
+      },
+      "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin"
+    ]
+  ],
+  "_from": "jsonwebtoken@7.1.9",
+  "_id": "jsonwebtoken@7.1.9",
+  "_inCache": true,
+  "_location": "/firebase-admin/jsonwebtoken",
+  "_phantomChildren": {},
+  "_requested": {
+    "raw": "jsonwebtoken@https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-7.1.9.tgz",
+    "scope": null,
+    "escapedName": "jsonwebtoken",
+    "name": "jsonwebtoken",
+    "rawSpec": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-7.1.9.tgz",
+    "spec": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-7.1.9.tgz",
+    "type": "remote"
+  },
+  "_requiredBy": [
+    "/firebase-admin"
+  ],
+  "_resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-7.1.9.tgz",
+  "_shasum": "847804e5258bec5a9499a8dc4a5e7a3bae08d58a",
+  "_shrinkwrap": null,
+  "_spec": "jsonwebtoken@https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-7.1.9.tgz",
+  "_where": "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin",
+  "author": {
+    "name": "auth0"
+  },
+  "bugs": {
+    "url": "https://github.com/auth0/node-jsonwebtoken/issues"
+  },
+  "dependencies": {
+    "joi": "^6.10.1",
+    "jws": "^3.1.3",
+    "lodash.once": "^4.0.0",
+    "ms": "^0.7.1",
+    "xtend": "^4.0.1"
+  },
+  "description": "JSON Web Token implementation (symmetric and asymmetric)",
+  "devDependencies": {
+    "atob": "^1.1.2",
+    "chai": "^1.10.0",
+    "conventional-changelog": "~1.1.0",
+    "mocha": "^2.1.0",
+    "sinon": "^1.15.4"
+  },
+  "engines": {
+    "node": ">=0.12",
+    "npm": ">=1.4.28"
+  },
+  "homepage": "https://github.com/auth0/node-jsonwebtoken#readme",
+  "keywords": [
+    "jwt"
+  ],
+  "license": "MIT",
+  "main": "index.js",
+  "name": "jsonwebtoken",
+  "optionalDependencies": {},
+  "readme": "# jsonwebtoken [![Build Status](https://secure.travis-ci.org/auth0/node-jsonwebtoken.svg?branch=master)](http://travis-ci.org/auth0/node-jsonwebtoken)[![Dependency Status](https://david-dm.org/auth0/node-jsonwebtoken.svg)](https://david-dm.org/auth0/node-jsonwebtoken)\n\n\nAn implementation of [JSON Web Tokens](https://tools.ietf.org/html/rfc7519).\n\nThis was developed against `draft-ietf-oauth-json-web-token-08`. It makes use of [node-jws](https://github.com/brianloveswords/node-jws)\n\n# Install\n\n```bash\n$ npm install jsonwebtoken\n```\n\n# Usage\n\n### jwt.sign(payload, secretOrPrivateKey, options, [callback])\n\n(Asynchronous) If a callback is supplied, callback is called with the `err` or the JWT.\n\n(Synchronous) Returns the JsonWebToken as string\n\n`payload` could be an object literal, buffer or string. *Please note that* `exp` is only set if the payload is an object literal.\n\n`secretOrPrivateKey` is a string or buffer containing either the secret for HMAC algorithms, or the PEM\nencoded private key for RSA and ECDSA.\n\n`options`:\n\n* `algorithm` (default: `HS256`)\n* `expiresIn`: expressed in seconds or a string describing a time span [rauchg/ms](https://github.com/rauchg/ms.js). Eg: `60`, `\"2 days\"`, `\"10h\"`, `\"7d\"`\n* `notBefore`: expressed in seconds or a string describing a time span [rauchg/ms](https://github.com/rauchg/ms.js). Eg: `60`, `\"2 days\"`, `\"10h\"`, `\"7d\"`\n* `audience`\n* `issuer`\n* `jwtid`\n* `subject`\n* `noTimestamp`\n* `header`\n\nIf `payload` is not a buffer or a string, it will be coerced into a string using `JSON.stringify`.\n\nThere are no default values for `expiresIn`, `notBefore`, `audience`, `subject`, `issuer`. These claims can also be provided in the payload directly with `exp`, `nbf`, `aud` and `sub` respectively, but you can't include in both places.\n\n\nThe header can be customized via the `option.header` object.\n\nGenerated jwts will include an `iat` (issued at) claim by default unless `noTimestamp` is specified. If `iat` is inserted in the payload, it will be used instead of the real timestamp for calculating other things like `exp` given a timespan in `options.expiresIn`.\n\nExample\n\n```js\n// sign with default (HMAC SHA256)\nvar jwt = require('jsonwebtoken');\nvar token = jwt.sign({ foo: 'bar' }, 'shhhhh');\n//backdate a jwt 30 seconds\nvar older_token = jwt.sign({ foo: 'bar', iat: Math.floor(Date.now() / 1000) - 30 }, 'shhhhh');\n\n// sign with RSA SHA256\nvar cert = fs.readFileSync('private.key');  // get private key\nvar token = jwt.sign({ foo: 'bar' }, cert, { algorithm: 'RS256'});\n\n// sign asynchronously\njwt.sign({ foo: 'bar' }, cert, { algorithm: 'RS256' }, function(err, token) {\n  console.log(token);\n});\n```\n\n### jwt.verify(token, secretOrPublicKey, [options, callback])\n\n(Asynchronous) If a callback is supplied, function acts asynchronously. Callback passed the payload decoded if the signature (and optionally expiration, audience, issuer) are valid. If not, it will be passed the error.\n\n(Synchronous) If a callback is not supplied, function acts synchronously. Returns the payload decoded if the signature (and optionally expiration, audience, issuer) are valid. If not, it will throw the error.\n\n`token` is the JsonWebToken string\n\n`secretOrPublicKey` is a string or buffer containing either the secret for HMAC algorithms, or the PEM\nencoded public key for RSA and ECDSA.\n\n`options`\n\n* `algorithms`: List of strings with the names of the allowed algorithms. For instance, `[\"HS256\", \"HS384\"]`.\n* `audience`: if you want to check audience (`aud`), provide a value here\n* `issuer` (optional): string or array of strings of valid values for the `iss` field.\n* `ignoreExpiration`: if `true` do not validate the expiration of the token.\n* `ignoreNotBefore`...\n* `subject`: if you want to check subject (`sub`), provide a value here\n* `clockTolerance`: number of second to tolerate when checking the `nbf` and `exp` claims, to deal with small clock differences among different servers\n\n\n```js\n// verify a token symmetric - synchronous\nvar decoded = jwt.verify(token, 'shhhhh');\nconsole.log(decoded.foo) // bar\n\n// verify a token symmetric\njwt.verify(token, 'shhhhh', function(err, decoded) {\n  console.log(decoded.foo) // bar\n});\n\n// invalid token - synchronous\ntry {\n  var decoded = jwt.verify(token, 'wrong-secret');\n} catch(err) {\n  // err\n}\n\n// invalid token\njwt.verify(token, 'wrong-secret', function(err, decoded) {\n  // err\n  // decoded undefined\n});\n\n// verify a token asymmetric\nvar cert = fs.readFileSync('public.pem');  // get public key\njwt.verify(token, cert, function(err, decoded) {\n  console.log(decoded.foo) // bar\n});\n\n// verify audience\nvar cert = fs.readFileSync('public.pem');  // get public key\njwt.verify(token, cert, { audience: 'urn:foo' }, function(err, decoded) {\n  // if audience mismatch, err == invalid audience\n});\n\n// verify issuer\nvar cert = fs.readFileSync('public.pem');  // get public key\njwt.verify(token, cert, { audience: 'urn:foo', issuer: 'urn:issuer' }, function(err, decoded) {\n  // if issuer mismatch, err == invalid issuer\n});\n\n// verify jwt id\nvar cert = fs.readFileSync('public.pem');  // get public key\njwt.verify(token, cert, { audience: 'urn:foo', issuer: 'urn:issuer', jwtid: 'jwtid' }, function(err, decoded) {\n  // if jwt id mismatch, err == invalid jwt id\n});\n\n// verify subject\nvar cert = fs.readFileSync('public.pem');  // get public key\njwt.verify(token, cert, { audience: 'urn:foo', issuer: 'urn:issuer', jwtid: 'jwtid', subject: 'subject' }, function(err, decoded) {\n  // if subject mismatch, err == invalid subject\n});\n\n// alg mismatch\nvar cert = fs.readFileSync('public.pem'); // get public key\njwt.verify(token, cert, { algorithms: ['RS256'] }, function (err, payload) {\n  // if token alg != RS256,  err == invalid signature\n});\n\n```\n\n### jwt.decode(token [, options])\n\n(Synchronous) Returns the decoded payload without verifying if the signature is valid.\n\n__Warning:__ This will __not__ verify whether the signature is valid. You should __not__ use this for untrusted messages. You most likely want to use `jwt.verify` instead.\n\n`token` is the JsonWebToken string\n\n`options`:\n\n* `json`: force JSON.parse on the payload even if the header doesn't contain `\"typ\":\"JWT\"`.\n* `complete`: return an object with the decoded payload and header.\n\nExample\n\n```js\n// get the decoded payload ignoring signature, no secretOrPrivateKey needed\nvar decoded = jwt.decode(token);\n\n// get the decoded payload and header\nvar decoded = jwt.decode(token, {complete: true});\nconsole.log(decoded.header);\nconsole.log(decoded.payload)\n```\n\n## Errors & Codes\nPossible thrown errors during verification.\nError is the first argument of the verification callback.\n\n### TokenExpiredError\n\nThrown error if the token is expired.\n\nError object:\n\n* name: 'TokenExpiredError'\n* message: 'jwt expired'\n* expiredAt: [ExpDate]\n\n```js\njwt.verify(token, 'shhhhh', function(err, decoded) {\n  if (err) {\n    /*\n      err = {\n        name: 'TokenExpiredError',\n        message: 'jwt expired',\n        expiredAt: 1408621000\n      }\n    */\n  }\n});\n```\n\n### JsonWebTokenError\nError object:\n\n* name: 'JsonWebTokenError'\n* message:\n  * 'jwt malformed'\n  * 'jwt signature is required'\n  * 'invalid signature'\n  * 'jwt audience invalid. expected: [OPTIONS AUDIENCE]'\n  * 'jwt issuer invalid. expected: [OPTIONS ISSUER]'\n  * 'jwt id invalid. expected: [OPTIONS JWT ID]'\n  * 'jwt subject invalid. expected: [OPTIONS SUBJECT]'\n\n```js\njwt.verify(token, 'shhhhh', function(err, decoded) {\n  if (err) {\n    /*\n      err = {\n        name: 'JsonWebTokenError',\n        message: 'jwt malformed'\n      }\n    */\n  }\n});\n```\n\n## Algorithms supported\n\nArray of supported algorithms. The following algorithms are currently supported.\n\nalg Parameter Value | Digital Signature or MAC Algorithm\n----------------|----------------------------\nHS256 | HMAC using SHA-256 hash algorithm\nHS384 | HMAC using SHA-384 hash algorithm\nHS512 | HMAC using SHA-512 hash algorithm\nRS256 | RSASSA using SHA-256 hash algorithm\nRS384 | RSASSA using SHA-384 hash algorithm\nRS512 | RSASSA using SHA-512 hash algorithm\nES256 | ECDSA using P-256 curve and SHA-256 hash algorithm\nES384 | ECDSA using P-384 curve and SHA-384 hash algorithm\nES512 | ECDSA using P-521 curve and SHA-512 hash algorithm\nnone | No digital signature or MAC value included\n\n# TODO\n\n* X.509 certificate chain is not checked\n\n## Issue Reporting\n\nIf you have found a bug or if you have a feature request, please report them at this repository issues section. Please do not report security vulnerabilities on the public GitHub issue tracker. The [Responsible Disclosure Program](https://auth0.com/whitehat) details the procedure for disclosing security issues.\n\n## Author\n\n[Auth0](https://auth0.com)\n\n## License\n\nThis project is licensed under the MIT license. See the [LICENSE](LICENSE) file for more info.\n",
+  "readmeFilename": "README.md",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/auth0/node-jsonwebtoken.git"
+  },
+  "scripts": {
+    "test": "mocha --require test/util/fakeDate"
+  },
+  "version": "7.1.9"
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/sign.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/sign.js
new file mode 100644
index 0000000000000000000000000000000000000000..cfdfdabc92817888ec6e7ece97998dbe3478ba62
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/sign.js
@@ -0,0 +1,146 @@
+var Joi = require('joi');
+var timespan = require('./lib/timespan');
+var xtend = require('xtend');
+var jws = require('jws');
+var once = require('lodash.once');
+
+var sign_options_schema = Joi.object().keys({
+  expiresIn: [Joi.number().integer(), Joi.string()],
+  notBefore: [Joi.number().integer(), Joi.string()],
+  audience: [Joi.string(), Joi.array()],
+  algorithm: Joi.string().valid('RS256', 'RS384', 'RS512', 'ES256', 'ES384', 'ES512', 'HS256', 'HS384', 'HS512', 'none'),
+  header: Joi.object(),
+  encoding: Joi.string(),
+  issuer: Joi.string(),
+  subject: Joi.string(),
+  jwtid: Joi.string(),
+  noTimestamp: Joi.boolean()
+});
+
+var registered_claims_schema = Joi.object().keys({
+  iat: Joi.number(),
+  exp: Joi.number(),
+  nbf: Joi.number()
+}).unknown();
+
+
+var options_to_payload = {
+  'audience': 'aud',
+  'issuer': 'iss',
+  'subject': 'sub',
+  'jwtid': 'jti'
+};
+
+var options_for_objects = [
+  'expiresIn',
+  'notBefore',
+  'noTimestamp',
+  'audience',
+  'issuer',
+  'subject',
+  'jwtid',
+];
+
+module.exports = function (payload, secretOrPrivateKey, options, callback) {
+  options = options || {};
+
+  var isObjectPayload = typeof payload === 'object' &&
+                        !Buffer.isBuffer(payload);
+
+  var header = xtend({
+    alg: options.algorithm || 'HS256',
+    typ: isObjectPayload ? 'JWT' : undefined
+  }, options.header);
+
+  function failure(err) {
+    if (callback) {
+      return callback(err);
+    }
+    throw err;
+  }
+
+
+  if (typeof payload === 'undefined') {
+    return failure(new Error('payload is required'));
+  } else if (isObjectPayload) {
+    var payload_validation_result = registered_claims_schema.validate(payload);
+
+    if (payload_validation_result.error) {
+      return failure(payload_validation_result.error);
+    }
+
+    payload = xtend(payload);
+  } else {
+    var invalid_options = options_for_objects.filter(function (opt) {
+      return typeof options[opt] !== 'undefined';
+    });
+
+    if (invalid_options.length > 0) {
+      return failure(new Error('invalid ' + invalid_options.join(',') + ' option for ' + (typeof payload ) + ' payload'));
+    }
+  }
+
+  if (typeof payload.exp !== 'undefined' && typeof options.expiresIn !== 'undefined') {
+    return failure(new Error('Bad "options.expiresIn" option the payload already has an "exp" property.'));
+  }
+
+  if (typeof payload.nbf !== 'undefined' && typeof options.notBefore !== 'undefined') {
+    return failure(new Error('Bad "options.notBefore" option the payload already has an "nbf" property.'));
+  }
+
+  var validation_result = sign_options_schema.validate(options);
+
+  if (validation_result.error) {
+    return failure(validation_result.error);
+  }
+
+  var timestamp = payload.iat || Math.floor(Date.now() / 1000);
+
+  if (!options.noTimestamp) {
+    payload.iat = timestamp;
+  } else {
+    delete payload.iat;
+  }
+
+  if (typeof options.notBefore !== 'undefined') {
+    payload.nbf = timespan(options.notBefore);
+    if (typeof payload.nbf === 'undefined') {
+      return failure(new Error('"notBefore" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60'));
+    }
+  }
+
+  if (typeof options.expiresIn !== 'undefined' && typeof payload === 'object') {
+    payload.exp = timespan(options.expiresIn, timestamp);
+    if (typeof payload.exp === 'undefined') {
+      return failure(new Error('"expiresIn" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60'));
+    }
+  }
+
+  Object.keys(options_to_payload).forEach(function (key) {
+    var claim = options_to_payload[key];
+    if (typeof options[key] !== 'undefined') {
+      if (typeof payload[claim] !== 'undefined') {
+        return failure(new Error('Bad "options.' + key + '" option. The payload already has an "' + claim + '" property.'));
+      }
+      payload[claim] = options[key];
+    }
+  });
+
+  var encoding = options.encoding || 'utf8';
+
+  if (typeof callback === 'function') {
+    callback = callback && once(callback);
+
+    jws.createSign({
+      header: header,
+      privateKey: secretOrPrivateKey,
+      payload: payload,
+      encoding: encoding
+    }).once('error', callback)
+      .once('done', function (signature) {
+        callback(null, signature);
+      });
+  } else {
+    return jws.sign({header: header, payload: payload, secret: secretOrPrivateKey, encoding: encoding});
+  }
+};
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/async_sign.tests.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/async_sign.tests.js
new file mode 100644
index 0000000000000000000000000000000000000000..da40dee44022ea1391a99d26fbfb37481d32858a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/async_sign.tests.js
@@ -0,0 +1,60 @@
+var jwt = require('../index');
+var expect = require('chai').expect;
+var jws = require('jws');
+
+describe('signing a token asynchronously', function() {
+
+  describe('when signing a token', function() {
+    var secret = 'shhhhhh';
+
+    it('should return the same result as singing synchronously', function(done) {
+      jwt.sign({ foo: 'bar' }, secret, { algorithm: 'HS256' }, function (err, asyncToken) {
+        if (err) return done(err);
+        var syncToken = jwt.sign({ foo: 'bar' }, secret, { algorithm: 'HS256' });
+        expect(asyncToken).to.be.a('string');
+        expect(asyncToken.split('.')).to.have.length(3);
+        expect(asyncToken).to.equal(syncToken);
+        done();
+      });
+    });
+
+    it('should work', function (done) {
+      jwt.sign({abc: 1}, "secret", {}, function (err, res) {
+        expect(err).to.be.null();
+        done();
+      });
+    });
+
+    it('should return error when secret is not a cert for RS256', function(done) {
+      //this throw an error because the secret is not a cert and RS256 requires a cert.
+      jwt.sign({ foo: 'bar' }, secret, { algorithm: 'RS256' }, function (err) {
+        expect(err).to.be.ok();
+        done();
+      });
+    });
+
+    it('should return error on wrong arguments', function(done) {
+      //this throw an error because the secret is not a cert and RS256 requires a cert.
+      jwt.sign({ foo: 'bar' }, secret, { notBefore: {} }, function (err) {
+        expect(err).to.be.ok();
+        done();
+      });
+    });
+
+    it('should return error on wrong arguments (2)', function(done) {
+      jwt.sign('string', 'secret', {noTimestamp: true}, function (err) {
+        expect(err).to.be.ok();
+        expect(err).to.be.instanceof(Error);
+        done();
+      });
+    });
+
+    it('should not stringify the payload', function (done) {
+      jwt.sign('string', 'secret', {}, function (err, token) {
+        if (err) { return done(err); }
+        expect(jws.decode(token).payload).to.equal('string');
+        done();
+      });
+    });
+  });
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/buffer.tests.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/buffer.tests.js
new file mode 100644
index 0000000000000000000000000000000000000000..612d171ba51229cac4e2281ce6d8ae6070a3c135
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/buffer.tests.js
@@ -0,0 +1,10 @@
+var jwt = require("../.");
+var assert = require('chai').assert;
+
+describe('buffer payload', function () {
+  it('should work', function () {
+    var payload = new Buffer('TkJyotZe8NFpgdfnmgINqg==', 'base64');
+    var token = jwt.sign(payload, "signing key");
+    assert.equal(jwt.decode(token), payload.toString());
+  });
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/encoding.tests.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/encoding.tests.js
new file mode 100644
index 0000000000000000000000000000000000000000..e5d0e76fc8bb081bc1f711d1dd4ac739abffc1a0
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/encoding.tests.js
@@ -0,0 +1,37 @@
+var jwt = require('../index');
+var expect = require('chai').expect;
+var atob = require('atob');
+
+describe('encoding', function() {
+
+  function b64_to_utf8 (str) {
+    return decodeURIComponent(escape(atob( str )));
+  }
+
+  it('should properly encode the token (utf8)', function () {
+    var expected = 'José';
+    var token = jwt.sign({ name: expected }, 'shhhhh');
+    var decoded_name = JSON.parse(b64_to_utf8(token.split('.')[1])).name;
+    expect(decoded_name).to.equal(expected);
+  });
+
+  it('should properly encode the token (binary)', function () {
+    var expected = 'José';
+    var token = jwt.sign({ name: expected }, 'shhhhh', { encoding: 'binary' });
+    var decoded_name = JSON.parse(atob(token.split('.')[1])).name;
+    expect(decoded_name).to.equal(expected);
+  });
+
+  it('should return the same result when decoding', function () {
+    var username = '測試';
+
+    var token = jwt.sign({
+      username: username
+    }, 'test');
+
+    var payload = jwt.verify(token, 'test');
+
+    expect(payload.username).to.equal(username);
+  });
+
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/expires_format.tests.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/expires_format.tests.js
new file mode 100644
index 0000000000000000000000000000000000000000..42d18a594605e1b369f2604300d92f28fdf91db5
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/expires_format.tests.js
@@ -0,0 +1,53 @@
+var jwt = require('../index');
+var expect = require('chai').expect;
+
+describe('expires option', function() {
+
+  it('should work with a number of seconds', function () {
+    var token = jwt.sign({foo: 123}, '123', { expiresIn: 10 });
+    var result = jwt.verify(token, '123');
+    expect(result.exp).to.be.closeTo(Math.floor(Date.now() / 1000) + 10, 0.2);
+  });
+
+  it('should work with a string', function () {
+    var token = jwt.sign({foo: 123}, '123', { expiresIn: '2d' });
+    var result = jwt.verify(token, '123');
+    var two_days_in_secs = 2 * 24 * 60 * 60;
+    expect(result.exp).to.be.closeTo(Math.floor(Date.now() / 1000) + two_days_in_secs, 0.2);
+  });
+
+  it('should work with a string second example', function () {
+    var token = jwt.sign({foo: 123}, '123', { expiresIn: '36h' });
+    var result = jwt.verify(token, '123');
+    var day_and_a_half_in_secs = 1.5 * 24 * 60 * 60;
+    expect(result.exp).to.be.closeTo(Math.floor(Date.now() / 1000) + day_and_a_half_in_secs, 0.2);
+  });
+
+
+  it('should throw if expires has a bad string format', function () {
+    expect(function () {
+      jwt.sign({foo: 123}, '123', { expiresIn: '1 monkey' });
+    }).to.throw(/"expiresIn" should be a number of seconds or string representing a timespan/);
+  });
+
+  it('should throw if expires is not an string or number', function () {
+    expect(function () {
+      jwt.sign({foo: 123}, '123', { expiresIn: { crazy : 213 } });
+    }).to.throw(/"expiresIn" must be a number/);
+  });
+
+  it('should throw an error if expiresIn and exp are provided', function () {
+    expect(function () {
+      jwt.sign({ foo: 123, exp: 839218392183 }, '123', { expiresIn: '5h' });
+    }).to.throw(/Bad "options.expiresIn" option the payload already has an "exp" property./);
+  });
+
+
+  it('should throw on deprecated expiresInSeconds option', function () {
+    expect(function () {
+      jwt.sign({foo: 123}, '123', { expiresInSeconds: 5 });
+    }).to.throw('"expiresInSeconds" is not allowed');
+  });
+
+
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/iat.tests.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/iat.tests.js
new file mode 100644
index 0000000000000000000000000000000000000000..6d2c2c02a13867b1ee8aacf27eef8ae8838f1d1f
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/iat.tests.js
@@ -0,0 +1,22 @@
+var jwt = require('../index');
+var expect = require('chai').expect;
+
+describe('iat', function () {
+
+  it('should work with a exp calculated based on numeric iat', function () {
+    var dateNow = Math.floor(Date.now() / 1000);
+    var iat = dateNow - 30;
+    var expiresIn = 50;
+    var token = jwt.sign({foo: 123, iat: iat}, '123', {expiresIn: expiresIn});
+    var result = jwt.verify(token, '123');
+    expect(result.exp).to.be.closeTo(iat + expiresIn, 0.2);
+  });
+
+
+  it('should throw if iat is not a number', function () {
+    expect(function () {
+      jwt.sign({foo: 123, iat: 'hello'}, '123');
+    }).to.throw(/"iat" must be a number/);
+  });
+
+});
\ No newline at end of file
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/invalid_exp.tests.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/invalid_exp.tests.js
new file mode 100644
index 0000000000000000000000000000000000000000..397b62fea52490d062533a35e5f8d4f8cff3bedf
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/invalid_exp.tests.js
@@ -0,0 +1,58 @@
+var jwt = require('../index');
+var expect = require('chai').expect;
+var assert = require('chai').assert;
+
+describe('invalid expiration', function() {
+
+  it('should fail with string', function (done) {
+    var broken_token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIxMjMiLCJmb28iOiJhZGFzIn0.cDa81le-pnwJMcJi3o3PBwB7cTJMiXCkizIhxbXAKRg';
+
+    jwt.verify(broken_token, '123', function (err, decoded) {
+      expect(err.name).to.equal('JsonWebTokenError');
+      done();
+    });
+
+  });
+
+  it('should fail with 0', function (done) {
+    var broken_token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjAsImZvbyI6ImFkYXMifQ.UKxix5T79WwfqAA0fLZr6UrhU-jMES2unwCOFa4grEA';
+
+    jwt.verify(broken_token, '123', function (err) {
+      expect(err.name).to.equal('TokenExpiredError');
+      done();
+    });
+
+  });
+
+  it('should fail with false', function (done) {
+    var broken_token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOmZhbHNlLCJmb28iOiJhZGFzIn0.iBn33Plwhp-ZFXqppCd8YtED77dwWU0h68QS_nEQL8I';
+
+    jwt.verify(broken_token, '123', function (err) {
+      expect(err.name).to.equal('JsonWebTokenError');
+      done();
+    });
+
+  });
+
+  it('should fail with true', function (done) {
+    var broken_token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOnRydWUsImZvbyI6ImFkYXMifQ.eOWfZCTM5CNYHAKSdFzzk2tDkPQmRT17yqllO-ItIMM';
+
+    jwt.verify(broken_token, '123', function (err) {
+      expect(err.name).to.equal('JsonWebTokenError');
+      done();
+    });
+
+  });
+
+  it('should fail with object', function (done) {
+    var broken_token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOnt9LCJmb28iOiJhZGFzIn0.1JjCTsWLJ2DF-CfESjLdLfKutUt3Ji9cC7ESlcoBHSY';
+
+    jwt.verify(broken_token, '123', function (err) {
+      expect(err.name).to.equal('JsonWebTokenError');
+      done();
+    });
+
+  });
+
+
+});
\ No newline at end of file
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/invalid_pub.pem b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/invalid_pub.pem
new file mode 100644
index 0000000000000000000000000000000000000000..2482abbde0ac8a0bc642abb61e2dfa2f80d24b02
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/invalid_pub.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDJjCCAg6gAwIBAgIJAMyz3mSPlaW4MA0GCSqGSIb3DQEBBQUAMBYxFDASBgNV
+BAMUCyouYXV0aDAuY29tMB4XDTEzMDQxODE3MDE1MFoXDTI2MTIyNjE3MDE1MFow
+FjEUMBIGA1UEAxQLKi5hdXRoMC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDZq1Ua0/BGm+TaBFoftKWeYMWrQG9Fx3g7ikErxljmyOvlwqkiat3q
+ixX+Dxw9TFb5gbBjNJ+L3nt4YefJgLsYvsHqkOUxWsB+HM/ulJRVnVrZm1tI3Nbg
+xO1BQ7DrGfBpq2KCxtQCaQFRlQJw1+qS5LwrdIvihB7Kc142VElCFFHJ6+09eMUy
+jy00Z5pfQr4Am6W6eEOS9ObDbNs4XgKOcWe5khWXj3UStou+VgbAg40XcYht2IbY
+gMfKF+VUZOy3+e+aRTqPOBU3MAeb0tvCCPUQJbNAUHgSKVhAvNf8mRwttVsOLT70
+anjjeCOd7RKS8fVKBwc2KtgNkghYdPY9AgMBAAGjdzB1MB0GA1UdDgQWBBSi4+X0
++MvCKDdd375mDhx/ZBbJ4DBGBgNVHSMEPzA9gBSi4+X0+MvCKDdd375mDhx/ZBbJ
+4KEapBgwFjEUMBIGA1UEAxQLKi5hdXRoMC5jb22CCQDMs95kj5WluDAMBgNVHRME
+BTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQBi0qPe0DzlPSufq+Gdk2Fwf1pGEtjA
+D34IxxJ9SX6r1DS/NIP7IOLUnNU8cP8BQWl7i413v29jJsNV457pjdmqf8J7OE9O
+eF5Yz1x91gY/27561Iga/TQeIVOlFQAgx66eLfUFFoAig3hz2srZo5TzYBixMJsS
+fYMXHPiU7KoLUqYXvpSXIllstQCu51KCC6t9H7wZ92lTES1v76hFY4edQ30sftPo
+kjAYWGEhMjPo/r4THcdSMqKXoRtCGEun4pTXid7MJcTgdGDrAJddLWi6SxKecEVB
+MhMu4XfUCdxCwqQPjHeJ+zE49A1CUdBB2FN3BNLbmTTwEBgmuwyGRzhj
+-----END CERTIFICATE-----
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/issue_147.tests.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/issue_147.tests.js
new file mode 100644
index 0000000000000000000000000000000000000000..57ecc8c62b66c631e6d2f270915af2471fb4ae8a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/issue_147.tests.js
@@ -0,0 +1,12 @@
+var jwt = require('../index');
+var expect = require('chai').expect;
+
+describe('issue 147 - signing with a sealed payload', function() {
+
+  it('should put the expiration claim', function () {
+    var token = jwt.sign(Object.seal({foo: 123}), '123', { expiresIn: 10 });
+    var result = jwt.verify(token, '123');
+    expect(result.exp).to.be.closeTo(Math.floor(Date.now() / 1000) + 10, 0.2);
+  });
+
+});
\ No newline at end of file
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/issue_196.tests.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/issue_196.tests.js
new file mode 100644
index 0000000000000000000000000000000000000000..7bd9a94e25f54681b91ea07d7d71f634efddd294
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/issue_196.tests.js
@@ -0,0 +1,15 @@
+var expect = require('chai').expect;
+var jwt = require('./..');
+var atob = require('atob');
+
+describe('issue 196', function () {
+  function b64_to_utf8 (str) {
+    return decodeURIComponent(escape(atob( str )));
+  }
+
+  it('should use issuer provided in payload.iss', function () {
+    var token = jwt.sign({ iss: 'foo' }, 'shhhhh');
+    var decoded_issuer = JSON.parse(b64_to_utf8(token.split('.')[1])).iss;
+    expect(decoded_issuer).to.equal('foo');
+  });
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/issue_70.tests.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/issue_70.tests.js
new file mode 100644
index 0000000000000000000000000000000000000000..90d8581879a5216e2135e0d776e95b56d9c0af59
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/issue_70.tests.js
@@ -0,0 +1,15 @@
+var jwt = require('../');
+
+describe('issue 70 - public key start with BEING PUBLIC KEY', function () {
+
+  it('should work', function (done) {
+    var fs = require('fs');
+    var cert_pub = fs.readFileSync(__dirname + '/rsa-public.pem');
+    var cert_priv = fs.readFileSync(__dirname + '/rsa-private.pem');
+
+    var token = jwt.sign({ foo: 'bar' }, cert_priv, { algorithm: 'RS256'});
+
+    jwt.verify(token, cert_pub, done);
+  });
+
+});
\ No newline at end of file
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/jwt.hs.tests.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/jwt.hs.tests.js
new file mode 100644
index 0000000000000000000000000000000000000000..b1ec9caf87846b11ace6455c52f4ce017fa6957d
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/jwt.hs.tests.js
@@ -0,0 +1,82 @@
+var jwt = require('../index');
+
+var expect = require('chai').expect;
+var assert = require('chai').assert;
+
+describe('HS256', function() {
+
+  describe('when signing a token', function() {
+    var secret = 'shhhhhh';
+
+    var token = jwt.sign({ foo: 'bar' }, secret, { algorithm: 'HS256' });
+
+    it('should be syntactically valid', function() {
+      expect(token).to.be.a('string');
+      expect(token.split('.')).to.have.length(3);
+    });
+
+    it('should without options', function(done) {
+      var callback = function(err, decoded) {
+        assert.ok(decoded.foo);
+        assert.equal('bar', decoded.foo);
+        done();
+      };
+      callback.issuer = "shouldn't affect";
+      jwt.verify(token, secret, callback );
+    });
+
+    it('should validate with secret', function(done) {
+      jwt.verify(token, secret, function(err, decoded) {
+        assert.ok(decoded.foo);
+        assert.equal('bar', decoded.foo);
+        done();
+      });
+    });
+
+    it('should throw with invalid secret', function(done) {
+      jwt.verify(token, 'invalid secret', function(err, decoded) {
+        assert.isUndefined(decoded);
+        assert.isNotNull(err);
+        done();
+      });
+    });
+
+    it('should throw with secret and token not signed', function(done) {
+      var signed = jwt.sign({ foo: 'bar' }, secret, { algorithm: 'none' });
+      var unsigned = signed.split('.')[0] + '.' + signed.split('.')[1] + '.';
+      jwt.verify(unsigned, 'secret', function(err, decoded) {
+        assert.isUndefined(decoded);
+        assert.isNotNull(err);
+        done();
+      });
+    });
+
+    it('should throw when verifying null', function(done) {
+      jwt.verify(null, 'secret', function(err, decoded) {
+        assert.isUndefined(decoded);
+        assert.isNotNull(err);
+        done();
+      });
+    });
+
+    it('should return an error when the token is expired', function(done) {
+      var token = jwt.sign({ exp: 1 }, secret, { algorithm: 'HS256' });
+      jwt.verify(token, secret, { algorithm: 'HS256' }, function(err, decoded) {
+        assert.isUndefined(decoded);
+        assert.isNotNull(err);
+        done();
+      });
+    });
+
+    it('should NOT return an error when the token is expired with "ignoreExpiration"', function(done) {
+      var token = jwt.sign({ exp: 1, foo: 'bar' }, secret, { algorithm: 'HS256' });
+      jwt.verify(token, secret, { algorithm: 'HS256', ignoreExpiration: true }, function(err, decoded) {
+        assert.ok(decoded.foo);
+        assert.equal('bar', decoded.foo);
+        assert.isNull(err);
+        done();
+      });
+    });
+
+  });
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/jwt.rs.tests.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/jwt.rs.tests.js
new file mode 100644
index 0000000000000000000000000000000000000000..5bd328a3f0f0ddacd8c6e5e215f0adca752a30bb
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/jwt.rs.tests.js
@@ -0,0 +1,423 @@
+var jwt = require('../index');
+var fs = require('fs');
+var path = require('path');
+
+var expect = require('chai').expect;
+var assert = require('chai').assert;
+var ms = require('ms');
+
+describe('RS256', function() {
+  var pub = fs.readFileSync(path.join(__dirname, 'pub.pem'));
+  var priv = fs.readFileSync(path.join(__dirname, 'priv.pem'));
+  var invalid_pub = fs.readFileSync(path.join(__dirname, 'invalid_pub.pem'));
+
+  describe('when signing a token', function() {
+    var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256' });
+
+    it('should be syntactically valid', function() {
+      expect(token).to.be.a('string');
+      expect(token.split('.')).to.have.length(3);
+    });
+
+    context('asynchronous', function() {
+      it('should validate with public key', function(done) {
+        jwt.verify(token, pub, function(err, decoded) {
+          assert.ok(decoded.foo);
+          assert.equal('bar', decoded.foo);
+          done();
+        });
+      });
+
+      it('should throw with invalid public key', function(done) {
+        jwt.verify(token, invalid_pub, function(err, decoded) {
+          assert.isUndefined(decoded);
+          assert.isNotNull(err);
+          done();
+        });
+      });
+    });
+
+    context('synchronous', function() {
+      it('should validate with public key', function() {
+        var decoded = jwt.verify(token, pub);
+        assert.ok(decoded.foo);
+        assert.equal('bar', decoded.foo);
+      });
+
+      it('should throw with invalid public key', function() {
+        var jwtVerify = jwt.verify.bind(null, token, invalid_pub)
+        assert.throw(jwtVerify, 'invalid signature');
+      });
+    });
+
+  });
+
+  describe('when signing a token with expiration', function() {
+    var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', expiresIn: '10m' });
+
+    it('should be valid expiration', function(done) {
+      jwt.verify(token, pub, function(err, decoded) {
+        assert.isNotNull(decoded);
+        assert.isNull(err);
+        done();
+      });
+    });
+
+    it('should be invalid', function(done) {
+      // expired token
+      token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', expiresIn: -1 * ms('10m') });
+
+      jwt.verify(token, pub, function(err, decoded) {
+        assert.isUndefined(decoded);
+        assert.isNotNull(err);
+        assert.equal(err.name, 'TokenExpiredError');
+        assert.instanceOf(err.expiredAt, Date);
+        assert.instanceOf(err, jwt.TokenExpiredError);
+        done();
+      });
+    });
+
+    it('should NOT be invalid', function(done) {
+      // expired token
+      token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', expiresIn: -1 * ms('10m') });
+
+      jwt.verify(token, pub, { ignoreExpiration: true }, function(err, decoded) {
+        assert.ok(decoded.foo);
+        assert.equal('bar', decoded.foo);
+        done();
+      });
+    });
+  });
+
+  describe('when signing a token with not before', function() {
+    var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', notBefore: -10 * 3600 });
+
+    it('should be valid expiration', function(done) {
+      jwt.verify(token, pub, function(err, decoded) {
+        assert.isNotNull(decoded);
+        assert.isNull(err);
+        done();
+      });
+    });
+
+    it('should be invalid', function(done) {
+      // not active token
+      token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', notBefore: '10m' });
+
+      jwt.verify(token, pub, function(err, decoded) {
+        assert.isUndefined(decoded);
+        assert.isNotNull(err);
+        assert.equal(err.name, 'NotBeforeError');
+        assert.instanceOf(err.date, Date);
+        assert.instanceOf(err, jwt.NotBeforeError);
+        done();
+      });
+    });
+
+
+    it('should valid when date are equals', function(done) {
+      Date.fix(1451908031);
+
+      token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', notBefore: 0 });
+
+      jwt.verify(token, pub, function(err, decoded) {
+        assert.isNull(err);
+        assert.isNotNull(decoded);
+        Date.unfix();
+        done();
+      });
+    });
+
+    it('should NOT be invalid', function(done) {
+      // not active token
+      token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', notBefore: '10m' });
+
+      jwt.verify(token, pub, { ignoreNotBefore: true }, function(err, decoded) {
+        assert.ok(decoded.foo);
+        assert.equal('bar', decoded.foo);
+        done();
+      });
+    });
+  });
+
+  describe('when signing a token with audience', function() {
+    var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', audience: 'urn:foo' });
+
+    it('should check audience', function(done) {
+      jwt.verify(token, pub, { audience: 'urn:foo' }, function(err, decoded) {
+        assert.isNotNull(decoded);
+        assert.isNull(err);
+        done();
+      });
+    });
+
+    it('should check audience in array', function(done) {
+      jwt.verify(token, pub, { audience: ['urn:foo', 'urn:other'] }, function (err, decoded) {
+        assert.isNotNull(decoded);
+        assert.isNull(err);
+        done();
+      });
+    });
+
+    it('should throw when invalid audience', function(done) {
+      jwt.verify(token, pub, { audience: 'urn:wrong' }, function(err, decoded) {
+        assert.isUndefined(decoded);
+        assert.isNotNull(err);
+        assert.equal(err.name, 'JsonWebTokenError');
+        assert.instanceOf(err, jwt.JsonWebTokenError);
+        done();
+      });
+    });
+
+    it('should throw when invalid audience in array', function(done) {
+      jwt.verify(token, pub, { audience: ['urn:wrong', 'urn:morewrong'] }, function(err, decoded) {
+        assert.isUndefined(decoded);
+        assert.isNotNull(err);
+        assert.equal(err.name, 'JsonWebTokenError');
+        assert.instanceOf(err, jwt.JsonWebTokenError);
+        done();
+      });
+    });
+
+  });
+
+  describe('when signing a token with array audience', function() {
+    var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', audience: [ 'urn:foo', 'urn:bar' ] });
+
+    it('should check audience', function(done) {
+      jwt.verify(token, pub, { audience: 'urn:foo' }, function(err, decoded) {
+        assert.isNotNull(decoded);
+        assert.isNull(err);
+        done();
+      });
+    });
+
+    it('should check other audience', function(done) {
+      jwt.verify(token, pub, { audience: 'urn:bar' }, function(err, decoded) {
+        assert.isNotNull(decoded);
+        assert.isNull(err);
+        done();
+      });
+    });
+
+    it('should check audience in array', function(done) {
+      jwt.verify(token, pub, { audience: ['urn:foo', 'urn:other'] }, function (err, decoded) {
+        assert.isNotNull(decoded);
+        assert.isNull(err);
+        done();
+      });
+    });
+
+    it('should throw when invalid audience', function(done) {
+      jwt.verify(token, pub, { audience: 'urn:wrong' }, function(err, decoded) {
+        assert.isUndefined(decoded);
+        assert.isNotNull(err);
+        assert.equal(err.name, 'JsonWebTokenError');
+        assert.instanceOf(err, jwt.JsonWebTokenError);
+        done();
+      });
+    });
+
+    it('should throw when invalid audience in array', function(done) {
+      jwt.verify(token, pub, { audience: ['urn:wrong', 'urn:morewrong'] }, function(err, decoded) {
+        assert.isUndefined(decoded);
+        assert.isNotNull(err);
+        assert.equal(err.name, 'JsonWebTokenError');
+        assert.instanceOf(err, jwt.JsonWebTokenError);
+        done();
+      });
+    });
+
+  });
+
+  describe('when signing a token without audience', function() {
+    var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256' });
+
+    it('should check audience', function(done) {
+      jwt.verify(token, pub, { audience: 'urn:wrong' }, function(err, decoded) {
+        assert.isUndefined(decoded);
+        assert.isNotNull(err);
+        assert.equal(err.name, 'JsonWebTokenError');
+        assert.instanceOf(err, jwt.JsonWebTokenError);
+        done();
+      });
+    });
+
+    it('should check audience in array', function(done) {
+      jwt.verify(token, pub, { audience: ['urn:wrong', 'urn:morewrong'] }, function(err, decoded) {
+        assert.isUndefined(decoded);
+        assert.isNotNull(err);
+        assert.equal(err.name, 'JsonWebTokenError');
+        assert.instanceOf(err, jwt.JsonWebTokenError);
+        done();
+      });
+    });
+
+  });
+
+  describe('when signing a token with issuer', function() {
+    var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', issuer: 'urn:foo' });
+
+    it('should check issuer', function(done) {
+      jwt.verify(token, pub, { issuer: 'urn:foo' }, function(err, decoded) {
+        assert.isNotNull(decoded);
+        assert.isNull(err);
+        done();
+      });
+    });
+
+    it('should check the issuer when providing a list of valid issuers', function(done) {
+      jwt.verify(token, pub, { issuer: [ 'urn:foo', 'urn:bar' ] }, function(err, decoded) {
+        assert.isNotNull(decoded);
+        assert.isNull(err);
+        done();
+      });
+    });
+
+    it('should throw when invalid issuer', function(done) {
+      jwt.verify(token, pub, { issuer: 'urn:wrong' }, function(err, decoded) {
+        assert.isUndefined(decoded);
+        assert.isNotNull(err);
+        assert.equal(err.name, 'JsonWebTokenError');
+        assert.instanceOf(err, jwt.JsonWebTokenError);
+        done();
+      });
+    });
+  });
+
+  describe('when signing a token without issuer', function() {
+    var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256' });
+
+    it('should check issuer', function(done) {
+      jwt.verify(token, pub, { issuer: 'urn:foo' }, function(err, decoded) {
+        assert.isUndefined(decoded);
+        assert.isNotNull(err);
+        assert.equal(err.name, 'JsonWebTokenError');
+        assert.instanceOf(err, jwt.JsonWebTokenError);
+        done();
+      });
+    });
+  });
+
+  describe('when signing a token with subject', function() {
+    var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', subject: 'subject' });
+
+    it('should check subject', function(done) {
+      jwt.verify(token, pub, { subject: 'subject' }, function(err, decoded) {
+        assert.isNotNull(decoded);
+        assert.isNull(err);
+        done();
+      });
+    });
+
+    it('should throw when invalid subject', function(done) {
+      jwt.verify(token, pub, { subject: 'wrongSubject' }, function(err, decoded) {
+        assert.isUndefined(decoded);
+        assert.isNotNull(err);
+        assert.equal(err.name, 'JsonWebTokenError');
+        assert.instanceOf(err, jwt.JsonWebTokenError);
+        done();
+      });
+    });
+  });
+
+  describe('when signing a token without subject', function() {
+    var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256' });
+
+    it('should check subject', function(done) {
+      jwt.verify(token, pub, { subject: 'subject' }, function(err, decoded) {
+        assert.isUndefined(decoded);
+        assert.isNotNull(err);
+        assert.equal(err.name, 'JsonWebTokenError');
+        assert.instanceOf(err, jwt.JsonWebTokenError);
+        done();
+      });
+    });
+  });
+
+  describe('when signing a token with jwt id', function() {
+    var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', jwtid: 'jwtid' });
+
+    it('should check jwt id', function(done) {
+      jwt.verify(token, pub, { jwtid: 'jwtid' }, function(err, decoded) {
+        assert.isNotNull(decoded);
+        assert.isNull(err);
+        done();
+      });
+    });
+
+    it('should throw when invalid jwt id', function(done) {
+      jwt.verify(token, pub, { jwtid: 'wrongJwtid' }, function(err, decoded) {
+        assert.isUndefined(decoded);
+        assert.isNotNull(err);
+        assert.equal(err.name, 'JsonWebTokenError');
+        assert.instanceOf(err, jwt.JsonWebTokenError);
+        done();
+      });
+    });
+  });
+
+  describe('when signing a token without jwt id', function() {
+    var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256' });
+
+    it('should check jwt id', function(done) {
+      jwt.verify(token, pub, { jwtid: 'jwtid' }, function(err, decoded) {
+        assert.isUndefined(decoded);
+        assert.isNotNull(err);
+        assert.equal(err.name, 'JsonWebTokenError');
+        assert.instanceOf(err, jwt.JsonWebTokenError);
+        done();
+      });
+    });
+  });
+
+  describe('when verifying a malformed token', function() {
+    it('should throw', function(done) {
+      jwt.verify('fruit.fruit.fruit', pub, function(err, decoded) {
+        assert.isUndefined(decoded);
+        assert.isNotNull(err);
+        assert.equal(err.name, 'JsonWebTokenError');
+        done();
+      });
+    });
+  });
+
+  describe('when decoding a jwt token with additional parts', function() {
+    var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256' });
+
+    it('should throw', function(done) {
+      jwt.verify(token + '.foo', pub, function(err, decoded) {
+        assert.isUndefined(decoded);
+        assert.isNotNull(err);
+        done();
+      });
+    });
+  });
+
+  describe('when decoding a invalid jwt token', function() {
+    it('should return null', function(done) {
+      var payload = jwt.decode('whatever.token');
+      assert.isNull(payload);
+      done();
+    });
+  });
+
+  describe('when decoding a valid jwt token', function() {
+    it('should return the payload', function(done) {
+      var obj     = { foo: 'bar' };
+      var token   = jwt.sign(obj, priv, { algorithm: 'RS256' });
+      var payload = jwt.decode(token);
+      assert.equal(payload.foo, obj.foo);
+      done();
+    });
+    it('should return the header and payload and signature if complete option is set', function(done) {
+      var obj     = { foo: 'bar' };
+      var token   = jwt.sign(obj, priv, { algorithm: 'RS256' });
+      var decoded = jwt.decode(token, { complete: true });
+      assert.equal(decoded.payload.foo, obj.foo);
+      assert.deepEqual(decoded.header, { typ: 'JWT', alg: 'RS256' });
+      assert.ok(typeof decoded.signature == 'string');
+      done();
+    });
+  });
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/noTimestamp.tests.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/noTimestamp.tests.js
new file mode 100644
index 0000000000000000000000000000000000000000..e08cf3ff4de4a9ba856f75a021188b887f7fed97
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/noTimestamp.tests.js
@@ -0,0 +1,12 @@
+var jwt = require('../index');
+var expect = require('chai').expect;
+
+describe('noTimestamp', function() {
+
+  it('should work with string', function () {
+    var token = jwt.sign({foo: 123}, '123', { expiresIn: '5m' , noTimestamp: true });
+    var result = jwt.verify(token, '123');
+    expect(result.exp).to.be.closeTo(Math.floor(Date.now() / 1000) + (5*60), 0.5);
+  });
+
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/non_object_values.tests.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/non_object_values.tests.js
new file mode 100644
index 0000000000000000000000000000000000000000..e7477f33b559439299e968a225c3ba5986e203fb
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/non_object_values.tests.js
@@ -0,0 +1,33 @@
+var jwt = require('../index');
+var expect = require('chai').expect;
+var JsonWebTokenError = require('../lib/JsonWebTokenError');
+
+describe('non_object_values values', function() {
+
+  it('should work with string', function () {
+    var token = jwt.sign('hello', '123');
+    var result = jwt.verify(token, '123');
+    expect(result).to.equal('hello');
+  });
+
+  //v6 version will throw in this case:
+  it('should throw with expiresIn', function () {
+    expect(function () {
+      jwt.sign('hello', '123', { expiresIn: '12h' });
+    }).to.throw(/invalid expiresIn option for string payload/);
+  });
+
+  it('should fail to validate audience when the payload is string', function () {
+    var token = jwt.sign('hello', '123');
+    expect(function () {
+      jwt.verify(token, '123', { audience: 'foo' });
+    }).to.throw(JsonWebTokenError);
+  });
+
+  it('should work with number', function () {
+    var token = jwt.sign(123, '123');
+    var result = jwt.verify(token, '123');
+    expect(result).to.equal('123');
+  });
+
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/priv.pem b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/priv.pem
new file mode 100644
index 0000000000000000000000000000000000000000..7be6d5abc5a57d4327ad420c6c0c1628f00f7f1d
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/priv.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAvtH4wKLYlIXZlfYQFJtXZVC3fD8XMarzwvb/fHUyJ6NvNStN
++H7GHp3/QhZbSaRyqK5hu5xXtFLgnI0QG8oE1NlXbczjH45LeHWhPIdc2uHSpzXi
+c78kOugMY1vng4J10PF6+T2FNaiv0iXeIQq9xbwwPYpflViQyJnzGCIZ7VGan6Gb
+RKzyTKcB58yx24pJq+CviLXEY52TIW1l5imcjGvLtlCp1za9qBZa4XGoVqHi1kRX
+kdDSHty6lZWj3KxoRvTbiaBCH+75U7rifS6fR9lqjWE57bCGoz7+BBu9YmPKtI1K
+kyHFqWpxaJc/AKf9xgg+UumeqVcirUmAsHJrMwIDAQABAoIBAQCYKw05YSNhXVPk
+eHLeW/pXuwR3OkCexPrakOmwMC0s2vIF7mChN0d6hvhVlUp68X7V8SnS2JxAGo8v
+iHY+Et3DdwZ3cxnzwh+BEhzgDfoIOmkoGppZPyX/K6klWtbGUrTtSISOWXbvEXQU
+G0qGAvDOzIGTsdMDX7slnU70Ac23JybPY5qBSiE+ky8U4dm2fUHMroWub4QP5vA/
+nqyWqX2FB/MEAbcujaknDQrFCtbmtUYlBbJCKGd9V3cGEqp6H7oH+ah2ofMc91gJ
+mCHk3YyWZB/bcVXH3CA+s1ywvCOVDBZ3Nw7Pt9zIcv6Rl9UKIy+Nx0QjXxR90Hla
+Tr0GHIShAoGBAPsD7uXm+0ksnGyKRYgvlVad8Z8FUFT6bf4B+vboDbx40FO8O/5V
+PraBPC5z8YRSBOQ/WfccPQzakkA28F2pXlRpXu5JcErVWnyyUiKpX5sw6iPenQR2
+JO9hY/GFbKiwUhVHpvWMcXFqFLSQu2A86jPnFFEfG48ZT4IhTzINKJVZAoGBAMKc
+B3YGfVfY9qiRFXzYRdSRLg5c8p/HzuWwXc9vfJ4kQTDkPXe/+nqD67rzeT54uVec
+jKoIrsCu4BfEaoyvOT+1KmUfdEpBgYZuuEC4CZf7dgKbXOpPVvZDMyJ/e7HyqTpw
+mvIYJLPm2fNAcAsnbrNX5mhLwwzEIltbplUUeRdrAoGBAKhZgPYsLkhrZRXevreR
+wkTvdUfD1pbHxtFfHqROCjhnhsFCM7JmFcNtdaFqHYczQxiZ7IqxI7jlNsVek2Md
+3qgaa5LBKlDmOuP67N9WXUrGSaJ5ATIm0qrB1Lf9VlzktIiVH8L7yHHaRby8fQ8U
+i7b3ukaV6HPW895A3M6iyJ8xAoGAInp4S+3MaTL0SFsj/nFmtcle6oaHKc3BlyoP
+BMBQyMfNkPbu+PdXTjtvGTknouzKkX4X4cwWAec5ppxS8EffEa1sLGxNMxa19vZI
+yJaShI21k7Ko3I5f7tNrDNKfPKCsYMEwgnHKluDwfktNTnyW/Uk2dgXuMaXSHHN5
+XZt59K8CgYArGVOWK7LUmf3dkTIs3tXBm4/IMtUZmWmcP9C8Xe/Dg/IdQhK5CIx4
+VXl8rgZNeX/5/4nJ8Q3LrdLau1Iz620trNRGU6sGMs3x4WQbSq93RRbFzfG1oK74
+IOo5yIBxImQOSk5jz31gF9RJb15SDBIxonuWv8qAERyUfvrmEwR0kg==
+-----END RSA PRIVATE KEY-----
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/pub.pem b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/pub.pem
new file mode 100644
index 0000000000000000000000000000000000000000..dd95d341ea38c564071a32584e96beeffd40d890
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/pub.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDtTCCAp2gAwIBAgIJAMKR/NsyfcazMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
+BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
+aWRnaXRzIFB0eSBMdGQwHhcNMTIxMTEyMjM0MzQxWhcNMTYxMjIxMjM0MzQxWjBF
+MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50
+ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAvtH4wKLYlIXZlfYQFJtXZVC3fD8XMarzwvb/fHUyJ6NvNStN+H7GHp3/
+QhZbSaRyqK5hu5xXtFLgnI0QG8oE1NlXbczjH45LeHWhPIdc2uHSpzXic78kOugM
+Y1vng4J10PF6+T2FNaiv0iXeIQq9xbwwPYpflViQyJnzGCIZ7VGan6GbRKzyTKcB
+58yx24pJq+CviLXEY52TIW1l5imcjGvLtlCp1za9qBZa4XGoVqHi1kRXkdDSHty6
+lZWj3KxoRvTbiaBCH+75U7rifS6fR9lqjWE57bCGoz7+BBu9YmPKtI1KkyHFqWpx
+aJc/AKf9xgg+UumeqVcirUmAsHJrMwIDAQABo4GnMIGkMB0GA1UdDgQWBBTs83nk
+LtoXFlmBUts3EIxcVvkvcjB1BgNVHSMEbjBsgBTs83nkLtoXFlmBUts3EIxcVvkv
+cqFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV
+BAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAMKR/NsyfcazMAwGA1UdEwQF
+MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBABw7w/5k4d5dVDgd/OOOmXdaaCIKvt7d
+3ntlv1SSvAoKT8d8lt97Dm5RrmefBI13I2yivZg5bfTge4+vAV6VdLFdWeFp1b/F
+OZkYUv6A8o5HW0OWQYVX26zIqBcG2Qrm3reiSl5BLvpj1WSpCsYvs5kaO4vFpMak
+/ICgdZD+rxwxf8Vb/6fntKywWSLgwKH3mJ+Z0kRlpq1g1oieiOm1/gpZ35s0Yuor
+XZba9ptfLCYSggg/qc3d3d0tbHplKYkwFm7f5ORGHDSD5SJm+gI7RPE+4bO8q79R
+PAfbG1UGuJ0b/oigagciHhJp851SQRYf3JuNSc17BnK2L5IEtzjqr+Q=
+-----END CERTIFICATE-----
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/rsa-private.pem b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/rsa-private.pem
new file mode 100644
index 0000000000000000000000000000000000000000..746366b5bf1edd26c3dfc05b2acc764b8abfa413
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/rsa-private.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEAvzoCEC2rpSpJQaWZbUmlsDNwp83Jr4fi6KmBWIwnj1MZ6CUQ
+7rBasuLI8AcfX5/10scSfQNCsTLV2tMKQaHuvyrVfwY0dINk+nkqB74QcT2oCCH9
+XduJjDuwWA4xLqAKuF96FsIes52opEM50W7/W7DZCKXkC8fFPFj6QF5ZzApDw2Qs
+u3yMRmr7/W9uWeaTwfPx24YdY7Ah+fdLy3KN40vXv9c4xiSafVvnx9BwYL7H1Q8N
+iK9LGEN6+JSWfgckQCs6UUBOXSZdreNN9zbQCwyzee7bOJqXUDAuLcFARzPw1EsZ
+AyjVtGCKIQ0/btqK+jFunT2NBC8RItanDZpptQIDAQABAoIBAQCsssO4Pra8hFMC
+gX7tr0x+tAYy1ewmpW8stiDFilYT33YPLKJ9HjHbSms0MwqHftwwTm8JDc/GXmW6
+qUui+I64gQOtIzpuW1fvyUtHEMSisI83QRMkF6fCSQm6jJ6oQAtOdZO6R/gYOPNb
+3gayeS8PbMilQcSRSwp6tNTVGyC33p43uUUKAKHnpvAwUSc61aVOtw2wkD062XzM
+hJjYpHm65i4V31AzXo8HF42NrAtZ8K/AuQZne5F/6F4QFVlMKzUoHkSUnTp60XZx
+X77GuyDeDmCgSc2J7xvR5o6VpjsHMo3ek0gJk5ZBnTgkHvnpbULCRxTmDfjeVPue
+v3NN2TBFAoGBAPxbqNEsXPOckGTvG3tUOAAkrK1hfW3TwvrW/7YXg1/6aNV4sklc
+vqn/40kCK0v9xJIv9FM/l0Nq+CMWcrb4sjLeGwHAa8ASfk6hKHbeiTFamA6FBkvQ
+//7GP5khD+y62RlWi9PmwJY21lEkn2mP99THxqvZjQiAVNiqlYdwiIc7AoGBAMH8
+f2Ay7Egc2KYRYU2qwa5E/Cljn/9sdvUnWM+gOzUXpc5sBi+/SUUQT8y/rY4AUVW6
+YaK7chG9YokZQq7ZwTCsYxTfxHK2pnG/tXjOxLFQKBwppQfJcFSRLbw0lMbQoZBk
+S+zb0ufZzxc2fJfXE+XeJxmKs0TS9ltQuJiSqCPPAoGBALEc84K7DBG+FGmCl1sb
+ZKJVGwwknA90zCeYtadrIT0/VkxchWSPvxE5Ep+u8gxHcqrXFTdILjWW4chefOyF
+5ytkTrgQAI+xawxsdyXWUZtd5dJq8lxLtx9srD4gwjh3et8ZqtFx5kCHBCu29Fr2
+PA4OmBUMfrs0tlfKgV+pT2j5AoGBAKnA0Z5XMZlxVM0OTH3wvYhI6fk2Kx8TxY2G
+nxsh9m3hgcD/mvJRjEaZnZto6PFoqcRBU4taSNnpRr7+kfH8sCht0k7D+l8AIutL
+ffx3xHv9zvvGHZqQ1nHKkaEuyjqo+5kli6N8QjWNzsFbdvBQ0CLJoqGhVHsXuWnz
+W3Z4cBbVAoGAEtnwY1OJM7+R2u1CW0tTjqDlYU2hUNa9t1AbhyGdI2arYp+p+umA
+b5VoYLNsdvZhqjVFTrYNEuhTJFYCF7jAiZLYvYm0C99BqcJnJPl7JjWynoNHNKw3
+9f6PIOE1rAmPE8Cfz/GFF5115ZKVlq+2BY8EKNxbCIy2d/vMEvisnXI=
+-----END RSA PRIVATE KEY-----
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/rsa-public-key.pem b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/rsa-public-key.pem
new file mode 100644
index 0000000000000000000000000000000000000000..eb9a29bad0599a86ecb3d325c030e284149be57e
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/rsa-public-key.pem
@@ -0,0 +1,8 @@
+-----BEGIN RSA PUBLIC KEY-----
+MIIBCgKCAQEAvzoCEC2rpSpJQaWZbUmlsDNwp83Jr4fi6KmBWIwnj1MZ6CUQ7rBa
+suLI8AcfX5/10scSfQNCsTLV2tMKQaHuvyrVfwY0dINk+nkqB74QcT2oCCH9XduJ
+jDuwWA4xLqAKuF96FsIes52opEM50W7/W7DZCKXkC8fFPFj6QF5ZzApDw2Qsu3yM
+Rmr7/W9uWeaTwfPx24YdY7Ah+fdLy3KN40vXv9c4xiSafVvnx9BwYL7H1Q8NiK9L
+GEN6+JSWfgckQCs6UUBOXSZdreNN9zbQCwyzee7bOJqXUDAuLcFARzPw1EsZAyjV
+tGCKIQ0/btqK+jFunT2NBC8RItanDZpptQIDAQAB
+-----END RSA PUBLIC KEY-----
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/rsa-public-key.tests.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/rsa-public-key.tests.js
new file mode 100644
index 0000000000000000000000000000000000000000..e2044fc3bebf4ec24a0e2145d711eb49531521a4
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/rsa-public-key.tests.js
@@ -0,0 +1,15 @@
+var jwt = require('../');
+
+describe('public key start with BEGIN RSA PUBLIC KEY', function () {
+
+  it('should work', function (done) {
+    var fs = require('fs');
+    var cert_pub = fs.readFileSync(__dirname + '/rsa-public-key.pem');
+    var cert_priv = fs.readFileSync(__dirname + '/rsa-private.pem');
+
+    var token = jwt.sign({ foo: 'bar' }, cert_priv, { algorithm: 'RS256'});
+
+    jwt.verify(token, cert_pub, done);
+  });
+
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/rsa-public.pem b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/rsa-public.pem
new file mode 100644
index 0000000000000000000000000000000000000000..9307812ab65855a103ae1a1af6e0957893a81568
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/rsa-public.pem
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvzoCEC2rpSpJQaWZbUml
+sDNwp83Jr4fi6KmBWIwnj1MZ6CUQ7rBasuLI8AcfX5/10scSfQNCsTLV2tMKQaHu
+vyrVfwY0dINk+nkqB74QcT2oCCH9XduJjDuwWA4xLqAKuF96FsIes52opEM50W7/
+W7DZCKXkC8fFPFj6QF5ZzApDw2Qsu3yMRmr7/W9uWeaTwfPx24YdY7Ah+fdLy3KN
+40vXv9c4xiSafVvnx9BwYL7H1Q8NiK9LGEN6+JSWfgckQCs6UUBOXSZdreNN9zbQ
+Cwyzee7bOJqXUDAuLcFARzPw1EsZAyjVtGCKIQ0/btqK+jFunT2NBC8RItanDZpp
+tQIDAQAB
+-----END PUBLIC KEY-----
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/set_headers.tests.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/set_headers.tests.js
new file mode 100644
index 0000000000000000000000000000000000000000..75e8a0242991e4df1e78ba81164d48795e511850
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/set_headers.tests.js
@@ -0,0 +1,18 @@
+var jwt = require('../index');
+var expect = require('chai').expect;
+
+describe('set header', function() {
+
+  it('should add the header', function () {
+    var token = jwt.sign({foo: 123}, '123', { header: { foo: 'bar' } });
+    var decoded = jwt.decode(token, {complete: true});
+    expect(decoded.header.foo).to.equal('bar');
+  });
+
+  it('should allow overriding header', function () {
+    var token = jwt.sign({foo: 123}, '123', { header: { alg: 'HS512' } });
+    var decoded = jwt.decode(token, {complete: true});
+    expect(decoded.header.alg).to.equal('HS512');
+  });
+
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/undefined_secretOrPublickey.tests.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/undefined_secretOrPublickey.tests.js
new file mode 100644
index 0000000000000000000000000000000000000000..01132ad9056fe6de0c03f11ce61bafcd7638b5ed
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/undefined_secretOrPublickey.tests.js
@@ -0,0 +1,20 @@
+var fs = require('fs');
+var jwt = require('../index');
+var JsonWebTokenError = require('../lib/JsonWebTokenError');
+var expect = require('chai').expect;
+
+var TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.t-IDcSemACt8x4iTMCda8Yhe3iZaWbvV5XKSTbuAn0M';
+
+describe('verifying without specified secret or public key', function () {
+  it('should not verify null', function () {
+    expect(function () {
+      jwt.verify(TOKEN, null);
+    }).to.throw(JsonWebTokenError, /secret or public key must be provided/);
+  });
+
+  it('should not verify undefined', function () {
+    expect(function () {
+      jwt.verify(TOKEN);
+    }).to.throw(JsonWebTokenError, /secret or public key must be provided/);
+  });
+});
\ No newline at end of file
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/util/fakeDate.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/util/fakeDate.js
new file mode 100644
index 0000000000000000000000000000000000000000..d889c826f1e6fb6f6ded63b0de788c165c4ce075
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/util/fakeDate.js
@@ -0,0 +1,32 @@
+var oldDate = global.Date;
+
+/*
+ * fix new Date() to a fixed unix timestamp.
+ */
+global.Date.fix = function (timestamp) {
+  var time = timestamp * 1000;
+
+  if (global.Date.unfake) {
+    global.Date.unfake();
+  }
+
+  global.Date = function (ts) {
+    return new oldDate(ts || time);
+  };
+
+  global.Date.prototype = Object.create(oldDate.prototype);
+  global.Date.prototype.constructor = global.Date;
+
+  global.Date.prototype.now = function () {
+    return time;
+  };
+
+  global.Date.now = function () {
+    return time;
+  };
+
+  global.Date.unfix = function () {
+    global.Date = oldDate;
+  };
+
+};
\ No newline at end of file
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/verify.tests.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/verify.tests.js
new file mode 100644
index 0000000000000000000000000000000000000000..da8dce4758852e8c560a85382c0e147b0ce099d2
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/verify.tests.js
@@ -0,0 +1,194 @@
+var jwt = require('../index');
+var jws = require('jws');
+var fs = require('fs');
+var path = require('path');
+var sinon = require('sinon');
+
+var assert = require('chai').assert;
+
+describe('verify', function() {
+  var pub = fs.readFileSync(path.join(__dirname, 'pub.pem'));
+  var priv = fs.readFileSync(path.join(__dirname, 'priv.pem'));
+
+  it('should first assume JSON claim set', function (done) {
+    var header = { alg: 'RS256' };
+    var payload = { iat: Math.floor(Date.now() / 1000 ) };
+
+    var signed = jws.sign({
+      header: header,
+        payload: payload,
+        secret: priv,
+        encoding: 'utf8'
+    });
+
+    jwt.verify(signed, pub, {typ: 'JWT'}, function(err, p) {
+      assert.isNull(err);
+      assert.deepEqual(p, payload);
+      done();
+    });
+  });
+
+  it('should be able to validate unsigned token', function (done) {
+    var header = { alg: 'none' };
+    var payload = { iat: Math.floor(Date.now() / 1000 ) };
+
+    var signed = jws.sign({
+      header: header,
+      payload: payload,
+      secret: priv,
+      encoding: 'utf8'
+    });
+
+    jwt.verify(signed, null, {typ: 'JWT'}, function(err, p) {
+      assert.isNull(err);
+      assert.deepEqual(p, payload);
+      done();
+    });
+  });
+
+  it('should not mutate options', function (done) {
+    var header = { alg: 'none' };
+
+    var payload = { iat: Math.floor(Date.now() / 1000 ) };
+
+    var options = {typ: 'JWT'};
+
+    var signed = jws.sign({
+      header: header,
+      payload: payload,
+      secret: priv,
+      encoding: 'utf8'
+    });
+
+    jwt.verify(signed, null, options, function(err) {
+      assert.isNull(err);
+      assert.deepEqual(Object.keys(options).length, 1);
+      done();
+    });
+  });
+
+  describe('expiration', function () {
+    // { foo: 'bar', iat: 1437018582, exp: 1437018583 }
+    var token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE0MzcwMTg1ODIsImV4cCI6MTQzNzAxODU4M30.NmMv7sXjM1dW0eALNXud8LoXknZ0mH14GtnFclwJv0s';
+    var key = 'key';
+
+    var clock;
+    afterEach(function () {
+      try { clock.restore(); } catch (e) {}
+    });
+
+    it('should error on expired token', function (done) {
+      clock = sinon.useFakeTimers(1437018650000);
+      var options = {algorithms: ['HS256']};
+
+      jwt.verify(token, key, options, function (err, p) {
+        assert.equal(err.name, 'TokenExpiredError');
+        assert.equal(err.message, 'jwt expired');
+        assert.equal(err.expiredAt.constructor.name, 'Date');
+        assert.equal(Number(err.expiredAt), 1437018583000);
+        assert.isUndefined(p);
+        done();
+      });
+    });
+
+    it('should not error on expired token within clockTolerance interval', function (done) {
+      clock = sinon.useFakeTimers(1437018584000);
+      var options = {algorithms: ['HS256'], clockTolerance: 100}
+
+      jwt.verify(token, key, options, function (err, p) {
+        assert.isNull(err);
+        assert.equal(p.foo, 'bar');
+        done();
+      });
+    });
+
+    it('should not error if within maxAge timespan', function (done) {
+      clock = sinon.useFakeTimers(1437018582500);
+      var options = {algorithms: ['HS256'], maxAge: '600ms'};
+
+      jwt.verify(token, key, options, function (err, p) {
+        assert.isNull(err);
+        assert.equal(p.foo, 'bar');
+        done();
+      });
+    });
+
+    describe('option: maxAge', function () {
+      it('should error for claims issued before a certain timespan', function (done) {
+        clock = sinon.useFakeTimers(1437018582500);
+        var options = {algorithms: ['HS256'], maxAge: '321ms'};
+
+        jwt.verify(token, key, options, function (err, p) {
+          assert.equal(err.name, 'TokenExpiredError');
+          assert.equal(err.message, 'maxAge exceeded');
+          assert.equal(err.expiredAt.constructor.name, 'Date');
+          assert.equal(Number(err.expiredAt), 1437018582321);
+          assert.isUndefined(p);
+          done();
+        });
+      });
+
+      it('should not error for claims issued before a certain timespan but still inside clockTolerance timespan', function (done) {
+        clock = sinon.useFakeTimers(1437018582500);
+        var options = {algorithms: ['HS256'], maxAge: '321ms', clockTolerance: 100};
+
+        jwt.verify(token, key, options, function (err, p) {
+          assert.isNull(err);
+          assert.equal(p.foo, 'bar');
+          done();
+        });
+      });
+
+      it('should not error if within maxAge timespan', function (done) {
+        clock = sinon.useFakeTimers(1437018582500);
+        var options = {algorithms: ['HS256'], maxAge: '600ms'};
+
+        jwt.verify(token, key, options, function (err, p) {
+          assert.isNull(err);
+          assert.equal(p.foo, 'bar');
+          done();
+        });
+      });
+      it('can be more restrictive than expiration', function (done) {
+        clock = sinon.useFakeTimers(1437018582900);
+        var options = {algorithms: ['HS256'], maxAge: '800ms'};
+
+        jwt.verify(token, key, options, function (err, p) {
+          assert.equal(err.name, 'TokenExpiredError');
+          assert.equal(err.message, 'maxAge exceeded');
+          assert.equal(err.expiredAt.constructor.name, 'Date');
+          assert.equal(Number(err.expiredAt), 1437018582800);
+          assert.isUndefined(p);
+          done();
+        });
+      });
+      it('cannot be more permissive than expiration', function (done) {
+        clock = sinon.useFakeTimers(1437018583100);
+        var options = {algorithms: ['HS256'], maxAge: '1200ms'};
+
+        jwt.verify(token, key, options, function (err, p) {
+          // maxAge not exceded, but still expired
+          assert.equal(err.name, 'TokenExpiredError');
+          assert.equal(err.message, 'jwt expired');
+          assert.equal(err.expiredAt.constructor.name, 'Date');
+          assert.equal(Number(err.expiredAt), 1437018583000);
+          assert.isUndefined(p);
+          done();
+        });
+      });
+      it('should error if maxAge is specified but there is no iat claim', function (done) {
+        clock = sinon.useFakeTimers(1437018582900);
+        var token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmb28iOiJiYXIifQ.0MBPd4Bru9-fK_HY3xmuDAc6N_embknmNuhdb9bKL_U';
+        var options = {algorithms: ['HS256'], maxAge: '1s'};
+
+        jwt.verify(token, key, options, function (err, p) {
+          assert.equal(err.name, 'JsonWebTokenError');
+          assert.equal(err.message, 'iat required when maxAge is specified');
+          assert.isUndefined(p);
+          done();
+        });
+      });
+    });
+  });
+
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/wrong_alg.tests.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/wrong_alg.tests.js
new file mode 100644
index 0000000000000000000000000000000000000000..04ce48e81605ee4e0589241ea2d2adb1c14a7b97
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/test/wrong_alg.tests.js
@@ -0,0 +1,42 @@
+var fs = require('fs');
+var path = require('path');
+var jwt = require('../index');
+var JsonWebTokenError = require('../lib/JsonWebTokenError');
+var expect = require('chai').expect;
+
+
+var pub = fs.readFileSync(path.join(__dirname, 'pub.pem'), 'utf8');
+// priv is never used
+// var priv = fs.readFileSync(path.join(__dirname, 'priv.pem'));
+
+var TOKEN = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE0MjY1NDY5MTl9.ETgkTn8BaxIX4YqvUWVFPmum3moNZ7oARZtSBXb_vP4';
+
+describe('when setting a wrong `header.alg`', function () {
+
+  describe('signing with pub key as symmetric', function () {
+    it('should not verify', function () {
+      expect(function () {
+        jwt.verify(TOKEN, pub);
+      }).to.throw(JsonWebTokenError, /invalid algorithm/);
+    });
+  });
+
+  describe('signing with pub key as HS256 and whitelisting only RS256', function () {
+    it('should not verify', function () {
+      expect(function () {
+        jwt.verify(TOKEN, pub, {algorithms: ['RS256']});
+      }).to.throw(JsonWebTokenError, /invalid algorithm/);
+    });
+  });
+
+  describe('signing with HS256 and checking with HS384', function () {
+    it('should not verify', function () {
+      expect(function () {
+        var token = jwt.sign({foo: 'bar'}, 'secret', {algorithm: 'HS256'});
+        jwt.verify(token, 'some secret', {algorithms: ['HS384']});
+      }).to.throw(JsonWebTokenError, /invalid algorithm/);
+    });
+  });
+
+
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/verify.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/verify.js
new file mode 100644
index 0000000000000000000000000000000000000000..a0950e036591f411600fff9199faa8b34fffd059
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jsonwebtoken/verify.js
@@ -0,0 +1,168 @@
+var JsonWebTokenError = require('./lib/JsonWebTokenError');
+var NotBeforeError    = require('./lib/NotBeforeError');
+var TokenExpiredError = require('./lib/TokenExpiredError');
+var decode            = require('./decode');
+var jws               = require('jws');
+var ms                = require('ms');
+var xtend             = require('xtend');
+
+module.exports = function (jwtString, secretOrPublicKey, options, callback) {
+  if ((typeof options === 'function') && !callback) {
+    callback = options;
+    options = {};
+  }
+
+  if (!options) {
+    options = {};
+  }
+
+  //clone this object since we are going to mutate it.
+  options = xtend(options);
+  var done;
+
+  if (callback) {
+    done = function() {
+      var args = Array.prototype.slice.call(arguments, 0);
+      return process.nextTick(function() {
+        callback.apply(null, args);
+      });
+    };
+  } else {
+    done = function(err, data) {
+      if (err) throw err;
+      return data;
+    };
+  }
+
+  if (!jwtString){
+    return done(new JsonWebTokenError('jwt must be provided'));
+  }
+
+  var parts = jwtString.split('.');
+
+  if (parts.length !== 3){
+    return done(new JsonWebTokenError('jwt malformed'));
+  }
+
+  var hasSignature = parts[2].trim() !== '';
+
+  if (!hasSignature && secretOrPublicKey){
+    return done(new JsonWebTokenError('jwt signature is required'));
+  }
+
+  if (hasSignature && !secretOrPublicKey) {
+    return done(new JsonWebTokenError('secret or public key must be provided'));
+  }
+
+  if (!hasSignature && !options.algorithms) {
+    options.algorithms = ['none'];
+  }
+
+  if (!options.algorithms) {
+    options.algorithms = ~secretOrPublicKey.toString().indexOf('BEGIN CERTIFICATE') ||
+                         ~secretOrPublicKey.toString().indexOf('BEGIN PUBLIC KEY') ?
+                          [ 'RS256','RS384','RS512','ES256','ES384','ES512' ] :
+                         ~secretOrPublicKey.toString().indexOf('BEGIN RSA PUBLIC KEY') ?
+                          [ 'RS256','RS384','RS512' ] :
+                          [ 'HS256','HS384','HS512' ];
+
+  }
+
+  var decodedToken;
+  try {
+    decodedToken = jws.decode(jwtString);
+  } catch(err) {
+    return done(new JsonWebTokenError('invalid token'));
+  }
+
+  if (!decodedToken) {
+    return done(new JsonWebTokenError('invalid token'));
+  }
+
+  var header = decodedToken.header;
+
+  if (!~options.algorithms.indexOf(header.alg)) {
+    return done(new JsonWebTokenError('invalid algorithm'));
+  }
+
+  var valid;
+
+  try {
+    valid = jws.verify(jwtString, header.alg, secretOrPublicKey);
+  } catch (e) {
+    return done(e);
+  }
+
+  if (!valid)
+    return done(new JsonWebTokenError('invalid signature'));
+
+  var payload;
+
+  try {
+    payload = decode(jwtString);
+  } catch(err) {
+    return done(err);
+  }
+
+  if (typeof payload.nbf !== 'undefined' && !options.ignoreNotBefore) {
+    if (typeof payload.nbf !== 'number') {
+      return done(new JsonWebTokenError('invalid nbf value'));
+    }
+    if (payload.nbf > Math.floor(Date.now() / 1000) + (options.clockTolerance || 0)) {
+      return done(new NotBeforeError('jwt not active', new Date(payload.nbf * 1000)));
+    }
+  }
+
+  if (typeof payload.exp !== 'undefined' && !options.ignoreExpiration) {
+    if (typeof payload.exp !== 'number') {
+      return done(new JsonWebTokenError('invalid exp value'));
+    }
+    if (Math.floor(Date.now() / 1000) >= payload.exp + (options.clockTolerance || 0)) {
+      return done(new TokenExpiredError('jwt expired', new Date(payload.exp * 1000)));
+    }
+  }
+
+  if (options.audience) {
+    var audiences = Array.isArray(options.audience)? options.audience : [options.audience];
+    var target = Array.isArray(payload.aud) ? payload.aud : [payload.aud];
+
+    var match = target.some(function(aud) { return audiences.indexOf(aud) != -1; });
+
+    if (!match)
+      return done(new JsonWebTokenError('jwt audience invalid. expected: ' + audiences.join(' or ')));
+  }
+
+  if (options.issuer) {
+    var invalid_issuer =
+        (typeof options.issuer === 'string' && payload.iss !== options.issuer) ||
+        (Array.isArray(options.issuer) && options.issuer.indexOf(payload.iss) === -1);
+
+    if (invalid_issuer) {
+      return done(new JsonWebTokenError('jwt issuer invalid. expected: ' + options.issuer));
+    }
+  }
+
+  if (options.subject) {
+    if (payload.sub !== options.subject) {
+      return done(new JsonWebTokenError('jwt subject invalid. expected: ' + options.subject));
+    }
+  }
+
+  if (options.jwtid) {
+    if (payload.jti !== options.jwtid) {
+      return done(new JsonWebTokenError('jwt jwtid invalid. expected: ' + options.jwtid));
+    }
+  }
+
+  if (options.maxAge) {
+    var maxAge = ms(options.maxAge);
+    if (typeof payload.iat !== 'number') {
+      return done(new JsonWebTokenError('iat required when maxAge is specified'));
+    }
+    if (Date.now() - (payload.iat * 1000) > maxAge + (options.clockTolerance || 0) * 1000) {
+      return done(new TokenExpiredError('maxAge exceeded', new Date(payload.iat * 1000 + maxAge)));
+    }
+  }
+
+  return done(null, payload);
+};
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jwa/.npmignore b/KEMMessaging/node_modules/firebase-admin/node_modules/jwa/.npmignore
new file mode 100644
index 0000000000000000000000000000000000000000..d0223a39c166a9e7e31af9ac3246ae676ce9d32a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jwa/.npmignore
@@ -0,0 +1,3 @@
+Makefile
+test/
+.travis.yml
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jwa/LICENSE b/KEMMessaging/node_modules/firebase-admin/node_modules/jwa/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..caeb8495c857edf2c981d26557292bc6f1cf872a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jwa/LICENSE
@@ -0,0 +1,17 @@
+Copyright (c) 2013 Brian J. Brennan
+
+Permission is hereby granted, free of charge, to any person obtaining a copy 
+of this software and associated documentation files (the "Software"), to deal in 
+the Software without restriction, including without limitation the rights to use, 
+copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 
+Software, and to permit persons to whom the Software is furnished to do so, 
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all 
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jwa/README.md b/KEMMessaging/node_modules/firebase-admin/node_modules/jwa/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..6ab1b8efd23cb337f5945e1d04feca18fa122091
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jwa/README.md
@@ -0,0 +1,145 @@
+# node-jwa [![Build Status](https://travis-ci.org/brianloveswords/node-jwa.png?branch=master)](https://travis-ci.org/brianloveswords/node-jwa)
+
+A
+[JSON Web Algorithms](http://tools.ietf.org/id/draft-ietf-jose-json-web-algorithms-08.html)
+implementation focusing (exclusively, at this point) on the algorithms necessary for
+[JSON Web Signatures](http://self-issued.info/docs/draft-ietf-jose-json-web-signature.html).
+
+This library supports all of the required, recommended and optional cryptographic algorithms for JWS:
+
+alg Parameter Value | Digital Signature or MAC Algorithm
+----------------|----------------------------
+HS256 | HMAC using SHA-256 hash algorithm
+HS384 | HMAC using SHA-384 hash algorithm
+HS512 | HMAC using SHA-512 hash algorithm
+RS256 | RSASSA using SHA-256 hash algorithm
+RS384 | RSASSA using SHA-384 hash algorithm
+RS512 | RSASSA using SHA-512 hash algorithm
+ES256 | ECDSA using P-256 curve and SHA-256 hash algorithm
+ES384 | ECDSA using P-384 curve and SHA-384 hash algorithm
+ES512 | ECDSA using P-521 curve and SHA-512 hash algorithm
+none | No digital signature or MAC value included
+
+# Requirements
+
+In order to run the tests, a recent version of OpenSSL is
+required. **The version that comes with OS X (OpenSSL 0.9.8r 8 Feb
+2011) is not recent enough**, as it does not fully support ECDSA
+keys. You'll need to use a version > 1.0.0; I tested with OpenSSL 1.0.1c 10 May 2012.
+
+# Testing
+
+To run the tests, do
+
+```bash
+$ npm test
+```
+
+This will generate a bunch of keypairs to use in testing. If you want to
+generate new keypairs, do `make clean` before running `npm test` again.
+
+## Methodology
+
+I spawn `openssl dgst -sign` to test OpenSSL sign → JS verify and
+`openssl dgst -verify` to test JS sign → OpenSSL verify for each of the
+RSA and ECDSA algorithms.
+
+# Usage
+
+## jwa(algorithm)
+
+Creates a new `jwa` object with `sign` and `verify` methods for the
+algorithm. Valid values for algorithm can be found in the table above
+(`'HS256'`, `'HS384'`, etc) and are case-insensitive. Passing an invalid
+algorithm value will throw a `TypeError`.
+
+
+## jwa#sign(input, secretOrPrivateKey)
+
+Sign some input with either a secret for HMAC algorithms, or a private
+key for RSA and ECDSA algorithms.
+
+If input is not already a string or buffer, `JSON.stringify` will be
+called on it to attempt to coerce it.
+
+For the HMAC algorithm, `secretOrPrivateKey` should be a string or a
+buffer. For ECDSA and RSA, the value should be a string representing a
+PEM encoded **private** key. 
+
+Output [base64url](http://en.wikipedia.org/wiki/Base64#URL_applications)
+formatted. This is for convenience as JWS expects the signature in this
+format. If your application needs the output in a different format,
+[please open an issue](https://github.com/brianloveswords/node-jwa/issues). In
+the meantime, you can use
+[brianloveswords/base64url](https://github.com/brianloveswords/base64url)
+to decode the signature.
+
+As of nodejs *v0.11.8*, SPKAC support was introduce. If your nodeJs
+version satisfies, then you can pass an object `{ key: '..', passphrase: '...' }`
+
+
+## jwa#verify(input, signature, secretOrPublicKey)
+
+Verify a signature. Returns `true` or `false`.
+
+`signature` should be a base64url encoded string.
+
+For the HMAC algorithm, `secretOrPublicKey` should be a string or a
+buffer. For ECDSA and RSA, the value should be a string represented a
+PEM encoded **public** key.
+
+
+# Example
+
+HMAC
+```js
+const jwa = require('jwa');
+
+const hmac = jwa('HS256');
+const input = 'super important stuff';
+const secret = 'shhhhhh';
+
+const signature = hmac.sign(input, secret);
+hmac.verify(input, signature, secret) // === true
+hmac.verify(input, signature, 'trickery!') // === false
+```
+
+With keys
+```js
+const fs = require('fs');
+const jwa = require('jwa');
+const privateKey = fs.readFileSync(__dirname + '/ecdsa-p521-private.pem');
+const publicKey = fs.readFileSync(__dirname + '/ecdsa-p521-public.pem');
+
+const ecdsa = jwa('ES512');
+const input = 'very important stuff';
+
+const signature = ecdsa.sign(input, privateKey);
+ecdsa.verify(input, signature, publicKey) // === true
+```
+## License
+
+MIT
+
+```
+Copyright (c) 2013 Brian J. Brennan
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+```
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jwa/index.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jwa/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..855be0b21dda67692326e8864e4284e4b1cd43f5
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jwa/index.js
@@ -0,0 +1,125 @@
+var bufferEqual = require('buffer-equal-constant-time');
+var base64url = require('base64url');
+var Buffer = require('safe-buffer').Buffer;
+var crypto = require('crypto');
+var formatEcdsa = require('ecdsa-sig-formatter');
+var util = require('util');
+
+var MSG_INVALID_ALGORITHM = '"%s" is not a valid algorithm.\n  Supported algorithms are:\n  "HS256", "HS384", "HS512", "RS256", "RS384", "RS512" and "none".'
+var MSG_INVALID_SECRET = 'secret must be a string or buffer';
+var MSG_INVALID_VERIFIER_KEY = 'key must be a string or a buffer';
+var MSG_INVALID_SIGNER_KEY = 'key must be a string, a buffer or an object';
+
+function typeError(template) {
+  var args = [].slice.call(arguments, 1);
+  var errMsg = util.format.bind(util, template).apply(null, args);
+  return new TypeError(errMsg);
+}
+
+function bufferOrString(obj) {
+  return Buffer.isBuffer(obj) || typeof obj === 'string';
+}
+
+function normalizeInput(thing) {
+  if (!bufferOrString(thing))
+    thing = JSON.stringify(thing);
+  return thing;
+}
+
+function createHmacSigner(bits) {
+  return function sign(thing, secret) {
+    if (!bufferOrString(secret))
+      throw typeError(MSG_INVALID_SECRET);
+    thing = normalizeInput(thing);
+    var hmac = crypto.createHmac('sha' + bits, secret);
+    var sig = (hmac.update(thing), hmac.digest('base64'))
+    return base64url.fromBase64(sig);
+  }
+}
+
+function createHmacVerifier(bits) {
+  return function verify(thing, signature, secret) {
+    var computedSig = createHmacSigner(bits)(thing, secret);
+    return bufferEqual(Buffer.from(signature), Buffer.from(computedSig));
+  }
+}
+
+function createKeySigner(bits) {
+ return function sign(thing, privateKey) {
+    if (!bufferOrString(privateKey) && !(typeof privateKey === 'object'))
+      throw typeError(MSG_INVALID_SIGNER_KEY);
+    thing = normalizeInput(thing);
+    // Even though we are specifying "RSA" here, this works with ECDSA
+    // keys as well.
+    var signer = crypto.createSign('RSA-SHA' + bits);
+    var sig = (signer.update(thing), signer.sign(privateKey, 'base64'));
+    return base64url.fromBase64(sig);
+  }
+}
+
+function createKeyVerifier(bits) {
+  return function verify(thing, signature, publicKey) {
+    if (!bufferOrString(publicKey))
+      throw typeError(MSG_INVALID_VERIFIER_KEY);
+    thing = normalizeInput(thing);
+    signature = base64url.toBase64(signature);
+    var verifier = crypto.createVerify('RSA-SHA' + bits);
+    verifier.update(thing);
+    return verifier.verify(publicKey, signature, 'base64');
+  }
+}
+
+function createECDSASigner(bits) {
+  var inner = createKeySigner(bits);
+  return function sign() {
+    var signature = inner.apply(null, arguments);
+    signature = formatEcdsa.derToJose(signature, 'ES' + bits);
+    return signature;
+  };
+}
+
+function createECDSAVerifer(bits) {
+  var inner = createKeyVerifier(bits);
+  return function verify(thing, signature, publicKey) {
+    signature = formatEcdsa.joseToDer(signature, 'ES' + bits).toString('base64');
+    var result = inner(thing, signature, publicKey);
+    return result;
+  };
+}
+
+function createNoneSigner() {
+  return function sign() {
+    return '';
+  }
+}
+
+function createNoneVerifier() {
+  return function verify(thing, signature) {
+    return signature === '';
+  }
+}
+
+module.exports = function jwa(algorithm) {
+  var signerFactories = {
+    hs: createHmacSigner,
+    rs: createKeySigner,
+    es: createECDSASigner,
+    none: createNoneSigner,
+  }
+  var verifierFactories = {
+    hs: createHmacVerifier,
+    rs: createKeyVerifier,
+    es: createECDSAVerifer,
+    none: createNoneVerifier,
+  }
+  var match = algorithm.match(/^(RS|ES|HS)(256|384|512)$|^(none)$/i);
+  if (!match)
+    throw typeError(MSG_INVALID_ALGORITHM, algorithm);
+  var algo = (match[1] || match[3]).toLowerCase();
+  var bits = match[2];
+
+  return {
+    sign: signerFactories[algo](bits),
+    verify: verifierFactories[algo](bits),
+  }
+};
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jwa/package.json b/KEMMessaging/node_modules/firebase-admin/node_modules/jwa/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..d347f6a55636b6e287382cd4f1be0efd4f80693c
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jwa/package.json
@@ -0,0 +1,83 @@
+{
+  "_args": [
+    [
+      {
+        "raw": "jwa@https://registry.npmjs.org/jwa/-/jwa-1.1.4.tgz",
+        "scope": null,
+        "escapedName": "jwa",
+        "name": "jwa",
+        "rawSpec": "https://registry.npmjs.org/jwa/-/jwa-1.1.4.tgz",
+        "spec": "https://registry.npmjs.org/jwa/-/jwa-1.1.4.tgz",
+        "type": "remote"
+      },
+      "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin"
+    ]
+  ],
+  "_from": "jwa@>=1.1.4 <2.0.0",
+  "_id": "jwa@1.1.4",
+  "_inCache": true,
+  "_location": "/firebase-admin/jwa",
+  "_phantomChildren": {},
+  "_requested": {
+    "raw": "jwa@https://registry.npmjs.org/jwa/-/jwa-1.1.4.tgz",
+    "scope": null,
+    "escapedName": "jwa",
+    "name": "jwa",
+    "rawSpec": "https://registry.npmjs.org/jwa/-/jwa-1.1.4.tgz",
+    "spec": "https://registry.npmjs.org/jwa/-/jwa-1.1.4.tgz",
+    "type": "remote"
+  },
+  "_requiredBy": [
+    "/firebase-admin",
+    "/firebase-admin/jws"
+  ],
+  "_resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.4.tgz",
+  "_shasum": "dbb01bd38cd409899fa715107e90d90f9bcb161e",
+  "_shrinkwrap": null,
+  "_spec": "jwa@https://registry.npmjs.org/jwa/-/jwa-1.1.4.tgz",
+  "_where": "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin",
+  "author": {
+    "name": "Brian J. Brennan",
+    "email": "brianloveswords@gmail.com"
+  },
+  "bugs": {
+    "url": "https://github.com/brianloveswords/node-jwa/issues"
+  },
+  "dependencies": {
+    "base64url": "2.0.0",
+    "buffer-equal-constant-time": "1.0.1",
+    "ecdsa-sig-formatter": "1.0.7",
+    "safe-buffer": "^5.0.1"
+  },
+  "description": "JWA implementation (supports all JWS algorithms)",
+  "devDependencies": {
+    "semver": "4.3.6",
+    "tap": "6.2.0"
+  },
+  "directories": {
+    "test": "test"
+  },
+  "homepage": "https://github.com/brianloveswords/node-jwa#readme",
+  "keywords": [
+    "jwa",
+    "jws",
+    "jwt",
+    "rsa",
+    "ecdsa",
+    "hmac"
+  ],
+  "license": "MIT",
+  "main": "index.js",
+  "name": "jwa",
+  "optionalDependencies": {},
+  "readme": "# node-jwa [![Build Status](https://travis-ci.org/brianloveswords/node-jwa.png?branch=master)](https://travis-ci.org/brianloveswords/node-jwa)\n\nA\n[JSON Web Algorithms](http://tools.ietf.org/id/draft-ietf-jose-json-web-algorithms-08.html)\nimplementation focusing (exclusively, at this point) on the algorithms necessary for\n[JSON Web Signatures](http://self-issued.info/docs/draft-ietf-jose-json-web-signature.html).\n\nThis library supports all of the required, recommended and optional cryptographic algorithms for JWS:\n\nalg Parameter Value | Digital Signature or MAC Algorithm\n----------------|----------------------------\nHS256 | HMAC using SHA-256 hash algorithm\nHS384 | HMAC using SHA-384 hash algorithm\nHS512 | HMAC using SHA-512 hash algorithm\nRS256 | RSASSA using SHA-256 hash algorithm\nRS384 | RSASSA using SHA-384 hash algorithm\nRS512 | RSASSA using SHA-512 hash algorithm\nES256 | ECDSA using P-256 curve and SHA-256 hash algorithm\nES384 | ECDSA using P-384 curve and SHA-384 hash algorithm\nES512 | ECDSA using P-521 curve and SHA-512 hash algorithm\nnone | No digital signature or MAC value included\n\n# Requirements\n\nIn order to run the tests, a recent version of OpenSSL is\nrequired. **The version that comes with OS X (OpenSSL 0.9.8r 8 Feb\n2011) is not recent enough**, as it does not fully support ECDSA\nkeys. You'll need to use a version > 1.0.0; I tested with OpenSSL 1.0.1c 10 May 2012.\n\n# Testing\n\nTo run the tests, do\n\n```bash\n$ npm test\n```\n\nThis will generate a bunch of keypairs to use in testing. If you want to\ngenerate new keypairs, do `make clean` before running `npm test` again.\n\n## Methodology\n\nI spawn `openssl dgst -sign` to test OpenSSL sign → JS verify and\n`openssl dgst -verify` to test JS sign → OpenSSL verify for each of the\nRSA and ECDSA algorithms.\n\n# Usage\n\n## jwa(algorithm)\n\nCreates a new `jwa` object with `sign` and `verify` methods for the\nalgorithm. Valid values for algorithm can be found in the table above\n(`'HS256'`, `'HS384'`, etc) and are case-insensitive. Passing an invalid\nalgorithm value will throw a `TypeError`.\n\n\n## jwa#sign(input, secretOrPrivateKey)\n\nSign some input with either a secret for HMAC algorithms, or a private\nkey for RSA and ECDSA algorithms.\n\nIf input is not already a string or buffer, `JSON.stringify` will be\ncalled on it to attempt to coerce it.\n\nFor the HMAC algorithm, `secretOrPrivateKey` should be a string or a\nbuffer. For ECDSA and RSA, the value should be a string representing a\nPEM encoded **private** key. \n\nOutput [base64url](http://en.wikipedia.org/wiki/Base64#URL_applications)\nformatted. This is for convenience as JWS expects the signature in this\nformat. If your application needs the output in a different format,\n[please open an issue](https://github.com/brianloveswords/node-jwa/issues). In\nthe meantime, you can use\n[brianloveswords/base64url](https://github.com/brianloveswords/base64url)\nto decode the signature.\n\nAs of nodejs *v0.11.8*, SPKAC support was introduce. If your nodeJs\nversion satisfies, then you can pass an object `{ key: '..', passphrase: '...' }`\n\n\n## jwa#verify(input, signature, secretOrPublicKey)\n\nVerify a signature. Returns `true` or `false`.\n\n`signature` should be a base64url encoded string.\n\nFor the HMAC algorithm, `secretOrPublicKey` should be a string or a\nbuffer. For ECDSA and RSA, the value should be a string represented a\nPEM encoded **public** key.\n\n\n# Example\n\nHMAC\n```js\nconst jwa = require('jwa');\n\nconst hmac = jwa('HS256');\nconst input = 'super important stuff';\nconst secret = 'shhhhhh';\n\nconst signature = hmac.sign(input, secret);\nhmac.verify(input, signature, secret) // === true\nhmac.verify(input, signature, 'trickery!') // === false\n```\n\nWith keys\n```js\nconst fs = require('fs');\nconst jwa = require('jwa');\nconst privateKey = fs.readFileSync(__dirname + '/ecdsa-p521-private.pem');\nconst publicKey = fs.readFileSync(__dirname + '/ecdsa-p521-public.pem');\n\nconst ecdsa = jwa('ES512');\nconst input = 'very important stuff';\n\nconst signature = ecdsa.sign(input, privateKey);\necdsa.verify(input, signature, publicKey) // === true\n```\n## License\n\nMIT\n\n```\nCopyright (c) 2013 Brian J. Brennan\n\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be included\nin all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\nOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n```\n",
+  "readmeFilename": "README.md",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/brianloveswords/node-jwa.git"
+  },
+  "scripts": {
+    "test": "make test"
+  },
+  "version": "1.1.4"
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jws/.npmignore b/KEMMessaging/node_modules/firebase-admin/node_modules/jws/.npmignore
new file mode 100644
index 0000000000000000000000000000000000000000..5315b6c5cb329fb5a0623d836239f2584a2d0104
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jws/.npmignore
@@ -0,0 +1,4 @@
+Makefile
+test/
+.travis.yml
+.jshintrc
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jws/CHANGELOG.md b/KEMMessaging/node_modules/firebase-admin/node_modules/jws/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..af8fc287676c18be82b92bcbae320a6ad07bdcd9
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jws/CHANGELOG.md
@@ -0,0 +1,34 @@
+# Change Log
+All notable changes to this project will be documented in this file.
+
+## [3.0.0]
+### Changed
+- **BREAKING**: `jwt.verify` now requires an `algorithm` parameter, and
+  `jws.createVerify` requires an `algorithm` option. The `"alg"` field
+  signature headers is ignored. This mitigates a critical security flaw
+  in the library which would allow an attacker to generate signatures with
+  arbitrary contents that would be accepted by `jwt.verify`. See
+  https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/
+  for details.
+
+## [2.0.0] - 2015-01-30
+### Changed
+- **BREAKING**: Default payload encoding changed from `binary` to
+  `utf8`. `utf8` is a is a more sensible default than `binary` because
+  many payloads, as far as I can tell, will contain user-facing
+  strings that could be in any language. (<code>[6b6de48]</code>)
+
+- Code reorganization, thanks [@fearphage]! (<code>[7880050]</code>)
+
+### Added
+- Option in all relevant methods for `encoding`. For those few users
+  that might be depending on a `binary` encoding of the messages, this
+  is for them. (<code>[6b6de48]</code>)
+
+[unreleased]: https://github.com/brianloveswords/node-jws/compare/v2.0.0...HEAD
+[2.0.0]: https://github.com/brianloveswords/node-jws/compare/v1.0.1...v2.0.0
+
+[7880050]: https://github.com/brianloveswords/node-jws/commit/7880050
+[6b6de48]: https://github.com/brianloveswords/node-jws/commit/6b6de48
+
+[@fearphage]: https://github.com/fearphage
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jws/LICENSE b/KEMMessaging/node_modules/firebase-admin/node_modules/jws/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..caeb8495c857edf2c981d26557292bc6f1cf872a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jws/LICENSE
@@ -0,0 +1,17 @@
+Copyright (c) 2013 Brian J. Brennan
+
+Permission is hereby granted, free of charge, to any person obtaining a copy 
+of this software and associated documentation files (the "Software"), to deal in 
+the Software without restriction, including without limitation the rights to use, 
+copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 
+Software, and to permit persons to whom the Software is furnished to do so, 
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all 
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jws/index.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jws/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..f29a1361ebc57651180f2bcee677b078f0b53e27
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jws/index.js
@@ -0,0 +1,21 @@
+/*global exports*/
+var SignStream = require('./lib/sign-stream');
+var VerifyStream = require('./lib/verify-stream');
+
+var ALGORITHMS = [
+  'HS256', 'HS384', 'HS512',
+  'RS256', 'RS384', 'RS512',
+  'ES256', 'ES384', 'ES512'
+];
+
+exports.ALGORITHMS = ALGORITHMS;
+exports.sign = SignStream.sign;
+exports.verify = VerifyStream.verify;
+exports.decode = VerifyStream.decode;
+exports.isValid = VerifyStream.isValid;
+exports.createSign = function createSign(opts) {
+  return new SignStream(opts);
+};
+exports.createVerify = function createVerify(opts) {
+  return new VerifyStream(opts);
+};
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jws/lib/data-stream.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jws/lib/data-stream.js
new file mode 100644
index 0000000000000000000000000000000000000000..3535d31d9fb315ab94cff7ce2e0dc7e220b283fa
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jws/lib/data-stream.js
@@ -0,0 +1,55 @@
+/*global module, process*/
+var Buffer = require('safe-buffer').Buffer;
+var Stream = require('stream');
+var util = require('util');
+
+function DataStream(data) {
+  this.buffer = null;
+  this.writable = true;
+  this.readable = true;
+
+  // No input
+  if (!data) {
+    this.buffer = Buffer.alloc(0);
+    return this;
+  }
+
+  // Stream
+  if (typeof data.pipe === 'function') {
+    this.buffer = Buffer.alloc(0);
+    data.pipe(this);
+    return this;
+  }
+
+  // Buffer or String
+  // or Object (assumedly a passworded key)
+  if (data.length || typeof data === 'object') {
+    this.buffer = data;
+    this.writable = false;
+    process.nextTick(function () {
+      this.emit('end', data);
+      this.readable = false;
+      this.emit('close');
+    }.bind(this));
+    return this;
+  }
+
+  throw new TypeError('Unexpected data type ('+ typeof data + ')');
+}
+util.inherits(DataStream, Stream);
+
+DataStream.prototype.write = function write(data) {
+  this.buffer = Buffer.concat([this.buffer, Buffer.from(data)]);
+  this.emit('data', data);
+};
+
+DataStream.prototype.end = function end(data) {
+  if (data)
+    this.write(data);
+  this.emit('end', data);
+  this.emit('close');
+  this.writable = false;
+  this.readable = false;
+};
+
+module.exports = DataStream;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jws/lib/sign-stream.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jws/lib/sign-stream.js
new file mode 100644
index 0000000000000000000000000000000000000000..e24576fb69049a3843e2d5e107262c87e6ec6a94
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jws/lib/sign-stream.js
@@ -0,0 +1,69 @@
+/*global module*/
+var base64url = require('base64url');
+var DataStream = require('./data-stream');
+var jwa = require('jwa');
+var Stream = require('stream');
+var toString = require('./tostring');
+var util = require('util');
+
+function jwsSecuredInput(header, payload, encoding) {
+  encoding = encoding || 'utf8';
+  var encodedHeader = base64url(toString(header), 'binary');
+  var encodedPayload = base64url(toString(payload), encoding);
+  return util.format('%s.%s', encodedHeader, encodedPayload);
+}
+
+function jwsSign(opts) {
+  var header = opts.header;
+  var payload = opts.payload;
+  var secretOrKey = opts.secret || opts.privateKey;
+  var encoding = opts.encoding;
+  var algo = jwa(header.alg);
+  var securedInput = jwsSecuredInput(header, payload, encoding);
+  var signature = algo.sign(securedInput, secretOrKey);
+  return util.format('%s.%s', securedInput, signature);
+}
+
+function SignStream(opts) {
+  var secret = opts.secret||opts.privateKey||opts.key;
+  var secretStream = new DataStream(secret);
+  this.readable = true;
+  this.header = opts.header;
+  this.encoding = opts.encoding;
+  this.secret = this.privateKey = this.key = secretStream;
+  this.payload = new DataStream(opts.payload);
+  this.secret.once('close', function () {
+    if (!this.payload.writable && this.readable)
+      this.sign();
+  }.bind(this));
+
+  this.payload.once('close', function () {
+    if (!this.secret.writable && this.readable)
+      this.sign();
+  }.bind(this));
+}
+util.inherits(SignStream, Stream);
+
+SignStream.prototype.sign = function sign() {
+  try {
+    var signature = jwsSign({
+      header: this.header,
+      payload: this.payload.buffer,
+      secret: this.secret.buffer,
+      encoding: this.encoding
+    });
+    this.emit('done', signature);
+    this.emit('data', signature);
+    this.emit('end');
+    this.readable = false;
+    return signature;
+  } catch (e) {
+    this.readable = false;
+    this.emit('error', e);
+    this.emit('close');
+  }
+};
+
+SignStream.sign = jwsSign;
+
+module.exports = SignStream;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jws/lib/tostring.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jws/lib/tostring.js
new file mode 100644
index 0000000000000000000000000000000000000000..f5a49a36548b1e299042c9e3d1cdd60c71d8ec0c
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jws/lib/tostring.js
@@ -0,0 +1,10 @@
+/*global module*/
+var Buffer = require('buffer').Buffer;
+
+module.exports = function toString(obj) {
+  if (typeof obj === 'string')
+    return obj;
+  if (typeof obj === 'number' || Buffer.isBuffer(obj))
+    return obj.toString();
+  return JSON.stringify(obj);
+};
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jws/lib/verify-stream.js b/KEMMessaging/node_modules/firebase-admin/node_modules/jws/lib/verify-stream.js
new file mode 100644
index 0000000000000000000000000000000000000000..d9bfa2b20c564fea8e75c974f644d5b8f7f0fd4c
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jws/lib/verify-stream.js
@@ -0,0 +1,120 @@
+/*global module*/
+var base64url = require('base64url');
+var DataStream = require('./data-stream');
+var jwa = require('jwa');
+var Stream = require('stream');
+var toString = require('./tostring');
+var util = require('util');
+var JWS_REGEX = /^[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?\.([a-zA-Z0-9\-_]+)?$/;
+
+function isObject(thing) {
+  return Object.prototype.toString.call(thing) === '[object Object]';
+}
+
+function safeJsonParse(thing) {
+  if (isObject(thing))
+    return thing;
+  try { return JSON.parse(thing); }
+  catch (e) { return undefined; }
+}
+
+function headerFromJWS(jwsSig) {
+  var encodedHeader = jwsSig.split('.', 1)[0];
+  return safeJsonParse(base64url.decode(encodedHeader, 'binary'));
+}
+
+function securedInputFromJWS(jwsSig) {
+  return jwsSig.split('.', 2).join('.');
+}
+
+function signatureFromJWS(jwsSig) {
+  return jwsSig.split('.')[2];
+}
+
+function payloadFromJWS(jwsSig, encoding) {
+  encoding = encoding || 'utf8';
+  var payload = jwsSig.split('.')[1];
+  return base64url.decode(payload, encoding);
+}
+
+function isValidJws(string) {
+  return JWS_REGEX.test(string) && !!headerFromJWS(string);
+}
+
+function jwsVerify(jwsSig, algorithm, secretOrKey) {
+  if (!algorithm) {
+    var err = new Error("Missing algorithm parameter for jws.verify");
+    err.code = "MISSING_ALGORITHM";
+    throw err;
+  }
+  jwsSig = toString(jwsSig);
+  var signature = signatureFromJWS(jwsSig);
+  var securedInput = securedInputFromJWS(jwsSig);
+  var algo = jwa(algorithm);
+  return algo.verify(securedInput, signature, secretOrKey);
+}
+
+function jwsDecode(jwsSig, opts) {
+  opts = opts || {};
+  jwsSig = toString(jwsSig);
+
+  if (!isValidJws(jwsSig))
+    return null;
+
+  var header = headerFromJWS(jwsSig);
+
+  if (!header)
+    return null;
+
+  var payload = payloadFromJWS(jwsSig);
+  if (header.typ === 'JWT' || opts.json)
+    payload = JSON.parse(payload, opts.encoding);
+
+  return {
+    header: header,
+    payload: payload,
+    signature: signatureFromJWS(jwsSig)
+  };
+}
+
+function VerifyStream(opts) {
+  opts = opts || {};
+  var secretOrKey = opts.secret||opts.publicKey||opts.key;
+  var secretStream = new DataStream(secretOrKey);
+  this.readable = true;
+  this.algorithm = opts.algorithm;
+  this.encoding = opts.encoding;
+  this.secret = this.publicKey = this.key = secretStream;
+  this.signature = new DataStream(opts.signature);
+  this.secret.once('close', function () {
+    if (!this.signature.writable && this.readable)
+      this.verify();
+  }.bind(this));
+
+  this.signature.once('close', function () {
+    if (!this.secret.writable && this.readable)
+      this.verify();
+  }.bind(this));
+}
+util.inherits(VerifyStream, Stream);
+VerifyStream.prototype.verify = function verify() {
+  try {
+    var valid = jwsVerify(this.signature.buffer, this.algorithm, this.key.buffer);
+    var obj = jwsDecode(this.signature.buffer, this.encoding);
+    this.emit('done', valid, obj);
+    this.emit('data', valid);
+    this.emit('end');
+    this.readable = false;
+    return valid;
+  } catch (e) {
+    this.readable = false;
+    this.emit('error', e);
+    this.emit('close');
+  }
+};
+
+VerifyStream.decode = jwsDecode;
+VerifyStream.isValid = isValidJws;
+VerifyStream.verify = jwsVerify;
+
+module.exports = VerifyStream;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jws/package.json b/KEMMessaging/node_modules/firebase-admin/node_modules/jws/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..cabc593480301e8356d3c779613b9d5d1ddce28d
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jws/package.json
@@ -0,0 +1,80 @@
+{
+  "_args": [
+    [
+      {
+        "raw": "jws@https://registry.npmjs.org/jws/-/jws-3.1.4.tgz",
+        "scope": null,
+        "escapedName": "jws",
+        "name": "jws",
+        "rawSpec": "https://registry.npmjs.org/jws/-/jws-3.1.4.tgz",
+        "spec": "https://registry.npmjs.org/jws/-/jws-3.1.4.tgz",
+        "type": "remote"
+      },
+      "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin"
+    ]
+  ],
+  "_from": "jws@>=3.1.3 <4.0.0",
+  "_id": "jws@3.1.4",
+  "_inCache": true,
+  "_location": "/firebase-admin/jws",
+  "_phantomChildren": {},
+  "_requested": {
+    "raw": "jws@https://registry.npmjs.org/jws/-/jws-3.1.4.tgz",
+    "scope": null,
+    "escapedName": "jws",
+    "name": "jws",
+    "rawSpec": "https://registry.npmjs.org/jws/-/jws-3.1.4.tgz",
+    "spec": "https://registry.npmjs.org/jws/-/jws-3.1.4.tgz",
+    "type": "remote"
+  },
+  "_requiredBy": [
+    "/firebase-admin",
+    "/firebase-admin/jsonwebtoken"
+  ],
+  "_resolved": "https://registry.npmjs.org/jws/-/jws-3.1.4.tgz",
+  "_shasum": "f9e8b9338e8a847277d6444b1464f61880e050a2",
+  "_shrinkwrap": null,
+  "_spec": "jws@https://registry.npmjs.org/jws/-/jws-3.1.4.tgz",
+  "_where": "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin",
+  "author": {
+    "name": "Brian J Brennan"
+  },
+  "bugs": {
+    "url": "https://github.com/brianloveswords/node-jws/issues"
+  },
+  "dependencies": {
+    "base64url": "^2.0.0",
+    "jwa": "^1.1.4",
+    "safe-buffer": "^5.0.1"
+  },
+  "description": "Implementation of JSON Web Signatures",
+  "devDependencies": {
+    "semver": "^5.1.0",
+    "tape": "~2.14.0"
+  },
+  "directories": {
+    "test": "test"
+  },
+  "gitHead": "c0f6b27bcea5a2ad2e304d91c2e842e4076a6b03",
+  "homepage": "https://github.com/brianloveswords/node-jws#readme",
+  "keywords": [
+    "jws",
+    "json",
+    "web",
+    "signatures"
+  ],
+  "license": "MIT",
+  "main": "index.js",
+  "name": "jws",
+  "optionalDependencies": {},
+  "readme": "# node-jws [![Build Status](https://secure.travis-ci.org/brianloveswords/node-jws.png)](http://travis-ci.org/brianloveswords/node-jws)\n\nAn implementation of [JSON Web Signatures](http://self-issued.info/docs/draft-ietf-jose-json-web-signature.html).\n\nThis was developed against `draft-ietf-jose-json-web-signature-08` and\nimplements the entire spec **except** X.509 Certificate Chain\nsigning/verifying (patches welcome).\n\nThere are both syncronous (`jws.sign`, `jws.verify`) and streaming\n(`jws.createSign`, `jws.createVerify`) APIs.\n\n# Install\n\n```bash\n$ npm install jws\n```\n\n# Usage\n\n## jws.ALGORITHMS\nArray of supported algorithms. The following algorithms are currently supported.\n\nalg Parameter Value | Digital Signature or MAC Algorithm\n----------------|----------------------------\nHS256 | HMAC using SHA-256 hash algorithm\nHS384 | HMAC using SHA-384 hash algorithm\nHS512 | HMAC using SHA-512 hash algorithm\nRS256 | RSASSA using SHA-256 hash algorithm\nRS384 | RSASSA using SHA-384 hash algorithm\nRS512 | RSASSA using SHA-512 hash algorithm\nES256 | ECDSA using P-256 curve and SHA-256 hash algorithm\nES384 | ECDSA using P-384 curve and SHA-384 hash algorithm\nES512 | ECDSA using P-521 curve and SHA-512 hash algorithm\nnone | No digital signature or MAC value included\n\n\n## jws.sign(options)\n\n(Synchronous) Return a JSON Web Signature for a header and a payload.\n\nOptions:\n\n* `header`\n* `payload`\n* `secret` or `privateKey`\n* `encoding` (Optional, defaults to 'utf8')\n\n`header` must be an object with an `alg` property. `header.alg` must be\none a value found in `jws.ALGORITHMS`. See above for a table of\nsupported algorithms.\n\nIf `payload` is not a buffer or a string, it will be coerced into a string\nusing `JSON.stringify`.\n\nExample\n\n```js\nconst signature = jws.sign({\n  header: { alg: 'HS256' },\n  payload: 'h. jon benjamin',\n  secret: 'has a van',\n});\n```\n\n## jws.verify(signature, algorithm, secretOrKey)\n\n(Synchronous) Returns`true` or `false` for whether a signature matches a\nsecret or key.\n\n`signature` is a JWS Signature. `header.alg` must be a value found in `jws.ALGORITHMS`.\nSee above for a table of supported algorithms. `secretOrKey` is a string or\nbuffer containing either the secret for HMAC algorithms, or the PEM\nencoded public key for RSA and ECDSA.\n\nNote that the `\"alg\"` value from the signature header is ignored.\n\n\n## jws.decode(signature)\n\n(Synchronous) Returns the decoded header, decoded payload, and signature\nparts of the JWS Signature.\n\nReturns an object with three properties, e.g.\n```js\n{ header: { alg: 'HS256' },\n  payload: 'h. jon benjamin',\n  signature: 'YOWPewyGHKu4Y_0M_vtlEnNlqmFOclqp4Hy6hVHfFT4'\n}\n```\n\n## jws.createSign(options)\nReturns a new SignStream object.\n\nOptions:\n\n* `header` (required)\n* `payload`\n* `key` || `privateKey` || `secret`\n* `encoding` (Optional, defaults to 'utf8')\n\nOther than `header`, all options expect a string or a buffer when the\nvalue is known ahead of time, or a stream for convenience.\n`key`/`privateKey`/`secret` may also be an object when using an encrypted\nprivate key, see the [crypto documentation][encrypted-key-docs].\n\nExample\n```js\n\n// This...\njws.createSign({\n  header: { alg: 'RS256' },\n  privateKey: privateKeyStream,\n  payload: payloadStream,\n}).on('done', function(signature) {\n  // ...\n});\n\n// is equivilant to this:\nconst signer = jws.createSign(\n  header: { alg: 'RS256' },\n);\nprivateKeyStream.pipe(signer.privateKey);\npayloadStream.pipe(signer.payload);\nsigner.on('done', function(signature) {\n  // ...\n});\n```\n\n## jws.createVerify(options)\nReturns a new VerifyStream object.\n\nOptions:\n\n* `signature`\n* `algorithm`\n* `key` || `publicKey` || `secret`\n* `encoding` (Optional, defaults to 'utf8')\n\nAll options expect a string or a buffer when the value is known ahead of\ntime, or a stream for convenience.\n\nExample\n```js\n\n// This...\njws.createVerify({\n  publicKey: pubKeyStream,\n  signature: sigStream,\n}).on('done', function(verified, obj) {\n  // ...\n});\n\n// is equivilant to this:\nconst verifier = jws.createVerify();\npubKeyStream.pipe(verifier.publicKey);\nsigStream.pipe(verifier.signature);\nverifier.on('done', function(verified, obj) {\n  // ...\n});\n```\n\n## Class: SignStream\nA `Readable Stream` that emits a single data event, the calculated\nsignature, when done.\n\n### Event: 'done'\n`function (signature) { }`\n\n### signer.payload\n\nA `Writable Stream` that expects the JWS payload. Do *not* use if you\npassed a `payload` option to the constructor.\n\nExample\n\n```js\npayloadStream.pipe(signer.payload);\n```\n\n### signer.secret<br>signer.key<br>signer.privateKey\n\nA `Writable Stream`. Expects the JWS secret for HMAC, or the privateKey\nfor ECDSA and RSA. Do *not* use if you passed a `secret` or `key` option\nto the constructor.\n\nExample:\n\n```js\nprivateKeyStream.pipe(signer.privateKey);\n```\n\n## Class: VerifyStream\n\nThis is a `Readable Stream` that emits a single data event, the result\nof whether or not that signature was valid.\n\n### Event: 'done'\n`function (valid, obj) { }`\n\n`valid` is a boolean for whether or not the signature is valid.\n\n### verifier.signature\nA `Writable Stream` that expects a JWS Signature. Do *not* use if you\npassed a `signature` option to the constructor.\n\n### verifier.secret<br>verifier.key<br>verifier.publicKey\n\nA `Writable Stream` that expects a public key or secret. Do *not* use if you\npassed a `key` or `secret` option to the constructor.\n\n\n# TODO\n\n* It feels like there should be some convenience options/APIs for\n  defining the algorithm rather than having to define a header object\n  with `{ alg: 'ES512' }` or whatever every time.\n\n* X.509 support, ugh\n\n\n# License\n\nMIT\n\n```\nCopyright (c) 2013-2015 Brian J. Brennan\n\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be included\nin all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\nOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n```\n\n[encrypted-key-docs]: https://nodejs.org/api/crypto.html#crypto_sign_sign_private_key_output_format\n",
+  "readmeFilename": "readme.md",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/brianloveswords/node-jws.git"
+  },
+  "scripts": {
+    "test": "make test"
+  },
+  "version": "3.1.4"
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/jws/readme.md b/KEMMessaging/node_modules/firebase-admin/node_modules/jws/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..e4200b872555cf97bd24c70105eaf98d5ebe3e9a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/jws/readme.md
@@ -0,0 +1,248 @@
+# node-jws [![Build Status](https://secure.travis-ci.org/brianloveswords/node-jws.png)](http://travis-ci.org/brianloveswords/node-jws)
+
+An implementation of [JSON Web Signatures](http://self-issued.info/docs/draft-ietf-jose-json-web-signature.html).
+
+This was developed against `draft-ietf-jose-json-web-signature-08` and
+implements the entire spec **except** X.509 Certificate Chain
+signing/verifying (patches welcome).
+
+There are both syncronous (`jws.sign`, `jws.verify`) and streaming
+(`jws.createSign`, `jws.createVerify`) APIs.
+
+# Install
+
+```bash
+$ npm install jws
+```
+
+# Usage
+
+## jws.ALGORITHMS
+Array of supported algorithms. The following algorithms are currently supported.
+
+alg Parameter Value | Digital Signature or MAC Algorithm
+----------------|----------------------------
+HS256 | HMAC using SHA-256 hash algorithm
+HS384 | HMAC using SHA-384 hash algorithm
+HS512 | HMAC using SHA-512 hash algorithm
+RS256 | RSASSA using SHA-256 hash algorithm
+RS384 | RSASSA using SHA-384 hash algorithm
+RS512 | RSASSA using SHA-512 hash algorithm
+ES256 | ECDSA using P-256 curve and SHA-256 hash algorithm
+ES384 | ECDSA using P-384 curve and SHA-384 hash algorithm
+ES512 | ECDSA using P-521 curve and SHA-512 hash algorithm
+none | No digital signature or MAC value included
+
+
+## jws.sign(options)
+
+(Synchronous) Return a JSON Web Signature for a header and a payload.
+
+Options:
+
+* `header`
+* `payload`
+* `secret` or `privateKey`
+* `encoding` (Optional, defaults to 'utf8')
+
+`header` must be an object with an `alg` property. `header.alg` must be
+one a value found in `jws.ALGORITHMS`. See above for a table of
+supported algorithms.
+
+If `payload` is not a buffer or a string, it will be coerced into a string
+using `JSON.stringify`.
+
+Example
+
+```js
+const signature = jws.sign({
+  header: { alg: 'HS256' },
+  payload: 'h. jon benjamin',
+  secret: 'has a van',
+});
+```
+
+## jws.verify(signature, algorithm, secretOrKey)
+
+(Synchronous) Returns`true` or `false` for whether a signature matches a
+secret or key.
+
+`signature` is a JWS Signature. `header.alg` must be a value found in `jws.ALGORITHMS`.
+See above for a table of supported algorithms. `secretOrKey` is a string or
+buffer containing either the secret for HMAC algorithms, or the PEM
+encoded public key for RSA and ECDSA.
+
+Note that the `"alg"` value from the signature header is ignored.
+
+
+## jws.decode(signature)
+
+(Synchronous) Returns the decoded header, decoded payload, and signature
+parts of the JWS Signature.
+
+Returns an object with three properties, e.g.
+```js
+{ header: { alg: 'HS256' },
+  payload: 'h. jon benjamin',
+  signature: 'YOWPewyGHKu4Y_0M_vtlEnNlqmFOclqp4Hy6hVHfFT4'
+}
+```
+
+## jws.createSign(options)
+Returns a new SignStream object.
+
+Options:
+
+* `header` (required)
+* `payload`
+* `key` || `privateKey` || `secret`
+* `encoding` (Optional, defaults to 'utf8')
+
+Other than `header`, all options expect a string or a buffer when the
+value is known ahead of time, or a stream for convenience.
+`key`/`privateKey`/`secret` may also be an object when using an encrypted
+private key, see the [crypto documentation][encrypted-key-docs].
+
+Example
+```js
+
+// This...
+jws.createSign({
+  header: { alg: 'RS256' },
+  privateKey: privateKeyStream,
+  payload: payloadStream,
+}).on('done', function(signature) {
+  // ...
+});
+
+// is equivilant to this:
+const signer = jws.createSign(
+  header: { alg: 'RS256' },
+);
+privateKeyStream.pipe(signer.privateKey);
+payloadStream.pipe(signer.payload);
+signer.on('done', function(signature) {
+  // ...
+});
+```
+
+## jws.createVerify(options)
+Returns a new VerifyStream object.
+
+Options:
+
+* `signature`
+* `algorithm`
+* `key` || `publicKey` || `secret`
+* `encoding` (Optional, defaults to 'utf8')
+
+All options expect a string or a buffer when the value is known ahead of
+time, or a stream for convenience.
+
+Example
+```js
+
+// This...
+jws.createVerify({
+  publicKey: pubKeyStream,
+  signature: sigStream,
+}).on('done', function(verified, obj) {
+  // ...
+});
+
+// is equivilant to this:
+const verifier = jws.createVerify();
+pubKeyStream.pipe(verifier.publicKey);
+sigStream.pipe(verifier.signature);
+verifier.on('done', function(verified, obj) {
+  // ...
+});
+```
+
+## Class: SignStream
+A `Readable Stream` that emits a single data event, the calculated
+signature, when done.
+
+### Event: 'done'
+`function (signature) { }`
+
+### signer.payload
+
+A `Writable Stream` that expects the JWS payload. Do *not* use if you
+passed a `payload` option to the constructor.
+
+Example
+
+```js
+payloadStream.pipe(signer.payload);
+```
+
+### signer.secret<br>signer.key<br>signer.privateKey
+
+A `Writable Stream`. Expects the JWS secret for HMAC, or the privateKey
+for ECDSA and RSA. Do *not* use if you passed a `secret` or `key` option
+to the constructor.
+
+Example:
+
+```js
+privateKeyStream.pipe(signer.privateKey);
+```
+
+## Class: VerifyStream
+
+This is a `Readable Stream` that emits a single data event, the result
+of whether or not that signature was valid.
+
+### Event: 'done'
+`function (valid, obj) { }`
+
+`valid` is a boolean for whether or not the signature is valid.
+
+### verifier.signature
+A `Writable Stream` that expects a JWS Signature. Do *not* use if you
+passed a `signature` option to the constructor.
+
+### verifier.secret<br>verifier.key<br>verifier.publicKey
+
+A `Writable Stream` that expects a public key or secret. Do *not* use if you
+passed a `key` or `secret` option to the constructor.
+
+
+# TODO
+
+* It feels like there should be some convenience options/APIs for
+  defining the algorithm rather than having to define a header object
+  with `{ alg: 'ES512' }` or whatever every time.
+
+* X.509 support, ugh
+
+
+# License
+
+MIT
+
+```
+Copyright (c) 2013-2015 Brian J. Brennan
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+```
+
+[encrypted-key-docs]: https://nodejs.org/api/crypto.html#crypto_sign_sign_private_key_output_format
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/lodash.once/LICENSE b/KEMMessaging/node_modules/firebase-admin/node_modules/lodash.once/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..e0c69d56032d1562a06c0caa8ab8b278efded3c0
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/lodash.once/LICENSE
@@ -0,0 +1,47 @@
+Copyright jQuery Foundation and other contributors <https://jquery.org/>
+
+Based on Underscore.js, copyright Jeremy Ashkenas,
+DocumentCloud and Investigative Reporters & Editors <http://underscorejs.org/>
+
+This software consists of voluntary contributions made by many
+individuals. For exact contribution history, see the revision history
+available at https://github.com/lodash/lodash
+
+The following license applies to all parts of this software except as
+documented below:
+
+====
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+====
+
+Copyright and related rights for sample code are waived via CC0. Sample
+code is defined as all source code displayed within the prose of the
+documentation.
+
+CC0: http://creativecommons.org/publicdomain/zero/1.0/
+
+====
+
+Files located in the node_modules and vendor directories are externally
+maintained libraries used by this software which have their own
+licenses; we recommend you read them, as their terms may differ from the
+terms above.
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/lodash.once/README.md b/KEMMessaging/node_modules/firebase-admin/node_modules/lodash.once/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..c4a2f1698f35a64b5e426010d21644b7787d28bf
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/lodash.once/README.md
@@ -0,0 +1,18 @@
+# lodash.once v4.1.1
+
+The [lodash](https://lodash.com/) method `_.once` exported as a [Node.js](https://nodejs.org/) module.
+
+## Installation
+
+Using npm:
+```bash
+$ {sudo -H} npm i -g npm
+$ npm i --save lodash.once
+```
+
+In Node.js:
+```js
+var once = require('lodash.once');
+```
+
+See the [documentation](https://lodash.com/docs#once) or [package source](https://github.com/lodash/lodash/blob/4.1.1-npm-packages/lodash.once) for more details.
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/lodash.once/index.js b/KEMMessaging/node_modules/firebase-admin/node_modules/lodash.once/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..414ceb3312c4d3d5e5ad3270b96f023ba3504bed
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/lodash.once/index.js
@@ -0,0 +1,294 @@
+/**
+ * lodash (Custom Build) <https://lodash.com/>
+ * Build: `lodash modularize exports="npm" -o ./`
+ * Copyright jQuery Foundation and other contributors <https://jquery.org/>
+ * Released under MIT license <https://lodash.com/license>
+ * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
+ * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ */
+
+/** Used as the `TypeError` message for "Functions" methods. */
+var FUNC_ERROR_TEXT = 'Expected a function';
+
+/** Used as references for various `Number` constants. */
+var INFINITY = 1 / 0,
+    MAX_INTEGER = 1.7976931348623157e+308,
+    NAN = 0 / 0;
+
+/** `Object#toString` result references. */
+var symbolTag = '[object Symbol]';
+
+/** Used to match leading and trailing whitespace. */
+var reTrim = /^\s+|\s+$/g;
+
+/** Used to detect bad signed hexadecimal string values. */
+var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
+
+/** Used to detect binary string values. */
+var reIsBinary = /^0b[01]+$/i;
+
+/** Used to detect octal string values. */
+var reIsOctal = /^0o[0-7]+$/i;
+
+/** Built-in method references without a dependency on `root`. */
+var freeParseInt = parseInt;
+
+/** Used for built-in method references. */
+var objectProto = Object.prototype;
+
+/**
+ * Used to resolve the
+ * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+var objectToString = objectProto.toString;
+
+/**
+ * Creates a function that invokes `func`, with the `this` binding and arguments
+ * of the created function, while it's called less than `n` times. Subsequent
+ * calls to the created function return the result of the last `func` invocation.
+ *
+ * @static
+ * @memberOf _
+ * @since 3.0.0
+ * @category Function
+ * @param {number} n The number of calls at which `func` is no longer invoked.
+ * @param {Function} func The function to restrict.
+ * @returns {Function} Returns the new restricted function.
+ * @example
+ *
+ * jQuery(element).on('click', _.before(5, addContactToList));
+ * // => Allows adding up to 4 contacts to the list.
+ */
+function before(n, func) {
+  var result;
+  if (typeof func != 'function') {
+    throw new TypeError(FUNC_ERROR_TEXT);
+  }
+  n = toInteger(n);
+  return function() {
+    if (--n > 0) {
+      result = func.apply(this, arguments);
+    }
+    if (n <= 1) {
+      func = undefined;
+    }
+    return result;
+  };
+}
+
+/**
+ * Creates a function that is restricted to invoking `func` once. Repeat calls
+ * to the function return the value of the first invocation. The `func` is
+ * invoked with the `this` binding and arguments of the created function.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Function
+ * @param {Function} func The function to restrict.
+ * @returns {Function} Returns the new restricted function.
+ * @example
+ *
+ * var initialize = _.once(createApplication);
+ * initialize();
+ * initialize();
+ * // => `createApplication` is invoked once
+ */
+function once(func) {
+  return before(2, func);
+}
+
+/**
+ * Checks if `value` is the
+ * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
+ * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an object, else `false`.
+ * @example
+ *
+ * _.isObject({});
+ * // => true
+ *
+ * _.isObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isObject(_.noop);
+ * // => true
+ *
+ * _.isObject(null);
+ * // => false
+ */
+function isObject(value) {
+  var type = typeof value;
+  return !!value && (type == 'object' || type == 'function');
+}
+
+/**
+ * Checks if `value` is object-like. A value is object-like if it's not `null`
+ * and has a `typeof` result of "object".
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
+ * @example
+ *
+ * _.isObjectLike({});
+ * // => true
+ *
+ * _.isObjectLike([1, 2, 3]);
+ * // => true
+ *
+ * _.isObjectLike(_.noop);
+ * // => false
+ *
+ * _.isObjectLike(null);
+ * // => false
+ */
+function isObjectLike(value) {
+  return !!value && typeof value == 'object';
+}
+
+/**
+ * Checks if `value` is classified as a `Symbol` primitive or object.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
+ * @example
+ *
+ * _.isSymbol(Symbol.iterator);
+ * // => true
+ *
+ * _.isSymbol('abc');
+ * // => false
+ */
+function isSymbol(value) {
+  return typeof value == 'symbol' ||
+    (isObjectLike(value) && objectToString.call(value) == symbolTag);
+}
+
+/**
+ * Converts `value` to a finite number.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.12.0
+ * @category Lang
+ * @param {*} value The value to convert.
+ * @returns {number} Returns the converted number.
+ * @example
+ *
+ * _.toFinite(3.2);
+ * // => 3.2
+ *
+ * _.toFinite(Number.MIN_VALUE);
+ * // => 5e-324
+ *
+ * _.toFinite(Infinity);
+ * // => 1.7976931348623157e+308
+ *
+ * _.toFinite('3.2');
+ * // => 3.2
+ */
+function toFinite(value) {
+  if (!value) {
+    return value === 0 ? value : 0;
+  }
+  value = toNumber(value);
+  if (value === INFINITY || value === -INFINITY) {
+    var sign = (value < 0 ? -1 : 1);
+    return sign * MAX_INTEGER;
+  }
+  return value === value ? value : 0;
+}
+
+/**
+ * Converts `value` to an integer.
+ *
+ * **Note:** This method is loosely based on
+ * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger).
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to convert.
+ * @returns {number} Returns the converted integer.
+ * @example
+ *
+ * _.toInteger(3.2);
+ * // => 3
+ *
+ * _.toInteger(Number.MIN_VALUE);
+ * // => 0
+ *
+ * _.toInteger(Infinity);
+ * // => 1.7976931348623157e+308
+ *
+ * _.toInteger('3.2');
+ * // => 3
+ */
+function toInteger(value) {
+  var result = toFinite(value),
+      remainder = result % 1;
+
+  return result === result ? (remainder ? result - remainder : result) : 0;
+}
+
+/**
+ * Converts `value` to a number.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to process.
+ * @returns {number} Returns the number.
+ * @example
+ *
+ * _.toNumber(3.2);
+ * // => 3.2
+ *
+ * _.toNumber(Number.MIN_VALUE);
+ * // => 5e-324
+ *
+ * _.toNumber(Infinity);
+ * // => Infinity
+ *
+ * _.toNumber('3.2');
+ * // => 3.2
+ */
+function toNumber(value) {
+  if (typeof value == 'number') {
+    return value;
+  }
+  if (isSymbol(value)) {
+    return NAN;
+  }
+  if (isObject(value)) {
+    var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
+    value = isObject(other) ? (other + '') : other;
+  }
+  if (typeof value != 'string') {
+    return value === 0 ? value : +value;
+  }
+  value = value.replace(reTrim, '');
+  var isBinary = reIsBinary.test(value);
+  return (isBinary || reIsOctal.test(value))
+    ? freeParseInt(value.slice(2), isBinary ? 2 : 8)
+    : (reIsBadHex.test(value) ? NAN : +value);
+}
+
+module.exports = once;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/lodash.once/package.json b/KEMMessaging/node_modules/firebase-admin/node_modules/lodash.once/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..f165686898ef899533b9a3b39d3f29c93bb9e11b
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/lodash.once/package.json
@@ -0,0 +1,86 @@
+{
+  "_args": [
+    [
+      {
+        "raw": "lodash.once@https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+        "scope": null,
+        "escapedName": "lodash.once",
+        "name": "lodash.once",
+        "rawSpec": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+        "spec": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+        "type": "remote"
+      },
+      "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin"
+    ]
+  ],
+  "_from": "lodash.once@>=4.0.0 <5.0.0",
+  "_id": "lodash.once@4.1.1",
+  "_inCache": true,
+  "_location": "/firebase-admin/lodash.once",
+  "_phantomChildren": {},
+  "_requested": {
+    "raw": "lodash.once@https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+    "scope": null,
+    "escapedName": "lodash.once",
+    "name": "lodash.once",
+    "rawSpec": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+    "spec": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+    "type": "remote"
+  },
+  "_requiredBy": [
+    "/firebase-admin",
+    "/firebase-admin/jsonwebtoken"
+  ],
+  "_resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+  "_shasum": "0dd3971213c7c56df880977d504c88fb471a97ac",
+  "_shrinkwrap": null,
+  "_spec": "lodash.once@https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+  "_where": "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin",
+  "author": {
+    "name": "John-David Dalton",
+    "email": "john.david.dalton@gmail.com",
+    "url": "http://allyoucanleet.com/"
+  },
+  "bugs": {
+    "url": "https://github.com/lodash/lodash/issues"
+  },
+  "contributors": [
+    {
+      "name": "John-David Dalton",
+      "email": "john.david.dalton@gmail.com",
+      "url": "http://allyoucanleet.com/"
+    },
+    {
+      "name": "Blaine Bublitz",
+      "email": "blaine.bublitz@gmail.com",
+      "url": "https://github.com/phated"
+    },
+    {
+      "name": "Mathias Bynens",
+      "email": "mathias@qiwi.be",
+      "url": "https://mathiasbynens.be/"
+    }
+  ],
+  "dependencies": {},
+  "description": "The lodash method `_.once` exported as a module.",
+  "devDependencies": {},
+  "homepage": "https://lodash.com/",
+  "icon": "https://lodash.com/icon.svg",
+  "keywords": [
+    "lodash-modularized",
+    "once"
+  ],
+  "license": "MIT",
+  "name": "lodash.once",
+  "optionalDependencies": {},
+  "readme": "# lodash.once v4.1.1\n\nThe [lodash](https://lodash.com/) method `_.once` exported as a [Node.js](https://nodejs.org/) module.\n\n## Installation\n\nUsing npm:\n```bash\n$ {sudo -H} npm i -g npm\n$ npm i --save lodash.once\n```\n\nIn Node.js:\n```js\nvar once = require('lodash.once');\n```\n\nSee the [documentation](https://lodash.com/docs#once) or [package source](https://github.com/lodash/lodash/blob/4.1.1-npm-packages/lodash.once) for more details.\n",
+  "readmeFilename": "README.md",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/lodash/lodash.git"
+  },
+  "scripts": {
+    "test": "echo \"See https://travis-ci.org/lodash/lodash-cli for testing details.\""
+  },
+  "version": "4.1.1"
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/CHANGELOG.md b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..1b47d09879045658dc3a54a32ec5348d2d551578
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/CHANGELOG.md
@@ -0,0 +1,719 @@
+Changelog
+=========
+
+### 2.16.0 [See full changelog](https://gist.github.com/ichernev/17bffc1005a032cb1a8ac4c1558b4994)
+* Release Nov 9, 2016
+
+## Features
+* [#3530](https://github.com/moment/moment/pull/3530) [feature] Check whether input is date before checking if format is array
+* [#3515](https://github.com/moment/moment/pull/3515) [feature] Fix [#2300](https://github.com/moment/moment/issues/2300): Default to current week.
+
+## Bugfixes
+* [#3546](https://github.com/moment/moment/pull/3546) [bugfix] Implement lazy-loading of child locales with missing prents
+* [#3523](https://github.com/moment/moment/pull/3523) [bugfix] parseZone should handle UTC
+* [#3502](https://github.com/moment/moment/pull/3502) [bugfix] Fix [#3500](https://github.com/moment/moment/issues/3500): ISO 8601 parsing should match the full string, not the beginning of the string.
+* [#3581](https://github.com/moment/moment/pull/3581) [bugfix] Fix parseZone, redo [#3504](https://github.com/moment/moment/issues/3504), fix [#3463](https://github.com/moment/moment/issues/3463)
+
+## New Locales
+* [#3416](https://github.com/moment/moment/pull/3416) [new locale] nl-be: Dutch (Belgium) locale
+* [#3393](https://github.com/moment/moment/pull/3393) [new locale] ar-dz: Arabic (Algeria) locale
+* [#3342](https://github.com/moment/moment/pull/3342) [new locale] tet: Tetun Dili (East Timor) locale
+
+And more locale, build and typescript improvements
+
+### 2.15.2
+* Release Oct 23, 2016
+* [#3525](https://github.com/moment/moment/pull/3525) Speedup month standalone/format regexes **(IMPORTANT)**
+* [#3466](https://github.com/moment/moment/pull/3466) Fix typo of Javanese
+
+### 2.15.1
+* Release Sept 20, 2016
+* [#3438](https://github.com/moment/moment/pull/3438) Fix locale autoload, revert [#3344](https://github.com/moment/moment/pull/3344)
+
+### 2.15.0 [See full changelog](https://gist.github.com/ichernev/10e1c5bf647545c72ca30e9628a09ed3)
+- Release Sept 12, 2016
+
+## New Locales
+* [#3255](https://github.com/moment/moment/pull/3255) [new locale] mi: Maori language
+* [#3267](https://github.com/moment/moment/pull/3267) [new locale] ar-ly: Arabic (Libya) locale
+* [#3333](https://github.com/moment/moment/pull/3333) [new locale] zh-hk: Chinese (Hong Kong) locale
+
+## Bugfixes
+* [#3276](https://github.com/moment/moment/pull/3276) [bugfix] duration: parser: Support ms durations in .NET syntax
+* [#3312](https://github.com/moment/moment/pull/3312) [bugfix] locales: Enable locale-data getters without moment (fixes [#3284](https://github.com/moment/moment/issues/3284))
+* [#3381](https://github.com/moment/moment/pull/3381) [bugfix] parsing: Fix parseZone without timezone in string, fixes [#3083](https://github.com/moment/moment/issues/3083)
+* [#3383](https://github.com/moment/moment/pull/3383) [bugfix] toJSON: Fix isValid so that toJSON works after a moment is frozen
+* [#3427](https://github.com/moment/moment/pull/3427) [bugfix] ie8: Fix IE8 (regression in 2.14.x)
+
+## Packaging
+* [#3299](https://github.com/moment/moment/pull/3299) [pkg] npm: Do not include .npmignore in npm package
+* [#3273](https://github.com/moment/moment/pull/3273) [pkg] jspm: Include moment.d.ts file in package
+* [#3344](https://github.com/moment/moment/pull/3344) [pkg] exports: use module.require for nodejs
+
+Also some locale and typescript improvements
+
+### 2.14.1
+- Release July 20, 2016
+* [#3280](https://github.com/moment/moment/pull/3280) Fix typescript definitions
+
+
+### 2.14.0 [See full changelog](https://gist.github.com/ichernev/812e79ac36a7829a22598fe964bfc18a)
+
+- Release July 20, 2016
+
+## New Features
+* [#3233](http://github.com/moment/moment/pull/3233) Introduce month.isFormat for format/standalone discovery
+* [#2848](http://github.com/moment/moment/pull/2848) Allow user to get/set the rounding method used when calculating relative time
+* [#3112](http://github.com/moment/moment/pull/3112) optimize configFromStringAndFormat
+* [#3147](http://github.com/moment/moment/pull/3147) Call calendar format function with moment context
+* [#3160](http://github.com/moment/moment/pull/3160) deprecate isDSTShifted
+* [#3175](http://github.com/moment/moment/pull/3175) make moment calendar extensible with ad-hoc options
+* [#3191](http://github.com/moment/moment/pull/3191) toDate returns a copy of the internal date object
+* [#3192](http://github.com/moment/moment/pull/3192) Adding support for rollup import.
+* [#3238](http://github.com/moment/moment/pull/3238) Handle empty object and empty array for creation as now
+* [#3082](http://github.com/moment/moment/pull/3082) Use relative AMD moment dependency
+
+## Bugfixes
+* [#3241](http://github.com/moment/moment/pull/3241) Escape all 24 mixed pieces, not only first 12 in computeMonthsParse
+* [#3008](http://github.com/moment/moment/pull/3008) Object setter orders sets based on size of unit
+* [#3177](http://github.com/moment/moment/pull/3177) Bug Fix [#2704](http://github.com/moment/moment/pull/2704) - isoWeekday(String) inconsistent with isoWeekday(Number)
+* [#3230](http://github.com/moment/moment/pull/3230) fix passing date with format string to ignore format string
+* [#3232](http://github.com/moment/moment/pull/3232) Fix negative 0 in certain diff cases
+* [#3235](http://github.com/moment/moment/pull/3235) Use proper locale inheritance for the base locale, fixes [#3137](http://github.com/moment/moment/pull/3137)
+
+Plus es-do locale and locale bugfixes
+
+### 2.13.0 [See full changelog](https://gist.github.com/ichernev/0132fcf5b61f7fc140b0bb0090480d49)
+- Release April 18, 2016
+## Enhancements:
+* [#2982](https://github.com/moment/moment/pull/2982) Add 'date' as alias to 'day' for startOf() and endOf().
+* [#2955](https://github.com/moment/moment/pull/2955) Add parsing negative components in durations when ISO 8601
+* [#2991](https://github.com/moment/moment/pull/2991) isBetween support for both open and closed intervals
+* [#3105](https://github.com/moment/moment/pull/3105) Add localeSorted argument to weekday listers
+* [#3102](https://github.com/moment/moment/pull/3102) Add k and kk formatting tokens
+
+## Bugfixes
+* [#3109](https://github.com/moment/moment/pull/3109) Fix [#1756](https://github.com/moment/moment/issues/1756) Resolved thread-safe issue on server side.
+* [#3078](https://github.com/moment/moment/pull/3078) Fix parsing for months/weekdays with weird characters
+* [#3098](https://github.com/moment/moment/pull/3098) Use Z suffix when in UTC mode ([#3020](https://github.com/moment/moment/issues/3020))
+* [#2995](https://github.com/moment/moment/pull/2995) Fix floating point rounding errors in durations
+* [#3059](https://github.com/moment/moment/pull/3059) fix bug where diff returns -0 in month-related diffs
+* [#3045](https://github.com/moment/moment/pull/3045) Fix mistaking any input for 'a' token
+* [#2877](https://github.com/moment/moment/pull/2877) Use explicit .valueOf() calls instead of coercion
+* [#3036](https://github.com/moment/moment/pull/3036) Year setter should keep time when DST changes
+
+Plus 3 new locales and locale fixes.
+
+### 2.12.0 [See full changelog](https://gist.github.com/ichernev/6e5bfdf8d6522fc4ac73)
+
+- Release March 7, 2016
+
+## Enhancements:
+* [#2932](https://github.com/moment/moment/pull/2932) List loaded locales
+* [#2818](https://github.com/moment/moment/pull/2818) Parse ISO-8061 duration containing both day and week values
+* [#2774](https://github.com/moment/moment/pull/2774) Implement locale inheritance and locale updating
+
+## Bugfixes:
+* [#2970](https://github.com/moment/moment/pull/2970) change add subtract to handle decimal values by rounding
+* [#2887](https://github.com/moment/moment/pull/2887) Fix toJSON casting of invalid moment
+* [#2897](https://github.com/moment/moment/pull/2897) parse string arguments for month() correctly, closes #2884
+* [#2946](https://github.com/moment/moment/pull/2946) Fix usage suggestions for min and max
+
+## New locales:
+* [#2917](https://github.com/moment/moment/pull/2917) Locale Punjabi(Gurmukhi) India format conversion
+
+And more
+
+### 2.11.2 (Fix ReDoS attack vector)
+
+- Release February 7, 2016
+
+* [#2939](https://github.com/moment/moment/pull/2939) use full-string match to speed up aspnet regex match
+
+### 2.11.1 [See full changelog](https://gist.github.com/ichernev/8ec3ee25b749b4cff3c2)
+
+- Release January 9, 2016
+
+## Bugfixes:
+* [#2881](https://github.com/moment/moment/pull/2881) Revert "Merge pull request #2746 from mbad0la:develop" Sep->Sept
+* [#2868](https://github.com/moment/moment/pull/2868) Add format and parse token Y, so it actually works
+* [#2865](https://github.com/moment/moment/pull/2865) Use typeof checks for undefined for global variables
+* [#2858](https://github.com/moment/moment/pull/2858) Fix Date mocking regression introduced in 2.11.0
+* [#2864](https://github.com/moment/moment/pull/2864) Include changelog in npm release
+* [#2830](https://github.com/moment/moment/pull/2830) dep: add grunt-cli
+* [#2869](https://github.com/moment/moment/pull/2869) Fix months parsing for some locales
+
+### 2.11.0 [See full changelog](https://gist.github.com/ichernev/6594bc29719dde6b2f66)
+
+- Release January 4, 2016
+
+* [#2624](https://github.com/moment/moment/pull/2624) Proper handling of invalid moments
+* [#2634](https://github.com/moment/moment/pull/2634) Fix strict month parsing issue in cs,ru,sk
+* [#2735](https://github.com/moment/moment/pull/2735) Reset the locale back to 'en' after defining all locales in min/locales.js
+* [#2702](https://github.com/moment/moment/pull/2702) Week rework
+* [#2746](https://github.com/moment/moment/pull/2746) Changed September Abbreviation to "Sept" in locale-specific english
+  files and default locale file
+* [#2646](https://github.com/moment/moment/pull/2646) Fix [#2645](https://github.com/moment/moment/pull/2645) - invalid dates pre-1970
+
+* [#2641](https://github.com/moment/moment/pull/2641) Implement basic format and comma as ms separator in ISO 8601
+* [#2665](https://github.com/moment/moment/pull/2665) Implement stricter weekday parsing
+* [#2700](https://github.com/moment/moment/pull/2700) Add [Hh]mm and [Hh]mmss formatting tokens, so you can parse 123 with
+  hmm for example
+* [#2565](https://github.com/moment/moment/pull/2565) [#2835](https://github.com/moment/moment/pull/2835) Expose arguments used for moment creation with creationData
+  (fix [#2443](https://github.com/moment/moment/pull/2443))
+* [#2648](https://github.com/moment/moment/pull/2648) fix issue [#2640](https://github.com/moment/moment/pull/2640): support instanceof operator
+* [#2709](https://github.com/moment/moment/pull/2709) Add isSameOrAfter and isSameOrBefore comparison methods
+* [#2721](https://github.com/moment/moment/pull/2721) Fix moment creation from object with strings values
+* [#2740](https://github.com/moment/moment/pull/2740) Enable 'd hh:mm:ss.sss' format for durations
+* [#2766](https://github.com/moment/moment/pull/2766) [#2833](https://github.com/moment/moment/pull/2833) Alternate Clock Source Support
+
+### 2.10.6
+
+- Release July 28, 2015
+
+[#2515](https://github.com/moment/moment/pull/2515) Fix regression introduced
+in `2.10.5` related to `moment.ISO_8601` parsing.
+
+### 2.10.5 [See full changelog](https://gist.github.com/ichernev/6ec13ac7efc396da44b2)
+
+- Release July 26, 2015
+
+Important changes:
+* [#2357](https://github.com/moment/moment/pull/2357) Improve unit bubbling for ISO dates
+  this fixes day to year conversions to work around end-of-year (~365 days). As
+  a side effect 365 days is 11 months and 30 days, and 366 days is one year.
+* [#2438](https://github.com/moment/moment/pull/2438) Fix inconsistent moment.min and moment.max results
+  Return invalid result if any of the inputs is invalid
+* [#2494](https://github.com/moment/moment/pull/2494) Fix two digit year parsing with YYYY format
+  This brings the benefits of YY to YYYY
+* [#2368](https://github.com/moment/moment/pull/2368) perf: use faster form of copying dates, across the board improvement
+
+
+### 2.10.3 [See full changelog](https://gist.github.com/ichernev/f264b9bed5b00f8b1b7f)
+
+- Release May 13, 2015
+
+* add `moment.fn.to` and `moment.fn.toNow` (similar to `from` and `fromNow`)
+* new locales (Sinhalese (si), Montenegrin (me), Javanese (ja))
+* performance improvements
+
+### 2.10.2
+
+- Release April 9, 2015
+
+* fixed moment-with-locales in browser env caused by esperanto change
+
+### 2.10.1
+
+* regression: Add moment.duration.fn back
+
+### 2.10.0
+
+Ported code to es6 modules.
+
+### 2.9.0 [See full changelog](https://gist.github.com/ichernev/0c9a9b49951111a27ce7)
+
+- Release January 8, 2015
+
+languages:
+* [2104](https://github.com/moment/moment/issues/2104) Frisian (fy) language file with unit test
+* [2097](https://github.com/moment/moment/issues/2097) add ar-tn locale
+
+deprecations:
+* [2074](https://github.com/moment/moment/issues/2074) Implement `moment.fn.utcOffset`, deprecate `moment.fn.zone`
+
+features:
+* [2088](https://github.com/moment/moment/issues/2088) add moment.fn.isBetween
+* [2054](https://github.com/moment/moment/issues/2054) Call updateOffset when creating moment (needed for default timezone in
+  moment-timezone)
+* [1893](https://github.com/moment/moment/issues/1893) Add moment.isDate method
+* [1825](https://github.com/moment/moment/issues/1825) Implement toJSON function on Duration
+* [1809](https://github.com/moment/moment/issues/1809) Allowing moment.set() to accept a hash of units
+* [2128](https://github.com/moment/moment/issues/2128) Add firstDayOfWeek, firstDayOfYear locale getters
+* [2131](https://github.com/moment/moment/issues/2131) Add quarter diff support
+
+Some bugfixes and language improvements -- [full changelog](https://gist.github.com/ichernev/0c9a9b49951111a27ce7)
+
+### 2.8.4 [See full changelog](https://gist.github.com/ichernev/a4fcb0a46d74e4b9b996)
+
+- Release November 19, 2014
+
+Features:
+
+* [#2000](https://github.com/moment/moment/issues/2000) Add LTS localised format that includes seconds
+* [#1960](https://github.com/moment/moment/issues/1960) added formatToken 'x' for unix offset in milliseconds #1938
+* [#1965](https://github.com/moment/moment/issues/1965) Support 24:00:00.000 to mean next day, at midnight.
+* [#2002](https://github.com/moment/moment/issues/2002) Accept 'date' key when creating moment with object
+* [#2009](https://github.com/moment/moment/issues/2009) Use native toISOString when we can
+
+Some bugfixes and language improvements -- [full changelog](https://gist.github.com/ichernev/a4fcb0a46d74e4b9b996)
+
+### 2.8.3
+
+- Release September 5, 2014
+
+Bugfixes:
+
+* [#1801](https://github.com/moment/moment/issues/1801) proper pluralization for Arabic
+* [#1833](https://github.com/moment/moment/issues/1833) improve spm integration
+* [#1871](https://github.com/moment/moment/issues/1871) fix zone bug caused by Firefox 24
+* [#1882](https://github.com/moment/moment/issues/1882) Use hh:mm in Czech
+* [#1883](https://github.com/moment/moment/issues/1883) Fix 2.8.0 regression in duration as conversions
+* [#1890](https://github.com/moment/moment/issues/1890) Faster travis builds
+* [#1892](https://github.com/moment/moment/issues/1892) Faster isBefore/After/Same
+* [#1848](https://github.com/moment/moment/issues/1848) Fix flaky month diffs
+* [#1895](https://github.com/moment/moment/issues/1895) Fix 2.8.0 regression in moment.utc with format array
+* [#1896](https://github.com/moment/moment/issues/1896) Support setting invalid instance locale (noop)
+* [#1897](https://github.com/moment/moment/issues/1897) Support moment([str]) in addition to moment([int])
+
+### 2.8.2
+
+- Release August 22, 2014
+
+Minor bugfixes:
+
+* [#1874](https://github.com/moment/moment/issues/1874) use `Object.prototype.hasOwnProperty`
+  instead of `obj.hasOwnProperty` (ie8 bug)
+* [#1873](https://github.com/moment/moment/issues/1873) add `duration#toString()`
+* [#1859](https://github.com/moment/moment/issues/1859) better month/weekday names in norwegian
+* [#1812](https://github.com/moment/moment/issues/1812) meridiem parsing for greek
+* [#1804](https://github.com/moment/moment/issues/1804) spanish del -> de
+* [#1800](https://github.com/moment/moment/issues/1800) korean LT improvement
+
+### 2.8.1
+
+- Release August 1, 2014
+
+* bugfix [#1813](https://github.com/moment/moment/issues/1813): fix moment().lang([key]) incompatibility
+
+### 2.8.0 [See changelog](https://gist.github.com/ichernev/ac3899324a5fa6c8c9b4)
+
+- Release July 31, 2014
+
+* incompatible changes
+    * [#1761](https://github.com/moment/moment/issues/1761): moments created without a language are no longer following the global language, in case it changes. Only newly created moments take the global language by default. In case you're affected by this, wait, comment on [#1797](https://github.com/moment/moment/issues/1797) and wait for a proper reimplementation
+    * [#1642](https://github.com/moment/moment/issues/1642): 45 days is no longer "a month" according to humanize, cutoffs for month, and year have changed. Hopefully your code does not depend on a particular answer from humanize (which it shouldn't anyway)
+    * [#1784](https://github.com/moment/moment/issues/1784): if you use the human readable English datetime format in a weird way (like storing them in a database) that would break when the format changes you're at risk.
+
+* deprecations (old behavior will be dropped in 3.0)
+    * [#1761](https://github.com/moment/moment/issues/1761) `lang` is renamed to `locale`, `langData` -> `localeData`. Also there is now `defineLocale` that should be used when creating new locales
+    * [#1763](https://github.com/moment/moment/issues/1763) `add(unit, value)` and `subtract(unit, value)` are now deprecated. Use `add(value, unit)` and `subtract(value, unit)` instead.
+    * [#1759](https://github.com/moment/moment/issues/1759) rename `duration.toIsoString` to `duration.toISOString`. The js standard library and moment's `toISOString` follow that convention.
+
+* new locales
+    * [#1789](https://github.com/moment/moment/issues/1789) Tibetan (bo)
+    * [#1786](https://github.com/moment/moment/issues/1786) Africaans (af)
+    * [#1778](https://github.com/moment/moment/issues/1778) Burmese (my)
+    * [#1727](https://github.com/moment/moment/issues/1727) Belarusian (be)
+
+* bugfixes, locale bugfixes, performance improvements, features
+
+### 2.7.0 [See changelog](https://gist.github.com/ichernev/b0a3d456d5a84c9901d7)
+
+- Release June 12, 2014
+
+* new languages
+
+  * [#1678](https://github.com/moment/moment/issues/1678) Bengali (bn)
+  * [#1628](https://github.com/moment/moment/issues/1628) Azerbaijani (az)
+  * [#1633](https://github.com/moment/moment/issues/1633) Arabic, Saudi Arabia (ar-sa)
+  * [#1648](https://github.com/moment/moment/issues/1648) Austrian German (de-at)
+
+* features
+
+  * [#1663](https://github.com/moment/moment/issues/1663) configurable relative time thresholds
+  * [#1554](https://github.com/moment/moment/issues/1554) support anchor time in moment.calendar
+  * [#1693](https://github.com/moment/moment/issues/1693) support moment.ISO_8601 as parsing format
+  * [#1637](https://github.com/moment/moment/issues/1637) add moment.min and moment.max and deprecate min/max instance methods
+  * [#1704](https://github.com/moment/moment/issues/1704) support string value in add/subtract
+  * [#1647](https://github.com/moment/moment/issues/1647) add spm support (package manager)
+
+* bugfixes
+
+### 2.6.0 [See changelog](https://gist.github.com/ichernev/10544682)
+
+- Release April 12 , 2014
+
+* languages
+  * [#1529](https://github.com/moment/moment/issues/1529) Serbian-Cyrillic (sr-cyr)
+  * [#1544](https://github.com/moment/moment/issues/1544), [#1546](https://github.com/moment/moment/issues/1546) Khmer Cambodia (km)
+
+* features
+    * [#1419](https://github.com/moment/moment/issues/1419), [#1468](https://github.com/moment/moment/issues/1468), [#1467](https://github.com/moment/moment/issues/1467), [#1546](https://github.com/moment/moment/issues/1546) better handling of timezone-d moments around DST
+    * [#1462](https://github.com/moment/moment/issues/1462) add weeksInYear and isoWeeksInYear
+    * [#1475](https://github.com/moment/moment/issues/1475) support ordinal parsing
+    * [#1499](https://github.com/moment/moment/issues/1499) composer support
+    * [#1577](https://github.com/moment/moment/issues/1577), [#1604](https://github.com/moment/moment/issues/1604) put Date parsing in moment.createFromInputFallback so it can be properly deprecated and controlled in the future
+    * [#1545](https://github.com/moment/moment/issues/1545) extract two-digit year parsing in moment.parseTwoDigitYear, so it can be overwritten
+    * [#1590](https://github.com/moment/moment/issues/1590) (see [#1574](https://github.com/moment/moment/issues/1574)) set AMD global before module definition to better support non AMD module dependencies used in AMD environment
+    * [#1589](https://github.com/moment/moment/issues/1589) remove global in Node.JS environment (was not working before, nobody complained, was scheduled for removal anyway)
+    * [#1586](https://github.com/moment/moment/issues/1586) support quarter setting and parsing
+
+* 18 bugs fixed
+
+### 2.5.1
+
+- Release January 22, 2014
+
+* languages
+  * [#1392](https://github.com/moment/moment/issues/1392) Armenian (hy-am)
+
+* bugfixes
+  * [#1429](https://github.com/moment/moment/issues/1429) fixes [#1423](https://github.com/moment/moment/issues/1423) weird chrome-32 bug with js object creation
+  * [#1421](https://github.com/moment/moment/issues/1421) remove html entities from Welsh
+  * [#1418](https://github.com/moment/moment/issues/1418) fixes [#1401](https://github.com/moment/moment/issues/1401) improved non-padded tokens in strict matching
+  * [#1417](https://github.com/moment/moment/issues/1417) fixes [#1404](https://github.com/moment/moment/issues/1404) handle buggy moment object created by property cloning
+  * [#1398](https://github.com/moment/moment/issues/1398) fixes [#1397](https://github.com/moment/moment/issues/1397) fix Arabic-like week number parsing
+  * [#1396](https://github.com/moment/moment/issues/1396) add leftZeroFill(4) to GGGG and gggg formats
+  * [#1373](https://github.com/moment/moment/issues/1373) use lowercase for months and days in Catalan
+
+* testing
+  * [#1374](https://github.com/moment/moment/issues/1374) run tests on multiple browser/os combos via SauceLabs and Travis
+
+### 2.5.0 [See changelog](https://gist.github.com/ichernev/8104451)
+
+- Release Dec 24, 2013
+
+* New languages
+  * Luxemburish (lb) [1247](https://github.com/moment/moment/issues/1247)
+  * Serbian (rs) [1319](https://github.com/moment/moment/issues/1319)
+  * Tamil (ta) [1324](https://github.com/moment/moment/issues/1324)
+  * Macedonian (mk) [1337](https://github.com/moment/moment/issues/1337)
+
+* Features
+  * [1311](https://github.com/moment/moment/issues/1311) Add quarter getter and format token `Q`
+  * [1303](https://github.com/moment/moment/issues/1303) strict parsing now respects number of digits per token (fix [1196](https://github.com/moment/moment/issues/1196))
+  * 0d30bb7 add jspm support
+  * [1347](https://github.com/moment/moment/issues/1347) improve zone parsing
+  * [1362](https://github.com/moment/moment/issues/1362) support merideam parsing in Korean
+
+* 22 bugfixes
+
+### 2.4.0
+
+- Release Oct 27, 2013
+
+* **Deprecate** globally exported moment, will be removed in next major
+* New languages
+  * Farose (fo) [#1206](https://github.com/moment/moment/issues/1206)
+  * Tagalog/Filipino (tl-ph) [#1197](https://github.com/moment/moment/issues/1197)
+  * Welsh (cy) [#1215](https://github.com/moment/moment/issues/1215)
+* Bugfixes
+  * properly handle Z at the end of iso RegExp [#1187](https://github.com/moment/moment/issues/1187)
+  * chinese meridian time improvements [#1076](https://github.com/moment/moment/issues/1076)
+  * fix language tests [#1177](https://github.com/moment/moment/issues/1177)
+  * remove some failing tests (that should have never existed :))
+    [#1185](https://github.com/moment/moment/issues/1185)
+    [#1183](https://github.com/moment/moment/issues/1183)
+  * handle russian noun cases in weird cases [#1195](https://github.com/moment/moment/issues/1195)
+
+### 2.3.1
+
+- Release Oct 9, 2013
+
+Removed a trailing comma [1169] and fixed a bug with `months`, `weekdays` getters [#1171](https://github.com/moment/moment/issues/1171).
+
+### 2.3.0 [See changelog](https://gist.github.com/ichernev/6864354)
+
+- Release Oct 7, 2013
+
+Changed isValid, added strict parsing.
+Week tokens parsing.
+
+### 2.2.1
+
+- Release Sep 12, 2013
+
+Fixed bug in string prototype test.
+Updated authors and contributors.
+
+### 2.2.0 [See changelog](https://gist.github.com/ichernev/00f837a9baf46a3565e4)
+
+- Release  Sep 11, 2013
+
+Added bower support.
+
+Language files now use UMD.
+
+Creating moment defaults to current date/month/year.
+
+Added a bundle of moment and all language files.
+
+### 2.1.0 [See changelog](https://gist.github.com/timrwood/b8c2d90d528eddb53ab5)
+
+- Release Jul 8, 2013
+
+Added better week support.
+
+Added ability to set offset with `moment#zone`.
+
+Added ability to set month or weekday from a string.
+
+Added `moment#min` and `moment#max`
+
+### 2.0.0 [See changelog](https://gist.github.com/timrwood/e72f2eef320ed9e37c51)
+
+- Release Feb 9, 2013
+
+Added short form localized tokens.
+
+Added ability to define language a string should be parsed in.
+
+Added support for reversed add/subtract arguments.
+
+Added support for `endOf('week')` and `startOf('week')`.
+
+Fixed the logic for `moment#diff(Moment, 'months')` and `moment#diff(Moment, 'years')`
+
+`moment#diff` now floors instead of rounds.
+
+Normalized `moment#toString`.
+
+Added `isSame`, `isAfter`, and `isBefore` methods.
+
+Added better week support.
+
+Added `moment#toJSON`
+
+Bugfix: Fixed parsing of first century dates
+
+Bugfix: Parsing 10Sep2001 should work as expected
+
+Bugfix: Fixed weirdness with `moment.utc()` parsing.
+
+Changed language ordinal method to return the number + ordinal instead of just the ordinal.
+
+Changed two digit year parsing cutoff to match strptime.
+
+Removed `moment#sod` and `moment#eod` in favor of `moment#startOf` and `moment#endOf`.
+
+Removed `moment.humanizeDuration()` in favor of `moment.duration().humanize()`.
+
+Removed the lang data objects from the top level namespace.
+
+Duplicate `Date` passed to `moment()` instead of referencing it.
+
+### 1.7.2 [See discussion](https://github.com/timrwood/moment/issues/456)
+
+- Release Oct 2, 2012
+
+Bugfixes
+
+### 1.7.1 [See discussion](https://github.com/timrwood/moment/issues/384)
+
+- Release Oct 1, 2012
+
+Bugfixes
+
+### 1.7.0 [See discussion](https://github.com/timrwood/moment/issues/288)
+
+- Release Jul 26, 2012
+
+Added `moment.fn.endOf()` and `moment.fn.startOf()`.
+
+Added validation via `moment.fn.isValid()`.
+
+Made formatting method 3x faster. http://jsperf.com/momentjs-cached-format-functions
+
+Add support for month/weekday callbacks in `moment.fn.format()`
+
+Added instance specific languages.
+
+Added two letter weekday abbreviations with the formatting token `dd`.
+
+Various language updates.
+
+Various bugfixes.
+
+### 1.6.0 [See discussion](https://github.com/timrwood/moment/pull/268)
+
+- Release Apr 26, 2012
+
+Added Durations.
+
+Revamped parser to support parsing non-separated strings (YYYYMMDD vs YYYY-MM-DD).
+
+Added support for millisecond parsing and formatting tokens (S SS SSS)
+
+Added a getter for `moment.lang()`
+
+Various bugfixes.
+
+There are a few things deprecated in the 1.6.0 release.
+
+1. The format tokens `z` and `zz` (timezone abbreviations like EST CST MST etc) will no longer be supported. Due to inconsistent browser support, we are unable to consistently produce this value. See [this issue](https://github.com/timrwood/moment/issues/162) for more background.
+
+2. The method `moment.fn.native` is deprecated in favor of `moment.fn.toDate`. There continue to be issues with Google Closure Compiler throwing errors when using `native`, even in valid instances.
+
+3. The way to customize am/pm strings is being changed. This would only affect you if you created a custom language file. For more information, see [this issue](https://github.com/timrwood/moment/pull/222).
+
+### 1.5.0 [See milestone](https://github.com/timrwood/moment/issues?milestone=10&page=1&state=closed)
+
+- Release Mar 20, 2012
+
+Added UTC mode.
+
+Added automatic ISO8601 parsing.
+
+Various bugfixes.
+
+### 1.4.0 [See milestone](https://github.com/timrwood/moment/issues?milestone=8&state=closed)
+
+- Release Feb 4, 2012
+
+Added `moment.fn.toDate` as a replacement for `moment.fn.native`.
+
+Added `moment.fn.sod` and `moment.fn.eod` to get the start and end of day.
+
+Various bugfixes.
+
+### 1.3.0 [See milestone](https://github.com/timrwood/moment/issues?milestone=7&state=closed)
+
+- Release Jan 5, 2012
+
+Added support for parsing month names in the current language.
+
+Added escape blocks for parsing tokens.
+
+Added `moment.fn.calendar` to format strings like 'Today 2:30 PM', 'Tomorrow 1:25 AM', and 'Last Sunday 4:30 AM'.
+
+Added `moment.fn.day` as a setter.
+
+Various bugfixes
+
+### 1.2.0 [See milestone](https://github.com/timrwood/moment/issues?milestone=4&state=closed)
+
+- Release Dec 7, 2011
+
+Added timezones to parser and formatter.
+
+Added `moment.fn.isDST`.
+
+Added `moment.fn.zone` to get the timezone offset in minutes.
+
+### 1.1.2 [See milestone](https://github.com/timrwood/moment/issues?milestone=6&state=closed)
+
+- Release Nov 18, 2011
+
+Various bugfixes
+
+### 1.1.1 [See milestone](https://github.com/timrwood/moment/issues?milestone=5&state=closed)
+
+- Release Nov 12, 2011
+
+Added time specific diffs (months, days, hours, etc)
+
+### 1.1.0
+
+- Release Oct 28, 2011
+
+Added `moment.fn.format` localized masks. 'L LL LLL LLLL' [issue 29](https://github.com/timrwood/moment/pull/29)
+
+Fixed [issue 31](https://github.com/timrwood/moment/pull/31).
+
+### 1.0.1
+
+- Release Oct 18, 2011
+
+Added `moment.version` to get the current version.
+
+Removed `window !== undefined` when checking if module exists to support browserify. [issue 25](https://github.com/timrwood/moment/pull/25)
+
+### 1.0.0
+
+- Release
+
+Added convenience methods for getting and setting date parts.
+
+Added better support for `moment.add()`.
+
+Added better lang support in NodeJS.
+
+Renamed library from underscore.date to Moment.js
+
+### 0.6.1
+
+- Release Oct 12, 2011
+
+Added Portuguese, Italian, and French language support
+
+### 0.6.0
+
+- Release Sep 21, 2011
+
+Added _date.lang() support.
+Added support for passing multiple formats to try to parse a date. _date("07-10-1986", ["MM-DD-YYYY", "YYYY-MM-DD"]);
+Made parse from string and single format 25% faster.
+
+### 0.5.2
+
+- Release Jul 11, 2011
+
+Bugfix for [issue 8](https://github.com/timrwood/underscore.date/pull/8) and [issue 9](https://github.com/timrwood/underscore.date/pull/9).
+
+### 0.5.1
+
+- Release Jun 17, 2011
+
+Bugfix for [issue 5](https://github.com/timrwood/underscore.date/pull/5).
+
+### 0.5.0
+
+- Release Jun 13, 2011
+
+Dropped the redundant `_date.date()` in favor of `_date()`.
+Removed `_date.now()`, as it is a duplicate of `_date()` with no parameters.
+Removed `_date.isLeapYear(yearNumber)`. Use `_date([yearNumber]).isLeapYear()` instead.
+Exposed customization options through the `_date.relativeTime`, `_date.weekdays`, `_date.weekdaysShort`, `_date.months`, `_date.monthsShort`, and `_date.ordinal` variables instead of the `_date.customize()` function.
+
+### 0.4.1
+
+- Release May 9, 2011
+
+Added date input formats for input strings.
+
+### 0.4.0
+
+- Release May 9, 2011
+
+Added underscore.date to npm. Removed dependencies on underscore.
+
+### 0.3.2
+
+- Release Apr 9, 2011
+
+Added `'z'` and `'zz'` to `_.date().format()`. Cleaned up some redundant code to trim off some bytes.
+
+### 0.3.1
+
+- Release Mar 25, 2011
+
+Cleaned up the namespace. Moved all date manipulation and display functions to the _.date() object.
+
+### 0.3.0
+
+- Release Mar 25, 2011
+
+Switched to the Underscore methodology of not mucking with the native objects' prototypes.
+Made chaining possible.
+
+### 0.2.1
+
+- Release
+
+Changed date names to be a more pseudo standardized 'dddd, MMMM Do YYYY, h:mm:ss a'.
+Added `Date.prototype` functions `add`, `subtract`, `isdst`, and `isleapyear`.
+
+### 0.2.0
+
+- Release
+
+Changed function names to be more concise.
+Changed date format from php date format to custom format.
+
+### 0.1.0
+
+- Release
+
+Initial release
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/LICENSE b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..8618b7333d6f520594c2f7b7c3c884e766f3e782
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) JS Foundation and other contributors
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/README.md b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..c45e9d62450246e7cfc0153b297e95e5f2ab54ba
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/README.md
@@ -0,0 +1,58 @@
+[![Join the chat at https://gitter.im/moment/moment](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/moment/moment?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+
+[![NPM version][npm-version-image]][npm-url] [![NPM downloads][npm-downloads-image]][npm-url] [![MIT License][license-image]][license-url] [![Build Status][travis-image]][travis-url]
+[![Coverage Status](https://coveralls.io/repos/moment/moment/badge.svg?branch=develop)](https://coveralls.io/r/moment/moment?branch=develop)
+
+A lightweight JavaScript date library for parsing, validating, manipulating, and formatting dates.
+
+**[Documentation](http://momentjs.com/docs/)**
+
+## Port to ECMAScript 6 (version 2.10.0)
+
+Moment 2.10.0 does not bring any new features, but the code is now written in
+ECMAScript 6 modules and placed inside `src/`. Previously `moment.js`, `locale/*.js` and
+`test/moment/*.js`, `test/locale/*.js` contained the source of the project. Now
+the source is in `src/`, temporary build (ECMAScript 5) files are placed under
+`build/umd/` (for running tests during development), and the `moment.js` and
+`locale/*.js` files are updated only on release.
+
+If you want to use a particular revision of the code, make sure to run
+`grunt transpile update-index`, so `moment.js` and `locales/*.js` are synced
+with `src/*`. We might place that in a commit hook in the future.
+
+## Upgrading to 2.0.0
+
+There are a number of small backwards incompatible changes with version 2.0.0. [See the full descriptions here](https://gist.github.com/timrwood/e72f2eef320ed9e37c51#backwards-incompatible-changes)
+
+ * Changed language ordinal method to return the number + ordinal instead of just the ordinal.
+
+ * Changed two digit year parsing cutoff to match strptime.
+
+ * Removed `moment#sod` and `moment#eod` in favor of `moment#startOf` and `moment#endOf`.
+
+ * Removed `moment.humanizeDuration()` in favor of `moment.duration().humanize()`.
+
+ * Removed the lang data objects from the top level namespace.
+
+ * Duplicate `Date` passed to `moment()` instead of referencing it.
+
+## [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md)
+
+## [Contributing](https://github.com/moment/moment/blob/develop/CONTRIBUTING.md)
+
+We're looking for co-maintainers! If you want to become a master of time please
+write to [ichernev](https://github.com/ichernev).
+
+## License
+
+Moment.js is freely distributable under the terms of the [MIT license](https://github.com/moment/moment/blob/develop/LICENSE).
+
+[license-image]: http://img.shields.io/badge/license-MIT-blue.svg?style=flat
+[license-url]: LICENSE
+
+[npm-url]: https://npmjs.org/package/moment
+[npm-version-image]: http://img.shields.io/npm/v/moment.svg?style=flat
+[npm-downloads-image]: http://img.shields.io/npm/dm/moment.svg?style=flat
+
+[travis-url]: http://travis-ci.org/moment/moment
+[travis-image]: http://img.shields.io/travis/moment/moment/develop.svg?style=flat
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/ender.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/ender.js
new file mode 100644
index 0000000000000000000000000000000000000000..71462a7708086e22078a431b17fce210257ef6b1
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/ender.js
@@ -0,0 +1 @@
+$.ender({ moment: require('moment') })
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/af.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/af.js
new file mode 100644
index 0000000000000000000000000000000000000000..08bb705022fd927e7bfe57d4beb2325ecaa4cb9b
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/af.js
@@ -0,0 +1,73 @@
+//! moment.js locale configuration
+//! locale : Afrikaans [af]
+//! author : Werner Mollentze : https://github.com/wernerm
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var af = moment.defineLocale('af', {
+    months : 'Januarie_Februarie_Maart_April_Mei_Junie_Julie_Augustus_September_Oktober_November_Desember'.split('_'),
+    monthsShort : 'Jan_Feb_Mrt_Apr_Mei_Jun_Jul_Aug_Sep_Okt_Nov_Des'.split('_'),
+    weekdays : 'Sondag_Maandag_Dinsdag_Woensdag_Donderdag_Vrydag_Saterdag'.split('_'),
+    weekdaysShort : 'Son_Maa_Din_Woe_Don_Vry_Sat'.split('_'),
+    weekdaysMin : 'So_Ma_Di_Wo_Do_Vr_Sa'.split('_'),
+    meridiemParse: /vm|nm/i,
+    isPM : function (input) {
+        return /^nm$/i.test(input);
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 12) {
+            return isLower ? 'vm' : 'VM';
+        } else {
+            return isLower ? 'nm' : 'NM';
+        }
+    },
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[Vandag om] LT',
+        nextDay : '[Môre om] LT',
+        nextWeek : 'dddd [om] LT',
+        lastDay : '[Gister om] LT',
+        lastWeek : '[Laas] dddd [om] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'oor %s',
+        past : '%s gelede',
+        s : '\'n paar sekondes',
+        m : '\'n minuut',
+        mm : '%d minute',
+        h : '\'n uur',
+        hh : '%d ure',
+        d : '\'n dag',
+        dd : '%d dae',
+        M : '\'n maand',
+        MM : '%d maande',
+        y : '\'n jaar',
+        yy : '%d jaar'
+    },
+    ordinalParse: /\d{1,2}(ste|de)/,
+    ordinal : function (number) {
+        return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de'); // Thanks to Joris Röling : https://github.com/jjupiter
+    },
+    week : {
+        dow : 1, // Maandag is die eerste dag van die week.
+        doy : 4  // Die week wat die 4de Januarie bevat is die eerste week van die jaar.
+    }
+});
+
+return af;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ar-dz.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ar-dz.js
new file mode 100644
index 0000000000000000000000000000000000000000..f39459446354671a6a6c173ed7aaeaeed52bf78a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ar-dz.js
@@ -0,0 +1,59 @@
+//! moment.js locale configuration
+//! locale : Arabic (Algeria) [ar-dz]
+//! author : Noureddine LOUAHEDJ : https://github.com/noureddineme
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var arDz = moment.defineLocale('ar-dz', {
+    months : 'جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
+    monthsShort : 'جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
+    weekdays : 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
+    weekdaysShort : 'احد_اثنين_ثلاثاء_اربعاء_خميس_جمعة_سبت'.split('_'),
+    weekdaysMin : 'أح_إث_ثلا_أر_خم_جم_سب'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[اليوم على الساعة] LT',
+        nextDay: '[غدا على الساعة] LT',
+        nextWeek: 'dddd [على الساعة] LT',
+        lastDay: '[أمس على الساعة] LT',
+        lastWeek: 'dddd [على الساعة] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'في %s',
+        past : 'منذ %s',
+        s : 'ثوان',
+        m : 'دقيقة',
+        mm : '%d دقائق',
+        h : 'ساعة',
+        hh : '%d ساعات',
+        d : 'يوم',
+        dd : '%d أيام',
+        M : 'شهر',
+        MM : '%d أشهر',
+        y : 'سنة',
+        yy : '%d سنوات'
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 4  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return arDz;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ar-ly.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ar-ly.js
new file mode 100644
index 0000000000000000000000000000000000000000..7180ed4ed8f3951e5806344c6dd880c006da923d
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ar-ly.js
@@ -0,0 +1,126 @@
+//! moment.js locale configuration
+//! locale : Arabic (Lybia) [ar-ly]
+//! author : Ali Hmer: https://github.com/kikoanis
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var symbolMap = {
+    '1': '1',
+    '2': '2',
+    '3': '3',
+    '4': '4',
+    '5': '5',
+    '6': '6',
+    '7': '7',
+    '8': '8',
+    '9': '9',
+    '0': '0'
+};
+var pluralForm = function (n) {
+    return n === 0 ? 0 : n === 1 ? 1 : n === 2 ? 2 : n % 100 >= 3 && n % 100 <= 10 ? 3 : n % 100 >= 11 ? 4 : 5;
+};
+var plurals = {
+    s : ['أقل من ثانية', 'ثانية واحدة', ['ثانيتان', 'ثانيتين'], '%d ثوان', '%d ثانية', '%d ثانية'],
+    m : ['أقل من دقيقة', 'دقيقة واحدة', ['دقيقتان', 'دقيقتين'], '%d دقائق', '%d دقيقة', '%d دقيقة'],
+    h : ['أقل من ساعة', 'ساعة واحدة', ['ساعتان', 'ساعتين'], '%d ساعات', '%d ساعة', '%d ساعة'],
+    d : ['أقل من يوم', 'يوم واحد', ['يومان', 'يومين'], '%d أيام', '%d يومًا', '%d يوم'],
+    M : ['أقل من شهر', 'شهر واحد', ['شهران', 'شهرين'], '%d أشهر', '%d شهرا', '%d شهر'],
+    y : ['أقل من عام', 'عام واحد', ['عامان', 'عامين'], '%d أعوام', '%d عامًا', '%d عام']
+};
+var pluralize = function (u) {
+    return function (number, withoutSuffix, string, isFuture) {
+        var f = pluralForm(number),
+            str = plurals[u][pluralForm(number)];
+        if (f === 2) {
+            str = str[withoutSuffix ? 0 : 1];
+        }
+        return str.replace(/%d/i, number);
+    };
+};
+var months = [
+    'يناير',
+    'فبراير',
+    'مارس',
+    'أبريل',
+    'مايو',
+    'يونيو',
+    'يوليو',
+    'أغسطس',
+    'سبتمبر',
+    'أكتوبر',
+    'نوفمبر',
+    'ديسمبر'
+];
+
+var arLy = moment.defineLocale('ar-ly', {
+    months : months,
+    monthsShort : months,
+    weekdays : 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
+    weekdaysShort : 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'),
+    weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'D/\u200FM/\u200FYYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    meridiemParse: /ص|م/,
+    isPM : function (input) {
+        return 'Ù…' === input;
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return 'ص';
+        } else {
+            return 'Ù…';
+        }
+    },
+    calendar : {
+        sameDay: '[اليوم عند الساعة] LT',
+        nextDay: '[غدًا عند الساعة] LT',
+        nextWeek: 'dddd [عند الساعة] LT',
+        lastDay: '[أمس عند الساعة] LT',
+        lastWeek: 'dddd [عند الساعة] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'بعد %s',
+        past : 'منذ %s',
+        s : pluralize('s'),
+        m : pluralize('m'),
+        mm : pluralize('m'),
+        h : pluralize('h'),
+        hh : pluralize('h'),
+        d : pluralize('d'),
+        dd : pluralize('d'),
+        M : pluralize('M'),
+        MM : pluralize('M'),
+        y : pluralize('y'),
+        yy : pluralize('y')
+    },
+    preparse: function (string) {
+        return string.replace(/\u200f/g, '').replace(/،/g, ',');
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap[match];
+        }).replace(/,/g, '،');
+    },
+    week : {
+        dow : 6, // Saturday is the first day of the week.
+        doy : 12  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return arLy;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ar-ma.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ar-ma.js
new file mode 100644
index 0000000000000000000000000000000000000000..cbd810ba79b5f68b81c960d4935a12991852ea96
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ar-ma.js
@@ -0,0 +1,60 @@
+//! moment.js locale configuration
+//! locale : Arabic (Morocco) [ar-ma]
+//! author : ElFadili Yassine : https://github.com/ElFadiliY
+//! author : Abdel Said : https://github.com/abdelsaid
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var arMa = moment.defineLocale('ar-ma', {
+    months : 'يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر'.split('_'),
+    monthsShort : 'يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر'.split('_'),
+    weekdays : 'الأحد_الإتنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
+    weekdaysShort : 'احد_اتنين_ثلاثاء_اربعاء_خميس_جمعة_سبت'.split('_'),
+    weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[اليوم على الساعة] LT',
+        nextDay: '[غدا على الساعة] LT',
+        nextWeek: 'dddd [على الساعة] LT',
+        lastDay: '[أمس على الساعة] LT',
+        lastWeek: 'dddd [على الساعة] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'في %s',
+        past : 'منذ %s',
+        s : 'ثوان',
+        m : 'دقيقة',
+        mm : '%d دقائق',
+        h : 'ساعة',
+        hh : '%d ساعات',
+        d : 'يوم',
+        dd : '%d أيام',
+        M : 'شهر',
+        MM : '%d أشهر',
+        y : 'سنة',
+        yy : '%d سنوات'
+    },
+    week : {
+        dow : 6, // Saturday is the first day of the week.
+        doy : 12  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return arMa;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ar-sa.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ar-sa.js
new file mode 100644
index 0000000000000000000000000000000000000000..dccd0d83309bb914af1fa9d7818e2e5d58f0ef4c
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ar-sa.js
@@ -0,0 +1,105 @@
+//! moment.js locale configuration
+//! locale : Arabic (Saudi Arabia) [ar-sa]
+//! author : Suhail Alkowaileet : https://github.com/xsoh
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var symbolMap = {
+    '1': 'Ù¡',
+    '2': 'Ù¢',
+    '3': 'Ù£',
+    '4': 'Ù¤',
+    '5': 'Ù¥',
+    '6': 'Ù¦',
+    '7': 'Ù§',
+    '8': 'Ù¨',
+    '9': 'Ù©',
+    '0': 'Ù '
+};
+var numberMap = {
+    'Ù¡': '1',
+    'Ù¢': '2',
+    'Ù£': '3',
+    'Ù¤': '4',
+    'Ù¥': '5',
+    'Ù¦': '6',
+    'Ù§': '7',
+    'Ù¨': '8',
+    'Ù©': '9',
+    'Ù ': '0'
+};
+
+var arSa = moment.defineLocale('ar-sa', {
+    months : 'يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
+    monthsShort : 'يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
+    weekdays : 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
+    weekdaysShort : 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'),
+    weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    meridiemParse: /ص|م/,
+    isPM : function (input) {
+        return 'Ù…' === input;
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return 'ص';
+        } else {
+            return 'Ù…';
+        }
+    },
+    calendar : {
+        sameDay: '[اليوم على الساعة] LT',
+        nextDay: '[غدا على الساعة] LT',
+        nextWeek: 'dddd [على الساعة] LT',
+        lastDay: '[أمس على الساعة] LT',
+        lastWeek: 'dddd [على الساعة] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'في %s',
+        past : 'منذ %s',
+        s : 'ثوان',
+        m : 'دقيقة',
+        mm : '%d دقائق',
+        h : 'ساعة',
+        hh : '%d ساعات',
+        d : 'يوم',
+        dd : '%d أيام',
+        M : 'شهر',
+        MM : '%d أشهر',
+        y : 'سنة',
+        yy : '%d سنوات'
+    },
+    preparse: function (string) {
+        return string.replace(/[١٢٣٤٥٦٧٨٩٠]/g, function (match) {
+            return numberMap[match];
+        }).replace(/،/g, ',');
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap[match];
+        }).replace(/,/g, '،');
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return arSa;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ar-tn.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ar-tn.js
new file mode 100644
index 0000000000000000000000000000000000000000..5f0d38bb06e9d1add877e7d795593d203a0e2111
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ar-tn.js
@@ -0,0 +1,59 @@
+//! moment.js locale configuration
+//! locale  :  Arabic (Tunisia) [ar-tn]
+//! author : Nader Toukabri : https://github.com/naderio
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var arTn = moment.defineLocale('ar-tn', {
+    months: 'جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
+    monthsShort: 'جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
+    weekdays: 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
+    weekdaysShort: 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'),
+    weekdaysMin: 'ح_ن_ث_ر_خ_ج_س'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat: {
+        LT: 'HH:mm',
+        LTS: 'HH:mm:ss',
+        L: 'DD/MM/YYYY',
+        LL: 'D MMMM YYYY',
+        LLL: 'D MMMM YYYY HH:mm',
+        LLLL: 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar: {
+        sameDay: '[اليوم على الساعة] LT',
+        nextDay: '[غدا على الساعة] LT',
+        nextWeek: 'dddd [على الساعة] LT',
+        lastDay: '[أمس على الساعة] LT',
+        lastWeek: 'dddd [على الساعة] LT',
+        sameElse: 'L'
+    },
+    relativeTime: {
+        future: 'في %s',
+        past: 'منذ %s',
+        s: 'ثوان',
+        m: 'دقيقة',
+        mm: '%d دقائق',
+        h: 'ساعة',
+        hh: '%d ساعات',
+        d: 'يوم',
+        dd: '%d أيام',
+        M: 'شهر',
+        MM: '%d أشهر',
+        y: 'سنة',
+        yy: '%d سنوات'
+    },
+    week: {
+        dow: 1, // Monday is the first day of the week.
+        doy: 4 // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return arTn;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ar.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ar.js
new file mode 100644
index 0000000000000000000000000000000000000000..d263e4c4f8d3c5cf1aa178d5a58d15290c1ac8f7
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ar.js
@@ -0,0 +1,142 @@
+//! moment.js locale configuration
+//! locale : Arabic [ar]
+//! author : Abdel Said: https://github.com/abdelsaid
+//! author : Ahmed Elkhatib
+//! author : forabi https://github.com/forabi
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var symbolMap = {
+    '1': 'Ù¡',
+    '2': 'Ù¢',
+    '3': 'Ù£',
+    '4': 'Ù¤',
+    '5': 'Ù¥',
+    '6': 'Ù¦',
+    '7': 'Ù§',
+    '8': 'Ù¨',
+    '9': 'Ù©',
+    '0': 'Ù '
+};
+var numberMap = {
+    'Ù¡': '1',
+    'Ù¢': '2',
+    'Ù£': '3',
+    'Ù¤': '4',
+    'Ù¥': '5',
+    'Ù¦': '6',
+    'Ù§': '7',
+    'Ù¨': '8',
+    'Ù©': '9',
+    'Ù ': '0'
+};
+var pluralForm = function (n) {
+    return n === 0 ? 0 : n === 1 ? 1 : n === 2 ? 2 : n % 100 >= 3 && n % 100 <= 10 ? 3 : n % 100 >= 11 ? 4 : 5;
+};
+var plurals = {
+    s : ['أقل من ثانية', 'ثانية واحدة', ['ثانيتان', 'ثانيتين'], '%d ثوان', '%d ثانية', '%d ثانية'],
+    m : ['أقل من دقيقة', 'دقيقة واحدة', ['دقيقتان', 'دقيقتين'], '%d دقائق', '%d دقيقة', '%d دقيقة'],
+    h : ['أقل من ساعة', 'ساعة واحدة', ['ساعتان', 'ساعتين'], '%d ساعات', '%d ساعة', '%d ساعة'],
+    d : ['أقل من يوم', 'يوم واحد', ['يومان', 'يومين'], '%d أيام', '%d يومًا', '%d يوم'],
+    M : ['أقل من شهر', 'شهر واحد', ['شهران', 'شهرين'], '%d أشهر', '%d شهرا', '%d شهر'],
+    y : ['أقل من عام', 'عام واحد', ['عامان', 'عامين'], '%d أعوام', '%d عامًا', '%d عام']
+};
+var pluralize = function (u) {
+    return function (number, withoutSuffix, string, isFuture) {
+        var f = pluralForm(number),
+            str = plurals[u][pluralForm(number)];
+        if (f === 2) {
+            str = str[withoutSuffix ? 0 : 1];
+        }
+        return str.replace(/%d/i, number);
+    };
+};
+var months = [
+    'كانون الثاني يناير',
+    'شباط فبراير',
+    'آذار مارس',
+    'نيسان أبريل',
+    'أيار مايو',
+    'حزيران يونيو',
+    'تموز يوليو',
+    'آب أغسطس',
+    'أيلول سبتمبر',
+    'تشرين الأول أكتوبر',
+    'تشرين الثاني نوفمبر',
+    'كانون الأول ديسمبر'
+];
+
+var ar = moment.defineLocale('ar', {
+    months : months,
+    monthsShort : months,
+    weekdays : 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
+    weekdaysShort : 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'),
+    weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'D/\u200FM/\u200FYYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    meridiemParse: /ص|م/,
+    isPM : function (input) {
+        return 'Ù…' === input;
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return 'ص';
+        } else {
+            return 'Ù…';
+        }
+    },
+    calendar : {
+        sameDay: '[اليوم عند الساعة] LT',
+        nextDay: '[غدًا عند الساعة] LT',
+        nextWeek: 'dddd [عند الساعة] LT',
+        lastDay: '[أمس عند الساعة] LT',
+        lastWeek: 'dddd [عند الساعة] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'بعد %s',
+        past : 'منذ %s',
+        s : pluralize('s'),
+        m : pluralize('m'),
+        mm : pluralize('m'),
+        h : pluralize('h'),
+        hh : pluralize('h'),
+        d : pluralize('d'),
+        dd : pluralize('d'),
+        M : pluralize('M'),
+        MM : pluralize('M'),
+        y : pluralize('y'),
+        yy : pluralize('y')
+    },
+    preparse: function (string) {
+        return string.replace(/\u200f/g, '').replace(/[١٢٣٤٥٦٧٨٩٠]/g, function (match) {
+            return numberMap[match];
+        }).replace(/،/g, ',');
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap[match];
+        }).replace(/,/g, '،');
+    },
+    week : {
+        dow : 6, // Saturday is the first day of the week.
+        doy : 12  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return ar;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/az.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/az.js
new file mode 100644
index 0000000000000000000000000000000000000000..054cb4724276a453f7d3687424bd5e7c8dab39bd
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/az.js
@@ -0,0 +1,105 @@
+//! moment.js locale configuration
+//! locale : Azerbaijani [az]
+//! author : topchiyev : https://github.com/topchiyev
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var suffixes = {
+    1: '-inci',
+    5: '-inci',
+    8: '-inci',
+    70: '-inci',
+    80: '-inci',
+    2: '-nci',
+    7: '-nci',
+    20: '-nci',
+    50: '-nci',
+    3: '-üncü',
+    4: '-üncü',
+    100: '-üncü',
+    6: '-ncı',
+    9: '-uncu',
+    10: '-uncu',
+    30: '-uncu',
+    60: '-ıncı',
+    90: '-ıncı'
+};
+
+var az = moment.defineLocale('az', {
+    months : 'yanvar_fevral_mart_aprel_may_iyun_iyul_avqust_sentyabr_oktyabr_noyabr_dekabr'.split('_'),
+    monthsShort : 'yan_fev_mar_apr_may_iyn_iyl_avq_sen_okt_noy_dek'.split('_'),
+    weekdays : 'Bazar_Bazar ertəsi_Çərşənbə axşamı_Çərşənbə_Cümə axşamı_Cümə_Şənbə'.split('_'),
+    weekdaysShort : 'Baz_BzE_ÇAx_Çər_CAx_Cüm_Şən'.split('_'),
+    weekdaysMin : 'Bz_BE_ÇA_Çə_CA_Cü_Şə'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[bugün saat] LT',
+        nextDay : '[sabah saat] LT',
+        nextWeek : '[gələn həftə] dddd [saat] LT',
+        lastDay : '[dünən] LT',
+        lastWeek : '[keçən həftə] dddd [saat] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s sonra',
+        past : '%s əvvəl',
+        s : 'birneçə saniyyə',
+        m : 'bir dəqiqə',
+        mm : '%d dəqiqə',
+        h : 'bir saat',
+        hh : '%d saat',
+        d : 'bir gün',
+        dd : '%d gün',
+        M : 'bir ay',
+        MM : '%d ay',
+        y : 'bir il',
+        yy : '%d il'
+    },
+    meridiemParse: /gecə|səhər|gündüz|axşam/,
+    isPM : function (input) {
+        return /^(gündüz|axşam)$/.test(input);
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'gecÉ™';
+        } else if (hour < 12) {
+            return 'səhər';
+        } else if (hour < 17) {
+            return 'gündüz';
+        } else {
+            return 'axÅŸam';
+        }
+    },
+    ordinalParse: /\d{1,2}-(ıncı|inci|nci|üncü|ncı|uncu)/,
+    ordinal : function (number) {
+        if (number === 0) {  // special case for zero
+            return number + '-ıncı';
+        }
+        var a = number % 10,
+            b = number % 100 - a,
+            c = number >= 100 ? 100 : null;
+        return number + (suffixes[a] || suffixes[b] || suffixes[c]);
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return az;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/be.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/be.js
new file mode 100644
index 0000000000000000000000000000000000000000..e8c269f5f8fb98b0f819e182054bb978aa0ed3a0
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/be.js
@@ -0,0 +1,134 @@
+//! moment.js locale configuration
+//! locale : Belarusian [be]
+//! author : Dmitry Demidov : https://github.com/demidov91
+//! author: Praleska: http://praleska.pro/
+//! Author : Menelion Elensúle : https://github.com/Oire
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+function plural(word, num) {
+    var forms = word.split('_');
+    return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]);
+}
+function relativeTimeWithPlural(number, withoutSuffix, key) {
+    var format = {
+        'mm': withoutSuffix ? 'хвіліна_хвіліны_хвілін' : 'хвіліну_хвіліны_хвілін',
+        'hh': withoutSuffix ? 'гадзіна_гадзіны_гадзін' : 'гадзіну_гадзіны_гадзін',
+        'dd': 'дзень_дні_дзён',
+        'MM': 'месяц_месяцы_месяцаў',
+        'yy': 'год_гады_гадоў'
+    };
+    if (key === 'm') {
+        return withoutSuffix ? 'хвіліна' : 'хвіліну';
+    }
+    else if (key === 'h') {
+        return withoutSuffix ? 'гадзіна' : 'гадзіну';
+    }
+    else {
+        return number + ' ' + plural(format[key], +number);
+    }
+}
+
+var be = moment.defineLocale('be', {
+    months : {
+        format: 'студзеня_лютага_сакавіка_красавіка_траўня_чэрвеня_ліпеня_жніўня_верасня_кастрычніка_лістапада_снежня'.split('_'),
+        standalone: 'студзень_люты_сакавік_красавік_травень_чэрвень_ліпень_жнівень_верасень_кастрычнік_лістапад_снежань'.split('_')
+    },
+    monthsShort : 'студ_лют_сак_крас_трав_чэрв_ліп_жнів_вер_каст_ліст_снеж'.split('_'),
+    weekdays : {
+        format: 'нядзелю_панядзелак_аўторак_сераду_чацвер_пятніцу_суботу'.split('_'),
+        standalone: 'нядзеля_панядзелак_аўторак_серада_чацвер_пятніца_субота'.split('_'),
+        isFormat: /\[ ?[Вв] ?(?:мінулую|наступную)? ?\] ?dddd/
+    },
+    weekdaysShort : 'нд_пн_ат_ср_чц_пт_сб'.split('_'),
+    weekdaysMin : 'нд_пн_ат_ср_чц_пт_сб'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY г.',
+        LLL : 'D MMMM YYYY г., HH:mm',
+        LLLL : 'dddd, D MMMM YYYY г., HH:mm'
+    },
+    calendar : {
+        sameDay: '[Сёння ў] LT',
+        nextDay: '[Заўтра ў] LT',
+        lastDay: '[Учора ў] LT',
+        nextWeek: function () {
+            return '[У] dddd [ў] LT';
+        },
+        lastWeek: function () {
+            switch (this.day()) {
+                case 0:
+                case 3:
+                case 5:
+                case 6:
+                    return '[У мінулую] dddd [ў] LT';
+                case 1:
+                case 2:
+                case 4:
+                    return '[У мінулы] dddd [ў] LT';
+            }
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'праз %s',
+        past : '%s таму',
+        s : 'некалькі секунд',
+        m : relativeTimeWithPlural,
+        mm : relativeTimeWithPlural,
+        h : relativeTimeWithPlural,
+        hh : relativeTimeWithPlural,
+        d : 'дзень',
+        dd : relativeTimeWithPlural,
+        M : 'месяц',
+        MM : relativeTimeWithPlural,
+        y : 'год',
+        yy : relativeTimeWithPlural
+    },
+    meridiemParse: /ночы|раніцы|дня|вечара/,
+    isPM : function (input) {
+        return /^(дня|вечара)$/.test(input);
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'ночы';
+        } else if (hour < 12) {
+            return 'раніцы';
+        } else if (hour < 17) {
+            return 'дня';
+        } else {
+            return 'вечара';
+        }
+    },
+    ordinalParse: /\d{1,2}-(і|ы|га)/,
+    ordinal: function (number, period) {
+        switch (period) {
+            case 'M':
+            case 'd':
+            case 'DDD':
+            case 'w':
+            case 'W':
+                return (number % 10 === 2 || number % 10 === 3) && (number % 100 !== 12 && number % 100 !== 13) ? number + '-Ñ–' : number + '-Ñ‹';
+            case 'D':
+                return number + '-га';
+            default:
+                return number;
+        }
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return be;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/bg-x.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/bg-x.js
new file mode 100644
index 0000000000000000000000000000000000000000..e91a4f80dcb3a78dd63dad3004cd124bbcc6751b
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/bg-x.js
@@ -0,0 +1,15 @@
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+var bgX = moment.defineLocale('bg-x', {
+    parentLocale: 'bg'
+});
+
+return bgX;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/bg.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/bg.js
new file mode 100644
index 0000000000000000000000000000000000000000..663f5be81320150ce2decfb96ee07a07902d1e49
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/bg.js
@@ -0,0 +1,90 @@
+//! moment.js locale configuration
+//! locale : Bulgarian [bg]
+//! author : Krasen Borisov : https://github.com/kraz
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var bg = moment.defineLocale('bg', {
+    months : 'януари_февруари_март_април_май_юни_юли_август_септември_октомври_ноември_декември'.split('_'),
+    monthsShort : 'янр_фев_мар_апр_май_юни_юли_авг_сеп_окт_ное_дек'.split('_'),
+    weekdays : 'неделя_понеделник_вторник_сряда_четвъртък_петък_събота'.split('_'),
+    weekdaysShort : 'нед_пон_вто_сря_чет_пет_съб'.split('_'),
+    weekdaysMin : 'нд_пн_вт_ср_чт_пт_сб'.split('_'),
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'D.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY H:mm',
+        LLLL : 'dddd, D MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay : '[Днес в] LT',
+        nextDay : '[Утре в] LT',
+        nextWeek : 'dddd [в] LT',
+        lastDay : '[Вчера в] LT',
+        lastWeek : function () {
+            switch (this.day()) {
+                case 0:
+                case 3:
+                case 6:
+                    return '[В изминалата] dddd [в] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[В изминалия] dddd [в] LT';
+            }
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'след %s',
+        past : 'преди %s',
+        s : 'няколко секунди',
+        m : 'минута',
+        mm : '%d минути',
+        h : 'час',
+        hh : '%d часа',
+        d : 'ден',
+        dd : '%d дни',
+        M : 'месец',
+        MM : '%d месеца',
+        y : 'година',
+        yy : '%d години'
+    },
+    ordinalParse: /\d{1,2}-(ев|ен|ти|ви|ри|ми)/,
+    ordinal : function (number) {
+        var lastDigit = number % 10,
+            last2Digits = number % 100;
+        if (number === 0) {
+            return number + '-ев';
+        } else if (last2Digits === 0) {
+            return number + '-ен';
+        } else if (last2Digits > 10 && last2Digits < 20) {
+            return number + '-ти';
+        } else if (lastDigit === 1) {
+            return number + '-ви';
+        } else if (lastDigit === 2) {
+            return number + '-ри';
+        } else if (lastDigit === 7 || lastDigit === 8) {
+            return number + '-ми';
+        } else {
+            return number + '-ти';
+        }
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return bg;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/bn.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/bn.js
new file mode 100644
index 0000000000000000000000000000000000000000..b6f942a6dcad1b8d63406d8d5af0dad72513b409
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/bn.js
@@ -0,0 +1,119 @@
+//! moment.js locale configuration
+//! locale : Bengali [bn]
+//! author : Kaushik Gandhi : https://github.com/kaushikgandhi
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var symbolMap = {
+    '1': 'à§§',
+    '2': '২',
+    '3': 'à§©',
+    '4': '৪',
+    '5': 'à§«',
+    '6': '৬',
+    '7': 'à§­',
+    '8': 'à§®',
+    '9': '৯',
+    '0': '০'
+};
+var numberMap = {
+    'à§§': '1',
+    '২': '2',
+    'à§©': '3',
+    '৪': '4',
+    'à§«': '5',
+    '৬': '6',
+    'à§­': '7',
+    'à§®': '8',
+    '৯': '9',
+    '০': '0'
+};
+
+var bn = moment.defineLocale('bn', {
+    months : 'জানুয়ারী_ফেব্রুয়ারি_মার্চ_এপ্রিল_মে_জুন_জুলাই_আগস্ট_সেপ্টেম্বর_অক্টোবর_নভেম্বর_ডিসেম্বর'.split('_'),
+    monthsShort : 'জানু_ফেব_মার্চ_এপ্র_মে_জুন_জুল_আগ_সেপ্ট_অক্টো_নভে_ডিসে'.split('_'),
+    weekdays : 'রবিবার_সোমবার_মঙ্গলবার_বুধবার_বৃহস্পতিবার_শুক্রবার_শনিবার'.split('_'),
+    weekdaysShort : 'রবি_সোম_মঙ্গল_বুধ_বৃহস্পতি_শুক্র_শনি'.split('_'),
+    weekdaysMin : 'রবি_সোম_মঙ্গ_বুধ_বৃহঃ_শুক্র_শনি'.split('_'),
+    longDateFormat : {
+        LT : 'A h:mm সময়',
+        LTS : 'A h:mm:ss সময়',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, A h:mm সময়',
+        LLLL : 'dddd, D MMMM YYYY, A h:mm সময়'
+    },
+    calendar : {
+        sameDay : '[আজ] LT',
+        nextDay : '[আগামীকাল] LT',
+        nextWeek : 'dddd, LT',
+        lastDay : '[গতকাল] LT',
+        lastWeek : '[গত] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s পরে',
+        past : '%s আগে',
+        s : 'কয়েক সেকেন্ড',
+        m : 'এক মিনিট',
+        mm : '%d মিনিট',
+        h : 'এক ঘন্টা',
+        hh : '%d ঘন্টা',
+        d : 'এক দিন',
+        dd : '%d দিন',
+        M : 'এক মাস',
+        MM : '%d মাস',
+        y : 'এক বছর',
+        yy : '%d বছর'
+    },
+    preparse: function (string) {
+        return string.replace(/[১২৩৪৫৬৭৮৯০]/g, function (match) {
+            return numberMap[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap[match];
+        });
+    },
+    meridiemParse: /রাত|সকাল|দুপুর|বিকাল|রাত/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if ((meridiem === 'রাত' && hour >= 4) ||
+                (meridiem === 'দুপুর' && hour < 5) ||
+                meridiem === 'বিকাল') {
+            return hour + 12;
+        } else {
+            return hour;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'রাত';
+        } else if (hour < 10) {
+            return 'সকাল';
+        } else if (hour < 17) {
+            return 'দুপুর';
+        } else if (hour < 20) {
+            return 'বিকাল';
+        } else {
+            return 'রাত';
+        }
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return bn;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/bo.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/bo.js
new file mode 100644
index 0000000000000000000000000000000000000000..eb6db476d8d9e5bf140c4fb8af6ea39fab8dc49d
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/bo.js
@@ -0,0 +1,119 @@
+//! moment.js locale configuration
+//! locale : Tibetan [bo]
+//! author : Thupten N. Chakrishar : https://github.com/vajradog
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var symbolMap = {
+    '1': '༡',
+    '2': '༢',
+    '3': '༣',
+    '4': '༤',
+    '5': '༥',
+    '6': '༦',
+    '7': '༧',
+    '8': '༨',
+    '9': '༩',
+    '0': '༠'
+};
+var numberMap = {
+    '༡': '1',
+    '༢': '2',
+    '༣': '3',
+    '༤': '4',
+    '༥': '5',
+    '༦': '6',
+    '༧': '7',
+    '༨': '8',
+    '༩': '9',
+    '༠': '0'
+};
+
+var bo = moment.defineLocale('bo', {
+    months : 'ཟླ་བ་དང་པོ_ཟླ་བ་གཉིས་པ_ཟླ་བ་གསུམ་པ_ཟླ་བ་བཞི་པ_ཟླ་བ་ལྔ་པ_ཟླ་བ་དྲུག་པ_ཟླ་བ་བདུན་པ_ཟླ་བ་བརྒྱད་པ_ཟླ་བ་དགུ་པ_ཟླ་བ་བཅུ་པ_ཟླ་བ་བཅུ་གཅིག་པ_ཟླ་བ་བཅུ་གཉིས་པ'.split('_'),
+    monthsShort : 'ཟླ་བ་དང་པོ_ཟླ་བ་གཉིས་པ_ཟླ་བ་གསུམ་པ_ཟླ་བ་བཞི་པ_ཟླ་བ་ལྔ་པ_ཟླ་བ་དྲུག་པ_ཟླ་བ་བདུན་པ_ཟླ་བ་བརྒྱད་པ_ཟླ་བ་དགུ་པ_ཟླ་བ་བཅུ་པ_ཟླ་བ་བཅུ་གཅིག་པ_ཟླ་བ་བཅུ་གཉིས་པ'.split('_'),
+    weekdays : 'གཟའ་ཉི་མ་_གཟའ་ཟླ་བ་_གཟའ་མིག་དམར་_གཟའ་ལྷག་པ་_གཟའ་ཕུར་བུ_གཟའ་པ་སངས་_གཟའ་སྤེན་པ་'.split('_'),
+    weekdaysShort : 'ཉི་མ་_ཟླ་བ་_མིག་དམར་_ལྷག་པ་_ཕུར་བུ_པ་སངས་_སྤེན་པ་'.split('_'),
+    weekdaysMin : 'ཉི་མ་_ཟླ་བ་_མིག་དམར་_ལྷག་པ་_ཕུར་བུ_པ་སངས་_སྤེན་པ་'.split('_'),
+    longDateFormat : {
+        LT : 'A h:mm',
+        LTS : 'A h:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, A h:mm',
+        LLLL : 'dddd, D MMMM YYYY, A h:mm'
+    },
+    calendar : {
+        sameDay : '[དི་རིང] LT',
+        nextDay : '[སང་ཉིན] LT',
+        nextWeek : '[བདུན་ཕྲག་རྗེས་མ], LT',
+        lastDay : '[ཁ་སང] LT',
+        lastWeek : '[བདུན་ཕྲག་མཐའ་མ] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s ལ་',
+        past : '%s སྔན་ལ',
+        s : 'ལམ་སང',
+        m : 'སྐར་མ་གཅིག',
+        mm : '%d སྐར་མ',
+        h : 'ཆུ་ཚོད་གཅིག',
+        hh : '%d ཆུ་ཚོད',
+        d : 'ཉིན་གཅིག',
+        dd : '%d ཉིན་',
+        M : 'ཟླ་བ་གཅིག',
+        MM : '%d ཟླ་བ',
+        y : 'ལོ་གཅིག',
+        yy : '%d ལོ'
+    },
+    preparse: function (string) {
+        return string.replace(/[༡༢༣༤༥༦༧༨༩༠]/g, function (match) {
+            return numberMap[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap[match];
+        });
+    },
+    meridiemParse: /མཚན་མོ|ཞོགས་ཀས|ཉིན་གུང|དགོང་དག|མཚན་མོ/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if ((meridiem === 'མཚན་མོ' && hour >= 4) ||
+                (meridiem === 'ཉིན་གུང' && hour < 5) ||
+                meridiem === 'དགོང་དག') {
+            return hour + 12;
+        } else {
+            return hour;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'མཚན་མོ';
+        } else if (hour < 10) {
+            return 'ཞོགས་ཀས';
+        } else if (hour < 17) {
+            return 'ཉིན་གུང';
+        } else if (hour < 20) {
+            return 'དགོང་དག';
+        } else {
+            return 'མཚན་མོ';
+        }
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return bo;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/br.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/br.js
new file mode 100644
index 0000000000000000000000000000000000000000..4e1829962f7b646b629d3f1ef77a2495dccc20a3
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/br.js
@@ -0,0 +1,108 @@
+//! moment.js locale configuration
+//! locale : Breton [br]
+//! author : Jean-Baptiste Le Duigou : https://github.com/jbleduigou
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+function relativeTimeWithMutation(number, withoutSuffix, key) {
+    var format = {
+        'mm': 'munutenn',
+        'MM': 'miz',
+        'dd': 'devezh'
+    };
+    return number + ' ' + mutation(format[key], number);
+}
+function specialMutationForYears(number) {
+    switch (lastNumber(number)) {
+        case 1:
+        case 3:
+        case 4:
+        case 5:
+        case 9:
+            return number + ' bloaz';
+        default:
+            return number + ' vloaz';
+    }
+}
+function lastNumber(number) {
+    if (number > 9) {
+        return lastNumber(number % 10);
+    }
+    return number;
+}
+function mutation(text, number) {
+    if (number === 2) {
+        return softMutation(text);
+    }
+    return text;
+}
+function softMutation(text) {
+    var mutationTable = {
+        'm': 'v',
+        'b': 'v',
+        'd': 'z'
+    };
+    if (mutationTable[text.charAt(0)] === undefined) {
+        return text;
+    }
+    return mutationTable[text.charAt(0)] + text.substring(1);
+}
+
+var br = moment.defineLocale('br', {
+    months : 'Genver_C\'hwevrer_Meurzh_Ebrel_Mae_Mezheven_Gouere_Eost_Gwengolo_Here_Du_Kerzu'.split('_'),
+    monthsShort : 'Gen_C\'hwe_Meu_Ebr_Mae_Eve_Gou_Eos_Gwe_Her_Du_Ker'.split('_'),
+    weekdays : 'Sul_Lun_Meurzh_Merc\'her_Yaou_Gwener_Sadorn'.split('_'),
+    weekdaysShort : 'Sul_Lun_Meu_Mer_Yao_Gwe_Sad'.split('_'),
+    weekdaysMin : 'Su_Lu_Me_Mer_Ya_Gw_Sa'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'h[e]mm A',
+        LTS : 'h[e]mm:ss A',
+        L : 'DD/MM/YYYY',
+        LL : 'D [a viz] MMMM YYYY',
+        LLL : 'D [a viz] MMMM YYYY h[e]mm A',
+        LLLL : 'dddd, D [a viz] MMMM YYYY h[e]mm A'
+    },
+    calendar : {
+        sameDay : '[Hiziv da] LT',
+        nextDay : '[Warc\'hoazh da] LT',
+        nextWeek : 'dddd [da] LT',
+        lastDay : '[Dec\'h da] LT',
+        lastWeek : 'dddd [paset da] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'a-benn %s',
+        past : '%s \'zo',
+        s : 'un nebeud segondennoù',
+        m : 'ur vunutenn',
+        mm : relativeTimeWithMutation,
+        h : 'un eur',
+        hh : '%d eur',
+        d : 'un devezh',
+        dd : relativeTimeWithMutation,
+        M : 'ur miz',
+        MM : relativeTimeWithMutation,
+        y : 'ur bloaz',
+        yy : specialMutationForYears
+    },
+    ordinalParse: /\d{1,2}(añ|vet)/,
+    ordinal : function (number) {
+        var output = (number === 1) ? 'añ' : 'vet';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return br;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/bs.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/bs.js
new file mode 100644
index 0000000000000000000000000000000000000000..f2b8725c531be934124dd3e8aeb1ea82644a7f06
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/bs.js
@@ -0,0 +1,143 @@
+//! moment.js locale configuration
+//! locale : Bosnian [bs]
+//! author : Nedim Cholich : https://github.com/frontyard
+//! based on (hr) translation by Bojan Marković
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+function translate(number, withoutSuffix, key) {
+    var result = number + ' ';
+    switch (key) {
+        case 'm':
+            return withoutSuffix ? 'jedna minuta' : 'jedne minute';
+        case 'mm':
+            if (number === 1) {
+                result += 'minuta';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'minute';
+            } else {
+                result += 'minuta';
+            }
+            return result;
+        case 'h':
+            return withoutSuffix ? 'jedan sat' : 'jednog sata';
+        case 'hh':
+            if (number === 1) {
+                result += 'sat';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'sata';
+            } else {
+                result += 'sati';
+            }
+            return result;
+        case 'dd':
+            if (number === 1) {
+                result += 'dan';
+            } else {
+                result += 'dana';
+            }
+            return result;
+        case 'MM':
+            if (number === 1) {
+                result += 'mjesec';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'mjeseca';
+            } else {
+                result += 'mjeseci';
+            }
+            return result;
+        case 'yy':
+            if (number === 1) {
+                result += 'godina';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'godine';
+            } else {
+                result += 'godina';
+            }
+            return result;
+    }
+}
+
+var bs = moment.defineLocale('bs', {
+    months : 'januar_februar_mart_april_maj_juni_juli_august_septembar_oktobar_novembar_decembar'.split('_'),
+    monthsShort : 'jan._feb._mar._apr._maj._jun._jul._aug._sep._okt._nov._dec.'.split('_'),
+    monthsParseExact: true,
+    weekdays : 'nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota'.split('_'),
+    weekdaysShort : 'ned._pon._uto._sri._čet._pet._sub.'.split('_'),
+    weekdaysMin : 'ne_po_ut_sr_če_pe_su'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY H:mm',
+        LLLL : 'dddd, D. MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay  : '[danas u] LT',
+        nextDay  : '[sutra u] LT',
+        nextWeek : function () {
+            switch (this.day()) {
+                case 0:
+                    return '[u] [nedjelju] [u] LT';
+                case 3:
+                    return '[u] [srijedu] [u] LT';
+                case 6:
+                    return '[u] [subotu] [u] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[u] dddd [u] LT';
+            }
+        },
+        lastDay  : '[jučer u] LT',
+        lastWeek : function () {
+            switch (this.day()) {
+                case 0:
+                case 3:
+                    return '[prošlu] dddd [u] LT';
+                case 6:
+                    return '[prošle] [subote] [u] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[prošli] dddd [u] LT';
+            }
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'za %s',
+        past   : 'prije %s',
+        s      : 'par sekundi',
+        m      : translate,
+        mm     : translate,
+        h      : translate,
+        hh     : translate,
+        d      : 'dan',
+        dd     : translate,
+        M      : 'mjesec',
+        MM     : translate,
+        y      : 'godinu',
+        yy     : translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return bs;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ca.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ca.js
new file mode 100644
index 0000000000000000000000000000000000000000..454e361baadbf134f748aecea44649e9888457e4
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ca.js
@@ -0,0 +1,81 @@
+//! moment.js locale configuration
+//! locale : Catalan [ca]
+//! author : Juan G. Hurtado : https://github.com/juanghurtado
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var ca = moment.defineLocale('ca', {
+    months : 'gener_febrer_març_abril_maig_juny_juliol_agost_setembre_octubre_novembre_desembre'.split('_'),
+    monthsShort : 'gen._febr._mar._abr._mai._jun._jul._ag._set._oct._nov._des.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'diumenge_dilluns_dimarts_dimecres_dijous_divendres_dissabte'.split('_'),
+    weekdaysShort : 'dg._dl._dt._dc._dj._dv._ds.'.split('_'),
+    weekdaysMin : 'Dg_Dl_Dt_Dc_Dj_Dv_Ds'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY H:mm',
+        LLLL : 'dddd D MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay : function () {
+            return '[avui a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
+        },
+        nextDay : function () {
+            return '[demà a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
+        },
+        nextWeek : function () {
+            return 'dddd [a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
+        },
+        lastDay : function () {
+            return '[ahir a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
+        },
+        lastWeek : function () {
+            return '[el] dddd [passat a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'en %s',
+        past : 'fa %s',
+        s : 'uns segons',
+        m : 'un minut',
+        mm : '%d minuts',
+        h : 'una hora',
+        hh : '%d hores',
+        d : 'un dia',
+        dd : '%d dies',
+        M : 'un mes',
+        MM : '%d mesos',
+        y : 'un any',
+        yy : '%d anys'
+    },
+    ordinalParse: /\d{1,2}(r|n|t|è|a)/,
+    ordinal : function (number, period) {
+        var output = (number === 1) ? 'r' :
+            (number === 2) ? 'n' :
+            (number === 3) ? 'r' :
+            (number === 4) ? 't' : 'è';
+        if (period === 'w' || period === 'W') {
+            output = 'a';
+        }
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return ca;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/cs.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/cs.js
new file mode 100644
index 0000000000000000000000000000000000000000..35a8a5a781e80f3c5b7f573a6a2bf7df51d17cff
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/cs.js
@@ -0,0 +1,172 @@
+//! moment.js locale configuration
+//! locale : Czech [cs]
+//! author : petrbela : https://github.com/petrbela
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var months = 'leden_únor_březen_duben_květen_červen_červenec_srpen_září_říjen_listopad_prosinec'.split('_');
+var monthsShort = 'led_úno_bře_dub_kvě_čvn_čvc_srp_zář_říj_lis_pro'.split('_');
+function plural(n) {
+    return (n > 1) && (n < 5) && (~~(n / 10) !== 1);
+}
+function translate(number, withoutSuffix, key, isFuture) {
+    var result = number + ' ';
+    switch (key) {
+        case 's':  // a few seconds / in a few seconds / a few seconds ago
+            return (withoutSuffix || isFuture) ? 'pár sekund' : 'pár sekundami';
+        case 'm':  // a minute / in a minute / a minute ago
+            return withoutSuffix ? 'minuta' : (isFuture ? 'minutu' : 'minutou');
+        case 'mm': // 9 minutes / in 9 minutes / 9 minutes ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural(number) ? 'minuty' : 'minut');
+            } else {
+                return result + 'minutami';
+            }
+            break;
+        case 'h':  // an hour / in an hour / an hour ago
+            return withoutSuffix ? 'hodina' : (isFuture ? 'hodinu' : 'hodinou');
+        case 'hh': // 9 hours / in 9 hours / 9 hours ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural(number) ? 'hodiny' : 'hodin');
+            } else {
+                return result + 'hodinami';
+            }
+            break;
+        case 'd':  // a day / in a day / a day ago
+            return (withoutSuffix || isFuture) ? 'den' : 'dnem';
+        case 'dd': // 9 days / in 9 days / 9 days ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural(number) ? 'dny' : 'dní');
+            } else {
+                return result + 'dny';
+            }
+            break;
+        case 'M':  // a month / in a month / a month ago
+            return (withoutSuffix || isFuture) ? 'měsíc' : 'měsícem';
+        case 'MM': // 9 months / in 9 months / 9 months ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural(number) ? 'měsíce' : 'měsíců');
+            } else {
+                return result + 'měsíci';
+            }
+            break;
+        case 'y':  // a year / in a year / a year ago
+            return (withoutSuffix || isFuture) ? 'rok' : 'rokem';
+        case 'yy': // 9 years / in 9 years / 9 years ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural(number) ? 'roky' : 'let');
+            } else {
+                return result + 'lety';
+            }
+            break;
+    }
+}
+
+var cs = moment.defineLocale('cs', {
+    months : months,
+    monthsShort : monthsShort,
+    monthsParse : (function (months, monthsShort) {
+        var i, _monthsParse = [];
+        for (i = 0; i < 12; i++) {
+            // use custom parser to solve problem with July (červenec)
+            _monthsParse[i] = new RegExp('^' + months[i] + '$|^' + monthsShort[i] + '$', 'i');
+        }
+        return _monthsParse;
+    }(months, monthsShort)),
+    shortMonthsParse : (function (monthsShort) {
+        var i, _shortMonthsParse = [];
+        for (i = 0; i < 12; i++) {
+            _shortMonthsParse[i] = new RegExp('^' + monthsShort[i] + '$', 'i');
+        }
+        return _shortMonthsParse;
+    }(monthsShort)),
+    longMonthsParse : (function (months) {
+        var i, _longMonthsParse = [];
+        for (i = 0; i < 12; i++) {
+            _longMonthsParse[i] = new RegExp('^' + months[i] + '$', 'i');
+        }
+        return _longMonthsParse;
+    }(months)),
+    weekdays : 'neděle_pondělí_úterý_středa_čtvrtek_pátek_sobota'.split('_'),
+    weekdaysShort : 'ne_po_út_st_čt_pá_so'.split('_'),
+    weekdaysMin : 'ne_po_út_st_čt_pá_so'.split('_'),
+    longDateFormat : {
+        LT: 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY H:mm',
+        LLLL : 'dddd D. MMMM YYYY H:mm',
+        l : 'D. M. YYYY'
+    },
+    calendar : {
+        sameDay: '[dnes v] LT',
+        nextDay: '[zítra v] LT',
+        nextWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[v neděli v] LT';
+                case 1:
+                case 2:
+                    return '[v] dddd [v] LT';
+                case 3:
+                    return '[ve středu v] LT';
+                case 4:
+                    return '[ve čtvrtek v] LT';
+                case 5:
+                    return '[v pátek v] LT';
+                case 6:
+                    return '[v sobotu v] LT';
+            }
+        },
+        lastDay: '[včera v] LT',
+        lastWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[minulou neděli v] LT';
+                case 1:
+                case 2:
+                    return '[minulé] dddd [v] LT';
+                case 3:
+                    return '[minulou středu v] LT';
+                case 4:
+                case 5:
+                    return '[minulý] dddd [v] LT';
+                case 6:
+                    return '[minulou sobotu v] LT';
+            }
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'za %s',
+        past : 'před %s',
+        s : translate,
+        m : translate,
+        mm : translate,
+        h : translate,
+        hh : translate,
+        d : translate,
+        dd : translate,
+        M : translate,
+        MM : translate,
+        y : translate,
+        yy : translate
+    },
+    ordinalParse : /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return cs;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/cv.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/cv.js
new file mode 100644
index 0000000000000000000000000000000000000000..59ad1445a569aa4e5bf886b4aba441cae0d28832
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/cv.js
@@ -0,0 +1,63 @@
+//! moment.js locale configuration
+//! locale : Chuvash [cv]
+//! author : Anatoly Mironov : https://github.com/mirontoli
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var cv = moment.defineLocale('cv', {
+    months : 'кӑрлач_нарӑс_пуш_ака_май_ҫӗртме_утӑ_ҫурла_авӑн_юпа_чӳк_раштав'.split('_'),
+    monthsShort : 'кӑр_нар_пуш_ака_май_ҫӗр_утӑ_ҫур_авн_юпа_чӳк_раш'.split('_'),
+    weekdays : 'вырсарникун_тунтикун_ытларикун_юнкун_кӗҫнерникун_эрнекун_шӑматкун'.split('_'),
+    weekdaysShort : 'выр_тун_ытл_юн_кӗҫ_эрн_шӑм'.split('_'),
+    weekdaysMin : 'вр_тн_ыт_юн_кҫ_эр_шм'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD-MM-YYYY',
+        LL : 'YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ]',
+        LLL : 'YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm',
+        LLLL : 'dddd, YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm'
+    },
+    calendar : {
+        sameDay: '[Паян] LT [сехетре]',
+        nextDay: '[Ыран] LT [сехетре]',
+        lastDay: '[Ӗнер] LT [сехетре]',
+        nextWeek: '[Ҫитес] dddd LT [сехетре]',
+        lastWeek: '[Иртнӗ] dddd LT [сехетре]',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : function (output) {
+            var affix = /сехет$/i.exec(output) ? 'рен' : /ҫул$/i.exec(output) ? 'тан' : 'ран';
+            return output + affix;
+        },
+        past : '%s каялла',
+        s : 'пӗр-ик ҫеккунт',
+        m : 'пӗр минут',
+        mm : '%d минут',
+        h : 'пӗр сехет',
+        hh : '%d сехет',
+        d : 'пӗр кун',
+        dd : '%d кун',
+        M : 'пӗр уйӑх',
+        MM : '%d уйӑх',
+        y : 'пӗр ҫул',
+        yy : '%d ҫул'
+    },
+    ordinalParse: /\d{1,2}-мӗш/,
+    ordinal : '%d-мӗш',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return cv;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/cy.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/cy.js
new file mode 100644
index 0000000000000000000000000000000000000000..022b10625743876e6a1085bd7a7ba3ed71a0f90a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/cy.js
@@ -0,0 +1,81 @@
+//! moment.js locale configuration
+//! locale : Welsh [cy]
+//! author : Robert Allen : https://github.com/robgallen
+//! author : https://github.com/ryangreaves
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var cy = moment.defineLocale('cy', {
+    months: 'Ionawr_Chwefror_Mawrth_Ebrill_Mai_Mehefin_Gorffennaf_Awst_Medi_Hydref_Tachwedd_Rhagfyr'.split('_'),
+    monthsShort: 'Ion_Chwe_Maw_Ebr_Mai_Meh_Gor_Aws_Med_Hyd_Tach_Rhag'.split('_'),
+    weekdays: 'Dydd Sul_Dydd Llun_Dydd Mawrth_Dydd Mercher_Dydd Iau_Dydd Gwener_Dydd Sadwrn'.split('_'),
+    weekdaysShort: 'Sul_Llun_Maw_Mer_Iau_Gwe_Sad'.split('_'),
+    weekdaysMin: 'Su_Ll_Ma_Me_Ia_Gw_Sa'.split('_'),
+    weekdaysParseExact : true,
+    // time formats are the same as en-gb
+    longDateFormat: {
+        LT: 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L: 'DD/MM/YYYY',
+        LL: 'D MMMM YYYY',
+        LLL: 'D MMMM YYYY HH:mm',
+        LLLL: 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar: {
+        sameDay: '[Heddiw am] LT',
+        nextDay: '[Yfory am] LT',
+        nextWeek: 'dddd [am] LT',
+        lastDay: '[Ddoe am] LT',
+        lastWeek: 'dddd [diwethaf am] LT',
+        sameElse: 'L'
+    },
+    relativeTime: {
+        future: 'mewn %s',
+        past: '%s yn ôl',
+        s: 'ychydig eiliadau',
+        m: 'munud',
+        mm: '%d munud',
+        h: 'awr',
+        hh: '%d awr',
+        d: 'diwrnod',
+        dd: '%d diwrnod',
+        M: 'mis',
+        MM: '%d mis',
+        y: 'blwyddyn',
+        yy: '%d flynedd'
+    },
+    ordinalParse: /\d{1,2}(fed|ain|af|il|ydd|ed|eg)/,
+    // traditional ordinal numbers above 31 are not commonly used in colloquial Welsh
+    ordinal: function (number) {
+        var b = number,
+            output = '',
+            lookup = [
+                '', 'af', 'il', 'ydd', 'ydd', 'ed', 'ed', 'ed', 'fed', 'fed', 'fed', // 1af to 10fed
+                'eg', 'fed', 'eg', 'eg', 'fed', 'eg', 'eg', 'fed', 'eg', 'fed' // 11eg to 20fed
+            ];
+        if (b > 20) {
+            if (b === 40 || b === 50 || b === 60 || b === 80 || b === 100) {
+                output = 'fed'; // not 30ain, 70ain or 90ain
+            } else {
+                output = 'ain';
+            }
+        } else if (b > 0) {
+            output = lookup[b];
+        }
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return cy;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/da.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/da.js
new file mode 100644
index 0000000000000000000000000000000000000000..223c3d7e45a4b9a09622436e01bf2988301ebdc8
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/da.js
@@ -0,0 +1,60 @@
+//! moment.js locale configuration
+//! locale : Danish [da]
+//! author : Ulrik Nielsen : https://github.com/mrbase
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var da = moment.defineLocale('da', {
+    months : 'januar_februar_marts_april_maj_juni_juli_august_september_oktober_november_december'.split('_'),
+    monthsShort : 'jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec'.split('_'),
+    weekdays : 'søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag'.split('_'),
+    weekdaysShort : 'søn_man_tir_ons_tor_fre_lør'.split('_'),
+    weekdaysMin : 'sø_ma_ti_on_to_fr_lø'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY HH:mm',
+        LLLL : 'dddd [d.] D. MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[I dag kl.] LT',
+        nextDay : '[I morgen kl.] LT',
+        nextWeek : 'dddd [kl.] LT',
+        lastDay : '[I går kl.] LT',
+        lastWeek : '[sidste] dddd [kl] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'om %s',
+        past : '%s siden',
+        s : 'få sekunder',
+        m : 'et minut',
+        mm : '%d minutter',
+        h : 'en time',
+        hh : '%d timer',
+        d : 'en dag',
+        dd : '%d dage',
+        M : 'en måned',
+        MM : '%d måneder',
+        y : 'et år',
+        yy : '%d år'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return da;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/de-at.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/de-at.js
new file mode 100644
index 0000000000000000000000000000000000000000..e72c124dc500f0910b733f75f713b06ce18faab5
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/de-at.js
@@ -0,0 +1,79 @@
+//! moment.js locale configuration
+//! locale : German (Austria) [de-at]
+//! author : lluchs : https://github.com/lluchs
+//! author: Menelion Elensúle: https://github.com/Oire
+//! author : Martin Groller : https://github.com/MadMG
+//! author : Mikolaj Dadela : https://github.com/mik01aj
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+function processRelativeTime(number, withoutSuffix, key, isFuture) {
+    var format = {
+        'm': ['eine Minute', 'einer Minute'],
+        'h': ['eine Stunde', 'einer Stunde'],
+        'd': ['ein Tag', 'einem Tag'],
+        'dd': [number + ' Tage', number + ' Tagen'],
+        'M': ['ein Monat', 'einem Monat'],
+        'MM': [number + ' Monate', number + ' Monaten'],
+        'y': ['ein Jahr', 'einem Jahr'],
+        'yy': [number + ' Jahre', number + ' Jahren']
+    };
+    return withoutSuffix ? format[key][0] : format[key][1];
+}
+
+var deAt = moment.defineLocale('de-at', {
+    months : 'Jänner_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember'.split('_'),
+    monthsShort : 'Jän._Febr._Mrz._Apr._Mai_Jun._Jul._Aug._Sept._Okt._Nov._Dez.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag'.split('_'),
+    weekdaysShort : 'So._Mo._Di._Mi._Do._Fr._Sa.'.split('_'),
+    weekdaysMin : 'So_Mo_Di_Mi_Do_Fr_Sa'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT: 'HH:mm',
+        LTS: 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY HH:mm',
+        LLLL : 'dddd, D. MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[heute um] LT [Uhr]',
+        sameElse: 'L',
+        nextDay: '[morgen um] LT [Uhr]',
+        nextWeek: 'dddd [um] LT [Uhr]',
+        lastDay: '[gestern um] LT [Uhr]',
+        lastWeek: '[letzten] dddd [um] LT [Uhr]'
+    },
+    relativeTime : {
+        future : 'in %s',
+        past : 'vor %s',
+        s : 'ein paar Sekunden',
+        m : processRelativeTime,
+        mm : '%d Minuten',
+        h : processRelativeTime,
+        hh : '%d Stunden',
+        d : processRelativeTime,
+        dd : processRelativeTime,
+        M : processRelativeTime,
+        MM : processRelativeTime,
+        y : processRelativeTime,
+        yy : processRelativeTime
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return deAt;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/de.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/de.js
new file mode 100644
index 0000000000000000000000000000000000000000..bb7197e48bb5c297efa3ac00144ea297d0d3547f
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/de.js
@@ -0,0 +1,78 @@
+//! moment.js locale configuration
+//! locale : German [de]
+//! author : lluchs : https://github.com/lluchs
+//! author: Menelion Elensúle: https://github.com/Oire
+//! author : Mikolaj Dadela : https://github.com/mik01aj
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+function processRelativeTime(number, withoutSuffix, key, isFuture) {
+    var format = {
+        'm': ['eine Minute', 'einer Minute'],
+        'h': ['eine Stunde', 'einer Stunde'],
+        'd': ['ein Tag', 'einem Tag'],
+        'dd': [number + ' Tage', number + ' Tagen'],
+        'M': ['ein Monat', 'einem Monat'],
+        'MM': [number + ' Monate', number + ' Monaten'],
+        'y': ['ein Jahr', 'einem Jahr'],
+        'yy': [number + ' Jahre', number + ' Jahren']
+    };
+    return withoutSuffix ? format[key][0] : format[key][1];
+}
+
+var de = moment.defineLocale('de', {
+    months : 'Januar_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember'.split('_'),
+    monthsShort : 'Jan._Febr._Mrz._Apr._Mai_Jun._Jul._Aug._Sept._Okt._Nov._Dez.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag'.split('_'),
+    weekdaysShort : 'So._Mo._Di._Mi._Do._Fr._Sa.'.split('_'),
+    weekdaysMin : 'So_Mo_Di_Mi_Do_Fr_Sa'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT: 'HH:mm',
+        LTS: 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY HH:mm',
+        LLLL : 'dddd, D. MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[heute um] LT [Uhr]',
+        sameElse: 'L',
+        nextDay: '[morgen um] LT [Uhr]',
+        nextWeek: 'dddd [um] LT [Uhr]',
+        lastDay: '[gestern um] LT [Uhr]',
+        lastWeek: '[letzten] dddd [um] LT [Uhr]'
+    },
+    relativeTime : {
+        future : 'in %s',
+        past : 'vor %s',
+        s : 'ein paar Sekunden',
+        m : processRelativeTime,
+        mm : '%d Minuten',
+        h : processRelativeTime,
+        hh : '%d Stunden',
+        d : processRelativeTime,
+        dd : processRelativeTime,
+        M : processRelativeTime,
+        MM : processRelativeTime,
+        y : processRelativeTime,
+        yy : processRelativeTime
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return de;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/dv.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/dv.js
new file mode 100644
index 0000000000000000000000000000000000000000..065df78c3643d1619d677c4c82cf5c15bb726257
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/dv.js
@@ -0,0 +1,100 @@
+//! moment.js locale configuration
+//! locale : Maldivian [dv]
+//! author : Jawish Hameed : https://github.com/jawish
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var months = [
+    'Þ–Þ¬Þ‚ÞªÞ‡Þ¦ÞƒÞ©',
+    'ÞŠÞ¬Þ„Þ°ÞƒÞªÞ‡Þ¦ÞƒÞ©',
+    'Þ‰Þ§ÞƒÞ¨Þ—Þª',
+    'އޭޕްރީލު',
+    'Þ‰Þ­',
+    'Þ–Þ«Þ‚Þ°',
+    'ޖުލައި',
+    'އޯގަސްޓު',
+    'ސެޕްޓެމްބަރު',
+    'Þ‡Þ®Þ†Þ°Þ“Þ¯Þ„Þ¦ÞƒÞª',
+    'Þ‚Þ®ÞˆÞ¬Þ‰Þ°Þ„Þ¦ÞƒÞª',
+    'ޑިސެމްބަރު'
+];
+var weekdays = [
+    'އާދިއްތަ',
+    'Þ€Þ¯Þ‰Þ¦',
+    'Þ‡Þ¦Þ‚Þ°ÞŽÞ§ÞƒÞ¦',
+    'Þ„ÞªÞ‹Þ¦',
+    'ބުރާސްފަތި',
+    'Þ€ÞªÞ†ÞªÞƒÞª',
+    'Þ€Þ®Þ‚Þ¨Þ€Þ¨ÞƒÞª'
+];
+
+var dv = moment.defineLocale('dv', {
+    months : months,
+    monthsShort : months,
+    weekdays : weekdays,
+    weekdaysShort : weekdays,
+    weekdaysMin : 'Þ‡Þ§Þ‹Þ¨_Þ€Þ¯Þ‰Þ¦_Þ‡Þ¦Þ‚Þ°_Þ„ÞªÞ‹Þ¦_Þ„ÞªÞƒÞ§_Þ€ÞªÞ†Þª_Þ€Þ®Þ‚Þ¨'.split('_'),
+    longDateFormat : {
+
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'D/M/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    meridiemParse: /Þ‰Þ†|Þ‰ÞŠ/,
+    isPM : function (input) {
+        return 'Þ‰ÞŠ' === input;
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return 'Þ‰Þ†';
+        } else {
+            return 'Þ‰ÞŠ';
+        }
+    },
+    calendar : {
+        sameDay : '[Þ‰Þ¨Þ‡Þ¦Þ‹Þª] LT',
+        nextDay : '[Þ‰Þ§Þ‹Þ¦Þ‰Þ§] LT',
+        nextWeek : 'dddd LT',
+        lastDay : '[Þ‡Þ¨Þ‡Þ°Þ”Þ¬] LT',
+        lastWeek : '[ފާއިތުވި] dddd LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'ތެރޭގައި %s',
+        past : 'Þ†ÞªÞƒÞ¨Þ‚Þ° %s',
+        s : 'ސިކުންތުކޮޅެއް',
+        m : 'Þ‰Þ¨Þ‚Þ¨Þ“Þ¬Þ‡Þ°',
+        mm : 'Þ‰Þ¨Þ‚Þ¨Þ“Þª %d',
+        h : 'ÞŽÞ¦Þ‘Þ¨Þ‡Þ¨ÞƒÞ¬Þ‡Þ°',
+        hh : 'ÞŽÞ¦Þ‘Þ¨Þ‡Þ¨ÞƒÞª %d',
+        d : 'Þ‹ÞªÞˆÞ¦Þ€Þ¬Þ‡Þ°',
+        dd : 'ދުވަސް %d',
+        M : 'Þ‰Þ¦Þ€Þ¬Þ‡Þ°',
+        MM : 'މަސް %d',
+        y : 'Þ‡Þ¦Þ€Þ¦ÞƒÞ¬Þ‡Þ°',
+        yy : 'Þ‡Þ¦Þ€Þ¦ÞƒÞª %d'
+    },
+    preparse: function (string) {
+        return string.replace(/،/g, ',');
+    },
+    postformat: function (string) {
+        return string.replace(/,/g, '،');
+    },
+    week : {
+        dow : 7,  // Sunday is the first day of the week.
+        doy : 12  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return dv;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/el.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/el.js
new file mode 100644
index 0000000000000000000000000000000000000000..8396665ce76b0f5b947e6d31f01626920613d5b2
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/el.js
@@ -0,0 +1,98 @@
+//! moment.js locale configuration
+//! locale : Greek [el]
+//! author : Aggelos Karalias : https://github.com/mehiel
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+function isFunction(input) {
+    return input instanceof Function || Object.prototype.toString.call(input) === '[object Function]';
+}
+
+
+var el = moment.defineLocale('el', {
+    monthsNominativeEl : 'Ιανουάριος_Φεβρουάριος_Μάρτιος_Απρίλιος_Μάιος_Ιούνιος_Ιούλιος_Αύγουστος_Σεπτέμβριος_Οκτώβριος_Νοέμβριος_Δεκέμβριος'.split('_'),
+    monthsGenitiveEl : 'Ιανουαρίου_Φεβρουαρίου_Μαρτίου_Απριλίου_Μαΐου_Ιουνίου_Ιουλίου_Αυγούστου_Σεπτεμβρίου_Οκτωβρίου_Νοεμβρίου_Δεκεμβρίου'.split('_'),
+    months : function (momentToFormat, format) {
+        if (/D/.test(format.substring(0, format.indexOf('MMMM')))) { // if there is a day number before 'MMMM'
+            return this._monthsGenitiveEl[momentToFormat.month()];
+        } else {
+            return this._monthsNominativeEl[momentToFormat.month()];
+        }
+    },
+    monthsShort : 'Ιαν_Φεβ_Μαρ_Απρ_Μαϊ_Ιουν_Ιουλ_Αυγ_Σεπ_Οκτ_Νοε_Δεκ'.split('_'),
+    weekdays : 'Κυριακή_Δευτέρα_Τρίτη_Τετάρτη_Πέμπτη_Παρασκευή_Σάββατο'.split('_'),
+    weekdaysShort : 'Κυρ_Δευ_Τρι_Τετ_Πεμ_Παρ_Σαβ'.split('_'),
+    weekdaysMin : 'Κυ_Δε_Τρ_Τε_Πε_Πα_Σα'.split('_'),
+    meridiem : function (hours, minutes, isLower) {
+        if (hours > 11) {
+            return isLower ? 'μμ' : 'ΜΜ';
+        } else {
+            return isLower ? 'πμ' : 'ΠΜ';
+        }
+    },
+    isPM : function (input) {
+        return ((input + '').toLowerCase()[0] === 'μ');
+    },
+    meridiemParse : /[ΠΜ]\.?Μ?\.?/i,
+    longDateFormat : {
+        LT : 'h:mm A',
+        LTS : 'h:mm:ss A',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY h:mm A',
+        LLLL : 'dddd, D MMMM YYYY h:mm A'
+    },
+    calendarEl : {
+        sameDay : '[Σήμερα {}] LT',
+        nextDay : '[Αύριο {}] LT',
+        nextWeek : 'dddd [{}] LT',
+        lastDay : '[Χθες {}] LT',
+        lastWeek : function () {
+            switch (this.day()) {
+                case 6:
+                    return '[το προηγούμενο] dddd [{}] LT';
+                default:
+                    return '[την προηγούμενη] dddd [{}] LT';
+            }
+        },
+        sameElse : 'L'
+    },
+    calendar : function (key, mom) {
+        var output = this._calendarEl[key],
+            hours = mom && mom.hours();
+        if (isFunction(output)) {
+            output = output.apply(mom);
+        }
+        return output.replace('{}', (hours % 12 === 1 ? 'στη' : 'στις'));
+    },
+    relativeTime : {
+        future : 'σε %s',
+        past : '%s πριν',
+        s : 'λίγα δευτερόλεπτα',
+        m : 'ένα λεπτό',
+        mm : '%d λεπτά',
+        h : 'μία ώρα',
+        hh : '%d ώρες',
+        d : 'μία μέρα',
+        dd : '%d μέρες',
+        M : 'ένας μήνας',
+        MM : '%d μήνες',
+        y : 'ένας χρόνος',
+        yy : '%d χρόνια'
+    },
+    ordinalParse: /\d{1,2}η/,
+    ordinal: '%dη',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4st is the first week of the year.
+    }
+});
+
+return el;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/en-au.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/en-au.js
new file mode 100644
index 0000000000000000000000000000000000000000..d13415796e2bf3d746d2d8c804bcac2f1a87510d
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/en-au.js
@@ -0,0 +1,67 @@
+//! moment.js locale configuration
+//! locale : English (Australia) [en-au]
+//! author : Jared Morse : https://github.com/jarcoal
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var enAu = moment.defineLocale('en-au', {
+    months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),
+    monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),
+    weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
+    weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
+    weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'h:mm A',
+        LTS : 'h:mm:ss A',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY h:mm A',
+        LLLL : 'dddd, D MMMM YYYY h:mm A'
+    },
+    calendar : {
+        sameDay : '[Today at] LT',
+        nextDay : '[Tomorrow at] LT',
+        nextWeek : 'dddd [at] LT',
+        lastDay : '[Yesterday at] LT',
+        lastWeek : '[Last] dddd [at] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'in %s',
+        past : '%s ago',
+        s : 'a few seconds',
+        m : 'a minute',
+        mm : '%d minutes',
+        h : 'an hour',
+        hh : '%d hours',
+        d : 'a day',
+        dd : '%d days',
+        M : 'a month',
+        MM : '%d months',
+        y : 'a year',
+        yy : '%d years'
+    },
+    ordinalParse: /\d{1,2}(st|nd|rd|th)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return enAu;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/en-ca.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/en-ca.js
new file mode 100644
index 0000000000000000000000000000000000000000..358b1837a2e9a842c70b94f55bfed89fe6a8b734
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/en-ca.js
@@ -0,0 +1,63 @@
+//! moment.js locale configuration
+//! locale : English (Canada) [en-ca]
+//! author : Jonathan Abourbih : https://github.com/jonbca
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var enCa = moment.defineLocale('en-ca', {
+    months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),
+    monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),
+    weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
+    weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
+    weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'h:mm A',
+        LTS : 'h:mm:ss A',
+        L : 'YYYY-MM-DD',
+        LL : 'MMMM D, YYYY',
+        LLL : 'MMMM D, YYYY h:mm A',
+        LLLL : 'dddd, MMMM D, YYYY h:mm A'
+    },
+    calendar : {
+        sameDay : '[Today at] LT',
+        nextDay : '[Tomorrow at] LT',
+        nextWeek : 'dddd [at] LT',
+        lastDay : '[Yesterday at] LT',
+        lastWeek : '[Last] dddd [at] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'in %s',
+        past : '%s ago',
+        s : 'a few seconds',
+        m : 'a minute',
+        mm : '%d minutes',
+        h : 'an hour',
+        hh : '%d hours',
+        d : 'a day',
+        dd : '%d days',
+        M : 'a month',
+        MM : '%d months',
+        y : 'a year',
+        yy : '%d years'
+    },
+    ordinalParse: /\d{1,2}(st|nd|rd|th)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    }
+});
+
+return enCa;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/en-gb.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/en-gb.js
new file mode 100644
index 0000000000000000000000000000000000000000..ed382905f3594d1df4387a686a924950946f611f
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/en-gb.js
@@ -0,0 +1,67 @@
+//! moment.js locale configuration
+//! locale : English (United Kingdom) [en-gb]
+//! author : Chris Gedrim : https://github.com/chrisgedrim
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var enGb = moment.defineLocale('en-gb', {
+    months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),
+    monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),
+    weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
+    weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
+    weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[Today at] LT',
+        nextDay : '[Tomorrow at] LT',
+        nextWeek : 'dddd [at] LT',
+        lastDay : '[Yesterday at] LT',
+        lastWeek : '[Last] dddd [at] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'in %s',
+        past : '%s ago',
+        s : 'a few seconds',
+        m : 'a minute',
+        mm : '%d minutes',
+        h : 'an hour',
+        hh : '%d hours',
+        d : 'a day',
+        dd : '%d days',
+        M : 'a month',
+        MM : '%d months',
+        y : 'a year',
+        yy : '%d years'
+    },
+    ordinalParse: /\d{1,2}(st|nd|rd|th)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return enGb;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/en-ie.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/en-ie.js
new file mode 100644
index 0000000000000000000000000000000000000000..54c3065ebe752ea8844252fabe4f524b59497baf
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/en-ie.js
@@ -0,0 +1,67 @@
+//! moment.js locale configuration
+//! locale : English (Ireland) [en-ie]
+//! author : Chris Cartlidge : https://github.com/chriscartlidge
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var enIe = moment.defineLocale('en-ie', {
+    months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),
+    monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),
+    weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
+    weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
+    weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD-MM-YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[Today at] LT',
+        nextDay : '[Tomorrow at] LT',
+        nextWeek : 'dddd [at] LT',
+        lastDay : '[Yesterday at] LT',
+        lastWeek : '[Last] dddd [at] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'in %s',
+        past : '%s ago',
+        s : 'a few seconds',
+        m : 'a minute',
+        mm : '%d minutes',
+        h : 'an hour',
+        hh : '%d hours',
+        d : 'a day',
+        dd : '%d days',
+        M : 'a month',
+        MM : '%d months',
+        y : 'a year',
+        yy : '%d years'
+    },
+    ordinalParse: /\d{1,2}(st|nd|rd|th)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return enIe;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/en-nz.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/en-nz.js
new file mode 100644
index 0000000000000000000000000000000000000000..c6c60302c6530a5358cf515a2cf7376bd5db3bad
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/en-nz.js
@@ -0,0 +1,67 @@
+//! moment.js locale configuration
+//! locale : English (New Zealand) [en-nz]
+//! author : Luke McGregor : https://github.com/lukemcgregor
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var enNz = moment.defineLocale('en-nz', {
+    months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),
+    monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),
+    weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
+    weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
+    weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'h:mm A',
+        LTS : 'h:mm:ss A',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY h:mm A',
+        LLLL : 'dddd, D MMMM YYYY h:mm A'
+    },
+    calendar : {
+        sameDay : '[Today at] LT',
+        nextDay : '[Tomorrow at] LT',
+        nextWeek : 'dddd [at] LT',
+        lastDay : '[Yesterday at] LT',
+        lastWeek : '[Last] dddd [at] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'in %s',
+        past : '%s ago',
+        s : 'a few seconds',
+        m : 'a minute',
+        mm : '%d minutes',
+        h : 'an hour',
+        hh : '%d hours',
+        d : 'a day',
+        dd : '%d days',
+        M : 'a month',
+        MM : '%d months',
+        y : 'a year',
+        yy : '%d years'
+    },
+    ordinalParse: /\d{1,2}(st|nd|rd|th)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return enNz;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/eo.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/eo.js
new file mode 100644
index 0000000000000000000000000000000000000000..75193181b910c97ee9c735789496fb136b25366f
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/eo.js
@@ -0,0 +1,73 @@
+//! moment.js locale configuration
+//! locale : Esperanto [eo]
+//! author : Colin Dean : https://github.com/colindean
+//! komento: Mi estas malcerta se mi korekte traktis akuzativojn en tiu traduko.
+//!          Se ne, bonvolu korekti kaj avizi min por ke mi povas lerni!
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var eo = moment.defineLocale('eo', {
+    months : 'januaro_februaro_marto_aprilo_majo_junio_julio_aÅ­gusto_septembro_oktobro_novembro_decembro'.split('_'),
+    monthsShort : 'jan_feb_mar_apr_maj_jun_jul_aÅ­g_sep_okt_nov_dec'.split('_'),
+    weekdays : 'Dimanĉo_Lundo_Mardo_Merkredo_Ĵaŭdo_Vendredo_Sabato'.split('_'),
+    weekdaysShort : 'Dim_Lun_Mard_Merk_Ä´aÅ­_Ven_Sab'.split('_'),
+    weekdaysMin : 'Di_Lu_Ma_Me_Ä´a_Ve_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'YYYY-MM-DD',
+        LL : 'D[-an de] MMMM, YYYY',
+        LLL : 'D[-an de] MMMM, YYYY HH:mm',
+        LLLL : 'dddd, [la] D[-an de] MMMM, YYYY HH:mm'
+    },
+    meridiemParse: /[ap]\.t\.m/i,
+    isPM: function (input) {
+        return input.charAt(0).toLowerCase() === 'p';
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours > 11) {
+            return isLower ? 'p.t.m.' : 'P.T.M.';
+        } else {
+            return isLower ? 'a.t.m.' : 'A.T.M.';
+        }
+    },
+    calendar : {
+        sameDay : '[HodiaÅ­ je] LT',
+        nextDay : '[MorgaÅ­ je] LT',
+        nextWeek : 'dddd [je] LT',
+        lastDay : '[HieraÅ­ je] LT',
+        lastWeek : '[pasinta] dddd [je] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'je %s',
+        past : 'antaÅ­ %s',
+        s : 'sekundoj',
+        m : 'minuto',
+        mm : '%d minutoj',
+        h : 'horo',
+        hh : '%d horoj',
+        d : 'tago',//ne 'diurno', ĉar estas uzita por proksimumo
+        dd : '%d tagoj',
+        M : 'monato',
+        MM : '%d monatoj',
+        y : 'jaro',
+        yy : '%d jaroj'
+    },
+    ordinalParse: /\d{1,2}a/,
+    ordinal : '%da',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return eo;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/es-do.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/es-do.js
new file mode 100644
index 0000000000000000000000000000000000000000..e86282ad0cdb8a5ce498b8f034b2844e5d528798
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/es-do.js
@@ -0,0 +1,80 @@
+//! moment.js locale configuration
+//! locale : Spanish (Dominican Republic) [es-do]
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var monthsShortDot = 'ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.'.split('_');
+var monthsShort = 'ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic'.split('_');
+
+var esDo = moment.defineLocale('es-do', {
+    months : 'enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre'.split('_'),
+    monthsShort : function (m, format) {
+        if (/-MMM-/.test(format)) {
+            return monthsShort[m.month()];
+        } else {
+            return monthsShortDot[m.month()];
+        }
+    },
+    monthsParseExact : true,
+    weekdays : 'domingo_lunes_martes_miércoles_jueves_viernes_sábado'.split('_'),
+    weekdaysShort : 'dom._lun._mar._mié._jue._vie._sáb.'.split('_'),
+    weekdaysMin : 'do_lu_ma_mi_ju_vi_sá'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'h:mm A',
+        LTS : 'h:mm:ss A',
+        L : 'DD/MM/YYYY',
+        LL : 'D [de] MMMM [de] YYYY',
+        LLL : 'D [de] MMMM [de] YYYY h:mm A',
+        LLLL : 'dddd, D [de] MMMM [de] YYYY h:mm A'
+    },
+    calendar : {
+        sameDay : function () {
+            return '[hoy a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        nextDay : function () {
+            return '[mañana a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        nextWeek : function () {
+            return 'dddd [a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        lastDay : function () {
+            return '[ayer a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        lastWeek : function () {
+            return '[el] dddd [pasado a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'en %s',
+        past : 'hace %s',
+        s : 'unos segundos',
+        m : 'un minuto',
+        mm : '%d minutos',
+        h : 'una hora',
+        hh : '%d horas',
+        d : 'un día',
+        dd : '%d días',
+        M : 'un mes',
+        MM : '%d meses',
+        y : 'un año',
+        yy : '%d años'
+    },
+    ordinalParse : /\d{1,2}º/,
+    ordinal : '%dº',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return esDo;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/es.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/es.js
new file mode 100644
index 0000000000000000000000000000000000000000..eb9e0809dfebdbf575f116f47782e90c600772a2
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/es.js
@@ -0,0 +1,81 @@
+//! moment.js locale configuration
+//! locale : Spanish [es]
+//! author : Julio Napurí : https://github.com/julionc
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var monthsShortDot = 'ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.'.split('_');
+var monthsShort = 'ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic'.split('_');
+
+var es = moment.defineLocale('es', {
+    months : 'enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre'.split('_'),
+    monthsShort : function (m, format) {
+        if (/-MMM-/.test(format)) {
+            return monthsShort[m.month()];
+        } else {
+            return monthsShortDot[m.month()];
+        }
+    },
+    monthsParseExact : true,
+    weekdays : 'domingo_lunes_martes_miércoles_jueves_viernes_sábado'.split('_'),
+    weekdaysShort : 'dom._lun._mar._mié._jue._vie._sáb.'.split('_'),
+    weekdaysMin : 'do_lu_ma_mi_ju_vi_sá'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D [de] MMMM [de] YYYY',
+        LLL : 'D [de] MMMM [de] YYYY H:mm',
+        LLLL : 'dddd, D [de] MMMM [de] YYYY H:mm'
+    },
+    calendar : {
+        sameDay : function () {
+            return '[hoy a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        nextDay : function () {
+            return '[mañana a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        nextWeek : function () {
+            return 'dddd [a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        lastDay : function () {
+            return '[ayer a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        lastWeek : function () {
+            return '[el] dddd [pasado a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'en %s',
+        past : 'hace %s',
+        s : 'unos segundos',
+        m : 'un minuto',
+        mm : '%d minutos',
+        h : 'una hora',
+        hh : '%d horas',
+        d : 'un día',
+        dd : '%d días',
+        M : 'un mes',
+        MM : '%d meses',
+        y : 'un año',
+        yy : '%d años'
+    },
+    ordinalParse : /\d{1,2}º/,
+    ordinal : '%dº',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return es;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/et.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/et.js
new file mode 100644
index 0000000000000000000000000000000000000000..dc40ac5044a46b1e7407851f4d372d10bcb462be
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/et.js
@@ -0,0 +1,80 @@
+//! moment.js locale configuration
+//! locale : Estonian [et]
+//! author : Henry Kehlmann : https://github.com/madhenry
+//! improvements : Illimar Tambek : https://github.com/ragulka
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+function processRelativeTime(number, withoutSuffix, key, isFuture) {
+    var format = {
+        's' : ['mõne sekundi', 'mõni sekund', 'paar sekundit'],
+        'm' : ['ühe minuti', 'üks minut'],
+        'mm': [number + ' minuti', number + ' minutit'],
+        'h' : ['ühe tunni', 'tund aega', 'üks tund'],
+        'hh': [number + ' tunni', number + ' tundi'],
+        'd' : ['ühe päeva', 'üks päev'],
+        'M' : ['kuu aja', 'kuu aega', 'üks kuu'],
+        'MM': [number + ' kuu', number + ' kuud'],
+        'y' : ['ühe aasta', 'aasta', 'üks aasta'],
+        'yy': [number + ' aasta', number + ' aastat']
+    };
+    if (withoutSuffix) {
+        return format[key][2] ? format[key][2] : format[key][1];
+    }
+    return isFuture ? format[key][0] : format[key][1];
+}
+
+var et = moment.defineLocale('et', {
+    months        : 'jaanuar_veebruar_märts_aprill_mai_juuni_juuli_august_september_oktoober_november_detsember'.split('_'),
+    monthsShort   : 'jaan_veebr_märts_apr_mai_juuni_juuli_aug_sept_okt_nov_dets'.split('_'),
+    weekdays      : 'pühapäev_esmaspäev_teisipäev_kolmapäev_neljapäev_reede_laupäev'.split('_'),
+    weekdaysShort : 'P_E_T_K_N_R_L'.split('_'),
+    weekdaysMin   : 'P_E_T_K_N_R_L'.split('_'),
+    longDateFormat : {
+        LT   : 'H:mm',
+        LTS : 'H:mm:ss',
+        L    : 'DD.MM.YYYY',
+        LL   : 'D. MMMM YYYY',
+        LLL  : 'D. MMMM YYYY H:mm',
+        LLLL : 'dddd, D. MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay  : '[Täna,] LT',
+        nextDay  : '[Homme,] LT',
+        nextWeek : '[Järgmine] dddd LT',
+        lastDay  : '[Eile,] LT',
+        lastWeek : '[Eelmine] dddd LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s pärast',
+        past   : '%s tagasi',
+        s      : processRelativeTime,
+        m      : processRelativeTime,
+        mm     : processRelativeTime,
+        h      : processRelativeTime,
+        hh     : processRelativeTime,
+        d      : processRelativeTime,
+        dd     : '%d päeva',
+        M      : processRelativeTime,
+        MM     : processRelativeTime,
+        y      : processRelativeTime,
+        yy     : processRelativeTime
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return et;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/eu.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/eu.js
new file mode 100644
index 0000000000000000000000000000000000000000..7db2443b70adecf8d618b7bde995d0b9bd042fda
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/eu.js
@@ -0,0 +1,66 @@
+//! moment.js locale configuration
+//! locale : Basque [eu]
+//! author : Eneko Illarramendi : https://github.com/eillarra
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var eu = moment.defineLocale('eu', {
+    months : 'urtarrila_otsaila_martxoa_apirila_maiatza_ekaina_uztaila_abuztua_iraila_urria_azaroa_abendua'.split('_'),
+    monthsShort : 'urt._ots._mar._api._mai._eka._uzt._abu._ira._urr._aza._abe.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'igandea_astelehena_asteartea_asteazkena_osteguna_ostirala_larunbata'.split('_'),
+    weekdaysShort : 'ig._al._ar._az._og._ol._lr.'.split('_'),
+    weekdaysMin : 'ig_al_ar_az_og_ol_lr'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'YYYY-MM-DD',
+        LL : 'YYYY[ko] MMMM[ren] D[a]',
+        LLL : 'YYYY[ko] MMMM[ren] D[a] HH:mm',
+        LLLL : 'dddd, YYYY[ko] MMMM[ren] D[a] HH:mm',
+        l : 'YYYY-M-D',
+        ll : 'YYYY[ko] MMM D[a]',
+        lll : 'YYYY[ko] MMM D[a] HH:mm',
+        llll : 'ddd, YYYY[ko] MMM D[a] HH:mm'
+    },
+    calendar : {
+        sameDay : '[gaur] LT[etan]',
+        nextDay : '[bihar] LT[etan]',
+        nextWeek : 'dddd LT[etan]',
+        lastDay : '[atzo] LT[etan]',
+        lastWeek : '[aurreko] dddd LT[etan]',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s barru',
+        past : 'duela %s',
+        s : 'segundo batzuk',
+        m : 'minutu bat',
+        mm : '%d minutu',
+        h : 'ordu bat',
+        hh : '%d ordu',
+        d : 'egun bat',
+        dd : '%d egun',
+        M : 'hilabete bat',
+        MM : '%d hilabete',
+        y : 'urte bat',
+        yy : '%d urte'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return eu;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/fa.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/fa.js
new file mode 100644
index 0000000000000000000000000000000000000000..7743b4f4f5aec1ed1c6cc71756e9bd5a648366b6
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/fa.js
@@ -0,0 +1,107 @@
+//! moment.js locale configuration
+//! locale : Persian [fa]
+//! author : Ebrahim Byagowi : https://github.com/ebraminio
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var symbolMap = {
+    '1': 'Û±',
+    '2': 'Û²',
+    '3': 'Û³',
+    '4': 'Û´',
+    '5': 'Ûµ',
+    '6': 'Û¶',
+    '7': 'Û·',
+    '8': 'Û¸',
+    '9': 'Û¹',
+    '0': 'Û°'
+};
+var numberMap = {
+    'Û±': '1',
+    'Û²': '2',
+    'Û³': '3',
+    'Û´': '4',
+    'Ûµ': '5',
+    'Û¶': '6',
+    'Û·': '7',
+    'Û¸': '8',
+    'Û¹': '9',
+    'Û°': '0'
+};
+
+var fa = moment.defineLocale('fa', {
+    months : 'ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر'.split('_'),
+    monthsShort : 'ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر'.split('_'),
+    weekdays : 'یک\u200cشنبه_دوشنبه_سه\u200cشنبه_چهارشنبه_پنج\u200cشنبه_جمعه_شنبه'.split('_'),
+    weekdaysShort : 'یک\u200cشنبه_دوشنبه_سه\u200cشنبه_چهارشنبه_پنج\u200cشنبه_جمعه_شنبه'.split('_'),
+    weekdaysMin : 'ی_د_س_چ_پ_ج_ش'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    meridiemParse: /قبل از ظهر|بعد از ظهر/,
+    isPM: function (input) {
+        return /بعد از ظهر/.test(input);
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return 'قبل از ظهر';
+        } else {
+            return 'بعد از ظهر';
+        }
+    },
+    calendar : {
+        sameDay : '[امروز ساعت] LT',
+        nextDay : '[فردا ساعت] LT',
+        nextWeek : 'dddd [ساعت] LT',
+        lastDay : '[دیروز ساعت] LT',
+        lastWeek : 'dddd [پیش] [ساعت] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'در %s',
+        past : '%s پیش',
+        s : 'چندین ثانیه',
+        m : 'یک دقیقه',
+        mm : '%d دقیقه',
+        h : 'یک ساعت',
+        hh : '%d ساعت',
+        d : 'یک روز',
+        dd : '%d روز',
+        M : 'یک ماه',
+        MM : '%d ماه',
+        y : 'یک سال',
+        yy : '%d سال'
+    },
+    preparse: function (string) {
+        return string.replace(/[Û°-Û¹]/g, function (match) {
+            return numberMap[match];
+        }).replace(/،/g, ',');
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap[match];
+        }).replace(/,/g, '،');
+    },
+    ordinalParse: /\d{1,2}Ù…/,
+    ordinal : '%dÙ…',
+    week : {
+        dow : 6, // Saturday is the first day of the week.
+        doy : 12 // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return fa;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/fi.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/fi.js
new file mode 100644
index 0000000000000000000000000000000000000000..4cbe4eec6d34a48ef8e3f08ca9ec63bb92e832d4
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/fi.js
@@ -0,0 +1,107 @@
+//! moment.js locale configuration
+//! locale : Finnish [fi]
+//! author : Tarmo Aidantausta : https://github.com/bleadof
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var numbersPast = 'nolla yksi kaksi kolme neljä viisi kuusi seitsemän kahdeksan yhdeksän'.split(' ');
+var numbersFuture = [
+        'nolla', 'yhden', 'kahden', 'kolmen', 'neljän', 'viiden', 'kuuden',
+        numbersPast[7], numbersPast[8], numbersPast[9]
+    ];
+function translate(number, withoutSuffix, key, isFuture) {
+    var result = '';
+    switch (key) {
+        case 's':
+            return isFuture ? 'muutaman sekunnin' : 'muutama sekunti';
+        case 'm':
+            return isFuture ? 'minuutin' : 'minuutti';
+        case 'mm':
+            result = isFuture ? 'minuutin' : 'minuuttia';
+            break;
+        case 'h':
+            return isFuture ? 'tunnin' : 'tunti';
+        case 'hh':
+            result = isFuture ? 'tunnin' : 'tuntia';
+            break;
+        case 'd':
+            return isFuture ? 'päivän' : 'päivä';
+        case 'dd':
+            result = isFuture ? 'päivän' : 'päivää';
+            break;
+        case 'M':
+            return isFuture ? 'kuukauden' : 'kuukausi';
+        case 'MM':
+            result = isFuture ? 'kuukauden' : 'kuukautta';
+            break;
+        case 'y':
+            return isFuture ? 'vuoden' : 'vuosi';
+        case 'yy':
+            result = isFuture ? 'vuoden' : 'vuotta';
+            break;
+    }
+    result = verbalNumber(number, isFuture) + ' ' + result;
+    return result;
+}
+function verbalNumber(number, isFuture) {
+    return number < 10 ? (isFuture ? numbersFuture[number] : numbersPast[number]) : number;
+}
+
+var fi = moment.defineLocale('fi', {
+    months : 'tammikuu_helmikuu_maaliskuu_huhtikuu_toukokuu_kesäkuu_heinäkuu_elokuu_syyskuu_lokakuu_marraskuu_joulukuu'.split('_'),
+    monthsShort : 'tammi_helmi_maalis_huhti_touko_kesä_heinä_elo_syys_loka_marras_joulu'.split('_'),
+    weekdays : 'sunnuntai_maanantai_tiistai_keskiviikko_torstai_perjantai_lauantai'.split('_'),
+    weekdaysShort : 'su_ma_ti_ke_to_pe_la'.split('_'),
+    weekdaysMin : 'su_ma_ti_ke_to_pe_la'.split('_'),
+    longDateFormat : {
+        LT : 'HH.mm',
+        LTS : 'HH.mm.ss',
+        L : 'DD.MM.YYYY',
+        LL : 'Do MMMM[ta] YYYY',
+        LLL : 'Do MMMM[ta] YYYY, [klo] HH.mm',
+        LLLL : 'dddd, Do MMMM[ta] YYYY, [klo] HH.mm',
+        l : 'D.M.YYYY',
+        ll : 'Do MMM YYYY',
+        lll : 'Do MMM YYYY, [klo] HH.mm',
+        llll : 'ddd, Do MMM YYYY, [klo] HH.mm'
+    },
+    calendar : {
+        sameDay : '[tänään] [klo] LT',
+        nextDay : '[huomenna] [klo] LT',
+        nextWeek : 'dddd [klo] LT',
+        lastDay : '[eilen] [klo] LT',
+        lastWeek : '[viime] dddd[na] [klo] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s päästä',
+        past : '%s sitten',
+        s : translate,
+        m : translate,
+        mm : translate,
+        h : translate,
+        hh : translate,
+        d : translate,
+        dd : translate,
+        M : translate,
+        MM : translate,
+        y : translate,
+        yy : translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return fi;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/fo.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/fo.js
new file mode 100644
index 0000000000000000000000000000000000000000..344ab5eed4dfd936b8df80ff394df24558fa1a5e
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/fo.js
@@ -0,0 +1,60 @@
+//! moment.js locale configuration
+//! locale : Faroese [fo]
+//! author : Ragnar Johannesen : https://github.com/ragnar123
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var fo = moment.defineLocale('fo', {
+    months : 'januar_februar_mars_apríl_mai_juni_juli_august_september_oktober_november_desember'.split('_'),
+    monthsShort : 'jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_'),
+    weekdays : 'sunnudagur_mánadagur_týsdagur_mikudagur_hósdagur_fríggjadagur_leygardagur'.split('_'),
+    weekdaysShort : 'sun_mán_týs_mik_hós_frí_ley'.split('_'),
+    weekdaysMin : 'su_má_tý_mi_hó_fr_le'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D. MMMM, YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[Í dag kl.] LT',
+        nextDay : '[Í morgin kl.] LT',
+        nextWeek : 'dddd [kl.] LT',
+        lastDay : '[Í gjár kl.] LT',
+        lastWeek : '[síðstu] dddd [kl] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'um %s',
+        past : '%s síðani',
+        s : 'fá sekund',
+        m : 'ein minutt',
+        mm : '%d minuttir',
+        h : 'ein tími',
+        hh : '%d tímar',
+        d : 'ein dagur',
+        dd : '%d dagar',
+        M : 'ein mánaði',
+        MM : '%d mánaðir',
+        y : 'eitt ár',
+        yy : '%d ár'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return fo;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/fr-ca.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/fr-ca.js
new file mode 100644
index 0000000000000000000000000000000000000000..9aada335e3d927c9aa3bd69e1270a68e6b296c11
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/fr-ca.js
@@ -0,0 +1,60 @@
+//! moment.js locale configuration
+//! locale : French (Canada) [fr-ca]
+//! author : Jonathan Abourbih : https://github.com/jonbca
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var frCa = moment.defineLocale('fr-ca', {
+    months : 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split('_'),
+    monthsShort : 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'),
+    weekdaysShort : 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'),
+    weekdaysMin : 'Di_Lu_Ma_Me_Je_Ve_Sa'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'YYYY-MM-DD',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Aujourd\'hui à] LT',
+        nextDay: '[Demain à] LT',
+        nextWeek: 'dddd [à] LT',
+        lastDay: '[Hier à] LT',
+        lastWeek: 'dddd [dernier à] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'dans %s',
+        past : 'il y a %s',
+        s : 'quelques secondes',
+        m : 'une minute',
+        mm : '%d minutes',
+        h : 'une heure',
+        hh : '%d heures',
+        d : 'un jour',
+        dd : '%d jours',
+        M : 'un mois',
+        MM : '%d mois',
+        y : 'un an',
+        yy : '%d ans'
+    },
+    ordinalParse: /\d{1,2}(er|e)/,
+    ordinal : function (number) {
+        return number + (number === 1 ? 'er' : 'e');
+    }
+});
+
+return frCa;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/fr-ch.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/fr-ch.js
new file mode 100644
index 0000000000000000000000000000000000000000..aade5acbe91364b90a19e4cad4455147ce44a05b
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/fr-ch.js
@@ -0,0 +1,64 @@
+//! moment.js locale configuration
+//! locale : French (Switzerland) [fr-ch]
+//! author : Gaspard Bucher : https://github.com/gaspard
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var frCh = moment.defineLocale('fr-ch', {
+    months : 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split('_'),
+    monthsShort : 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'),
+    weekdaysShort : 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'),
+    weekdaysMin : 'Di_Lu_Ma_Me_Je_Ve_Sa'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Aujourd\'hui à] LT',
+        nextDay: '[Demain à] LT',
+        nextWeek: 'dddd [à] LT',
+        lastDay: '[Hier à] LT',
+        lastWeek: 'dddd [dernier à] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'dans %s',
+        past : 'il y a %s',
+        s : 'quelques secondes',
+        m : 'une minute',
+        mm : '%d minutes',
+        h : 'une heure',
+        hh : '%d heures',
+        d : 'un jour',
+        dd : '%d jours',
+        M : 'un mois',
+        MM : '%d mois',
+        y : 'un an',
+        yy : '%d ans'
+    },
+    ordinalParse: /\d{1,2}(er|e)/,
+    ordinal : function (number) {
+        return number + (number === 1 ? 'er' : 'e');
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return frCh;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/fr.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/fr.js
new file mode 100644
index 0000000000000000000000000000000000000000..8079ee755ade608477aae3389f60657e8beb6805
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/fr.js
@@ -0,0 +1,64 @@
+//! moment.js locale configuration
+//! locale : French [fr]
+//! author : John Fischer : https://github.com/jfroffice
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var fr = moment.defineLocale('fr', {
+    months : 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split('_'),
+    monthsShort : 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'),
+    weekdaysShort : 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'),
+    weekdaysMin : 'Di_Lu_Ma_Me_Je_Ve_Sa'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Aujourd\'hui à] LT',
+        nextDay: '[Demain à] LT',
+        nextWeek: 'dddd [à] LT',
+        lastDay: '[Hier à] LT',
+        lastWeek: 'dddd [dernier à] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'dans %s',
+        past : 'il y a %s',
+        s : 'quelques secondes',
+        m : 'une minute',
+        mm : '%d minutes',
+        h : 'une heure',
+        hh : '%d heures',
+        d : 'un jour',
+        dd : '%d jours',
+        M : 'un mois',
+        MM : '%d mois',
+        y : 'un an',
+        yy : '%d ans'
+    },
+    ordinalParse: /\d{1,2}(er|)/,
+    ordinal : function (number) {
+        return number + (number === 1 ? 'er' : '');
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return fr;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/fy.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/fy.js
new file mode 100644
index 0000000000000000000000000000000000000000..13a32d80eedda92ef510278484239b79b0485c26
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/fy.js
@@ -0,0 +1,73 @@
+//! moment.js locale configuration
+//! locale : Frisian [fy]
+//! author : Robin van der Vliet : https://github.com/robin0van0der0v
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var monthsShortWithDots = 'jan._feb._mrt._apr._mai_jun._jul._aug._sep._okt._nov._des.'.split('_');
+var monthsShortWithoutDots = 'jan_feb_mrt_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_');
+
+var fy = moment.defineLocale('fy', {
+    months : 'jannewaris_febrewaris_maart_april_maaie_juny_july_augustus_septimber_oktober_novimber_desimber'.split('_'),
+    monthsShort : function (m, format) {
+        if (/-MMM-/.test(format)) {
+            return monthsShortWithoutDots[m.month()];
+        } else {
+            return monthsShortWithDots[m.month()];
+        }
+    },
+    monthsParseExact : true,
+    weekdays : 'snein_moandei_tiisdei_woansdei_tongersdei_freed_sneon'.split('_'),
+    weekdaysShort : 'si._mo._ti._wo._to._fr._so.'.split('_'),
+    weekdaysMin : 'Si_Mo_Ti_Wo_To_Fr_So'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD-MM-YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[hjoed om] LT',
+        nextDay: '[moarn om] LT',
+        nextWeek: 'dddd [om] LT',
+        lastDay: '[juster om] LT',
+        lastWeek: '[ôfrûne] dddd [om] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'oer %s',
+        past : '%s lyn',
+        s : 'in pear sekonden',
+        m : 'ien minút',
+        mm : '%d minuten',
+        h : 'ien oere',
+        hh : '%d oeren',
+        d : 'ien dei',
+        dd : '%d dagen',
+        M : 'ien moanne',
+        MM : '%d moannen',
+        y : 'ien jier',
+        yy : '%d jierren'
+    },
+    ordinalParse: /\d{1,2}(ste|de)/,
+    ordinal : function (number) {
+        return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de');
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return fy;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/gd.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/gd.js
new file mode 100644
index 0000000000000000000000000000000000000000..542005e14b582c0c87932e43d197d528221f6704
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/gd.js
@@ -0,0 +1,76 @@
+//! moment.js locale configuration
+//! locale : Scottish Gaelic [gd]
+//! author : Jon Ashdown : https://github.com/jonashdown
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var months = [
+    'Am Faoilleach', 'An Gearran', 'Am Màrt', 'An Giblean', 'An Cèitean', 'An t-Ògmhios', 'An t-Iuchar', 'An Lùnastal', 'An t-Sultain', 'An Dàmhair', 'An t-Samhain', 'An Dùbhlachd'
+];
+
+var monthsShort = ['Faoi', 'Gear', 'Màrt', 'Gibl', 'Cèit', 'Ògmh', 'Iuch', 'Lùn', 'Sult', 'Dàmh', 'Samh', 'Dùbh'];
+
+var weekdays = ['Didòmhnaich', 'Diluain', 'Dimàirt', 'Diciadain', 'Diardaoin', 'Dihaoine', 'Disathairne'];
+
+var weekdaysShort = ['Did', 'Dil', 'Dim', 'Dic', 'Dia', 'Dih', 'Dis'];
+
+var weekdaysMin = ['Dò', 'Lu', 'Mà', 'Ci', 'Ar', 'Ha', 'Sa'];
+
+var gd = moment.defineLocale('gd', {
+    months : months,
+    monthsShort : monthsShort,
+    monthsParseExact : true,
+    weekdays : weekdays,
+    weekdaysShort : weekdaysShort,
+    weekdaysMin : weekdaysMin,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[An-diugh aig] LT',
+        nextDay : '[A-màireach aig] LT',
+        nextWeek : 'dddd [aig] LT',
+        lastDay : '[An-dè aig] LT',
+        lastWeek : 'dddd [seo chaidh] [aig] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'ann an %s',
+        past : 'bho chionn %s',
+        s : 'beagan diogan',
+        m : 'mionaid',
+        mm : '%d mionaidean',
+        h : 'uair',
+        hh : '%d uairean',
+        d : 'latha',
+        dd : '%d latha',
+        M : 'mìos',
+        MM : '%d mìosan',
+        y : 'bliadhna',
+        yy : '%d bliadhna'
+    },
+    ordinalParse : /\d{1,2}(d|na|mh)/,
+    ordinal : function (number) {
+        var output = number === 1 ? 'd' : number % 10 === 2 ? 'na' : 'mh';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return gd;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/gl.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/gl.js
new file mode 100644
index 0000000000000000000000000000000000000000..205819eea189641af0cfc0d9fc83854c3d1ff969
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/gl.js
@@ -0,0 +1,77 @@
+//! moment.js locale configuration
+//! locale : Galician [gl]
+//! author : Juan G. Hurtado : https://github.com/juanghurtado
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var gl = moment.defineLocale('gl', {
+    months : 'xaneiro_febreiro_marzo_abril_maio_xuño_xullo_agosto_setembro_outubro_novembro_decembro'.split('_'),
+    monthsShort : 'xan._feb._mar._abr._mai._xuñ._xul._ago._set._out._nov._dec.'.split('_'),
+    monthsParseExact: true,
+    weekdays : 'domingo_luns_martes_mércores_xoves_venres_sábado'.split('_'),
+    weekdaysShort : 'dom._lun._mar._mér._xov._ven._sáb.'.split('_'),
+    weekdaysMin : 'do_lu_ma_mé_xo_ve_sá'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D [de] MMMM [de] YYYY',
+        LLL : 'D [de] MMMM [de] YYYY H:mm',
+        LLLL : 'dddd, D [de] MMMM [de] YYYY H:mm'
+    },
+    calendar : {
+        sameDay : function () {
+            return '[hoxe ' + ((this.hours() !== 1) ? 'ás' : 'á') + '] LT';
+        },
+        nextDay : function () {
+            return '[mañá ' + ((this.hours() !== 1) ? 'ás' : 'á') + '] LT';
+        },
+        nextWeek : function () {
+            return 'dddd [' + ((this.hours() !== 1) ? 'ás' : 'a') + '] LT';
+        },
+        lastDay : function () {
+            return '[onte ' + ((this.hours() !== 1) ? 'á' : 'a') + '] LT';
+        },
+        lastWeek : function () {
+            return '[o] dddd [pasado ' + ((this.hours() !== 1) ? 'ás' : 'a') + '] LT';
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : function (str) {
+            if (str.indexOf('un') === 0) {
+                return 'n' + str;
+            }
+            return 'en ' + str;
+        },
+        past : 'hai %s',
+        s : 'uns segundos',
+        m : 'un minuto',
+        mm : '%d minutos',
+        h : 'unha hora',
+        hh : '%d horas',
+        d : 'un día',
+        dd : '%d días',
+        M : 'un mes',
+        MM : '%d meses',
+        y : 'un ano',
+        yy : '%d anos'
+    },
+    ordinalParse : /\d{1,2}º/,
+    ordinal : '%dº',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return gl;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/he.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/he.js
new file mode 100644
index 0000000000000000000000000000000000000000..e884381105bf87c27dbd8668e0881e3e6835f854
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/he.js
@@ -0,0 +1,99 @@
+//! moment.js locale configuration
+//! locale : Hebrew [he]
+//! author : Tomer Cohen : https://github.com/tomer
+//! author : Moshe Simantov : https://github.com/DevelopmentIL
+//! author : Tal Ater : https://github.com/TalAter
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var he = moment.defineLocale('he', {
+    months : 'ינואר_פברואר_מרץ_אפריל_מאי_יוני_יולי_אוגוסט_ספטמבר_אוקטובר_נובמבר_דצמבר'.split('_'),
+    monthsShort : 'ינו׳_פבר׳_מרץ_אפר׳_מאי_יוני_יולי_אוג׳_ספט׳_אוק׳_נוב׳_דצמ׳'.split('_'),
+    weekdays : 'ראשון_שני_שלישי_רביעי_חמישי_שישי_שבת'.split('_'),
+    weekdaysShort : 'א׳_ב׳_ג׳_ד׳_ה׳_ו׳_ש׳'.split('_'),
+    weekdaysMin : 'א_ב_ג_ד_ה_ו_ש'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D [ב]MMMM YYYY',
+        LLL : 'D [ב]MMMM YYYY HH:mm',
+        LLLL : 'dddd, D [ב]MMMM YYYY HH:mm',
+        l : 'D/M/YYYY',
+        ll : 'D MMM YYYY',
+        lll : 'D MMM YYYY HH:mm',
+        llll : 'ddd, D MMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[היום ב־]LT',
+        nextDay : '[מחר ב־]LT',
+        nextWeek : 'dddd [בשעה] LT',
+        lastDay : '[אתמול ב־]LT',
+        lastWeek : '[ביום] dddd [האחרון בשעה] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'בעוד %s',
+        past : 'לפני %s',
+        s : 'מספר שניות',
+        m : 'דקה',
+        mm : '%d דקות',
+        h : 'שעה',
+        hh : function (number) {
+            if (number === 2) {
+                return 'שעתיים';
+            }
+            return number + ' שעות';
+        },
+        d : 'יום',
+        dd : function (number) {
+            if (number === 2) {
+                return 'יומיים';
+            }
+            return number + ' ימים';
+        },
+        M : 'חודש',
+        MM : function (number) {
+            if (number === 2) {
+                return 'חודשיים';
+            }
+            return number + ' חודשים';
+        },
+        y : 'שנה',
+        yy : function (number) {
+            if (number === 2) {
+                return 'שנתיים';
+            } else if (number % 10 === 0 && number !== 10) {
+                return number + ' שנה';
+            }
+            return number + ' שנים';
+        }
+    },
+    meridiemParse: /אחה"צ|לפנה"צ|אחרי הצהריים|לפני הצהריים|לפנות בוקר|בבוקר|בערב/i,
+    isPM : function (input) {
+        return /^(אחה"צ|אחרי הצהריים|בערב)$/.test(input);
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 5) {
+            return 'לפנות בוקר';
+        } else if (hour < 10) {
+            return 'בבוקר';
+        } else if (hour < 12) {
+            return isLower ? 'לפנה"צ' : 'לפני הצהריים';
+        } else if (hour < 18) {
+            return isLower ? 'אחה"צ' : 'אחרי הצהריים';
+        } else {
+            return 'בערב';
+        }
+    }
+});
+
+return he;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/hi.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/hi.js
new file mode 100644
index 0000000000000000000000000000000000000000..58afc6b1dd09871114d04f47bf59b191b85c2b46
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/hi.js
@@ -0,0 +1,124 @@
+//! moment.js locale configuration
+//! locale : Hindi [hi]
+//! author : Mayank Singhal : https://github.com/mayanksinghal
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var symbolMap = {
+    '1': '१',
+    '2': '२',
+    '3': '३',
+    '4': '४',
+    '5': '५',
+    '6': '६',
+    '7': '७',
+    '8': '८',
+    '9': '९',
+    '0': '०'
+};
+var numberMap = {
+    '१': '1',
+    '२': '2',
+    '३': '3',
+    '४': '4',
+    '५': '5',
+    '६': '6',
+    '७': '7',
+    '८': '8',
+    '९': '9',
+    '०': '0'
+};
+
+var hi = moment.defineLocale('hi', {
+    months : 'जनवरी_फ़रवरी_मार्च_अप्रैल_मई_जून_जुलाई_अगस्त_सितम्बर_अक्टूबर_नवम्बर_दिसम्बर'.split('_'),
+    monthsShort : 'जन._फ़र._मार्च_अप्रै._मई_जून_जुल._अग._सित._अक्टू._नव._दिस.'.split('_'),
+    monthsParseExact: true,
+    weekdays : 'रविवार_सोमवार_मंगलवार_बुधवार_गुरूवार_शुक्रवार_शनिवार'.split('_'),
+    weekdaysShort : 'रवि_सोम_मंगल_बुध_गुरू_शुक्र_शनि'.split('_'),
+    weekdaysMin : 'र_सो_मं_बु_गु_शु_श'.split('_'),
+    longDateFormat : {
+        LT : 'A h:mm बजे',
+        LTS : 'A h:mm:ss बजे',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, A h:mm बजे',
+        LLLL : 'dddd, D MMMM YYYY, A h:mm बजे'
+    },
+    calendar : {
+        sameDay : '[आज] LT',
+        nextDay : '[कल] LT',
+        nextWeek : 'dddd, LT',
+        lastDay : '[कल] LT',
+        lastWeek : '[पिछले] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s में',
+        past : '%s पहले',
+        s : 'कुछ ही क्षण',
+        m : 'एक मिनट',
+        mm : '%d मिनट',
+        h : 'एक घंटा',
+        hh : '%d घंटे',
+        d : 'एक दिन',
+        dd : '%d दिन',
+        M : 'एक महीने',
+        MM : '%d महीने',
+        y : 'एक वर्ष',
+        yy : '%d वर्ष'
+    },
+    preparse: function (string) {
+        return string.replace(/[१२३४५६७८९०]/g, function (match) {
+            return numberMap[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap[match];
+        });
+    },
+    // Hindi notation for meridiems are quite fuzzy in practice. While there exists
+    // a rigid notion of a 'Pahar' it is not used as rigidly in modern Hindi.
+    meridiemParse: /रात|सुबह|दोपहर|शाम/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'रात') {
+            return hour < 4 ? hour : hour + 12;
+        } else if (meridiem === 'सुबह') {
+            return hour;
+        } else if (meridiem === 'दोपहर') {
+            return hour >= 10 ? hour : hour + 12;
+        } else if (meridiem === 'शाम') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'रात';
+        } else if (hour < 10) {
+            return 'सुबह';
+        } else if (hour < 17) {
+            return 'दोपहर';
+        } else if (hour < 20) {
+            return 'शाम';
+        } else {
+            return 'रात';
+        }
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return hi;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/hr.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/hr.js
new file mode 100644
index 0000000000000000000000000000000000000000..c2e04e61db8a02f04214687d538b065baf20ae74
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/hr.js
@@ -0,0 +1,145 @@
+//! moment.js locale configuration
+//! locale : Croatian [hr]
+//! author : Bojan Marković : https://github.com/bmarkovic
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+function translate(number, withoutSuffix, key) {
+    var result = number + ' ';
+    switch (key) {
+        case 'm':
+            return withoutSuffix ? 'jedna minuta' : 'jedne minute';
+        case 'mm':
+            if (number === 1) {
+                result += 'minuta';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'minute';
+            } else {
+                result += 'minuta';
+            }
+            return result;
+        case 'h':
+            return withoutSuffix ? 'jedan sat' : 'jednog sata';
+        case 'hh':
+            if (number === 1) {
+                result += 'sat';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'sata';
+            } else {
+                result += 'sati';
+            }
+            return result;
+        case 'dd':
+            if (number === 1) {
+                result += 'dan';
+            } else {
+                result += 'dana';
+            }
+            return result;
+        case 'MM':
+            if (number === 1) {
+                result += 'mjesec';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'mjeseca';
+            } else {
+                result += 'mjeseci';
+            }
+            return result;
+        case 'yy':
+            if (number === 1) {
+                result += 'godina';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'godine';
+            } else {
+                result += 'godina';
+            }
+            return result;
+    }
+}
+
+var hr = moment.defineLocale('hr', {
+    months : {
+        format: 'siječnja_veljače_ožujka_travnja_svibnja_lipnja_srpnja_kolovoza_rujna_listopada_studenoga_prosinca'.split('_'),
+        standalone: 'siječanj_veljača_ožujak_travanj_svibanj_lipanj_srpanj_kolovoz_rujan_listopad_studeni_prosinac'.split('_')
+    },
+    monthsShort : 'sij._velj._ožu._tra._svi._lip._srp._kol._ruj._lis._stu._pro.'.split('_'),
+    monthsParseExact: true,
+    weekdays : 'nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota'.split('_'),
+    weekdaysShort : 'ned._pon._uto._sri._čet._pet._sub.'.split('_'),
+    weekdaysMin : 'ne_po_ut_sr_če_pe_su'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY H:mm',
+        LLLL : 'dddd, D. MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay  : '[danas u] LT',
+        nextDay  : '[sutra u] LT',
+        nextWeek : function () {
+            switch (this.day()) {
+                case 0:
+                    return '[u] [nedjelju] [u] LT';
+                case 3:
+                    return '[u] [srijedu] [u] LT';
+                case 6:
+                    return '[u] [subotu] [u] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[u] dddd [u] LT';
+            }
+        },
+        lastDay  : '[jučer u] LT',
+        lastWeek : function () {
+            switch (this.day()) {
+                case 0:
+                case 3:
+                    return '[prošlu] dddd [u] LT';
+                case 6:
+                    return '[prošle] [subote] [u] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[prošli] dddd [u] LT';
+            }
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'za %s',
+        past   : 'prije %s',
+        s      : 'par sekundi',
+        m      : translate,
+        mm     : translate,
+        h      : translate,
+        hh     : translate,
+        d      : 'dan',
+        dd     : translate,
+        M      : 'mjesec',
+        MM     : translate,
+        y      : 'godinu',
+        yy     : translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return hr;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/hu.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/hu.js
new file mode 100644
index 0000000000000000000000000000000000000000..c81036b2a839ee0d52e64ca405683508800a878c
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/hu.js
@@ -0,0 +1,109 @@
+//! moment.js locale configuration
+//! locale : Hungarian [hu]
+//! author : Adam Brunner : https://github.com/adambrunner
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var weekEndings = 'vasárnap hétfőn kedden szerdán csütörtökön pénteken szombaton'.split(' ');
+function translate(number, withoutSuffix, key, isFuture) {
+    var num = number,
+        suffix;
+    switch (key) {
+        case 's':
+            return (isFuture || withoutSuffix) ? 'néhány másodperc' : 'néhány másodperce';
+        case 'm':
+            return 'egy' + (isFuture || withoutSuffix ? ' perc' : ' perce');
+        case 'mm':
+            return num + (isFuture || withoutSuffix ? ' perc' : ' perce');
+        case 'h':
+            return 'egy' + (isFuture || withoutSuffix ? ' óra' : ' órája');
+        case 'hh':
+            return num + (isFuture || withoutSuffix ? ' óra' : ' órája');
+        case 'd':
+            return 'egy' + (isFuture || withoutSuffix ? ' nap' : ' napja');
+        case 'dd':
+            return num + (isFuture || withoutSuffix ? ' nap' : ' napja');
+        case 'M':
+            return 'egy' + (isFuture || withoutSuffix ? ' hónap' : ' hónapja');
+        case 'MM':
+            return num + (isFuture || withoutSuffix ? ' hónap' : ' hónapja');
+        case 'y':
+            return 'egy' + (isFuture || withoutSuffix ? ' év' : ' éve');
+        case 'yy':
+            return num + (isFuture || withoutSuffix ? ' év' : ' éve');
+    }
+    return '';
+}
+function week(isFuture) {
+    return (isFuture ? '' : '[múlt] ') + '[' + weekEndings[this.day()] + '] LT[-kor]';
+}
+
+var hu = moment.defineLocale('hu', {
+    months : 'január_február_március_április_május_június_július_augusztus_szeptember_október_november_december'.split('_'),
+    monthsShort : 'jan_feb_márc_ápr_máj_jún_júl_aug_szept_okt_nov_dec'.split('_'),
+    weekdays : 'vasárnap_hétfő_kedd_szerda_csütörtök_péntek_szombat'.split('_'),
+    weekdaysShort : 'vas_hét_kedd_sze_csüt_pén_szo'.split('_'),
+    weekdaysMin : 'v_h_k_sze_cs_p_szo'.split('_'),
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'YYYY.MM.DD.',
+        LL : 'YYYY. MMMM D.',
+        LLL : 'YYYY. MMMM D. H:mm',
+        LLLL : 'YYYY. MMMM D., dddd H:mm'
+    },
+    meridiemParse: /de|du/i,
+    isPM: function (input) {
+        return input.charAt(1).toLowerCase() === 'u';
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 12) {
+            return isLower === true ? 'de' : 'DE';
+        } else {
+            return isLower === true ? 'du' : 'DU';
+        }
+    },
+    calendar : {
+        sameDay : '[ma] LT[-kor]',
+        nextDay : '[holnap] LT[-kor]',
+        nextWeek : function () {
+            return week.call(this, true);
+        },
+        lastDay : '[tegnap] LT[-kor]',
+        lastWeek : function () {
+            return week.call(this, false);
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s múlva',
+        past : '%s',
+        s : translate,
+        m : translate,
+        mm : translate,
+        h : translate,
+        hh : translate,
+        d : translate,
+        dd : translate,
+        M : translate,
+        MM : translate,
+        y : translate,
+        yy : translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return hu;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/hy-am.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/hy-am.js
new file mode 100644
index 0000000000000000000000000000000000000000..58045b7565b5dcf942134c8d3db55d40bf10c945
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/hy-am.js
@@ -0,0 +1,95 @@
+//! moment.js locale configuration
+//! locale : Armenian [hy-am]
+//! author : Armendarabyan : https://github.com/armendarabyan
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var hyAm = moment.defineLocale('hy-am', {
+    months : {
+        format: 'Õ°Õ¸Ö‚Õ¶Õ¾Õ¡Ö€Õ«_ÖƒÕ¥Õ¿Ö€Õ¾Õ¡Ö€Õ«_Õ´Õ¡Ö€Õ¿Õ«_Õ¡ÕºÖ€Õ«Õ¬Õ«_Õ´Õ¡ÕµÕ«Õ½Õ«_Õ°Õ¸Ö‚Õ¶Õ«Õ½Õ«_Õ°Õ¸Ö‚Õ¬Õ«Õ½Õ«_Ö…Õ£Õ¸Õ½Õ¿Õ¸Õ½Õ«_Õ½Õ¥ÕºÕ¿Õ¥Õ´Õ¢Õ¥Ö€Õ«_Õ°Õ¸Õ¯Õ¿Õ¥Õ´Õ¢Õ¥Ö€Õ«_Õ¶Õ¸ÕµÕ¥Õ´Õ¢Õ¥Ö€Õ«_Õ¤Õ¥Õ¯Õ¿Õ¥Õ´Õ¢Õ¥Ö€Õ«'.split('_'),
+        standalone: 'Õ°Õ¸Ö‚Õ¶Õ¾Õ¡Ö€_ÖƒÕ¥Õ¿Ö€Õ¾Õ¡Ö€_Õ´Õ¡Ö€Õ¿_Õ¡ÕºÖ€Õ«Õ¬_Õ´Õ¡ÕµÕ«Õ½_Õ°Õ¸Ö‚Õ¶Õ«Õ½_Õ°Õ¸Ö‚Õ¬Õ«Õ½_Ö…Õ£Õ¸Õ½Õ¿Õ¸Õ½_Õ½Õ¥ÕºÕ¿Õ¥Õ´Õ¢Õ¥Ö€_Õ°Õ¸Õ¯Õ¿Õ¥Õ´Õ¢Õ¥Ö€_Õ¶Õ¸ÕµÕ¥Õ´Õ¢Õ¥Ö€_Õ¤Õ¥Õ¯Õ¿Õ¥Õ´Õ¢Õ¥Ö€'.split('_')
+    },
+    monthsShort : 'Õ°Õ¶Õ¾_ÖƒÕ¿Ö€_Õ´Ö€Õ¿_Õ¡ÕºÖ€_Õ´ÕµÕ½_Õ°Õ¶Õ½_Õ°Õ¬Õ½_Ö…Õ£Õ½_Õ½ÕºÕ¿_Õ°Õ¯Õ¿_Õ¶Õ´Õ¢_Õ¤Õ¯Õ¿'.split('_'),
+    weekdays : 'Õ¯Õ«Ö€Õ¡Õ¯Õ«_Õ¥Ö€Õ¯Õ¸Ö‚Õ·Õ¡Õ¢Õ©Õ«_Õ¥Ö€Õ¥Ö„Õ·Õ¡Õ¢Õ©Õ«_Õ¹Õ¸Ö€Õ¥Ö„Õ·Õ¡Õ¢Õ©Õ«_Õ°Õ«Õ¶Õ£Õ·Õ¡Õ¢Õ©Õ«_Õ¸Ö‚Ö€Õ¢Õ¡Õ©_Õ·Õ¡Õ¢Õ¡Õ©'.split('_'),
+    weekdaysShort : 'Õ¯Ö€Õ¯_Õ¥Ö€Õ¯_Õ¥Ö€Ö„_Õ¹Ö€Ö„_Õ°Õ¶Õ£_Õ¸Ö‚Ö€Õ¢_Õ·Õ¢Õ©'.split('_'),
+    weekdaysMin : 'Õ¯Ö€Õ¯_Õ¥Ö€Õ¯_Õ¥Ö€Ö„_Õ¹Ö€Ö„_Õ°Õ¶Õ£_Õ¸Ö‚Ö€Õ¢_Õ·Õ¢Õ©'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY Õ©.',
+        LLL : 'D MMMM YYYY Õ©., HH:mm',
+        LLLL : 'dddd, D MMMM YYYY Õ©., HH:mm'
+    },
+    calendar : {
+        sameDay: '[Õ¡ÕµÕ½Ö…Ö€] LT',
+        nextDay: '[Õ¾Õ¡Õ²Õ¨] LT',
+        lastDay: '[Õ¥Ö€Õ¥Õ¯] LT',
+        nextWeek: function () {
+            return 'dddd [Ö…Ö€Õ¨ ÕªÕ¡Õ´Õ¨] LT';
+        },
+        lastWeek: function () {
+            return '[անցած] dddd [օրը ժամը] LT';
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : '%s Õ°Õ¥Õ¿Õ¸',
+        past : '%s Õ¡Õ¼Õ¡Õ»',
+        s : 'Õ´Õ« Ö„Õ¡Õ¶Õ« Õ¾Õ¡ÕµÖ€Õ¯ÕµÕ¡Õ¶',
+        m : 'Ö€Õ¸ÕºÕ¥',
+        mm : '%d Ö€Õ¸ÕºÕ¥',
+        h : 'ÕªÕ¡Õ´',
+        hh : '%d ÕªÕ¡Õ´',
+        d : 'Ö…Ö€',
+        dd : '%d Ö…Ö€',
+        M : 'Õ¡Õ´Õ«Õ½',
+        MM : '%d Õ¡Õ´Õ«Õ½',
+        y : 'Õ¿Õ¡Ö€Õ«',
+        yy : '%d Õ¿Õ¡Ö€Õ«'
+    },
+    meridiemParse: /գիշերվա|առավոտվա|ցերեկվա|երեկոյան/,
+    isPM: function (input) {
+        return /^(ցերեկվա|երեկոյան)$/.test(input);
+    },
+    meridiem : function (hour) {
+        if (hour < 4) {
+            return 'Õ£Õ«Õ·Õ¥Ö€Õ¾Õ¡';
+        } else if (hour < 12) {
+            return 'Õ¡Õ¼Õ¡Õ¾Õ¸Õ¿Õ¾Õ¡';
+        } else if (hour < 17) {
+            return 'ցերեկվա';
+        } else {
+            return 'Õ¥Ö€Õ¥Õ¯Õ¸ÕµÕ¡Õ¶';
+        }
+    },
+    ordinalParse: /\d{1,2}|\d{1,2}-(Õ«Õ¶|Ö€Õ¤)/,
+    ordinal: function (number, period) {
+        switch (period) {
+            case 'DDD':
+            case 'w':
+            case 'W':
+            case 'DDDo':
+                if (number === 1) {
+                    return number + '-Õ«Õ¶';
+                }
+                return number + '-Ö€Õ¤';
+            default:
+                return number;
+        }
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return hyAm;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/id.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/id.js
new file mode 100644
index 0000000000000000000000000000000000000000..a1cfb1834598329a57901cab22a29bdaa69d0aa6
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/id.js
@@ -0,0 +1,83 @@
+//! moment.js locale configuration
+//! locale : Indonesian [id]
+//! author : Mohammad Satrio Utomo : https://github.com/tyok
+//! reference: http://id.wikisource.org/wiki/Pedoman_Umum_Ejaan_Bahasa_Indonesia_yang_Disempurnakan
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var id = moment.defineLocale('id', {
+    months : 'Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_November_Desember'.split('_'),
+    monthsShort : 'Jan_Feb_Mar_Apr_Mei_Jun_Jul_Ags_Sep_Okt_Nov_Des'.split('_'),
+    weekdays : 'Minggu_Senin_Selasa_Rabu_Kamis_Jumat_Sabtu'.split('_'),
+    weekdaysShort : 'Min_Sen_Sel_Rab_Kam_Jum_Sab'.split('_'),
+    weekdaysMin : 'Mg_Sn_Sl_Rb_Km_Jm_Sb'.split('_'),
+    longDateFormat : {
+        LT : 'HH.mm',
+        LTS : 'HH.mm.ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY [pukul] HH.mm',
+        LLLL : 'dddd, D MMMM YYYY [pukul] HH.mm'
+    },
+    meridiemParse: /pagi|siang|sore|malam/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'pagi') {
+            return hour;
+        } else if (meridiem === 'siang') {
+            return hour >= 11 ? hour : hour + 12;
+        } else if (meridiem === 'sore' || meridiem === 'malam') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 11) {
+            return 'pagi';
+        } else if (hours < 15) {
+            return 'siang';
+        } else if (hours < 19) {
+            return 'sore';
+        } else {
+            return 'malam';
+        }
+    },
+    calendar : {
+        sameDay : '[Hari ini pukul] LT',
+        nextDay : '[Besok pukul] LT',
+        nextWeek : 'dddd [pukul] LT',
+        lastDay : '[Kemarin pukul] LT',
+        lastWeek : 'dddd [lalu pukul] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'dalam %s',
+        past : '%s yang lalu',
+        s : 'beberapa detik',
+        m : 'semenit',
+        mm : '%d menit',
+        h : 'sejam',
+        hh : '%d jam',
+        d : 'sehari',
+        dd : '%d hari',
+        M : 'sebulan',
+        MM : '%d bulan',
+        y : 'setahun',
+        yy : '%d tahun'
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return id;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/is.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/is.js
new file mode 100644
index 0000000000000000000000000000000000000000..9658aab2f9d76828c45d6caec42d0f6aa80d8335
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/is.js
@@ -0,0 +1,127 @@
+//! moment.js locale configuration
+//! locale : Icelandic [is]
+//! author : Hinrik Örn Sigurðsson : https://github.com/hinrik
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+function plural(n) {
+    if (n % 100 === 11) {
+        return true;
+    } else if (n % 10 === 1) {
+        return false;
+    }
+    return true;
+}
+function translate(number, withoutSuffix, key, isFuture) {
+    var result = number + ' ';
+    switch (key) {
+        case 's':
+            return withoutSuffix || isFuture ? 'nokkrar sekúndur' : 'nokkrum sekúndum';
+        case 'm':
+            return withoutSuffix ? 'mínúta' : 'mínútu';
+        case 'mm':
+            if (plural(number)) {
+                return result + (withoutSuffix || isFuture ? 'mínútur' : 'mínútum');
+            } else if (withoutSuffix) {
+                return result + 'mínúta';
+            }
+            return result + 'mínútu';
+        case 'hh':
+            if (plural(number)) {
+                return result + (withoutSuffix || isFuture ? 'klukkustundir' : 'klukkustundum');
+            }
+            return result + 'klukkustund';
+        case 'd':
+            if (withoutSuffix) {
+                return 'dagur';
+            }
+            return isFuture ? 'dag' : 'degi';
+        case 'dd':
+            if (plural(number)) {
+                if (withoutSuffix) {
+                    return result + 'dagar';
+                }
+                return result + (isFuture ? 'daga' : 'dögum');
+            } else if (withoutSuffix) {
+                return result + 'dagur';
+            }
+            return result + (isFuture ? 'dag' : 'degi');
+        case 'M':
+            if (withoutSuffix) {
+                return 'mánuður';
+            }
+            return isFuture ? 'mánuð' : 'mánuði';
+        case 'MM':
+            if (plural(number)) {
+                if (withoutSuffix) {
+                    return result + 'mánuðir';
+                }
+                return result + (isFuture ? 'mánuði' : 'mánuðum');
+            } else if (withoutSuffix) {
+                return result + 'mánuður';
+            }
+            return result + (isFuture ? 'mánuð' : 'mánuði');
+        case 'y':
+            return withoutSuffix || isFuture ? 'ár' : 'ári';
+        case 'yy':
+            if (plural(number)) {
+                return result + (withoutSuffix || isFuture ? 'ár' : 'árum');
+            }
+            return result + (withoutSuffix || isFuture ? 'ár' : 'ári');
+    }
+}
+
+var is = moment.defineLocale('is', {
+    months : 'janúar_febrúar_mars_apríl_maí_júní_júlí_ágúst_september_október_nóvember_desember'.split('_'),
+    monthsShort : 'jan_feb_mar_apr_maí_jún_júl_ágú_sep_okt_nóv_des'.split('_'),
+    weekdays : 'sunnudagur_mánudagur_þriðjudagur_miðvikudagur_fimmtudagur_föstudagur_laugardagur'.split('_'),
+    weekdaysShort : 'sun_mán_þri_mið_fim_fös_lau'.split('_'),
+    weekdaysMin : 'Su_Má_Þr_Mi_Fi_Fö_La'.split('_'),
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY [kl.] H:mm',
+        LLLL : 'dddd, D. MMMM YYYY [kl.] H:mm'
+    },
+    calendar : {
+        sameDay : '[í dag kl.] LT',
+        nextDay : '[á morgun kl.] LT',
+        nextWeek : 'dddd [kl.] LT',
+        lastDay : '[í gær kl.] LT',
+        lastWeek : '[síðasta] dddd [kl.] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'eftir %s',
+        past : 'fyrir %s síðan',
+        s : translate,
+        m : translate,
+        mm : translate,
+        h : 'klukkustund',
+        hh : translate,
+        d : translate,
+        dd : translate,
+        M : translate,
+        MM : translate,
+        y : translate,
+        yy : translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return is;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/it.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/it.js
new file mode 100644
index 0000000000000000000000000000000000000000..d5ddf18e83ceab7238dae3d101c19d5bc043ba04
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/it.js
@@ -0,0 +1,70 @@
+//! moment.js locale configuration
+//! locale : Italian [it]
+//! author : Lorenzo : https://github.com/aliem
+//! author: Mattia Larentis: https://github.com/nostalgiaz
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var it = moment.defineLocale('it', {
+    months : 'gennaio_febbraio_marzo_aprile_maggio_giugno_luglio_agosto_settembre_ottobre_novembre_dicembre'.split('_'),
+    monthsShort : 'gen_feb_mar_apr_mag_giu_lug_ago_set_ott_nov_dic'.split('_'),
+    weekdays : 'Domenica_Lunedì_Martedì_Mercoledì_Giovedì_Venerdì_Sabato'.split('_'),
+    weekdaysShort : 'Dom_Lun_Mar_Mer_Gio_Ven_Sab'.split('_'),
+    weekdaysMin : 'Do_Lu_Ma_Me_Gi_Ve_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Oggi alle] LT',
+        nextDay: '[Domani alle] LT',
+        nextWeek: 'dddd [alle] LT',
+        lastDay: '[Ieri alle] LT',
+        lastWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[la scorsa] dddd [alle] LT';
+                default:
+                    return '[lo scorso] dddd [alle] LT';
+            }
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : function (s) {
+            return ((/^[0-9].+$/).test(s) ? 'tra' : 'in') + ' ' + s;
+        },
+        past : '%s fa',
+        s : 'alcuni secondi',
+        m : 'un minuto',
+        mm : '%d minuti',
+        h : 'un\'ora',
+        hh : '%d ore',
+        d : 'un giorno',
+        dd : '%d giorni',
+        M : 'un mese',
+        MM : '%d mesi',
+        y : 'un anno',
+        yy : '%d anni'
+    },
+    ordinalParse : /\d{1,2}º/,
+    ordinal: '%dº',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return it;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ja.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ja.js
new file mode 100644
index 0000000000000000000000000000000000000000..4df51ad03cf43cb8454be1c23e5ca93681cfa405
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ja.js
@@ -0,0 +1,76 @@
+//! moment.js locale configuration
+//! locale : Japanese [ja]
+//! author : LI Long : https://github.com/baryon
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var ja = moment.defineLocale('ja', {
+    months : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
+    monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
+    weekdays : '日曜日_月曜日_火曜日_水曜日_木曜日_金曜日_土曜日'.split('_'),
+    weekdaysShort : '日_月_火_水_木_金_土'.split('_'),
+    weekdaysMin : '日_月_火_水_木_金_土'.split('_'),
+    longDateFormat : {
+        LT : 'Ah時m分',
+        LTS : 'Ah時m分s秒',
+        L : 'YYYY/MM/DD',
+        LL : 'YYYY年M月D日',
+        LLL : 'YYYY年M月D日Ah時m分',
+        LLLL : 'YYYY年M月D日Ah時m分 dddd'
+    },
+    meridiemParse: /午前|午後/i,
+    isPM : function (input) {
+        return input === '午後';
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return '午前';
+        } else {
+            return '午後';
+        }
+    },
+    calendar : {
+        sameDay : '[今日] LT',
+        nextDay : '[明日] LT',
+        nextWeek : '[来週]dddd LT',
+        lastDay : '[昨日] LT',
+        lastWeek : '[前週]dddd LT',
+        sameElse : 'L'
+    },
+    ordinalParse : /\d{1,2}æ—¥/,
+    ordinal : function (number, period) {
+        switch (period) {
+            case 'd':
+            case 'D':
+            case 'DDD':
+                return number + 'æ—¥';
+            default:
+                return number;
+        }
+    },
+    relativeTime : {
+        future : '%s後',
+        past : '%s前',
+        s : 'æ•°ç§’',
+        m : '1分',
+        mm : '%d分',
+        h : '1時間',
+        hh : '%d時間',
+        d : '1æ—¥',
+        dd : '%dæ—¥',
+        M : '1ヶ月',
+        MM : '%dヶ月',
+        y : '1å¹´',
+        yy : '%då¹´'
+    }
+});
+
+return ja;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/jv.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/jv.js
new file mode 100644
index 0000000000000000000000000000000000000000..5b939e0fcb1133cf1b157fc488ffe9c0c19ad663
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/jv.js
@@ -0,0 +1,83 @@
+//! moment.js locale configuration
+//! locale : Javanese [jv]
+//! author : Rony Lantip : https://github.com/lantip
+//! reference: http://jv.wikipedia.org/wiki/Basa_Jawa
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var jv = moment.defineLocale('jv', {
+    months : 'Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_Nopember_Desember'.split('_'),
+    monthsShort : 'Jan_Feb_Mar_Apr_Mei_Jun_Jul_Ags_Sep_Okt_Nop_Des'.split('_'),
+    weekdays : 'Minggu_Senen_Seloso_Rebu_Kemis_Jemuwah_Septu'.split('_'),
+    weekdaysShort : 'Min_Sen_Sel_Reb_Kem_Jem_Sep'.split('_'),
+    weekdaysMin : 'Mg_Sn_Sl_Rb_Km_Jm_Sp'.split('_'),
+    longDateFormat : {
+        LT : 'HH.mm',
+        LTS : 'HH.mm.ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY [pukul] HH.mm',
+        LLLL : 'dddd, D MMMM YYYY [pukul] HH.mm'
+    },
+    meridiemParse: /enjing|siyang|sonten|ndalu/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'enjing') {
+            return hour;
+        } else if (meridiem === 'siyang') {
+            return hour >= 11 ? hour : hour + 12;
+        } else if (meridiem === 'sonten' || meridiem === 'ndalu') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 11) {
+            return 'enjing';
+        } else if (hours < 15) {
+            return 'siyang';
+        } else if (hours < 19) {
+            return 'sonten';
+        } else {
+            return 'ndalu';
+        }
+    },
+    calendar : {
+        sameDay : '[Dinten puniko pukul] LT',
+        nextDay : '[Mbenjang pukul] LT',
+        nextWeek : 'dddd [pukul] LT',
+        lastDay : '[Kala wingi pukul] LT',
+        lastWeek : 'dddd [kepengker pukul] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'wonten ing %s',
+        past : '%s ingkang kepengker',
+        s : 'sawetawis detik',
+        m : 'setunggal menit',
+        mm : '%d menit',
+        h : 'setunggal jam',
+        hh : '%d jam',
+        d : 'sedinten',
+        dd : '%d dinten',
+        M : 'sewulan',
+        MM : '%d wulan',
+        y : 'setaun',
+        yy : '%d taun'
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return jv;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ka.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ka.js
new file mode 100644
index 0000000000000000000000000000000000000000..be866c8b6c98119345082b38ffcf323a045f7af1
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ka.js
@@ -0,0 +1,89 @@
+//! moment.js locale configuration
+//! locale : Georgian [ka]
+//! author : Irakli Janiashvili : https://github.com/irakli-janiashvili
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var ka = moment.defineLocale('ka', {
+    months : {
+        standalone: 'იანვარი_თებერვალი_მარტი_აპრილი_მაისი_ივნისი_ივლისი_აგვისტო_სექტემბერი_ოქტომბერი_ნოემბერი_დეკემბერი'.split('_'),
+        format: 'იანვარს_თებერვალს_მარტს_აპრილის_მაისს_ივნისს_ივლისს_აგვისტს_სექტემბერს_ოქტომბერს_ნოემბერს_დეკემბერს'.split('_')
+    },
+    monthsShort : 'იან_თებ_მარ_აპრ_მაი_ივნ_ივლ_აგვ_სექ_ოქტ_ნოე_დეკ'.split('_'),
+    weekdays : {
+        standalone: 'კვირა_ორშაბათი_სამშაბათი_ოთხშაბათი_ხუთშაბათი_პარასკევი_შაბათი'.split('_'),
+        format: 'კვირას_ორშაბათს_სამშაბათს_ოთხშაბათს_ხუთშაბათს_პარასკევს_შაბათს'.split('_'),
+        isFormat: /(წინა|შემდეგ)/
+    },
+    weekdaysShort : 'კვი_ორშ_სამ_ოთხ_ხუთ_პარ_შაბ'.split('_'),
+    weekdaysMin : 'კვ_ორ_სა_ოთ_ხუ_პა_შა'.split('_'),
+    longDateFormat : {
+        LT : 'h:mm A',
+        LTS : 'h:mm:ss A',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY h:mm A',
+        LLLL : 'dddd, D MMMM YYYY h:mm A'
+    },
+    calendar : {
+        sameDay : '[დღეს] LT[-ზე]',
+        nextDay : '[ხვალ] LT[-ზე]',
+        lastDay : '[გუშინ] LT[-ზე]',
+        nextWeek : '[შემდეგ] dddd LT[-ზე]',
+        lastWeek : '[წინა] dddd LT-ზე',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : function (s) {
+            return (/(წამი|წუთი|საათი|წელი)/).test(s) ?
+                s.replace(/ი$/, 'ში') :
+                s + 'ში';
+        },
+        past : function (s) {
+            if ((/(წამი|წუთი|საათი|დღე|თვე)/).test(s)) {
+                return s.replace(/(ი|ე)$/, 'ის წინ');
+            }
+            if ((/წელი/).test(s)) {
+                return s.replace(/წელი$/, 'წლის წინ');
+            }
+        },
+        s : 'რამდენიმე წამი',
+        m : 'წუთი',
+        mm : '%d წუთი',
+        h : 'საათი',
+        hh : '%d საათი',
+        d : 'დღე',
+        dd : '%d დღე',
+        M : 'თვე',
+        MM : '%d თვე',
+        y : 'წელი',
+        yy : '%d წელი'
+    },
+    ordinalParse: /0|1-ლი|მე-\d{1,2}|\d{1,2}-ე/,
+    ordinal : function (number) {
+        if (number === 0) {
+            return number;
+        }
+        if (number === 1) {
+            return number + '-ლი';
+        }
+        if ((number < 20) || (number <= 100 && (number % 20 === 0)) || (number % 100 === 0)) {
+            return 'მე-' + number;
+        }
+        return number + '-ე';
+    },
+    week : {
+        dow : 1,
+        doy : 7
+    }
+});
+
+return ka;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/kk.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/kk.js
new file mode 100644
index 0000000000000000000000000000000000000000..94a231258a6f30939b5f024c927386fad3185f8a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/kk.js
@@ -0,0 +1,87 @@
+//! moment.js locale configuration
+//! locale : Kazakh [kk]
+//! authors : Nurlan Rakhimzhanov : https://github.com/nurlan
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var suffixes = {
+    0: '-ші',
+    1: '-ші',
+    2: '-ші',
+    3: '-ші',
+    4: '-ші',
+    5: '-ші',
+    6: '-шы',
+    7: '-ші',
+    8: '-ші',
+    9: '-шы',
+    10: '-шы',
+    20: '-шы',
+    30: '-шы',
+    40: '-шы',
+    50: '-ші',
+    60: '-шы',
+    70: '-ші',
+    80: '-ші',
+    90: '-шы',
+    100: '-ші'
+};
+
+var kk = moment.defineLocale('kk', {
+    months : 'қаңтар_ақпан_наурыз_сәуір_мамыр_маусым_шілде_тамыз_қыркүйек_қазан_қараша_желтоқсан'.split('_'),
+    monthsShort : 'қаң_ақп_нау_сәу_мам_мау_шіл_там_қыр_қаз_қар_жел'.split('_'),
+    weekdays : 'жексенбі_дүйсенбі_сейсенбі_сәрсенбі_бейсенбі_жұма_сенбі'.split('_'),
+    weekdaysShort : 'жек_дүй_сей_сәр_бей_жұм_сен'.split('_'),
+    weekdaysMin : 'жк_дй_сй_ср_бй_жм_сн'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[Бүгін сағат] LT',
+        nextDay : '[Ертең сағат] LT',
+        nextWeek : 'dddd [сағат] LT',
+        lastDay : '[Кеше сағат] LT',
+        lastWeek : '[Өткен аптаның] dddd [сағат] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s ішінде',
+        past : '%s бұрын',
+        s : 'бірнеше секунд',
+        m : 'бір минут',
+        mm : '%d минут',
+        h : 'бір сағат',
+        hh : '%d сағат',
+        d : 'бір күн',
+        dd : '%d күн',
+        M : 'бір ай',
+        MM : '%d ай',
+        y : 'бір жыл',
+        yy : '%d жыл'
+    },
+    ordinalParse: /\d{1,2}-(ші|шы)/,
+    ordinal : function (number) {
+        var a = number % 10,
+            b = number >= 100 ? 100 : null;
+        return number + (suffixes[number] || suffixes[a] || suffixes[b]);
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return kk;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/km.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/km.js
new file mode 100644
index 0000000000000000000000000000000000000000..71482a7b52dc487118665bb7adb686b68038d8e3
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/km.js
@@ -0,0 +1,58 @@
+//! moment.js locale configuration
+//! locale : Cambodian [km]
+//! author : Kruy Vanna : https://github.com/kruyvanna
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var km = moment.defineLocale('km', {
+    months: 'មករា_កុម្ភៈ_មីនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ'.split('_'),
+    monthsShort: 'មករា_កុម្ភៈ_មីនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ'.split('_'),
+    weekdays: 'អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍'.split('_'),
+    weekdaysShort: 'អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍'.split('_'),
+    weekdaysMin: 'អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍'.split('_'),
+    longDateFormat: {
+        LT: 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L: 'DD/MM/YYYY',
+        LL: 'D MMMM YYYY',
+        LLL: 'D MMMM YYYY HH:mm',
+        LLLL: 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar: {
+        sameDay: '[ថ្ងៃនេះ ម៉ោង] LT',
+        nextDay: '[ស្អែក ម៉ោង] LT',
+        nextWeek: 'dddd [ម៉ោង] LT',
+        lastDay: '[ម្សិលមិញ ម៉ោង] LT',
+        lastWeek: 'dddd [សប្តាហ៍មុន] [ម៉ោង] LT',
+        sameElse: 'L'
+    },
+    relativeTime: {
+        future: '%sទៀត',
+        past: '%sមុន',
+        s: 'ប៉ុន្មានវិនាទី',
+        m: 'មួយនាទី',
+        mm: '%d នាទី',
+        h: 'មួយម៉ោង',
+        hh: '%d ម៉ោង',
+        d: 'មួយថ្ងៃ',
+        dd: '%d ថ្ងៃ',
+        M: 'មួយខែ',
+        MM: '%d ខែ',
+        y: 'មួយឆ្នាំ',
+        yy: '%d ឆ្នាំ'
+    },
+    week: {
+        dow: 1, // Monday is the first day of the week.
+        doy: 4 // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return km;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ko.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ko.js
new file mode 100644
index 0000000000000000000000000000000000000000..b736583e8cc1b5ca74895bb503c3fb721d169edc
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ko.js
@@ -0,0 +1,65 @@
+//! moment.js locale configuration
+//! locale : Korean [ko]
+//! author : Kyungwook, Park : https://github.com/kyungw00k
+//! author : Jeeeyul Lee <jeeeyul@gmail.com>
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var ko = moment.defineLocale('ko', {
+    months : '1ì›”_2ì›”_3ì›”_4ì›”_5ì›”_6ì›”_7ì›”_8ì›”_9ì›”_10ì›”_11ì›”_12ì›”'.split('_'),
+    monthsShort : '1ì›”_2ì›”_3ì›”_4ì›”_5ì›”_6ì›”_7ì›”_8ì›”_9ì›”_10ì›”_11ì›”_12ì›”'.split('_'),
+    weekdays : '일요일_월요일_화요일_수요일_목요일_금요일_토요일'.split('_'),
+    weekdaysShort : '일_월_화_수_목_금_토'.split('_'),
+    weekdaysMin : '일_월_화_수_목_금_토'.split('_'),
+    longDateFormat : {
+        LT : 'A h시 m분',
+        LTS : 'A h시 m분 s초',
+        L : 'YYYY.MM.DD',
+        LL : 'YYYY년 MMMM D일',
+        LLL : 'YYYY년 MMMM D일 A h시 m분',
+        LLLL : 'YYYY년 MMMM D일 dddd A h시 m분'
+    },
+    calendar : {
+        sameDay : '오늘 LT',
+        nextDay : '내일 LT',
+        nextWeek : 'dddd LT',
+        lastDay : '어제 LT',
+        lastWeek : '지난주 dddd LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s 후',
+        past : '%s ì „',
+        s : '몇 초',
+        ss : '%dì´ˆ',
+        m : '일분',
+        mm : '%dë¶„',
+        h : '한 시간',
+        hh : '%d시간',
+        d : '하루',
+        dd : '%d일',
+        M : '한 달',
+        MM : '%d달',
+        y : '일 년',
+        yy : '%dë…„'
+    },
+    ordinalParse : /\d{1,2}일/,
+    ordinal : '%d일',
+    meridiemParse : /오전|오후/,
+    isPM : function (token) {
+        return token === '오후';
+    },
+    meridiem : function (hour, minute, isUpper) {
+        return hour < 12 ? '오전' : '오후';
+    }
+});
+
+return ko;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ky.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ky.js
new file mode 100644
index 0000000000000000000000000000000000000000..baf241813e14d0372b6b4771c88ac16f79f3f9cf
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ky.js
@@ -0,0 +1,88 @@
+//! moment.js locale configuration
+//! locale : Kyrgyz [ky]
+//! author : Chyngyz Arystan uulu : https://github.com/chyngyz
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+
+var suffixes = {
+    0: '-чү',
+    1: '-чи',
+    2: '-чи',
+    3: '-чү',
+    4: '-чү',
+    5: '-чи',
+    6: '-чы',
+    7: '-чи',
+    8: '-чи',
+    9: '-чу',
+    10: '-чу',
+    20: '-чы',
+    30: '-чу',
+    40: '-чы',
+    50: '-чү',
+    60: '-чы',
+    70: '-чи',
+    80: '-чи',
+    90: '-чу',
+    100: '-чү'
+};
+
+var ky = moment.defineLocale('ky', {
+    months : 'январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь'.split('_'),
+    monthsShort : 'янв_фев_март_апр_май_июнь_июль_авг_сен_окт_ноя_дек'.split('_'),
+    weekdays : 'Жекшемби_Дүйшөмбү_Шейшемби_Шаршемби_Бейшемби_Жума_Ишемби'.split('_'),
+    weekdaysShort : 'Жек_Дүй_Шей_Шар_Бей_Жум_Ише'.split('_'),
+    weekdaysMin : 'Жк_Дй_Шй_Шр_Бй_Жм_Иш'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[Бүгүн саат] LT',
+        nextDay : '[Эртең саат] LT',
+        nextWeek : 'dddd [саат] LT',
+        lastDay : '[Кече саат] LT',
+        lastWeek : '[Өткен аптанын] dddd [күнү] [саат] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s ичинде',
+        past : '%s мурун',
+        s : 'бирнече секунд',
+        m : 'бир мүнөт',
+        mm : '%d мүнөт',
+        h : 'бир саат',
+        hh : '%d саат',
+        d : 'бир күн',
+        dd : '%d күн',
+        M : 'бир ай',
+        MM : '%d ай',
+        y : 'бир жыл',
+        yy : '%d жыл'
+    },
+    ordinalParse: /\d{1,2}-(чи|чы|чү|чу)/,
+    ordinal : function (number) {
+        var a = number % 10,
+            b = number >= 100 ? 100 : null;
+        return number + (suffixes[number] || suffixes[a] || suffixes[b]);
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return ky;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/lb.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/lb.js
new file mode 100644
index 0000000000000000000000000000000000000000..e55d57bad1e7ead82cea3f971402861a714cf73b
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/lb.js
@@ -0,0 +1,137 @@
+//! moment.js locale configuration
+//! locale : Luxembourgish [lb]
+//! author : mweimerskirch : https://github.com/mweimerskirch
+//! author : David Raison : https://github.com/kwisatz
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+function processRelativeTime(number, withoutSuffix, key, isFuture) {
+    var format = {
+        'm': ['eng Minutt', 'enger Minutt'],
+        'h': ['eng Stonn', 'enger Stonn'],
+        'd': ['een Dag', 'engem Dag'],
+        'M': ['ee Mount', 'engem Mount'],
+        'y': ['ee Joer', 'engem Joer']
+    };
+    return withoutSuffix ? format[key][0] : format[key][1];
+}
+function processFutureTime(string) {
+    var number = string.substr(0, string.indexOf(' '));
+    if (eifelerRegelAppliesToNumber(number)) {
+        return 'a ' + string;
+    }
+    return 'an ' + string;
+}
+function processPastTime(string) {
+    var number = string.substr(0, string.indexOf(' '));
+    if (eifelerRegelAppliesToNumber(number)) {
+        return 'viru ' + string;
+    }
+    return 'virun ' + string;
+}
+/**
+ * Returns true if the word before the given number loses the '-n' ending.
+ * e.g. 'an 10 Deeg' but 'a 5 Deeg'
+ *
+ * @param number {integer}
+ * @returns {boolean}
+ */
+function eifelerRegelAppliesToNumber(number) {
+    number = parseInt(number, 10);
+    if (isNaN(number)) {
+        return false;
+    }
+    if (number < 0) {
+        // Negative Number --> always true
+        return true;
+    } else if (number < 10) {
+        // Only 1 digit
+        if (4 <= number && number <= 7) {
+            return true;
+        }
+        return false;
+    } else if (number < 100) {
+        // 2 digits
+        var lastDigit = number % 10, firstDigit = number / 10;
+        if (lastDigit === 0) {
+            return eifelerRegelAppliesToNumber(firstDigit);
+        }
+        return eifelerRegelAppliesToNumber(lastDigit);
+    } else if (number < 10000) {
+        // 3 or 4 digits --> recursively check first digit
+        while (number >= 10) {
+            number = number / 10;
+        }
+        return eifelerRegelAppliesToNumber(number);
+    } else {
+        // Anything larger than 4 digits: recursively check first n-3 digits
+        number = number / 1000;
+        return eifelerRegelAppliesToNumber(number);
+    }
+}
+
+var lb = moment.defineLocale('lb', {
+    months: 'Januar_Februar_Mäerz_Abrëll_Mee_Juni_Juli_August_September_Oktober_November_Dezember'.split('_'),
+    monthsShort: 'Jan._Febr._Mrz._Abr._Mee_Jun._Jul._Aug._Sept._Okt._Nov._Dez.'.split('_'),
+    monthsParseExact : true,
+    weekdays: 'Sonndeg_Méindeg_Dënschdeg_Mëttwoch_Donneschdeg_Freideg_Samschdeg'.split('_'),
+    weekdaysShort: 'So._Mé._Dë._Më._Do._Fr._Sa.'.split('_'),
+    weekdaysMin: 'So_Mé_Dë_Më_Do_Fr_Sa'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat: {
+        LT: 'H:mm [Auer]',
+        LTS: 'H:mm:ss [Auer]',
+        L: 'DD.MM.YYYY',
+        LL: 'D. MMMM YYYY',
+        LLL: 'D. MMMM YYYY H:mm [Auer]',
+        LLLL: 'dddd, D. MMMM YYYY H:mm [Auer]'
+    },
+    calendar: {
+        sameDay: '[Haut um] LT',
+        sameElse: 'L',
+        nextDay: '[Muer um] LT',
+        nextWeek: 'dddd [um] LT',
+        lastDay: '[Gëschter um] LT',
+        lastWeek: function () {
+            // Different date string for 'Dënschdeg' (Tuesday) and 'Donneschdeg' (Thursday) due to phonological rule
+            switch (this.day()) {
+                case 2:
+                case 4:
+                    return '[Leschten] dddd [um] LT';
+                default:
+                    return '[Leschte] dddd [um] LT';
+            }
+        }
+    },
+    relativeTime : {
+        future : processFutureTime,
+        past : processPastTime,
+        s : 'e puer Sekonnen',
+        m : processRelativeTime,
+        mm : '%d Minutten',
+        h : processRelativeTime,
+        hh : '%d Stonnen',
+        d : processRelativeTime,
+        dd : '%d Deeg',
+        M : processRelativeTime,
+        MM : '%d Méint',
+        y : processRelativeTime,
+        yy : '%d Joer'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal: '%d.',
+    week: {
+        dow: 1, // Monday is the first day of the week.
+        doy: 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return lb;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/lo.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/lo.js
new file mode 100644
index 0000000000000000000000000000000000000000..27065c97b92bdf89d09759098a714845b3731948
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/lo.js
@@ -0,0 +1,70 @@
+//! moment.js locale configuration
+//! locale : Lao [lo]
+//! author : Ryan Hart : https://github.com/ryanhart2
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var lo = moment.defineLocale('lo', {
+    months : 'ມັງກອນ_ກຸມພາ_ມີນາ_ເມສາ_ພຶດສະພາ_ມິຖຸນາ_ກໍລະກົດ_ສິງຫາ_ກັນຍາ_ຕຸລາ_ພະຈິກ_ທັນວາ'.split('_'),
+    monthsShort : 'ມັງກອນ_ກຸມພາ_ມີນາ_ເມສາ_ພຶດສະພາ_ມິຖຸນາ_ກໍລະກົດ_ສິງຫາ_ກັນຍາ_ຕຸລາ_ພະຈິກ_ທັນວາ'.split('_'),
+    weekdays : 'ອາທິດ_ຈັນ_ອັງຄານ_ພຸດ_ພະຫັດ_ສຸກ_ເສົາ'.split('_'),
+    weekdaysShort : 'ທິດ_ຈັນ_ອັງຄານ_ພຸດ_ພະຫັດ_ສຸກ_ເສົາ'.split('_'),
+    weekdaysMin : 'ທ_ຈ_ອຄ_ພ_ພຫ_ສກ_ສ'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'ວັນdddd D MMMM YYYY HH:mm'
+    },
+    meridiemParse: /ຕອນເຊົ້າ|ຕອນແລງ/,
+    isPM: function (input) {
+        return input === 'ຕອນແລງ';
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return 'ຕອນເຊົ້າ';
+        } else {
+            return 'ຕອນແລງ';
+        }
+    },
+    calendar : {
+        sameDay : '[ມື້ນີ້ເວລາ] LT',
+        nextDay : '[ມື້ອື່ນເວລາ] LT',
+        nextWeek : '[ວັນ]dddd[ໜ້າເວລາ] LT',
+        lastDay : '[ມື້ວານນີ້ເວລາ] LT',
+        lastWeek : '[ວັນ]dddd[ແລ້ວນີ້ເວລາ] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'ອີກ %s',
+        past : '%sຜ່ານມາ',
+        s : 'ບໍ່ເທົ່າໃດວິນາທີ',
+        m : '1 ນາທີ',
+        mm : '%d ນາທີ',
+        h : '1 ຊົ່ວໂມງ',
+        hh : '%d ຊົ່ວໂມງ',
+        d : '1 ມື້',
+        dd : '%d ມື້',
+        M : '1 ເດືອນ',
+        MM : '%d ເດືອນ',
+        y : '1 ປີ',
+        yy : '%d ປີ'
+    },
+    ordinalParse: /(ທີ່)\d{1,2}/,
+    ordinal : function (number) {
+        return 'ທີ່' + number;
+    }
+});
+
+return lo;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/lt.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/lt.js
new file mode 100644
index 0000000000000000000000000000000000000000..37990261af1f802262ac8e96e64614a550bceea4
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/lt.js
@@ -0,0 +1,117 @@
+//! moment.js locale configuration
+//! locale : Lithuanian [lt]
+//! author : Mindaugas Mozūras : https://github.com/mmozuras
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var units = {
+    'm' : 'minutÄ—_minutÄ—s_minutÄ™',
+    'mm': 'minutės_minučių_minutes',
+    'h' : 'valanda_valandos_valandÄ…',
+    'hh': 'valandos_valandų_valandas',
+    'd' : 'diena_dienos_dienÄ…',
+    'dd': 'dienos_dienų_dienas',
+    'M' : 'mėnuo_mėnesio_mėnesį',
+    'MM': 'mėnesiai_mėnesių_mėnesius',
+    'y' : 'metai_metų_metus',
+    'yy': 'metai_metų_metus'
+};
+function translateSeconds(number, withoutSuffix, key, isFuture) {
+    if (withoutSuffix) {
+        return 'kelios sekundÄ—s';
+    } else {
+        return isFuture ? 'kelių sekundžių' : 'kelias sekundes';
+    }
+}
+function translateSingular(number, withoutSuffix, key, isFuture) {
+    return withoutSuffix ? forms(key)[0] : (isFuture ? forms(key)[1] : forms(key)[2]);
+}
+function special(number) {
+    return number % 10 === 0 || (number > 10 && number < 20);
+}
+function forms(key) {
+    return units[key].split('_');
+}
+function translate(number, withoutSuffix, key, isFuture) {
+    var result = number + ' ';
+    if (number === 1) {
+        return result + translateSingular(number, withoutSuffix, key[0], isFuture);
+    } else if (withoutSuffix) {
+        return result + (special(number) ? forms(key)[1] : forms(key)[0]);
+    } else {
+        if (isFuture) {
+            return result + forms(key)[1];
+        } else {
+            return result + (special(number) ? forms(key)[1] : forms(key)[2]);
+        }
+    }
+}
+var lt = moment.defineLocale('lt', {
+    months : {
+        format: 'sausio_vasario_kovo_balandžio_gegužės_birželio_liepos_rugpjūčio_rugsėjo_spalio_lapkričio_gruodžio'.split('_'),
+        standalone: 'sausis_vasaris_kovas_balandis_gegužė_birželis_liepa_rugpjūtis_rugsėjis_spalis_lapkritis_gruodis'.split('_'),
+        isFormat: /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?|MMMM?(\[[^\[\]]*\]|\s)+D[oD]?/
+    },
+    monthsShort : 'sau_vas_kov_bal_geg_bir_lie_rgp_rgs_spa_lap_grd'.split('_'),
+    weekdays : {
+        format: 'sekmadienį_pirmadienį_antradienį_trečiadienį_ketvirtadienį_penktadienį_šeštadienį'.split('_'),
+        standalone: 'sekmadienis_pirmadienis_antradienis_trečiadienis_ketvirtadienis_penktadienis_šeštadienis'.split('_'),
+        isFormat: /dddd HH:mm/
+    },
+    weekdaysShort : 'Sek_Pir_Ant_Tre_Ket_Pen_Šeš'.split('_'),
+    weekdaysMin : 'S_P_A_T_K_Pn_Å '.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'YYYY-MM-DD',
+        LL : 'YYYY [m.] MMMM D [d.]',
+        LLL : 'YYYY [m.] MMMM D [d.], HH:mm [val.]',
+        LLLL : 'YYYY [m.] MMMM D [d.], dddd, HH:mm [val.]',
+        l : 'YYYY-MM-DD',
+        ll : 'YYYY [m.] MMMM D [d.]',
+        lll : 'YYYY [m.] MMMM D [d.], HH:mm [val.]',
+        llll : 'YYYY [m.] MMMM D [d.], ddd, HH:mm [val.]'
+    },
+    calendar : {
+        sameDay : '[Å iandien] LT',
+        nextDay : '[Rytoj] LT',
+        nextWeek : 'dddd LT',
+        lastDay : '[Vakar] LT',
+        lastWeek : '[Praėjusį] dddd LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'po %s',
+        past : 'prieš %s',
+        s : translateSeconds,
+        m : translateSingular,
+        mm : translate,
+        h : translateSingular,
+        hh : translate,
+        d : translateSingular,
+        dd : translate,
+        M : translateSingular,
+        MM : translate,
+        y : translateSingular,
+        yy : translate
+    },
+    ordinalParse: /\d{1,2}-oji/,
+    ordinal : function (number) {
+        return number + '-oji';
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return lt;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/lv.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/lv.js
new file mode 100644
index 0000000000000000000000000000000000000000..d96991199346d81334014c3a611f02d943676426
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/lv.js
@@ -0,0 +1,97 @@
+//! moment.js locale configuration
+//! locale : Latvian [lv]
+//! author : Kristaps Karlsons : https://github.com/skakri
+//! author : Jānis Elmeris : https://github.com/JanisE
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var units = {
+    'm': 'minūtes_minūtēm_minūte_minūtes'.split('_'),
+    'mm': 'minūtes_minūtēm_minūte_minūtes'.split('_'),
+    'h': 'stundas_stundām_stunda_stundas'.split('_'),
+    'hh': 'stundas_stundām_stunda_stundas'.split('_'),
+    'd': 'dienas_dienām_diena_dienas'.split('_'),
+    'dd': 'dienas_dienām_diena_dienas'.split('_'),
+    'M': 'mēneša_mēnešiem_mēnesis_mēneši'.split('_'),
+    'MM': 'mēneša_mēnešiem_mēnesis_mēneši'.split('_'),
+    'y': 'gada_gadiem_gads_gadi'.split('_'),
+    'yy': 'gada_gadiem_gads_gadi'.split('_')
+};
+/**
+ * @param withoutSuffix boolean true = a length of time; false = before/after a period of time.
+ */
+function format(forms, number, withoutSuffix) {
+    if (withoutSuffix) {
+        // E.g. "21 minūte", "3 minūtes".
+        return number % 10 === 1 && number % 100 !== 11 ? forms[2] : forms[3];
+    } else {
+        // E.g. "21 minūtes" as in "pēc 21 minūtes".
+        // E.g. "3 minūtēm" as in "pēc 3 minūtēm".
+        return number % 10 === 1 && number % 100 !== 11 ? forms[0] : forms[1];
+    }
+}
+function relativeTimeWithPlural(number, withoutSuffix, key) {
+    return number + ' ' + format(units[key], number, withoutSuffix);
+}
+function relativeTimeWithSingular(number, withoutSuffix, key) {
+    return format(units[key], number, withoutSuffix);
+}
+function relativeSeconds(number, withoutSuffix) {
+    return withoutSuffix ? 'dažas sekundes' : 'dažām sekundēm';
+}
+
+var lv = moment.defineLocale('lv', {
+    months : 'janvāris_februāris_marts_aprīlis_maijs_jūnijs_jūlijs_augusts_septembris_oktobris_novembris_decembris'.split('_'),
+    monthsShort : 'jan_feb_mar_apr_mai_jūn_jūl_aug_sep_okt_nov_dec'.split('_'),
+    weekdays : 'svētdiena_pirmdiena_otrdiena_trešdiena_ceturtdiena_piektdiena_sestdiena'.split('_'),
+    weekdaysShort : 'Sv_P_O_T_C_Pk_S'.split('_'),
+    weekdaysMin : 'Sv_P_O_T_C_Pk_S'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY.',
+        LL : 'YYYY. [gada] D. MMMM',
+        LLL : 'YYYY. [gada] D. MMMM, HH:mm',
+        LLLL : 'YYYY. [gada] D. MMMM, dddd, HH:mm'
+    },
+    calendar : {
+        sameDay : '[Å odien pulksten] LT',
+        nextDay : '[Rīt pulksten] LT',
+        nextWeek : 'dddd [pulksten] LT',
+        lastDay : '[Vakar pulksten] LT',
+        lastWeek : '[Pagājušā] dddd [pulksten] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'pēc %s',
+        past : 'pirms %s',
+        s : relativeSeconds,
+        m : relativeTimeWithSingular,
+        mm : relativeTimeWithPlural,
+        h : relativeTimeWithSingular,
+        hh : relativeTimeWithPlural,
+        d : relativeTimeWithSingular,
+        dd : relativeTimeWithPlural,
+        M : relativeTimeWithSingular,
+        MM : relativeTimeWithPlural,
+        y : relativeTimeWithSingular,
+        yy : relativeTimeWithPlural
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return lv;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/me.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/me.js
new file mode 100644
index 0000000000000000000000000000000000000000..292970e72d5b1960d7f8d820e5e89136f840f412
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/me.js
@@ -0,0 +1,111 @@
+//! moment.js locale configuration
+//! locale : Montenegrin [me]
+//! author : Miodrag Nikač <miodrag@restartit.me> : https://github.com/miodragnikac
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var translator = {
+    words: { //Different grammatical cases
+        m: ['jedan minut', 'jednog minuta'],
+        mm: ['minut', 'minuta', 'minuta'],
+        h: ['jedan sat', 'jednog sata'],
+        hh: ['sat', 'sata', 'sati'],
+        dd: ['dan', 'dana', 'dana'],
+        MM: ['mjesec', 'mjeseca', 'mjeseci'],
+        yy: ['godina', 'godine', 'godina']
+    },
+    correctGrammaticalCase: function (number, wordKey) {
+        return number === 1 ? wordKey[0] : (number >= 2 && number <= 4 ? wordKey[1] : wordKey[2]);
+    },
+    translate: function (number, withoutSuffix, key) {
+        var wordKey = translator.words[key];
+        if (key.length === 1) {
+            return withoutSuffix ? wordKey[0] : wordKey[1];
+        } else {
+            return number + ' ' + translator.correctGrammaticalCase(number, wordKey);
+        }
+    }
+};
+
+var me = moment.defineLocale('me', {
+    months: 'januar_februar_mart_april_maj_jun_jul_avgust_septembar_oktobar_novembar_decembar'.split('_'),
+    monthsShort: 'jan._feb._mar._apr._maj_jun_jul_avg._sep._okt._nov._dec.'.split('_'),
+    monthsParseExact : true,
+    weekdays: 'nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota'.split('_'),
+    weekdaysShort: 'ned._pon._uto._sri._čet._pet._sub.'.split('_'),
+    weekdaysMin: 'ne_po_ut_sr_če_pe_su'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat: {
+        LT: 'H:mm',
+        LTS : 'H:mm:ss',
+        L: 'DD.MM.YYYY',
+        LL: 'D. MMMM YYYY',
+        LLL: 'D. MMMM YYYY H:mm',
+        LLLL: 'dddd, D. MMMM YYYY H:mm'
+    },
+    calendar: {
+        sameDay: '[danas u] LT',
+        nextDay: '[sjutra u] LT',
+
+        nextWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[u] [nedjelju] [u] LT';
+                case 3:
+                    return '[u] [srijedu] [u] LT';
+                case 6:
+                    return '[u] [subotu] [u] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[u] dddd [u] LT';
+            }
+        },
+        lastDay  : '[juče u] LT',
+        lastWeek : function () {
+            var lastWeekDays = [
+                '[prošle] [nedjelje] [u] LT',
+                '[prošlog] [ponedjeljka] [u] LT',
+                '[prošlog] [utorka] [u] LT',
+                '[prošle] [srijede] [u] LT',
+                '[prošlog] [četvrtka] [u] LT',
+                '[prošlog] [petka] [u] LT',
+                '[prošle] [subote] [u] LT'
+            ];
+            return lastWeekDays[this.day()];
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'za %s',
+        past   : 'prije %s',
+        s      : 'nekoliko sekundi',
+        m      : translator.translate,
+        mm     : translator.translate,
+        h      : translator.translate,
+        hh     : translator.translate,
+        d      : 'dan',
+        dd     : translator.translate,
+        M      : 'mjesec',
+        MM     : translator.translate,
+        y      : 'godinu',
+        yy     : translator.translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return me;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/mi.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/mi.js
new file mode 100644
index 0000000000000000000000000000000000000000..03b65a47e973bec828ec5f1b75053471cf3708e7
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/mi.js
@@ -0,0 +1,64 @@
+//! moment.js locale configuration
+//! locale : Maori [mi]
+//! author : John Corrigan <robbiecloset@gmail.com> : https://github.com/johnideal
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var mi = moment.defineLocale('mi', {
+    months: 'Kohi-tāte_Hui-tanguru_Poutū-te-rangi_Paenga-whāwhā_Haratua_Pipiri_Hōngoingoi_Here-turi-kōkā_Mahuru_Whiringa-ā-nuku_Whiringa-ā-rangi_Hakihea'.split('_'),
+    monthsShort: 'Kohi_Hui_Pou_Pae_Hara_Pipi_Hōngoi_Here_Mahu_Whi-nu_Whi-ra_Haki'.split('_'),
+    monthsRegex: /(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,
+    monthsStrictRegex: /(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,
+    monthsShortRegex: /(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,
+    monthsShortStrictRegex: /(?:['a-z\u0101\u014D\u016B]+\-?){1,2}/i,
+    weekdays: 'Rātapu_Mane_Tūrei_Wenerei_Tāite_Paraire_Hātarei'.split('_'),
+    weekdaysShort: 'Ta_Ma_Tū_We_Tāi_Pa_Hā'.split('_'),
+    weekdaysMin: 'Ta_Ma_Tū_We_Tāi_Pa_Hā'.split('_'),
+    longDateFormat: {
+        LT: 'HH:mm',
+        LTS: 'HH:mm:ss',
+        L: 'DD/MM/YYYY',
+        LL: 'D MMMM YYYY',
+        LLL: 'D MMMM YYYY [i] HH:mm',
+        LLLL: 'dddd, D MMMM YYYY [i] HH:mm'
+    },
+    calendar: {
+        sameDay: '[i teie mahana, i] LT',
+        nextDay: '[apopo i] LT',
+        nextWeek: 'dddd [i] LT',
+        lastDay: '[inanahi i] LT',
+        lastWeek: 'dddd [whakamutunga i] LT',
+        sameElse: 'L'
+    },
+    relativeTime: {
+        future: 'i roto i %s',
+        past: '%s i mua',
+        s: 'te hēkona ruarua',
+        m: 'he meneti',
+        mm: '%d meneti',
+        h: 'te haora',
+        hh: '%d haora',
+        d: 'he ra',
+        dd: '%d ra',
+        M: 'he marama',
+        MM: '%d marama',
+        y: 'he tau',
+        yy: '%d tau'
+    },
+    ordinalParse: /\d{1,2}º/,
+    ordinal: '%dº',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return mi;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/mk.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/mk.js
new file mode 100644
index 0000000000000000000000000000000000000000..52758d3e8aa01420504eaeff935c18a67ce9b49d
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/mk.js
@@ -0,0 +1,90 @@
+//! moment.js locale configuration
+//! locale : Macedonian [mk]
+//! author : Borislav Mickov : https://github.com/B0k0
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var mk = moment.defineLocale('mk', {
+    months : 'јануари_февруари_март_април_мај_јуни_јули_август_септември_октомври_ноември_декември'.split('_'),
+    monthsShort : 'јан_фев_мар_апр_мај_јун_јул_авг_сеп_окт_ное_дек'.split('_'),
+    weekdays : 'недела_понеделник_вторник_среда_четврток_петок_сабота'.split('_'),
+    weekdaysShort : 'нед_пон_вто_сре_чет_пет_саб'.split('_'),
+    weekdaysMin : 'нe_пo_вт_ср_че_пе_сa'.split('_'),
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'D.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY H:mm',
+        LLLL : 'dddd, D MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay : '[Денес во] LT',
+        nextDay : '[Утре во] LT',
+        nextWeek : '[Во] dddd [во] LT',
+        lastDay : '[Вчера во] LT',
+        lastWeek : function () {
+            switch (this.day()) {
+                case 0:
+                case 3:
+                case 6:
+                    return '[Изминатата] dddd [во] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[Изминатиот] dddd [во] LT';
+            }
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'после %s',
+        past : 'пред %s',
+        s : 'неколку секунди',
+        m : 'минута',
+        mm : '%d минути',
+        h : 'час',
+        hh : '%d часа',
+        d : 'ден',
+        dd : '%d дена',
+        M : 'месец',
+        MM : '%d месеци',
+        y : 'година',
+        yy : '%d години'
+    },
+    ordinalParse: /\d{1,2}-(ев|ен|ти|ви|ри|ми)/,
+    ordinal : function (number) {
+        var lastDigit = number % 10,
+            last2Digits = number % 100;
+        if (number === 0) {
+            return number + '-ев';
+        } else if (last2Digits === 0) {
+            return number + '-ен';
+        } else if (last2Digits > 10 && last2Digits < 20) {
+            return number + '-ти';
+        } else if (lastDigit === 1) {
+            return number + '-ви';
+        } else if (lastDigit === 2) {
+            return number + '-ри';
+        } else if (lastDigit === 7 || lastDigit === 8) {
+            return number + '-ми';
+        } else {
+            return number + '-ти';
+        }
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return mk;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ml.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ml.js
new file mode 100644
index 0000000000000000000000000000000000000000..e5f52e9c9a91edaff6d006b11373c7fe0331c0e7
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ml.js
@@ -0,0 +1,81 @@
+//! moment.js locale configuration
+//! locale : Malayalam [ml]
+//! author : Floyd Pink : https://github.com/floydpink
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var ml = moment.defineLocale('ml', {
+    months : 'ജനുവരി_ഫെബ്രുവരി_മാർച്ച്_ഏപ്രിൽ_മേയ്_ജൂൺ_ജൂലൈ_ഓഗസ്റ്റ്_സെപ്റ്റംബർ_ഒക്ടോബർ_നവംബർ_ഡിസംബർ'.split('_'),
+    monthsShort : 'ജനു._ഫെബ്രു._മാർ._ഏപ്രി._മേയ്_ജൂൺ_ജൂലൈ._ഓഗ._സെപ്റ്റ._ഒക്ടോ._നവം._ഡിസം.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'ഞായറാഴ്ച_തിങ്കളാഴ്ച_ചൊവ്വാഴ്ച_ബുധനാഴ്ച_വ്യാഴാഴ്ച_വെള്ളിയാഴ്ച_ശനിയാഴ്ച'.split('_'),
+    weekdaysShort : 'ഞായർ_തിങ്കൾ_ചൊവ്വ_ബുധൻ_വ്യാഴം_വെള്ളി_ശനി'.split('_'),
+    weekdaysMin : 'ഞാ_തി_ചൊ_ബു_വ്യാ_വെ_ശ'.split('_'),
+    longDateFormat : {
+        LT : 'A h:mm -നു',
+        LTS : 'A h:mm:ss -നു',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, A h:mm -നു',
+        LLLL : 'dddd, D MMMM YYYY, A h:mm -നു'
+    },
+    calendar : {
+        sameDay : '[ഇന്ന്] LT',
+        nextDay : '[നാളെ] LT',
+        nextWeek : 'dddd, LT',
+        lastDay : '[ഇന്നലെ] LT',
+        lastWeek : '[കഴിഞ്ഞ] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s കഴിഞ്ഞ്',
+        past : '%s മുൻപ്',
+        s : 'അൽപ നിമിഷങ്ങൾ',
+        m : 'ഒരു മിനിറ്റ്',
+        mm : '%d മിനിറ്റ്',
+        h : 'ഒരു മണിക്കൂർ',
+        hh : '%d മണിക്കൂർ',
+        d : 'ഒരു ദിവസം',
+        dd : '%d ദിവസം',
+        M : 'ഒരു മാസം',
+        MM : '%d മാസം',
+        y : 'ഒരു വർഷം',
+        yy : '%d വർഷം'
+    },
+    meridiemParse: /രാത്രി|രാവിലെ|ഉച്ച കഴിഞ്ഞ്|വൈകുന്നേരം|രാത്രി/i,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if ((meridiem === 'രാത്രി' && hour >= 4) ||
+                meridiem === 'ഉച്ച കഴിഞ്ഞ്' ||
+                meridiem === 'വൈകുന്നേരം') {
+            return hour + 12;
+        } else {
+            return hour;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'രാത്രി';
+        } else if (hour < 12) {
+            return 'രാവിലെ';
+        } else if (hour < 17) {
+            return 'ഉച്ച കഴിഞ്ഞ്';
+        } else if (hour < 20) {
+            return 'വൈകുന്നേരം';
+        } else {
+            return 'രാത്രി';
+        }
+    }
+});
+
+return ml;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/mr.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/mr.js
new file mode 100644
index 0000000000000000000000000000000000000000..abe1024b131f6238c1f7cf7d31c5c37b59fb2655
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/mr.js
@@ -0,0 +1,159 @@
+//! moment.js locale configuration
+//! locale : Marathi [mr]
+//! author : Harshad Kale : https://github.com/kalehv
+//! author : Vivek Athalye : https://github.com/vnathalye
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var symbolMap = {
+    '1': '१',
+    '2': '२',
+    '3': '३',
+    '4': '४',
+    '5': '५',
+    '6': '६',
+    '7': '७',
+    '8': '८',
+    '9': '९',
+    '0': '०'
+};
+var numberMap = {
+    '१': '1',
+    '२': '2',
+    '३': '3',
+    '४': '4',
+    '५': '5',
+    '६': '6',
+    '७': '7',
+    '८': '8',
+    '९': '9',
+    '०': '0'
+};
+
+function relativeTimeMr(number, withoutSuffix, string, isFuture)
+{
+    var output = '';
+    if (withoutSuffix) {
+        switch (string) {
+            case 's': output = 'काही सेकंद'; break;
+            case 'm': output = 'एक मिनिट'; break;
+            case 'mm': output = '%d मिनिटे'; break;
+            case 'h': output = 'एक तास'; break;
+            case 'hh': output = '%d तास'; break;
+            case 'd': output = 'एक दिवस'; break;
+            case 'dd': output = '%d दिवस'; break;
+            case 'M': output = 'एक महिना'; break;
+            case 'MM': output = '%d महिने'; break;
+            case 'y': output = 'एक वर्ष'; break;
+            case 'yy': output = '%d वर्षे'; break;
+        }
+    }
+    else {
+        switch (string) {
+            case 's': output = 'काही सेकंदां'; break;
+            case 'm': output = 'एका मिनिटा'; break;
+            case 'mm': output = '%d मिनिटां'; break;
+            case 'h': output = 'एका तासा'; break;
+            case 'hh': output = '%d तासां'; break;
+            case 'd': output = 'एका दिवसा'; break;
+            case 'dd': output = '%d दिवसां'; break;
+            case 'M': output = 'एका महिन्या'; break;
+            case 'MM': output = '%d महिन्यां'; break;
+            case 'y': output = 'एका वर्षा'; break;
+            case 'yy': output = '%d वर्षां'; break;
+        }
+    }
+    return output.replace(/%d/i, number);
+}
+
+var mr = moment.defineLocale('mr', {
+    months : 'जानेवारी_फेब्रुवारी_मार्च_एप्रिल_मे_जून_जुलै_ऑगस्ट_सप्टेंबर_ऑक्टोबर_नोव्हेंबर_डिसेंबर'.split('_'),
+    monthsShort: 'जाने._फेब्रु._मार्च._एप्रि._मे._जून._जुलै._ऑग._सप्टें._ऑक्टो._नोव्हें._डिसें.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'रविवार_सोमवार_मंगळवार_बुधवार_गुरूवार_शुक्रवार_शनिवार'.split('_'),
+    weekdaysShort : 'रवि_सोम_मंगळ_बुध_गुरू_शुक्र_शनि'.split('_'),
+    weekdaysMin : 'र_सो_मं_बु_गु_शु_श'.split('_'),
+    longDateFormat : {
+        LT : 'A h:mm वाजता',
+        LTS : 'A h:mm:ss वाजता',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, A h:mm वाजता',
+        LLLL : 'dddd, D MMMM YYYY, A h:mm वाजता'
+    },
+    calendar : {
+        sameDay : '[आज] LT',
+        nextDay : '[उद्या] LT',
+        nextWeek : 'dddd, LT',
+        lastDay : '[काल] LT',
+        lastWeek: '[मागील] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future: '%sमध्ये',
+        past: '%sपूर्वी',
+        s: relativeTimeMr,
+        m: relativeTimeMr,
+        mm: relativeTimeMr,
+        h: relativeTimeMr,
+        hh: relativeTimeMr,
+        d: relativeTimeMr,
+        dd: relativeTimeMr,
+        M: relativeTimeMr,
+        MM: relativeTimeMr,
+        y: relativeTimeMr,
+        yy: relativeTimeMr
+    },
+    preparse: function (string) {
+        return string.replace(/[१२३४५६७८९०]/g, function (match) {
+            return numberMap[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap[match];
+        });
+    },
+    meridiemParse: /रात्री|सकाळी|दुपारी|सायंकाळी/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'रात्री') {
+            return hour < 4 ? hour : hour + 12;
+        } else if (meridiem === 'सकाळी') {
+            return hour;
+        } else if (meridiem === 'दुपारी') {
+            return hour >= 10 ? hour : hour + 12;
+        } else if (meridiem === 'सायंकाळी') {
+            return hour + 12;
+        }
+    },
+    meridiem: function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'रात्री';
+        } else if (hour < 10) {
+            return 'सकाळी';
+        } else if (hour < 17) {
+            return 'दुपारी';
+        } else if (hour < 20) {
+            return 'सायंकाळी';
+        } else {
+            return 'रात्री';
+        }
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return mr;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ms-my.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ms-my.js
new file mode 100644
index 0000000000000000000000000000000000000000..0cb403d347a00e92a445d7753026bb5963a87923
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ms-my.js
@@ -0,0 +1,83 @@
+//! moment.js locale configuration
+//! locale : Malay [ms-my]
+//! note : DEPRECATED, the correct one is [ms]
+//! author : Weldan Jamili : https://github.com/weldan
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var msMy = moment.defineLocale('ms-my', {
+    months : 'Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember'.split('_'),
+    monthsShort : 'Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis'.split('_'),
+    weekdays : 'Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu'.split('_'),
+    weekdaysShort : 'Ahd_Isn_Sel_Rab_Kha_Jum_Sab'.split('_'),
+    weekdaysMin : 'Ah_Is_Sl_Rb_Km_Jm_Sb'.split('_'),
+    longDateFormat : {
+        LT : 'HH.mm',
+        LTS : 'HH.mm.ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY [pukul] HH.mm',
+        LLLL : 'dddd, D MMMM YYYY [pukul] HH.mm'
+    },
+    meridiemParse: /pagi|tengahari|petang|malam/,
+    meridiemHour: function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'pagi') {
+            return hour;
+        } else if (meridiem === 'tengahari') {
+            return hour >= 11 ? hour : hour + 12;
+        } else if (meridiem === 'petang' || meridiem === 'malam') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 11) {
+            return 'pagi';
+        } else if (hours < 15) {
+            return 'tengahari';
+        } else if (hours < 19) {
+            return 'petang';
+        } else {
+            return 'malam';
+        }
+    },
+    calendar : {
+        sameDay : '[Hari ini pukul] LT',
+        nextDay : '[Esok pukul] LT',
+        nextWeek : 'dddd [pukul] LT',
+        lastDay : '[Kelmarin pukul] LT',
+        lastWeek : 'dddd [lepas pukul] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'dalam %s',
+        past : '%s yang lepas',
+        s : 'beberapa saat',
+        m : 'seminit',
+        mm : '%d minit',
+        h : 'sejam',
+        hh : '%d jam',
+        d : 'sehari',
+        dd : '%d hari',
+        M : 'sebulan',
+        MM : '%d bulan',
+        y : 'setahun',
+        yy : '%d tahun'
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return msMy;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ms.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ms.js
new file mode 100644
index 0000000000000000000000000000000000000000..4d4afff5dfc9ec737bca78792cecb36c893c18bb
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ms.js
@@ -0,0 +1,82 @@
+//! moment.js locale configuration
+//! locale : Malay [ms]
+//! author : Weldan Jamili : https://github.com/weldan
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var ms = moment.defineLocale('ms', {
+    months : 'Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember'.split('_'),
+    monthsShort : 'Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis'.split('_'),
+    weekdays : 'Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu'.split('_'),
+    weekdaysShort : 'Ahd_Isn_Sel_Rab_Kha_Jum_Sab'.split('_'),
+    weekdaysMin : 'Ah_Is_Sl_Rb_Km_Jm_Sb'.split('_'),
+    longDateFormat : {
+        LT : 'HH.mm',
+        LTS : 'HH.mm.ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY [pukul] HH.mm',
+        LLLL : 'dddd, D MMMM YYYY [pukul] HH.mm'
+    },
+    meridiemParse: /pagi|tengahari|petang|malam/,
+    meridiemHour: function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'pagi') {
+            return hour;
+        } else if (meridiem === 'tengahari') {
+            return hour >= 11 ? hour : hour + 12;
+        } else if (meridiem === 'petang' || meridiem === 'malam') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 11) {
+            return 'pagi';
+        } else if (hours < 15) {
+            return 'tengahari';
+        } else if (hours < 19) {
+            return 'petang';
+        } else {
+            return 'malam';
+        }
+    },
+    calendar : {
+        sameDay : '[Hari ini pukul] LT',
+        nextDay : '[Esok pukul] LT',
+        nextWeek : 'dddd [pukul] LT',
+        lastDay : '[Kelmarin pukul] LT',
+        lastWeek : 'dddd [lepas pukul] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'dalam %s',
+        past : '%s yang lepas',
+        s : 'beberapa saat',
+        m : 'seminit',
+        mm : '%d minit',
+        h : 'sejam',
+        hh : '%d jam',
+        d : 'sehari',
+        dd : '%d hari',
+        M : 'sebulan',
+        MM : '%d bulan',
+        y : 'setahun',
+        yy : '%d tahun'
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return ms;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/my.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/my.js
new file mode 100644
index 0000000000000000000000000000000000000000..32d67e2bae58f30416deca70aa1b691d12f67c9f
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/my.js
@@ -0,0 +1,96 @@
+//! moment.js locale configuration
+//! locale : Burmese [my]
+//! author : Squar team, mysquar.com
+//! author : David Rossellat : https://github.com/gholadr
+//! author : Tin Aung Lin : https://github.com/thanyawzinmin
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var symbolMap = {
+    '1': '၁',
+    '2': '၂',
+    '3': '၃',
+    '4': '၄',
+    '5': '၅',
+    '6': '၆',
+    '7': '၇',
+    '8': '၈',
+    '9': '၉',
+    '0': '၀'
+};
+var numberMap = {
+    '၁': '1',
+    '၂': '2',
+    '၃': '3',
+    '၄': '4',
+    '၅': '5',
+    '၆': '6',
+    '၇': '7',
+    '၈': '8',
+    '၉': '9',
+    '၀': '0'
+};
+
+var my = moment.defineLocale('my', {
+    months: 'ဇန်နဝါရီ_ဖေဖော်ဝါရီ_မတ်_ဧပြီ_မေ_ဇွန်_ဇူလိုင်_သြဂုတ်_စက်တင်ဘာ_အောက်တိုဘာ_နိုဝင်ဘာ_ဒီဇင်ဘာ'.split('_'),
+    monthsShort: 'ဇန်_ဖေ_မတ်_ပြီ_မေ_ဇွန်_လိုင်_သြ_စက်_အောက်_နို_ဒီ'.split('_'),
+    weekdays: 'တနင်္ဂနွေ_တနင်္လာ_အင်္ဂါ_ဗုဒ္ဓဟူး_ကြာသပတေး_သောကြာ_စနေ'.split('_'),
+    weekdaysShort: 'နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ'.split('_'),
+    weekdaysMin: 'နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ'.split('_'),
+
+    longDateFormat: {
+        LT: 'HH:mm',
+        LTS: 'HH:mm:ss',
+        L: 'DD/MM/YYYY',
+        LL: 'D MMMM YYYY',
+        LLL: 'D MMMM YYYY HH:mm',
+        LLLL: 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar: {
+        sameDay: '[ယနေ.] LT [မှာ]',
+        nextDay: '[မနက်ဖြန်] LT [မှာ]',
+        nextWeek: 'dddd LT [မှာ]',
+        lastDay: '[မနေ.က] LT [မှာ]',
+        lastWeek: '[ပြီးခဲ့သော] dddd LT [မှာ]',
+        sameElse: 'L'
+    },
+    relativeTime: {
+        future: 'လာမည့် %s မှာ',
+        past: 'လွန်ခဲ့သော %s က',
+        s: 'စက္ကန်.အနည်းငယ်',
+        m: 'တစ်မိနစ်',
+        mm: '%d မိနစ်',
+        h: 'တစ်နာရီ',
+        hh: '%d နာရီ',
+        d: 'တစ်ရက်',
+        dd: '%d ရက်',
+        M: 'တစ်လ',
+        MM: '%d လ',
+        y: 'တစ်နှစ်',
+        yy: '%d နှစ်'
+    },
+    preparse: function (string) {
+        return string.replace(/[၁၂၃၄၅၆၇၈၉၀]/g, function (match) {
+            return numberMap[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap[match];
+        });
+    },
+    week: {
+        dow: 1, // Monday is the first day of the week.
+        doy: 4 // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return my;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/nb.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/nb.js
new file mode 100644
index 0000000000000000000000000000000000000000..b77e576dc6cfa39e8b89b97d226790fb491a508f
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/nb.js
@@ -0,0 +1,63 @@
+//! moment.js locale configuration
+//! locale : Norwegian Bokmål [nb]
+//! authors : Espen Hovlandsdal : https://github.com/rexxars
+//!           Sigurd Gartmann : https://github.com/sigurdga
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var nb = moment.defineLocale('nb', {
+    months : 'januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember'.split('_'),
+    monthsShort : 'jan._feb._mars_april_mai_juni_juli_aug._sep._okt._nov._des.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag'.split('_'),
+    weekdaysShort : 'sø._ma._ti._on._to._fr._lø.'.split('_'),
+    weekdaysMin : 'sø_ma_ti_on_to_fr_lø'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY [kl.] HH:mm',
+        LLLL : 'dddd D. MMMM YYYY [kl.] HH:mm'
+    },
+    calendar : {
+        sameDay: '[i dag kl.] LT',
+        nextDay: '[i morgen kl.] LT',
+        nextWeek: 'dddd [kl.] LT',
+        lastDay: '[i går kl.] LT',
+        lastWeek: '[forrige] dddd [kl.] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'om %s',
+        past : '%s siden',
+        s : 'noen sekunder',
+        m : 'ett minutt',
+        mm : '%d minutter',
+        h : 'en time',
+        hh : '%d timer',
+        d : 'en dag',
+        dd : '%d dager',
+        M : 'en måned',
+        MM : '%d måneder',
+        y : 'ett år',
+        yy : '%d år'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return nb;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ne.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ne.js
new file mode 100644
index 0000000000000000000000000000000000000000..a35947a9e311a4ddbd0f3ba03e51186be8351b02
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ne.js
@@ -0,0 +1,123 @@
+//! moment.js locale configuration
+//! locale : Nepalese [ne]
+//! author : suvash : https://github.com/suvash
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var symbolMap = {
+    '1': '१',
+    '2': '२',
+    '3': '३',
+    '4': '४',
+    '5': '५',
+    '6': '६',
+    '7': '७',
+    '8': '८',
+    '9': '९',
+    '0': '०'
+};
+var numberMap = {
+    '१': '1',
+    '२': '2',
+    '३': '3',
+    '४': '4',
+    '५': '5',
+    '६': '6',
+    '७': '7',
+    '८': '8',
+    '९': '9',
+    '०': '0'
+};
+
+var ne = moment.defineLocale('ne', {
+    months : 'जनवरी_फेब्रुवरी_मार्च_अप्रिल_मई_जुन_जुलाई_अगष्ट_सेप्टेम्बर_अक्टोबर_नोभेम्बर_डिसेम्बर'.split('_'),
+    monthsShort : 'जन._फेब्रु._मार्च_अप्रि._मई_जुन_जुलाई._अग._सेप्ट._अक्टो._नोभे._डिसे.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'आइतबार_सोमबार_मङ्गलबार_बुधबार_बिहिबार_शुक्रबार_शनिबार'.split('_'),
+    weekdaysShort : 'आइत._सोम._मङ्गल._बुध._बिहि._शुक्र._शनि.'.split('_'),
+    weekdaysMin : 'आ._सो._मं._बु._बि._शु._श.'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'Aको h:mm बजे',
+        LTS : 'Aको h:mm:ss बजे',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, Aको h:mm बजे',
+        LLLL : 'dddd, D MMMM YYYY, Aको h:mm बजे'
+    },
+    preparse: function (string) {
+        return string.replace(/[१२३४५६७८९०]/g, function (match) {
+            return numberMap[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap[match];
+        });
+    },
+    meridiemParse: /राति|बिहान|दिउँसो|साँझ/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'राति') {
+            return hour < 4 ? hour : hour + 12;
+        } else if (meridiem === 'बिहान') {
+            return hour;
+        } else if (meridiem === 'दिउँसो') {
+            return hour >= 10 ? hour : hour + 12;
+        } else if (meridiem === 'साँझ') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 3) {
+            return 'राति';
+        } else if (hour < 12) {
+            return 'बिहान';
+        } else if (hour < 16) {
+            return 'दिउँसो';
+        } else if (hour < 20) {
+            return 'साँझ';
+        } else {
+            return 'राति';
+        }
+    },
+    calendar : {
+        sameDay : '[आज] LT',
+        nextDay : '[भोलि] LT',
+        nextWeek : '[आउँदो] dddd[,] LT',
+        lastDay : '[हिजो] LT',
+        lastWeek : '[गएको] dddd[,] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%sमा',
+        past : '%s अगाडि',
+        s : 'केही क्षण',
+        m : 'एक मिनेट',
+        mm : '%d मिनेट',
+        h : 'एक घण्टा',
+        hh : '%d घण्टा',
+        d : 'एक दिन',
+        dd : '%d दिन',
+        M : 'एक महिना',
+        MM : '%d महिना',
+        y : 'एक बर्ष',
+        yy : '%d बर्ष'
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return ne;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/nl-be.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/nl-be.js
new file mode 100644
index 0000000000000000000000000000000000000000..aaa5d74ac2bfd2f19ec8b13743cefcddfdb8b96f
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/nl-be.js
@@ -0,0 +1,86 @@
+//! moment.js locale configuration
+//! locale : Dutch (Belgium) [nl-be]
+//! author : Joris Röling : https://github.com/jorisroling
+//! author : Jacob Middag : https://github.com/middagj
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var monthsShortWithDots = 'jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.'.split('_');
+var monthsShortWithoutDots = 'jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec'.split('_');
+
+var monthsParse = [/^jan/i, /^feb/i, /^maart|mrt.?$/i, /^apr/i, /^mei$/i, /^jun[i.]?$/i, /^jul[i.]?$/i, /^aug/i, /^sep/i, /^okt/i, /^nov/i, /^dec/i];
+var monthsRegex = /^(januari|februari|maart|april|mei|april|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i;
+
+var nlBe = moment.defineLocale('nl-be', {
+    months : 'januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december'.split('_'),
+    monthsShort : function (m, format) {
+        if (/-MMM-/.test(format)) {
+            return monthsShortWithoutDots[m.month()];
+        } else {
+            return monthsShortWithDots[m.month()];
+        }
+    },
+
+    monthsRegex: monthsRegex,
+    monthsShortRegex: monthsRegex,
+    monthsStrictRegex: /^(januari|februari|maart|mei|ju[nl]i|april|augustus|september|oktober|november|december)/i,
+    monthsShortStrictRegex: /^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i,
+
+    monthsParse : monthsParse,
+    longMonthsParse : monthsParse,
+    shortMonthsParse : monthsParse,
+
+    weekdays : 'zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag'.split('_'),
+    weekdaysShort : 'zo._ma._di._wo._do._vr._za.'.split('_'),
+    weekdaysMin : 'Zo_Ma_Di_Wo_Do_Vr_Za'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[vandaag om] LT',
+        nextDay: '[morgen om] LT',
+        nextWeek: 'dddd [om] LT',
+        lastDay: '[gisteren om] LT',
+        lastWeek: '[afgelopen] dddd [om] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'over %s',
+        past : '%s geleden',
+        s : 'een paar seconden',
+        m : 'één minuut',
+        mm : '%d minuten',
+        h : 'één uur',
+        hh : '%d uur',
+        d : 'één dag',
+        dd : '%d dagen',
+        M : 'één maand',
+        MM : '%d maanden',
+        y : 'één jaar',
+        yy : '%d jaar'
+    },
+    ordinalParse: /\d{1,2}(ste|de)/,
+    ordinal : function (number) {
+        return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de');
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return nlBe;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/nl.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/nl.js
new file mode 100644
index 0000000000000000000000000000000000000000..15beaef13cf8bf92ea0a931157769ec77c0cf4e6
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/nl.js
@@ -0,0 +1,86 @@
+//! moment.js locale configuration
+//! locale : Dutch [nl]
+//! author : Joris Röling : https://github.com/jorisroling
+//! author : Jacob Middag : https://github.com/middagj
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var monthsShortWithDots = 'jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.'.split('_');
+var monthsShortWithoutDots = 'jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec'.split('_');
+
+var monthsParse = [/^jan/i, /^feb/i, /^maart|mrt.?$/i, /^apr/i, /^mei$/i, /^jun[i.]?$/i, /^jul[i.]?$/i, /^aug/i, /^sep/i, /^okt/i, /^nov/i, /^dec/i];
+var monthsRegex = /^(januari|februari|maart|april|mei|april|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i;
+
+var nl = moment.defineLocale('nl', {
+    months : 'januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december'.split('_'),
+    monthsShort : function (m, format) {
+        if (/-MMM-/.test(format)) {
+            return monthsShortWithoutDots[m.month()];
+        } else {
+            return monthsShortWithDots[m.month()];
+        }
+    },
+
+    monthsRegex: monthsRegex,
+    monthsShortRegex: monthsRegex,
+    monthsStrictRegex: /^(januari|februari|maart|mei|ju[nl]i|april|augustus|september|oktober|november|december)/i,
+    monthsShortStrictRegex: /^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i,
+
+    monthsParse : monthsParse,
+    longMonthsParse : monthsParse,
+    shortMonthsParse : monthsParse,
+
+    weekdays : 'zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag'.split('_'),
+    weekdaysShort : 'zo._ma._di._wo._do._vr._za.'.split('_'),
+    weekdaysMin : 'Zo_Ma_Di_Wo_Do_Vr_Za'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD-MM-YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[vandaag om] LT',
+        nextDay: '[morgen om] LT',
+        nextWeek: 'dddd [om] LT',
+        lastDay: '[gisteren om] LT',
+        lastWeek: '[afgelopen] dddd [om] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'over %s',
+        past : '%s geleden',
+        s : 'een paar seconden',
+        m : 'één minuut',
+        mm : '%d minuten',
+        h : 'één uur',
+        hh : '%d uur',
+        d : 'één dag',
+        dd : '%d dagen',
+        M : 'één maand',
+        MM : '%d maanden',
+        y : 'één jaar',
+        yy : '%d jaar'
+    },
+    ordinalParse: /\d{1,2}(ste|de)/,
+    ordinal : function (number) {
+        return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de');
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return nl;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/nn.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/nn.js
new file mode 100644
index 0000000000000000000000000000000000000000..cf39af5e7b928b210c81d5c2710371bae9281831
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/nn.js
@@ -0,0 +1,60 @@
+//! moment.js locale configuration
+//! locale : Nynorsk [nn]
+//! author : https://github.com/mechuwind
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var nn = moment.defineLocale('nn', {
+    months : 'januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember'.split('_'),
+    monthsShort : 'jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_'),
+    weekdays : 'sundag_måndag_tysdag_onsdag_torsdag_fredag_laurdag'.split('_'),
+    weekdaysShort : 'sun_mån_tys_ons_tor_fre_lau'.split('_'),
+    weekdaysMin : 'su_må_ty_on_to_fr_lø'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY [kl.] H:mm',
+        LLLL : 'dddd D. MMMM YYYY [kl.] HH:mm'
+    },
+    calendar : {
+        sameDay: '[I dag klokka] LT',
+        nextDay: '[I morgon klokka] LT',
+        nextWeek: 'dddd [klokka] LT',
+        lastDay: '[I går klokka] LT',
+        lastWeek: '[Føregåande] dddd [klokka] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'om %s',
+        past : '%s sidan',
+        s : 'nokre sekund',
+        m : 'eit minutt',
+        mm : '%d minutt',
+        h : 'ein time',
+        hh : '%d timar',
+        d : 'ein dag',
+        dd : '%d dagar',
+        M : 'ein månad',
+        MM : '%d månader',
+        y : 'eit år',
+        yy : '%d år'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return nn;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/pa-in.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/pa-in.js
new file mode 100644
index 0000000000000000000000000000000000000000..6dec8d172435aa759ebe4f0862003fdf72bd5309
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/pa-in.js
@@ -0,0 +1,124 @@
+//! moment.js locale configuration
+//! locale : Punjabi (India) [pa-in]
+//! author : Harpreet Singh : https://github.com/harpreetkhalsagtbit
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var symbolMap = {
+    '1': 'à©§',
+    '2': '੨',
+    '3': 'à©©',
+    '4': '੪',
+    '5': 'à©«',
+    '6': '੬',
+    '7': 'à©­',
+    '8': 'à©®',
+    '9': '੯',
+    '0': '੦'
+};
+var numberMap = {
+    'à©§': '1',
+    '੨': '2',
+    'à©©': '3',
+    '੪': '4',
+    'à©«': '5',
+    '੬': '6',
+    'à©­': '7',
+    'à©®': '8',
+    '੯': '9',
+    '੦': '0'
+};
+
+var paIn = moment.defineLocale('pa-in', {
+    // There are months name as per Nanakshahi Calender but they are not used as rigidly in modern Punjabi.
+    months : 'ਜਨਵਰੀ_ਫ਼ਰਵਰੀ_ਮਾਰਚ_ਅਪ੍ਰੈਲ_ਮਈ_ਜੂਨ_ਜੁਲਾਈ_ਅਗਸਤ_ਸਤੰਬਰ_ਅਕਤੂਬਰ_ਨਵੰਬਰ_ਦਸੰਬਰ'.split('_'),
+    monthsShort : 'ਜਨਵਰੀ_ਫ਼ਰਵਰੀ_ਮਾਰਚ_ਅਪ੍ਰੈਲ_ਮਈ_ਜੂਨ_ਜੁਲਾਈ_ਅਗਸਤ_ਸਤੰਬਰ_ਅਕਤੂਬਰ_ਨਵੰਬਰ_ਦਸੰਬਰ'.split('_'),
+    weekdays : 'ਐਤਵਾਰ_ਸੋਮਵਾਰ_ਮੰਗਲਵਾਰ_ਬੁਧਵਾਰ_ਵੀਰਵਾਰ_ਸ਼ੁੱਕਰਵਾਰ_ਸ਼ਨੀਚਰਵਾਰ'.split('_'),
+    weekdaysShort : 'ਐਤ_ਸੋਮ_ਮੰਗਲ_ਬੁਧ_ਵੀਰ_ਸ਼ੁਕਰ_ਸ਼ਨੀ'.split('_'),
+    weekdaysMin : 'ਐਤ_ਸੋਮ_ਮੰਗਲ_ਬੁਧ_ਵੀਰ_ਸ਼ੁਕਰ_ਸ਼ਨੀ'.split('_'),
+    longDateFormat : {
+        LT : 'A h:mm ਵਜੇ',
+        LTS : 'A h:mm:ss ਵਜੇ',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, A h:mm ਵਜੇ',
+        LLLL : 'dddd, D MMMM YYYY, A h:mm ਵਜੇ'
+    },
+    calendar : {
+        sameDay : '[ਅਜ] LT',
+        nextDay : '[ਕਲ] LT',
+        nextWeek : 'dddd, LT',
+        lastDay : '[ਕਲ] LT',
+        lastWeek : '[ਪਿਛਲੇ] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s ਵਿੱਚ',
+        past : '%s ਪਿਛਲੇ',
+        s : 'ਕੁਝ ਸਕਿੰਟ',
+        m : 'ਇਕ ਮਿੰਟ',
+        mm : '%d ਮਿੰਟ',
+        h : 'ਇੱਕ ਘੰਟਾ',
+        hh : '%d ਘੰਟੇ',
+        d : 'ਇੱਕ ਦਿਨ',
+        dd : '%d ਦਿਨ',
+        M : 'ਇੱਕ ਮਹੀਨਾ',
+        MM : '%d ਮਹੀਨੇ',
+        y : 'ਇੱਕ ਸਾਲ',
+        yy : '%d ਸਾਲ'
+    },
+    preparse: function (string) {
+        return string.replace(/[੧੨੩੪੫੬੭੮੯੦]/g, function (match) {
+            return numberMap[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap[match];
+        });
+    },
+    // Punjabi notation for meridiems are quite fuzzy in practice. While there exists
+    // a rigid notion of a 'Pahar' it is not used as rigidly in modern Punjabi.
+    meridiemParse: /ਰਾਤ|ਸਵੇਰ|ਦੁਪਹਿਰ|ਸ਼ਾਮ/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'ਰਾਤ') {
+            return hour < 4 ? hour : hour + 12;
+        } else if (meridiem === 'ਸਵੇਰ') {
+            return hour;
+        } else if (meridiem === 'ਦੁਪਹਿਰ') {
+            return hour >= 10 ? hour : hour + 12;
+        } else if (meridiem === 'ਸ਼ਾਮ') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'ਰਾਤ';
+        } else if (hour < 10) {
+            return 'ਸਵੇਰ';
+        } else if (hour < 17) {
+            return 'ਦੁਪਹਿਰ';
+        } else if (hour < 20) {
+            return 'ਸ਼ਾਮ';
+        } else {
+            return 'ਰਾਤ';
+        }
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return paIn;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/pl.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/pl.js
new file mode 100644
index 0000000000000000000000000000000000000000..aab946b0d7cc4dae78393b581e38d9502d8c9452
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/pl.js
@@ -0,0 +1,105 @@
+//! moment.js locale configuration
+//! locale : Polish [pl]
+//! author : Rafal Hirsz : https://github.com/evoL
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var monthsNominative = 'styczeń_luty_marzec_kwiecień_maj_czerwiec_lipiec_sierpień_wrzesień_październik_listopad_grudzień'.split('_');
+var monthsSubjective = 'stycznia_lutego_marca_kwietnia_maja_czerwca_lipca_sierpnia_września_października_listopada_grudnia'.split('_');
+function plural(n) {
+    return (n % 10 < 5) && (n % 10 > 1) && ((~~(n / 10) % 10) !== 1);
+}
+function translate(number, withoutSuffix, key) {
+    var result = number + ' ';
+    switch (key) {
+        case 'm':
+            return withoutSuffix ? 'minuta' : 'minutÄ™';
+        case 'mm':
+            return result + (plural(number) ? 'minuty' : 'minut');
+        case 'h':
+            return withoutSuffix  ? 'godzina'  : 'godzinÄ™';
+        case 'hh':
+            return result + (plural(number) ? 'godziny' : 'godzin');
+        case 'MM':
+            return result + (plural(number) ? 'miesiące' : 'miesięcy');
+        case 'yy':
+            return result + (plural(number) ? 'lata' : 'lat');
+    }
+}
+
+var pl = moment.defineLocale('pl', {
+    months : function (momentToFormat, format) {
+        if (format === '') {
+            // Hack: if format empty we know this is used to generate
+            // RegExp by moment. Give then back both valid forms of months
+            // in RegExp ready format.
+            return '(' + monthsSubjective[momentToFormat.month()] + '|' + monthsNominative[momentToFormat.month()] + ')';
+        } else if (/D MMMM/.test(format)) {
+            return monthsSubjective[momentToFormat.month()];
+        } else {
+            return monthsNominative[momentToFormat.month()];
+        }
+    },
+    monthsShort : 'sty_lut_mar_kwi_maj_cze_lip_sie_wrz_paź_lis_gru'.split('_'),
+    weekdays : 'niedziela_poniedziałek_wtorek_środa_czwartek_piątek_sobota'.split('_'),
+    weekdaysShort : 'ndz_pon_wt_śr_czw_pt_sob'.split('_'),
+    weekdaysMin : 'Nd_Pn_Wt_Åšr_Cz_Pt_So'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[DziÅ› o] LT',
+        nextDay: '[Jutro o] LT',
+        nextWeek: '[W] dddd [o] LT',
+        lastDay: '[Wczoraj o] LT',
+        lastWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[W zeszłą niedzielę o] LT';
+                case 3:
+                    return '[W zeszłą środę o] LT';
+                case 6:
+                    return '[W zeszłą sobotę o] LT';
+                default:
+                    return '[W zeszły] dddd [o] LT';
+            }
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'za %s',
+        past : '%s temu',
+        s : 'kilka sekund',
+        m : translate,
+        mm : translate,
+        h : translate,
+        hh : translate,
+        d : '1 dzień',
+        dd : '%d dni',
+        M : 'miesiÄ…c',
+        MM : translate,
+        y : 'rok',
+        yy : translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return pl;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/pt-br.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/pt-br.js
new file mode 100644
index 0000000000000000000000000000000000000000..20897f78af8b7223d80938d9d1564caca9c3ecef
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/pt-br.js
@@ -0,0 +1,61 @@
+//! moment.js locale configuration
+//! locale : Portuguese (Brazil) [pt-br]
+//! author : Caio Ribeiro Pereira : https://github.com/caio-ribeiro-pereira
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var ptBr = moment.defineLocale('pt-br', {
+    months : 'Janeiro_Fevereiro_Março_Abril_Maio_Junho_Julho_Agosto_Setembro_Outubro_Novembro_Dezembro'.split('_'),
+    monthsShort : 'Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez'.split('_'),
+    weekdays : 'Domingo_Segunda-feira_Terça-feira_Quarta-feira_Quinta-feira_Sexta-feira_Sábado'.split('_'),
+    weekdaysShort : 'Dom_Seg_Ter_Qua_Qui_Sex_Sáb'.split('_'),
+    weekdaysMin : 'Dom_2ª_3ª_4ª_5ª_6ª_Sáb'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D [de] MMMM [de] YYYY',
+        LLL : 'D [de] MMMM [de] YYYY [às] HH:mm',
+        LLLL : 'dddd, D [de] MMMM [de] YYYY [às] HH:mm'
+    },
+    calendar : {
+        sameDay: '[Hoje às] LT',
+        nextDay: '[Amanhã às] LT',
+        nextWeek: 'dddd [às] LT',
+        lastDay: '[Ontem às] LT',
+        lastWeek: function () {
+            return (this.day() === 0 || this.day() === 6) ?
+                '[Último] dddd [às] LT' : // Saturday + Sunday
+                '[Última] dddd [às] LT'; // Monday - Friday
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'em %s',
+        past : '%s atrás',
+        s : 'poucos segundos',
+        m : 'um minuto',
+        mm : '%d minutos',
+        h : 'uma hora',
+        hh : '%d horas',
+        d : 'um dia',
+        dd : '%d dias',
+        M : 'um mês',
+        MM : '%d meses',
+        y : 'um ano',
+        yy : '%d anos'
+    },
+    ordinalParse: /\d{1,2}º/,
+    ordinal : '%dº'
+});
+
+return ptBr;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/pt.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/pt.js
new file mode 100644
index 0000000000000000000000000000000000000000..7a852285698f68d58cb64a357bb666eee13961cb
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/pt.js
@@ -0,0 +1,65 @@
+//! moment.js locale configuration
+//! locale : Portuguese [pt]
+//! author : Jefferson : https://github.com/jalex79
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var pt = moment.defineLocale('pt', {
+    months : 'Janeiro_Fevereiro_Março_Abril_Maio_Junho_Julho_Agosto_Setembro_Outubro_Novembro_Dezembro'.split('_'),
+    monthsShort : 'Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez'.split('_'),
+    weekdays : 'Domingo_Segunda-Feira_Terça-Feira_Quarta-Feira_Quinta-Feira_Sexta-Feira_Sábado'.split('_'),
+    weekdaysShort : 'Dom_Seg_Ter_Qua_Qui_Sex_Sáb'.split('_'),
+    weekdaysMin : 'Dom_2ª_3ª_4ª_5ª_6ª_Sáb'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D [de] MMMM [de] YYYY',
+        LLL : 'D [de] MMMM [de] YYYY HH:mm',
+        LLLL : 'dddd, D [de] MMMM [de] YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Hoje às] LT',
+        nextDay: '[Amanhã às] LT',
+        nextWeek: 'dddd [às] LT',
+        lastDay: '[Ontem às] LT',
+        lastWeek: function () {
+            return (this.day() === 0 || this.day() === 6) ?
+                '[Último] dddd [às] LT' : // Saturday + Sunday
+                '[Última] dddd [às] LT'; // Monday - Friday
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'em %s',
+        past : 'há %s',
+        s : 'segundos',
+        m : 'um minuto',
+        mm : '%d minutos',
+        h : 'uma hora',
+        hh : '%d horas',
+        d : 'um dia',
+        dd : '%d dias',
+        M : 'um mês',
+        MM : '%d meses',
+        y : 'um ano',
+        yy : '%d anos'
+    },
+    ordinalParse: /\d{1,2}º/,
+    ordinal : '%dº',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return pt;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ro.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ro.js
new file mode 100644
index 0000000000000000000000000000000000000000..8a0cd7501ad35c1ae9e3ee2fb1a252a7e80355cf
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ro.js
@@ -0,0 +1,75 @@
+//! moment.js locale configuration
+//! locale : Romanian [ro]
+//! author : Vlad Gurdiga : https://github.com/gurdiga
+//! author : Valentin Agachi : https://github.com/avaly
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+function relativeTimeWithPlural(number, withoutSuffix, key) {
+    var format = {
+            'mm': 'minute',
+            'hh': 'ore',
+            'dd': 'zile',
+            'MM': 'luni',
+            'yy': 'ani'
+        },
+        separator = ' ';
+    if (number % 100 >= 20 || (number >= 100 && number % 100 === 0)) {
+        separator = ' de ';
+    }
+    return number + separator + format[key];
+}
+
+var ro = moment.defineLocale('ro', {
+    months : 'ianuarie_februarie_martie_aprilie_mai_iunie_iulie_august_septembrie_octombrie_noiembrie_decembrie'.split('_'),
+    monthsShort : 'ian._febr._mart._apr._mai_iun._iul._aug._sept._oct._nov._dec.'.split('_'),
+    monthsParseExact: true,
+    weekdays : 'duminică_luni_marți_miercuri_joi_vineri_sâmbătă'.split('_'),
+    weekdaysShort : 'Dum_Lun_Mar_Mie_Joi_Vin_Sâm'.split('_'),
+    weekdaysMin : 'Du_Lu_Ma_Mi_Jo_Vi_Sâ'.split('_'),
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY H:mm',
+        LLLL : 'dddd, D MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay: '[azi la] LT',
+        nextDay: '[mâine la] LT',
+        nextWeek: 'dddd [la] LT',
+        lastDay: '[ieri la] LT',
+        lastWeek: '[fosta] dddd [la] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'peste %s',
+        past : '%s în urmă',
+        s : 'câteva secunde',
+        m : 'un minut',
+        mm : relativeTimeWithPlural,
+        h : 'o oră',
+        hh : relativeTimeWithPlural,
+        d : 'o zi',
+        dd : relativeTimeWithPlural,
+        M : 'o lună',
+        MM : relativeTimeWithPlural,
+        y : 'un an',
+        yy : relativeTimeWithPlural
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return ro;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ru.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ru.js
new file mode 100644
index 0000000000000000000000000000000000000000..35bba86a2eefa38fe8bae8dd9648ed96d73c4caa
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ru.js
@@ -0,0 +1,183 @@
+//! moment.js locale configuration
+//! locale : Russian [ru]
+//! author : Viktorminator : https://github.com/Viktorminator
+//! Author : Menelion Elensúle : https://github.com/Oire
+//! author : Коренберг Марк : https://github.com/socketpair
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+function plural(word, num) {
+    var forms = word.split('_');
+    return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]);
+}
+function relativeTimeWithPlural(number, withoutSuffix, key) {
+    var format = {
+        'mm': withoutSuffix ? 'минута_минуты_минут' : 'минуту_минуты_минут',
+        'hh': 'час_часа_часов',
+        'dd': 'день_дня_дней',
+        'MM': 'месяц_месяца_месяцев',
+        'yy': 'год_года_лет'
+    };
+    if (key === 'm') {
+        return withoutSuffix ? 'минута' : 'минуту';
+    }
+    else {
+        return number + ' ' + plural(format[key], +number);
+    }
+}
+var monthsParse = [/^янв/i, /^фев/i, /^мар/i, /^апр/i, /^ма[йя]/i, /^июн/i, /^июл/i, /^авг/i, /^сен/i, /^окт/i, /^ноя/i, /^дек/i];
+
+// http://new.gramota.ru/spravka/rules/139-prop : § 103
+// Сокращения месяцев: http://new.gramota.ru/spravka/buro/search-answer?s=242637
+// CLDR data:          http://www.unicode.org/cldr/charts/28/summary/ru.html#1753
+var ru = moment.defineLocale('ru', {
+    months : {
+        format: 'января_февраля_марта_апреля_мая_июня_июля_августа_сентября_октября_ноября_декабря'.split('_'),
+        standalone: 'январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь'.split('_')
+    },
+    monthsShort : {
+        // по CLDR именно "июл." и "июн.", но какой смысл менять букву на точку ?
+        format: 'янв._февр._мар._апр._мая_июня_июля_авг._сент._окт._нояб._дек.'.split('_'),
+        standalone: 'янв._февр._март_апр._май_июнь_июль_авг._сент._окт._нояб._дек.'.split('_')
+    },
+    weekdays : {
+        standalone: 'воскресенье_понедельник_вторник_среда_четверг_пятница_суббота'.split('_'),
+        format: 'воскресенье_понедельник_вторник_среду_четверг_пятницу_субботу'.split('_'),
+        isFormat: /\[ ?[Вв] ?(?:прошлую|следующую|эту)? ?\] ?dddd/
+    },
+    weekdaysShort : 'вс_пн_вт_ср_чт_пт_сб'.split('_'),
+    weekdaysMin : 'вс_пн_вт_ср_чт_пт_сб'.split('_'),
+    monthsParse : monthsParse,
+    longMonthsParse : monthsParse,
+    shortMonthsParse : monthsParse,
+
+    // полные названия с падежами, по три буквы, для некоторых, по 4 буквы, сокращения с точкой и без точки
+    monthsRegex: /^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i,
+
+    // копия предыдущего
+    monthsShortRegex: /^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i,
+
+    // полные названия с падежами
+    monthsStrictRegex: /^(январ[яь]|феврал[яь]|марта?|апрел[яь]|ма[яй]|июн[яь]|июл[яь]|августа?|сентябр[яь]|октябр[яь]|ноябр[яь]|декабр[яь])/i,
+
+    // Выражение, которое соотвествует только сокращённым формам
+    monthsShortStrictRegex: /^(янв\.|февр?\.|мар[т.]|апр\.|ма[яй]|июн[ья.]|июл[ья.]|авг\.|сент?\.|окт\.|нояб?\.|дек\.)/i,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY г.',
+        LLL : 'D MMMM YYYY г., HH:mm',
+        LLLL : 'dddd, D MMMM YYYY г., HH:mm'
+    },
+    calendar : {
+        sameDay: '[Сегодня в] LT',
+        nextDay: '[Завтра в] LT',
+        lastDay: '[Вчера в] LT',
+        nextWeek: function (now) {
+            if (now.week() !== this.week()) {
+                switch (this.day()) {
+                    case 0:
+                        return '[В следующее] dddd [в] LT';
+                    case 1:
+                    case 2:
+                    case 4:
+                        return '[В следующий] dddd [в] LT';
+                    case 3:
+                    case 5:
+                    case 6:
+                        return '[В следующую] dddd [в] LT';
+                }
+            } else {
+                if (this.day() === 2) {
+                    return '[Во] dddd [в] LT';
+                } else {
+                    return '[В] dddd [в] LT';
+                }
+            }
+        },
+        lastWeek: function (now) {
+            if (now.week() !== this.week()) {
+                switch (this.day()) {
+                    case 0:
+                        return '[В прошлое] dddd [в] LT';
+                    case 1:
+                    case 2:
+                    case 4:
+                        return '[В прошлый] dddd [в] LT';
+                    case 3:
+                    case 5:
+                    case 6:
+                        return '[В прошлую] dddd [в] LT';
+                }
+            } else {
+                if (this.day() === 2) {
+                    return '[Во] dddd [в] LT';
+                } else {
+                    return '[В] dddd [в] LT';
+                }
+            }
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'через %s',
+        past : '%s назад',
+        s : 'несколько секунд',
+        m : relativeTimeWithPlural,
+        mm : relativeTimeWithPlural,
+        h : 'час',
+        hh : relativeTimeWithPlural,
+        d : 'день',
+        dd : relativeTimeWithPlural,
+        M : 'месяц',
+        MM : relativeTimeWithPlural,
+        y : 'год',
+        yy : relativeTimeWithPlural
+    },
+    meridiemParse: /ночи|утра|дня|вечера/i,
+    isPM : function (input) {
+        return /^(дня|вечера)$/.test(input);
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'ночи';
+        } else if (hour < 12) {
+            return 'утра';
+        } else if (hour < 17) {
+            return 'дня';
+        } else {
+            return 'вечера';
+        }
+    },
+    ordinalParse: /\d{1,2}-(й|го|я)/,
+    ordinal: function (number, period) {
+        switch (period) {
+            case 'M':
+            case 'd':
+            case 'DDD':
+                return number + '-й';
+            case 'D':
+                return number + '-го';
+            case 'w':
+            case 'W':
+                return number + '-я';
+            default:
+                return number;
+        }
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return ru;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/se.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/se.js
new file mode 100644
index 0000000000000000000000000000000000000000..ab52fdff2ad9f7a4cd5ddc190b0ec8fd0557b93b
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/se.js
@@ -0,0 +1,61 @@
+//! moment.js locale configuration
+//! locale : Northern Sami [se]
+//! authors : BÃ¥rd Rolstad Henriksen : https://github.com/karamell
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+
+var se = moment.defineLocale('se', {
+    months : 'ođđajagemánnu_guovvamánnu_njukčamánnu_cuoŋománnu_miessemánnu_geassemánnu_suoidnemánnu_borgemánnu_čakčamánnu_golggotmánnu_skábmamánnu_juovlamánnu'.split('_'),
+    monthsShort : 'ođđj_guov_njuk_cuo_mies_geas_suoi_borg_čakč_golg_skáb_juov'.split('_'),
+    weekdays : 'sotnabeaivi_vuossárga_maŋŋebárga_gaskavahkku_duorastat_bearjadat_lávvardat'.split('_'),
+    weekdaysShort : 'sotn_vuos_maŋ_gask_duor_bear_láv'.split('_'),
+    weekdaysMin : 's_v_m_g_d_b_L'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'MMMM D. [b.] YYYY',
+        LLL : 'MMMM D. [b.] YYYY [ti.] HH:mm',
+        LLLL : 'dddd, MMMM D. [b.] YYYY [ti.] HH:mm'
+    },
+    calendar : {
+        sameDay: '[otne ti] LT',
+        nextDay: '[ihttin ti] LT',
+        nextWeek: 'dddd [ti] LT',
+        lastDay: '[ikte ti] LT',
+        lastWeek: '[ovddit] dddd [ti] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : '%s geažes',
+        past : 'maŋit %s',
+        s : 'moadde sekunddat',
+        m : 'okta minuhta',
+        mm : '%d minuhtat',
+        h : 'okta diimmu',
+        hh : '%d diimmut',
+        d : 'okta beaivi',
+        dd : '%d beaivvit',
+        M : 'okta mánnu',
+        MM : '%d mánut',
+        y : 'okta jahki',
+        yy : '%d jagit'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return se;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/si.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/si.js
new file mode 100644
index 0000000000000000000000000000000000000000..47d435b8313e095ad8d43ef78ce16a9d6e993469
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/si.js
@@ -0,0 +1,71 @@
+//! moment.js locale configuration
+//! locale : Sinhalese [si]
+//! author : Sampath Sitinamaluwa : https://github.com/sampathsris
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+/*jshint -W100*/
+var si = moment.defineLocale('si', {
+    months : 'ජනවාරි_පෙබරවාරි_මාර්තු_අප්‍රේල්_මැයි_ජූනි_ජූලි_අගෝස්තු_සැප්තැම්බර්_ඔක්තෝබර්_නොවැම්බර්_දෙසැම්බර්'.split('_'),
+    monthsShort : 'ජන_පෙබ_මාර්_අප්_මැයි_ජූනි_ජූලි_අගෝ_සැප්_ඔක්_නොවැ_දෙසැ'.split('_'),
+    weekdays : 'ඉරිදා_සඳුදා_අඟහරුවාදා_බදාදා_බ්‍රහස්පතින්දා_සිකුරාදා_සෙනසුරාදා'.split('_'),
+    weekdaysShort : 'ඉරි_සඳු_අඟ_බදා_බ්‍රහ_සිකු_සෙන'.split('_'),
+    weekdaysMin : 'ඉ_ස_අ_බ_බ්‍ර_සි_සෙ'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'a h:mm',
+        LTS : 'a h:mm:ss',
+        L : 'YYYY/MM/DD',
+        LL : 'YYYY MMMM D',
+        LLL : 'YYYY MMMM D, a h:mm',
+        LLLL : 'YYYY MMMM D [වැනි] dddd, a h:mm:ss'
+    },
+    calendar : {
+        sameDay : '[අද] LT[ට]',
+        nextDay : '[හෙට] LT[ට]',
+        nextWeek : 'dddd LT[à¶§]',
+        lastDay : '[ඊයේ] LT[ට]',
+        lastWeek : '[පසුගිය] dddd LT[ට]',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%sකින්',
+        past : '%sකට පෙර',
+        s : 'තත්පර කිහිපය',
+        m : 'මිනිත්තුව',
+        mm : 'මිනිත්තු %d',
+        h : 'පැය',
+        hh : 'පැය %d',
+        d : 'දිනය',
+        dd : 'දින %d',
+        M : 'මාසය',
+        MM : 'මාස %d',
+        y : 'වසර',
+        yy : 'වසර %d'
+    },
+    ordinalParse: /\d{1,2} වැනි/,
+    ordinal : function (number) {
+        return number + ' වැනි';
+    },
+    meridiemParse : /පෙර වරු|පස් වරු|පෙ.ව|ප.ව./,
+    isPM : function (input) {
+        return input === 'ප.ව.' || input === 'පස් වරු';
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours > 11) {
+            return isLower ? 'ප.ව.' : 'පස් වරු';
+        } else {
+            return isLower ? 'පෙ.ව.' : 'පෙර වරු';
+        }
+    }
+});
+
+return si;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/sk.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/sk.js
new file mode 100644
index 0000000000000000000000000000000000000000..f31291f4d131af969d06ec689fd5b23cfdcf9a23
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/sk.js
@@ -0,0 +1,150 @@
+//! moment.js locale configuration
+//! locale : Slovak [sk]
+//! author : Martin Minka : https://github.com/k2s
+//! based on work of petrbela : https://github.com/petrbela
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var months = 'január_február_marec_apríl_máj_jún_júl_august_september_október_november_december'.split('_');
+var monthsShort = 'jan_feb_mar_apr_máj_jún_júl_aug_sep_okt_nov_dec'.split('_');
+function plural(n) {
+    return (n > 1) && (n < 5);
+}
+function translate(number, withoutSuffix, key, isFuture) {
+    var result = number + ' ';
+    switch (key) {
+        case 's':  // a few seconds / in a few seconds / a few seconds ago
+            return (withoutSuffix || isFuture) ? 'pár sekúnd' : 'pár sekundami';
+        case 'm':  // a minute / in a minute / a minute ago
+            return withoutSuffix ? 'minúta' : (isFuture ? 'minútu' : 'minútou');
+        case 'mm': // 9 minutes / in 9 minutes / 9 minutes ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural(number) ? 'minúty' : 'minút');
+            } else {
+                return result + 'minútami';
+            }
+            break;
+        case 'h':  // an hour / in an hour / an hour ago
+            return withoutSuffix ? 'hodina' : (isFuture ? 'hodinu' : 'hodinou');
+        case 'hh': // 9 hours / in 9 hours / 9 hours ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural(number) ? 'hodiny' : 'hodín');
+            } else {
+                return result + 'hodinami';
+            }
+            break;
+        case 'd':  // a day / in a day / a day ago
+            return (withoutSuffix || isFuture) ? 'deň' : 'dňom';
+        case 'dd': // 9 days / in 9 days / 9 days ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural(number) ? 'dni' : 'dní');
+            } else {
+                return result + 'dňami';
+            }
+            break;
+        case 'M':  // a month / in a month / a month ago
+            return (withoutSuffix || isFuture) ? 'mesiac' : 'mesiacom';
+        case 'MM': // 9 months / in 9 months / 9 months ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural(number) ? 'mesiace' : 'mesiacov');
+            } else {
+                return result + 'mesiacmi';
+            }
+            break;
+        case 'y':  // a year / in a year / a year ago
+            return (withoutSuffix || isFuture) ? 'rok' : 'rokom';
+        case 'yy': // 9 years / in 9 years / 9 years ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural(number) ? 'roky' : 'rokov');
+            } else {
+                return result + 'rokmi';
+            }
+            break;
+    }
+}
+
+var sk = moment.defineLocale('sk', {
+    months : months,
+    monthsShort : monthsShort,
+    weekdays : 'nedeľa_pondelok_utorok_streda_štvrtok_piatok_sobota'.split('_'),
+    weekdaysShort : 'ne_po_ut_st_št_pi_so'.split('_'),
+    weekdaysMin : 'ne_po_ut_st_št_pi_so'.split('_'),
+    longDateFormat : {
+        LT: 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY H:mm',
+        LLLL : 'dddd D. MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay: '[dnes o] LT',
+        nextDay: '[zajtra o] LT',
+        nextWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[v nedeľu o] LT';
+                case 1:
+                case 2:
+                    return '[v] dddd [o] LT';
+                case 3:
+                    return '[v stredu o] LT';
+                case 4:
+                    return '[vo štvrtok o] LT';
+                case 5:
+                    return '[v piatok o] LT';
+                case 6:
+                    return '[v sobotu o] LT';
+            }
+        },
+        lastDay: '[včera o] LT',
+        lastWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[minulú nedeľu o] LT';
+                case 1:
+                case 2:
+                    return '[minulý] dddd [o] LT';
+                case 3:
+                    return '[minulú stredu o] LT';
+                case 4:
+                case 5:
+                    return '[minulý] dddd [o] LT';
+                case 6:
+                    return '[minulú sobotu o] LT';
+            }
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'za %s',
+        past : 'pred %s',
+        s : translate,
+        m : translate,
+        mm : translate,
+        h : translate,
+        hh : translate,
+        d : translate,
+        dd : translate,
+        M : translate,
+        MM : translate,
+        y : translate,
+        yy : translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return sk;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/sl.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/sl.js
new file mode 100644
index 0000000000000000000000000000000000000000..d9b36245a742c8b3aaa55ad4a99945cfd2b439b0
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/sl.js
@@ -0,0 +1,162 @@
+//! moment.js locale configuration
+//! locale : Slovenian [sl]
+//! author : Robert Sedovšek : https://github.com/sedovsek
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+function processRelativeTime(number, withoutSuffix, key, isFuture) {
+    var result = number + ' ';
+    switch (key) {
+        case 's':
+            return withoutSuffix || isFuture ? 'nekaj sekund' : 'nekaj sekundami';
+        case 'm':
+            return withoutSuffix ? 'ena minuta' : 'eno minuto';
+        case 'mm':
+            if (number === 1) {
+                result += withoutSuffix ? 'minuta' : 'minuto';
+            } else if (number === 2) {
+                result += withoutSuffix || isFuture ? 'minuti' : 'minutama';
+            } else if (number < 5) {
+                result += withoutSuffix || isFuture ? 'minute' : 'minutami';
+            } else {
+                result += withoutSuffix || isFuture ? 'minut' : 'minutami';
+            }
+            return result;
+        case 'h':
+            return withoutSuffix ? 'ena ura' : 'eno uro';
+        case 'hh':
+            if (number === 1) {
+                result += withoutSuffix ? 'ura' : 'uro';
+            } else if (number === 2) {
+                result += withoutSuffix || isFuture ? 'uri' : 'urama';
+            } else if (number < 5) {
+                result += withoutSuffix || isFuture ? 'ure' : 'urami';
+            } else {
+                result += withoutSuffix || isFuture ? 'ur' : 'urami';
+            }
+            return result;
+        case 'd':
+            return withoutSuffix || isFuture ? 'en dan' : 'enim dnem';
+        case 'dd':
+            if (number === 1) {
+                result += withoutSuffix || isFuture ? 'dan' : 'dnem';
+            } else if (number === 2) {
+                result += withoutSuffix || isFuture ? 'dni' : 'dnevoma';
+            } else {
+                result += withoutSuffix || isFuture ? 'dni' : 'dnevi';
+            }
+            return result;
+        case 'M':
+            return withoutSuffix || isFuture ? 'en mesec' : 'enim mesecem';
+        case 'MM':
+            if (number === 1) {
+                result += withoutSuffix || isFuture ? 'mesec' : 'mesecem';
+            } else if (number === 2) {
+                result += withoutSuffix || isFuture ? 'meseca' : 'mesecema';
+            } else if (number < 5) {
+                result += withoutSuffix || isFuture ? 'mesece' : 'meseci';
+            } else {
+                result += withoutSuffix || isFuture ? 'mesecev' : 'meseci';
+            }
+            return result;
+        case 'y':
+            return withoutSuffix || isFuture ? 'eno leto' : 'enim letom';
+        case 'yy':
+            if (number === 1) {
+                result += withoutSuffix || isFuture ? 'leto' : 'letom';
+            } else if (number === 2) {
+                result += withoutSuffix || isFuture ? 'leti' : 'letoma';
+            } else if (number < 5) {
+                result += withoutSuffix || isFuture ? 'leta' : 'leti';
+            } else {
+                result += withoutSuffix || isFuture ? 'let' : 'leti';
+            }
+            return result;
+    }
+}
+
+var sl = moment.defineLocale('sl', {
+    months : 'januar_februar_marec_april_maj_junij_julij_avgust_september_oktober_november_december'.split('_'),
+    monthsShort : 'jan._feb._mar._apr._maj._jun._jul._avg._sep._okt._nov._dec.'.split('_'),
+    monthsParseExact: true,
+    weekdays : 'nedelja_ponedeljek_torek_sreda_četrtek_petek_sobota'.split('_'),
+    weekdaysShort : 'ned._pon._tor._sre._čet._pet._sob.'.split('_'),
+    weekdaysMin : 'ne_po_to_sr_če_pe_so'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY H:mm',
+        LLLL : 'dddd, D. MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay  : '[danes ob] LT',
+        nextDay  : '[jutri ob] LT',
+
+        nextWeek : function () {
+            switch (this.day()) {
+                case 0:
+                    return '[v] [nedeljo] [ob] LT';
+                case 3:
+                    return '[v] [sredo] [ob] LT';
+                case 6:
+                    return '[v] [soboto] [ob] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[v] dddd [ob] LT';
+            }
+        },
+        lastDay  : '[včeraj ob] LT',
+        lastWeek : function () {
+            switch (this.day()) {
+                case 0:
+                    return '[prejšnjo] [nedeljo] [ob] LT';
+                case 3:
+                    return '[prejšnjo] [sredo] [ob] LT';
+                case 6:
+                    return '[prejšnjo] [soboto] [ob] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[prejšnji] dddd [ob] LT';
+            }
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'čez %s',
+        past   : 'pred %s',
+        s      : processRelativeTime,
+        m      : processRelativeTime,
+        mm     : processRelativeTime,
+        h      : processRelativeTime,
+        hh     : processRelativeTime,
+        d      : processRelativeTime,
+        dd     : processRelativeTime,
+        M      : processRelativeTime,
+        MM     : processRelativeTime,
+        y      : processRelativeTime,
+        yy     : processRelativeTime
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return sl;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/sq.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/sq.js
new file mode 100644
index 0000000000000000000000000000000000000000..1ca3fdd821bd20afc12a29c39b58a27d7dad548a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/sq.js
@@ -0,0 +1,70 @@
+//! moment.js locale configuration
+//! locale : Albanian [sq]
+//! author : Flakërim Ismani : https://github.com/flakerimi
+//! author : Menelion Elensúle : https://github.com/Oire
+//! author : Oerd Cukalla : https://github.com/oerd
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var sq = moment.defineLocale('sq', {
+    months : 'Janar_Shkurt_Mars_Prill_Maj_Qershor_Korrik_Gusht_Shtator_Tetor_Nëntor_Dhjetor'.split('_'),
+    monthsShort : 'Jan_Shk_Mar_Pri_Maj_Qer_Kor_Gus_Sht_Tet_Nën_Dhj'.split('_'),
+    weekdays : 'E Diel_E Hënë_E Martë_E Mërkurë_E Enjte_E Premte_E Shtunë'.split('_'),
+    weekdaysShort : 'Die_Hën_Mar_Mër_Enj_Pre_Sht'.split('_'),
+    weekdaysMin : 'D_H_Ma_Më_E_P_Sh'.split('_'),
+    weekdaysParseExact : true,
+    meridiemParse: /PD|MD/,
+    isPM: function (input) {
+        return input.charAt(0) === 'M';
+    },
+    meridiem : function (hours, minutes, isLower) {
+        return hours < 12 ? 'PD' : 'MD';
+    },
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[Sot në] LT',
+        nextDay : '[Nesër në] LT',
+        nextWeek : 'dddd [në] LT',
+        lastDay : '[Dje në] LT',
+        lastWeek : 'dddd [e kaluar në] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'në %s',
+        past : '%s më parë',
+        s : 'disa sekonda',
+        m : 'një minutë',
+        mm : '%d minuta',
+        h : 'një orë',
+        hh : '%d orë',
+        d : 'një ditë',
+        dd : '%d ditë',
+        M : 'një muaj',
+        MM : '%d muaj',
+        y : 'një vit',
+        yy : '%d vite'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return sq;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/sr-cyrl.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/sr-cyrl.js
new file mode 100644
index 0000000000000000000000000000000000000000..caeef089e7c6f634cd6243ac08a97ea3e763548a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/sr-cyrl.js
@@ -0,0 +1,110 @@
+//! moment.js locale configuration
+//! locale : Serbian Cyrillic [sr-cyrl]
+//! author : Milan Janačković<milanjanackovic@gmail.com> : https://github.com/milan-j
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var translator = {
+    words: { //Different grammatical cases
+        m: ['један минут', 'једне минуте'],
+        mm: ['минут', 'минуте', 'минута'],
+        h: ['један сат', 'једног сата'],
+        hh: ['сат', 'сата', 'сати'],
+        dd: ['дан', 'дана', 'дана'],
+        MM: ['месец', 'месеца', 'месеци'],
+        yy: ['година', 'године', 'година']
+    },
+    correctGrammaticalCase: function (number, wordKey) {
+        return number === 1 ? wordKey[0] : (number >= 2 && number <= 4 ? wordKey[1] : wordKey[2]);
+    },
+    translate: function (number, withoutSuffix, key) {
+        var wordKey = translator.words[key];
+        if (key.length === 1) {
+            return withoutSuffix ? wordKey[0] : wordKey[1];
+        } else {
+            return number + ' ' + translator.correctGrammaticalCase(number, wordKey);
+        }
+    }
+};
+
+var srCyrl = moment.defineLocale('sr-cyrl', {
+    months: 'јануар_фебруар_март_април_мај_јун_јул_август_септембар_октобар_новембар_децембар'.split('_'),
+    monthsShort: 'јан._феб._мар._апр._мај_јун_јул_авг._сеп._окт._нов._дец.'.split('_'),
+    monthsParseExact: true,
+    weekdays: 'недеља_понедељак_уторак_среда_четвртак_петак_субота'.split('_'),
+    weekdaysShort: 'нед._пон._уто._сре._чет._пет._суб.'.split('_'),
+    weekdaysMin: 'не_по_ут_ср_че_пе_су'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat: {
+        LT: 'H:mm',
+        LTS : 'H:mm:ss',
+        L: 'DD.MM.YYYY',
+        LL: 'D. MMMM YYYY',
+        LLL: 'D. MMMM YYYY H:mm',
+        LLLL: 'dddd, D. MMMM YYYY H:mm'
+    },
+    calendar: {
+        sameDay: '[данас у] LT',
+        nextDay: '[сутра у] LT',
+        nextWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[у] [недељу] [у] LT';
+                case 3:
+                    return '[у] [среду] [у] LT';
+                case 6:
+                    return '[у] [суботу] [у] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[у] dddd [у] LT';
+            }
+        },
+        lastDay  : '[јуче у] LT',
+        lastWeek : function () {
+            var lastWeekDays = [
+                '[прошле] [недеље] [у] LT',
+                '[прошлог] [понедељка] [у] LT',
+                '[прошлог] [уторка] [у] LT',
+                '[прошле] [среде] [у] LT',
+                '[прошлог] [четвртка] [у] LT',
+                '[прошлог] [петка] [у] LT',
+                '[прошле] [суботе] [у] LT'
+            ];
+            return lastWeekDays[this.day()];
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'за %s',
+        past   : 'пре %s',
+        s      : 'неколико секунди',
+        m      : translator.translate,
+        mm     : translator.translate,
+        h      : translator.translate,
+        hh     : translator.translate,
+        d      : 'дан',
+        dd     : translator.translate,
+        M      : 'месец',
+        MM     : translator.translate,
+        y      : 'годину',
+        yy     : translator.translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return srCyrl;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/sr.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/sr.js
new file mode 100644
index 0000000000000000000000000000000000000000..9c254444ff3105e1fc93483fc4be85209c43e0cc
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/sr.js
@@ -0,0 +1,110 @@
+//! moment.js locale configuration
+//! locale : Serbian [sr]
+//! author : Milan Janačković<milanjanackovic@gmail.com> : https://github.com/milan-j
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var translator = {
+    words: { //Different grammatical cases
+        m: ['jedan minut', 'jedne minute'],
+        mm: ['minut', 'minute', 'minuta'],
+        h: ['jedan sat', 'jednog sata'],
+        hh: ['sat', 'sata', 'sati'],
+        dd: ['dan', 'dana', 'dana'],
+        MM: ['mesec', 'meseca', 'meseci'],
+        yy: ['godina', 'godine', 'godina']
+    },
+    correctGrammaticalCase: function (number, wordKey) {
+        return number === 1 ? wordKey[0] : (number >= 2 && number <= 4 ? wordKey[1] : wordKey[2]);
+    },
+    translate: function (number, withoutSuffix, key) {
+        var wordKey = translator.words[key];
+        if (key.length === 1) {
+            return withoutSuffix ? wordKey[0] : wordKey[1];
+        } else {
+            return number + ' ' + translator.correctGrammaticalCase(number, wordKey);
+        }
+    }
+};
+
+var sr = moment.defineLocale('sr', {
+    months: 'januar_februar_mart_april_maj_jun_jul_avgust_septembar_oktobar_novembar_decembar'.split('_'),
+    monthsShort: 'jan._feb._mar._apr._maj_jun_jul_avg._sep._okt._nov._dec.'.split('_'),
+    monthsParseExact: true,
+    weekdays: 'nedelja_ponedeljak_utorak_sreda_četvrtak_petak_subota'.split('_'),
+    weekdaysShort: 'ned._pon._uto._sre._čet._pet._sub.'.split('_'),
+    weekdaysMin: 'ne_po_ut_sr_če_pe_su'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat: {
+        LT: 'H:mm',
+        LTS : 'H:mm:ss',
+        L: 'DD.MM.YYYY',
+        LL: 'D. MMMM YYYY',
+        LLL: 'D. MMMM YYYY H:mm',
+        LLLL: 'dddd, D. MMMM YYYY H:mm'
+    },
+    calendar: {
+        sameDay: '[danas u] LT',
+        nextDay: '[sutra u] LT',
+        nextWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[u] [nedelju] [u] LT';
+                case 3:
+                    return '[u] [sredu] [u] LT';
+                case 6:
+                    return '[u] [subotu] [u] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[u] dddd [u] LT';
+            }
+        },
+        lastDay  : '[juče u] LT',
+        lastWeek : function () {
+            var lastWeekDays = [
+                '[prošle] [nedelje] [u] LT',
+                '[prošlog] [ponedeljka] [u] LT',
+                '[prošlog] [utorka] [u] LT',
+                '[prošle] [srede] [u] LT',
+                '[prošlog] [četvrtka] [u] LT',
+                '[prošlog] [petka] [u] LT',
+                '[prošle] [subote] [u] LT'
+            ];
+            return lastWeekDays[this.day()];
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'za %s',
+        past   : 'pre %s',
+        s      : 'nekoliko sekundi',
+        m      : translator.translate,
+        mm     : translator.translate,
+        h      : translator.translate,
+        hh     : translator.translate,
+        d      : 'dan',
+        dd     : translator.translate,
+        M      : 'mesec',
+        MM     : translator.translate,
+        y      : 'godinu',
+        yy     : translator.translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return sr;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ss.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ss.js
new file mode 100644
index 0000000000000000000000000000000000000000..f2363573870476fd013ae0e8650d7f75588cb6b6
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ss.js
@@ -0,0 +1,89 @@
+//! moment.js locale configuration
+//! locale : siSwati [ss]
+//! author : Nicolai Davies<mail@nicolai.io> : https://github.com/nicolaidavies
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+
+var ss = moment.defineLocale('ss', {
+    months : "Bhimbidvwane_Indlovana_Indlov'lenkhulu_Mabasa_Inkhwekhweti_Inhlaba_Kholwane_Ingci_Inyoni_Imphala_Lweti_Ingongoni".split('_'),
+    monthsShort : 'Bhi_Ina_Inu_Mab_Ink_Inh_Kho_Igc_Iny_Imp_Lwe_Igo'.split('_'),
+    weekdays : 'Lisontfo_Umsombuluko_Lesibili_Lesitsatfu_Lesine_Lesihlanu_Umgcibelo'.split('_'),
+    weekdaysShort : 'Lis_Umb_Lsb_Les_Lsi_Lsh_Umg'.split('_'),
+    weekdaysMin : 'Li_Us_Lb_Lt_Ls_Lh_Ug'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'h:mm A',
+        LTS : 'h:mm:ss A',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY h:mm A',
+        LLLL : 'dddd, D MMMM YYYY h:mm A'
+    },
+    calendar : {
+        sameDay : '[Namuhla nga] LT',
+        nextDay : '[Kusasa nga] LT',
+        nextWeek : 'dddd [nga] LT',
+        lastDay : '[Itolo nga] LT',
+        lastWeek : 'dddd [leliphelile] [nga] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'nga %s',
+        past : 'wenteka nga %s',
+        s : 'emizuzwana lomcane',
+        m : 'umzuzu',
+        mm : '%d emizuzu',
+        h : 'lihora',
+        hh : '%d emahora',
+        d : 'lilanga',
+        dd : '%d emalanga',
+        M : 'inyanga',
+        MM : '%d tinyanga',
+        y : 'umnyaka',
+        yy : '%d iminyaka'
+    },
+    meridiemParse: /ekuseni|emini|entsambama|ebusuku/,
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 11) {
+            return 'ekuseni';
+        } else if (hours < 15) {
+            return 'emini';
+        } else if (hours < 19) {
+            return 'entsambama';
+        } else {
+            return 'ebusuku';
+        }
+    },
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'ekuseni') {
+            return hour;
+        } else if (meridiem === 'emini') {
+            return hour >= 11 ? hour : hour + 12;
+        } else if (meridiem === 'entsambama' || meridiem === 'ebusuku') {
+            if (hour === 0) {
+                return 0;
+            }
+            return hour + 12;
+        }
+    },
+    ordinalParse: /\d{1,2}/,
+    ordinal : '%d',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return ss;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/sv.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/sv.js
new file mode 100644
index 0000000000000000000000000000000000000000..77a3402b2296dbc6d4b31f27afb49da66f50e1a0
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/sv.js
@@ -0,0 +1,69 @@
+//! moment.js locale configuration
+//! locale : Swedish [sv]
+//! author : Jens Alm : https://github.com/ulmus
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var sv = moment.defineLocale('sv', {
+    months : 'januari_februari_mars_april_maj_juni_juli_augusti_september_oktober_november_december'.split('_'),
+    monthsShort : 'jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec'.split('_'),
+    weekdays : 'söndag_måndag_tisdag_onsdag_torsdag_fredag_lördag'.split('_'),
+    weekdaysShort : 'sön_mån_tis_ons_tor_fre_lör'.split('_'),
+    weekdaysMin : 'sö_må_ti_on_to_fr_lö'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'YYYY-MM-DD',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY [kl.] HH:mm',
+        LLLL : 'dddd D MMMM YYYY [kl.] HH:mm',
+        lll : 'D MMM YYYY HH:mm',
+        llll : 'ddd D MMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Idag] LT',
+        nextDay: '[Imorgon] LT',
+        lastDay: '[Igår] LT',
+        nextWeek: '[PÃ¥] dddd LT',
+        lastWeek: '[I] dddd[s] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'om %s',
+        past : 'för %s sedan',
+        s : 'några sekunder',
+        m : 'en minut',
+        mm : '%d minuter',
+        h : 'en timme',
+        hh : '%d timmar',
+        d : 'en dag',
+        dd : '%d dagar',
+        M : 'en månad',
+        MM : '%d månader',
+        y : 'ett år',
+        yy : '%d år'
+    },
+    ordinalParse: /\d{1,2}(e|a)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'e' :
+            (b === 1) ? 'a' :
+            (b === 2) ? 'a' :
+            (b === 3) ? 'e' : 'e';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return sv;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/sw.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/sw.js
new file mode 100644
index 0000000000000000000000000000000000000000..9ed314f5631fee53f4b92c4f85811509004b27f0
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/sw.js
@@ -0,0 +1,59 @@
+//! moment.js locale configuration
+//! locale : Swahili [sw]
+//! author : Fahad Kassim : https://github.com/fadsel
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var sw = moment.defineLocale('sw', {
+    months : 'Januari_Februari_Machi_Aprili_Mei_Juni_Julai_Agosti_Septemba_Oktoba_Novemba_Desemba'.split('_'),
+    monthsShort : 'Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ago_Sep_Okt_Nov_Des'.split('_'),
+    weekdays : 'Jumapili_Jumatatu_Jumanne_Jumatano_Alhamisi_Ijumaa_Jumamosi'.split('_'),
+    weekdaysShort : 'Jpl_Jtat_Jnne_Jtan_Alh_Ijm_Jmos'.split('_'),
+    weekdaysMin : 'J2_J3_J4_J5_Al_Ij_J1'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[leo saa] LT',
+        nextDay : '[kesho saa] LT',
+        nextWeek : '[wiki ijayo] dddd [saat] LT',
+        lastDay : '[jana] LT',
+        lastWeek : '[wiki iliyopita] dddd [saat] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s baadaye',
+        past : 'tokea %s',
+        s : 'hivi punde',
+        m : 'dakika moja',
+        mm : 'dakika %d',
+        h : 'saa limoja',
+        hh : 'masaa %d',
+        d : 'siku moja',
+        dd : 'masiku %d',
+        M : 'mwezi mmoja',
+        MM : 'miezi %d',
+        y : 'mwaka mmoja',
+        yy : 'miaka %d'
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return sw;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ta.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ta.js
new file mode 100644
index 0000000000000000000000000000000000000000..043ae6007ad99ff4089115b53287996314d53f73
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/ta.js
@@ -0,0 +1,130 @@
+//! moment.js locale configuration
+//! locale : Tamil [ta]
+//! author : Arjunkumar Krishnamoorthy : https://github.com/tk120404
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var symbolMap = {
+    '1': '௧',
+    '2': '௨',
+    '3': '௩',
+    '4': '௪',
+    '5': '௫',
+    '6': '௬',
+    '7': '௭',
+    '8': '௮',
+    '9': '௯',
+    '0': '௦'
+};
+var numberMap = {
+    '௧': '1',
+    '௨': '2',
+    '௩': '3',
+    '௪': '4',
+    '௫': '5',
+    '௬': '6',
+    '௭': '7',
+    '௮': '8',
+    '௯': '9',
+    '௦': '0'
+};
+
+var ta = moment.defineLocale('ta', {
+    months : 'ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்'.split('_'),
+    monthsShort : 'ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்'.split('_'),
+    weekdays : 'ஞாயிற்றுக்கிழமை_திங்கட்கிழமை_செவ்வாய்கிழமை_புதன்கிழமை_வியாழக்கிழமை_வெள்ளிக்கிழமை_சனிக்கிழமை'.split('_'),
+    weekdaysShort : 'ஞாயிறு_திங்கள்_செவ்வாய்_புதன்_வியாழன்_வெள்ளி_சனி'.split('_'),
+    weekdaysMin : 'ஞா_தி_செ_பு_வி_வெ_ச'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, HH:mm',
+        LLLL : 'dddd, D MMMM YYYY, HH:mm'
+    },
+    calendar : {
+        sameDay : '[இன்று] LT',
+        nextDay : '[நாளை] LT',
+        nextWeek : 'dddd, LT',
+        lastDay : '[நேற்று] LT',
+        lastWeek : '[கடந்த வாரம்] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s இல்',
+        past : '%s முன்',
+        s : 'ஒரு சில விநாடிகள்',
+        m : 'ஒரு நிமிடம்',
+        mm : '%d நிமிடங்கள்',
+        h : 'ஒரு மணி நேரம்',
+        hh : '%d மணி நேரம்',
+        d : 'ஒரு நாள்',
+        dd : '%d நாட்கள்',
+        M : 'ஒரு மாதம்',
+        MM : '%d மாதங்கள்',
+        y : 'ஒரு வருடம்',
+        yy : '%d ஆண்டுகள்'
+    },
+    ordinalParse: /\d{1,2}வது/,
+    ordinal : function (number) {
+        return number + 'வது';
+    },
+    preparse: function (string) {
+        return string.replace(/[௧௨௩௪௫௬௭௮௯௦]/g, function (match) {
+            return numberMap[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap[match];
+        });
+    },
+    // refer http://ta.wikipedia.org/s/1er1
+    meridiemParse: /யாமம்|வைகறை|காலை|நண்பகல்|எற்பாடு|மாலை/,
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 2) {
+            return ' யாமம்';
+        } else if (hour < 6) {
+            return ' வைகறை';  // வைகறை
+        } else if (hour < 10) {
+            return ' காலை'; // காலை
+        } else if (hour < 14) {
+            return ' நண்பகல்'; // நண்பகல்
+        } else if (hour < 18) {
+            return ' எற்பாடு'; // எற்பாடு
+        } else if (hour < 22) {
+            return ' மாலை'; // மாலை
+        } else {
+            return ' யாமம்';
+        }
+    },
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'யாமம்') {
+            return hour < 2 ? hour : hour + 12;
+        } else if (meridiem === 'வைகறை' || meridiem === 'காலை') {
+            return hour;
+        } else if (meridiem === 'நண்பகல்') {
+            return hour >= 10 ? hour : hour + 12;
+        } else {
+            return hour + 12;
+        }
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return ta;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/te.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/te.js
new file mode 100644
index 0000000000000000000000000000000000000000..ac6ef03375200bb775473d81013a6bc19a669cf8
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/te.js
@@ -0,0 +1,89 @@
+//! moment.js locale configuration
+//! locale : Telugu [te]
+//! author : Krishna Chaitanya Thota : https://github.com/kcthota
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var te = moment.defineLocale('te', {
+    months : 'జనవరి_ఫిబ్రవరి_మార్చి_ఏప్రిల్_మే_జూన్_జూలై_ఆగస్టు_సెప్టెంబర్_అక్టోబర్_నవంబర్_డిసెంబర్'.split('_'),
+    monthsShort : 'జన._ఫిబ్ర._మార్చి_ఏప్రి._మే_జూన్_జూలై_ఆగ._సెప్._అక్టో._నవ._డిసె.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'ఆదివారం_సోమవారం_మంగళవారం_బుధవారం_గురువారం_శుక్రవారం_శనివారం'.split('_'),
+    weekdaysShort : 'ఆది_సోమ_మంగళ_బుధ_గురు_శుక్ర_శని'.split('_'),
+    weekdaysMin : 'ఆ_సో_మం_బు_గు_శు_శ'.split('_'),
+    longDateFormat : {
+        LT : 'A h:mm',
+        LTS : 'A h:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, A h:mm',
+        LLLL : 'dddd, D MMMM YYYY, A h:mm'
+    },
+    calendar : {
+        sameDay : '[నేడు] LT',
+        nextDay : '[రేపు] LT',
+        nextWeek : 'dddd, LT',
+        lastDay : '[నిన్న] LT',
+        lastWeek : '[à°—à°¤] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s లో',
+        past : '%s క్రితం',
+        s : 'కొన్ని క్షణాలు',
+        m : 'ఒక నిమిషం',
+        mm : '%d నిమిషాలు',
+        h : 'à°’à°• à°—à°‚à°Ÿ',
+        hh : '%d గంటలు',
+        d : 'ఒక రోజు',
+        dd : '%d రోజులు',
+        M : 'ఒక నెల',
+        MM : '%d నెలలు',
+        y : 'ఒక సంవత్సరం',
+        yy : '%d సంవత్సరాలు'
+    },
+    ordinalParse : /\d{1,2}à°µ/,
+    ordinal : '%dà°µ',
+    meridiemParse: /రాత్రి|ఉదయం|మధ్యాహ్నం|సాయంత్రం/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'రాత్రి') {
+            return hour < 4 ? hour : hour + 12;
+        } else if (meridiem === 'ఉదయం') {
+            return hour;
+        } else if (meridiem === 'మధ్యాహ్నం') {
+            return hour >= 10 ? hour : hour + 12;
+        } else if (meridiem === 'సాయంత్రం') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'రాత్రి';
+        } else if (hour < 10) {
+            return 'ఉదయం';
+        } else if (hour < 17) {
+            return 'మధ్యాహ్నం';
+        } else if (hour < 20) {
+            return 'సాయంత్రం';
+        } else {
+            return 'రాత్రి';
+        }
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return te;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/tet.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/tet.js
new file mode 100644
index 0000000000000000000000000000000000000000..e419ef323392d55fb6a2ecc03c82f444e5d7dfad
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/tet.js
@@ -0,0 +1,68 @@
+//! moment.js locale configuration
+//! locale : Tetun Dili (East Timor) [tet]
+//! author : Joshua Brooks : https://github.com/joshbrooks
+//! author : Onorio De J. Afonso : https://github.com/marobo
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var tet = moment.defineLocale('tet', {
+    months : 'Janeiru_Fevereiru_Marsu_Abril_Maiu_Juniu_Juliu_Augustu_Setembru_Outubru_Novembru_Dezembru'.split('_'),
+    monthsShort : 'Jan_Fev_Mar_Abr_Mai_Jun_Jul_Aug_Set_Out_Nov_Dez'.split('_'),
+    weekdays : 'Domingu_Segunda_Tersa_Kuarta_Kinta_Sexta_Sabadu'.split('_'),
+    weekdaysShort : 'Dom_Seg_Ters_Kua_Kint_Sext_Sab'.split('_'),
+    weekdaysMin : 'Do_Seg_Te_Ku_Ki_Sex_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Ohin iha] LT',
+        nextDay: '[Aban iha] LT',
+        nextWeek: 'dddd [iha] LT',
+        lastDay: '[Horiseik iha] LT',
+        lastWeek: 'dddd [semana kotuk] [iha] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'iha %s',
+        past : '%s liuba',
+        s : 'minutu balun',
+        m : 'minutu ida',
+        mm : 'minutus %d',
+        h : 'horas ida',
+        hh : 'horas %d',
+        d : 'loron ida',
+        dd : 'loron %d',
+        M : 'fulan ida',
+        MM : 'fulan %d',
+        y : 'tinan ida',
+        yy : 'tinan %d'
+    },
+    ordinalParse: /\d{1,2}(st|nd|rd|th)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return tet;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/th.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/th.js
new file mode 100644
index 0000000000000000000000000000000000000000..22f6ab9a4804494a1bb2b8c5a29fb91eaa3aaa8c
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/th.js
@@ -0,0 +1,67 @@
+//! moment.js locale configuration
+//! locale : Thai [th]
+//! author : Kridsada Thanabulpong : https://github.com/sirn
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var th = moment.defineLocale('th', {
+    months : 'มกราคม_กุมภาพันธ์_มีนาคม_เมษายน_พฤษภาคม_มิถุนายน_กรกฎาคม_สิงหาคม_กันยายน_ตุลาคม_พฤศจิกายน_ธันวาคม'.split('_'),
+    monthsShort : 'ม.ค._ก.พ._มี.ค._เม.ย._พ.ค._มิ.ย._ก.ค._ส.ค._ก.ย._ต.ค._พ.ย._ธ.ค.'.split('_'),
+    monthsParseExact: true,
+    weekdays : 'อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัสบดี_ศุกร์_เสาร์'.split('_'),
+    weekdaysShort : 'อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัส_ศุกร์_เสาร์'.split('_'), // yes, three characters difference
+    weekdaysMin : 'อา._จ._อ._พ._พฤ._ศ._ส.'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'YYYY/MM/DD',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY เวลา H:mm',
+        LLLL : 'วันddddที่ D MMMM YYYY เวลา H:mm'
+    },
+    meridiemParse: /ก่อนเที่ยง|หลังเที่ยง/,
+    isPM: function (input) {
+        return input === 'หลังเที่ยง';
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return 'ก่อนเที่ยง';
+        } else {
+            return 'หลังเที่ยง';
+        }
+    },
+    calendar : {
+        sameDay : '[วันนี้ เวลา] LT',
+        nextDay : '[พรุ่งนี้ เวลา] LT',
+        nextWeek : 'dddd[หน้า เวลา] LT',
+        lastDay : '[เมื่อวานนี้ เวลา] LT',
+        lastWeek : '[วัน]dddd[ที่แล้ว เวลา] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'อีก %s',
+        past : '%sที่แล้ว',
+        s : 'ไม่กี่วินาที',
+        m : '1 นาที',
+        mm : '%d นาที',
+        h : '1 ชั่วโมง',
+        hh : '%d ชั่วโมง',
+        d : '1 วัน',
+        dd : '%d วัน',
+        M : '1 เดือน',
+        MM : '%d เดือน',
+        y : '1 ปี',
+        yy : '%d ปี'
+    }
+});
+
+return th;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/tl-ph.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/tl-ph.js
new file mode 100644
index 0000000000000000000000000000000000000000..a37b86e7131182e2ee3d4ba74d30ce13a39474d9
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/tl-ph.js
@@ -0,0 +1,62 @@
+//! moment.js locale configuration
+//! locale : Tagalog (Philippines) [tl-ph]
+//! author : Dan Hagman : https://github.com/hagmandan
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var tlPh = moment.defineLocale('tl-ph', {
+    months : 'Enero_Pebrero_Marso_Abril_Mayo_Hunyo_Hulyo_Agosto_Setyembre_Oktubre_Nobyembre_Disyembre'.split('_'),
+    monthsShort : 'Ene_Peb_Mar_Abr_May_Hun_Hul_Ago_Set_Okt_Nob_Dis'.split('_'),
+    weekdays : 'Linggo_Lunes_Martes_Miyerkules_Huwebes_Biyernes_Sabado'.split('_'),
+    weekdaysShort : 'Lin_Lun_Mar_Miy_Huw_Biy_Sab'.split('_'),
+    weekdaysMin : 'Li_Lu_Ma_Mi_Hu_Bi_Sab'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'MM/D/YYYY',
+        LL : 'MMMM D, YYYY',
+        LLL : 'MMMM D, YYYY HH:mm',
+        LLLL : 'dddd, MMMM DD, YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: 'LT [ngayong araw]',
+        nextDay: '[Bukas ng] LT',
+        nextWeek: 'LT [sa susunod na] dddd',
+        lastDay: 'LT [kahapon]',
+        lastWeek: 'LT [noong nakaraang] dddd',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'sa loob ng %s',
+        past : '%s ang nakalipas',
+        s : 'ilang segundo',
+        m : 'isang minuto',
+        mm : '%d minuto',
+        h : 'isang oras',
+        hh : '%d oras',
+        d : 'isang araw',
+        dd : '%d araw',
+        M : 'isang buwan',
+        MM : '%d buwan',
+        y : 'isang taon',
+        yy : '%d taon'
+    },
+    ordinalParse: /\d{1,2}/,
+    ordinal : function (number) {
+        return number;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return tlPh;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/tlh.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/tlh.js
new file mode 100644
index 0000000000000000000000000000000000000000..7eb7df9c5209ad33571bde47a65431fb4f5d87c8
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/tlh.js
@@ -0,0 +1,120 @@
+//! moment.js locale configuration
+//! locale : Klingon [tlh]
+//! author : Dominika Kruk : https://github.com/amaranthrose
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var numbersNouns = 'pagh_wa’_cha’_wej_loS_vagh_jav_Soch_chorgh_Hut'.split('_');
+
+function translateFuture(output) {
+    var time = output;
+    time = (output.indexOf('jaj') !== -1) ?
+    time.slice(0, -3) + 'leS' :
+    (output.indexOf('jar') !== -1) ?
+    time.slice(0, -3) + 'waQ' :
+    (output.indexOf('DIS') !== -1) ?
+    time.slice(0, -3) + 'nem' :
+    time + ' pIq';
+    return time;
+}
+
+function translatePast(output) {
+    var time = output;
+    time = (output.indexOf('jaj') !== -1) ?
+    time.slice(0, -3) + 'Hu’' :
+    (output.indexOf('jar') !== -1) ?
+    time.slice(0, -3) + 'wen' :
+    (output.indexOf('DIS') !== -1) ?
+    time.slice(0, -3) + 'ben' :
+    time + ' ret';
+    return time;
+}
+
+function translate(number, withoutSuffix, string, isFuture) {
+    var numberNoun = numberAsNoun(number);
+    switch (string) {
+        case 'mm':
+            return numberNoun + ' tup';
+        case 'hh':
+            return numberNoun + ' rep';
+        case 'dd':
+            return numberNoun + ' jaj';
+        case 'MM':
+            return numberNoun + ' jar';
+        case 'yy':
+            return numberNoun + ' DIS';
+    }
+}
+
+function numberAsNoun(number) {
+    var hundred = Math.floor((number % 1000) / 100),
+    ten = Math.floor((number % 100) / 10),
+    one = number % 10,
+    word = '';
+    if (hundred > 0) {
+        word += numbersNouns[hundred] + 'vatlh';
+    }
+    if (ten > 0) {
+        word += ((word !== '') ? ' ' : '') + numbersNouns[ten] + 'maH';
+    }
+    if (one > 0) {
+        word += ((word !== '') ? ' ' : '') + numbersNouns[one];
+    }
+    return (word === '') ? 'pagh' : word;
+}
+
+var tlh = moment.defineLocale('tlh', {
+    months : 'tera’ jar wa’_tera’ jar cha’_tera’ jar wej_tera’ jar loS_tera’ jar vagh_tera’ jar jav_tera’ jar Soch_tera’ jar chorgh_tera’ jar Hut_tera’ jar wa’maH_tera’ jar wa’maH wa’_tera’ jar wa’maH cha’'.split('_'),
+    monthsShort : 'jar wa’_jar cha’_jar wej_jar loS_jar vagh_jar jav_jar Soch_jar chorgh_jar Hut_jar wa’maH_jar wa’maH wa’_jar wa’maH cha’'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj'.split('_'),
+    weekdaysShort : 'lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj'.split('_'),
+    weekdaysMin : 'lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[DaHjaj] LT',
+        nextDay: '[wa’leS] LT',
+        nextWeek: 'LLL',
+        lastDay: '[wa’Hu’] LT',
+        lastWeek: 'LLL',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : translateFuture,
+        past : translatePast,
+        s : 'puS lup',
+        m : 'wa’ tup',
+        mm : translate,
+        h : 'wa’ rep',
+        hh : translate,
+        d : 'wa’ jaj',
+        dd : translate,
+        M : 'wa’ jar',
+        MM : translate,
+        y : 'wa’ DIS',
+        yy : translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return tlh;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/tr.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/tr.js
new file mode 100644
index 0000000000000000000000000000000000000000..425386f369a1807deb7b89dd6a364605a69e8e3e
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/tr.js
@@ -0,0 +1,90 @@
+//! moment.js locale configuration
+//! locale : Turkish [tr]
+//! authors : Erhan Gundogan : https://github.com/erhangundogan,
+//!           Burak YiÄŸit Kaya: https://github.com/BYK
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var suffixes = {
+    1: '\'inci',
+    5: '\'inci',
+    8: '\'inci',
+    70: '\'inci',
+    80: '\'inci',
+    2: '\'nci',
+    7: '\'nci',
+    20: '\'nci',
+    50: '\'nci',
+    3: '\'üncü',
+    4: '\'üncü',
+    100: '\'üncü',
+    6: '\'ncı',
+    9: '\'uncu',
+    10: '\'uncu',
+    30: '\'uncu',
+    60: '\'ıncı',
+    90: '\'ıncı'
+};
+
+var tr = moment.defineLocale('tr', {
+    months : 'Ocak_Şubat_Mart_Nisan_Mayıs_Haziran_Temmuz_Ağustos_Eylül_Ekim_Kasım_Aralık'.split('_'),
+    monthsShort : 'Oca_Åžub_Mar_Nis_May_Haz_Tem_AÄŸu_Eyl_Eki_Kas_Ara'.split('_'),
+    weekdays : 'Pazar_Pazartesi_Salı_Çarşamba_Perşembe_Cuma_Cumartesi'.split('_'),
+    weekdaysShort : 'Paz_Pts_Sal_Çar_Per_Cum_Cts'.split('_'),
+    weekdaysMin : 'Pz_Pt_Sa_Ça_Pe_Cu_Ct'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[bugün saat] LT',
+        nextDay : '[yarın saat] LT',
+        nextWeek : '[haftaya] dddd [saat] LT',
+        lastDay : '[dün] LT',
+        lastWeek : '[geçen hafta] dddd [saat] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s sonra',
+        past : '%s önce',
+        s : 'birkaç saniye',
+        m : 'bir dakika',
+        mm : '%d dakika',
+        h : 'bir saat',
+        hh : '%d saat',
+        d : 'bir gün',
+        dd : '%d gün',
+        M : 'bir ay',
+        MM : '%d ay',
+        y : 'bir yıl',
+        yy : '%d yıl'
+    },
+    ordinalParse: /\d{1,2}'(inci|nci|üncü|ncı|uncu|ıncı)/,
+    ordinal : function (number) {
+        if (number === 0) {  // special case for zero
+            return number + '\'ıncı';
+        }
+        var a = number % 10,
+            b = number % 100 - a,
+            c = number >= 100 ? 100 : null;
+        return number + (suffixes[a] || suffixes[b] || suffixes[c]);
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return tr;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/tzl.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/tzl.js
new file mode 100644
index 0000000000000000000000000000000000000000..bd7537c54cda27ce0a410a79d25511fcf25d1895
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/tzl.js
@@ -0,0 +1,91 @@
+//! moment.js locale configuration
+//! locale : Talossan [tzl]
+//! author : Robin van der Vliet : https://github.com/robin0van0der0v
+//! author : Iustì Canun
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+// After the year there should be a slash and the amount of years since December 26, 1979 in Roman numerals.
+// This is currently too difficult (maybe even impossible) to add.
+var tzl = moment.defineLocale('tzl', {
+    months : 'Januar_Fevraglh_Març_Avrïu_Mai_Gün_Julia_Guscht_Setemvar_Listopäts_Noemvar_Zecemvar'.split('_'),
+    monthsShort : 'Jan_Fev_Mar_Avr_Mai_Gün_Jul_Gus_Set_Lis_Noe_Zec'.split('_'),
+    weekdays : 'Súladi_Lúneçi_Maitzi_Márcuri_Xhúadi_Viénerçi_Sáturi'.split('_'),
+    weekdaysShort : 'Súl_Lún_Mai_Már_Xhú_Vié_Sát'.split('_'),
+    weekdaysMin : 'Sú_Lú_Ma_Má_Xh_Vi_Sá'.split('_'),
+    longDateFormat : {
+        LT : 'HH.mm',
+        LTS : 'HH.mm.ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM [dallas] YYYY',
+        LLL : 'D. MMMM [dallas] YYYY HH.mm',
+        LLLL : 'dddd, [li] D. MMMM [dallas] YYYY HH.mm'
+    },
+    meridiemParse: /d\'o|d\'a/i,
+    isPM : function (input) {
+        return 'd\'o' === input.toLowerCase();
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours > 11) {
+            return isLower ? 'd\'o' : 'D\'O';
+        } else {
+            return isLower ? 'd\'a' : 'D\'A';
+        }
+    },
+    calendar : {
+        sameDay : '[oxhi à] LT',
+        nextDay : '[demà à] LT',
+        nextWeek : 'dddd [à] LT',
+        lastDay : '[ieiri à] LT',
+        lastWeek : '[sür el] dddd [lasteu à] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'osprei %s',
+        past : 'ja%s',
+        s : processRelativeTime,
+        m : processRelativeTime,
+        mm : processRelativeTime,
+        h : processRelativeTime,
+        hh : processRelativeTime,
+        d : processRelativeTime,
+        dd : processRelativeTime,
+        M : processRelativeTime,
+        MM : processRelativeTime,
+        y : processRelativeTime,
+        yy : processRelativeTime
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+function processRelativeTime(number, withoutSuffix, key, isFuture) {
+    var format = {
+        's': ['viensas secunds', '\'iensas secunds'],
+        'm': ['\'n míut', '\'iens míut'],
+        'mm': [number + ' míuts', '' + number + ' míuts'],
+        'h': ['\'n þora', '\'iensa þora'],
+        'hh': [number + ' þoras', '' + number + ' þoras'],
+        'd': ['\'n ziua', '\'iensa ziua'],
+        'dd': [number + ' ziuas', '' + number + ' ziuas'],
+        'M': ['\'n mes', '\'iens mes'],
+        'MM': [number + ' mesen', '' + number + ' mesen'],
+        'y': ['\'n ar', '\'iens ar'],
+        'yy': [number + ' ars', '' + number + ' ars']
+    };
+    return isFuture ? format[key][0] : (withoutSuffix ? format[key][0] : format[key][1]);
+}
+
+return tzl;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/tzm-latn.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/tzm-latn.js
new file mode 100644
index 0000000000000000000000000000000000000000..4d742c52fe8e929b0c861aaa4d58f66719ac23f6
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/tzm-latn.js
@@ -0,0 +1,58 @@
+//! moment.js locale configuration
+//! locale : Central Atlas Tamazight Latin [tzm-latn]
+//! author : Abdel Said : https://github.com/abdelsaid
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var tzmLatn = moment.defineLocale('tzm-latn', {
+    months : 'innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir'.split('_'),
+    monthsShort : 'innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir'.split('_'),
+    weekdays : 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'),
+    weekdaysShort : 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'),
+    weekdaysMin : 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[asdkh g] LT',
+        nextDay: '[aska g] LT',
+        nextWeek: 'dddd [g] LT',
+        lastDay: '[assant g] LT',
+        lastWeek: 'dddd [g] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'dadkh s yan %s',
+        past : 'yan %s',
+        s : 'imik',
+        m : 'minuḍ',
+        mm : '%d minuḍ',
+        h : 'saɛa',
+        hh : '%d tassaɛin',
+        d : 'ass',
+        dd : '%d ossan',
+        M : 'ayowr',
+        MM : '%d iyyirn',
+        y : 'asgas',
+        yy : '%d isgasn'
+    },
+    week : {
+        dow : 6, // Saturday is the first day of the week.
+        doy : 12  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return tzmLatn;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/tzm.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/tzm.js
new file mode 100644
index 0000000000000000000000000000000000000000..1d1c26006d30064121fdec73efa38dceae997892
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/tzm.js
@@ -0,0 +1,58 @@
+//! moment.js locale configuration
+//! locale : Central Atlas Tamazight [tzm]
+//! author : Abdel Said : https://github.com/abdelsaid
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var tzm = moment.defineLocale('tzm', {
+    months : 'ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ'.split('_'),
+    monthsShort : 'ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ'.split('_'),
+    weekdays : 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'),
+    weekdaysShort : 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'),
+    weekdaysMin : 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS: 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[ⴰⵙⴷⵅ ⴴ] LT',
+        nextDay: '[ⴰⵙⴽⴰ ⴴ] LT',
+        nextWeek: 'dddd [â´´] LT',
+        lastDay: '[ⴰⵚⴰⵏⵜ ⴴ] LT',
+        lastWeek: 'dddd [â´´] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'ⴷⴰⴷⵅ ⵙ ⵢⴰⵏ %s',
+        past : 'ⵢⴰⵏ %s',
+        s : 'ⵉⵎⵉⴽ',
+        m : 'ⵎⵉⵏⵓⴺ',
+        mm : '%d ⵎⵉⵏⵓⴺ',
+        h : 'ⵙⴰⵄⴰ',
+        hh : '%d ⵜⴰⵙⵙⴰⵄⵉⵏ',
+        d : 'ⴰⵙⵙ',
+        dd : '%d oⵙⵙⴰⵏ',
+        M : 'ⴰⵢoⵓⵔ',
+        MM : '%d ⵉⵢⵢⵉⵔⵏ',
+        y : 'ⴰⵙⴳⴰⵙ',
+        yy : '%d ⵉⵙⴳⴰⵙⵏ'
+    },
+    week : {
+        dow : 6, // Saturday is the first day of the week.
+        doy : 12  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return tzm;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/uk.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/uk.js
new file mode 100644
index 0000000000000000000000000000000000000000..af79fab5042c7c66389289d02e58e5adad638207
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/uk.js
@@ -0,0 +1,146 @@
+//! moment.js locale configuration
+//! locale : Ukrainian [uk]
+//! author : zemlanin : https://github.com/zemlanin
+//! Author : Menelion Elensúle : https://github.com/Oire
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+function plural(word, num) {
+    var forms = word.split('_');
+    return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]);
+}
+function relativeTimeWithPlural(number, withoutSuffix, key) {
+    var format = {
+        'mm': withoutSuffix ? 'хвилина_хвилини_хвилин' : 'хвилину_хвилини_хвилин',
+        'hh': withoutSuffix ? 'година_години_годин' : 'годину_години_годин',
+        'dd': 'день_дні_днів',
+        'MM': 'місяць_місяці_місяців',
+        'yy': 'рік_роки_років'
+    };
+    if (key === 'm') {
+        return withoutSuffix ? 'хвилина' : 'хвилину';
+    }
+    else if (key === 'h') {
+        return withoutSuffix ? 'година' : 'годину';
+    }
+    else {
+        return number + ' ' + plural(format[key], +number);
+    }
+}
+function weekdaysCaseReplace(m, format) {
+    var weekdays = {
+        'nominative': 'неділя_понеділок_вівторок_середа_четвер_п’ятниця_субота'.split('_'),
+        'accusative': 'неділю_понеділок_вівторок_середу_четвер_п’ятницю_суботу'.split('_'),
+        'genitive': 'неділі_понеділка_вівторка_середи_четверга_п’ятниці_суботи'.split('_')
+    },
+    nounCase = (/(\[[ВвУу]\]) ?dddd/).test(format) ?
+        'accusative' :
+        ((/\[?(?:минулої|наступної)? ?\] ?dddd/).test(format) ?
+            'genitive' :
+            'nominative');
+    return weekdays[nounCase][m.day()];
+}
+function processHoursFunction(str) {
+    return function () {
+        return str + 'о' + (this.hours() === 11 ? 'б' : '') + '] LT';
+    };
+}
+
+var uk = moment.defineLocale('uk', {
+    months : {
+        'format': 'січня_лютого_березня_квітня_травня_червня_липня_серпня_вересня_жовтня_листопада_грудня'.split('_'),
+        'standalone': 'січень_лютий_березень_квітень_травень_червень_липень_серпень_вересень_жовтень_листопад_грудень'.split('_')
+    },
+    monthsShort : 'січ_лют_бер_квіт_трав_черв_лип_серп_вер_жовт_лист_груд'.split('_'),
+    weekdays : weekdaysCaseReplace,
+    weekdaysShort : 'нд_пн_вт_ср_чт_пт_сб'.split('_'),
+    weekdaysMin : 'нд_пн_вт_ср_чт_пт_сб'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY р.',
+        LLL : 'D MMMM YYYY р., HH:mm',
+        LLLL : 'dddd, D MMMM YYYY р., HH:mm'
+    },
+    calendar : {
+        sameDay: processHoursFunction('[Сьогодні '),
+        nextDay: processHoursFunction('[Завтра '),
+        lastDay: processHoursFunction('[Вчора '),
+        nextWeek: processHoursFunction('[У] dddd ['),
+        lastWeek: function () {
+            switch (this.day()) {
+                case 0:
+                case 3:
+                case 5:
+                case 6:
+                    return processHoursFunction('[Минулої] dddd [').call(this);
+                case 1:
+                case 2:
+                case 4:
+                    return processHoursFunction('[Минулого] dddd [').call(this);
+            }
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'за %s',
+        past : '%s тому',
+        s : 'декілька секунд',
+        m : relativeTimeWithPlural,
+        mm : relativeTimeWithPlural,
+        h : 'годину',
+        hh : relativeTimeWithPlural,
+        d : 'день',
+        dd : relativeTimeWithPlural,
+        M : 'місяць',
+        MM : relativeTimeWithPlural,
+        y : 'рік',
+        yy : relativeTimeWithPlural
+    },
+    // M. E.: those two are virtually unused but a user might want to implement them for his/her website for some reason
+    meridiemParse: /ночі|ранку|дня|вечора/,
+    isPM: function (input) {
+        return /^(дня|вечора)$/.test(input);
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'ночі';
+        } else if (hour < 12) {
+            return 'ранку';
+        } else if (hour < 17) {
+            return 'дня';
+        } else {
+            return 'вечора';
+        }
+    },
+    ordinalParse: /\d{1,2}-(й|го)/,
+    ordinal: function (number, period) {
+        switch (period) {
+            case 'M':
+            case 'd':
+            case 'DDD':
+            case 'w':
+            case 'W':
+                return number + '-й';
+            case 'D':
+                return number + '-го';
+            default:
+                return number;
+        }
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+return uk;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/uz.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/uz.js
new file mode 100644
index 0000000000000000000000000000000000000000..378461eb003b9c98ade39d915119a88e06c605d5
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/uz.js
@@ -0,0 +1,58 @@
+//! moment.js locale configuration
+//! locale : Uzbek [uz]
+//! author : Sardor Muminov : https://github.com/muminoff
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var uz = moment.defineLocale('uz', {
+    months : 'январ_феврал_март_апрел_май_июн_июл_август_сентябр_октябр_ноябр_декабр'.split('_'),
+    monthsShort : 'янв_фев_мар_апр_май_июн_июл_авг_сен_окт_ноя_дек'.split('_'),
+    weekdays : 'Якшанба_Душанба_Сешанба_Чоршанба_Пайшанба_Жума_Шанба'.split('_'),
+    weekdaysShort : 'Якш_Душ_Сеш_Чор_Пай_Жум_Шан'.split('_'),
+    weekdaysMin : 'Як_Ду_Се_Чо_Па_Жу_Ша'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'D MMMM YYYY, dddd HH:mm'
+    },
+    calendar : {
+        sameDay : '[Бугун соат] LT [да]',
+        nextDay : '[Эртага] LT [да]',
+        nextWeek : 'dddd [куни соат] LT [да]',
+        lastDay : '[Кеча соат] LT [да]',
+        lastWeek : '[Утган] dddd [куни соат] LT [да]',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'Якин %s ичида',
+        past : 'Бир неча %s олдин',
+        s : 'фурсат',
+        m : 'бир дакика',
+        mm : '%d дакика',
+        h : 'бир соат',
+        hh : '%d соат',
+        d : 'бир кун',
+        dd : '%d кун',
+        M : 'бир ой',
+        MM : '%d ой',
+        y : 'бир йил',
+        yy : '%d йил'
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return uz;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/vi.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/vi.js
new file mode 100644
index 0000000000000000000000000000000000000000..7af5cce188e3656265d8ef6e096ab7fce8816f0b
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/vi.js
@@ -0,0 +1,79 @@
+//! moment.js locale configuration
+//! locale : Vietnamese [vi]
+//! author : Bang Nguyen : https://github.com/bangnk
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var vi = moment.defineLocale('vi', {
+    months : 'tháng 1_tháng 2_tháng 3_tháng 4_tháng 5_tháng 6_tháng 7_tháng 8_tháng 9_tháng 10_tháng 11_tháng 12'.split('_'),
+    monthsShort : 'Th01_Th02_Th03_Th04_Th05_Th06_Th07_Th08_Th09_Th10_Th11_Th12'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'chủ nhật_thứ hai_thứ ba_thứ tư_thứ năm_thứ sáu_thứ bảy'.split('_'),
+    weekdaysShort : 'CN_T2_T3_T4_T5_T6_T7'.split('_'),
+    weekdaysMin : 'CN_T2_T3_T4_T5_T6_T7'.split('_'),
+    weekdaysParseExact : true,
+    meridiemParse: /sa|ch/i,
+    isPM : function (input) {
+        return /^ch$/i.test(input);
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 12) {
+            return isLower ? 'sa' : 'SA';
+        } else {
+            return isLower ? 'ch' : 'CH';
+        }
+    },
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM [năm] YYYY',
+        LLL : 'D MMMM [năm] YYYY HH:mm',
+        LLLL : 'dddd, D MMMM [năm] YYYY HH:mm',
+        l : 'DD/M/YYYY',
+        ll : 'D MMM YYYY',
+        lll : 'D MMM YYYY HH:mm',
+        llll : 'ddd, D MMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Hôm nay lúc] LT',
+        nextDay: '[Ngày mai lúc] LT',
+        nextWeek: 'dddd [tuần tới lúc] LT',
+        lastDay: '[Hôm qua lúc] LT',
+        lastWeek: 'dddd [tuần rồi lúc] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : '%s tá»›i',
+        past : '%s trước',
+        s : 'vài giây',
+        m : 'một phút',
+        mm : '%d phút',
+        h : 'một giờ',
+        hh : '%d giờ',
+        d : 'một ngày',
+        dd : '%d ngày',
+        M : 'một tháng',
+        MM : '%d tháng',
+        y : 'một năm',
+        yy : '%d năm'
+    },
+    ordinalParse: /\d{1,2}/,
+    ordinal : function (number) {
+        return number;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return vi;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/x-pseudo.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/x-pseudo.js
new file mode 100644
index 0000000000000000000000000000000000000000..ee24b9f0951ecbdb1ebc080574af2a1ec0482e0a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/x-pseudo.js
@@ -0,0 +1,68 @@
+//! moment.js locale configuration
+//! locale : Pseudo [x-pseudo]
+//! author : Andrew Hood : https://github.com/andrewhood125
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var xPseudo = moment.defineLocale('x-pseudo', {
+    months : 'J~áñúá~rý_F~ébrú~árý_~Márc~h_Áp~ríl_~Máý_~Júñé~_Júl~ý_Áú~gúst~_Sép~témb~ér_Ó~ctób~ér_Ñ~óvém~bér_~Décé~mbér'.split('_'),
+    monthsShort : 'J~áñ_~Féb_~Már_~Ápr_~Máý_~Júñ_~Júl_~Áúg_~Sép_~Óct_~Ñóv_~Déc'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'S~úñdá~ý_Mó~ñdáý~_Túé~sdáý~_Wéd~ñésd~áý_T~húrs~dáý_~Fríd~áý_S~átúr~dáý'.split('_'),
+    weekdaysShort : 'S~úñ_~Móñ_~Túé_~Wéd_~Thú_~Frí_~Sát'.split('_'),
+    weekdaysMin : 'S~ú_Mó~_Tú_~Wé_T~h_Fr~_Sá'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[T~ódá~ý át] LT',
+        nextDay : '[T~ómó~rró~w át] LT',
+        nextWeek : 'dddd [át] LT',
+        lastDay : '[Ý~ést~érdá~ý át] LT',
+        lastWeek : '[L~ást] dddd [át] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'í~ñ %s',
+        past : '%s á~gó',
+        s : 'á ~féw ~sécó~ñds',
+        m : 'á ~míñ~úté',
+        mm : '%d m~íñú~tés',
+        h : 'á~ñ hó~úr',
+        hh : '%d h~óúrs',
+        d : 'á ~dáý',
+        dd : '%d d~áýs',
+        M : 'á ~móñ~th',
+        MM : '%d m~óñt~hs',
+        y : 'á ~ýéár',
+        yy : '%d ý~éárs'
+    },
+    ordinalParse: /\d{1,2}(th|st|nd|rd)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return xPseudo;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/zh-cn.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/zh-cn.js
new file mode 100644
index 0000000000000000000000000000000000000000..df5d20394645d07b262cd40c820cdb02c1a2d626
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/zh-cn.js
@@ -0,0 +1,127 @@
+//! moment.js locale configuration
+//! locale : Chinese (China) [zh-cn]
+//! author : suupic : https://github.com/suupic
+//! author : Zeno Zeng : https://github.com/zenozeng
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var zhCn = moment.defineLocale('zh-cn', {
+    months : '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'),
+    monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
+    weekdays : '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'),
+    weekdaysShort : '周日_周一_周二_周三_周四_周五_周六'.split('_'),
+    weekdaysMin : '日_一_二_三_四_五_六'.split('_'),
+    longDateFormat : {
+        LT : 'Ah点mm分',
+        LTS : 'Ah点m分s秒',
+        L : 'YYYY-MM-DD',
+        LL : 'YYYYå¹´MMMDæ—¥',
+        LLL : 'YYYY年MMMD日Ah点mm分',
+        LLLL : 'YYYY年MMMD日ddddAh点mm分',
+        l : 'YYYY-MM-DD',
+        ll : 'YYYYå¹´MMMDæ—¥',
+        lll : 'YYYY年MMMD日Ah点mm分',
+        llll : 'YYYY年MMMD日ddddAh点mm分'
+    },
+    meridiemParse: /凌晨|早上|上午|中午|下午|晚上/,
+    meridiemHour: function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === '凌晨' || meridiem === '早上' ||
+                meridiem === '上午') {
+            return hour;
+        } else if (meridiem === '下午' || meridiem === '晚上') {
+            return hour + 12;
+        } else {
+            // '中午'
+            return hour >= 11 ? hour : hour + 12;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        var hm = hour * 100 + minute;
+        if (hm < 600) {
+            return '凌晨';
+        } else if (hm < 900) {
+            return '早上';
+        } else if (hm < 1130) {
+            return '上午';
+        } else if (hm < 1230) {
+            return '中午';
+        } else if (hm < 1800) {
+            return '下午';
+        } else {
+            return '晚上';
+        }
+    },
+    calendar : {
+        sameDay : function () {
+            return this.minutes() === 0 ? '[今天]Ah[点整]' : '[今天]LT';
+        },
+        nextDay : function () {
+            return this.minutes() === 0 ? '[明天]Ah[点整]' : '[明天]LT';
+        },
+        lastDay : function () {
+            return this.minutes() === 0 ? '[昨天]Ah[点整]' : '[昨天]LT';
+        },
+        nextWeek : function () {
+            var startOfWeek, prefix;
+            startOfWeek = moment().startOf('week');
+            prefix = this.diff(startOfWeek, 'days') >= 7 ? '[下]' : '[本]';
+            return this.minutes() === 0 ? prefix + 'dddAh点整' : prefix + 'dddAh点mm';
+        },
+        lastWeek : function () {
+            var startOfWeek, prefix;
+            startOfWeek = moment().startOf('week');
+            prefix = this.unix() < startOfWeek.unix()  ? '[上]' : '[本]';
+            return this.minutes() === 0 ? prefix + 'dddAh点整' : prefix + 'dddAh点mm';
+        },
+        sameElse : 'LL'
+    },
+    ordinalParse: /\d{1,2}(日|月|周)/,
+    ordinal : function (number, period) {
+        switch (period) {
+            case 'd':
+            case 'D':
+            case 'DDD':
+                return number + 'æ—¥';
+            case 'M':
+                return number + '月';
+            case 'w':
+            case 'W':
+                return number + '周';
+            default:
+                return number;
+        }
+    },
+    relativeTime : {
+        future : '%s内',
+        past : '%s前',
+        s : '几秒',
+        m : '1 分钟',
+        mm : '%d 分钟',
+        h : '1 小时',
+        hh : '%d 小时',
+        d : '1 天',
+        dd : '%d 天',
+        M : '1 个月',
+        MM : '%d 个月',
+        y : '1 å¹´',
+        yy : '%d å¹´'
+    },
+    week : {
+        // GB/T 7408-1994《数据元和交换格式·信息交换·日期和时间表示法》与ISO 8601:1988等效
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+return zhCn;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/zh-hk.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/zh-hk.js
new file mode 100644
index 0000000000000000000000000000000000000000..f39fe3fbfc931ab6b6da3b591b6b4ca281da9d21
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/zh-hk.js
@@ -0,0 +1,105 @@
+//! moment.js locale configuration
+//! locale : Chinese (Hong Kong) [zh-hk]
+//! author : Ben : https://github.com/ben-lin
+//! author : Chris Lam : https://github.com/hehachris
+//! author : Konstantin : https://github.com/skfd
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var zhHk = moment.defineLocale('zh-hk', {
+    months : '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'),
+    monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
+    weekdays : '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'),
+    weekdaysShort : '週日_週一_週二_週三_週四_週五_週六'.split('_'),
+    weekdaysMin : '日_一_二_三_四_五_六'.split('_'),
+    longDateFormat : {
+        LT : 'Ah點mm分',
+        LTS : 'Ah點m分s秒',
+        L : 'YYYYå¹´MMMDæ—¥',
+        LL : 'YYYYå¹´MMMDæ—¥',
+        LLL : 'YYYY年MMMD日Ah點mm分',
+        LLLL : 'YYYY年MMMD日ddddAh點mm分',
+        l : 'YYYYå¹´MMMDæ—¥',
+        ll : 'YYYYå¹´MMMDæ—¥',
+        lll : 'YYYY年MMMD日Ah點mm分',
+        llll : 'YYYY年MMMD日ddddAh點mm分'
+    },
+    meridiemParse: /凌晨|早上|上午|中午|下午|晚上/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === '凌晨' || meridiem === '早上' || meridiem === '上午') {
+            return hour;
+        } else if (meridiem === '中午') {
+            return hour >= 11 ? hour : hour + 12;
+        } else if (meridiem === '下午' || meridiem === '晚上') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        var hm = hour * 100 + minute;
+        if (hm < 600) {
+            return '凌晨';
+        } else if (hm < 900) {
+            return '早上';
+        } else if (hm < 1130) {
+            return '上午';
+        } else if (hm < 1230) {
+            return '中午';
+        } else if (hm < 1800) {
+            return '下午';
+        } else {
+            return '晚上';
+        }
+    },
+    calendar : {
+        sameDay : '[今天]LT',
+        nextDay : '[明天]LT',
+        nextWeek : '[下]ddddLT',
+        lastDay : '[昨天]LT',
+        lastWeek : '[上]ddddLT',
+        sameElse : 'L'
+    },
+    ordinalParse: /\d{1,2}(日|月|週)/,
+    ordinal : function (number, period) {
+        switch (period) {
+            case 'd' :
+            case 'D' :
+            case 'DDD' :
+                return number + 'æ—¥';
+            case 'M' :
+                return number + '月';
+            case 'w' :
+            case 'W' :
+                return number + '週';
+            default :
+                return number;
+        }
+    },
+    relativeTime : {
+        future : '%så…§',
+        past : '%s前',
+        s : '幾秒',
+        m : '1 分鐘',
+        mm : '%d 分鐘',
+        h : '1 小時',
+        hh : '%d 小時',
+        d : '1 天',
+        dd : '%d 天',
+        M : '1 個月',
+        MM : '%d 個月',
+        y : '1 å¹´',
+        yy : '%d å¹´'
+    }
+});
+
+return zhHk;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/zh-tw.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/zh-tw.js
new file mode 100644
index 0000000000000000000000000000000000000000..2e385fb2739fcc543272ed40c9eff0e8d81766f5
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/locale/zh-tw.js
@@ -0,0 +1,104 @@
+//! moment.js locale configuration
+//! locale : Chinese (Taiwan) [zh-tw]
+//! author : Ben : https://github.com/ben-lin
+//! author : Chris Lam : https://github.com/hehachris
+
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+
+var zhTw = moment.defineLocale('zh-tw', {
+    months : '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'),
+    monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
+    weekdays : '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'),
+    weekdaysShort : '週日_週一_週二_週三_週四_週五_週六'.split('_'),
+    weekdaysMin : '日_一_二_三_四_五_六'.split('_'),
+    longDateFormat : {
+        LT : 'Ah點mm分',
+        LTS : 'Ah點m分s秒',
+        L : 'YYYYå¹´MMMDæ—¥',
+        LL : 'YYYYå¹´MMMDæ—¥',
+        LLL : 'YYYY年MMMD日Ah點mm分',
+        LLLL : 'YYYY年MMMD日ddddAh點mm分',
+        l : 'YYYYå¹´MMMDæ—¥',
+        ll : 'YYYYå¹´MMMDæ—¥',
+        lll : 'YYYY年MMMD日Ah點mm分',
+        llll : 'YYYY年MMMD日ddddAh點mm分'
+    },
+    meridiemParse: /凌晨|早上|上午|中午|下午|晚上/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === '凌晨' || meridiem === '早上' || meridiem === '上午') {
+            return hour;
+        } else if (meridiem === '中午') {
+            return hour >= 11 ? hour : hour + 12;
+        } else if (meridiem === '下午' || meridiem === '晚上') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        var hm = hour * 100 + minute;
+        if (hm < 600) {
+            return '凌晨';
+        } else if (hm < 900) {
+            return '早上';
+        } else if (hm < 1130) {
+            return '上午';
+        } else if (hm < 1230) {
+            return '中午';
+        } else if (hm < 1800) {
+            return '下午';
+        } else {
+            return '晚上';
+        }
+    },
+    calendar : {
+        sameDay : '[今天]LT',
+        nextDay : '[明天]LT',
+        nextWeek : '[下]ddddLT',
+        lastDay : '[昨天]LT',
+        lastWeek : '[上]ddddLT',
+        sameElse : 'L'
+    },
+    ordinalParse: /\d{1,2}(日|月|週)/,
+    ordinal : function (number, period) {
+        switch (period) {
+            case 'd' :
+            case 'D' :
+            case 'DDD' :
+                return number + 'æ—¥';
+            case 'M' :
+                return number + '月';
+            case 'w' :
+            case 'W' :
+                return number + '週';
+            default :
+                return number;
+        }
+    },
+    relativeTime : {
+        future : '%så…§',
+        past : '%s前',
+        s : '幾秒',
+        m : '1 分鐘',
+        mm : '%d 分鐘',
+        h : '1 小時',
+        hh : '%d 小時',
+        d : '1 天',
+        dd : '%d 天',
+        M : '1 個月',
+        MM : '%d 個月',
+        y : '1 å¹´',
+        yy : '%d å¹´'
+    }
+});
+
+return zhTw;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/min/locales.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/min/locales.js
new file mode 100644
index 0000000000000000000000000000000000000000..d09eb434721f8cd22589c2469be1fb0575cb7898
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/min/locales.js
@@ -0,0 +1,8579 @@
+;(function (global, factory) {
+   typeof exports === 'object' && typeof module !== 'undefined'
+       && typeof require === 'function' ? factory(require('../moment')) :
+   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
+   factory(global.moment)
+}(this, (function (moment) { 'use strict';
+
+//! moment.js locale configuration
+//! locale : Afrikaans [af]
+//! author : Werner Mollentze : https://github.com/wernerm
+
+moment.defineLocale('af', {
+    months : 'Januarie_Februarie_Maart_April_Mei_Junie_Julie_Augustus_September_Oktober_November_Desember'.split('_'),
+    monthsShort : 'Jan_Feb_Mrt_Apr_Mei_Jun_Jul_Aug_Sep_Okt_Nov_Des'.split('_'),
+    weekdays : 'Sondag_Maandag_Dinsdag_Woensdag_Donderdag_Vrydag_Saterdag'.split('_'),
+    weekdaysShort : 'Son_Maa_Din_Woe_Don_Vry_Sat'.split('_'),
+    weekdaysMin : 'So_Ma_Di_Wo_Do_Vr_Sa'.split('_'),
+    meridiemParse: /vm|nm/i,
+    isPM : function (input) {
+        return /^nm$/i.test(input);
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 12) {
+            return isLower ? 'vm' : 'VM';
+        } else {
+            return isLower ? 'nm' : 'NM';
+        }
+    },
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[Vandag om] LT',
+        nextDay : '[Môre om] LT',
+        nextWeek : 'dddd [om] LT',
+        lastDay : '[Gister om] LT',
+        lastWeek : '[Laas] dddd [om] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'oor %s',
+        past : '%s gelede',
+        s : '\'n paar sekondes',
+        m : '\'n minuut',
+        mm : '%d minute',
+        h : '\'n uur',
+        hh : '%d ure',
+        d : '\'n dag',
+        dd : '%d dae',
+        M : '\'n maand',
+        MM : '%d maande',
+        y : '\'n jaar',
+        yy : '%d jaar'
+    },
+    ordinalParse: /\d{1,2}(ste|de)/,
+    ordinal : function (number) {
+        return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de'); // Thanks to Joris Röling : https://github.com/jjupiter
+    },
+    week : {
+        dow : 1, // Maandag is die eerste dag van die week.
+        doy : 4  // Die week wat die 4de Januarie bevat is die eerste week van die jaar.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Arabic (Algeria) [ar-dz]
+//! author : Noureddine LOUAHEDJ : https://github.com/noureddineme
+
+moment.defineLocale('ar-dz', {
+    months : 'جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
+    monthsShort : 'جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
+    weekdays : 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
+    weekdaysShort : 'احد_اثنين_ثلاثاء_اربعاء_خميس_جمعة_سبت'.split('_'),
+    weekdaysMin : 'أح_إث_ثلا_أر_خم_جم_سب'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[اليوم على الساعة] LT',
+        nextDay: '[غدا على الساعة] LT',
+        nextWeek: 'dddd [على الساعة] LT',
+        lastDay: '[أمس على الساعة] LT',
+        lastWeek: 'dddd [على الساعة] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'في %s',
+        past : 'منذ %s',
+        s : 'ثوان',
+        m : 'دقيقة',
+        mm : '%d دقائق',
+        h : 'ساعة',
+        hh : '%d ساعات',
+        d : 'يوم',
+        dd : '%d أيام',
+        M : 'شهر',
+        MM : '%d أشهر',
+        y : 'سنة',
+        yy : '%d سنوات'
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 4  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Arabic (Lybia) [ar-ly]
+//! author : Ali Hmer: https://github.com/kikoanis
+
+var symbolMap = {
+    '1': '1',
+    '2': '2',
+    '3': '3',
+    '4': '4',
+    '5': '5',
+    '6': '6',
+    '7': '7',
+    '8': '8',
+    '9': '9',
+    '0': '0'
+};
+var pluralForm = function (n) {
+    return n === 0 ? 0 : n === 1 ? 1 : n === 2 ? 2 : n % 100 >= 3 && n % 100 <= 10 ? 3 : n % 100 >= 11 ? 4 : 5;
+};
+var plurals = {
+    s : ['أقل من ثانية', 'ثانية واحدة', ['ثانيتان', 'ثانيتين'], '%d ثوان', '%d ثانية', '%d ثانية'],
+    m : ['أقل من دقيقة', 'دقيقة واحدة', ['دقيقتان', 'دقيقتين'], '%d دقائق', '%d دقيقة', '%d دقيقة'],
+    h : ['أقل من ساعة', 'ساعة واحدة', ['ساعتان', 'ساعتين'], '%d ساعات', '%d ساعة', '%d ساعة'],
+    d : ['أقل من يوم', 'يوم واحد', ['يومان', 'يومين'], '%d أيام', '%d يومًا', '%d يوم'],
+    M : ['أقل من شهر', 'شهر واحد', ['شهران', 'شهرين'], '%d أشهر', '%d شهرا', '%d شهر'],
+    y : ['أقل من عام', 'عام واحد', ['عامان', 'عامين'], '%d أعوام', '%d عامًا', '%d عام']
+};
+var pluralize = function (u) {
+    return function (number, withoutSuffix, string, isFuture) {
+        var f = pluralForm(number),
+            str = plurals[u][pluralForm(number)];
+        if (f === 2) {
+            str = str[withoutSuffix ? 0 : 1];
+        }
+        return str.replace(/%d/i, number);
+    };
+};
+var months = [
+    'يناير',
+    'فبراير',
+    'مارس',
+    'أبريل',
+    'مايو',
+    'يونيو',
+    'يوليو',
+    'أغسطس',
+    'سبتمبر',
+    'أكتوبر',
+    'نوفمبر',
+    'ديسمبر'
+];
+
+moment.defineLocale('ar-ly', {
+    months : months,
+    monthsShort : months,
+    weekdays : 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
+    weekdaysShort : 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'),
+    weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'D/\u200FM/\u200FYYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    meridiemParse: /ص|م/,
+    isPM : function (input) {
+        return 'Ù…' === input;
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return 'ص';
+        } else {
+            return 'Ù…';
+        }
+    },
+    calendar : {
+        sameDay: '[اليوم عند الساعة] LT',
+        nextDay: '[غدًا عند الساعة] LT',
+        nextWeek: 'dddd [عند الساعة] LT',
+        lastDay: '[أمس عند الساعة] LT',
+        lastWeek: 'dddd [عند الساعة] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'بعد %s',
+        past : 'منذ %s',
+        s : pluralize('s'),
+        m : pluralize('m'),
+        mm : pluralize('m'),
+        h : pluralize('h'),
+        hh : pluralize('h'),
+        d : pluralize('d'),
+        dd : pluralize('d'),
+        M : pluralize('M'),
+        MM : pluralize('M'),
+        y : pluralize('y'),
+        yy : pluralize('y')
+    },
+    preparse: function (string) {
+        return string.replace(/\u200f/g, '').replace(/،/g, ',');
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap[match];
+        }).replace(/,/g, '،');
+    },
+    week : {
+        dow : 6, // Saturday is the first day of the week.
+        doy : 12  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Arabic (Morocco) [ar-ma]
+//! author : ElFadili Yassine : https://github.com/ElFadiliY
+//! author : Abdel Said : https://github.com/abdelsaid
+
+moment.defineLocale('ar-ma', {
+    months : 'يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر'.split('_'),
+    monthsShort : 'يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر'.split('_'),
+    weekdays : 'الأحد_الإتنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
+    weekdaysShort : 'احد_اتنين_ثلاثاء_اربعاء_خميس_جمعة_سبت'.split('_'),
+    weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[اليوم على الساعة] LT',
+        nextDay: '[غدا على الساعة] LT',
+        nextWeek: 'dddd [على الساعة] LT',
+        lastDay: '[أمس على الساعة] LT',
+        lastWeek: 'dddd [على الساعة] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'في %s',
+        past : 'منذ %s',
+        s : 'ثوان',
+        m : 'دقيقة',
+        mm : '%d دقائق',
+        h : 'ساعة',
+        hh : '%d ساعات',
+        d : 'يوم',
+        dd : '%d أيام',
+        M : 'شهر',
+        MM : '%d أشهر',
+        y : 'سنة',
+        yy : '%d سنوات'
+    },
+    week : {
+        dow : 6, // Saturday is the first day of the week.
+        doy : 12  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Arabic (Saudi Arabia) [ar-sa]
+//! author : Suhail Alkowaileet : https://github.com/xsoh
+
+var symbolMap$1 = {
+    '1': 'Ù¡',
+    '2': 'Ù¢',
+    '3': 'Ù£',
+    '4': 'Ù¤',
+    '5': 'Ù¥',
+    '6': 'Ù¦',
+    '7': 'Ù§',
+    '8': 'Ù¨',
+    '9': 'Ù©',
+    '0': 'Ù '
+};
+var numberMap = {
+    'Ù¡': '1',
+    'Ù¢': '2',
+    'Ù£': '3',
+    'Ù¤': '4',
+    'Ù¥': '5',
+    'Ù¦': '6',
+    'Ù§': '7',
+    'Ù¨': '8',
+    'Ù©': '9',
+    'Ù ': '0'
+};
+
+moment.defineLocale('ar-sa', {
+    months : 'يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
+    monthsShort : 'يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
+    weekdays : 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
+    weekdaysShort : 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'),
+    weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    meridiemParse: /ص|م/,
+    isPM : function (input) {
+        return 'Ù…' === input;
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return 'ص';
+        } else {
+            return 'Ù…';
+        }
+    },
+    calendar : {
+        sameDay: '[اليوم على الساعة] LT',
+        nextDay: '[غدا على الساعة] LT',
+        nextWeek: 'dddd [على الساعة] LT',
+        lastDay: '[أمس على الساعة] LT',
+        lastWeek: 'dddd [على الساعة] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'في %s',
+        past : 'منذ %s',
+        s : 'ثوان',
+        m : 'دقيقة',
+        mm : '%d دقائق',
+        h : 'ساعة',
+        hh : '%d ساعات',
+        d : 'يوم',
+        dd : '%d أيام',
+        M : 'شهر',
+        MM : '%d أشهر',
+        y : 'سنة',
+        yy : '%d سنوات'
+    },
+    preparse: function (string) {
+        return string.replace(/[١٢٣٤٥٦٧٨٩٠]/g, function (match) {
+            return numberMap[match];
+        }).replace(/،/g, ',');
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap$1[match];
+        }).replace(/,/g, '،');
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale  :  Arabic (Tunisia) [ar-tn]
+//! author : Nader Toukabri : https://github.com/naderio
+
+moment.defineLocale('ar-tn', {
+    months: 'جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
+    monthsShort: 'جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
+    weekdays: 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
+    weekdaysShort: 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'),
+    weekdaysMin: 'ح_ن_ث_ر_خ_ج_س'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat: {
+        LT: 'HH:mm',
+        LTS: 'HH:mm:ss',
+        L: 'DD/MM/YYYY',
+        LL: 'D MMMM YYYY',
+        LLL: 'D MMMM YYYY HH:mm',
+        LLLL: 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar: {
+        sameDay: '[اليوم على الساعة] LT',
+        nextDay: '[غدا على الساعة] LT',
+        nextWeek: 'dddd [على الساعة] LT',
+        lastDay: '[أمس على الساعة] LT',
+        lastWeek: 'dddd [على الساعة] LT',
+        sameElse: 'L'
+    },
+    relativeTime: {
+        future: 'في %s',
+        past: 'منذ %s',
+        s: 'ثوان',
+        m: 'دقيقة',
+        mm: '%d دقائق',
+        h: 'ساعة',
+        hh: '%d ساعات',
+        d: 'يوم',
+        dd: '%d أيام',
+        M: 'شهر',
+        MM: '%d أشهر',
+        y: 'سنة',
+        yy: '%d سنوات'
+    },
+    week: {
+        dow: 1, // Monday is the first day of the week.
+        doy: 4 // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Arabic [ar]
+//! author : Abdel Said: https://github.com/abdelsaid
+//! author : Ahmed Elkhatib
+//! author : forabi https://github.com/forabi
+
+var symbolMap$2 = {
+    '1': 'Ù¡',
+    '2': 'Ù¢',
+    '3': 'Ù£',
+    '4': 'Ù¤',
+    '5': 'Ù¥',
+    '6': 'Ù¦',
+    '7': 'Ù§',
+    '8': 'Ù¨',
+    '9': 'Ù©',
+    '0': 'Ù '
+};
+var numberMap$1 = {
+    'Ù¡': '1',
+    'Ù¢': '2',
+    'Ù£': '3',
+    'Ù¤': '4',
+    'Ù¥': '5',
+    'Ù¦': '6',
+    'Ù§': '7',
+    'Ù¨': '8',
+    'Ù©': '9',
+    'Ù ': '0'
+};
+var pluralForm$1 = function (n) {
+    return n === 0 ? 0 : n === 1 ? 1 : n === 2 ? 2 : n % 100 >= 3 && n % 100 <= 10 ? 3 : n % 100 >= 11 ? 4 : 5;
+};
+var plurals$1 = {
+    s : ['أقل من ثانية', 'ثانية واحدة', ['ثانيتان', 'ثانيتين'], '%d ثوان', '%d ثانية', '%d ثانية'],
+    m : ['أقل من دقيقة', 'دقيقة واحدة', ['دقيقتان', 'دقيقتين'], '%d دقائق', '%d دقيقة', '%d دقيقة'],
+    h : ['أقل من ساعة', 'ساعة واحدة', ['ساعتان', 'ساعتين'], '%d ساعات', '%d ساعة', '%d ساعة'],
+    d : ['أقل من يوم', 'يوم واحد', ['يومان', 'يومين'], '%d أيام', '%d يومًا', '%d يوم'],
+    M : ['أقل من شهر', 'شهر واحد', ['شهران', 'شهرين'], '%d أشهر', '%d شهرا', '%d شهر'],
+    y : ['أقل من عام', 'عام واحد', ['عامان', 'عامين'], '%d أعوام', '%d عامًا', '%d عام']
+};
+var pluralize$1 = function (u) {
+    return function (number, withoutSuffix, string, isFuture) {
+        var f = pluralForm$1(number),
+            str = plurals$1[u][pluralForm$1(number)];
+        if (f === 2) {
+            str = str[withoutSuffix ? 0 : 1];
+        }
+        return str.replace(/%d/i, number);
+    };
+};
+var months$1 = [
+    'كانون الثاني يناير',
+    'شباط فبراير',
+    'آذار مارس',
+    'نيسان أبريل',
+    'أيار مايو',
+    'حزيران يونيو',
+    'تموز يوليو',
+    'آب أغسطس',
+    'أيلول سبتمبر',
+    'تشرين الأول أكتوبر',
+    'تشرين الثاني نوفمبر',
+    'كانون الأول ديسمبر'
+];
+
+moment.defineLocale('ar', {
+    months : months$1,
+    monthsShort : months$1,
+    weekdays : 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
+    weekdaysShort : 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'),
+    weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'D/\u200FM/\u200FYYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    meridiemParse: /ص|م/,
+    isPM : function (input) {
+        return 'Ù…' === input;
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return 'ص';
+        } else {
+            return 'Ù…';
+        }
+    },
+    calendar : {
+        sameDay: '[اليوم عند الساعة] LT',
+        nextDay: '[غدًا عند الساعة] LT',
+        nextWeek: 'dddd [عند الساعة] LT',
+        lastDay: '[أمس عند الساعة] LT',
+        lastWeek: 'dddd [عند الساعة] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'بعد %s',
+        past : 'منذ %s',
+        s : pluralize$1('s'),
+        m : pluralize$1('m'),
+        mm : pluralize$1('m'),
+        h : pluralize$1('h'),
+        hh : pluralize$1('h'),
+        d : pluralize$1('d'),
+        dd : pluralize$1('d'),
+        M : pluralize$1('M'),
+        MM : pluralize$1('M'),
+        y : pluralize$1('y'),
+        yy : pluralize$1('y')
+    },
+    preparse: function (string) {
+        return string.replace(/\u200f/g, '').replace(/[١٢٣٤٥٦٧٨٩٠]/g, function (match) {
+            return numberMap$1[match];
+        }).replace(/،/g, ',');
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap$2[match];
+        }).replace(/,/g, '،');
+    },
+    week : {
+        dow : 6, // Saturday is the first day of the week.
+        doy : 12  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Azerbaijani [az]
+//! author : topchiyev : https://github.com/topchiyev
+
+var suffixes = {
+    1: '-inci',
+    5: '-inci',
+    8: '-inci',
+    70: '-inci',
+    80: '-inci',
+    2: '-nci',
+    7: '-nci',
+    20: '-nci',
+    50: '-nci',
+    3: '-üncü',
+    4: '-üncü',
+    100: '-üncü',
+    6: '-ncı',
+    9: '-uncu',
+    10: '-uncu',
+    30: '-uncu',
+    60: '-ıncı',
+    90: '-ıncı'
+};
+
+moment.defineLocale('az', {
+    months : 'yanvar_fevral_mart_aprel_may_iyun_iyul_avqust_sentyabr_oktyabr_noyabr_dekabr'.split('_'),
+    monthsShort : 'yan_fev_mar_apr_may_iyn_iyl_avq_sen_okt_noy_dek'.split('_'),
+    weekdays : 'Bazar_Bazar ertəsi_Çərşənbə axşamı_Çərşənbə_Cümə axşamı_Cümə_Şənbə'.split('_'),
+    weekdaysShort : 'Baz_BzE_ÇAx_Çər_CAx_Cüm_Şən'.split('_'),
+    weekdaysMin : 'Bz_BE_ÇA_Çə_CA_Cü_Şə'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[bugün saat] LT',
+        nextDay : '[sabah saat] LT',
+        nextWeek : '[gələn həftə] dddd [saat] LT',
+        lastDay : '[dünən] LT',
+        lastWeek : '[keçən həftə] dddd [saat] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s sonra',
+        past : '%s əvvəl',
+        s : 'birneçə saniyyə',
+        m : 'bir dəqiqə',
+        mm : '%d dəqiqə',
+        h : 'bir saat',
+        hh : '%d saat',
+        d : 'bir gün',
+        dd : '%d gün',
+        M : 'bir ay',
+        MM : '%d ay',
+        y : 'bir il',
+        yy : '%d il'
+    },
+    meridiemParse: /gecə|səhər|gündüz|axşam/,
+    isPM : function (input) {
+        return /^(gündüz|axşam)$/.test(input);
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'gecÉ™';
+        } else if (hour < 12) {
+            return 'səhər';
+        } else if (hour < 17) {
+            return 'gündüz';
+        } else {
+            return 'axÅŸam';
+        }
+    },
+    ordinalParse: /\d{1,2}-(ıncı|inci|nci|üncü|ncı|uncu)/,
+    ordinal : function (number) {
+        if (number === 0) {  // special case for zero
+            return number + '-ıncı';
+        }
+        var a = number % 10,
+            b = number % 100 - a,
+            c = number >= 100 ? 100 : null;
+        return number + (suffixes[a] || suffixes[b] || suffixes[c]);
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Belarusian [be]
+//! author : Dmitry Demidov : https://github.com/demidov91
+//! author: Praleska: http://praleska.pro/
+//! Author : Menelion Elensúle : https://github.com/Oire
+
+function plural(word, num) {
+    var forms = word.split('_');
+    return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]);
+}
+function relativeTimeWithPlural(number, withoutSuffix, key) {
+    var format = {
+        'mm': withoutSuffix ? 'хвіліна_хвіліны_хвілін' : 'хвіліну_хвіліны_хвілін',
+        'hh': withoutSuffix ? 'гадзіна_гадзіны_гадзін' : 'гадзіну_гадзіны_гадзін',
+        'dd': 'дзень_дні_дзён',
+        'MM': 'месяц_месяцы_месяцаў',
+        'yy': 'год_гады_гадоў'
+    };
+    if (key === 'm') {
+        return withoutSuffix ? 'хвіліна' : 'хвіліну';
+    }
+    else if (key === 'h') {
+        return withoutSuffix ? 'гадзіна' : 'гадзіну';
+    }
+    else {
+        return number + ' ' + plural(format[key], +number);
+    }
+}
+
+moment.defineLocale('be', {
+    months : {
+        format: 'студзеня_лютага_сакавіка_красавіка_траўня_чэрвеня_ліпеня_жніўня_верасня_кастрычніка_лістапада_снежня'.split('_'),
+        standalone: 'студзень_люты_сакавік_красавік_травень_чэрвень_ліпень_жнівень_верасень_кастрычнік_лістапад_снежань'.split('_')
+    },
+    monthsShort : 'студ_лют_сак_крас_трав_чэрв_ліп_жнів_вер_каст_ліст_снеж'.split('_'),
+    weekdays : {
+        format: 'нядзелю_панядзелак_аўторак_сераду_чацвер_пятніцу_суботу'.split('_'),
+        standalone: 'нядзеля_панядзелак_аўторак_серада_чацвер_пятніца_субота'.split('_'),
+        isFormat: /\[ ?[Вв] ?(?:мінулую|наступную)? ?\] ?dddd/
+    },
+    weekdaysShort : 'нд_пн_ат_ср_чц_пт_сб'.split('_'),
+    weekdaysMin : 'нд_пн_ат_ср_чц_пт_сб'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY г.',
+        LLL : 'D MMMM YYYY г., HH:mm',
+        LLLL : 'dddd, D MMMM YYYY г., HH:mm'
+    },
+    calendar : {
+        sameDay: '[Сёння ў] LT',
+        nextDay: '[Заўтра ў] LT',
+        lastDay: '[Учора ў] LT',
+        nextWeek: function () {
+            return '[У] dddd [ў] LT';
+        },
+        lastWeek: function () {
+            switch (this.day()) {
+                case 0:
+                case 3:
+                case 5:
+                case 6:
+                    return '[У мінулую] dddd [ў] LT';
+                case 1:
+                case 2:
+                case 4:
+                    return '[У мінулы] dddd [ў] LT';
+            }
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'праз %s',
+        past : '%s таму',
+        s : 'некалькі секунд',
+        m : relativeTimeWithPlural,
+        mm : relativeTimeWithPlural,
+        h : relativeTimeWithPlural,
+        hh : relativeTimeWithPlural,
+        d : 'дзень',
+        dd : relativeTimeWithPlural,
+        M : 'месяц',
+        MM : relativeTimeWithPlural,
+        y : 'год',
+        yy : relativeTimeWithPlural
+    },
+    meridiemParse: /ночы|раніцы|дня|вечара/,
+    isPM : function (input) {
+        return /^(дня|вечара)$/.test(input);
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'ночы';
+        } else if (hour < 12) {
+            return 'раніцы';
+        } else if (hour < 17) {
+            return 'дня';
+        } else {
+            return 'вечара';
+        }
+    },
+    ordinalParse: /\d{1,2}-(і|ы|га)/,
+    ordinal: function (number, period) {
+        switch (period) {
+            case 'M':
+            case 'd':
+            case 'DDD':
+            case 'w':
+            case 'W':
+                return (number % 10 === 2 || number % 10 === 3) && (number % 100 !== 12 && number % 100 !== 13) ? number + '-Ñ–' : number + '-Ñ‹';
+            case 'D':
+                return number + '-га';
+            default:
+                return number;
+        }
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+moment.defineLocale('bg-x', {
+    parentLocale: 'bg'
+});
+
+//! moment.js locale configuration
+//! locale : Bulgarian [bg]
+//! author : Krasen Borisov : https://github.com/kraz
+
+moment.defineLocale('bg', {
+    months : 'януари_февруари_март_април_май_юни_юли_август_септември_октомври_ноември_декември'.split('_'),
+    monthsShort : 'янр_фев_мар_апр_май_юни_юли_авг_сеп_окт_ное_дек'.split('_'),
+    weekdays : 'неделя_понеделник_вторник_сряда_четвъртък_петък_събота'.split('_'),
+    weekdaysShort : 'нед_пон_вто_сря_чет_пет_съб'.split('_'),
+    weekdaysMin : 'нд_пн_вт_ср_чт_пт_сб'.split('_'),
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'D.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY H:mm',
+        LLLL : 'dddd, D MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay : '[Днес в] LT',
+        nextDay : '[Утре в] LT',
+        nextWeek : 'dddd [в] LT',
+        lastDay : '[Вчера в] LT',
+        lastWeek : function () {
+            switch (this.day()) {
+                case 0:
+                case 3:
+                case 6:
+                    return '[В изминалата] dddd [в] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[В изминалия] dddd [в] LT';
+            }
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'след %s',
+        past : 'преди %s',
+        s : 'няколко секунди',
+        m : 'минута',
+        mm : '%d минути',
+        h : 'час',
+        hh : '%d часа',
+        d : 'ден',
+        dd : '%d дни',
+        M : 'месец',
+        MM : '%d месеца',
+        y : 'година',
+        yy : '%d години'
+    },
+    ordinalParse: /\d{1,2}-(ев|ен|ти|ви|ри|ми)/,
+    ordinal : function (number) {
+        var lastDigit = number % 10,
+            last2Digits = number % 100;
+        if (number === 0) {
+            return number + '-ев';
+        } else if (last2Digits === 0) {
+            return number + '-ен';
+        } else if (last2Digits > 10 && last2Digits < 20) {
+            return number + '-ти';
+        } else if (lastDigit === 1) {
+            return number + '-ви';
+        } else if (lastDigit === 2) {
+            return number + '-ри';
+        } else if (lastDigit === 7 || lastDigit === 8) {
+            return number + '-ми';
+        } else {
+            return number + '-ти';
+        }
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Bengali [bn]
+//! author : Kaushik Gandhi : https://github.com/kaushikgandhi
+
+var symbolMap$3 = {
+    '1': 'à§§',
+    '2': '২',
+    '3': 'à§©',
+    '4': '৪',
+    '5': 'à§«',
+    '6': '৬',
+    '7': 'à§­',
+    '8': 'à§®',
+    '9': '৯',
+    '0': '০'
+};
+var numberMap$2 = {
+    'à§§': '1',
+    '২': '2',
+    'à§©': '3',
+    '৪': '4',
+    'à§«': '5',
+    '৬': '6',
+    'à§­': '7',
+    'à§®': '8',
+    '৯': '9',
+    '০': '0'
+};
+
+moment.defineLocale('bn', {
+    months : 'জানুয়ারী_ফেব্রুয়ারি_মার্চ_এপ্রিল_মে_জুন_জুলাই_আগস্ট_সেপ্টেম্বর_অক্টোবর_নভেম্বর_ডিসেম্বর'.split('_'),
+    monthsShort : 'জানু_ফেব_মার্চ_এপ্র_মে_জুন_জুল_আগ_সেপ্ট_অক্টো_নভে_ডিসে'.split('_'),
+    weekdays : 'রবিবার_সোমবার_মঙ্গলবার_বুধবার_বৃহস্পতিবার_শুক্রবার_শনিবার'.split('_'),
+    weekdaysShort : 'রবি_সোম_মঙ্গল_বুধ_বৃহস্পতি_শুক্র_শনি'.split('_'),
+    weekdaysMin : 'রবি_সোম_মঙ্গ_বুধ_বৃহঃ_শুক্র_শনি'.split('_'),
+    longDateFormat : {
+        LT : 'A h:mm সময়',
+        LTS : 'A h:mm:ss সময়',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, A h:mm সময়',
+        LLLL : 'dddd, D MMMM YYYY, A h:mm সময়'
+    },
+    calendar : {
+        sameDay : '[আজ] LT',
+        nextDay : '[আগামীকাল] LT',
+        nextWeek : 'dddd, LT',
+        lastDay : '[গতকাল] LT',
+        lastWeek : '[গত] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s পরে',
+        past : '%s আগে',
+        s : 'কয়েক সেকেন্ড',
+        m : 'এক মিনিট',
+        mm : '%d মিনিট',
+        h : 'এক ঘন্টা',
+        hh : '%d ঘন্টা',
+        d : 'এক দিন',
+        dd : '%d দিন',
+        M : 'এক মাস',
+        MM : '%d মাস',
+        y : 'এক বছর',
+        yy : '%d বছর'
+    },
+    preparse: function (string) {
+        return string.replace(/[১২৩৪৫৬৭৮৯০]/g, function (match) {
+            return numberMap$2[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap$3[match];
+        });
+    },
+    meridiemParse: /রাত|সকাল|দুপুর|বিকাল|রাত/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if ((meridiem === 'রাত' && hour >= 4) ||
+                (meridiem === 'দুপুর' && hour < 5) ||
+                meridiem === 'বিকাল') {
+            return hour + 12;
+        } else {
+            return hour;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'রাত';
+        } else if (hour < 10) {
+            return 'সকাল';
+        } else if (hour < 17) {
+            return 'দুপুর';
+        } else if (hour < 20) {
+            return 'বিকাল';
+        } else {
+            return 'রাত';
+        }
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Tibetan [bo]
+//! author : Thupten N. Chakrishar : https://github.com/vajradog
+
+var symbolMap$4 = {
+    '1': '༡',
+    '2': '༢',
+    '3': '༣',
+    '4': '༤',
+    '5': '༥',
+    '6': '༦',
+    '7': '༧',
+    '8': '༨',
+    '9': '༩',
+    '0': '༠'
+};
+var numberMap$3 = {
+    '༡': '1',
+    '༢': '2',
+    '༣': '3',
+    '༤': '4',
+    '༥': '5',
+    '༦': '6',
+    '༧': '7',
+    '༨': '8',
+    '༩': '9',
+    '༠': '0'
+};
+
+moment.defineLocale('bo', {
+    months : 'ཟླ་བ་དང་པོ_ཟླ་བ་གཉིས་པ_ཟླ་བ་གསུམ་པ_ཟླ་བ་བཞི་པ_ཟླ་བ་ལྔ་པ_ཟླ་བ་དྲུག་པ_ཟླ་བ་བདུན་པ_ཟླ་བ་བརྒྱད་པ_ཟླ་བ་དགུ་པ_ཟླ་བ་བཅུ་པ_ཟླ་བ་བཅུ་གཅིག་པ_ཟླ་བ་བཅུ་གཉིས་པ'.split('_'),
+    monthsShort : 'ཟླ་བ་དང་པོ_ཟླ་བ་གཉིས་པ_ཟླ་བ་གསུམ་པ_ཟླ་བ་བཞི་པ_ཟླ་བ་ལྔ་པ_ཟླ་བ་དྲུག་པ_ཟླ་བ་བདུན་པ_ཟླ་བ་བརྒྱད་པ_ཟླ་བ་དགུ་པ_ཟླ་བ་བཅུ་པ_ཟླ་བ་བཅུ་གཅིག་པ_ཟླ་བ་བཅུ་གཉིས་པ'.split('_'),
+    weekdays : 'གཟའ་ཉི་མ་_གཟའ་ཟླ་བ་_གཟའ་མིག་དམར་_གཟའ་ལྷག་པ་_གཟའ་ཕུར་བུ_གཟའ་པ་སངས་_གཟའ་སྤེན་པ་'.split('_'),
+    weekdaysShort : 'ཉི་མ་_ཟླ་བ་_མིག་དམར་_ལྷག་པ་_ཕུར་བུ_པ་སངས་_སྤེན་པ་'.split('_'),
+    weekdaysMin : 'ཉི་མ་_ཟླ་བ་_མིག་དམར་_ལྷག་པ་_ཕུར་བུ_པ་སངས་_སྤེན་པ་'.split('_'),
+    longDateFormat : {
+        LT : 'A h:mm',
+        LTS : 'A h:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, A h:mm',
+        LLLL : 'dddd, D MMMM YYYY, A h:mm'
+    },
+    calendar : {
+        sameDay : '[དི་རིང] LT',
+        nextDay : '[སང་ཉིན] LT',
+        nextWeek : '[བདུན་ཕྲག་རྗེས་མ], LT',
+        lastDay : '[ཁ་སང] LT',
+        lastWeek : '[བདུན་ཕྲག་མཐའ་མ] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s ལ་',
+        past : '%s སྔན་ལ',
+        s : 'ལམ་སང',
+        m : 'སྐར་མ་གཅིག',
+        mm : '%d སྐར་མ',
+        h : 'ཆུ་ཚོད་གཅིག',
+        hh : '%d ཆུ་ཚོད',
+        d : 'ཉིན་གཅིག',
+        dd : '%d ཉིན་',
+        M : 'ཟླ་བ་གཅིག',
+        MM : '%d ཟླ་བ',
+        y : 'ལོ་གཅིག',
+        yy : '%d ལོ'
+    },
+    preparse: function (string) {
+        return string.replace(/[༡༢༣༤༥༦༧༨༩༠]/g, function (match) {
+            return numberMap$3[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap$4[match];
+        });
+    },
+    meridiemParse: /མཚན་མོ|ཞོགས་ཀས|ཉིན་གུང|དགོང་དག|མཚན་མོ/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if ((meridiem === 'མཚན་མོ' && hour >= 4) ||
+                (meridiem === 'ཉིན་གུང' && hour < 5) ||
+                meridiem === 'དགོང་དག') {
+            return hour + 12;
+        } else {
+            return hour;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'མཚན་མོ';
+        } else if (hour < 10) {
+            return 'ཞོགས་ཀས';
+        } else if (hour < 17) {
+            return 'ཉིན་གུང';
+        } else if (hour < 20) {
+            return 'དགོང་དག';
+        } else {
+            return 'མཚན་མོ';
+        }
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Breton [br]
+//! author : Jean-Baptiste Le Duigou : https://github.com/jbleduigou
+
+function relativeTimeWithMutation(number, withoutSuffix, key) {
+    var format = {
+        'mm': 'munutenn',
+        'MM': 'miz',
+        'dd': 'devezh'
+    };
+    return number + ' ' + mutation(format[key], number);
+}
+function specialMutationForYears(number) {
+    switch (lastNumber(number)) {
+        case 1:
+        case 3:
+        case 4:
+        case 5:
+        case 9:
+            return number + ' bloaz';
+        default:
+            return number + ' vloaz';
+    }
+}
+function lastNumber(number) {
+    if (number > 9) {
+        return lastNumber(number % 10);
+    }
+    return number;
+}
+function mutation(text, number) {
+    if (number === 2) {
+        return softMutation(text);
+    }
+    return text;
+}
+function softMutation(text) {
+    var mutationTable = {
+        'm': 'v',
+        'b': 'v',
+        'd': 'z'
+    };
+    if (mutationTable[text.charAt(0)] === undefined) {
+        return text;
+    }
+    return mutationTable[text.charAt(0)] + text.substring(1);
+}
+
+moment.defineLocale('br', {
+    months : 'Genver_C\'hwevrer_Meurzh_Ebrel_Mae_Mezheven_Gouere_Eost_Gwengolo_Here_Du_Kerzu'.split('_'),
+    monthsShort : 'Gen_C\'hwe_Meu_Ebr_Mae_Eve_Gou_Eos_Gwe_Her_Du_Ker'.split('_'),
+    weekdays : 'Sul_Lun_Meurzh_Merc\'her_Yaou_Gwener_Sadorn'.split('_'),
+    weekdaysShort : 'Sul_Lun_Meu_Mer_Yao_Gwe_Sad'.split('_'),
+    weekdaysMin : 'Su_Lu_Me_Mer_Ya_Gw_Sa'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'h[e]mm A',
+        LTS : 'h[e]mm:ss A',
+        L : 'DD/MM/YYYY',
+        LL : 'D [a viz] MMMM YYYY',
+        LLL : 'D [a viz] MMMM YYYY h[e]mm A',
+        LLLL : 'dddd, D [a viz] MMMM YYYY h[e]mm A'
+    },
+    calendar : {
+        sameDay : '[Hiziv da] LT',
+        nextDay : '[Warc\'hoazh da] LT',
+        nextWeek : 'dddd [da] LT',
+        lastDay : '[Dec\'h da] LT',
+        lastWeek : 'dddd [paset da] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'a-benn %s',
+        past : '%s \'zo',
+        s : 'un nebeud segondennoù',
+        m : 'ur vunutenn',
+        mm : relativeTimeWithMutation,
+        h : 'un eur',
+        hh : '%d eur',
+        d : 'un devezh',
+        dd : relativeTimeWithMutation,
+        M : 'ur miz',
+        MM : relativeTimeWithMutation,
+        y : 'ur bloaz',
+        yy : specialMutationForYears
+    },
+    ordinalParse: /\d{1,2}(añ|vet)/,
+    ordinal : function (number) {
+        var output = (number === 1) ? 'añ' : 'vet';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Bosnian [bs]
+//! author : Nedim Cholich : https://github.com/frontyard
+//! based on (hr) translation by Bojan Marković
+
+function translate(number, withoutSuffix, key) {
+    var result = number + ' ';
+    switch (key) {
+        case 'm':
+            return withoutSuffix ? 'jedna minuta' : 'jedne minute';
+        case 'mm':
+            if (number === 1) {
+                result += 'minuta';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'minute';
+            } else {
+                result += 'minuta';
+            }
+            return result;
+        case 'h':
+            return withoutSuffix ? 'jedan sat' : 'jednog sata';
+        case 'hh':
+            if (number === 1) {
+                result += 'sat';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'sata';
+            } else {
+                result += 'sati';
+            }
+            return result;
+        case 'dd':
+            if (number === 1) {
+                result += 'dan';
+            } else {
+                result += 'dana';
+            }
+            return result;
+        case 'MM':
+            if (number === 1) {
+                result += 'mjesec';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'mjeseca';
+            } else {
+                result += 'mjeseci';
+            }
+            return result;
+        case 'yy':
+            if (number === 1) {
+                result += 'godina';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'godine';
+            } else {
+                result += 'godina';
+            }
+            return result;
+    }
+}
+
+moment.defineLocale('bs', {
+    months : 'januar_februar_mart_april_maj_juni_juli_august_septembar_oktobar_novembar_decembar'.split('_'),
+    monthsShort : 'jan._feb._mar._apr._maj._jun._jul._aug._sep._okt._nov._dec.'.split('_'),
+    monthsParseExact: true,
+    weekdays : 'nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota'.split('_'),
+    weekdaysShort : 'ned._pon._uto._sri._čet._pet._sub.'.split('_'),
+    weekdaysMin : 'ne_po_ut_sr_če_pe_su'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY H:mm',
+        LLLL : 'dddd, D. MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay  : '[danas u] LT',
+        nextDay  : '[sutra u] LT',
+        nextWeek : function () {
+            switch (this.day()) {
+                case 0:
+                    return '[u] [nedjelju] [u] LT';
+                case 3:
+                    return '[u] [srijedu] [u] LT';
+                case 6:
+                    return '[u] [subotu] [u] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[u] dddd [u] LT';
+            }
+        },
+        lastDay  : '[jučer u] LT',
+        lastWeek : function () {
+            switch (this.day()) {
+                case 0:
+                case 3:
+                    return '[prošlu] dddd [u] LT';
+                case 6:
+                    return '[prošle] [subote] [u] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[prošli] dddd [u] LT';
+            }
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'za %s',
+        past   : 'prije %s',
+        s      : 'par sekundi',
+        m      : translate,
+        mm     : translate,
+        h      : translate,
+        hh     : translate,
+        d      : 'dan',
+        dd     : translate,
+        M      : 'mjesec',
+        MM     : translate,
+        y      : 'godinu',
+        yy     : translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Catalan [ca]
+//! author : Juan G. Hurtado : https://github.com/juanghurtado
+
+moment.defineLocale('ca', {
+    months : 'gener_febrer_març_abril_maig_juny_juliol_agost_setembre_octubre_novembre_desembre'.split('_'),
+    monthsShort : 'gen._febr._mar._abr._mai._jun._jul._ag._set._oct._nov._des.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'diumenge_dilluns_dimarts_dimecres_dijous_divendres_dissabte'.split('_'),
+    weekdaysShort : 'dg._dl._dt._dc._dj._dv._ds.'.split('_'),
+    weekdaysMin : 'Dg_Dl_Dt_Dc_Dj_Dv_Ds'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY H:mm',
+        LLLL : 'dddd D MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay : function () {
+            return '[avui a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
+        },
+        nextDay : function () {
+            return '[demà a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
+        },
+        nextWeek : function () {
+            return 'dddd [a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
+        },
+        lastDay : function () {
+            return '[ahir a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
+        },
+        lastWeek : function () {
+            return '[el] dddd [passat a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'en %s',
+        past : 'fa %s',
+        s : 'uns segons',
+        m : 'un minut',
+        mm : '%d minuts',
+        h : 'una hora',
+        hh : '%d hores',
+        d : 'un dia',
+        dd : '%d dies',
+        M : 'un mes',
+        MM : '%d mesos',
+        y : 'un any',
+        yy : '%d anys'
+    },
+    ordinalParse: /\d{1,2}(r|n|t|è|a)/,
+    ordinal : function (number, period) {
+        var output = (number === 1) ? 'r' :
+            (number === 2) ? 'n' :
+            (number === 3) ? 'r' :
+            (number === 4) ? 't' : 'è';
+        if (period === 'w' || period === 'W') {
+            output = 'a';
+        }
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Czech [cs]
+//! author : petrbela : https://github.com/petrbela
+
+var months$2 = 'leden_únor_březen_duben_květen_červen_červenec_srpen_září_říjen_listopad_prosinec'.split('_');
+var monthsShort = 'led_úno_bře_dub_kvě_čvn_čvc_srp_zář_říj_lis_pro'.split('_');
+function plural$1(n) {
+    return (n > 1) && (n < 5) && (~~(n / 10) !== 1);
+}
+function translate$1(number, withoutSuffix, key, isFuture) {
+    var result = number + ' ';
+    switch (key) {
+        case 's':  // a few seconds / in a few seconds / a few seconds ago
+            return (withoutSuffix || isFuture) ? 'pár sekund' : 'pár sekundami';
+        case 'm':  // a minute / in a minute / a minute ago
+            return withoutSuffix ? 'minuta' : (isFuture ? 'minutu' : 'minutou');
+        case 'mm': // 9 minutes / in 9 minutes / 9 minutes ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural$1(number) ? 'minuty' : 'minut');
+            } else {
+                return result + 'minutami';
+            }
+            break;
+        case 'h':  // an hour / in an hour / an hour ago
+            return withoutSuffix ? 'hodina' : (isFuture ? 'hodinu' : 'hodinou');
+        case 'hh': // 9 hours / in 9 hours / 9 hours ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural$1(number) ? 'hodiny' : 'hodin');
+            } else {
+                return result + 'hodinami';
+            }
+            break;
+        case 'd':  // a day / in a day / a day ago
+            return (withoutSuffix || isFuture) ? 'den' : 'dnem';
+        case 'dd': // 9 days / in 9 days / 9 days ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural$1(number) ? 'dny' : 'dní');
+            } else {
+                return result + 'dny';
+            }
+            break;
+        case 'M':  // a month / in a month / a month ago
+            return (withoutSuffix || isFuture) ? 'měsíc' : 'měsícem';
+        case 'MM': // 9 months / in 9 months / 9 months ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural$1(number) ? 'měsíce' : 'měsíců');
+            } else {
+                return result + 'měsíci';
+            }
+            break;
+        case 'y':  // a year / in a year / a year ago
+            return (withoutSuffix || isFuture) ? 'rok' : 'rokem';
+        case 'yy': // 9 years / in 9 years / 9 years ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural$1(number) ? 'roky' : 'let');
+            } else {
+                return result + 'lety';
+            }
+            break;
+    }
+}
+
+moment.defineLocale('cs', {
+    months : months$2,
+    monthsShort : monthsShort,
+    monthsParse : (function (months, monthsShort) {
+        var i, _monthsParse = [];
+        for (i = 0; i < 12; i++) {
+            // use custom parser to solve problem with July (červenec)
+            _monthsParse[i] = new RegExp('^' + months[i] + '$|^' + monthsShort[i] + '$', 'i');
+        }
+        return _monthsParse;
+    }(months$2, monthsShort)),
+    shortMonthsParse : (function (monthsShort) {
+        var i, _shortMonthsParse = [];
+        for (i = 0; i < 12; i++) {
+            _shortMonthsParse[i] = new RegExp('^' + monthsShort[i] + '$', 'i');
+        }
+        return _shortMonthsParse;
+    }(monthsShort)),
+    longMonthsParse : (function (months) {
+        var i, _longMonthsParse = [];
+        for (i = 0; i < 12; i++) {
+            _longMonthsParse[i] = new RegExp('^' + months[i] + '$', 'i');
+        }
+        return _longMonthsParse;
+    }(months$2)),
+    weekdays : 'neděle_pondělí_úterý_středa_čtvrtek_pátek_sobota'.split('_'),
+    weekdaysShort : 'ne_po_út_st_čt_pá_so'.split('_'),
+    weekdaysMin : 'ne_po_út_st_čt_pá_so'.split('_'),
+    longDateFormat : {
+        LT: 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY H:mm',
+        LLLL : 'dddd D. MMMM YYYY H:mm',
+        l : 'D. M. YYYY'
+    },
+    calendar : {
+        sameDay: '[dnes v] LT',
+        nextDay: '[zítra v] LT',
+        nextWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[v neděli v] LT';
+                case 1:
+                case 2:
+                    return '[v] dddd [v] LT';
+                case 3:
+                    return '[ve středu v] LT';
+                case 4:
+                    return '[ve čtvrtek v] LT';
+                case 5:
+                    return '[v pátek v] LT';
+                case 6:
+                    return '[v sobotu v] LT';
+            }
+        },
+        lastDay: '[včera v] LT',
+        lastWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[minulou neděli v] LT';
+                case 1:
+                case 2:
+                    return '[minulé] dddd [v] LT';
+                case 3:
+                    return '[minulou středu v] LT';
+                case 4:
+                case 5:
+                    return '[minulý] dddd [v] LT';
+                case 6:
+                    return '[minulou sobotu v] LT';
+            }
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'za %s',
+        past : 'před %s',
+        s : translate$1,
+        m : translate$1,
+        mm : translate$1,
+        h : translate$1,
+        hh : translate$1,
+        d : translate$1,
+        dd : translate$1,
+        M : translate$1,
+        MM : translate$1,
+        y : translate$1,
+        yy : translate$1
+    },
+    ordinalParse : /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Chuvash [cv]
+//! author : Anatoly Mironov : https://github.com/mirontoli
+
+moment.defineLocale('cv', {
+    months : 'кӑрлач_нарӑс_пуш_ака_май_ҫӗртме_утӑ_ҫурла_авӑн_юпа_чӳк_раштав'.split('_'),
+    monthsShort : 'кӑр_нар_пуш_ака_май_ҫӗр_утӑ_ҫур_авн_юпа_чӳк_раш'.split('_'),
+    weekdays : 'вырсарникун_тунтикун_ытларикун_юнкун_кӗҫнерникун_эрнекун_шӑматкун'.split('_'),
+    weekdaysShort : 'выр_тун_ытл_юн_кӗҫ_эрн_шӑм'.split('_'),
+    weekdaysMin : 'вр_тн_ыт_юн_кҫ_эр_шм'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD-MM-YYYY',
+        LL : 'YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ]',
+        LLL : 'YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm',
+        LLLL : 'dddd, YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm'
+    },
+    calendar : {
+        sameDay: '[Паян] LT [сехетре]',
+        nextDay: '[Ыран] LT [сехетре]',
+        lastDay: '[Ӗнер] LT [сехетре]',
+        nextWeek: '[Ҫитес] dddd LT [сехетре]',
+        lastWeek: '[Иртнӗ] dddd LT [сехетре]',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : function (output) {
+            var affix = /сехет$/i.exec(output) ? 'рен' : /ҫул$/i.exec(output) ? 'тан' : 'ран';
+            return output + affix;
+        },
+        past : '%s каялла',
+        s : 'пӗр-ик ҫеккунт',
+        m : 'пӗр минут',
+        mm : '%d минут',
+        h : 'пӗр сехет',
+        hh : '%d сехет',
+        d : 'пӗр кун',
+        dd : '%d кун',
+        M : 'пӗр уйӑх',
+        MM : '%d уйӑх',
+        y : 'пӗр ҫул',
+        yy : '%d ҫул'
+    },
+    ordinalParse: /\d{1,2}-мӗш/,
+    ordinal : '%d-мӗш',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Welsh [cy]
+//! author : Robert Allen : https://github.com/robgallen
+//! author : https://github.com/ryangreaves
+
+moment.defineLocale('cy', {
+    months: 'Ionawr_Chwefror_Mawrth_Ebrill_Mai_Mehefin_Gorffennaf_Awst_Medi_Hydref_Tachwedd_Rhagfyr'.split('_'),
+    monthsShort: 'Ion_Chwe_Maw_Ebr_Mai_Meh_Gor_Aws_Med_Hyd_Tach_Rhag'.split('_'),
+    weekdays: 'Dydd Sul_Dydd Llun_Dydd Mawrth_Dydd Mercher_Dydd Iau_Dydd Gwener_Dydd Sadwrn'.split('_'),
+    weekdaysShort: 'Sul_Llun_Maw_Mer_Iau_Gwe_Sad'.split('_'),
+    weekdaysMin: 'Su_Ll_Ma_Me_Ia_Gw_Sa'.split('_'),
+    weekdaysParseExact : true,
+    // time formats are the same as en-gb
+    longDateFormat: {
+        LT: 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L: 'DD/MM/YYYY',
+        LL: 'D MMMM YYYY',
+        LLL: 'D MMMM YYYY HH:mm',
+        LLLL: 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar: {
+        sameDay: '[Heddiw am] LT',
+        nextDay: '[Yfory am] LT',
+        nextWeek: 'dddd [am] LT',
+        lastDay: '[Ddoe am] LT',
+        lastWeek: 'dddd [diwethaf am] LT',
+        sameElse: 'L'
+    },
+    relativeTime: {
+        future: 'mewn %s',
+        past: '%s yn ôl',
+        s: 'ychydig eiliadau',
+        m: 'munud',
+        mm: '%d munud',
+        h: 'awr',
+        hh: '%d awr',
+        d: 'diwrnod',
+        dd: '%d diwrnod',
+        M: 'mis',
+        MM: '%d mis',
+        y: 'blwyddyn',
+        yy: '%d flynedd'
+    },
+    ordinalParse: /\d{1,2}(fed|ain|af|il|ydd|ed|eg)/,
+    // traditional ordinal numbers above 31 are not commonly used in colloquial Welsh
+    ordinal: function (number) {
+        var b = number,
+            output = '',
+            lookup = [
+                '', 'af', 'il', 'ydd', 'ydd', 'ed', 'ed', 'ed', 'fed', 'fed', 'fed', // 1af to 10fed
+                'eg', 'fed', 'eg', 'eg', 'fed', 'eg', 'eg', 'fed', 'eg', 'fed' // 11eg to 20fed
+            ];
+        if (b > 20) {
+            if (b === 40 || b === 50 || b === 60 || b === 80 || b === 100) {
+                output = 'fed'; // not 30ain, 70ain or 90ain
+            } else {
+                output = 'ain';
+            }
+        } else if (b > 0) {
+            output = lookup[b];
+        }
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Danish [da]
+//! author : Ulrik Nielsen : https://github.com/mrbase
+
+moment.defineLocale('da', {
+    months : 'januar_februar_marts_april_maj_juni_juli_august_september_oktober_november_december'.split('_'),
+    monthsShort : 'jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec'.split('_'),
+    weekdays : 'søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag'.split('_'),
+    weekdaysShort : 'søn_man_tir_ons_tor_fre_lør'.split('_'),
+    weekdaysMin : 'sø_ma_ti_on_to_fr_lø'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY HH:mm',
+        LLLL : 'dddd [d.] D. MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[I dag kl.] LT',
+        nextDay : '[I morgen kl.] LT',
+        nextWeek : 'dddd [kl.] LT',
+        lastDay : '[I går kl.] LT',
+        lastWeek : '[sidste] dddd [kl] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'om %s',
+        past : '%s siden',
+        s : 'få sekunder',
+        m : 'et minut',
+        mm : '%d minutter',
+        h : 'en time',
+        hh : '%d timer',
+        d : 'en dag',
+        dd : '%d dage',
+        M : 'en måned',
+        MM : '%d måneder',
+        y : 'et år',
+        yy : '%d år'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : German (Austria) [de-at]
+//! author : lluchs : https://github.com/lluchs
+//! author: Menelion Elensúle: https://github.com/Oire
+//! author : Martin Groller : https://github.com/MadMG
+//! author : Mikolaj Dadela : https://github.com/mik01aj
+
+function processRelativeTime(number, withoutSuffix, key, isFuture) {
+    var format = {
+        'm': ['eine Minute', 'einer Minute'],
+        'h': ['eine Stunde', 'einer Stunde'],
+        'd': ['ein Tag', 'einem Tag'],
+        'dd': [number + ' Tage', number + ' Tagen'],
+        'M': ['ein Monat', 'einem Monat'],
+        'MM': [number + ' Monate', number + ' Monaten'],
+        'y': ['ein Jahr', 'einem Jahr'],
+        'yy': [number + ' Jahre', number + ' Jahren']
+    };
+    return withoutSuffix ? format[key][0] : format[key][1];
+}
+
+moment.defineLocale('de-at', {
+    months : 'Jänner_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember'.split('_'),
+    monthsShort : 'Jän._Febr._Mrz._Apr._Mai_Jun._Jul._Aug._Sept._Okt._Nov._Dez.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag'.split('_'),
+    weekdaysShort : 'So._Mo._Di._Mi._Do._Fr._Sa.'.split('_'),
+    weekdaysMin : 'So_Mo_Di_Mi_Do_Fr_Sa'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT: 'HH:mm',
+        LTS: 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY HH:mm',
+        LLLL : 'dddd, D. MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[heute um] LT [Uhr]',
+        sameElse: 'L',
+        nextDay: '[morgen um] LT [Uhr]',
+        nextWeek: 'dddd [um] LT [Uhr]',
+        lastDay: '[gestern um] LT [Uhr]',
+        lastWeek: '[letzten] dddd [um] LT [Uhr]'
+    },
+    relativeTime : {
+        future : 'in %s',
+        past : 'vor %s',
+        s : 'ein paar Sekunden',
+        m : processRelativeTime,
+        mm : '%d Minuten',
+        h : processRelativeTime,
+        hh : '%d Stunden',
+        d : processRelativeTime,
+        dd : processRelativeTime,
+        M : processRelativeTime,
+        MM : processRelativeTime,
+        y : processRelativeTime,
+        yy : processRelativeTime
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : German [de]
+//! author : lluchs : https://github.com/lluchs
+//! author: Menelion Elensúle: https://github.com/Oire
+//! author : Mikolaj Dadela : https://github.com/mik01aj
+
+function processRelativeTime$1(number, withoutSuffix, key, isFuture) {
+    var format = {
+        'm': ['eine Minute', 'einer Minute'],
+        'h': ['eine Stunde', 'einer Stunde'],
+        'd': ['ein Tag', 'einem Tag'],
+        'dd': [number + ' Tage', number + ' Tagen'],
+        'M': ['ein Monat', 'einem Monat'],
+        'MM': [number + ' Monate', number + ' Monaten'],
+        'y': ['ein Jahr', 'einem Jahr'],
+        'yy': [number + ' Jahre', number + ' Jahren']
+    };
+    return withoutSuffix ? format[key][0] : format[key][1];
+}
+
+moment.defineLocale('de', {
+    months : 'Januar_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember'.split('_'),
+    monthsShort : 'Jan._Febr._Mrz._Apr._Mai_Jun._Jul._Aug._Sept._Okt._Nov._Dez.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag'.split('_'),
+    weekdaysShort : 'So._Mo._Di._Mi._Do._Fr._Sa.'.split('_'),
+    weekdaysMin : 'So_Mo_Di_Mi_Do_Fr_Sa'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT: 'HH:mm',
+        LTS: 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY HH:mm',
+        LLLL : 'dddd, D. MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[heute um] LT [Uhr]',
+        sameElse: 'L',
+        nextDay: '[morgen um] LT [Uhr]',
+        nextWeek: 'dddd [um] LT [Uhr]',
+        lastDay: '[gestern um] LT [Uhr]',
+        lastWeek: '[letzten] dddd [um] LT [Uhr]'
+    },
+    relativeTime : {
+        future : 'in %s',
+        past : 'vor %s',
+        s : 'ein paar Sekunden',
+        m : processRelativeTime$1,
+        mm : '%d Minuten',
+        h : processRelativeTime$1,
+        hh : '%d Stunden',
+        d : processRelativeTime$1,
+        dd : processRelativeTime$1,
+        M : processRelativeTime$1,
+        MM : processRelativeTime$1,
+        y : processRelativeTime$1,
+        yy : processRelativeTime$1
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Maldivian [dv]
+//! author : Jawish Hameed : https://github.com/jawish
+
+var months$3 = [
+    'Þ–Þ¬Þ‚ÞªÞ‡Þ¦ÞƒÞ©',
+    'ÞŠÞ¬Þ„Þ°ÞƒÞªÞ‡Þ¦ÞƒÞ©',
+    'Þ‰Þ§ÞƒÞ¨Þ—Þª',
+    'އޭޕްރީލު',
+    'Þ‰Þ­',
+    'Þ–Þ«Þ‚Þ°',
+    'ޖުލައި',
+    'އޯގަސްޓު',
+    'ސެޕްޓެމްބަރު',
+    'Þ‡Þ®Þ†Þ°Þ“Þ¯Þ„Þ¦ÞƒÞª',
+    'Þ‚Þ®ÞˆÞ¬Þ‰Þ°Þ„Þ¦ÞƒÞª',
+    'ޑިސެމްބަރު'
+];
+var weekdays = [
+    'އާދިއްތަ',
+    'Þ€Þ¯Þ‰Þ¦',
+    'Þ‡Þ¦Þ‚Þ°ÞŽÞ§ÞƒÞ¦',
+    'Þ„ÞªÞ‹Þ¦',
+    'ބުރާސްފަތި',
+    'Þ€ÞªÞ†ÞªÞƒÞª',
+    'Þ€Þ®Þ‚Þ¨Þ€Þ¨ÞƒÞª'
+];
+
+moment.defineLocale('dv', {
+    months : months$3,
+    monthsShort : months$3,
+    weekdays : weekdays,
+    weekdaysShort : weekdays,
+    weekdaysMin : 'Þ‡Þ§Þ‹Þ¨_Þ€Þ¯Þ‰Þ¦_Þ‡Þ¦Þ‚Þ°_Þ„ÞªÞ‹Þ¦_Þ„ÞªÞƒÞ§_Þ€ÞªÞ†Þª_Þ€Þ®Þ‚Þ¨'.split('_'),
+    longDateFormat : {
+
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'D/M/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    meridiemParse: /Þ‰Þ†|Þ‰ÞŠ/,
+    isPM : function (input) {
+        return 'Þ‰ÞŠ' === input;
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return 'Þ‰Þ†';
+        } else {
+            return 'Þ‰ÞŠ';
+        }
+    },
+    calendar : {
+        sameDay : '[Þ‰Þ¨Þ‡Þ¦Þ‹Þª] LT',
+        nextDay : '[Þ‰Þ§Þ‹Þ¦Þ‰Þ§] LT',
+        nextWeek : 'dddd LT',
+        lastDay : '[Þ‡Þ¨Þ‡Þ°Þ”Þ¬] LT',
+        lastWeek : '[ފާއިތުވި] dddd LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'ތެރޭގައި %s',
+        past : 'Þ†ÞªÞƒÞ¨Þ‚Þ° %s',
+        s : 'ސިކުންތުކޮޅެއް',
+        m : 'Þ‰Þ¨Þ‚Þ¨Þ“Þ¬Þ‡Þ°',
+        mm : 'Þ‰Þ¨Þ‚Þ¨Þ“Þª %d',
+        h : 'ÞŽÞ¦Þ‘Þ¨Þ‡Þ¨ÞƒÞ¬Þ‡Þ°',
+        hh : 'ÞŽÞ¦Þ‘Þ¨Þ‡Þ¨ÞƒÞª %d',
+        d : 'Þ‹ÞªÞˆÞ¦Þ€Þ¬Þ‡Þ°',
+        dd : 'ދުވަސް %d',
+        M : 'Þ‰Þ¦Þ€Þ¬Þ‡Þ°',
+        MM : 'މަސް %d',
+        y : 'Þ‡Þ¦Þ€Þ¦ÞƒÞ¬Þ‡Þ°',
+        yy : 'Þ‡Þ¦Þ€Þ¦ÞƒÞª %d'
+    },
+    preparse: function (string) {
+        return string.replace(/،/g, ',');
+    },
+    postformat: function (string) {
+        return string.replace(/,/g, '،');
+    },
+    week : {
+        dow : 7,  // Sunday is the first day of the week.
+        doy : 12  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+function isFunction(input) {
+    return input instanceof Function || Object.prototype.toString.call(input) === '[object Function]';
+}
+
+//! moment.js locale configuration
+//! locale : Greek [el]
+//! author : Aggelos Karalias : https://github.com/mehiel
+
+moment.defineLocale('el', {
+    monthsNominativeEl : 'Ιανουάριος_Φεβρουάριος_Μάρτιος_Απρίλιος_Μάιος_Ιούνιος_Ιούλιος_Αύγουστος_Σεπτέμβριος_Οκτώβριος_Νοέμβριος_Δεκέμβριος'.split('_'),
+    monthsGenitiveEl : 'Ιανουαρίου_Φεβρουαρίου_Μαρτίου_Απριλίου_Μαΐου_Ιουνίου_Ιουλίου_Αυγούστου_Σεπτεμβρίου_Οκτωβρίου_Νοεμβρίου_Δεκεμβρίου'.split('_'),
+    months : function (momentToFormat, format) {
+        if (/D/.test(format.substring(0, format.indexOf('MMMM')))) { // if there is a day number before 'MMMM'
+            return this._monthsGenitiveEl[momentToFormat.month()];
+        } else {
+            return this._monthsNominativeEl[momentToFormat.month()];
+        }
+    },
+    monthsShort : 'Ιαν_Φεβ_Μαρ_Απρ_Μαϊ_Ιουν_Ιουλ_Αυγ_Σεπ_Οκτ_Νοε_Δεκ'.split('_'),
+    weekdays : 'Κυριακή_Δευτέρα_Τρίτη_Τετάρτη_Πέμπτη_Παρασκευή_Σάββατο'.split('_'),
+    weekdaysShort : 'Κυρ_Δευ_Τρι_Τετ_Πεμ_Παρ_Σαβ'.split('_'),
+    weekdaysMin : 'Κυ_Δε_Τρ_Τε_Πε_Πα_Σα'.split('_'),
+    meridiem : function (hours, minutes, isLower) {
+        if (hours > 11) {
+            return isLower ? 'μμ' : 'ΜΜ';
+        } else {
+            return isLower ? 'πμ' : 'ΠΜ';
+        }
+    },
+    isPM : function (input) {
+        return ((input + '').toLowerCase()[0] === 'μ');
+    },
+    meridiemParse : /[ΠΜ]\.?Μ?\.?/i,
+    longDateFormat : {
+        LT : 'h:mm A',
+        LTS : 'h:mm:ss A',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY h:mm A',
+        LLLL : 'dddd, D MMMM YYYY h:mm A'
+    },
+    calendarEl : {
+        sameDay : '[Σήμερα {}] LT',
+        nextDay : '[Αύριο {}] LT',
+        nextWeek : 'dddd [{}] LT',
+        lastDay : '[Χθες {}] LT',
+        lastWeek : function () {
+            switch (this.day()) {
+                case 6:
+                    return '[το προηγούμενο] dddd [{}] LT';
+                default:
+                    return '[την προηγούμενη] dddd [{}] LT';
+            }
+        },
+        sameElse : 'L'
+    },
+    calendar : function (key, mom) {
+        var output = this._calendarEl[key],
+            hours = mom && mom.hours();
+        if (isFunction(output)) {
+            output = output.apply(mom);
+        }
+        return output.replace('{}', (hours % 12 === 1 ? 'στη' : 'στις'));
+    },
+    relativeTime : {
+        future : 'σε %s',
+        past : '%s πριν',
+        s : 'λίγα δευτερόλεπτα',
+        m : 'ένα λεπτό',
+        mm : '%d λεπτά',
+        h : 'μία ώρα',
+        hh : '%d ώρες',
+        d : 'μία μέρα',
+        dd : '%d μέρες',
+        M : 'ένας μήνας',
+        MM : '%d μήνες',
+        y : 'ένας χρόνος',
+        yy : '%d χρόνια'
+    },
+    ordinalParse: /\d{1,2}η/,
+    ordinal: '%dη',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : English (Australia) [en-au]
+//! author : Jared Morse : https://github.com/jarcoal
+
+moment.defineLocale('en-au', {
+    months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),
+    monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),
+    weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
+    weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
+    weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'h:mm A',
+        LTS : 'h:mm:ss A',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY h:mm A',
+        LLLL : 'dddd, D MMMM YYYY h:mm A'
+    },
+    calendar : {
+        sameDay : '[Today at] LT',
+        nextDay : '[Tomorrow at] LT',
+        nextWeek : 'dddd [at] LT',
+        lastDay : '[Yesterday at] LT',
+        lastWeek : '[Last] dddd [at] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'in %s',
+        past : '%s ago',
+        s : 'a few seconds',
+        m : 'a minute',
+        mm : '%d minutes',
+        h : 'an hour',
+        hh : '%d hours',
+        d : 'a day',
+        dd : '%d days',
+        M : 'a month',
+        MM : '%d months',
+        y : 'a year',
+        yy : '%d years'
+    },
+    ordinalParse: /\d{1,2}(st|nd|rd|th)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : English (Canada) [en-ca]
+//! author : Jonathan Abourbih : https://github.com/jonbca
+
+moment.defineLocale('en-ca', {
+    months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),
+    monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),
+    weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
+    weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
+    weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'h:mm A',
+        LTS : 'h:mm:ss A',
+        L : 'YYYY-MM-DD',
+        LL : 'MMMM D, YYYY',
+        LLL : 'MMMM D, YYYY h:mm A',
+        LLLL : 'dddd, MMMM D, YYYY h:mm A'
+    },
+    calendar : {
+        sameDay : '[Today at] LT',
+        nextDay : '[Tomorrow at] LT',
+        nextWeek : 'dddd [at] LT',
+        lastDay : '[Yesterday at] LT',
+        lastWeek : '[Last] dddd [at] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'in %s',
+        past : '%s ago',
+        s : 'a few seconds',
+        m : 'a minute',
+        mm : '%d minutes',
+        h : 'an hour',
+        hh : '%d hours',
+        d : 'a day',
+        dd : '%d days',
+        M : 'a month',
+        MM : '%d months',
+        y : 'a year',
+        yy : '%d years'
+    },
+    ordinalParse: /\d{1,2}(st|nd|rd|th)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    }
+});
+
+//! moment.js locale configuration
+//! locale : English (United Kingdom) [en-gb]
+//! author : Chris Gedrim : https://github.com/chrisgedrim
+
+moment.defineLocale('en-gb', {
+    months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),
+    monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),
+    weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
+    weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
+    weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[Today at] LT',
+        nextDay : '[Tomorrow at] LT',
+        nextWeek : 'dddd [at] LT',
+        lastDay : '[Yesterday at] LT',
+        lastWeek : '[Last] dddd [at] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'in %s',
+        past : '%s ago',
+        s : 'a few seconds',
+        m : 'a minute',
+        mm : '%d minutes',
+        h : 'an hour',
+        hh : '%d hours',
+        d : 'a day',
+        dd : '%d days',
+        M : 'a month',
+        MM : '%d months',
+        y : 'a year',
+        yy : '%d years'
+    },
+    ordinalParse: /\d{1,2}(st|nd|rd|th)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : English (Ireland) [en-ie]
+//! author : Chris Cartlidge : https://github.com/chriscartlidge
+
+moment.defineLocale('en-ie', {
+    months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),
+    monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),
+    weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
+    weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
+    weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD-MM-YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[Today at] LT',
+        nextDay : '[Tomorrow at] LT',
+        nextWeek : 'dddd [at] LT',
+        lastDay : '[Yesterday at] LT',
+        lastWeek : '[Last] dddd [at] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'in %s',
+        past : '%s ago',
+        s : 'a few seconds',
+        m : 'a minute',
+        mm : '%d minutes',
+        h : 'an hour',
+        hh : '%d hours',
+        d : 'a day',
+        dd : '%d days',
+        M : 'a month',
+        MM : '%d months',
+        y : 'a year',
+        yy : '%d years'
+    },
+    ordinalParse: /\d{1,2}(st|nd|rd|th)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : English (New Zealand) [en-nz]
+//! author : Luke McGregor : https://github.com/lukemcgregor
+
+moment.defineLocale('en-nz', {
+    months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),
+    monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),
+    weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
+    weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
+    weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'h:mm A',
+        LTS : 'h:mm:ss A',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY h:mm A',
+        LLLL : 'dddd, D MMMM YYYY h:mm A'
+    },
+    calendar : {
+        sameDay : '[Today at] LT',
+        nextDay : '[Tomorrow at] LT',
+        nextWeek : 'dddd [at] LT',
+        lastDay : '[Yesterday at] LT',
+        lastWeek : '[Last] dddd [at] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'in %s',
+        past : '%s ago',
+        s : 'a few seconds',
+        m : 'a minute',
+        mm : '%d minutes',
+        h : 'an hour',
+        hh : '%d hours',
+        d : 'a day',
+        dd : '%d days',
+        M : 'a month',
+        MM : '%d months',
+        y : 'a year',
+        yy : '%d years'
+    },
+    ordinalParse: /\d{1,2}(st|nd|rd|th)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Esperanto [eo]
+//! author : Colin Dean : https://github.com/colindean
+//! komento: Mi estas malcerta se mi korekte traktis akuzativojn en tiu traduko.
+//!          Se ne, bonvolu korekti kaj avizi min por ke mi povas lerni!
+
+moment.defineLocale('eo', {
+    months : 'januaro_februaro_marto_aprilo_majo_junio_julio_aÅ­gusto_septembro_oktobro_novembro_decembro'.split('_'),
+    monthsShort : 'jan_feb_mar_apr_maj_jun_jul_aÅ­g_sep_okt_nov_dec'.split('_'),
+    weekdays : 'Dimanĉo_Lundo_Mardo_Merkredo_Ĵaŭdo_Vendredo_Sabato'.split('_'),
+    weekdaysShort : 'Dim_Lun_Mard_Merk_Ä´aÅ­_Ven_Sab'.split('_'),
+    weekdaysMin : 'Di_Lu_Ma_Me_Ä´a_Ve_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'YYYY-MM-DD',
+        LL : 'D[-an de] MMMM, YYYY',
+        LLL : 'D[-an de] MMMM, YYYY HH:mm',
+        LLLL : 'dddd, [la] D[-an de] MMMM, YYYY HH:mm'
+    },
+    meridiemParse: /[ap]\.t\.m/i,
+    isPM: function (input) {
+        return input.charAt(0).toLowerCase() === 'p';
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours > 11) {
+            return isLower ? 'p.t.m.' : 'P.T.M.';
+        } else {
+            return isLower ? 'a.t.m.' : 'A.T.M.';
+        }
+    },
+    calendar : {
+        sameDay : '[HodiaÅ­ je] LT',
+        nextDay : '[MorgaÅ­ je] LT',
+        nextWeek : 'dddd [je] LT',
+        lastDay : '[HieraÅ­ je] LT',
+        lastWeek : '[pasinta] dddd [je] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'je %s',
+        past : 'antaÅ­ %s',
+        s : 'sekundoj',
+        m : 'minuto',
+        mm : '%d minutoj',
+        h : 'horo',
+        hh : '%d horoj',
+        d : 'tago',//ne 'diurno', ĉar estas uzita por proksimumo
+        dd : '%d tagoj',
+        M : 'monato',
+        MM : '%d monatoj',
+        y : 'jaro',
+        yy : '%d jaroj'
+    },
+    ordinalParse: /\d{1,2}a/,
+    ordinal : '%da',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Spanish (Dominican Republic) [es-do]
+
+var monthsShortDot = 'ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.'.split('_');
+var monthsShort$1 = 'ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic'.split('_');
+
+moment.defineLocale('es-do', {
+    months : 'enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre'.split('_'),
+    monthsShort : function (m, format) {
+        if (/-MMM-/.test(format)) {
+            return monthsShort$1[m.month()];
+        } else {
+            return monthsShortDot[m.month()];
+        }
+    },
+    monthsParseExact : true,
+    weekdays : 'domingo_lunes_martes_miércoles_jueves_viernes_sábado'.split('_'),
+    weekdaysShort : 'dom._lun._mar._mié._jue._vie._sáb.'.split('_'),
+    weekdaysMin : 'do_lu_ma_mi_ju_vi_sá'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'h:mm A',
+        LTS : 'h:mm:ss A',
+        L : 'DD/MM/YYYY',
+        LL : 'D [de] MMMM [de] YYYY',
+        LLL : 'D [de] MMMM [de] YYYY h:mm A',
+        LLLL : 'dddd, D [de] MMMM [de] YYYY h:mm A'
+    },
+    calendar : {
+        sameDay : function () {
+            return '[hoy a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        nextDay : function () {
+            return '[mañana a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        nextWeek : function () {
+            return 'dddd [a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        lastDay : function () {
+            return '[ayer a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        lastWeek : function () {
+            return '[el] dddd [pasado a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'en %s',
+        past : 'hace %s',
+        s : 'unos segundos',
+        m : 'un minuto',
+        mm : '%d minutos',
+        h : 'una hora',
+        hh : '%d horas',
+        d : 'un día',
+        dd : '%d días',
+        M : 'un mes',
+        MM : '%d meses',
+        y : 'un año',
+        yy : '%d años'
+    },
+    ordinalParse : /\d{1,2}º/,
+    ordinal : '%dº',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Spanish [es]
+//! author : Julio Napurí : https://github.com/julionc
+
+var monthsShortDot$1 = 'ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.'.split('_');
+var monthsShort$2 = 'ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic'.split('_');
+
+moment.defineLocale('es', {
+    months : 'enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre'.split('_'),
+    monthsShort : function (m, format) {
+        if (/-MMM-/.test(format)) {
+            return monthsShort$2[m.month()];
+        } else {
+            return monthsShortDot$1[m.month()];
+        }
+    },
+    monthsParseExact : true,
+    weekdays : 'domingo_lunes_martes_miércoles_jueves_viernes_sábado'.split('_'),
+    weekdaysShort : 'dom._lun._mar._mié._jue._vie._sáb.'.split('_'),
+    weekdaysMin : 'do_lu_ma_mi_ju_vi_sá'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D [de] MMMM [de] YYYY',
+        LLL : 'D [de] MMMM [de] YYYY H:mm',
+        LLLL : 'dddd, D [de] MMMM [de] YYYY H:mm'
+    },
+    calendar : {
+        sameDay : function () {
+            return '[hoy a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        nextDay : function () {
+            return '[mañana a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        nextWeek : function () {
+            return 'dddd [a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        lastDay : function () {
+            return '[ayer a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        lastWeek : function () {
+            return '[el] dddd [pasado a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'en %s',
+        past : 'hace %s',
+        s : 'unos segundos',
+        m : 'un minuto',
+        mm : '%d minutos',
+        h : 'una hora',
+        hh : '%d horas',
+        d : 'un día',
+        dd : '%d días',
+        M : 'un mes',
+        MM : '%d meses',
+        y : 'un año',
+        yy : '%d años'
+    },
+    ordinalParse : /\d{1,2}º/,
+    ordinal : '%dº',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Estonian [et]
+//! author : Henry Kehlmann : https://github.com/madhenry
+//! improvements : Illimar Tambek : https://github.com/ragulka
+
+function processRelativeTime$2(number, withoutSuffix, key, isFuture) {
+    var format = {
+        's' : ['mõne sekundi', 'mõni sekund', 'paar sekundit'],
+        'm' : ['ühe minuti', 'üks minut'],
+        'mm': [number + ' minuti', number + ' minutit'],
+        'h' : ['ühe tunni', 'tund aega', 'üks tund'],
+        'hh': [number + ' tunni', number + ' tundi'],
+        'd' : ['ühe päeva', 'üks päev'],
+        'M' : ['kuu aja', 'kuu aega', 'üks kuu'],
+        'MM': [number + ' kuu', number + ' kuud'],
+        'y' : ['ühe aasta', 'aasta', 'üks aasta'],
+        'yy': [number + ' aasta', number + ' aastat']
+    };
+    if (withoutSuffix) {
+        return format[key][2] ? format[key][2] : format[key][1];
+    }
+    return isFuture ? format[key][0] : format[key][1];
+}
+
+moment.defineLocale('et', {
+    months        : 'jaanuar_veebruar_märts_aprill_mai_juuni_juuli_august_september_oktoober_november_detsember'.split('_'),
+    monthsShort   : 'jaan_veebr_märts_apr_mai_juuni_juuli_aug_sept_okt_nov_dets'.split('_'),
+    weekdays      : 'pühapäev_esmaspäev_teisipäev_kolmapäev_neljapäev_reede_laupäev'.split('_'),
+    weekdaysShort : 'P_E_T_K_N_R_L'.split('_'),
+    weekdaysMin   : 'P_E_T_K_N_R_L'.split('_'),
+    longDateFormat : {
+        LT   : 'H:mm',
+        LTS : 'H:mm:ss',
+        L    : 'DD.MM.YYYY',
+        LL   : 'D. MMMM YYYY',
+        LLL  : 'D. MMMM YYYY H:mm',
+        LLLL : 'dddd, D. MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay  : '[Täna,] LT',
+        nextDay  : '[Homme,] LT',
+        nextWeek : '[Järgmine] dddd LT',
+        lastDay  : '[Eile,] LT',
+        lastWeek : '[Eelmine] dddd LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s pärast',
+        past   : '%s tagasi',
+        s      : processRelativeTime$2,
+        m      : processRelativeTime$2,
+        mm     : processRelativeTime$2,
+        h      : processRelativeTime$2,
+        hh     : processRelativeTime$2,
+        d      : processRelativeTime$2,
+        dd     : '%d päeva',
+        M      : processRelativeTime$2,
+        MM     : processRelativeTime$2,
+        y      : processRelativeTime$2,
+        yy     : processRelativeTime$2
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Basque [eu]
+//! author : Eneko Illarramendi : https://github.com/eillarra
+
+moment.defineLocale('eu', {
+    months : 'urtarrila_otsaila_martxoa_apirila_maiatza_ekaina_uztaila_abuztua_iraila_urria_azaroa_abendua'.split('_'),
+    monthsShort : 'urt._ots._mar._api._mai._eka._uzt._abu._ira._urr._aza._abe.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'igandea_astelehena_asteartea_asteazkena_osteguna_ostirala_larunbata'.split('_'),
+    weekdaysShort : 'ig._al._ar._az._og._ol._lr.'.split('_'),
+    weekdaysMin : 'ig_al_ar_az_og_ol_lr'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'YYYY-MM-DD',
+        LL : 'YYYY[ko] MMMM[ren] D[a]',
+        LLL : 'YYYY[ko] MMMM[ren] D[a] HH:mm',
+        LLLL : 'dddd, YYYY[ko] MMMM[ren] D[a] HH:mm',
+        l : 'YYYY-M-D',
+        ll : 'YYYY[ko] MMM D[a]',
+        lll : 'YYYY[ko] MMM D[a] HH:mm',
+        llll : 'ddd, YYYY[ko] MMM D[a] HH:mm'
+    },
+    calendar : {
+        sameDay : '[gaur] LT[etan]',
+        nextDay : '[bihar] LT[etan]',
+        nextWeek : 'dddd LT[etan]',
+        lastDay : '[atzo] LT[etan]',
+        lastWeek : '[aurreko] dddd LT[etan]',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s barru',
+        past : 'duela %s',
+        s : 'segundo batzuk',
+        m : 'minutu bat',
+        mm : '%d minutu',
+        h : 'ordu bat',
+        hh : '%d ordu',
+        d : 'egun bat',
+        dd : '%d egun',
+        M : 'hilabete bat',
+        MM : '%d hilabete',
+        y : 'urte bat',
+        yy : '%d urte'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Persian [fa]
+//! author : Ebrahim Byagowi : https://github.com/ebraminio
+
+var symbolMap$5 = {
+    '1': 'Û±',
+    '2': 'Û²',
+    '3': 'Û³',
+    '4': 'Û´',
+    '5': 'Ûµ',
+    '6': 'Û¶',
+    '7': 'Û·',
+    '8': 'Û¸',
+    '9': 'Û¹',
+    '0': 'Û°'
+};
+var numberMap$4 = {
+    'Û±': '1',
+    'Û²': '2',
+    'Û³': '3',
+    'Û´': '4',
+    'Ûµ': '5',
+    'Û¶': '6',
+    'Û·': '7',
+    'Û¸': '8',
+    'Û¹': '9',
+    'Û°': '0'
+};
+
+moment.defineLocale('fa', {
+    months : 'ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر'.split('_'),
+    monthsShort : 'ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر'.split('_'),
+    weekdays : 'یک\u200cشنبه_دوشنبه_سه\u200cشنبه_چهارشنبه_پنج\u200cشنبه_جمعه_شنبه'.split('_'),
+    weekdaysShort : 'یک\u200cشنبه_دوشنبه_سه\u200cشنبه_چهارشنبه_پنج\u200cشنبه_جمعه_شنبه'.split('_'),
+    weekdaysMin : 'ی_د_س_چ_پ_ج_ش'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    meridiemParse: /قبل از ظهر|بعد از ظهر/,
+    isPM: function (input) {
+        return /بعد از ظهر/.test(input);
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return 'قبل از ظهر';
+        } else {
+            return 'بعد از ظهر';
+        }
+    },
+    calendar : {
+        sameDay : '[امروز ساعت] LT',
+        nextDay : '[فردا ساعت] LT',
+        nextWeek : 'dddd [ساعت] LT',
+        lastDay : '[دیروز ساعت] LT',
+        lastWeek : 'dddd [پیش] [ساعت] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'در %s',
+        past : '%s پیش',
+        s : 'چندین ثانیه',
+        m : 'یک دقیقه',
+        mm : '%d دقیقه',
+        h : 'یک ساعت',
+        hh : '%d ساعت',
+        d : 'یک روز',
+        dd : '%d روز',
+        M : 'یک ماه',
+        MM : '%d ماه',
+        y : 'یک سال',
+        yy : '%d سال'
+    },
+    preparse: function (string) {
+        return string.replace(/[Û°-Û¹]/g, function (match) {
+            return numberMap$4[match];
+        }).replace(/،/g, ',');
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap$5[match];
+        }).replace(/,/g, '،');
+    },
+    ordinalParse: /\d{1,2}Ù…/,
+    ordinal : '%dÙ…',
+    week : {
+        dow : 6, // Saturday is the first day of the week.
+        doy : 12 // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Finnish [fi]
+//! author : Tarmo Aidantausta : https://github.com/bleadof
+
+var numbersPast = 'nolla yksi kaksi kolme neljä viisi kuusi seitsemän kahdeksan yhdeksän'.split(' ');
+var numbersFuture = [
+        'nolla', 'yhden', 'kahden', 'kolmen', 'neljän', 'viiden', 'kuuden',
+        numbersPast[7], numbersPast[8], numbersPast[9]
+    ];
+function translate$2(number, withoutSuffix, key, isFuture) {
+    var result = '';
+    switch (key) {
+        case 's':
+            return isFuture ? 'muutaman sekunnin' : 'muutama sekunti';
+        case 'm':
+            return isFuture ? 'minuutin' : 'minuutti';
+        case 'mm':
+            result = isFuture ? 'minuutin' : 'minuuttia';
+            break;
+        case 'h':
+            return isFuture ? 'tunnin' : 'tunti';
+        case 'hh':
+            result = isFuture ? 'tunnin' : 'tuntia';
+            break;
+        case 'd':
+            return isFuture ? 'päivän' : 'päivä';
+        case 'dd':
+            result = isFuture ? 'päivän' : 'päivää';
+            break;
+        case 'M':
+            return isFuture ? 'kuukauden' : 'kuukausi';
+        case 'MM':
+            result = isFuture ? 'kuukauden' : 'kuukautta';
+            break;
+        case 'y':
+            return isFuture ? 'vuoden' : 'vuosi';
+        case 'yy':
+            result = isFuture ? 'vuoden' : 'vuotta';
+            break;
+    }
+    result = verbalNumber(number, isFuture) + ' ' + result;
+    return result;
+}
+function verbalNumber(number, isFuture) {
+    return number < 10 ? (isFuture ? numbersFuture[number] : numbersPast[number]) : number;
+}
+
+moment.defineLocale('fi', {
+    months : 'tammikuu_helmikuu_maaliskuu_huhtikuu_toukokuu_kesäkuu_heinäkuu_elokuu_syyskuu_lokakuu_marraskuu_joulukuu'.split('_'),
+    monthsShort : 'tammi_helmi_maalis_huhti_touko_kesä_heinä_elo_syys_loka_marras_joulu'.split('_'),
+    weekdays : 'sunnuntai_maanantai_tiistai_keskiviikko_torstai_perjantai_lauantai'.split('_'),
+    weekdaysShort : 'su_ma_ti_ke_to_pe_la'.split('_'),
+    weekdaysMin : 'su_ma_ti_ke_to_pe_la'.split('_'),
+    longDateFormat : {
+        LT : 'HH.mm',
+        LTS : 'HH.mm.ss',
+        L : 'DD.MM.YYYY',
+        LL : 'Do MMMM[ta] YYYY',
+        LLL : 'Do MMMM[ta] YYYY, [klo] HH.mm',
+        LLLL : 'dddd, Do MMMM[ta] YYYY, [klo] HH.mm',
+        l : 'D.M.YYYY',
+        ll : 'Do MMM YYYY',
+        lll : 'Do MMM YYYY, [klo] HH.mm',
+        llll : 'ddd, Do MMM YYYY, [klo] HH.mm'
+    },
+    calendar : {
+        sameDay : '[tänään] [klo] LT',
+        nextDay : '[huomenna] [klo] LT',
+        nextWeek : 'dddd [klo] LT',
+        lastDay : '[eilen] [klo] LT',
+        lastWeek : '[viime] dddd[na] [klo] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s päästä',
+        past : '%s sitten',
+        s : translate$2,
+        m : translate$2,
+        mm : translate$2,
+        h : translate$2,
+        hh : translate$2,
+        d : translate$2,
+        dd : translate$2,
+        M : translate$2,
+        MM : translate$2,
+        y : translate$2,
+        yy : translate$2
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Faroese [fo]
+//! author : Ragnar Johannesen : https://github.com/ragnar123
+
+moment.defineLocale('fo', {
+    months : 'januar_februar_mars_apríl_mai_juni_juli_august_september_oktober_november_desember'.split('_'),
+    monthsShort : 'jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_'),
+    weekdays : 'sunnudagur_mánadagur_týsdagur_mikudagur_hósdagur_fríggjadagur_leygardagur'.split('_'),
+    weekdaysShort : 'sun_mán_týs_mik_hós_frí_ley'.split('_'),
+    weekdaysMin : 'su_má_tý_mi_hó_fr_le'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D. MMMM, YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[Í dag kl.] LT',
+        nextDay : '[Í morgin kl.] LT',
+        nextWeek : 'dddd [kl.] LT',
+        lastDay : '[Í gjár kl.] LT',
+        lastWeek : '[síðstu] dddd [kl] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'um %s',
+        past : '%s síðani',
+        s : 'fá sekund',
+        m : 'ein minutt',
+        mm : '%d minuttir',
+        h : 'ein tími',
+        hh : '%d tímar',
+        d : 'ein dagur',
+        dd : '%d dagar',
+        M : 'ein mánaði',
+        MM : '%d mánaðir',
+        y : 'eitt ár',
+        yy : '%d ár'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : French (Canada) [fr-ca]
+//! author : Jonathan Abourbih : https://github.com/jonbca
+
+moment.defineLocale('fr-ca', {
+    months : 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split('_'),
+    monthsShort : 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'),
+    weekdaysShort : 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'),
+    weekdaysMin : 'Di_Lu_Ma_Me_Je_Ve_Sa'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'YYYY-MM-DD',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Aujourd\'hui à] LT',
+        nextDay: '[Demain à] LT',
+        nextWeek: 'dddd [à] LT',
+        lastDay: '[Hier à] LT',
+        lastWeek: 'dddd [dernier à] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'dans %s',
+        past : 'il y a %s',
+        s : 'quelques secondes',
+        m : 'une minute',
+        mm : '%d minutes',
+        h : 'une heure',
+        hh : '%d heures',
+        d : 'un jour',
+        dd : '%d jours',
+        M : 'un mois',
+        MM : '%d mois',
+        y : 'un an',
+        yy : '%d ans'
+    },
+    ordinalParse: /\d{1,2}(er|e)/,
+    ordinal : function (number) {
+        return number + (number === 1 ? 'er' : 'e');
+    }
+});
+
+//! moment.js locale configuration
+//! locale : French (Switzerland) [fr-ch]
+//! author : Gaspard Bucher : https://github.com/gaspard
+
+moment.defineLocale('fr-ch', {
+    months : 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split('_'),
+    monthsShort : 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'),
+    weekdaysShort : 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'),
+    weekdaysMin : 'Di_Lu_Ma_Me_Je_Ve_Sa'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Aujourd\'hui à] LT',
+        nextDay: '[Demain à] LT',
+        nextWeek: 'dddd [à] LT',
+        lastDay: '[Hier à] LT',
+        lastWeek: 'dddd [dernier à] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'dans %s',
+        past : 'il y a %s',
+        s : 'quelques secondes',
+        m : 'une minute',
+        mm : '%d minutes',
+        h : 'une heure',
+        hh : '%d heures',
+        d : 'un jour',
+        dd : '%d jours',
+        M : 'un mois',
+        MM : '%d mois',
+        y : 'un an',
+        yy : '%d ans'
+    },
+    ordinalParse: /\d{1,2}(er|e)/,
+    ordinal : function (number) {
+        return number + (number === 1 ? 'er' : 'e');
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : French [fr]
+//! author : John Fischer : https://github.com/jfroffice
+
+moment.defineLocale('fr', {
+    months : 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split('_'),
+    monthsShort : 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'),
+    weekdaysShort : 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'),
+    weekdaysMin : 'Di_Lu_Ma_Me_Je_Ve_Sa'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Aujourd\'hui à] LT',
+        nextDay: '[Demain à] LT',
+        nextWeek: 'dddd [à] LT',
+        lastDay: '[Hier à] LT',
+        lastWeek: 'dddd [dernier à] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'dans %s',
+        past : 'il y a %s',
+        s : 'quelques secondes',
+        m : 'une minute',
+        mm : '%d minutes',
+        h : 'une heure',
+        hh : '%d heures',
+        d : 'un jour',
+        dd : '%d jours',
+        M : 'un mois',
+        MM : '%d mois',
+        y : 'un an',
+        yy : '%d ans'
+    },
+    ordinalParse: /\d{1,2}(er|)/,
+    ordinal : function (number) {
+        return number + (number === 1 ? 'er' : '');
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Frisian [fy]
+//! author : Robin van der Vliet : https://github.com/robin0van0der0v
+
+var monthsShortWithDots = 'jan._feb._mrt._apr._mai_jun._jul._aug._sep._okt._nov._des.'.split('_');
+var monthsShortWithoutDots = 'jan_feb_mrt_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_');
+
+moment.defineLocale('fy', {
+    months : 'jannewaris_febrewaris_maart_april_maaie_juny_july_augustus_septimber_oktober_novimber_desimber'.split('_'),
+    monthsShort : function (m, format) {
+        if (/-MMM-/.test(format)) {
+            return monthsShortWithoutDots[m.month()];
+        } else {
+            return monthsShortWithDots[m.month()];
+        }
+    },
+    monthsParseExact : true,
+    weekdays : 'snein_moandei_tiisdei_woansdei_tongersdei_freed_sneon'.split('_'),
+    weekdaysShort : 'si._mo._ti._wo._to._fr._so.'.split('_'),
+    weekdaysMin : 'Si_Mo_Ti_Wo_To_Fr_So'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD-MM-YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[hjoed om] LT',
+        nextDay: '[moarn om] LT',
+        nextWeek: 'dddd [om] LT',
+        lastDay: '[juster om] LT',
+        lastWeek: '[ôfrûne] dddd [om] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'oer %s',
+        past : '%s lyn',
+        s : 'in pear sekonden',
+        m : 'ien minút',
+        mm : '%d minuten',
+        h : 'ien oere',
+        hh : '%d oeren',
+        d : 'ien dei',
+        dd : '%d dagen',
+        M : 'ien moanne',
+        MM : '%d moannen',
+        y : 'ien jier',
+        yy : '%d jierren'
+    },
+    ordinalParse: /\d{1,2}(ste|de)/,
+    ordinal : function (number) {
+        return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de');
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Scottish Gaelic [gd]
+//! author : Jon Ashdown : https://github.com/jonashdown
+
+var months$4 = [
+    'Am Faoilleach', 'An Gearran', 'Am Màrt', 'An Giblean', 'An Cèitean', 'An t-Ògmhios', 'An t-Iuchar', 'An Lùnastal', 'An t-Sultain', 'An Dàmhair', 'An t-Samhain', 'An Dùbhlachd'
+];
+
+var monthsShort$3 = ['Faoi', 'Gear', 'Màrt', 'Gibl', 'Cèit', 'Ògmh', 'Iuch', 'Lùn', 'Sult', 'Dàmh', 'Samh', 'Dùbh'];
+
+var weekdays$1 = ['Didòmhnaich', 'Diluain', 'Dimàirt', 'Diciadain', 'Diardaoin', 'Dihaoine', 'Disathairne'];
+
+var weekdaysShort = ['Did', 'Dil', 'Dim', 'Dic', 'Dia', 'Dih', 'Dis'];
+
+var weekdaysMin = ['Dò', 'Lu', 'Mà', 'Ci', 'Ar', 'Ha', 'Sa'];
+
+moment.defineLocale('gd', {
+    months : months$4,
+    monthsShort : monthsShort$3,
+    monthsParseExact : true,
+    weekdays : weekdays$1,
+    weekdaysShort : weekdaysShort,
+    weekdaysMin : weekdaysMin,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[An-diugh aig] LT',
+        nextDay : '[A-màireach aig] LT',
+        nextWeek : 'dddd [aig] LT',
+        lastDay : '[An-dè aig] LT',
+        lastWeek : 'dddd [seo chaidh] [aig] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'ann an %s',
+        past : 'bho chionn %s',
+        s : 'beagan diogan',
+        m : 'mionaid',
+        mm : '%d mionaidean',
+        h : 'uair',
+        hh : '%d uairean',
+        d : 'latha',
+        dd : '%d latha',
+        M : 'mìos',
+        MM : '%d mìosan',
+        y : 'bliadhna',
+        yy : '%d bliadhna'
+    },
+    ordinalParse : /\d{1,2}(d|na|mh)/,
+    ordinal : function (number) {
+        var output = number === 1 ? 'd' : number % 10 === 2 ? 'na' : 'mh';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Galician [gl]
+//! author : Juan G. Hurtado : https://github.com/juanghurtado
+
+moment.defineLocale('gl', {
+    months : 'xaneiro_febreiro_marzo_abril_maio_xuño_xullo_agosto_setembro_outubro_novembro_decembro'.split('_'),
+    monthsShort : 'xan._feb._mar._abr._mai._xuñ._xul._ago._set._out._nov._dec.'.split('_'),
+    monthsParseExact: true,
+    weekdays : 'domingo_luns_martes_mércores_xoves_venres_sábado'.split('_'),
+    weekdaysShort : 'dom._lun._mar._mér._xov._ven._sáb.'.split('_'),
+    weekdaysMin : 'do_lu_ma_mé_xo_ve_sá'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D [de] MMMM [de] YYYY',
+        LLL : 'D [de] MMMM [de] YYYY H:mm',
+        LLLL : 'dddd, D [de] MMMM [de] YYYY H:mm'
+    },
+    calendar : {
+        sameDay : function () {
+            return '[hoxe ' + ((this.hours() !== 1) ? 'ás' : 'á') + '] LT';
+        },
+        nextDay : function () {
+            return '[mañá ' + ((this.hours() !== 1) ? 'ás' : 'á') + '] LT';
+        },
+        nextWeek : function () {
+            return 'dddd [' + ((this.hours() !== 1) ? 'ás' : 'a') + '] LT';
+        },
+        lastDay : function () {
+            return '[onte ' + ((this.hours() !== 1) ? 'á' : 'a') + '] LT';
+        },
+        lastWeek : function () {
+            return '[o] dddd [pasado ' + ((this.hours() !== 1) ? 'ás' : 'a') + '] LT';
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : function (str) {
+            if (str.indexOf('un') === 0) {
+                return 'n' + str;
+            }
+            return 'en ' + str;
+        },
+        past : 'hai %s',
+        s : 'uns segundos',
+        m : 'un minuto',
+        mm : '%d minutos',
+        h : 'unha hora',
+        hh : '%d horas',
+        d : 'un día',
+        dd : '%d días',
+        M : 'un mes',
+        MM : '%d meses',
+        y : 'un ano',
+        yy : '%d anos'
+    },
+    ordinalParse : /\d{1,2}º/,
+    ordinal : '%dº',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Hebrew [he]
+//! author : Tomer Cohen : https://github.com/tomer
+//! author : Moshe Simantov : https://github.com/DevelopmentIL
+//! author : Tal Ater : https://github.com/TalAter
+
+moment.defineLocale('he', {
+    months : 'ינואר_פברואר_מרץ_אפריל_מאי_יוני_יולי_אוגוסט_ספטמבר_אוקטובר_נובמבר_דצמבר'.split('_'),
+    monthsShort : 'ינו׳_פבר׳_מרץ_אפר׳_מאי_יוני_יולי_אוג׳_ספט׳_אוק׳_נוב׳_דצמ׳'.split('_'),
+    weekdays : 'ראשון_שני_שלישי_רביעי_חמישי_שישי_שבת'.split('_'),
+    weekdaysShort : 'א׳_ב׳_ג׳_ד׳_ה׳_ו׳_ש׳'.split('_'),
+    weekdaysMin : 'א_ב_ג_ד_ה_ו_ש'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D [ב]MMMM YYYY',
+        LLL : 'D [ב]MMMM YYYY HH:mm',
+        LLLL : 'dddd, D [ב]MMMM YYYY HH:mm',
+        l : 'D/M/YYYY',
+        ll : 'D MMM YYYY',
+        lll : 'D MMM YYYY HH:mm',
+        llll : 'ddd, D MMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[היום ב־]LT',
+        nextDay : '[מחר ב־]LT',
+        nextWeek : 'dddd [בשעה] LT',
+        lastDay : '[אתמול ב־]LT',
+        lastWeek : '[ביום] dddd [האחרון בשעה] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'בעוד %s',
+        past : 'לפני %s',
+        s : 'מספר שניות',
+        m : 'דקה',
+        mm : '%d דקות',
+        h : 'שעה',
+        hh : function (number) {
+            if (number === 2) {
+                return 'שעתיים';
+            }
+            return number + ' שעות';
+        },
+        d : 'יום',
+        dd : function (number) {
+            if (number === 2) {
+                return 'יומיים';
+            }
+            return number + ' ימים';
+        },
+        M : 'חודש',
+        MM : function (number) {
+            if (number === 2) {
+                return 'חודשיים';
+            }
+            return number + ' חודשים';
+        },
+        y : 'שנה',
+        yy : function (number) {
+            if (number === 2) {
+                return 'שנתיים';
+            } else if (number % 10 === 0 && number !== 10) {
+                return number + ' שנה';
+            }
+            return number + ' שנים';
+        }
+    },
+    meridiemParse: /אחה"צ|לפנה"צ|אחרי הצהריים|לפני הצהריים|לפנות בוקר|בבוקר|בערב/i,
+    isPM : function (input) {
+        return /^(אחה"צ|אחרי הצהריים|בערב)$/.test(input);
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 5) {
+            return 'לפנות בוקר';
+        } else if (hour < 10) {
+            return 'בבוקר';
+        } else if (hour < 12) {
+            return isLower ? 'לפנה"צ' : 'לפני הצהריים';
+        } else if (hour < 18) {
+            return isLower ? 'אחה"צ' : 'אחרי הצהריים';
+        } else {
+            return 'בערב';
+        }
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Hindi [hi]
+//! author : Mayank Singhal : https://github.com/mayanksinghal
+
+var symbolMap$6 = {
+    '1': '१',
+    '2': '२',
+    '3': '३',
+    '4': '४',
+    '5': '५',
+    '6': '६',
+    '7': '७',
+    '8': '८',
+    '9': '९',
+    '0': '०'
+};
+var numberMap$5 = {
+    '१': '1',
+    '२': '2',
+    '३': '3',
+    '४': '4',
+    '५': '5',
+    '६': '6',
+    '७': '7',
+    '८': '8',
+    '९': '9',
+    '०': '0'
+};
+
+moment.defineLocale('hi', {
+    months : 'जनवरी_फ़रवरी_मार्च_अप्रैल_मई_जून_जुलाई_अगस्त_सितम्बर_अक्टूबर_नवम्बर_दिसम्बर'.split('_'),
+    monthsShort : 'जन._फ़र._मार्च_अप्रै._मई_जून_जुल._अग._सित._अक्टू._नव._दिस.'.split('_'),
+    monthsParseExact: true,
+    weekdays : 'रविवार_सोमवार_मंगलवार_बुधवार_गुरूवार_शुक्रवार_शनिवार'.split('_'),
+    weekdaysShort : 'रवि_सोम_मंगल_बुध_गुरू_शुक्र_शनि'.split('_'),
+    weekdaysMin : 'र_सो_मं_बु_गु_शु_श'.split('_'),
+    longDateFormat : {
+        LT : 'A h:mm बजे',
+        LTS : 'A h:mm:ss बजे',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, A h:mm बजे',
+        LLLL : 'dddd, D MMMM YYYY, A h:mm बजे'
+    },
+    calendar : {
+        sameDay : '[आज] LT',
+        nextDay : '[कल] LT',
+        nextWeek : 'dddd, LT',
+        lastDay : '[कल] LT',
+        lastWeek : '[पिछले] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s में',
+        past : '%s पहले',
+        s : 'कुछ ही क्षण',
+        m : 'एक मिनट',
+        mm : '%d मिनट',
+        h : 'एक घंटा',
+        hh : '%d घंटे',
+        d : 'एक दिन',
+        dd : '%d दिन',
+        M : 'एक महीने',
+        MM : '%d महीने',
+        y : 'एक वर्ष',
+        yy : '%d वर्ष'
+    },
+    preparse: function (string) {
+        return string.replace(/[१२३४५६७८९०]/g, function (match) {
+            return numberMap$5[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap$6[match];
+        });
+    },
+    // Hindi notation for meridiems are quite fuzzy in practice. While there exists
+    // a rigid notion of a 'Pahar' it is not used as rigidly in modern Hindi.
+    meridiemParse: /रात|सुबह|दोपहर|शाम/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'रात') {
+            return hour < 4 ? hour : hour + 12;
+        } else if (meridiem === 'सुबह') {
+            return hour;
+        } else if (meridiem === 'दोपहर') {
+            return hour >= 10 ? hour : hour + 12;
+        } else if (meridiem === 'शाम') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'रात';
+        } else if (hour < 10) {
+            return 'सुबह';
+        } else if (hour < 17) {
+            return 'दोपहर';
+        } else if (hour < 20) {
+            return 'शाम';
+        } else {
+            return 'रात';
+        }
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Croatian [hr]
+//! author : Bojan Marković : https://github.com/bmarkovic
+
+function translate$3(number, withoutSuffix, key) {
+    var result = number + ' ';
+    switch (key) {
+        case 'm':
+            return withoutSuffix ? 'jedna minuta' : 'jedne minute';
+        case 'mm':
+            if (number === 1) {
+                result += 'minuta';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'minute';
+            } else {
+                result += 'minuta';
+            }
+            return result;
+        case 'h':
+            return withoutSuffix ? 'jedan sat' : 'jednog sata';
+        case 'hh':
+            if (number === 1) {
+                result += 'sat';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'sata';
+            } else {
+                result += 'sati';
+            }
+            return result;
+        case 'dd':
+            if (number === 1) {
+                result += 'dan';
+            } else {
+                result += 'dana';
+            }
+            return result;
+        case 'MM':
+            if (number === 1) {
+                result += 'mjesec';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'mjeseca';
+            } else {
+                result += 'mjeseci';
+            }
+            return result;
+        case 'yy':
+            if (number === 1) {
+                result += 'godina';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'godine';
+            } else {
+                result += 'godina';
+            }
+            return result;
+    }
+}
+
+moment.defineLocale('hr', {
+    months : {
+        format: 'siječnja_veljače_ožujka_travnja_svibnja_lipnja_srpnja_kolovoza_rujna_listopada_studenoga_prosinca'.split('_'),
+        standalone: 'siječanj_veljača_ožujak_travanj_svibanj_lipanj_srpanj_kolovoz_rujan_listopad_studeni_prosinac'.split('_')
+    },
+    monthsShort : 'sij._velj._ožu._tra._svi._lip._srp._kol._ruj._lis._stu._pro.'.split('_'),
+    monthsParseExact: true,
+    weekdays : 'nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota'.split('_'),
+    weekdaysShort : 'ned._pon._uto._sri._čet._pet._sub.'.split('_'),
+    weekdaysMin : 'ne_po_ut_sr_če_pe_su'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY H:mm',
+        LLLL : 'dddd, D. MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay  : '[danas u] LT',
+        nextDay  : '[sutra u] LT',
+        nextWeek : function () {
+            switch (this.day()) {
+                case 0:
+                    return '[u] [nedjelju] [u] LT';
+                case 3:
+                    return '[u] [srijedu] [u] LT';
+                case 6:
+                    return '[u] [subotu] [u] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[u] dddd [u] LT';
+            }
+        },
+        lastDay  : '[jučer u] LT',
+        lastWeek : function () {
+            switch (this.day()) {
+                case 0:
+                case 3:
+                    return '[prošlu] dddd [u] LT';
+                case 6:
+                    return '[prošle] [subote] [u] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[prošli] dddd [u] LT';
+            }
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'za %s',
+        past   : 'prije %s',
+        s      : 'par sekundi',
+        m      : translate$3,
+        mm     : translate$3,
+        h      : translate$3,
+        hh     : translate$3,
+        d      : 'dan',
+        dd     : translate$3,
+        M      : 'mjesec',
+        MM     : translate$3,
+        y      : 'godinu',
+        yy     : translate$3
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Hungarian [hu]
+//! author : Adam Brunner : https://github.com/adambrunner
+
+var weekEndings = 'vasárnap hétfőn kedden szerdán csütörtökön pénteken szombaton'.split(' ');
+function translate$4(number, withoutSuffix, key, isFuture) {
+    var num = number,
+        suffix;
+    switch (key) {
+        case 's':
+            return (isFuture || withoutSuffix) ? 'néhány másodperc' : 'néhány másodperce';
+        case 'm':
+            return 'egy' + (isFuture || withoutSuffix ? ' perc' : ' perce');
+        case 'mm':
+            return num + (isFuture || withoutSuffix ? ' perc' : ' perce');
+        case 'h':
+            return 'egy' + (isFuture || withoutSuffix ? ' óra' : ' órája');
+        case 'hh':
+            return num + (isFuture || withoutSuffix ? ' óra' : ' órája');
+        case 'd':
+            return 'egy' + (isFuture || withoutSuffix ? ' nap' : ' napja');
+        case 'dd':
+            return num + (isFuture || withoutSuffix ? ' nap' : ' napja');
+        case 'M':
+            return 'egy' + (isFuture || withoutSuffix ? ' hónap' : ' hónapja');
+        case 'MM':
+            return num + (isFuture || withoutSuffix ? ' hónap' : ' hónapja');
+        case 'y':
+            return 'egy' + (isFuture || withoutSuffix ? ' év' : ' éve');
+        case 'yy':
+            return num + (isFuture || withoutSuffix ? ' év' : ' éve');
+    }
+    return '';
+}
+function week(isFuture) {
+    return (isFuture ? '' : '[múlt] ') + '[' + weekEndings[this.day()] + '] LT[-kor]';
+}
+
+moment.defineLocale('hu', {
+    months : 'január_február_március_április_május_június_július_augusztus_szeptember_október_november_december'.split('_'),
+    monthsShort : 'jan_feb_márc_ápr_máj_jún_júl_aug_szept_okt_nov_dec'.split('_'),
+    weekdays : 'vasárnap_hétfő_kedd_szerda_csütörtök_péntek_szombat'.split('_'),
+    weekdaysShort : 'vas_hét_kedd_sze_csüt_pén_szo'.split('_'),
+    weekdaysMin : 'v_h_k_sze_cs_p_szo'.split('_'),
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'YYYY.MM.DD.',
+        LL : 'YYYY. MMMM D.',
+        LLL : 'YYYY. MMMM D. H:mm',
+        LLLL : 'YYYY. MMMM D., dddd H:mm'
+    },
+    meridiemParse: /de|du/i,
+    isPM: function (input) {
+        return input.charAt(1).toLowerCase() === 'u';
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 12) {
+            return isLower === true ? 'de' : 'DE';
+        } else {
+            return isLower === true ? 'du' : 'DU';
+        }
+    },
+    calendar : {
+        sameDay : '[ma] LT[-kor]',
+        nextDay : '[holnap] LT[-kor]',
+        nextWeek : function () {
+            return week.call(this, true);
+        },
+        lastDay : '[tegnap] LT[-kor]',
+        lastWeek : function () {
+            return week.call(this, false);
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s múlva',
+        past : '%s',
+        s : translate$4,
+        m : translate$4,
+        mm : translate$4,
+        h : translate$4,
+        hh : translate$4,
+        d : translate$4,
+        dd : translate$4,
+        M : translate$4,
+        MM : translate$4,
+        y : translate$4,
+        yy : translate$4
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Armenian [hy-am]
+//! author : Armendarabyan : https://github.com/armendarabyan
+
+moment.defineLocale('hy-am', {
+    months : {
+        format: 'Õ°Õ¸Ö‚Õ¶Õ¾Õ¡Ö€Õ«_ÖƒÕ¥Õ¿Ö€Õ¾Õ¡Ö€Õ«_Õ´Õ¡Ö€Õ¿Õ«_Õ¡ÕºÖ€Õ«Õ¬Õ«_Õ´Õ¡ÕµÕ«Õ½Õ«_Õ°Õ¸Ö‚Õ¶Õ«Õ½Õ«_Õ°Õ¸Ö‚Õ¬Õ«Õ½Õ«_Ö…Õ£Õ¸Õ½Õ¿Õ¸Õ½Õ«_Õ½Õ¥ÕºÕ¿Õ¥Õ´Õ¢Õ¥Ö€Õ«_Õ°Õ¸Õ¯Õ¿Õ¥Õ´Õ¢Õ¥Ö€Õ«_Õ¶Õ¸ÕµÕ¥Õ´Õ¢Õ¥Ö€Õ«_Õ¤Õ¥Õ¯Õ¿Õ¥Õ´Õ¢Õ¥Ö€Õ«'.split('_'),
+        standalone: 'Õ°Õ¸Ö‚Õ¶Õ¾Õ¡Ö€_ÖƒÕ¥Õ¿Ö€Õ¾Õ¡Ö€_Õ´Õ¡Ö€Õ¿_Õ¡ÕºÖ€Õ«Õ¬_Õ´Õ¡ÕµÕ«Õ½_Õ°Õ¸Ö‚Õ¶Õ«Õ½_Õ°Õ¸Ö‚Õ¬Õ«Õ½_Ö…Õ£Õ¸Õ½Õ¿Õ¸Õ½_Õ½Õ¥ÕºÕ¿Õ¥Õ´Õ¢Õ¥Ö€_Õ°Õ¸Õ¯Õ¿Õ¥Õ´Õ¢Õ¥Ö€_Õ¶Õ¸ÕµÕ¥Õ´Õ¢Õ¥Ö€_Õ¤Õ¥Õ¯Õ¿Õ¥Õ´Õ¢Õ¥Ö€'.split('_')
+    },
+    monthsShort : 'Õ°Õ¶Õ¾_ÖƒÕ¿Ö€_Õ´Ö€Õ¿_Õ¡ÕºÖ€_Õ´ÕµÕ½_Õ°Õ¶Õ½_Õ°Õ¬Õ½_Ö…Õ£Õ½_Õ½ÕºÕ¿_Õ°Õ¯Õ¿_Õ¶Õ´Õ¢_Õ¤Õ¯Õ¿'.split('_'),
+    weekdays : 'Õ¯Õ«Ö€Õ¡Õ¯Õ«_Õ¥Ö€Õ¯Õ¸Ö‚Õ·Õ¡Õ¢Õ©Õ«_Õ¥Ö€Õ¥Ö„Õ·Õ¡Õ¢Õ©Õ«_Õ¹Õ¸Ö€Õ¥Ö„Õ·Õ¡Õ¢Õ©Õ«_Õ°Õ«Õ¶Õ£Õ·Õ¡Õ¢Õ©Õ«_Õ¸Ö‚Ö€Õ¢Õ¡Õ©_Õ·Õ¡Õ¢Õ¡Õ©'.split('_'),
+    weekdaysShort : 'Õ¯Ö€Õ¯_Õ¥Ö€Õ¯_Õ¥Ö€Ö„_Õ¹Ö€Ö„_Õ°Õ¶Õ£_Õ¸Ö‚Ö€Õ¢_Õ·Õ¢Õ©'.split('_'),
+    weekdaysMin : 'Õ¯Ö€Õ¯_Õ¥Ö€Õ¯_Õ¥Ö€Ö„_Õ¹Ö€Ö„_Õ°Õ¶Õ£_Õ¸Ö‚Ö€Õ¢_Õ·Õ¢Õ©'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY Õ©.',
+        LLL : 'D MMMM YYYY Õ©., HH:mm',
+        LLLL : 'dddd, D MMMM YYYY Õ©., HH:mm'
+    },
+    calendar : {
+        sameDay: '[Õ¡ÕµÕ½Ö…Ö€] LT',
+        nextDay: '[Õ¾Õ¡Õ²Õ¨] LT',
+        lastDay: '[Õ¥Ö€Õ¥Õ¯] LT',
+        nextWeek: function () {
+            return 'dddd [Ö…Ö€Õ¨ ÕªÕ¡Õ´Õ¨] LT';
+        },
+        lastWeek: function () {
+            return '[անցած] dddd [օրը ժամը] LT';
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : '%s Õ°Õ¥Õ¿Õ¸',
+        past : '%s Õ¡Õ¼Õ¡Õ»',
+        s : 'Õ´Õ« Ö„Õ¡Õ¶Õ« Õ¾Õ¡ÕµÖ€Õ¯ÕµÕ¡Õ¶',
+        m : 'Ö€Õ¸ÕºÕ¥',
+        mm : '%d Ö€Õ¸ÕºÕ¥',
+        h : 'ÕªÕ¡Õ´',
+        hh : '%d ÕªÕ¡Õ´',
+        d : 'Ö…Ö€',
+        dd : '%d Ö…Ö€',
+        M : 'Õ¡Õ´Õ«Õ½',
+        MM : '%d Õ¡Õ´Õ«Õ½',
+        y : 'Õ¿Õ¡Ö€Õ«',
+        yy : '%d Õ¿Õ¡Ö€Õ«'
+    },
+    meridiemParse: /գիշերվա|առավոտվա|ցերեկվա|երեկոյան/,
+    isPM: function (input) {
+        return /^(ցերեկվա|երեկոյան)$/.test(input);
+    },
+    meridiem : function (hour) {
+        if (hour < 4) {
+            return 'Õ£Õ«Õ·Õ¥Ö€Õ¾Õ¡';
+        } else if (hour < 12) {
+            return 'Õ¡Õ¼Õ¡Õ¾Õ¸Õ¿Õ¾Õ¡';
+        } else if (hour < 17) {
+            return 'ցերեկվա';
+        } else {
+            return 'Õ¥Ö€Õ¥Õ¯Õ¸ÕµÕ¡Õ¶';
+        }
+    },
+    ordinalParse: /\d{1,2}|\d{1,2}-(Õ«Õ¶|Ö€Õ¤)/,
+    ordinal: function (number, period) {
+        switch (period) {
+            case 'DDD':
+            case 'w':
+            case 'W':
+            case 'DDDo':
+                if (number === 1) {
+                    return number + '-Õ«Õ¶';
+                }
+                return number + '-Ö€Õ¤';
+            default:
+                return number;
+        }
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Indonesian [id]
+//! author : Mohammad Satrio Utomo : https://github.com/tyok
+//! reference: http://id.wikisource.org/wiki/Pedoman_Umum_Ejaan_Bahasa_Indonesia_yang_Disempurnakan
+
+moment.defineLocale('id', {
+    months : 'Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_November_Desember'.split('_'),
+    monthsShort : 'Jan_Feb_Mar_Apr_Mei_Jun_Jul_Ags_Sep_Okt_Nov_Des'.split('_'),
+    weekdays : 'Minggu_Senin_Selasa_Rabu_Kamis_Jumat_Sabtu'.split('_'),
+    weekdaysShort : 'Min_Sen_Sel_Rab_Kam_Jum_Sab'.split('_'),
+    weekdaysMin : 'Mg_Sn_Sl_Rb_Km_Jm_Sb'.split('_'),
+    longDateFormat : {
+        LT : 'HH.mm',
+        LTS : 'HH.mm.ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY [pukul] HH.mm',
+        LLLL : 'dddd, D MMMM YYYY [pukul] HH.mm'
+    },
+    meridiemParse: /pagi|siang|sore|malam/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'pagi') {
+            return hour;
+        } else if (meridiem === 'siang') {
+            return hour >= 11 ? hour : hour + 12;
+        } else if (meridiem === 'sore' || meridiem === 'malam') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 11) {
+            return 'pagi';
+        } else if (hours < 15) {
+            return 'siang';
+        } else if (hours < 19) {
+            return 'sore';
+        } else {
+            return 'malam';
+        }
+    },
+    calendar : {
+        sameDay : '[Hari ini pukul] LT',
+        nextDay : '[Besok pukul] LT',
+        nextWeek : 'dddd [pukul] LT',
+        lastDay : '[Kemarin pukul] LT',
+        lastWeek : 'dddd [lalu pukul] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'dalam %s',
+        past : '%s yang lalu',
+        s : 'beberapa detik',
+        m : 'semenit',
+        mm : '%d menit',
+        h : 'sejam',
+        hh : '%d jam',
+        d : 'sehari',
+        dd : '%d hari',
+        M : 'sebulan',
+        MM : '%d bulan',
+        y : 'setahun',
+        yy : '%d tahun'
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Icelandic [is]
+//! author : Hinrik Örn Sigurðsson : https://github.com/hinrik
+
+function plural$2(n) {
+    if (n % 100 === 11) {
+        return true;
+    } else if (n % 10 === 1) {
+        return false;
+    }
+    return true;
+}
+function translate$5(number, withoutSuffix, key, isFuture) {
+    var result = number + ' ';
+    switch (key) {
+        case 's':
+            return withoutSuffix || isFuture ? 'nokkrar sekúndur' : 'nokkrum sekúndum';
+        case 'm':
+            return withoutSuffix ? 'mínúta' : 'mínútu';
+        case 'mm':
+            if (plural$2(number)) {
+                return result + (withoutSuffix || isFuture ? 'mínútur' : 'mínútum');
+            } else if (withoutSuffix) {
+                return result + 'mínúta';
+            }
+            return result + 'mínútu';
+        case 'hh':
+            if (plural$2(number)) {
+                return result + (withoutSuffix || isFuture ? 'klukkustundir' : 'klukkustundum');
+            }
+            return result + 'klukkustund';
+        case 'd':
+            if (withoutSuffix) {
+                return 'dagur';
+            }
+            return isFuture ? 'dag' : 'degi';
+        case 'dd':
+            if (plural$2(number)) {
+                if (withoutSuffix) {
+                    return result + 'dagar';
+                }
+                return result + (isFuture ? 'daga' : 'dögum');
+            } else if (withoutSuffix) {
+                return result + 'dagur';
+            }
+            return result + (isFuture ? 'dag' : 'degi');
+        case 'M':
+            if (withoutSuffix) {
+                return 'mánuður';
+            }
+            return isFuture ? 'mánuð' : 'mánuði';
+        case 'MM':
+            if (plural$2(number)) {
+                if (withoutSuffix) {
+                    return result + 'mánuðir';
+                }
+                return result + (isFuture ? 'mánuði' : 'mánuðum');
+            } else if (withoutSuffix) {
+                return result + 'mánuður';
+            }
+            return result + (isFuture ? 'mánuð' : 'mánuði');
+        case 'y':
+            return withoutSuffix || isFuture ? 'ár' : 'ári';
+        case 'yy':
+            if (plural$2(number)) {
+                return result + (withoutSuffix || isFuture ? 'ár' : 'árum');
+            }
+            return result + (withoutSuffix || isFuture ? 'ár' : 'ári');
+    }
+}
+
+moment.defineLocale('is', {
+    months : 'janúar_febrúar_mars_apríl_maí_júní_júlí_ágúst_september_október_nóvember_desember'.split('_'),
+    monthsShort : 'jan_feb_mar_apr_maí_jún_júl_ágú_sep_okt_nóv_des'.split('_'),
+    weekdays : 'sunnudagur_mánudagur_þriðjudagur_miðvikudagur_fimmtudagur_föstudagur_laugardagur'.split('_'),
+    weekdaysShort : 'sun_mán_þri_mið_fim_fös_lau'.split('_'),
+    weekdaysMin : 'Su_Má_Þr_Mi_Fi_Fö_La'.split('_'),
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY [kl.] H:mm',
+        LLLL : 'dddd, D. MMMM YYYY [kl.] H:mm'
+    },
+    calendar : {
+        sameDay : '[í dag kl.] LT',
+        nextDay : '[á morgun kl.] LT',
+        nextWeek : 'dddd [kl.] LT',
+        lastDay : '[í gær kl.] LT',
+        lastWeek : '[síðasta] dddd [kl.] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'eftir %s',
+        past : 'fyrir %s síðan',
+        s : translate$5,
+        m : translate$5,
+        mm : translate$5,
+        h : 'klukkustund',
+        hh : translate$5,
+        d : translate$5,
+        dd : translate$5,
+        M : translate$5,
+        MM : translate$5,
+        y : translate$5,
+        yy : translate$5
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Italian [it]
+//! author : Lorenzo : https://github.com/aliem
+//! author: Mattia Larentis: https://github.com/nostalgiaz
+
+moment.defineLocale('it', {
+    months : 'gennaio_febbraio_marzo_aprile_maggio_giugno_luglio_agosto_settembre_ottobre_novembre_dicembre'.split('_'),
+    monthsShort : 'gen_feb_mar_apr_mag_giu_lug_ago_set_ott_nov_dic'.split('_'),
+    weekdays : 'Domenica_Lunedì_Martedì_Mercoledì_Giovedì_Venerdì_Sabato'.split('_'),
+    weekdaysShort : 'Dom_Lun_Mar_Mer_Gio_Ven_Sab'.split('_'),
+    weekdaysMin : 'Do_Lu_Ma_Me_Gi_Ve_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Oggi alle] LT',
+        nextDay: '[Domani alle] LT',
+        nextWeek: 'dddd [alle] LT',
+        lastDay: '[Ieri alle] LT',
+        lastWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[la scorsa] dddd [alle] LT';
+                default:
+                    return '[lo scorso] dddd [alle] LT';
+            }
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : function (s) {
+            return ((/^[0-9].+$/).test(s) ? 'tra' : 'in') + ' ' + s;
+        },
+        past : '%s fa',
+        s : 'alcuni secondi',
+        m : 'un minuto',
+        mm : '%d minuti',
+        h : 'un\'ora',
+        hh : '%d ore',
+        d : 'un giorno',
+        dd : '%d giorni',
+        M : 'un mese',
+        MM : '%d mesi',
+        y : 'un anno',
+        yy : '%d anni'
+    },
+    ordinalParse : /\d{1,2}º/,
+    ordinal: '%dº',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Japanese [ja]
+//! author : LI Long : https://github.com/baryon
+
+moment.defineLocale('ja', {
+    months : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
+    monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
+    weekdays : '日曜日_月曜日_火曜日_水曜日_木曜日_金曜日_土曜日'.split('_'),
+    weekdaysShort : '日_月_火_水_木_金_土'.split('_'),
+    weekdaysMin : '日_月_火_水_木_金_土'.split('_'),
+    longDateFormat : {
+        LT : 'Ah時m分',
+        LTS : 'Ah時m分s秒',
+        L : 'YYYY/MM/DD',
+        LL : 'YYYY年M月D日',
+        LLL : 'YYYY年M月D日Ah時m分',
+        LLLL : 'YYYY年M月D日Ah時m分 dddd'
+    },
+    meridiemParse: /午前|午後/i,
+    isPM : function (input) {
+        return input === '午後';
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return '午前';
+        } else {
+            return '午後';
+        }
+    },
+    calendar : {
+        sameDay : '[今日] LT',
+        nextDay : '[明日] LT',
+        nextWeek : '[来週]dddd LT',
+        lastDay : '[昨日] LT',
+        lastWeek : '[前週]dddd LT',
+        sameElse : 'L'
+    },
+    ordinalParse : /\d{1,2}æ—¥/,
+    ordinal : function (number, period) {
+        switch (period) {
+            case 'd':
+            case 'D':
+            case 'DDD':
+                return number + 'æ—¥';
+            default:
+                return number;
+        }
+    },
+    relativeTime : {
+        future : '%s後',
+        past : '%s前',
+        s : 'æ•°ç§’',
+        m : '1分',
+        mm : '%d分',
+        h : '1時間',
+        hh : '%d時間',
+        d : '1æ—¥',
+        dd : '%dæ—¥',
+        M : '1ヶ月',
+        MM : '%dヶ月',
+        y : '1å¹´',
+        yy : '%då¹´'
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Javanese [jv]
+//! author : Rony Lantip : https://github.com/lantip
+//! reference: http://jv.wikipedia.org/wiki/Basa_Jawa
+
+moment.defineLocale('jv', {
+    months : 'Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_Nopember_Desember'.split('_'),
+    monthsShort : 'Jan_Feb_Mar_Apr_Mei_Jun_Jul_Ags_Sep_Okt_Nop_Des'.split('_'),
+    weekdays : 'Minggu_Senen_Seloso_Rebu_Kemis_Jemuwah_Septu'.split('_'),
+    weekdaysShort : 'Min_Sen_Sel_Reb_Kem_Jem_Sep'.split('_'),
+    weekdaysMin : 'Mg_Sn_Sl_Rb_Km_Jm_Sp'.split('_'),
+    longDateFormat : {
+        LT : 'HH.mm',
+        LTS : 'HH.mm.ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY [pukul] HH.mm',
+        LLLL : 'dddd, D MMMM YYYY [pukul] HH.mm'
+    },
+    meridiemParse: /enjing|siyang|sonten|ndalu/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'enjing') {
+            return hour;
+        } else if (meridiem === 'siyang') {
+            return hour >= 11 ? hour : hour + 12;
+        } else if (meridiem === 'sonten' || meridiem === 'ndalu') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 11) {
+            return 'enjing';
+        } else if (hours < 15) {
+            return 'siyang';
+        } else if (hours < 19) {
+            return 'sonten';
+        } else {
+            return 'ndalu';
+        }
+    },
+    calendar : {
+        sameDay : '[Dinten puniko pukul] LT',
+        nextDay : '[Mbenjang pukul] LT',
+        nextWeek : 'dddd [pukul] LT',
+        lastDay : '[Kala wingi pukul] LT',
+        lastWeek : 'dddd [kepengker pukul] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'wonten ing %s',
+        past : '%s ingkang kepengker',
+        s : 'sawetawis detik',
+        m : 'setunggal menit',
+        mm : '%d menit',
+        h : 'setunggal jam',
+        hh : '%d jam',
+        d : 'sedinten',
+        dd : '%d dinten',
+        M : 'sewulan',
+        MM : '%d wulan',
+        y : 'setaun',
+        yy : '%d taun'
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Georgian [ka]
+//! author : Irakli Janiashvili : https://github.com/irakli-janiashvili
+
+moment.defineLocale('ka', {
+    months : {
+        standalone: 'იანვარი_თებერვალი_მარტი_აპრილი_მაისი_ივნისი_ივლისი_აგვისტო_სექტემბერი_ოქტომბერი_ნოემბერი_დეკემბერი'.split('_'),
+        format: 'იანვარს_თებერვალს_მარტს_აპრილის_მაისს_ივნისს_ივლისს_აგვისტს_სექტემბერს_ოქტომბერს_ნოემბერს_დეკემბერს'.split('_')
+    },
+    monthsShort : 'იან_თებ_მარ_აპრ_მაი_ივნ_ივლ_აგვ_სექ_ოქტ_ნოე_დეკ'.split('_'),
+    weekdays : {
+        standalone: 'კვირა_ორშაბათი_სამშაბათი_ოთხშაბათი_ხუთშაბათი_პარასკევი_შაბათი'.split('_'),
+        format: 'კვირას_ორშაბათს_სამშაბათს_ოთხშაბათს_ხუთშაბათს_პარასკევს_შაბათს'.split('_'),
+        isFormat: /(წინა|შემდეგ)/
+    },
+    weekdaysShort : 'კვი_ორშ_სამ_ოთხ_ხუთ_პარ_შაბ'.split('_'),
+    weekdaysMin : 'კვ_ორ_სა_ოთ_ხუ_პა_შა'.split('_'),
+    longDateFormat : {
+        LT : 'h:mm A',
+        LTS : 'h:mm:ss A',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY h:mm A',
+        LLLL : 'dddd, D MMMM YYYY h:mm A'
+    },
+    calendar : {
+        sameDay : '[დღეს] LT[-ზე]',
+        nextDay : '[ხვალ] LT[-ზე]',
+        lastDay : '[გუშინ] LT[-ზე]',
+        nextWeek : '[შემდეგ] dddd LT[-ზე]',
+        lastWeek : '[წინა] dddd LT-ზე',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : function (s) {
+            return (/(წამი|წუთი|საათი|წელი)/).test(s) ?
+                s.replace(/ი$/, 'ში') :
+                s + 'ში';
+        },
+        past : function (s) {
+            if ((/(წამი|წუთი|საათი|დღე|თვე)/).test(s)) {
+                return s.replace(/(ი|ე)$/, 'ის წინ');
+            }
+            if ((/წელი/).test(s)) {
+                return s.replace(/წელი$/, 'წლის წინ');
+            }
+        },
+        s : 'რამდენიმე წამი',
+        m : 'წუთი',
+        mm : '%d წუთი',
+        h : 'საათი',
+        hh : '%d საათი',
+        d : 'დღე',
+        dd : '%d დღე',
+        M : 'თვე',
+        MM : '%d თვე',
+        y : 'წელი',
+        yy : '%d წელი'
+    },
+    ordinalParse: /0|1-ლი|მე-\d{1,2}|\d{1,2}-ე/,
+    ordinal : function (number) {
+        if (number === 0) {
+            return number;
+        }
+        if (number === 1) {
+            return number + '-ლი';
+        }
+        if ((number < 20) || (number <= 100 && (number % 20 === 0)) || (number % 100 === 0)) {
+            return 'მე-' + number;
+        }
+        return number + '-ე';
+    },
+    week : {
+        dow : 1,
+        doy : 7
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Kazakh [kk]
+//! authors : Nurlan Rakhimzhanov : https://github.com/nurlan
+
+var suffixes$1 = {
+    0: '-ші',
+    1: '-ші',
+    2: '-ші',
+    3: '-ші',
+    4: '-ші',
+    5: '-ші',
+    6: '-шы',
+    7: '-ші',
+    8: '-ші',
+    9: '-шы',
+    10: '-шы',
+    20: '-шы',
+    30: '-шы',
+    40: '-шы',
+    50: '-ші',
+    60: '-шы',
+    70: '-ші',
+    80: '-ші',
+    90: '-шы',
+    100: '-ші'
+};
+
+moment.defineLocale('kk', {
+    months : 'қаңтар_ақпан_наурыз_сәуір_мамыр_маусым_шілде_тамыз_қыркүйек_қазан_қараша_желтоқсан'.split('_'),
+    monthsShort : 'қаң_ақп_нау_сәу_мам_мау_шіл_там_қыр_қаз_қар_жел'.split('_'),
+    weekdays : 'жексенбі_дүйсенбі_сейсенбі_сәрсенбі_бейсенбі_жұма_сенбі'.split('_'),
+    weekdaysShort : 'жек_дүй_сей_сәр_бей_жұм_сен'.split('_'),
+    weekdaysMin : 'жк_дй_сй_ср_бй_жм_сн'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[Бүгін сағат] LT',
+        nextDay : '[Ертең сағат] LT',
+        nextWeek : 'dddd [сағат] LT',
+        lastDay : '[Кеше сағат] LT',
+        lastWeek : '[Өткен аптаның] dddd [сағат] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s ішінде',
+        past : '%s бұрын',
+        s : 'бірнеше секунд',
+        m : 'бір минут',
+        mm : '%d минут',
+        h : 'бір сағат',
+        hh : '%d сағат',
+        d : 'бір күн',
+        dd : '%d күн',
+        M : 'бір ай',
+        MM : '%d ай',
+        y : 'бір жыл',
+        yy : '%d жыл'
+    },
+    ordinalParse: /\d{1,2}-(ші|шы)/,
+    ordinal : function (number) {
+        var a = number % 10,
+            b = number >= 100 ? 100 : null;
+        return number + (suffixes$1[number] || suffixes$1[a] || suffixes$1[b]);
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Cambodian [km]
+//! author : Kruy Vanna : https://github.com/kruyvanna
+
+moment.defineLocale('km', {
+    months: 'មករា_កុម្ភៈ_មីនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ'.split('_'),
+    monthsShort: 'មករា_កុម្ភៈ_មីនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ'.split('_'),
+    weekdays: 'អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍'.split('_'),
+    weekdaysShort: 'អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍'.split('_'),
+    weekdaysMin: 'អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍'.split('_'),
+    longDateFormat: {
+        LT: 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L: 'DD/MM/YYYY',
+        LL: 'D MMMM YYYY',
+        LLL: 'D MMMM YYYY HH:mm',
+        LLLL: 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar: {
+        sameDay: '[ថ្ងៃនេះ ម៉ោង] LT',
+        nextDay: '[ស្អែក ម៉ោង] LT',
+        nextWeek: 'dddd [ម៉ោង] LT',
+        lastDay: '[ម្សិលមិញ ម៉ោង] LT',
+        lastWeek: 'dddd [សប្តាហ៍មុន] [ម៉ោង] LT',
+        sameElse: 'L'
+    },
+    relativeTime: {
+        future: '%sទៀត',
+        past: '%sមុន',
+        s: 'ប៉ុន្មានវិនាទី',
+        m: 'មួយនាទី',
+        mm: '%d នាទី',
+        h: 'មួយម៉ោង',
+        hh: '%d ម៉ោង',
+        d: 'មួយថ្ងៃ',
+        dd: '%d ថ្ងៃ',
+        M: 'មួយខែ',
+        MM: '%d ខែ',
+        y: 'មួយឆ្នាំ',
+        yy: '%d ឆ្នាំ'
+    },
+    week: {
+        dow: 1, // Monday is the first day of the week.
+        doy: 4 // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Korean [ko]
+//! author : Kyungwook, Park : https://github.com/kyungw00k
+//! author : Jeeeyul Lee <jeeeyul@gmail.com>
+
+moment.defineLocale('ko', {
+    months : '1ì›”_2ì›”_3ì›”_4ì›”_5ì›”_6ì›”_7ì›”_8ì›”_9ì›”_10ì›”_11ì›”_12ì›”'.split('_'),
+    monthsShort : '1ì›”_2ì›”_3ì›”_4ì›”_5ì›”_6ì›”_7ì›”_8ì›”_9ì›”_10ì›”_11ì›”_12ì›”'.split('_'),
+    weekdays : '일요일_월요일_화요일_수요일_목요일_금요일_토요일'.split('_'),
+    weekdaysShort : '일_월_화_수_목_금_토'.split('_'),
+    weekdaysMin : '일_월_화_수_목_금_토'.split('_'),
+    longDateFormat : {
+        LT : 'A h시 m분',
+        LTS : 'A h시 m분 s초',
+        L : 'YYYY.MM.DD',
+        LL : 'YYYY년 MMMM D일',
+        LLL : 'YYYY년 MMMM D일 A h시 m분',
+        LLLL : 'YYYY년 MMMM D일 dddd A h시 m분'
+    },
+    calendar : {
+        sameDay : '오늘 LT',
+        nextDay : '내일 LT',
+        nextWeek : 'dddd LT',
+        lastDay : '어제 LT',
+        lastWeek : '지난주 dddd LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s 후',
+        past : '%s ì „',
+        s : '몇 초',
+        ss : '%dì´ˆ',
+        m : '일분',
+        mm : '%dë¶„',
+        h : '한 시간',
+        hh : '%d시간',
+        d : '하루',
+        dd : '%d일',
+        M : '한 달',
+        MM : '%d달',
+        y : '일 년',
+        yy : '%dë…„'
+    },
+    ordinalParse : /\d{1,2}일/,
+    ordinal : '%d일',
+    meridiemParse : /오전|오후/,
+    isPM : function (token) {
+        return token === '오후';
+    },
+    meridiem : function (hour, minute, isUpper) {
+        return hour < 12 ? '오전' : '오후';
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Kyrgyz [ky]
+//! author : Chyngyz Arystan uulu : https://github.com/chyngyz
+
+
+var suffixes$2 = {
+    0: '-чү',
+    1: '-чи',
+    2: '-чи',
+    3: '-чү',
+    4: '-чү',
+    5: '-чи',
+    6: '-чы',
+    7: '-чи',
+    8: '-чи',
+    9: '-чу',
+    10: '-чу',
+    20: '-чы',
+    30: '-чу',
+    40: '-чы',
+    50: '-чү',
+    60: '-чы',
+    70: '-чи',
+    80: '-чи',
+    90: '-чу',
+    100: '-чү'
+};
+
+moment.defineLocale('ky', {
+    months : 'январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь'.split('_'),
+    monthsShort : 'янв_фев_март_апр_май_июнь_июль_авг_сен_окт_ноя_дек'.split('_'),
+    weekdays : 'Жекшемби_Дүйшөмбү_Шейшемби_Шаршемби_Бейшемби_Жума_Ишемби'.split('_'),
+    weekdaysShort : 'Жек_Дүй_Шей_Шар_Бей_Жум_Ише'.split('_'),
+    weekdaysMin : 'Жк_Дй_Шй_Шр_Бй_Жм_Иш'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[Бүгүн саат] LT',
+        nextDay : '[Эртең саат] LT',
+        nextWeek : 'dddd [саат] LT',
+        lastDay : '[Кече саат] LT',
+        lastWeek : '[Өткен аптанын] dddd [күнү] [саат] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s ичинде',
+        past : '%s мурун',
+        s : 'бирнече секунд',
+        m : 'бир мүнөт',
+        mm : '%d мүнөт',
+        h : 'бир саат',
+        hh : '%d саат',
+        d : 'бир күн',
+        dd : '%d күн',
+        M : 'бир ай',
+        MM : '%d ай',
+        y : 'бир жыл',
+        yy : '%d жыл'
+    },
+    ordinalParse: /\d{1,2}-(чи|чы|чү|чу)/,
+    ordinal : function (number) {
+        var a = number % 10,
+            b = number >= 100 ? 100 : null;
+        return number + (suffixes$2[number] || suffixes$2[a] || suffixes$2[b]);
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Luxembourgish [lb]
+//! author : mweimerskirch : https://github.com/mweimerskirch
+//! author : David Raison : https://github.com/kwisatz
+
+function processRelativeTime$3(number, withoutSuffix, key, isFuture) {
+    var format = {
+        'm': ['eng Minutt', 'enger Minutt'],
+        'h': ['eng Stonn', 'enger Stonn'],
+        'd': ['een Dag', 'engem Dag'],
+        'M': ['ee Mount', 'engem Mount'],
+        'y': ['ee Joer', 'engem Joer']
+    };
+    return withoutSuffix ? format[key][0] : format[key][1];
+}
+function processFutureTime(string) {
+    var number = string.substr(0, string.indexOf(' '));
+    if (eifelerRegelAppliesToNumber(number)) {
+        return 'a ' + string;
+    }
+    return 'an ' + string;
+}
+function processPastTime(string) {
+    var number = string.substr(0, string.indexOf(' '));
+    if (eifelerRegelAppliesToNumber(number)) {
+        return 'viru ' + string;
+    }
+    return 'virun ' + string;
+}
+/**
+ * Returns true if the word before the given number loses the '-n' ending.
+ * e.g. 'an 10 Deeg' but 'a 5 Deeg'
+ *
+ * @param number {integer}
+ * @returns {boolean}
+ */
+function eifelerRegelAppliesToNumber(number) {
+    number = parseInt(number, 10);
+    if (isNaN(number)) {
+        return false;
+    }
+    if (number < 0) {
+        // Negative Number --> always true
+        return true;
+    } else if (number < 10) {
+        // Only 1 digit
+        if (4 <= number && number <= 7) {
+            return true;
+        }
+        return false;
+    } else if (number < 100) {
+        // 2 digits
+        var lastDigit = number % 10, firstDigit = number / 10;
+        if (lastDigit === 0) {
+            return eifelerRegelAppliesToNumber(firstDigit);
+        }
+        return eifelerRegelAppliesToNumber(lastDigit);
+    } else if (number < 10000) {
+        // 3 or 4 digits --> recursively check first digit
+        while (number >= 10) {
+            number = number / 10;
+        }
+        return eifelerRegelAppliesToNumber(number);
+    } else {
+        // Anything larger than 4 digits: recursively check first n-3 digits
+        number = number / 1000;
+        return eifelerRegelAppliesToNumber(number);
+    }
+}
+
+moment.defineLocale('lb', {
+    months: 'Januar_Februar_Mäerz_Abrëll_Mee_Juni_Juli_August_September_Oktober_November_Dezember'.split('_'),
+    monthsShort: 'Jan._Febr._Mrz._Abr._Mee_Jun._Jul._Aug._Sept._Okt._Nov._Dez.'.split('_'),
+    monthsParseExact : true,
+    weekdays: 'Sonndeg_Méindeg_Dënschdeg_Mëttwoch_Donneschdeg_Freideg_Samschdeg'.split('_'),
+    weekdaysShort: 'So._Mé._Dë._Më._Do._Fr._Sa.'.split('_'),
+    weekdaysMin: 'So_Mé_Dë_Më_Do_Fr_Sa'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat: {
+        LT: 'H:mm [Auer]',
+        LTS: 'H:mm:ss [Auer]',
+        L: 'DD.MM.YYYY',
+        LL: 'D. MMMM YYYY',
+        LLL: 'D. MMMM YYYY H:mm [Auer]',
+        LLLL: 'dddd, D. MMMM YYYY H:mm [Auer]'
+    },
+    calendar: {
+        sameDay: '[Haut um] LT',
+        sameElse: 'L',
+        nextDay: '[Muer um] LT',
+        nextWeek: 'dddd [um] LT',
+        lastDay: '[Gëschter um] LT',
+        lastWeek: function () {
+            // Different date string for 'Dënschdeg' (Tuesday) and 'Donneschdeg' (Thursday) due to phonological rule
+            switch (this.day()) {
+                case 2:
+                case 4:
+                    return '[Leschten] dddd [um] LT';
+                default:
+                    return '[Leschte] dddd [um] LT';
+            }
+        }
+    },
+    relativeTime : {
+        future : processFutureTime,
+        past : processPastTime,
+        s : 'e puer Sekonnen',
+        m : processRelativeTime$3,
+        mm : '%d Minutten',
+        h : processRelativeTime$3,
+        hh : '%d Stonnen',
+        d : processRelativeTime$3,
+        dd : '%d Deeg',
+        M : processRelativeTime$3,
+        MM : '%d Méint',
+        y : processRelativeTime$3,
+        yy : '%d Joer'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal: '%d.',
+    week: {
+        dow: 1, // Monday is the first day of the week.
+        doy: 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Lao [lo]
+//! author : Ryan Hart : https://github.com/ryanhart2
+
+moment.defineLocale('lo', {
+    months : 'ມັງກອນ_ກຸມພາ_ມີນາ_ເມສາ_ພຶດສະພາ_ມິຖຸນາ_ກໍລະກົດ_ສິງຫາ_ກັນຍາ_ຕຸລາ_ພະຈິກ_ທັນວາ'.split('_'),
+    monthsShort : 'ມັງກອນ_ກຸມພາ_ມີນາ_ເມສາ_ພຶດສະພາ_ມິຖຸນາ_ກໍລະກົດ_ສິງຫາ_ກັນຍາ_ຕຸລາ_ພະຈິກ_ທັນວາ'.split('_'),
+    weekdays : 'ອາທິດ_ຈັນ_ອັງຄານ_ພຸດ_ພະຫັດ_ສຸກ_ເສົາ'.split('_'),
+    weekdaysShort : 'ທິດ_ຈັນ_ອັງຄານ_ພຸດ_ພະຫັດ_ສຸກ_ເສົາ'.split('_'),
+    weekdaysMin : 'ທ_ຈ_ອຄ_ພ_ພຫ_ສກ_ສ'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'ວັນdddd D MMMM YYYY HH:mm'
+    },
+    meridiemParse: /ຕອນເຊົ້າ|ຕອນແລງ/,
+    isPM: function (input) {
+        return input === 'ຕອນແລງ';
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return 'ຕອນເຊົ້າ';
+        } else {
+            return 'ຕອນແລງ';
+        }
+    },
+    calendar : {
+        sameDay : '[ມື້ນີ້ເວລາ] LT',
+        nextDay : '[ມື້ອື່ນເວລາ] LT',
+        nextWeek : '[ວັນ]dddd[ໜ້າເວລາ] LT',
+        lastDay : '[ມື້ວານນີ້ເວລາ] LT',
+        lastWeek : '[ວັນ]dddd[ແລ້ວນີ້ເວລາ] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'ອີກ %s',
+        past : '%sຜ່ານມາ',
+        s : 'ບໍ່ເທົ່າໃດວິນາທີ',
+        m : '1 ນາທີ',
+        mm : '%d ນາທີ',
+        h : '1 ຊົ່ວໂມງ',
+        hh : '%d ຊົ່ວໂມງ',
+        d : '1 ມື້',
+        dd : '%d ມື້',
+        M : '1 ເດືອນ',
+        MM : '%d ເດືອນ',
+        y : '1 ປີ',
+        yy : '%d ປີ'
+    },
+    ordinalParse: /(ທີ່)\d{1,2}/,
+    ordinal : function (number) {
+        return 'ທີ່' + number;
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Lithuanian [lt]
+//! author : Mindaugas Mozūras : https://github.com/mmozuras
+
+var units = {
+    'm' : 'minutÄ—_minutÄ—s_minutÄ™',
+    'mm': 'minutės_minučių_minutes',
+    'h' : 'valanda_valandos_valandÄ…',
+    'hh': 'valandos_valandų_valandas',
+    'd' : 'diena_dienos_dienÄ…',
+    'dd': 'dienos_dienų_dienas',
+    'M' : 'mėnuo_mėnesio_mėnesį',
+    'MM': 'mėnesiai_mėnesių_mėnesius',
+    'y' : 'metai_metų_metus',
+    'yy': 'metai_metų_metus'
+};
+function translateSeconds(number, withoutSuffix, key, isFuture) {
+    if (withoutSuffix) {
+        return 'kelios sekundÄ—s';
+    } else {
+        return isFuture ? 'kelių sekundžių' : 'kelias sekundes';
+    }
+}
+function translateSingular(number, withoutSuffix, key, isFuture) {
+    return withoutSuffix ? forms(key)[0] : (isFuture ? forms(key)[1] : forms(key)[2]);
+}
+function special(number) {
+    return number % 10 === 0 || (number > 10 && number < 20);
+}
+function forms(key) {
+    return units[key].split('_');
+}
+function translate$6(number, withoutSuffix, key, isFuture) {
+    var result = number + ' ';
+    if (number === 1) {
+        return result + translateSingular(number, withoutSuffix, key[0], isFuture);
+    } else if (withoutSuffix) {
+        return result + (special(number) ? forms(key)[1] : forms(key)[0]);
+    } else {
+        if (isFuture) {
+            return result + forms(key)[1];
+        } else {
+            return result + (special(number) ? forms(key)[1] : forms(key)[2]);
+        }
+    }
+}
+moment.defineLocale('lt', {
+    months : {
+        format: 'sausio_vasario_kovo_balandžio_gegužės_birželio_liepos_rugpjūčio_rugsėjo_spalio_lapkričio_gruodžio'.split('_'),
+        standalone: 'sausis_vasaris_kovas_balandis_gegužė_birželis_liepa_rugpjūtis_rugsėjis_spalis_lapkritis_gruodis'.split('_'),
+        isFormat: /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?|MMMM?(\[[^\[\]]*\]|\s)+D[oD]?/
+    },
+    monthsShort : 'sau_vas_kov_bal_geg_bir_lie_rgp_rgs_spa_lap_grd'.split('_'),
+    weekdays : {
+        format: 'sekmadienį_pirmadienį_antradienį_trečiadienį_ketvirtadienį_penktadienį_šeštadienį'.split('_'),
+        standalone: 'sekmadienis_pirmadienis_antradienis_trečiadienis_ketvirtadienis_penktadienis_šeštadienis'.split('_'),
+        isFormat: /dddd HH:mm/
+    },
+    weekdaysShort : 'Sek_Pir_Ant_Tre_Ket_Pen_Šeš'.split('_'),
+    weekdaysMin : 'S_P_A_T_K_Pn_Å '.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'YYYY-MM-DD',
+        LL : 'YYYY [m.] MMMM D [d.]',
+        LLL : 'YYYY [m.] MMMM D [d.], HH:mm [val.]',
+        LLLL : 'YYYY [m.] MMMM D [d.], dddd, HH:mm [val.]',
+        l : 'YYYY-MM-DD',
+        ll : 'YYYY [m.] MMMM D [d.]',
+        lll : 'YYYY [m.] MMMM D [d.], HH:mm [val.]',
+        llll : 'YYYY [m.] MMMM D [d.], ddd, HH:mm [val.]'
+    },
+    calendar : {
+        sameDay : '[Å iandien] LT',
+        nextDay : '[Rytoj] LT',
+        nextWeek : 'dddd LT',
+        lastDay : '[Vakar] LT',
+        lastWeek : '[Praėjusį] dddd LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'po %s',
+        past : 'prieš %s',
+        s : translateSeconds,
+        m : translateSingular,
+        mm : translate$6,
+        h : translateSingular,
+        hh : translate$6,
+        d : translateSingular,
+        dd : translate$6,
+        M : translateSingular,
+        MM : translate$6,
+        y : translateSingular,
+        yy : translate$6
+    },
+    ordinalParse: /\d{1,2}-oji/,
+    ordinal : function (number) {
+        return number + '-oji';
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Latvian [lv]
+//! author : Kristaps Karlsons : https://github.com/skakri
+//! author : Jānis Elmeris : https://github.com/JanisE
+
+var units$1 = {
+    'm': 'minūtes_minūtēm_minūte_minūtes'.split('_'),
+    'mm': 'minūtes_minūtēm_minūte_minūtes'.split('_'),
+    'h': 'stundas_stundām_stunda_stundas'.split('_'),
+    'hh': 'stundas_stundām_stunda_stundas'.split('_'),
+    'd': 'dienas_dienām_diena_dienas'.split('_'),
+    'dd': 'dienas_dienām_diena_dienas'.split('_'),
+    'M': 'mēneša_mēnešiem_mēnesis_mēneši'.split('_'),
+    'MM': 'mēneša_mēnešiem_mēnesis_mēneši'.split('_'),
+    'y': 'gada_gadiem_gads_gadi'.split('_'),
+    'yy': 'gada_gadiem_gads_gadi'.split('_')
+};
+/**
+ * @param withoutSuffix boolean true = a length of time; false = before/after a period of time.
+ */
+function format(forms, number, withoutSuffix) {
+    if (withoutSuffix) {
+        // E.g. "21 minūte", "3 minūtes".
+        return number % 10 === 1 && number % 100 !== 11 ? forms[2] : forms[3];
+    } else {
+        // E.g. "21 minūtes" as in "pēc 21 minūtes".
+        // E.g. "3 minūtēm" as in "pēc 3 minūtēm".
+        return number % 10 === 1 && number % 100 !== 11 ? forms[0] : forms[1];
+    }
+}
+function relativeTimeWithPlural$1(number, withoutSuffix, key) {
+    return number + ' ' + format(units$1[key], number, withoutSuffix);
+}
+function relativeTimeWithSingular(number, withoutSuffix, key) {
+    return format(units$1[key], number, withoutSuffix);
+}
+function relativeSeconds(number, withoutSuffix) {
+    return withoutSuffix ? 'dažas sekundes' : 'dažām sekundēm';
+}
+
+moment.defineLocale('lv', {
+    months : 'janvāris_februāris_marts_aprīlis_maijs_jūnijs_jūlijs_augusts_septembris_oktobris_novembris_decembris'.split('_'),
+    monthsShort : 'jan_feb_mar_apr_mai_jūn_jūl_aug_sep_okt_nov_dec'.split('_'),
+    weekdays : 'svētdiena_pirmdiena_otrdiena_trešdiena_ceturtdiena_piektdiena_sestdiena'.split('_'),
+    weekdaysShort : 'Sv_P_O_T_C_Pk_S'.split('_'),
+    weekdaysMin : 'Sv_P_O_T_C_Pk_S'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY.',
+        LL : 'YYYY. [gada] D. MMMM',
+        LLL : 'YYYY. [gada] D. MMMM, HH:mm',
+        LLLL : 'YYYY. [gada] D. MMMM, dddd, HH:mm'
+    },
+    calendar : {
+        sameDay : '[Å odien pulksten] LT',
+        nextDay : '[Rīt pulksten] LT',
+        nextWeek : 'dddd [pulksten] LT',
+        lastDay : '[Vakar pulksten] LT',
+        lastWeek : '[Pagājušā] dddd [pulksten] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'pēc %s',
+        past : 'pirms %s',
+        s : relativeSeconds,
+        m : relativeTimeWithSingular,
+        mm : relativeTimeWithPlural$1,
+        h : relativeTimeWithSingular,
+        hh : relativeTimeWithPlural$1,
+        d : relativeTimeWithSingular,
+        dd : relativeTimeWithPlural$1,
+        M : relativeTimeWithSingular,
+        MM : relativeTimeWithPlural$1,
+        y : relativeTimeWithSingular,
+        yy : relativeTimeWithPlural$1
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Montenegrin [me]
+//! author : Miodrag Nikač <miodrag@restartit.me> : https://github.com/miodragnikac
+
+var translator = {
+    words: { //Different grammatical cases
+        m: ['jedan minut', 'jednog minuta'],
+        mm: ['minut', 'minuta', 'minuta'],
+        h: ['jedan sat', 'jednog sata'],
+        hh: ['sat', 'sata', 'sati'],
+        dd: ['dan', 'dana', 'dana'],
+        MM: ['mjesec', 'mjeseca', 'mjeseci'],
+        yy: ['godina', 'godine', 'godina']
+    },
+    correctGrammaticalCase: function (number, wordKey) {
+        return number === 1 ? wordKey[0] : (number >= 2 && number <= 4 ? wordKey[1] : wordKey[2]);
+    },
+    translate: function (number, withoutSuffix, key) {
+        var wordKey = translator.words[key];
+        if (key.length === 1) {
+            return withoutSuffix ? wordKey[0] : wordKey[1];
+        } else {
+            return number + ' ' + translator.correctGrammaticalCase(number, wordKey);
+        }
+    }
+};
+
+moment.defineLocale('me', {
+    months: 'januar_februar_mart_april_maj_jun_jul_avgust_septembar_oktobar_novembar_decembar'.split('_'),
+    monthsShort: 'jan._feb._mar._apr._maj_jun_jul_avg._sep._okt._nov._dec.'.split('_'),
+    monthsParseExact : true,
+    weekdays: 'nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota'.split('_'),
+    weekdaysShort: 'ned._pon._uto._sri._čet._pet._sub.'.split('_'),
+    weekdaysMin: 'ne_po_ut_sr_če_pe_su'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat: {
+        LT: 'H:mm',
+        LTS : 'H:mm:ss',
+        L: 'DD.MM.YYYY',
+        LL: 'D. MMMM YYYY',
+        LLL: 'D. MMMM YYYY H:mm',
+        LLLL: 'dddd, D. MMMM YYYY H:mm'
+    },
+    calendar: {
+        sameDay: '[danas u] LT',
+        nextDay: '[sjutra u] LT',
+
+        nextWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[u] [nedjelju] [u] LT';
+                case 3:
+                    return '[u] [srijedu] [u] LT';
+                case 6:
+                    return '[u] [subotu] [u] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[u] dddd [u] LT';
+            }
+        },
+        lastDay  : '[juče u] LT',
+        lastWeek : function () {
+            var lastWeekDays = [
+                '[prošle] [nedjelje] [u] LT',
+                '[prošlog] [ponedjeljka] [u] LT',
+                '[prošlog] [utorka] [u] LT',
+                '[prošle] [srijede] [u] LT',
+                '[prošlog] [četvrtka] [u] LT',
+                '[prošlog] [petka] [u] LT',
+                '[prošle] [subote] [u] LT'
+            ];
+            return lastWeekDays[this.day()];
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'za %s',
+        past   : 'prije %s',
+        s      : 'nekoliko sekundi',
+        m      : translator.translate,
+        mm     : translator.translate,
+        h      : translator.translate,
+        hh     : translator.translate,
+        d      : 'dan',
+        dd     : translator.translate,
+        M      : 'mjesec',
+        MM     : translator.translate,
+        y      : 'godinu',
+        yy     : translator.translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Maori [mi]
+//! author : John Corrigan <robbiecloset@gmail.com> : https://github.com/johnideal
+
+moment.defineLocale('mi', {
+    months: 'Kohi-tāte_Hui-tanguru_Poutū-te-rangi_Paenga-whāwhā_Haratua_Pipiri_Hōngoingoi_Here-turi-kōkā_Mahuru_Whiringa-ā-nuku_Whiringa-ā-rangi_Hakihea'.split('_'),
+    monthsShort: 'Kohi_Hui_Pou_Pae_Hara_Pipi_Hōngoi_Here_Mahu_Whi-nu_Whi-ra_Haki'.split('_'),
+    monthsRegex: /(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,
+    monthsStrictRegex: /(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,
+    monthsShortRegex: /(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,
+    monthsShortStrictRegex: /(?:['a-z\u0101\u014D\u016B]+\-?){1,2}/i,
+    weekdays: 'Rātapu_Mane_Tūrei_Wenerei_Tāite_Paraire_Hātarei'.split('_'),
+    weekdaysShort: 'Ta_Ma_Tū_We_Tāi_Pa_Hā'.split('_'),
+    weekdaysMin: 'Ta_Ma_Tū_We_Tāi_Pa_Hā'.split('_'),
+    longDateFormat: {
+        LT: 'HH:mm',
+        LTS: 'HH:mm:ss',
+        L: 'DD/MM/YYYY',
+        LL: 'D MMMM YYYY',
+        LLL: 'D MMMM YYYY [i] HH:mm',
+        LLLL: 'dddd, D MMMM YYYY [i] HH:mm'
+    },
+    calendar: {
+        sameDay: '[i teie mahana, i] LT',
+        nextDay: '[apopo i] LT',
+        nextWeek: 'dddd [i] LT',
+        lastDay: '[inanahi i] LT',
+        lastWeek: 'dddd [whakamutunga i] LT',
+        sameElse: 'L'
+    },
+    relativeTime: {
+        future: 'i roto i %s',
+        past: '%s i mua',
+        s: 'te hēkona ruarua',
+        m: 'he meneti',
+        mm: '%d meneti',
+        h: 'te haora',
+        hh: '%d haora',
+        d: 'he ra',
+        dd: '%d ra',
+        M: 'he marama',
+        MM: '%d marama',
+        y: 'he tau',
+        yy: '%d tau'
+    },
+    ordinalParse: /\d{1,2}º/,
+    ordinal: '%dº',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Macedonian [mk]
+//! author : Borislav Mickov : https://github.com/B0k0
+
+moment.defineLocale('mk', {
+    months : 'јануари_февруари_март_април_мај_јуни_јули_август_септември_октомври_ноември_декември'.split('_'),
+    monthsShort : 'јан_фев_мар_апр_мај_јун_јул_авг_сеп_окт_ное_дек'.split('_'),
+    weekdays : 'недела_понеделник_вторник_среда_четврток_петок_сабота'.split('_'),
+    weekdaysShort : 'нед_пон_вто_сре_чет_пет_саб'.split('_'),
+    weekdaysMin : 'нe_пo_вт_ср_че_пе_сa'.split('_'),
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'D.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY H:mm',
+        LLLL : 'dddd, D MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay : '[Денес во] LT',
+        nextDay : '[Утре во] LT',
+        nextWeek : '[Во] dddd [во] LT',
+        lastDay : '[Вчера во] LT',
+        lastWeek : function () {
+            switch (this.day()) {
+                case 0:
+                case 3:
+                case 6:
+                    return '[Изминатата] dddd [во] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[Изминатиот] dddd [во] LT';
+            }
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'после %s',
+        past : 'пред %s',
+        s : 'неколку секунди',
+        m : 'минута',
+        mm : '%d минути',
+        h : 'час',
+        hh : '%d часа',
+        d : 'ден',
+        dd : '%d дена',
+        M : 'месец',
+        MM : '%d месеци',
+        y : 'година',
+        yy : '%d години'
+    },
+    ordinalParse: /\d{1,2}-(ев|ен|ти|ви|ри|ми)/,
+    ordinal : function (number) {
+        var lastDigit = number % 10,
+            last2Digits = number % 100;
+        if (number === 0) {
+            return number + '-ев';
+        } else if (last2Digits === 0) {
+            return number + '-ен';
+        } else if (last2Digits > 10 && last2Digits < 20) {
+            return number + '-ти';
+        } else if (lastDigit === 1) {
+            return number + '-ви';
+        } else if (lastDigit === 2) {
+            return number + '-ри';
+        } else if (lastDigit === 7 || lastDigit === 8) {
+            return number + '-ми';
+        } else {
+            return number + '-ти';
+        }
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Malayalam [ml]
+//! author : Floyd Pink : https://github.com/floydpink
+
+moment.defineLocale('ml', {
+    months : 'ജനുവരി_ഫെബ്രുവരി_മാർച്ച്_ഏപ്രിൽ_മേയ്_ജൂൺ_ജൂലൈ_ഓഗസ്റ്റ്_സെപ്റ്റംബർ_ഒക്ടോബർ_നവംബർ_ഡിസംബർ'.split('_'),
+    monthsShort : 'ജനു._ഫെബ്രു._മാർ._ഏപ്രി._മേയ്_ജൂൺ_ജൂലൈ._ഓഗ._സെപ്റ്റ._ഒക്ടോ._നവം._ഡിസം.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'ഞായറാഴ്ച_തിങ്കളാഴ്ച_ചൊവ്വാഴ്ച_ബുധനാഴ്ച_വ്യാഴാഴ്ച_വെള്ളിയാഴ്ച_ശനിയാഴ്ച'.split('_'),
+    weekdaysShort : 'ഞായർ_തിങ്കൾ_ചൊവ്വ_ബുധൻ_വ്യാഴം_വെള്ളി_ശനി'.split('_'),
+    weekdaysMin : 'ഞാ_തി_ചൊ_ബു_വ്യാ_വെ_ശ'.split('_'),
+    longDateFormat : {
+        LT : 'A h:mm -നു',
+        LTS : 'A h:mm:ss -നു',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, A h:mm -നു',
+        LLLL : 'dddd, D MMMM YYYY, A h:mm -നു'
+    },
+    calendar : {
+        sameDay : '[ഇന്ന്] LT',
+        nextDay : '[നാളെ] LT',
+        nextWeek : 'dddd, LT',
+        lastDay : '[ഇന്നലെ] LT',
+        lastWeek : '[കഴിഞ്ഞ] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s കഴിഞ്ഞ്',
+        past : '%s മുൻപ്',
+        s : 'അൽപ നിമിഷങ്ങൾ',
+        m : 'ഒരു മിനിറ്റ്',
+        mm : '%d മിനിറ്റ്',
+        h : 'ഒരു മണിക്കൂർ',
+        hh : '%d മണിക്കൂർ',
+        d : 'ഒരു ദിവസം',
+        dd : '%d ദിവസം',
+        M : 'ഒരു മാസം',
+        MM : '%d മാസം',
+        y : 'ഒരു വർഷം',
+        yy : '%d വർഷം'
+    },
+    meridiemParse: /രാത്രി|രാവിലെ|ഉച്ച കഴിഞ്ഞ്|വൈകുന്നേരം|രാത്രി/i,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if ((meridiem === 'രാത്രി' && hour >= 4) ||
+                meridiem === 'ഉച്ച കഴിഞ്ഞ്' ||
+                meridiem === 'വൈകുന്നേരം') {
+            return hour + 12;
+        } else {
+            return hour;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'രാത്രി';
+        } else if (hour < 12) {
+            return 'രാവിലെ';
+        } else if (hour < 17) {
+            return 'ഉച്ച കഴിഞ്ഞ്';
+        } else if (hour < 20) {
+            return 'വൈകുന്നേരം';
+        } else {
+            return 'രാത്രി';
+        }
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Marathi [mr]
+//! author : Harshad Kale : https://github.com/kalehv
+//! author : Vivek Athalye : https://github.com/vnathalye
+
+var symbolMap$7 = {
+    '1': '१',
+    '2': '२',
+    '3': '३',
+    '4': '४',
+    '5': '५',
+    '6': '६',
+    '7': '७',
+    '8': '८',
+    '9': '९',
+    '0': '०'
+};
+var numberMap$6 = {
+    '१': '1',
+    '२': '2',
+    '३': '3',
+    '४': '4',
+    '५': '5',
+    '६': '6',
+    '७': '7',
+    '८': '8',
+    '९': '9',
+    '०': '0'
+};
+
+function relativeTimeMr(number, withoutSuffix, string, isFuture)
+{
+    var output = '';
+    if (withoutSuffix) {
+        switch (string) {
+            case 's': output = 'काही सेकंद'; break;
+            case 'm': output = 'एक मिनिट'; break;
+            case 'mm': output = '%d मिनिटे'; break;
+            case 'h': output = 'एक तास'; break;
+            case 'hh': output = '%d तास'; break;
+            case 'd': output = 'एक दिवस'; break;
+            case 'dd': output = '%d दिवस'; break;
+            case 'M': output = 'एक महिना'; break;
+            case 'MM': output = '%d महिने'; break;
+            case 'y': output = 'एक वर्ष'; break;
+            case 'yy': output = '%d वर्षे'; break;
+        }
+    }
+    else {
+        switch (string) {
+            case 's': output = 'काही सेकंदां'; break;
+            case 'm': output = 'एका मिनिटा'; break;
+            case 'mm': output = '%d मिनिटां'; break;
+            case 'h': output = 'एका तासा'; break;
+            case 'hh': output = '%d तासां'; break;
+            case 'd': output = 'एका दिवसा'; break;
+            case 'dd': output = '%d दिवसां'; break;
+            case 'M': output = 'एका महिन्या'; break;
+            case 'MM': output = '%d महिन्यां'; break;
+            case 'y': output = 'एका वर्षा'; break;
+            case 'yy': output = '%d वर्षां'; break;
+        }
+    }
+    return output.replace(/%d/i, number);
+}
+
+moment.defineLocale('mr', {
+    months : 'जानेवारी_फेब्रुवारी_मार्च_एप्रिल_मे_जून_जुलै_ऑगस्ट_सप्टेंबर_ऑक्टोबर_नोव्हेंबर_डिसेंबर'.split('_'),
+    monthsShort: 'जाने._फेब्रु._मार्च._एप्रि._मे._जून._जुलै._ऑग._सप्टें._ऑक्टो._नोव्हें._डिसें.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'रविवार_सोमवार_मंगळवार_बुधवार_गुरूवार_शुक्रवार_शनिवार'.split('_'),
+    weekdaysShort : 'रवि_सोम_मंगळ_बुध_गुरू_शुक्र_शनि'.split('_'),
+    weekdaysMin : 'र_सो_मं_बु_गु_शु_श'.split('_'),
+    longDateFormat : {
+        LT : 'A h:mm वाजता',
+        LTS : 'A h:mm:ss वाजता',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, A h:mm वाजता',
+        LLLL : 'dddd, D MMMM YYYY, A h:mm वाजता'
+    },
+    calendar : {
+        sameDay : '[आज] LT',
+        nextDay : '[उद्या] LT',
+        nextWeek : 'dddd, LT',
+        lastDay : '[काल] LT',
+        lastWeek: '[मागील] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future: '%sमध्ये',
+        past: '%sपूर्वी',
+        s: relativeTimeMr,
+        m: relativeTimeMr,
+        mm: relativeTimeMr,
+        h: relativeTimeMr,
+        hh: relativeTimeMr,
+        d: relativeTimeMr,
+        dd: relativeTimeMr,
+        M: relativeTimeMr,
+        MM: relativeTimeMr,
+        y: relativeTimeMr,
+        yy: relativeTimeMr
+    },
+    preparse: function (string) {
+        return string.replace(/[१२३४५६७८९०]/g, function (match) {
+            return numberMap$6[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap$7[match];
+        });
+    },
+    meridiemParse: /रात्री|सकाळी|दुपारी|सायंकाळी/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'रात्री') {
+            return hour < 4 ? hour : hour + 12;
+        } else if (meridiem === 'सकाळी') {
+            return hour;
+        } else if (meridiem === 'दुपारी') {
+            return hour >= 10 ? hour : hour + 12;
+        } else if (meridiem === 'सायंकाळी') {
+            return hour + 12;
+        }
+    },
+    meridiem: function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'रात्री';
+        } else if (hour < 10) {
+            return 'सकाळी';
+        } else if (hour < 17) {
+            return 'दुपारी';
+        } else if (hour < 20) {
+            return 'सायंकाळी';
+        } else {
+            return 'रात्री';
+        }
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Malay [ms-my]
+//! note : DEPRECATED, the correct one is [ms]
+//! author : Weldan Jamili : https://github.com/weldan
+
+moment.defineLocale('ms-my', {
+    months : 'Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember'.split('_'),
+    monthsShort : 'Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis'.split('_'),
+    weekdays : 'Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu'.split('_'),
+    weekdaysShort : 'Ahd_Isn_Sel_Rab_Kha_Jum_Sab'.split('_'),
+    weekdaysMin : 'Ah_Is_Sl_Rb_Km_Jm_Sb'.split('_'),
+    longDateFormat : {
+        LT : 'HH.mm',
+        LTS : 'HH.mm.ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY [pukul] HH.mm',
+        LLLL : 'dddd, D MMMM YYYY [pukul] HH.mm'
+    },
+    meridiemParse: /pagi|tengahari|petang|malam/,
+    meridiemHour: function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'pagi') {
+            return hour;
+        } else if (meridiem === 'tengahari') {
+            return hour >= 11 ? hour : hour + 12;
+        } else if (meridiem === 'petang' || meridiem === 'malam') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 11) {
+            return 'pagi';
+        } else if (hours < 15) {
+            return 'tengahari';
+        } else if (hours < 19) {
+            return 'petang';
+        } else {
+            return 'malam';
+        }
+    },
+    calendar : {
+        sameDay : '[Hari ini pukul] LT',
+        nextDay : '[Esok pukul] LT',
+        nextWeek : 'dddd [pukul] LT',
+        lastDay : '[Kelmarin pukul] LT',
+        lastWeek : 'dddd [lepas pukul] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'dalam %s',
+        past : '%s yang lepas',
+        s : 'beberapa saat',
+        m : 'seminit',
+        mm : '%d minit',
+        h : 'sejam',
+        hh : '%d jam',
+        d : 'sehari',
+        dd : '%d hari',
+        M : 'sebulan',
+        MM : '%d bulan',
+        y : 'setahun',
+        yy : '%d tahun'
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Malay [ms]
+//! author : Weldan Jamili : https://github.com/weldan
+
+moment.defineLocale('ms', {
+    months : 'Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember'.split('_'),
+    monthsShort : 'Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis'.split('_'),
+    weekdays : 'Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu'.split('_'),
+    weekdaysShort : 'Ahd_Isn_Sel_Rab_Kha_Jum_Sab'.split('_'),
+    weekdaysMin : 'Ah_Is_Sl_Rb_Km_Jm_Sb'.split('_'),
+    longDateFormat : {
+        LT : 'HH.mm',
+        LTS : 'HH.mm.ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY [pukul] HH.mm',
+        LLLL : 'dddd, D MMMM YYYY [pukul] HH.mm'
+    },
+    meridiemParse: /pagi|tengahari|petang|malam/,
+    meridiemHour: function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'pagi') {
+            return hour;
+        } else if (meridiem === 'tengahari') {
+            return hour >= 11 ? hour : hour + 12;
+        } else if (meridiem === 'petang' || meridiem === 'malam') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 11) {
+            return 'pagi';
+        } else if (hours < 15) {
+            return 'tengahari';
+        } else if (hours < 19) {
+            return 'petang';
+        } else {
+            return 'malam';
+        }
+    },
+    calendar : {
+        sameDay : '[Hari ini pukul] LT',
+        nextDay : '[Esok pukul] LT',
+        nextWeek : 'dddd [pukul] LT',
+        lastDay : '[Kelmarin pukul] LT',
+        lastWeek : 'dddd [lepas pukul] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'dalam %s',
+        past : '%s yang lepas',
+        s : 'beberapa saat',
+        m : 'seminit',
+        mm : '%d minit',
+        h : 'sejam',
+        hh : '%d jam',
+        d : 'sehari',
+        dd : '%d hari',
+        M : 'sebulan',
+        MM : '%d bulan',
+        y : 'setahun',
+        yy : '%d tahun'
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Burmese [my]
+//! author : Squar team, mysquar.com
+//! author : David Rossellat : https://github.com/gholadr
+//! author : Tin Aung Lin : https://github.com/thanyawzinmin
+
+var symbolMap$8 = {
+    '1': '၁',
+    '2': '၂',
+    '3': '၃',
+    '4': '၄',
+    '5': '၅',
+    '6': '၆',
+    '7': '၇',
+    '8': '၈',
+    '9': '၉',
+    '0': '၀'
+};
+var numberMap$7 = {
+    '၁': '1',
+    '၂': '2',
+    '၃': '3',
+    '၄': '4',
+    '၅': '5',
+    '၆': '6',
+    '၇': '7',
+    '၈': '8',
+    '၉': '9',
+    '၀': '0'
+};
+
+moment.defineLocale('my', {
+    months: 'ဇန်နဝါရီ_ဖေဖော်ဝါရီ_မတ်_ဧပြီ_မေ_ဇွန်_ဇူလိုင်_သြဂုတ်_စက်တင်ဘာ_အောက်တိုဘာ_နိုဝင်ဘာ_ဒီဇင်ဘာ'.split('_'),
+    monthsShort: 'ဇန်_ဖေ_မတ်_ပြီ_မေ_ဇွန်_လိုင်_သြ_စက်_အောက်_နို_ဒီ'.split('_'),
+    weekdays: 'တနင်္ဂနွေ_တနင်္လာ_အင်္ဂါ_ဗုဒ္ဓဟူး_ကြာသပတေး_သောကြာ_စနေ'.split('_'),
+    weekdaysShort: 'နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ'.split('_'),
+    weekdaysMin: 'နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ'.split('_'),
+
+    longDateFormat: {
+        LT: 'HH:mm',
+        LTS: 'HH:mm:ss',
+        L: 'DD/MM/YYYY',
+        LL: 'D MMMM YYYY',
+        LLL: 'D MMMM YYYY HH:mm',
+        LLLL: 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar: {
+        sameDay: '[ယနေ.] LT [မှာ]',
+        nextDay: '[မနက်ဖြန်] LT [မှာ]',
+        nextWeek: 'dddd LT [မှာ]',
+        lastDay: '[မနေ.က] LT [မှာ]',
+        lastWeek: '[ပြီးခဲ့သော] dddd LT [မှာ]',
+        sameElse: 'L'
+    },
+    relativeTime: {
+        future: 'လာမည့် %s မှာ',
+        past: 'လွန်ခဲ့သော %s က',
+        s: 'စက္ကန်.အနည်းငယ်',
+        m: 'တစ်မိနစ်',
+        mm: '%d မိနစ်',
+        h: 'တစ်နာရီ',
+        hh: '%d နာရီ',
+        d: 'တစ်ရက်',
+        dd: '%d ရက်',
+        M: 'တစ်လ',
+        MM: '%d လ',
+        y: 'တစ်နှစ်',
+        yy: '%d နှစ်'
+    },
+    preparse: function (string) {
+        return string.replace(/[၁၂၃၄၅၆၇၈၉၀]/g, function (match) {
+            return numberMap$7[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap$8[match];
+        });
+    },
+    week: {
+        dow: 1, // Monday is the first day of the week.
+        doy: 4 // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Norwegian Bokmål [nb]
+//! authors : Espen Hovlandsdal : https://github.com/rexxars
+//!           Sigurd Gartmann : https://github.com/sigurdga
+
+moment.defineLocale('nb', {
+    months : 'januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember'.split('_'),
+    monthsShort : 'jan._feb._mars_april_mai_juni_juli_aug._sep._okt._nov._des.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag'.split('_'),
+    weekdaysShort : 'sø._ma._ti._on._to._fr._lø.'.split('_'),
+    weekdaysMin : 'sø_ma_ti_on_to_fr_lø'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY [kl.] HH:mm',
+        LLLL : 'dddd D. MMMM YYYY [kl.] HH:mm'
+    },
+    calendar : {
+        sameDay: '[i dag kl.] LT',
+        nextDay: '[i morgen kl.] LT',
+        nextWeek: 'dddd [kl.] LT',
+        lastDay: '[i går kl.] LT',
+        lastWeek: '[forrige] dddd [kl.] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'om %s',
+        past : '%s siden',
+        s : 'noen sekunder',
+        m : 'ett minutt',
+        mm : '%d minutter',
+        h : 'en time',
+        hh : '%d timer',
+        d : 'en dag',
+        dd : '%d dager',
+        M : 'en måned',
+        MM : '%d måneder',
+        y : 'ett år',
+        yy : '%d år'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Nepalese [ne]
+//! author : suvash : https://github.com/suvash
+
+var symbolMap$9 = {
+    '1': '१',
+    '2': '२',
+    '3': '३',
+    '4': '४',
+    '5': '५',
+    '6': '६',
+    '7': '७',
+    '8': '८',
+    '9': '९',
+    '0': '०'
+};
+var numberMap$8 = {
+    '१': '1',
+    '२': '2',
+    '३': '3',
+    '४': '4',
+    '५': '5',
+    '६': '6',
+    '७': '7',
+    '८': '8',
+    '९': '9',
+    '०': '0'
+};
+
+moment.defineLocale('ne', {
+    months : 'जनवरी_फेब्रुवरी_मार्च_अप्रिल_मई_जुन_जुलाई_अगष्ट_सेप्टेम्बर_अक्टोबर_नोभेम्बर_डिसेम्बर'.split('_'),
+    monthsShort : 'जन._फेब्रु._मार्च_अप्रि._मई_जुन_जुलाई._अग._सेप्ट._अक्टो._नोभे._डिसे.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'आइतबार_सोमबार_मङ्गलबार_बुधबार_बिहिबार_शुक्रबार_शनिबार'.split('_'),
+    weekdaysShort : 'आइत._सोम._मङ्गल._बुध._बिहि._शुक्र._शनि.'.split('_'),
+    weekdaysMin : 'आ._सो._मं._बु._बि._शु._श.'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'Aको h:mm बजे',
+        LTS : 'Aको h:mm:ss बजे',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, Aको h:mm बजे',
+        LLLL : 'dddd, D MMMM YYYY, Aको h:mm बजे'
+    },
+    preparse: function (string) {
+        return string.replace(/[१२३४५६७८९०]/g, function (match) {
+            return numberMap$8[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap$9[match];
+        });
+    },
+    meridiemParse: /राति|बिहान|दिउँसो|साँझ/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'राति') {
+            return hour < 4 ? hour : hour + 12;
+        } else if (meridiem === 'बिहान') {
+            return hour;
+        } else if (meridiem === 'दिउँसो') {
+            return hour >= 10 ? hour : hour + 12;
+        } else if (meridiem === 'साँझ') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 3) {
+            return 'राति';
+        } else if (hour < 12) {
+            return 'बिहान';
+        } else if (hour < 16) {
+            return 'दिउँसो';
+        } else if (hour < 20) {
+            return 'साँझ';
+        } else {
+            return 'राति';
+        }
+    },
+    calendar : {
+        sameDay : '[आज] LT',
+        nextDay : '[भोलि] LT',
+        nextWeek : '[आउँदो] dddd[,] LT',
+        lastDay : '[हिजो] LT',
+        lastWeek : '[गएको] dddd[,] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%sमा',
+        past : '%s अगाडि',
+        s : 'केही क्षण',
+        m : 'एक मिनेट',
+        mm : '%d मिनेट',
+        h : 'एक घण्टा',
+        hh : '%d घण्टा',
+        d : 'एक दिन',
+        dd : '%d दिन',
+        M : 'एक महिना',
+        MM : '%d महिना',
+        y : 'एक बर्ष',
+        yy : '%d बर्ष'
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Dutch (Belgium) [nl-be]
+//! author : Joris Röling : https://github.com/jorisroling
+//! author : Jacob Middag : https://github.com/middagj
+
+var monthsShortWithDots$1 = 'jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.'.split('_');
+var monthsShortWithoutDots$1 = 'jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec'.split('_');
+
+var monthsParse = [/^jan/i, /^feb/i, /^maart|mrt.?$/i, /^apr/i, /^mei$/i, /^jun[i.]?$/i, /^jul[i.]?$/i, /^aug/i, /^sep/i, /^okt/i, /^nov/i, /^dec/i];
+var monthsRegex = /^(januari|februari|maart|april|mei|april|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i;
+
+moment.defineLocale('nl-be', {
+    months : 'januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december'.split('_'),
+    monthsShort : function (m, format) {
+        if (/-MMM-/.test(format)) {
+            return monthsShortWithoutDots$1[m.month()];
+        } else {
+            return monthsShortWithDots$1[m.month()];
+        }
+    },
+
+    monthsRegex: monthsRegex,
+    monthsShortRegex: monthsRegex,
+    monthsStrictRegex: /^(januari|februari|maart|mei|ju[nl]i|april|augustus|september|oktober|november|december)/i,
+    monthsShortStrictRegex: /^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i,
+
+    monthsParse : monthsParse,
+    longMonthsParse : monthsParse,
+    shortMonthsParse : monthsParse,
+
+    weekdays : 'zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag'.split('_'),
+    weekdaysShort : 'zo._ma._di._wo._do._vr._za.'.split('_'),
+    weekdaysMin : 'Zo_Ma_Di_Wo_Do_Vr_Za'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[vandaag om] LT',
+        nextDay: '[morgen om] LT',
+        nextWeek: 'dddd [om] LT',
+        lastDay: '[gisteren om] LT',
+        lastWeek: '[afgelopen] dddd [om] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'over %s',
+        past : '%s geleden',
+        s : 'een paar seconden',
+        m : 'één minuut',
+        mm : '%d minuten',
+        h : 'één uur',
+        hh : '%d uur',
+        d : 'één dag',
+        dd : '%d dagen',
+        M : 'één maand',
+        MM : '%d maanden',
+        y : 'één jaar',
+        yy : '%d jaar'
+    },
+    ordinalParse: /\d{1,2}(ste|de)/,
+    ordinal : function (number) {
+        return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de');
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Dutch [nl]
+//! author : Joris Röling : https://github.com/jorisroling
+//! author : Jacob Middag : https://github.com/middagj
+
+var monthsShortWithDots$2 = 'jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.'.split('_');
+var monthsShortWithoutDots$2 = 'jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec'.split('_');
+
+var monthsParse$1 = [/^jan/i, /^feb/i, /^maart|mrt.?$/i, /^apr/i, /^mei$/i, /^jun[i.]?$/i, /^jul[i.]?$/i, /^aug/i, /^sep/i, /^okt/i, /^nov/i, /^dec/i];
+var monthsRegex$1 = /^(januari|februari|maart|april|mei|april|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i;
+
+moment.defineLocale('nl', {
+    months : 'januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december'.split('_'),
+    monthsShort : function (m, format) {
+        if (/-MMM-/.test(format)) {
+            return monthsShortWithoutDots$2[m.month()];
+        } else {
+            return monthsShortWithDots$2[m.month()];
+        }
+    },
+
+    monthsRegex: monthsRegex$1,
+    monthsShortRegex: monthsRegex$1,
+    monthsStrictRegex: /^(januari|februari|maart|mei|ju[nl]i|april|augustus|september|oktober|november|december)/i,
+    monthsShortStrictRegex: /^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i,
+
+    monthsParse : monthsParse$1,
+    longMonthsParse : monthsParse$1,
+    shortMonthsParse : monthsParse$1,
+
+    weekdays : 'zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag'.split('_'),
+    weekdaysShort : 'zo._ma._di._wo._do._vr._za.'.split('_'),
+    weekdaysMin : 'Zo_Ma_Di_Wo_Do_Vr_Za'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD-MM-YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[vandaag om] LT',
+        nextDay: '[morgen om] LT',
+        nextWeek: 'dddd [om] LT',
+        lastDay: '[gisteren om] LT',
+        lastWeek: '[afgelopen] dddd [om] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'over %s',
+        past : '%s geleden',
+        s : 'een paar seconden',
+        m : 'één minuut',
+        mm : '%d minuten',
+        h : 'één uur',
+        hh : '%d uur',
+        d : 'één dag',
+        dd : '%d dagen',
+        M : 'één maand',
+        MM : '%d maanden',
+        y : 'één jaar',
+        yy : '%d jaar'
+    },
+    ordinalParse: /\d{1,2}(ste|de)/,
+    ordinal : function (number) {
+        return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de');
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Nynorsk [nn]
+//! author : https://github.com/mechuwind
+
+moment.defineLocale('nn', {
+    months : 'januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember'.split('_'),
+    monthsShort : 'jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_'),
+    weekdays : 'sundag_måndag_tysdag_onsdag_torsdag_fredag_laurdag'.split('_'),
+    weekdaysShort : 'sun_mån_tys_ons_tor_fre_lau'.split('_'),
+    weekdaysMin : 'su_må_ty_on_to_fr_lø'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY [kl.] H:mm',
+        LLLL : 'dddd D. MMMM YYYY [kl.] HH:mm'
+    },
+    calendar : {
+        sameDay: '[I dag klokka] LT',
+        nextDay: '[I morgon klokka] LT',
+        nextWeek: 'dddd [klokka] LT',
+        lastDay: '[I går klokka] LT',
+        lastWeek: '[Føregåande] dddd [klokka] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'om %s',
+        past : '%s sidan',
+        s : 'nokre sekund',
+        m : 'eit minutt',
+        mm : '%d minutt',
+        h : 'ein time',
+        hh : '%d timar',
+        d : 'ein dag',
+        dd : '%d dagar',
+        M : 'ein månad',
+        MM : '%d månader',
+        y : 'eit år',
+        yy : '%d år'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Punjabi (India) [pa-in]
+//! author : Harpreet Singh : https://github.com/harpreetkhalsagtbit
+
+var symbolMap$10 = {
+    '1': 'à©§',
+    '2': '੨',
+    '3': 'à©©',
+    '4': '੪',
+    '5': 'à©«',
+    '6': '੬',
+    '7': 'à©­',
+    '8': 'à©®',
+    '9': '੯',
+    '0': '੦'
+};
+var numberMap$9 = {
+    'à©§': '1',
+    '੨': '2',
+    'à©©': '3',
+    '੪': '4',
+    'à©«': '5',
+    '੬': '6',
+    'à©­': '7',
+    'à©®': '8',
+    '੯': '9',
+    '੦': '0'
+};
+
+moment.defineLocale('pa-in', {
+    // There are months name as per Nanakshahi Calender but they are not used as rigidly in modern Punjabi.
+    months : 'ਜਨਵਰੀ_ਫ਼ਰਵਰੀ_ਮਾਰਚ_ਅਪ੍ਰੈਲ_ਮਈ_ਜੂਨ_ਜੁਲਾਈ_ਅਗਸਤ_ਸਤੰਬਰ_ਅਕਤੂਬਰ_ਨਵੰਬਰ_ਦਸੰਬਰ'.split('_'),
+    monthsShort : 'ਜਨਵਰੀ_ਫ਼ਰਵਰੀ_ਮਾਰਚ_ਅਪ੍ਰੈਲ_ਮਈ_ਜੂਨ_ਜੁਲਾਈ_ਅਗਸਤ_ਸਤੰਬਰ_ਅਕਤੂਬਰ_ਨਵੰਬਰ_ਦਸੰਬਰ'.split('_'),
+    weekdays : 'ਐਤਵਾਰ_ਸੋਮਵਾਰ_ਮੰਗਲਵਾਰ_ਬੁਧਵਾਰ_ਵੀਰਵਾਰ_ਸ਼ੁੱਕਰਵਾਰ_ਸ਼ਨੀਚਰਵਾਰ'.split('_'),
+    weekdaysShort : 'ਐਤ_ਸੋਮ_ਮੰਗਲ_ਬੁਧ_ਵੀਰ_ਸ਼ੁਕਰ_ਸ਼ਨੀ'.split('_'),
+    weekdaysMin : 'ਐਤ_ਸੋਮ_ਮੰਗਲ_ਬੁਧ_ਵੀਰ_ਸ਼ੁਕਰ_ਸ਼ਨੀ'.split('_'),
+    longDateFormat : {
+        LT : 'A h:mm ਵਜੇ',
+        LTS : 'A h:mm:ss ਵਜੇ',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, A h:mm ਵਜੇ',
+        LLLL : 'dddd, D MMMM YYYY, A h:mm ਵਜੇ'
+    },
+    calendar : {
+        sameDay : '[ਅਜ] LT',
+        nextDay : '[ਕਲ] LT',
+        nextWeek : 'dddd, LT',
+        lastDay : '[ਕਲ] LT',
+        lastWeek : '[ਪਿਛਲੇ] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s ਵਿੱਚ',
+        past : '%s ਪਿਛਲੇ',
+        s : 'ਕੁਝ ਸਕਿੰਟ',
+        m : 'ਇਕ ਮਿੰਟ',
+        mm : '%d ਮਿੰਟ',
+        h : 'ਇੱਕ ਘੰਟਾ',
+        hh : '%d ਘੰਟੇ',
+        d : 'ਇੱਕ ਦਿਨ',
+        dd : '%d ਦਿਨ',
+        M : 'ਇੱਕ ਮਹੀਨਾ',
+        MM : '%d ਮਹੀਨੇ',
+        y : 'ਇੱਕ ਸਾਲ',
+        yy : '%d ਸਾਲ'
+    },
+    preparse: function (string) {
+        return string.replace(/[੧੨੩੪੫੬੭੮੯੦]/g, function (match) {
+            return numberMap$9[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap$10[match];
+        });
+    },
+    // Punjabi notation for meridiems are quite fuzzy in practice. While there exists
+    // a rigid notion of a 'Pahar' it is not used as rigidly in modern Punjabi.
+    meridiemParse: /ਰਾਤ|ਸਵੇਰ|ਦੁਪਹਿਰ|ਸ਼ਾਮ/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'ਰਾਤ') {
+            return hour < 4 ? hour : hour + 12;
+        } else if (meridiem === 'ਸਵੇਰ') {
+            return hour;
+        } else if (meridiem === 'ਦੁਪਹਿਰ') {
+            return hour >= 10 ? hour : hour + 12;
+        } else if (meridiem === 'ਸ਼ਾਮ') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'ਰਾਤ';
+        } else if (hour < 10) {
+            return 'ਸਵੇਰ';
+        } else if (hour < 17) {
+            return 'ਦੁਪਹਿਰ';
+        } else if (hour < 20) {
+            return 'ਸ਼ਾਮ';
+        } else {
+            return 'ਰਾਤ';
+        }
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Polish [pl]
+//! author : Rafal Hirsz : https://github.com/evoL
+
+var monthsNominative = 'styczeń_luty_marzec_kwiecień_maj_czerwiec_lipiec_sierpień_wrzesień_październik_listopad_grudzień'.split('_');
+var monthsSubjective = 'stycznia_lutego_marca_kwietnia_maja_czerwca_lipca_sierpnia_września_października_listopada_grudnia'.split('_');
+function plural$3(n) {
+    return (n % 10 < 5) && (n % 10 > 1) && ((~~(n / 10) % 10) !== 1);
+}
+function translate$7(number, withoutSuffix, key) {
+    var result = number + ' ';
+    switch (key) {
+        case 'm':
+            return withoutSuffix ? 'minuta' : 'minutÄ™';
+        case 'mm':
+            return result + (plural$3(number) ? 'minuty' : 'minut');
+        case 'h':
+            return withoutSuffix  ? 'godzina'  : 'godzinÄ™';
+        case 'hh':
+            return result + (plural$3(number) ? 'godziny' : 'godzin');
+        case 'MM':
+            return result + (plural$3(number) ? 'miesiące' : 'miesięcy');
+        case 'yy':
+            return result + (plural$3(number) ? 'lata' : 'lat');
+    }
+}
+
+moment.defineLocale('pl', {
+    months : function (momentToFormat, format) {
+        if (format === '') {
+            // Hack: if format empty we know this is used to generate
+            // RegExp by moment. Give then back both valid forms of months
+            // in RegExp ready format.
+            return '(' + monthsSubjective[momentToFormat.month()] + '|' + monthsNominative[momentToFormat.month()] + ')';
+        } else if (/D MMMM/.test(format)) {
+            return monthsSubjective[momentToFormat.month()];
+        } else {
+            return monthsNominative[momentToFormat.month()];
+        }
+    },
+    monthsShort : 'sty_lut_mar_kwi_maj_cze_lip_sie_wrz_paź_lis_gru'.split('_'),
+    weekdays : 'niedziela_poniedziałek_wtorek_środa_czwartek_piątek_sobota'.split('_'),
+    weekdaysShort : 'ndz_pon_wt_śr_czw_pt_sob'.split('_'),
+    weekdaysMin : 'Nd_Pn_Wt_Åšr_Cz_Pt_So'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[DziÅ› o] LT',
+        nextDay: '[Jutro o] LT',
+        nextWeek: '[W] dddd [o] LT',
+        lastDay: '[Wczoraj o] LT',
+        lastWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[W zeszłą niedzielę o] LT';
+                case 3:
+                    return '[W zeszłą środę o] LT';
+                case 6:
+                    return '[W zeszłą sobotę o] LT';
+                default:
+                    return '[W zeszły] dddd [o] LT';
+            }
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'za %s',
+        past : '%s temu',
+        s : 'kilka sekund',
+        m : translate$7,
+        mm : translate$7,
+        h : translate$7,
+        hh : translate$7,
+        d : '1 dzień',
+        dd : '%d dni',
+        M : 'miesiÄ…c',
+        MM : translate$7,
+        y : 'rok',
+        yy : translate$7
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Portuguese (Brazil) [pt-br]
+//! author : Caio Ribeiro Pereira : https://github.com/caio-ribeiro-pereira
+
+moment.defineLocale('pt-br', {
+    months : 'Janeiro_Fevereiro_Março_Abril_Maio_Junho_Julho_Agosto_Setembro_Outubro_Novembro_Dezembro'.split('_'),
+    monthsShort : 'Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez'.split('_'),
+    weekdays : 'Domingo_Segunda-feira_Terça-feira_Quarta-feira_Quinta-feira_Sexta-feira_Sábado'.split('_'),
+    weekdaysShort : 'Dom_Seg_Ter_Qua_Qui_Sex_Sáb'.split('_'),
+    weekdaysMin : 'Dom_2ª_3ª_4ª_5ª_6ª_Sáb'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D [de] MMMM [de] YYYY',
+        LLL : 'D [de] MMMM [de] YYYY [às] HH:mm',
+        LLLL : 'dddd, D [de] MMMM [de] YYYY [às] HH:mm'
+    },
+    calendar : {
+        sameDay: '[Hoje às] LT',
+        nextDay: '[Amanhã às] LT',
+        nextWeek: 'dddd [às] LT',
+        lastDay: '[Ontem às] LT',
+        lastWeek: function () {
+            return (this.day() === 0 || this.day() === 6) ?
+                '[Último] dddd [às] LT' : // Saturday + Sunday
+                '[Última] dddd [às] LT'; // Monday - Friday
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'em %s',
+        past : '%s atrás',
+        s : 'poucos segundos',
+        m : 'um minuto',
+        mm : '%d minutos',
+        h : 'uma hora',
+        hh : '%d horas',
+        d : 'um dia',
+        dd : '%d dias',
+        M : 'um mês',
+        MM : '%d meses',
+        y : 'um ano',
+        yy : '%d anos'
+    },
+    ordinalParse: /\d{1,2}º/,
+    ordinal : '%dº'
+});
+
+//! moment.js locale configuration
+//! locale : Portuguese [pt]
+//! author : Jefferson : https://github.com/jalex79
+
+moment.defineLocale('pt', {
+    months : 'Janeiro_Fevereiro_Março_Abril_Maio_Junho_Julho_Agosto_Setembro_Outubro_Novembro_Dezembro'.split('_'),
+    monthsShort : 'Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez'.split('_'),
+    weekdays : 'Domingo_Segunda-Feira_Terça-Feira_Quarta-Feira_Quinta-Feira_Sexta-Feira_Sábado'.split('_'),
+    weekdaysShort : 'Dom_Seg_Ter_Qua_Qui_Sex_Sáb'.split('_'),
+    weekdaysMin : 'Dom_2ª_3ª_4ª_5ª_6ª_Sáb'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D [de] MMMM [de] YYYY',
+        LLL : 'D [de] MMMM [de] YYYY HH:mm',
+        LLLL : 'dddd, D [de] MMMM [de] YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Hoje às] LT',
+        nextDay: '[Amanhã às] LT',
+        nextWeek: 'dddd [às] LT',
+        lastDay: '[Ontem às] LT',
+        lastWeek: function () {
+            return (this.day() === 0 || this.day() === 6) ?
+                '[Último] dddd [às] LT' : // Saturday + Sunday
+                '[Última] dddd [às] LT'; // Monday - Friday
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'em %s',
+        past : 'há %s',
+        s : 'segundos',
+        m : 'um minuto',
+        mm : '%d minutos',
+        h : 'uma hora',
+        hh : '%d horas',
+        d : 'um dia',
+        dd : '%d dias',
+        M : 'um mês',
+        MM : '%d meses',
+        y : 'um ano',
+        yy : '%d anos'
+    },
+    ordinalParse: /\d{1,2}º/,
+    ordinal : '%dº',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Romanian [ro]
+//! author : Vlad Gurdiga : https://github.com/gurdiga
+//! author : Valentin Agachi : https://github.com/avaly
+
+function relativeTimeWithPlural$2(number, withoutSuffix, key) {
+    var format = {
+            'mm': 'minute',
+            'hh': 'ore',
+            'dd': 'zile',
+            'MM': 'luni',
+            'yy': 'ani'
+        },
+        separator = ' ';
+    if (number % 100 >= 20 || (number >= 100 && number % 100 === 0)) {
+        separator = ' de ';
+    }
+    return number + separator + format[key];
+}
+
+moment.defineLocale('ro', {
+    months : 'ianuarie_februarie_martie_aprilie_mai_iunie_iulie_august_septembrie_octombrie_noiembrie_decembrie'.split('_'),
+    monthsShort : 'ian._febr._mart._apr._mai_iun._iul._aug._sept._oct._nov._dec.'.split('_'),
+    monthsParseExact: true,
+    weekdays : 'duminică_luni_marți_miercuri_joi_vineri_sâmbătă'.split('_'),
+    weekdaysShort : 'Dum_Lun_Mar_Mie_Joi_Vin_Sâm'.split('_'),
+    weekdaysMin : 'Du_Lu_Ma_Mi_Jo_Vi_Sâ'.split('_'),
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY H:mm',
+        LLLL : 'dddd, D MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay: '[azi la] LT',
+        nextDay: '[mâine la] LT',
+        nextWeek: 'dddd [la] LT',
+        lastDay: '[ieri la] LT',
+        lastWeek: '[fosta] dddd [la] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'peste %s',
+        past : '%s în urmă',
+        s : 'câteva secunde',
+        m : 'un minut',
+        mm : relativeTimeWithPlural$2,
+        h : 'o oră',
+        hh : relativeTimeWithPlural$2,
+        d : 'o zi',
+        dd : relativeTimeWithPlural$2,
+        M : 'o lună',
+        MM : relativeTimeWithPlural$2,
+        y : 'un an',
+        yy : relativeTimeWithPlural$2
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Russian [ru]
+//! author : Viktorminator : https://github.com/Viktorminator
+//! Author : Menelion Elensúle : https://github.com/Oire
+//! author : Коренберг Марк : https://github.com/socketpair
+
+function plural$4(word, num) {
+    var forms = word.split('_');
+    return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]);
+}
+function relativeTimeWithPlural$3(number, withoutSuffix, key) {
+    var format = {
+        'mm': withoutSuffix ? 'минута_минуты_минут' : 'минуту_минуты_минут',
+        'hh': 'час_часа_часов',
+        'dd': 'день_дня_дней',
+        'MM': 'месяц_месяца_месяцев',
+        'yy': 'год_года_лет'
+    };
+    if (key === 'm') {
+        return withoutSuffix ? 'минута' : 'минуту';
+    }
+    else {
+        return number + ' ' + plural$4(format[key], +number);
+    }
+}
+var monthsParse$2 = [/^янв/i, /^фев/i, /^мар/i, /^апр/i, /^ма[йя]/i, /^июн/i, /^июл/i, /^авг/i, /^сен/i, /^окт/i, /^ноя/i, /^дек/i];
+
+// http://new.gramota.ru/spravka/rules/139-prop : § 103
+// Сокращения месяцев: http://new.gramota.ru/spravka/buro/search-answer?s=242637
+// CLDR data:          http://www.unicode.org/cldr/charts/28/summary/ru.html#1753
+moment.defineLocale('ru', {
+    months : {
+        format: 'января_февраля_марта_апреля_мая_июня_июля_августа_сентября_октября_ноября_декабря'.split('_'),
+        standalone: 'январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь'.split('_')
+    },
+    monthsShort : {
+        // по CLDR именно "июл." и "июн.", но какой смысл менять букву на точку ?
+        format: 'янв._февр._мар._апр._мая_июня_июля_авг._сент._окт._нояб._дек.'.split('_'),
+        standalone: 'янв._февр._март_апр._май_июнь_июль_авг._сент._окт._нояб._дек.'.split('_')
+    },
+    weekdays : {
+        standalone: 'воскресенье_понедельник_вторник_среда_четверг_пятница_суббота'.split('_'),
+        format: 'воскресенье_понедельник_вторник_среду_четверг_пятницу_субботу'.split('_'),
+        isFormat: /\[ ?[Вв] ?(?:прошлую|следующую|эту)? ?\] ?dddd/
+    },
+    weekdaysShort : 'вс_пн_вт_ср_чт_пт_сб'.split('_'),
+    weekdaysMin : 'вс_пн_вт_ср_чт_пт_сб'.split('_'),
+    monthsParse : monthsParse$2,
+    longMonthsParse : monthsParse$2,
+    shortMonthsParse : monthsParse$2,
+
+    // полные названия с падежами, по три буквы, для некоторых, по 4 буквы, сокращения с точкой и без точки
+    monthsRegex: /^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i,
+
+    // копия предыдущего
+    monthsShortRegex: /^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i,
+
+    // полные названия с падежами
+    monthsStrictRegex: /^(январ[яь]|феврал[яь]|марта?|апрел[яь]|ма[яй]|июн[яь]|июл[яь]|августа?|сентябр[яь]|октябр[яь]|ноябр[яь]|декабр[яь])/i,
+
+    // Выражение, которое соотвествует только сокращённым формам
+    monthsShortStrictRegex: /^(янв\.|февр?\.|мар[т.]|апр\.|ма[яй]|июн[ья.]|июл[ья.]|авг\.|сент?\.|окт\.|нояб?\.|дек\.)/i,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY г.',
+        LLL : 'D MMMM YYYY г., HH:mm',
+        LLLL : 'dddd, D MMMM YYYY г., HH:mm'
+    },
+    calendar : {
+        sameDay: '[Сегодня в] LT',
+        nextDay: '[Завтра в] LT',
+        lastDay: '[Вчера в] LT',
+        nextWeek: function (now) {
+            if (now.week() !== this.week()) {
+                switch (this.day()) {
+                    case 0:
+                        return '[В следующее] dddd [в] LT';
+                    case 1:
+                    case 2:
+                    case 4:
+                        return '[В следующий] dddd [в] LT';
+                    case 3:
+                    case 5:
+                    case 6:
+                        return '[В следующую] dddd [в] LT';
+                }
+            } else {
+                if (this.day() === 2) {
+                    return '[Во] dddd [в] LT';
+                } else {
+                    return '[В] dddd [в] LT';
+                }
+            }
+        },
+        lastWeek: function (now) {
+            if (now.week() !== this.week()) {
+                switch (this.day()) {
+                    case 0:
+                        return '[В прошлое] dddd [в] LT';
+                    case 1:
+                    case 2:
+                    case 4:
+                        return '[В прошлый] dddd [в] LT';
+                    case 3:
+                    case 5:
+                    case 6:
+                        return '[В прошлую] dddd [в] LT';
+                }
+            } else {
+                if (this.day() === 2) {
+                    return '[Во] dddd [в] LT';
+                } else {
+                    return '[В] dddd [в] LT';
+                }
+            }
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'через %s',
+        past : '%s назад',
+        s : 'несколько секунд',
+        m : relativeTimeWithPlural$3,
+        mm : relativeTimeWithPlural$3,
+        h : 'час',
+        hh : relativeTimeWithPlural$3,
+        d : 'день',
+        dd : relativeTimeWithPlural$3,
+        M : 'месяц',
+        MM : relativeTimeWithPlural$3,
+        y : 'год',
+        yy : relativeTimeWithPlural$3
+    },
+    meridiemParse: /ночи|утра|дня|вечера/i,
+    isPM : function (input) {
+        return /^(дня|вечера)$/.test(input);
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'ночи';
+        } else if (hour < 12) {
+            return 'утра';
+        } else if (hour < 17) {
+            return 'дня';
+        } else {
+            return 'вечера';
+        }
+    },
+    ordinalParse: /\d{1,2}-(й|го|я)/,
+    ordinal: function (number, period) {
+        switch (period) {
+            case 'M':
+            case 'd':
+            case 'DDD':
+                return number + '-й';
+            case 'D':
+                return number + '-го';
+            case 'w':
+            case 'W':
+                return number + '-я';
+            default:
+                return number;
+        }
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Northern Sami [se]
+//! authors : BÃ¥rd Rolstad Henriksen : https://github.com/karamell
+
+
+moment.defineLocale('se', {
+    months : 'ođđajagemánnu_guovvamánnu_njukčamánnu_cuoŋománnu_miessemánnu_geassemánnu_suoidnemánnu_borgemánnu_čakčamánnu_golggotmánnu_skábmamánnu_juovlamánnu'.split('_'),
+    monthsShort : 'ođđj_guov_njuk_cuo_mies_geas_suoi_borg_čakč_golg_skáb_juov'.split('_'),
+    weekdays : 'sotnabeaivi_vuossárga_maŋŋebárga_gaskavahkku_duorastat_bearjadat_lávvardat'.split('_'),
+    weekdaysShort : 'sotn_vuos_maŋ_gask_duor_bear_láv'.split('_'),
+    weekdaysMin : 's_v_m_g_d_b_L'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'MMMM D. [b.] YYYY',
+        LLL : 'MMMM D. [b.] YYYY [ti.] HH:mm',
+        LLLL : 'dddd, MMMM D. [b.] YYYY [ti.] HH:mm'
+    },
+    calendar : {
+        sameDay: '[otne ti] LT',
+        nextDay: '[ihttin ti] LT',
+        nextWeek: 'dddd [ti] LT',
+        lastDay: '[ikte ti] LT',
+        lastWeek: '[ovddit] dddd [ti] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : '%s geažes',
+        past : 'maŋit %s',
+        s : 'moadde sekunddat',
+        m : 'okta minuhta',
+        mm : '%d minuhtat',
+        h : 'okta diimmu',
+        hh : '%d diimmut',
+        d : 'okta beaivi',
+        dd : '%d beaivvit',
+        M : 'okta mánnu',
+        MM : '%d mánut',
+        y : 'okta jahki',
+        yy : '%d jagit'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Sinhalese [si]
+//! author : Sampath Sitinamaluwa : https://github.com/sampathsris
+
+/*jshint -W100*/
+moment.defineLocale('si', {
+    months : 'ජනවාරි_පෙබරවාරි_මාර්තු_අප්‍රේල්_මැයි_ජූනි_ජූලි_අගෝස්තු_සැප්තැම්බර්_ඔක්තෝබර්_නොවැම්බර්_දෙසැම්බර්'.split('_'),
+    monthsShort : 'ජන_පෙබ_මාර්_අප්_මැයි_ජූනි_ජූලි_අගෝ_සැප්_ඔක්_නොවැ_දෙසැ'.split('_'),
+    weekdays : 'ඉරිදා_සඳුදා_අඟහරුවාදා_බදාදා_බ්‍රහස්පතින්දා_සිකුරාදා_සෙනසුරාදා'.split('_'),
+    weekdaysShort : 'ඉරි_සඳු_අඟ_බදා_බ්‍රහ_සිකු_සෙන'.split('_'),
+    weekdaysMin : 'ඉ_ස_අ_බ_බ්‍ර_සි_සෙ'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'a h:mm',
+        LTS : 'a h:mm:ss',
+        L : 'YYYY/MM/DD',
+        LL : 'YYYY MMMM D',
+        LLL : 'YYYY MMMM D, a h:mm',
+        LLLL : 'YYYY MMMM D [වැනි] dddd, a h:mm:ss'
+    },
+    calendar : {
+        sameDay : '[අද] LT[ට]',
+        nextDay : '[හෙට] LT[ට]',
+        nextWeek : 'dddd LT[à¶§]',
+        lastDay : '[ඊයේ] LT[ට]',
+        lastWeek : '[පසුගිය] dddd LT[ට]',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%sකින්',
+        past : '%sකට පෙර',
+        s : 'තත්පර කිහිපය',
+        m : 'මිනිත්තුව',
+        mm : 'මිනිත්තු %d',
+        h : 'පැය',
+        hh : 'පැය %d',
+        d : 'දිනය',
+        dd : 'දින %d',
+        M : 'මාසය',
+        MM : 'මාස %d',
+        y : 'වසර',
+        yy : 'වසර %d'
+    },
+    ordinalParse: /\d{1,2} වැනි/,
+    ordinal : function (number) {
+        return number + ' වැනි';
+    },
+    meridiemParse : /පෙර වරු|පස් වරු|පෙ.ව|ප.ව./,
+    isPM : function (input) {
+        return input === 'ප.ව.' || input === 'පස් වරු';
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours > 11) {
+            return isLower ? 'ප.ව.' : 'පස් වරු';
+        } else {
+            return isLower ? 'පෙ.ව.' : 'පෙර වරු';
+        }
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Slovak [sk]
+//! author : Martin Minka : https://github.com/k2s
+//! based on work of petrbela : https://github.com/petrbela
+
+var months$5 = 'január_február_marec_apríl_máj_jún_júl_august_september_október_november_december'.split('_');
+var monthsShort$4 = 'jan_feb_mar_apr_máj_jún_júl_aug_sep_okt_nov_dec'.split('_');
+function plural$5(n) {
+    return (n > 1) && (n < 5);
+}
+function translate$8(number, withoutSuffix, key, isFuture) {
+    var result = number + ' ';
+    switch (key) {
+        case 's':  // a few seconds / in a few seconds / a few seconds ago
+            return (withoutSuffix || isFuture) ? 'pár sekúnd' : 'pár sekundami';
+        case 'm':  // a minute / in a minute / a minute ago
+            return withoutSuffix ? 'minúta' : (isFuture ? 'minútu' : 'minútou');
+        case 'mm': // 9 minutes / in 9 minutes / 9 minutes ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural$5(number) ? 'minúty' : 'minút');
+            } else {
+                return result + 'minútami';
+            }
+            break;
+        case 'h':  // an hour / in an hour / an hour ago
+            return withoutSuffix ? 'hodina' : (isFuture ? 'hodinu' : 'hodinou');
+        case 'hh': // 9 hours / in 9 hours / 9 hours ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural$5(number) ? 'hodiny' : 'hodín');
+            } else {
+                return result + 'hodinami';
+            }
+            break;
+        case 'd':  // a day / in a day / a day ago
+            return (withoutSuffix || isFuture) ? 'deň' : 'dňom';
+        case 'dd': // 9 days / in 9 days / 9 days ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural$5(number) ? 'dni' : 'dní');
+            } else {
+                return result + 'dňami';
+            }
+            break;
+        case 'M':  // a month / in a month / a month ago
+            return (withoutSuffix || isFuture) ? 'mesiac' : 'mesiacom';
+        case 'MM': // 9 months / in 9 months / 9 months ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural$5(number) ? 'mesiace' : 'mesiacov');
+            } else {
+                return result + 'mesiacmi';
+            }
+            break;
+        case 'y':  // a year / in a year / a year ago
+            return (withoutSuffix || isFuture) ? 'rok' : 'rokom';
+        case 'yy': // 9 years / in 9 years / 9 years ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural$5(number) ? 'roky' : 'rokov');
+            } else {
+                return result + 'rokmi';
+            }
+            break;
+    }
+}
+
+moment.defineLocale('sk', {
+    months : months$5,
+    monthsShort : monthsShort$4,
+    weekdays : 'nedeľa_pondelok_utorok_streda_štvrtok_piatok_sobota'.split('_'),
+    weekdaysShort : 'ne_po_ut_st_št_pi_so'.split('_'),
+    weekdaysMin : 'ne_po_ut_st_št_pi_so'.split('_'),
+    longDateFormat : {
+        LT: 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY H:mm',
+        LLLL : 'dddd D. MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay: '[dnes o] LT',
+        nextDay: '[zajtra o] LT',
+        nextWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[v nedeľu o] LT';
+                case 1:
+                case 2:
+                    return '[v] dddd [o] LT';
+                case 3:
+                    return '[v stredu o] LT';
+                case 4:
+                    return '[vo štvrtok o] LT';
+                case 5:
+                    return '[v piatok o] LT';
+                case 6:
+                    return '[v sobotu o] LT';
+            }
+        },
+        lastDay: '[včera o] LT',
+        lastWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[minulú nedeľu o] LT';
+                case 1:
+                case 2:
+                    return '[minulý] dddd [o] LT';
+                case 3:
+                    return '[minulú stredu o] LT';
+                case 4:
+                case 5:
+                    return '[minulý] dddd [o] LT';
+                case 6:
+                    return '[minulú sobotu o] LT';
+            }
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'za %s',
+        past : 'pred %s',
+        s : translate$8,
+        m : translate$8,
+        mm : translate$8,
+        h : translate$8,
+        hh : translate$8,
+        d : translate$8,
+        dd : translate$8,
+        M : translate$8,
+        MM : translate$8,
+        y : translate$8,
+        yy : translate$8
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Slovenian [sl]
+//! author : Robert Sedovšek : https://github.com/sedovsek
+
+function processRelativeTime$4(number, withoutSuffix, key, isFuture) {
+    var result = number + ' ';
+    switch (key) {
+        case 's':
+            return withoutSuffix || isFuture ? 'nekaj sekund' : 'nekaj sekundami';
+        case 'm':
+            return withoutSuffix ? 'ena minuta' : 'eno minuto';
+        case 'mm':
+            if (number === 1) {
+                result += withoutSuffix ? 'minuta' : 'minuto';
+            } else if (number === 2) {
+                result += withoutSuffix || isFuture ? 'minuti' : 'minutama';
+            } else if (number < 5) {
+                result += withoutSuffix || isFuture ? 'minute' : 'minutami';
+            } else {
+                result += withoutSuffix || isFuture ? 'minut' : 'minutami';
+            }
+            return result;
+        case 'h':
+            return withoutSuffix ? 'ena ura' : 'eno uro';
+        case 'hh':
+            if (number === 1) {
+                result += withoutSuffix ? 'ura' : 'uro';
+            } else if (number === 2) {
+                result += withoutSuffix || isFuture ? 'uri' : 'urama';
+            } else if (number < 5) {
+                result += withoutSuffix || isFuture ? 'ure' : 'urami';
+            } else {
+                result += withoutSuffix || isFuture ? 'ur' : 'urami';
+            }
+            return result;
+        case 'd':
+            return withoutSuffix || isFuture ? 'en dan' : 'enim dnem';
+        case 'dd':
+            if (number === 1) {
+                result += withoutSuffix || isFuture ? 'dan' : 'dnem';
+            } else if (number === 2) {
+                result += withoutSuffix || isFuture ? 'dni' : 'dnevoma';
+            } else {
+                result += withoutSuffix || isFuture ? 'dni' : 'dnevi';
+            }
+            return result;
+        case 'M':
+            return withoutSuffix || isFuture ? 'en mesec' : 'enim mesecem';
+        case 'MM':
+            if (number === 1) {
+                result += withoutSuffix || isFuture ? 'mesec' : 'mesecem';
+            } else if (number === 2) {
+                result += withoutSuffix || isFuture ? 'meseca' : 'mesecema';
+            } else if (number < 5) {
+                result += withoutSuffix || isFuture ? 'mesece' : 'meseci';
+            } else {
+                result += withoutSuffix || isFuture ? 'mesecev' : 'meseci';
+            }
+            return result;
+        case 'y':
+            return withoutSuffix || isFuture ? 'eno leto' : 'enim letom';
+        case 'yy':
+            if (number === 1) {
+                result += withoutSuffix || isFuture ? 'leto' : 'letom';
+            } else if (number === 2) {
+                result += withoutSuffix || isFuture ? 'leti' : 'letoma';
+            } else if (number < 5) {
+                result += withoutSuffix || isFuture ? 'leta' : 'leti';
+            } else {
+                result += withoutSuffix || isFuture ? 'let' : 'leti';
+            }
+            return result;
+    }
+}
+
+moment.defineLocale('sl', {
+    months : 'januar_februar_marec_april_maj_junij_julij_avgust_september_oktober_november_december'.split('_'),
+    monthsShort : 'jan._feb._mar._apr._maj._jun._jul._avg._sep._okt._nov._dec.'.split('_'),
+    monthsParseExact: true,
+    weekdays : 'nedelja_ponedeljek_torek_sreda_četrtek_petek_sobota'.split('_'),
+    weekdaysShort : 'ned._pon._tor._sre._čet._pet._sob.'.split('_'),
+    weekdaysMin : 'ne_po_to_sr_če_pe_so'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY H:mm',
+        LLLL : 'dddd, D. MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay  : '[danes ob] LT',
+        nextDay  : '[jutri ob] LT',
+
+        nextWeek : function () {
+            switch (this.day()) {
+                case 0:
+                    return '[v] [nedeljo] [ob] LT';
+                case 3:
+                    return '[v] [sredo] [ob] LT';
+                case 6:
+                    return '[v] [soboto] [ob] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[v] dddd [ob] LT';
+            }
+        },
+        lastDay  : '[včeraj ob] LT',
+        lastWeek : function () {
+            switch (this.day()) {
+                case 0:
+                    return '[prejšnjo] [nedeljo] [ob] LT';
+                case 3:
+                    return '[prejšnjo] [sredo] [ob] LT';
+                case 6:
+                    return '[prejšnjo] [soboto] [ob] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[prejšnji] dddd [ob] LT';
+            }
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'čez %s',
+        past   : 'pred %s',
+        s      : processRelativeTime$4,
+        m      : processRelativeTime$4,
+        mm     : processRelativeTime$4,
+        h      : processRelativeTime$4,
+        hh     : processRelativeTime$4,
+        d      : processRelativeTime$4,
+        dd     : processRelativeTime$4,
+        M      : processRelativeTime$4,
+        MM     : processRelativeTime$4,
+        y      : processRelativeTime$4,
+        yy     : processRelativeTime$4
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Albanian [sq]
+//! author : Flakërim Ismani : https://github.com/flakerimi
+//! author : Menelion Elensúle : https://github.com/Oire
+//! author : Oerd Cukalla : https://github.com/oerd
+
+moment.defineLocale('sq', {
+    months : 'Janar_Shkurt_Mars_Prill_Maj_Qershor_Korrik_Gusht_Shtator_Tetor_Nëntor_Dhjetor'.split('_'),
+    monthsShort : 'Jan_Shk_Mar_Pri_Maj_Qer_Kor_Gus_Sht_Tet_Nën_Dhj'.split('_'),
+    weekdays : 'E Diel_E Hënë_E Martë_E Mërkurë_E Enjte_E Premte_E Shtunë'.split('_'),
+    weekdaysShort : 'Die_Hën_Mar_Mër_Enj_Pre_Sht'.split('_'),
+    weekdaysMin : 'D_H_Ma_Më_E_P_Sh'.split('_'),
+    weekdaysParseExact : true,
+    meridiemParse: /PD|MD/,
+    isPM: function (input) {
+        return input.charAt(0) === 'M';
+    },
+    meridiem : function (hours, minutes, isLower) {
+        return hours < 12 ? 'PD' : 'MD';
+    },
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[Sot në] LT',
+        nextDay : '[Nesër në] LT',
+        nextWeek : 'dddd [në] LT',
+        lastDay : '[Dje në] LT',
+        lastWeek : 'dddd [e kaluar në] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'në %s',
+        past : '%s më parë',
+        s : 'disa sekonda',
+        m : 'një minutë',
+        mm : '%d minuta',
+        h : 'një orë',
+        hh : '%d orë',
+        d : 'një ditë',
+        dd : '%d ditë',
+        M : 'një muaj',
+        MM : '%d muaj',
+        y : 'një vit',
+        yy : '%d vite'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Serbian Cyrillic [sr-cyrl]
+//! author : Milan Janačković<milanjanackovic@gmail.com> : https://github.com/milan-j
+
+var translator$1 = {
+    words: { //Different grammatical cases
+        m: ['један минут', 'једне минуте'],
+        mm: ['минут', 'минуте', 'минута'],
+        h: ['један сат', 'једног сата'],
+        hh: ['сат', 'сата', 'сати'],
+        dd: ['дан', 'дана', 'дана'],
+        MM: ['месец', 'месеца', 'месеци'],
+        yy: ['година', 'године', 'година']
+    },
+    correctGrammaticalCase: function (number, wordKey) {
+        return number === 1 ? wordKey[0] : (number >= 2 && number <= 4 ? wordKey[1] : wordKey[2]);
+    },
+    translate: function (number, withoutSuffix, key) {
+        var wordKey = translator$1.words[key];
+        if (key.length === 1) {
+            return withoutSuffix ? wordKey[0] : wordKey[1];
+        } else {
+            return number + ' ' + translator$1.correctGrammaticalCase(number, wordKey);
+        }
+    }
+};
+
+moment.defineLocale('sr-cyrl', {
+    months: 'јануар_фебруар_март_април_мај_јун_јул_август_септембар_октобар_новембар_децембар'.split('_'),
+    monthsShort: 'јан._феб._мар._апр._мај_јун_јул_авг._сеп._окт._нов._дец.'.split('_'),
+    monthsParseExact: true,
+    weekdays: 'недеља_понедељак_уторак_среда_четвртак_петак_субота'.split('_'),
+    weekdaysShort: 'нед._пон._уто._сре._чет._пет._суб.'.split('_'),
+    weekdaysMin: 'не_по_ут_ср_че_пе_су'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat: {
+        LT: 'H:mm',
+        LTS : 'H:mm:ss',
+        L: 'DD.MM.YYYY',
+        LL: 'D. MMMM YYYY',
+        LLL: 'D. MMMM YYYY H:mm',
+        LLLL: 'dddd, D. MMMM YYYY H:mm'
+    },
+    calendar: {
+        sameDay: '[данас у] LT',
+        nextDay: '[сутра у] LT',
+        nextWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[у] [недељу] [у] LT';
+                case 3:
+                    return '[у] [среду] [у] LT';
+                case 6:
+                    return '[у] [суботу] [у] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[у] dddd [у] LT';
+            }
+        },
+        lastDay  : '[јуче у] LT',
+        lastWeek : function () {
+            var lastWeekDays = [
+                '[прошле] [недеље] [у] LT',
+                '[прошлог] [понедељка] [у] LT',
+                '[прошлог] [уторка] [у] LT',
+                '[прошле] [среде] [у] LT',
+                '[прошлог] [четвртка] [у] LT',
+                '[прошлог] [петка] [у] LT',
+                '[прошле] [суботе] [у] LT'
+            ];
+            return lastWeekDays[this.day()];
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'за %s',
+        past   : 'пре %s',
+        s      : 'неколико секунди',
+        m      : translator$1.translate,
+        mm     : translator$1.translate,
+        h      : translator$1.translate,
+        hh     : translator$1.translate,
+        d      : 'дан',
+        dd     : translator$1.translate,
+        M      : 'месец',
+        MM     : translator$1.translate,
+        y      : 'годину',
+        yy     : translator$1.translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Serbian [sr]
+//! author : Milan Janačković<milanjanackovic@gmail.com> : https://github.com/milan-j
+
+var translator$2 = {
+    words: { //Different grammatical cases
+        m: ['jedan minut', 'jedne minute'],
+        mm: ['minut', 'minute', 'minuta'],
+        h: ['jedan sat', 'jednog sata'],
+        hh: ['sat', 'sata', 'sati'],
+        dd: ['dan', 'dana', 'dana'],
+        MM: ['mesec', 'meseca', 'meseci'],
+        yy: ['godina', 'godine', 'godina']
+    },
+    correctGrammaticalCase: function (number, wordKey) {
+        return number === 1 ? wordKey[0] : (number >= 2 && number <= 4 ? wordKey[1] : wordKey[2]);
+    },
+    translate: function (number, withoutSuffix, key) {
+        var wordKey = translator$2.words[key];
+        if (key.length === 1) {
+            return withoutSuffix ? wordKey[0] : wordKey[1];
+        } else {
+            return number + ' ' + translator$2.correctGrammaticalCase(number, wordKey);
+        }
+    }
+};
+
+moment.defineLocale('sr', {
+    months: 'januar_februar_mart_april_maj_jun_jul_avgust_septembar_oktobar_novembar_decembar'.split('_'),
+    monthsShort: 'jan._feb._mar._apr._maj_jun_jul_avg._sep._okt._nov._dec.'.split('_'),
+    monthsParseExact: true,
+    weekdays: 'nedelja_ponedeljak_utorak_sreda_četvrtak_petak_subota'.split('_'),
+    weekdaysShort: 'ned._pon._uto._sre._čet._pet._sub.'.split('_'),
+    weekdaysMin: 'ne_po_ut_sr_če_pe_su'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat: {
+        LT: 'H:mm',
+        LTS : 'H:mm:ss',
+        L: 'DD.MM.YYYY',
+        LL: 'D. MMMM YYYY',
+        LLL: 'D. MMMM YYYY H:mm',
+        LLLL: 'dddd, D. MMMM YYYY H:mm'
+    },
+    calendar: {
+        sameDay: '[danas u] LT',
+        nextDay: '[sutra u] LT',
+        nextWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[u] [nedelju] [u] LT';
+                case 3:
+                    return '[u] [sredu] [u] LT';
+                case 6:
+                    return '[u] [subotu] [u] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[u] dddd [u] LT';
+            }
+        },
+        lastDay  : '[juče u] LT',
+        lastWeek : function () {
+            var lastWeekDays = [
+                '[prošle] [nedelje] [u] LT',
+                '[prošlog] [ponedeljka] [u] LT',
+                '[prošlog] [utorka] [u] LT',
+                '[prošle] [srede] [u] LT',
+                '[prošlog] [četvrtka] [u] LT',
+                '[prošlog] [petka] [u] LT',
+                '[prošle] [subote] [u] LT'
+            ];
+            return lastWeekDays[this.day()];
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'za %s',
+        past   : 'pre %s',
+        s      : 'nekoliko sekundi',
+        m      : translator$2.translate,
+        mm     : translator$2.translate,
+        h      : translator$2.translate,
+        hh     : translator$2.translate,
+        d      : 'dan',
+        dd     : translator$2.translate,
+        M      : 'mesec',
+        MM     : translator$2.translate,
+        y      : 'godinu',
+        yy     : translator$2.translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : siSwati [ss]
+//! author : Nicolai Davies<mail@nicolai.io> : https://github.com/nicolaidavies
+
+
+moment.defineLocale('ss', {
+    months : "Bhimbidvwane_Indlovana_Indlov'lenkhulu_Mabasa_Inkhwekhweti_Inhlaba_Kholwane_Ingci_Inyoni_Imphala_Lweti_Ingongoni".split('_'),
+    monthsShort : 'Bhi_Ina_Inu_Mab_Ink_Inh_Kho_Igc_Iny_Imp_Lwe_Igo'.split('_'),
+    weekdays : 'Lisontfo_Umsombuluko_Lesibili_Lesitsatfu_Lesine_Lesihlanu_Umgcibelo'.split('_'),
+    weekdaysShort : 'Lis_Umb_Lsb_Les_Lsi_Lsh_Umg'.split('_'),
+    weekdaysMin : 'Li_Us_Lb_Lt_Ls_Lh_Ug'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'h:mm A',
+        LTS : 'h:mm:ss A',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY h:mm A',
+        LLLL : 'dddd, D MMMM YYYY h:mm A'
+    },
+    calendar : {
+        sameDay : '[Namuhla nga] LT',
+        nextDay : '[Kusasa nga] LT',
+        nextWeek : 'dddd [nga] LT',
+        lastDay : '[Itolo nga] LT',
+        lastWeek : 'dddd [leliphelile] [nga] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'nga %s',
+        past : 'wenteka nga %s',
+        s : 'emizuzwana lomcane',
+        m : 'umzuzu',
+        mm : '%d emizuzu',
+        h : 'lihora',
+        hh : '%d emahora',
+        d : 'lilanga',
+        dd : '%d emalanga',
+        M : 'inyanga',
+        MM : '%d tinyanga',
+        y : 'umnyaka',
+        yy : '%d iminyaka'
+    },
+    meridiemParse: /ekuseni|emini|entsambama|ebusuku/,
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 11) {
+            return 'ekuseni';
+        } else if (hours < 15) {
+            return 'emini';
+        } else if (hours < 19) {
+            return 'entsambama';
+        } else {
+            return 'ebusuku';
+        }
+    },
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'ekuseni') {
+            return hour;
+        } else if (meridiem === 'emini') {
+            return hour >= 11 ? hour : hour + 12;
+        } else if (meridiem === 'entsambama' || meridiem === 'ebusuku') {
+            if (hour === 0) {
+                return 0;
+            }
+            return hour + 12;
+        }
+    },
+    ordinalParse: /\d{1,2}/,
+    ordinal : '%d',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Swedish [sv]
+//! author : Jens Alm : https://github.com/ulmus
+
+moment.defineLocale('sv', {
+    months : 'januari_februari_mars_april_maj_juni_juli_augusti_september_oktober_november_december'.split('_'),
+    monthsShort : 'jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec'.split('_'),
+    weekdays : 'söndag_måndag_tisdag_onsdag_torsdag_fredag_lördag'.split('_'),
+    weekdaysShort : 'sön_mån_tis_ons_tor_fre_lör'.split('_'),
+    weekdaysMin : 'sö_må_ti_on_to_fr_lö'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'YYYY-MM-DD',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY [kl.] HH:mm',
+        LLLL : 'dddd D MMMM YYYY [kl.] HH:mm',
+        lll : 'D MMM YYYY HH:mm',
+        llll : 'ddd D MMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Idag] LT',
+        nextDay: '[Imorgon] LT',
+        lastDay: '[Igår] LT',
+        nextWeek: '[PÃ¥] dddd LT',
+        lastWeek: '[I] dddd[s] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'om %s',
+        past : 'för %s sedan',
+        s : 'några sekunder',
+        m : 'en minut',
+        mm : '%d minuter',
+        h : 'en timme',
+        hh : '%d timmar',
+        d : 'en dag',
+        dd : '%d dagar',
+        M : 'en månad',
+        MM : '%d månader',
+        y : 'ett år',
+        yy : '%d år'
+    },
+    ordinalParse: /\d{1,2}(e|a)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'e' :
+            (b === 1) ? 'a' :
+            (b === 2) ? 'a' :
+            (b === 3) ? 'e' : 'e';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Swahili [sw]
+//! author : Fahad Kassim : https://github.com/fadsel
+
+moment.defineLocale('sw', {
+    months : 'Januari_Februari_Machi_Aprili_Mei_Juni_Julai_Agosti_Septemba_Oktoba_Novemba_Desemba'.split('_'),
+    monthsShort : 'Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ago_Sep_Okt_Nov_Des'.split('_'),
+    weekdays : 'Jumapili_Jumatatu_Jumanne_Jumatano_Alhamisi_Ijumaa_Jumamosi'.split('_'),
+    weekdaysShort : 'Jpl_Jtat_Jnne_Jtan_Alh_Ijm_Jmos'.split('_'),
+    weekdaysMin : 'J2_J3_J4_J5_Al_Ij_J1'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[leo saa] LT',
+        nextDay : '[kesho saa] LT',
+        nextWeek : '[wiki ijayo] dddd [saat] LT',
+        lastDay : '[jana] LT',
+        lastWeek : '[wiki iliyopita] dddd [saat] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s baadaye',
+        past : 'tokea %s',
+        s : 'hivi punde',
+        m : 'dakika moja',
+        mm : 'dakika %d',
+        h : 'saa limoja',
+        hh : 'masaa %d',
+        d : 'siku moja',
+        dd : 'masiku %d',
+        M : 'mwezi mmoja',
+        MM : 'miezi %d',
+        y : 'mwaka mmoja',
+        yy : 'miaka %d'
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Tamil [ta]
+//! author : Arjunkumar Krishnamoorthy : https://github.com/tk120404
+
+var symbolMap$11 = {
+    '1': '௧',
+    '2': '௨',
+    '3': '௩',
+    '4': '௪',
+    '5': '௫',
+    '6': '௬',
+    '7': '௭',
+    '8': '௮',
+    '9': '௯',
+    '0': '௦'
+};
+var numberMap$10 = {
+    '௧': '1',
+    '௨': '2',
+    '௩': '3',
+    '௪': '4',
+    '௫': '5',
+    '௬': '6',
+    '௭': '7',
+    '௮': '8',
+    '௯': '9',
+    '௦': '0'
+};
+
+moment.defineLocale('ta', {
+    months : 'ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்'.split('_'),
+    monthsShort : 'ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்'.split('_'),
+    weekdays : 'ஞாயிற்றுக்கிழமை_திங்கட்கிழமை_செவ்வாய்கிழமை_புதன்கிழமை_வியாழக்கிழமை_வெள்ளிக்கிழமை_சனிக்கிழமை'.split('_'),
+    weekdaysShort : 'ஞாயிறு_திங்கள்_செவ்வாய்_புதன்_வியாழன்_வெள்ளி_சனி'.split('_'),
+    weekdaysMin : 'ஞா_தி_செ_பு_வி_வெ_ச'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, HH:mm',
+        LLLL : 'dddd, D MMMM YYYY, HH:mm'
+    },
+    calendar : {
+        sameDay : '[இன்று] LT',
+        nextDay : '[நாளை] LT',
+        nextWeek : 'dddd, LT',
+        lastDay : '[நேற்று] LT',
+        lastWeek : '[கடந்த வாரம்] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s இல்',
+        past : '%s முன்',
+        s : 'ஒரு சில விநாடிகள்',
+        m : 'ஒரு நிமிடம்',
+        mm : '%d நிமிடங்கள்',
+        h : 'ஒரு மணி நேரம்',
+        hh : '%d மணி நேரம்',
+        d : 'ஒரு நாள்',
+        dd : '%d நாட்கள்',
+        M : 'ஒரு மாதம்',
+        MM : '%d மாதங்கள்',
+        y : 'ஒரு வருடம்',
+        yy : '%d ஆண்டுகள்'
+    },
+    ordinalParse: /\d{1,2}வது/,
+    ordinal : function (number) {
+        return number + 'வது';
+    },
+    preparse: function (string) {
+        return string.replace(/[௧௨௩௪௫௬௭௮௯௦]/g, function (match) {
+            return numberMap$10[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap$11[match];
+        });
+    },
+    // refer http://ta.wikipedia.org/s/1er1
+    meridiemParse: /யாமம்|வைகறை|காலை|நண்பகல்|எற்பாடு|மாலை/,
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 2) {
+            return ' யாமம்';
+        } else if (hour < 6) {
+            return ' வைகறை';  // வைகறை
+        } else if (hour < 10) {
+            return ' காலை'; // காலை
+        } else if (hour < 14) {
+            return ' நண்பகல்'; // நண்பகல்
+        } else if (hour < 18) {
+            return ' எற்பாடு'; // எற்பாடு
+        } else if (hour < 22) {
+            return ' மாலை'; // மாலை
+        } else {
+            return ' யாமம்';
+        }
+    },
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'யாமம்') {
+            return hour < 2 ? hour : hour + 12;
+        } else if (meridiem === 'வைகறை' || meridiem === 'காலை') {
+            return hour;
+        } else if (meridiem === 'நண்பகல்') {
+            return hour >= 10 ? hour : hour + 12;
+        } else {
+            return hour + 12;
+        }
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Telugu [te]
+//! author : Krishna Chaitanya Thota : https://github.com/kcthota
+
+moment.defineLocale('te', {
+    months : 'జనవరి_ఫిబ్రవరి_మార్చి_ఏప్రిల్_మే_జూన్_జూలై_ఆగస్టు_సెప్టెంబర్_అక్టోబర్_నవంబర్_డిసెంబర్'.split('_'),
+    monthsShort : 'జన._ఫిబ్ర._మార్చి_ఏప్రి._మే_జూన్_జూలై_ఆగ._సెప్._అక్టో._నవ._డిసె.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'ఆదివారం_సోమవారం_మంగళవారం_బుధవారం_గురువారం_శుక్రవారం_శనివారం'.split('_'),
+    weekdaysShort : 'ఆది_సోమ_మంగళ_బుధ_గురు_శుక్ర_శని'.split('_'),
+    weekdaysMin : 'ఆ_సో_మం_బు_గు_శు_శ'.split('_'),
+    longDateFormat : {
+        LT : 'A h:mm',
+        LTS : 'A h:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, A h:mm',
+        LLLL : 'dddd, D MMMM YYYY, A h:mm'
+    },
+    calendar : {
+        sameDay : '[నేడు] LT',
+        nextDay : '[రేపు] LT',
+        nextWeek : 'dddd, LT',
+        lastDay : '[నిన్న] LT',
+        lastWeek : '[à°—à°¤] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s లో',
+        past : '%s క్రితం',
+        s : 'కొన్ని క్షణాలు',
+        m : 'ఒక నిమిషం',
+        mm : '%d నిమిషాలు',
+        h : 'à°’à°• à°—à°‚à°Ÿ',
+        hh : '%d గంటలు',
+        d : 'ఒక రోజు',
+        dd : '%d రోజులు',
+        M : 'ఒక నెల',
+        MM : '%d నెలలు',
+        y : 'ఒక సంవత్సరం',
+        yy : '%d సంవత్సరాలు'
+    },
+    ordinalParse : /\d{1,2}à°µ/,
+    ordinal : '%dà°µ',
+    meridiemParse: /రాత్రి|ఉదయం|మధ్యాహ్నం|సాయంత్రం/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'రాత్రి') {
+            return hour < 4 ? hour : hour + 12;
+        } else if (meridiem === 'ఉదయం') {
+            return hour;
+        } else if (meridiem === 'మధ్యాహ్నం') {
+            return hour >= 10 ? hour : hour + 12;
+        } else if (meridiem === 'సాయంత్రం') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'రాత్రి';
+        } else if (hour < 10) {
+            return 'ఉదయం';
+        } else if (hour < 17) {
+            return 'మధ్యాహ్నం';
+        } else if (hour < 20) {
+            return 'సాయంత్రం';
+        } else {
+            return 'రాత్రి';
+        }
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Tetun Dili (East Timor) [tet]
+//! author : Joshua Brooks : https://github.com/joshbrooks
+//! author : Onorio De J. Afonso : https://github.com/marobo
+
+moment.defineLocale('tet', {
+    months : 'Janeiru_Fevereiru_Marsu_Abril_Maiu_Juniu_Juliu_Augustu_Setembru_Outubru_Novembru_Dezembru'.split('_'),
+    monthsShort : 'Jan_Fev_Mar_Abr_Mai_Jun_Jul_Aug_Set_Out_Nov_Dez'.split('_'),
+    weekdays : 'Domingu_Segunda_Tersa_Kuarta_Kinta_Sexta_Sabadu'.split('_'),
+    weekdaysShort : 'Dom_Seg_Ters_Kua_Kint_Sext_Sab'.split('_'),
+    weekdaysMin : 'Do_Seg_Te_Ku_Ki_Sex_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Ohin iha] LT',
+        nextDay: '[Aban iha] LT',
+        nextWeek: 'dddd [iha] LT',
+        lastDay: '[Horiseik iha] LT',
+        lastWeek: 'dddd [semana kotuk] [iha] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'iha %s',
+        past : '%s liuba',
+        s : 'minutu balun',
+        m : 'minutu ida',
+        mm : 'minutus %d',
+        h : 'horas ida',
+        hh : 'horas %d',
+        d : 'loron ida',
+        dd : 'loron %d',
+        M : 'fulan ida',
+        MM : 'fulan %d',
+        y : 'tinan ida',
+        yy : 'tinan %d'
+    },
+    ordinalParse: /\d{1,2}(st|nd|rd|th)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Thai [th]
+//! author : Kridsada Thanabulpong : https://github.com/sirn
+
+moment.defineLocale('th', {
+    months : 'มกราคม_กุมภาพันธ์_มีนาคม_เมษายน_พฤษภาคม_มิถุนายน_กรกฎาคม_สิงหาคม_กันยายน_ตุลาคม_พฤศจิกายน_ธันวาคม'.split('_'),
+    monthsShort : 'ม.ค._ก.พ._มี.ค._เม.ย._พ.ค._มิ.ย._ก.ค._ส.ค._ก.ย._ต.ค._พ.ย._ธ.ค.'.split('_'),
+    monthsParseExact: true,
+    weekdays : 'อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัสบดี_ศุกร์_เสาร์'.split('_'),
+    weekdaysShort : 'อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัส_ศุกร์_เสาร์'.split('_'), // yes, three characters difference
+    weekdaysMin : 'อา._จ._อ._พ._พฤ._ศ._ส.'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'YYYY/MM/DD',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY เวลา H:mm',
+        LLLL : 'วันddddที่ D MMMM YYYY เวลา H:mm'
+    },
+    meridiemParse: /ก่อนเที่ยง|หลังเที่ยง/,
+    isPM: function (input) {
+        return input === 'หลังเที่ยง';
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return 'ก่อนเที่ยง';
+        } else {
+            return 'หลังเที่ยง';
+        }
+    },
+    calendar : {
+        sameDay : '[วันนี้ เวลา] LT',
+        nextDay : '[พรุ่งนี้ เวลา] LT',
+        nextWeek : 'dddd[หน้า เวลา] LT',
+        lastDay : '[เมื่อวานนี้ เวลา] LT',
+        lastWeek : '[วัน]dddd[ที่แล้ว เวลา] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'อีก %s',
+        past : '%sที่แล้ว',
+        s : 'ไม่กี่วินาที',
+        m : '1 นาที',
+        mm : '%d นาที',
+        h : '1 ชั่วโมง',
+        hh : '%d ชั่วโมง',
+        d : '1 วัน',
+        dd : '%d วัน',
+        M : '1 เดือน',
+        MM : '%d เดือน',
+        y : '1 ปี',
+        yy : '%d ปี'
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Tagalog (Philippines) [tl-ph]
+//! author : Dan Hagman : https://github.com/hagmandan
+
+moment.defineLocale('tl-ph', {
+    months : 'Enero_Pebrero_Marso_Abril_Mayo_Hunyo_Hulyo_Agosto_Setyembre_Oktubre_Nobyembre_Disyembre'.split('_'),
+    monthsShort : 'Ene_Peb_Mar_Abr_May_Hun_Hul_Ago_Set_Okt_Nob_Dis'.split('_'),
+    weekdays : 'Linggo_Lunes_Martes_Miyerkules_Huwebes_Biyernes_Sabado'.split('_'),
+    weekdaysShort : 'Lin_Lun_Mar_Miy_Huw_Biy_Sab'.split('_'),
+    weekdaysMin : 'Li_Lu_Ma_Mi_Hu_Bi_Sab'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'MM/D/YYYY',
+        LL : 'MMMM D, YYYY',
+        LLL : 'MMMM D, YYYY HH:mm',
+        LLLL : 'dddd, MMMM DD, YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: 'LT [ngayong araw]',
+        nextDay: '[Bukas ng] LT',
+        nextWeek: 'LT [sa susunod na] dddd',
+        lastDay: 'LT [kahapon]',
+        lastWeek: 'LT [noong nakaraang] dddd',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'sa loob ng %s',
+        past : '%s ang nakalipas',
+        s : 'ilang segundo',
+        m : 'isang minuto',
+        mm : '%d minuto',
+        h : 'isang oras',
+        hh : '%d oras',
+        d : 'isang araw',
+        dd : '%d araw',
+        M : 'isang buwan',
+        MM : '%d buwan',
+        y : 'isang taon',
+        yy : '%d taon'
+    },
+    ordinalParse: /\d{1,2}/,
+    ordinal : function (number) {
+        return number;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Klingon [tlh]
+//! author : Dominika Kruk : https://github.com/amaranthrose
+
+var numbersNouns = 'pagh_wa’_cha’_wej_loS_vagh_jav_Soch_chorgh_Hut'.split('_');
+
+function translateFuture(output) {
+    var time = output;
+    time = (output.indexOf('jaj') !== -1) ?
+    time.slice(0, -3) + 'leS' :
+    (output.indexOf('jar') !== -1) ?
+    time.slice(0, -3) + 'waQ' :
+    (output.indexOf('DIS') !== -1) ?
+    time.slice(0, -3) + 'nem' :
+    time + ' pIq';
+    return time;
+}
+
+function translatePast(output) {
+    var time = output;
+    time = (output.indexOf('jaj') !== -1) ?
+    time.slice(0, -3) + 'Hu’' :
+    (output.indexOf('jar') !== -1) ?
+    time.slice(0, -3) + 'wen' :
+    (output.indexOf('DIS') !== -1) ?
+    time.slice(0, -3) + 'ben' :
+    time + ' ret';
+    return time;
+}
+
+function translate$9(number, withoutSuffix, string, isFuture) {
+    var numberNoun = numberAsNoun(number);
+    switch (string) {
+        case 'mm':
+            return numberNoun + ' tup';
+        case 'hh':
+            return numberNoun + ' rep';
+        case 'dd':
+            return numberNoun + ' jaj';
+        case 'MM':
+            return numberNoun + ' jar';
+        case 'yy':
+            return numberNoun + ' DIS';
+    }
+}
+
+function numberAsNoun(number) {
+    var hundred = Math.floor((number % 1000) / 100),
+    ten = Math.floor((number % 100) / 10),
+    one = number % 10,
+    word = '';
+    if (hundred > 0) {
+        word += numbersNouns[hundred] + 'vatlh';
+    }
+    if (ten > 0) {
+        word += ((word !== '') ? ' ' : '') + numbersNouns[ten] + 'maH';
+    }
+    if (one > 0) {
+        word += ((word !== '') ? ' ' : '') + numbersNouns[one];
+    }
+    return (word === '') ? 'pagh' : word;
+}
+
+moment.defineLocale('tlh', {
+    months : 'tera’ jar wa’_tera’ jar cha’_tera’ jar wej_tera’ jar loS_tera’ jar vagh_tera’ jar jav_tera’ jar Soch_tera’ jar chorgh_tera’ jar Hut_tera’ jar wa’maH_tera’ jar wa’maH wa’_tera’ jar wa’maH cha’'.split('_'),
+    monthsShort : 'jar wa’_jar cha’_jar wej_jar loS_jar vagh_jar jav_jar Soch_jar chorgh_jar Hut_jar wa’maH_jar wa’maH wa’_jar wa’maH cha’'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj'.split('_'),
+    weekdaysShort : 'lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj'.split('_'),
+    weekdaysMin : 'lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[DaHjaj] LT',
+        nextDay: '[wa’leS] LT',
+        nextWeek: 'LLL',
+        lastDay: '[wa’Hu’] LT',
+        lastWeek: 'LLL',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : translateFuture,
+        past : translatePast,
+        s : 'puS lup',
+        m : 'wa’ tup',
+        mm : translate$9,
+        h : 'wa’ rep',
+        hh : translate$9,
+        d : 'wa’ jaj',
+        dd : translate$9,
+        M : 'wa’ jar',
+        MM : translate$9,
+        y : 'wa’ DIS',
+        yy : translate$9
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Turkish [tr]
+//! authors : Erhan Gundogan : https://github.com/erhangundogan,
+//!           Burak YiÄŸit Kaya: https://github.com/BYK
+
+var suffixes$3 = {
+    1: '\'inci',
+    5: '\'inci',
+    8: '\'inci',
+    70: '\'inci',
+    80: '\'inci',
+    2: '\'nci',
+    7: '\'nci',
+    20: '\'nci',
+    50: '\'nci',
+    3: '\'üncü',
+    4: '\'üncü',
+    100: '\'üncü',
+    6: '\'ncı',
+    9: '\'uncu',
+    10: '\'uncu',
+    30: '\'uncu',
+    60: '\'ıncı',
+    90: '\'ıncı'
+};
+
+moment.defineLocale('tr', {
+    months : 'Ocak_Şubat_Mart_Nisan_Mayıs_Haziran_Temmuz_Ağustos_Eylül_Ekim_Kasım_Aralık'.split('_'),
+    monthsShort : 'Oca_Åžub_Mar_Nis_May_Haz_Tem_AÄŸu_Eyl_Eki_Kas_Ara'.split('_'),
+    weekdays : 'Pazar_Pazartesi_Salı_Çarşamba_Perşembe_Cuma_Cumartesi'.split('_'),
+    weekdaysShort : 'Paz_Pts_Sal_Çar_Per_Cum_Cts'.split('_'),
+    weekdaysMin : 'Pz_Pt_Sa_Ça_Pe_Cu_Ct'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[bugün saat] LT',
+        nextDay : '[yarın saat] LT',
+        nextWeek : '[haftaya] dddd [saat] LT',
+        lastDay : '[dün] LT',
+        lastWeek : '[geçen hafta] dddd [saat] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s sonra',
+        past : '%s önce',
+        s : 'birkaç saniye',
+        m : 'bir dakika',
+        mm : '%d dakika',
+        h : 'bir saat',
+        hh : '%d saat',
+        d : 'bir gün',
+        dd : '%d gün',
+        M : 'bir ay',
+        MM : '%d ay',
+        y : 'bir yıl',
+        yy : '%d yıl'
+    },
+    ordinalParse: /\d{1,2}'(inci|nci|üncü|ncı|uncu|ıncı)/,
+    ordinal : function (number) {
+        if (number === 0) {  // special case for zero
+            return number + '\'ıncı';
+        }
+        var a = number % 10,
+            b = number % 100 - a,
+            c = number >= 100 ? 100 : null;
+        return number + (suffixes$3[a] || suffixes$3[b] || suffixes$3[c]);
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Talossan [tzl]
+//! author : Robin van der Vliet : https://github.com/robin0van0der0v
+//! author : Iustì Canun
+
+// After the year there should be a slash and the amount of years since December 26, 1979 in Roman numerals.
+// This is currently too difficult (maybe even impossible) to add.
+moment.defineLocale('tzl', {
+    months : 'Januar_Fevraglh_Març_Avrïu_Mai_Gün_Julia_Guscht_Setemvar_Listopäts_Noemvar_Zecemvar'.split('_'),
+    monthsShort : 'Jan_Fev_Mar_Avr_Mai_Gün_Jul_Gus_Set_Lis_Noe_Zec'.split('_'),
+    weekdays : 'Súladi_Lúneçi_Maitzi_Márcuri_Xhúadi_Viénerçi_Sáturi'.split('_'),
+    weekdaysShort : 'Súl_Lún_Mai_Már_Xhú_Vié_Sát'.split('_'),
+    weekdaysMin : 'Sú_Lú_Ma_Má_Xh_Vi_Sá'.split('_'),
+    longDateFormat : {
+        LT : 'HH.mm',
+        LTS : 'HH.mm.ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM [dallas] YYYY',
+        LLL : 'D. MMMM [dallas] YYYY HH.mm',
+        LLLL : 'dddd, [li] D. MMMM [dallas] YYYY HH.mm'
+    },
+    meridiemParse: /d\'o|d\'a/i,
+    isPM : function (input) {
+        return 'd\'o' === input.toLowerCase();
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours > 11) {
+            return isLower ? 'd\'o' : 'D\'O';
+        } else {
+            return isLower ? 'd\'a' : 'D\'A';
+        }
+    },
+    calendar : {
+        sameDay : '[oxhi à] LT',
+        nextDay : '[demà à] LT',
+        nextWeek : 'dddd [à] LT',
+        lastDay : '[ieiri à] LT',
+        lastWeek : '[sür el] dddd [lasteu à] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'osprei %s',
+        past : 'ja%s',
+        s : processRelativeTime$5,
+        m : processRelativeTime$5,
+        mm : processRelativeTime$5,
+        h : processRelativeTime$5,
+        hh : processRelativeTime$5,
+        d : processRelativeTime$5,
+        dd : processRelativeTime$5,
+        M : processRelativeTime$5,
+        MM : processRelativeTime$5,
+        y : processRelativeTime$5,
+        yy : processRelativeTime$5
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+function processRelativeTime$5(number, withoutSuffix, key, isFuture) {
+    var format = {
+        's': ['viensas secunds', '\'iensas secunds'],
+        'm': ['\'n míut', '\'iens míut'],
+        'mm': [number + ' míuts', '' + number + ' míuts'],
+        'h': ['\'n þora', '\'iensa þora'],
+        'hh': [number + ' þoras', '' + number + ' þoras'],
+        'd': ['\'n ziua', '\'iensa ziua'],
+        'dd': [number + ' ziuas', '' + number + ' ziuas'],
+        'M': ['\'n mes', '\'iens mes'],
+        'MM': [number + ' mesen', '' + number + ' mesen'],
+        'y': ['\'n ar', '\'iens ar'],
+        'yy': [number + ' ars', '' + number + ' ars']
+    };
+    return isFuture ? format[key][0] : (withoutSuffix ? format[key][0] : format[key][1]);
+}
+
+//! moment.js locale configuration
+//! locale : Central Atlas Tamazight Latin [tzm-latn]
+//! author : Abdel Said : https://github.com/abdelsaid
+
+moment.defineLocale('tzm-latn', {
+    months : 'innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir'.split('_'),
+    monthsShort : 'innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir'.split('_'),
+    weekdays : 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'),
+    weekdaysShort : 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'),
+    weekdaysMin : 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[asdkh g] LT',
+        nextDay: '[aska g] LT',
+        nextWeek: 'dddd [g] LT',
+        lastDay: '[assant g] LT',
+        lastWeek: 'dddd [g] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'dadkh s yan %s',
+        past : 'yan %s',
+        s : 'imik',
+        m : 'minuḍ',
+        mm : '%d minuḍ',
+        h : 'saɛa',
+        hh : '%d tassaɛin',
+        d : 'ass',
+        dd : '%d ossan',
+        M : 'ayowr',
+        MM : '%d iyyirn',
+        y : 'asgas',
+        yy : '%d isgasn'
+    },
+    week : {
+        dow : 6, // Saturday is the first day of the week.
+        doy : 12  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Central Atlas Tamazight [tzm]
+//! author : Abdel Said : https://github.com/abdelsaid
+
+moment.defineLocale('tzm', {
+    months : 'ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ'.split('_'),
+    monthsShort : 'ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ'.split('_'),
+    weekdays : 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'),
+    weekdaysShort : 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'),
+    weekdaysMin : 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS: 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[ⴰⵙⴷⵅ ⴴ] LT',
+        nextDay: '[ⴰⵙⴽⴰ ⴴ] LT',
+        nextWeek: 'dddd [â´´] LT',
+        lastDay: '[ⴰⵚⴰⵏⵜ ⴴ] LT',
+        lastWeek: 'dddd [â´´] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'ⴷⴰⴷⵅ ⵙ ⵢⴰⵏ %s',
+        past : 'ⵢⴰⵏ %s',
+        s : 'ⵉⵎⵉⴽ',
+        m : 'ⵎⵉⵏⵓⴺ',
+        mm : '%d ⵎⵉⵏⵓⴺ',
+        h : 'ⵙⴰⵄⴰ',
+        hh : '%d ⵜⴰⵙⵙⴰⵄⵉⵏ',
+        d : 'ⴰⵙⵙ',
+        dd : '%d oⵙⵙⴰⵏ',
+        M : 'ⴰⵢoⵓⵔ',
+        MM : '%d ⵉⵢⵢⵉⵔⵏ',
+        y : 'ⴰⵙⴳⴰⵙ',
+        yy : '%d ⵉⵙⴳⴰⵙⵏ'
+    },
+    week : {
+        dow : 6, // Saturday is the first day of the week.
+        doy : 12  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Ukrainian [uk]
+//! author : zemlanin : https://github.com/zemlanin
+//! Author : Menelion Elensúle : https://github.com/Oire
+
+function plural$6(word, num) {
+    var forms = word.split('_');
+    return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]);
+}
+function relativeTimeWithPlural$4(number, withoutSuffix, key) {
+    var format = {
+        'mm': withoutSuffix ? 'хвилина_хвилини_хвилин' : 'хвилину_хвилини_хвилин',
+        'hh': withoutSuffix ? 'година_години_годин' : 'годину_години_годин',
+        'dd': 'день_дні_днів',
+        'MM': 'місяць_місяці_місяців',
+        'yy': 'рік_роки_років'
+    };
+    if (key === 'm') {
+        return withoutSuffix ? 'хвилина' : 'хвилину';
+    }
+    else if (key === 'h') {
+        return withoutSuffix ? 'година' : 'годину';
+    }
+    else {
+        return number + ' ' + plural$6(format[key], +number);
+    }
+}
+function weekdaysCaseReplace(m, format) {
+    var weekdays = {
+        'nominative': 'неділя_понеділок_вівторок_середа_четвер_п’ятниця_субота'.split('_'),
+        'accusative': 'неділю_понеділок_вівторок_середу_четвер_п’ятницю_суботу'.split('_'),
+        'genitive': 'неділі_понеділка_вівторка_середи_четверга_п’ятниці_суботи'.split('_')
+    },
+    nounCase = (/(\[[ВвУу]\]) ?dddd/).test(format) ?
+        'accusative' :
+        ((/\[?(?:минулої|наступної)? ?\] ?dddd/).test(format) ?
+            'genitive' :
+            'nominative');
+    return weekdays[nounCase][m.day()];
+}
+function processHoursFunction(str) {
+    return function () {
+        return str + 'о' + (this.hours() === 11 ? 'б' : '') + '] LT';
+    };
+}
+
+moment.defineLocale('uk', {
+    months : {
+        'format': 'січня_лютого_березня_квітня_травня_червня_липня_серпня_вересня_жовтня_листопада_грудня'.split('_'),
+        'standalone': 'січень_лютий_березень_квітень_травень_червень_липень_серпень_вересень_жовтень_листопад_грудень'.split('_')
+    },
+    monthsShort : 'січ_лют_бер_квіт_трав_черв_лип_серп_вер_жовт_лист_груд'.split('_'),
+    weekdays : weekdaysCaseReplace,
+    weekdaysShort : 'нд_пн_вт_ср_чт_пт_сб'.split('_'),
+    weekdaysMin : 'нд_пн_вт_ср_чт_пт_сб'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY р.',
+        LLL : 'D MMMM YYYY р., HH:mm',
+        LLLL : 'dddd, D MMMM YYYY р., HH:mm'
+    },
+    calendar : {
+        sameDay: processHoursFunction('[Сьогодні '),
+        nextDay: processHoursFunction('[Завтра '),
+        lastDay: processHoursFunction('[Вчора '),
+        nextWeek: processHoursFunction('[У] dddd ['),
+        lastWeek: function () {
+            switch (this.day()) {
+                case 0:
+                case 3:
+                case 5:
+                case 6:
+                    return processHoursFunction('[Минулої] dddd [').call(this);
+                case 1:
+                case 2:
+                case 4:
+                    return processHoursFunction('[Минулого] dddd [').call(this);
+            }
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'за %s',
+        past : '%s тому',
+        s : 'декілька секунд',
+        m : relativeTimeWithPlural$4,
+        mm : relativeTimeWithPlural$4,
+        h : 'годину',
+        hh : relativeTimeWithPlural$4,
+        d : 'день',
+        dd : relativeTimeWithPlural$4,
+        M : 'місяць',
+        MM : relativeTimeWithPlural$4,
+        y : 'рік',
+        yy : relativeTimeWithPlural$4
+    },
+    // M. E.: those two are virtually unused but a user might want to implement them for his/her website for some reason
+    meridiemParse: /ночі|ранку|дня|вечора/,
+    isPM: function (input) {
+        return /^(дня|вечора)$/.test(input);
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'ночі';
+        } else if (hour < 12) {
+            return 'ранку';
+        } else if (hour < 17) {
+            return 'дня';
+        } else {
+            return 'вечора';
+        }
+    },
+    ordinalParse: /\d{1,2}-(й|го)/,
+    ordinal: function (number, period) {
+        switch (period) {
+            case 'M':
+            case 'd':
+            case 'DDD':
+            case 'w':
+            case 'W':
+                return number + '-й';
+            case 'D':
+                return number + '-го';
+            default:
+                return number;
+        }
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Uzbek [uz]
+//! author : Sardor Muminov : https://github.com/muminoff
+
+moment.defineLocale('uz', {
+    months : 'январ_феврал_март_апрел_май_июн_июл_август_сентябр_октябр_ноябр_декабр'.split('_'),
+    monthsShort : 'янв_фев_мар_апр_май_июн_июл_авг_сен_окт_ноя_дек'.split('_'),
+    weekdays : 'Якшанба_Душанба_Сешанба_Чоршанба_Пайшанба_Жума_Шанба'.split('_'),
+    weekdaysShort : 'Якш_Душ_Сеш_Чор_Пай_Жум_Шан'.split('_'),
+    weekdaysMin : 'Як_Ду_Се_Чо_Па_Жу_Ша'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'D MMMM YYYY, dddd HH:mm'
+    },
+    calendar : {
+        sameDay : '[Бугун соат] LT [да]',
+        nextDay : '[Эртага] LT [да]',
+        nextWeek : 'dddd [куни соат] LT [да]',
+        lastDay : '[Кеча соат] LT [да]',
+        lastWeek : '[Утган] dddd [куни соат] LT [да]',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'Якин %s ичида',
+        past : 'Бир неча %s олдин',
+        s : 'фурсат',
+        m : 'бир дакика',
+        mm : '%d дакика',
+        h : 'бир соат',
+        hh : '%d соат',
+        d : 'бир кун',
+        dd : '%d кун',
+        M : 'бир ой',
+        MM : '%d ой',
+        y : 'бир йил',
+        yy : '%d йил'
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Vietnamese [vi]
+//! author : Bang Nguyen : https://github.com/bangnk
+
+moment.defineLocale('vi', {
+    months : 'tháng 1_tháng 2_tháng 3_tháng 4_tháng 5_tháng 6_tháng 7_tháng 8_tháng 9_tháng 10_tháng 11_tháng 12'.split('_'),
+    monthsShort : 'Th01_Th02_Th03_Th04_Th05_Th06_Th07_Th08_Th09_Th10_Th11_Th12'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'chủ nhật_thứ hai_thứ ba_thứ tư_thứ năm_thứ sáu_thứ bảy'.split('_'),
+    weekdaysShort : 'CN_T2_T3_T4_T5_T6_T7'.split('_'),
+    weekdaysMin : 'CN_T2_T3_T4_T5_T6_T7'.split('_'),
+    weekdaysParseExact : true,
+    meridiemParse: /sa|ch/i,
+    isPM : function (input) {
+        return /^ch$/i.test(input);
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 12) {
+            return isLower ? 'sa' : 'SA';
+        } else {
+            return isLower ? 'ch' : 'CH';
+        }
+    },
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM [năm] YYYY',
+        LLL : 'D MMMM [năm] YYYY HH:mm',
+        LLLL : 'dddd, D MMMM [năm] YYYY HH:mm',
+        l : 'DD/M/YYYY',
+        ll : 'D MMM YYYY',
+        lll : 'D MMM YYYY HH:mm',
+        llll : 'ddd, D MMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Hôm nay lúc] LT',
+        nextDay: '[Ngày mai lúc] LT',
+        nextWeek: 'dddd [tuần tới lúc] LT',
+        lastDay: '[Hôm qua lúc] LT',
+        lastWeek: 'dddd [tuần rồi lúc] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : '%s tá»›i',
+        past : '%s trước',
+        s : 'vài giây',
+        m : 'một phút',
+        mm : '%d phút',
+        h : 'một giờ',
+        hh : '%d giờ',
+        d : 'một ngày',
+        dd : '%d ngày',
+        M : 'một tháng',
+        MM : '%d tháng',
+        y : 'một năm',
+        yy : '%d năm'
+    },
+    ordinalParse: /\d{1,2}/,
+    ordinal : function (number) {
+        return number;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Pseudo [x-pseudo]
+//! author : Andrew Hood : https://github.com/andrewhood125
+
+moment.defineLocale('x-pseudo', {
+    months : 'J~áñúá~rý_F~ébrú~árý_~Márc~h_Áp~ríl_~Máý_~Júñé~_Júl~ý_Áú~gúst~_Sép~témb~ér_Ó~ctób~ér_Ñ~óvém~bér_~Décé~mbér'.split('_'),
+    monthsShort : 'J~áñ_~Féb_~Már_~Ápr_~Máý_~Júñ_~Júl_~Áúg_~Sép_~Óct_~Ñóv_~Déc'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'S~úñdá~ý_Mó~ñdáý~_Túé~sdáý~_Wéd~ñésd~áý_T~húrs~dáý_~Fríd~áý_S~átúr~dáý'.split('_'),
+    weekdaysShort : 'S~úñ_~Móñ_~Túé_~Wéd_~Thú_~Frí_~Sát'.split('_'),
+    weekdaysMin : 'S~ú_Mó~_Tú_~Wé_T~h_Fr~_Sá'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[T~ódá~ý át] LT',
+        nextDay : '[T~ómó~rró~w át] LT',
+        nextWeek : 'dddd [át] LT',
+        lastDay : '[Ý~ést~érdá~ý át] LT',
+        lastWeek : '[L~ást] dddd [át] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'í~ñ %s',
+        past : '%s á~gó',
+        s : 'á ~féw ~sécó~ñds',
+        m : 'á ~míñ~úté',
+        mm : '%d m~íñú~tés',
+        h : 'á~ñ hó~úr',
+        hh : '%d h~óúrs',
+        d : 'á ~dáý',
+        dd : '%d d~áýs',
+        M : 'á ~móñ~th',
+        MM : '%d m~óñt~hs',
+        y : 'á ~ýéár',
+        yy : '%d ý~éárs'
+    },
+    ordinalParse: /\d{1,2}(th|st|nd|rd)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Chinese (China) [zh-cn]
+//! author : suupic : https://github.com/suupic
+//! author : Zeno Zeng : https://github.com/zenozeng
+
+moment.defineLocale('zh-cn', {
+    months : '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'),
+    monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
+    weekdays : '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'),
+    weekdaysShort : '周日_周一_周二_周三_周四_周五_周六'.split('_'),
+    weekdaysMin : '日_一_二_三_四_五_六'.split('_'),
+    longDateFormat : {
+        LT : 'Ah点mm分',
+        LTS : 'Ah点m分s秒',
+        L : 'YYYY-MM-DD',
+        LL : 'YYYYå¹´MMMDæ—¥',
+        LLL : 'YYYY年MMMD日Ah点mm分',
+        LLLL : 'YYYY年MMMD日ddddAh点mm分',
+        l : 'YYYY-MM-DD',
+        ll : 'YYYYå¹´MMMDæ—¥',
+        lll : 'YYYY年MMMD日Ah点mm分',
+        llll : 'YYYY年MMMD日ddddAh点mm分'
+    },
+    meridiemParse: /凌晨|早上|上午|中午|下午|晚上/,
+    meridiemHour: function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === '凌晨' || meridiem === '早上' ||
+                meridiem === '上午') {
+            return hour;
+        } else if (meridiem === '下午' || meridiem === '晚上') {
+            return hour + 12;
+        } else {
+            // '中午'
+            return hour >= 11 ? hour : hour + 12;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        var hm = hour * 100 + minute;
+        if (hm < 600) {
+            return '凌晨';
+        } else if (hm < 900) {
+            return '早上';
+        } else if (hm < 1130) {
+            return '上午';
+        } else if (hm < 1230) {
+            return '中午';
+        } else if (hm < 1800) {
+            return '下午';
+        } else {
+            return '晚上';
+        }
+    },
+    calendar : {
+        sameDay : function () {
+            return this.minutes() === 0 ? '[今天]Ah[点整]' : '[今天]LT';
+        },
+        nextDay : function () {
+            return this.minutes() === 0 ? '[明天]Ah[点整]' : '[明天]LT';
+        },
+        lastDay : function () {
+            return this.minutes() === 0 ? '[昨天]Ah[点整]' : '[昨天]LT';
+        },
+        nextWeek : function () {
+            var startOfWeek, prefix;
+            startOfWeek = moment().startOf('week');
+            prefix = this.diff(startOfWeek, 'days') >= 7 ? '[下]' : '[本]';
+            return this.minutes() === 0 ? prefix + 'dddAh点整' : prefix + 'dddAh点mm';
+        },
+        lastWeek : function () {
+            var startOfWeek, prefix;
+            startOfWeek = moment().startOf('week');
+            prefix = this.unix() < startOfWeek.unix()  ? '[上]' : '[本]';
+            return this.minutes() === 0 ? prefix + 'dddAh点整' : prefix + 'dddAh点mm';
+        },
+        sameElse : 'LL'
+    },
+    ordinalParse: /\d{1,2}(日|月|周)/,
+    ordinal : function (number, period) {
+        switch (period) {
+            case 'd':
+            case 'D':
+            case 'DDD':
+                return number + 'æ—¥';
+            case 'M':
+                return number + '月';
+            case 'w':
+            case 'W':
+                return number + '周';
+            default:
+                return number;
+        }
+    },
+    relativeTime : {
+        future : '%s内',
+        past : '%s前',
+        s : '几秒',
+        m : '1 分钟',
+        mm : '%d 分钟',
+        h : '1 小时',
+        hh : '%d 小时',
+        d : '1 天',
+        dd : '%d 天',
+        M : '1 个月',
+        MM : '%d 个月',
+        y : '1 å¹´',
+        yy : '%d å¹´'
+    },
+    week : {
+        // GB/T 7408-1994《数据元和交换格式·信息交换·日期和时间表示法》与ISO 8601:1988等效
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Chinese (Hong Kong) [zh-hk]
+//! author : Ben : https://github.com/ben-lin
+//! author : Chris Lam : https://github.com/hehachris
+//! author : Konstantin : https://github.com/skfd
+
+moment.defineLocale('zh-hk', {
+    months : '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'),
+    monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
+    weekdays : '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'),
+    weekdaysShort : '週日_週一_週二_週三_週四_週五_週六'.split('_'),
+    weekdaysMin : '日_一_二_三_四_五_六'.split('_'),
+    longDateFormat : {
+        LT : 'Ah點mm分',
+        LTS : 'Ah點m分s秒',
+        L : 'YYYYå¹´MMMDæ—¥',
+        LL : 'YYYYå¹´MMMDæ—¥',
+        LLL : 'YYYY年MMMD日Ah點mm分',
+        LLLL : 'YYYY年MMMD日ddddAh點mm分',
+        l : 'YYYYå¹´MMMDæ—¥',
+        ll : 'YYYYå¹´MMMDæ—¥',
+        lll : 'YYYY年MMMD日Ah點mm分',
+        llll : 'YYYY年MMMD日ddddAh點mm分'
+    },
+    meridiemParse: /凌晨|早上|上午|中午|下午|晚上/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === '凌晨' || meridiem === '早上' || meridiem === '上午') {
+            return hour;
+        } else if (meridiem === '中午') {
+            return hour >= 11 ? hour : hour + 12;
+        } else if (meridiem === '下午' || meridiem === '晚上') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        var hm = hour * 100 + minute;
+        if (hm < 600) {
+            return '凌晨';
+        } else if (hm < 900) {
+            return '早上';
+        } else if (hm < 1130) {
+            return '上午';
+        } else if (hm < 1230) {
+            return '中午';
+        } else if (hm < 1800) {
+            return '下午';
+        } else {
+            return '晚上';
+        }
+    },
+    calendar : {
+        sameDay : '[今天]LT',
+        nextDay : '[明天]LT',
+        nextWeek : '[下]ddddLT',
+        lastDay : '[昨天]LT',
+        lastWeek : '[上]ddddLT',
+        sameElse : 'L'
+    },
+    ordinalParse: /\d{1,2}(日|月|週)/,
+    ordinal : function (number, period) {
+        switch (period) {
+            case 'd' :
+            case 'D' :
+            case 'DDD' :
+                return number + 'æ—¥';
+            case 'M' :
+                return number + '月';
+            case 'w' :
+            case 'W' :
+                return number + '週';
+            default :
+                return number;
+        }
+    },
+    relativeTime : {
+        future : '%så…§',
+        past : '%s前',
+        s : '幾秒',
+        m : '1 分鐘',
+        mm : '%d 分鐘',
+        h : '1 小時',
+        hh : '%d 小時',
+        d : '1 天',
+        dd : '%d 天',
+        M : '1 個月',
+        MM : '%d 個月',
+        y : '1 å¹´',
+        yy : '%d å¹´'
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Chinese (Taiwan) [zh-tw]
+//! author : Ben : https://github.com/ben-lin
+//! author : Chris Lam : https://github.com/hehachris
+
+moment.defineLocale('zh-tw', {
+    months : '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'),
+    monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
+    weekdays : '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'),
+    weekdaysShort : '週日_週一_週二_週三_週四_週五_週六'.split('_'),
+    weekdaysMin : '日_一_二_三_四_五_六'.split('_'),
+    longDateFormat : {
+        LT : 'Ah點mm分',
+        LTS : 'Ah點m分s秒',
+        L : 'YYYYå¹´MMMDæ—¥',
+        LL : 'YYYYå¹´MMMDæ—¥',
+        LLL : 'YYYY年MMMD日Ah點mm分',
+        LLLL : 'YYYY年MMMD日ddddAh點mm分',
+        l : 'YYYYå¹´MMMDæ—¥',
+        ll : 'YYYYå¹´MMMDæ—¥',
+        lll : 'YYYY年MMMD日Ah點mm分',
+        llll : 'YYYY年MMMD日ddddAh點mm分'
+    },
+    meridiemParse: /凌晨|早上|上午|中午|下午|晚上/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === '凌晨' || meridiem === '早上' || meridiem === '上午') {
+            return hour;
+        } else if (meridiem === '中午') {
+            return hour >= 11 ? hour : hour + 12;
+        } else if (meridiem === '下午' || meridiem === '晚上') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        var hm = hour * 100 + minute;
+        if (hm < 600) {
+            return '凌晨';
+        } else if (hm < 900) {
+            return '早上';
+        } else if (hm < 1130) {
+            return '上午';
+        } else if (hm < 1230) {
+            return '中午';
+        } else if (hm < 1800) {
+            return '下午';
+        } else {
+            return '晚上';
+        }
+    },
+    calendar : {
+        sameDay : '[今天]LT',
+        nextDay : '[明天]LT',
+        nextWeek : '[下]ddddLT',
+        lastDay : '[昨天]LT',
+        lastWeek : '[上]ddddLT',
+        sameElse : 'L'
+    },
+    ordinalParse: /\d{1,2}(日|月|週)/,
+    ordinal : function (number, period) {
+        switch (period) {
+            case 'd' :
+            case 'D' :
+            case 'DDD' :
+                return number + 'æ—¥';
+            case 'M' :
+                return number + '月';
+            case 'w' :
+            case 'W' :
+                return number + '週';
+            default :
+                return number;
+        }
+    },
+    relativeTime : {
+        future : '%så…§',
+        past : '%s前',
+        s : '幾秒',
+        m : '1 分鐘',
+        mm : '%d 分鐘',
+        h : '1 小時',
+        hh : '%d 小時',
+        d : '1 天',
+        dd : '%d 天',
+        M : '1 個月',
+        MM : '%d 個月',
+        y : '1 å¹´',
+        yy : '%d å¹´'
+    }
+});
+
+moment.locale('en');
+
+return moment;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/min/locales.min.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/min/locales.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..12343433be1d94cd57e5beed57a79a58deffedc2
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/min/locales.min.js
@@ -0,0 +1,659 @@
+!function(a,b){"object"==typeof exports&&"undefined"!=typeof module&&"function"==typeof require?b(require("../moment")):"function"==typeof define&&define.amd?define(["../moment"],b):b(a.moment)}(this,function(a){"use strict";
+//! moment.js locale configuration
+//! locale : Belarusian [be]
+//! author : Dmitry Demidov : https://github.com/demidov91
+//! author: Praleska: http://praleska.pro/
+//! Author : Menelion Elensúle : https://github.com/Oire
+function b(a,b){var c=a.split("_");return b%10===1&&b%100!==11?c[0]:b%10>=2&&b%10<=4&&(b%100<10||b%100>=20)?c[1]:c[2]}function c(a,c,d){var e={mm:c?"хвіліна_хвіліны_хвілін":"хвіліну_хвіліны_хвілін",hh:c?"гадзіна_гадзіны_гадзін":"гадзіну_гадзіны_гадзін",dd:"дзень_дні_дзён",MM:"месяц_месяцы_месяцаў",yy:"год_гады_гадоў"};return"m"===d?c?"хвіліна":"хвіліну":"h"===d?c?"гадзіна":"гадзіну":a+" "+b(e[d],+a)}
+//! moment.js locale configuration
+//! locale : Breton [br]
+//! author : Jean-Baptiste Le Duigou : https://github.com/jbleduigou
+function d(a,b,c){var d={mm:"munutenn",MM:"miz",dd:"devezh"};return a+" "+g(d[c],a)}function e(a){switch(f(a)){case 1:case 3:case 4:case 5:case 9:return a+" bloaz";default:return a+" vloaz"}}function f(a){return a>9?f(a%10):a}function g(a,b){return 2===b?h(a):a}function h(a){var b={m:"v",b:"v",d:"z"};return void 0===b[a.charAt(0)]?a:b[a.charAt(0)]+a.substring(1)}
+//! moment.js locale configuration
+//! locale : Bosnian [bs]
+//! author : Nedim Cholich : https://github.com/frontyard
+//! based on (hr) translation by Bojan Marković
+function i(a,b,c){var d=a+" ";switch(c){case"m":return b?"jedna minuta":"jedne minute";case"mm":return d+=1===a?"minuta":2===a||3===a||4===a?"minute":"minuta";case"h":return b?"jedan sat":"jednog sata";case"hh":return d+=1===a?"sat":2===a||3===a||4===a?"sata":"sati";case"dd":return d+=1===a?"dan":"dana";case"MM":return d+=1===a?"mjesec":2===a||3===a||4===a?"mjeseca":"mjeseci";case"yy":return d+=1===a?"godina":2===a||3===a||4===a?"godine":"godina"}}function j(a){return a>1&&a<5&&1!==~~(a/10)}function k(a,b,c,d){var e=a+" ";switch(c){case"s":// a few seconds / in a few seconds / a few seconds ago
+return b||d?"pár sekund":"pár sekundami";case"m":// a minute / in a minute / a minute ago
+return b?"minuta":d?"minutu":"minutou";case"mm":// 9 minutes / in 9 minutes / 9 minutes ago
+// 9 minutes / in 9 minutes / 9 minutes ago
+return b||d?e+(j(a)?"minuty":"minut"):e+"minutami";break;case"h":// an hour / in an hour / an hour ago
+return b?"hodina":d?"hodinu":"hodinou";case"hh":// 9 hours / in 9 hours / 9 hours ago
+// 9 hours / in 9 hours / 9 hours ago
+return b||d?e+(j(a)?"hodiny":"hodin"):e+"hodinami";break;case"d":// a day / in a day / a day ago
+return b||d?"den":"dnem";case"dd":// 9 days / in 9 days / 9 days ago
+// 9 days / in 9 days / 9 days ago
+return b||d?e+(j(a)?"dny":"dní"):e+"dny";break;case"M":// a month / in a month / a month ago
+return b||d?"měsíc":"měsícem";case"MM":// 9 months / in 9 months / 9 months ago
+// 9 months / in 9 months / 9 months ago
+return b||d?e+(j(a)?"měsíce":"měsíců"):e+"měsíci";break;case"y":// a year / in a year / a year ago
+return b||d?"rok":"rokem";case"yy":// 9 years / in 9 years / 9 years ago
+// 9 years / in 9 years / 9 years ago
+return b||d?e+(j(a)?"roky":"let"):e+"lety"}}
+//! moment.js locale configuration
+//! locale : German (Austria) [de-at]
+//! author : lluchs : https://github.com/lluchs
+//! author: Menelion Elensúle: https://github.com/Oire
+//! author : Martin Groller : https://github.com/MadMG
+//! author : Mikolaj Dadela : https://github.com/mik01aj
+function l(a,b,c,d){var e={m:["eine Minute","einer Minute"],h:["eine Stunde","einer Stunde"],d:["ein Tag","einem Tag"],dd:[a+" Tage",a+" Tagen"],M:["ein Monat","einem Monat"],MM:[a+" Monate",a+" Monaten"],y:["ein Jahr","einem Jahr"],yy:[a+" Jahre",a+" Jahren"]};return b?e[c][0]:e[c][1]}
+//! moment.js locale configuration
+//! locale : German [de]
+//! author : lluchs : https://github.com/lluchs
+//! author: Menelion Elensúle: https://github.com/Oire
+//! author : Mikolaj Dadela : https://github.com/mik01aj
+function m(a,b,c,d){var e={m:["eine Minute","einer Minute"],h:["eine Stunde","einer Stunde"],d:["ein Tag","einem Tag"],dd:[a+" Tage",a+" Tagen"],M:["ein Monat","einem Monat"],MM:[a+" Monate",a+" Monaten"],y:["ein Jahr","einem Jahr"],yy:[a+" Jahre",a+" Jahren"]};return b?e[c][0]:e[c][1]}function n(a){return a instanceof Function||"[object Function]"===Object.prototype.toString.call(a)}
+//! moment.js locale configuration
+//! locale : Estonian [et]
+//! author : Henry Kehlmann : https://github.com/madhenry
+//! improvements : Illimar Tambek : https://github.com/ragulka
+function o(a,b,c,d){var e={s:["mõne sekundi","mõni sekund","paar sekundit"],m:["ühe minuti","üks minut"],mm:[a+" minuti",a+" minutit"],h:["ühe tunni","tund aega","üks tund"],hh:[a+" tunni",a+" tundi"],d:["ühe päeva","üks päev"],M:["kuu aja","kuu aega","üks kuu"],MM:[a+" kuu",a+" kuud"],y:["ühe aasta","aasta","üks aasta"],yy:[a+" aasta",a+" aastat"]};return b?e[c][2]?e[c][2]:e[c][1]:d?e[c][0]:e[c][1]}function p(a,b,c,d){var e="";switch(c){case"s":return d?"muutaman sekunnin":"muutama sekunti";case"m":return d?"minuutin":"minuutti";case"mm":e=d?"minuutin":"minuuttia";break;case"h":return d?"tunnin":"tunti";case"hh":e=d?"tunnin":"tuntia";break;case"d":return d?"päivän":"päivä";case"dd":e=d?"päivän":"päivää";break;case"M":return d?"kuukauden":"kuukausi";case"MM":e=d?"kuukauden":"kuukautta";break;case"y":return d?"vuoden":"vuosi";case"yy":e=d?"vuoden":"vuotta"}return e=q(a,d)+" "+e}function q(a,b){return a<10?b?Ca[a]:Ba[a]:a}
+//! moment.js locale configuration
+//! locale : Croatian [hr]
+//! author : Bojan Marković : https://github.com/bmarkovic
+function r(a,b,c){var d=a+" ";switch(c){case"m":return b?"jedna minuta":"jedne minute";case"mm":return d+=1===a?"minuta":2===a||3===a||4===a?"minute":"minuta";case"h":return b?"jedan sat":"jednog sata";case"hh":return d+=1===a?"sat":2===a||3===a||4===a?"sata":"sati";case"dd":return d+=1===a?"dan":"dana";case"MM":return d+=1===a?"mjesec":2===a||3===a||4===a?"mjeseca":"mjeseci";case"yy":return d+=1===a?"godina":2===a||3===a||4===a?"godine":"godina"}}function s(a,b,c,d){var e=a;switch(c){case"s":return d||b?"néhány másodperc":"néhány másodperce";case"m":return"egy"+(d||b?" perc":" perce");case"mm":return e+(d||b?" perc":" perce");case"h":return"egy"+(d||b?" óra":" órája");case"hh":return e+(d||b?" óra":" órája");case"d":return"egy"+(d||b?" nap":" napja");case"dd":return e+(d||b?" nap":" napja");case"M":return"egy"+(d||b?" hónap":" hónapja");case"MM":return e+(d||b?" hónap":" hónapja");case"y":return"egy"+(d||b?" év":" éve");case"yy":return e+(d||b?" év":" éve")}return""}function t(a){return(a?"":"[múlt] ")+"["+Ma[this.day()]+"] LT[-kor]"}
+//! moment.js locale configuration
+//! locale : Icelandic [is]
+//! author : Hinrik Örn Sigurðsson : https://github.com/hinrik
+function u(a){return a%100===11||a%10!==1}function v(a,b,c,d){var e=a+" ";switch(c){case"s":return b||d?"nokkrar sekúndur":"nokkrum sekúndum";case"m":return b?"mínúta":"mínútu";case"mm":return u(a)?e+(b||d?"mínútur":"mínútum"):b?e+"mínúta":e+"mínútu";case"hh":return u(a)?e+(b||d?"klukkustundir":"klukkustundum"):e+"klukkustund";case"d":return b?"dagur":d?"dag":"degi";case"dd":return u(a)?b?e+"dagar":e+(d?"daga":"dögum"):b?e+"dagur":e+(d?"dag":"degi");case"M":return b?"mánuður":d?"mánuð":"mánuði";case"MM":return u(a)?b?e+"mánuðir":e+(d?"mánuði":"mánuðum"):b?e+"mánuður":e+(d?"mánuð":"mánuði");case"y":return b||d?"ár":"ári";case"yy":return u(a)?e+(b||d?"ár":"árum"):e+(b||d?"ár":"ári")}}
+//! moment.js locale configuration
+//! locale : Luxembourgish [lb]
+//! author : mweimerskirch : https://github.com/mweimerskirch
+//! author : David Raison : https://github.com/kwisatz
+function w(a,b,c,d){var e={m:["eng Minutt","enger Minutt"],h:["eng Stonn","enger Stonn"],d:["een Dag","engem Dag"],M:["ee Mount","engem Mount"],y:["ee Joer","engem Joer"]};return b?e[c][0]:e[c][1]}function x(a){var b=a.substr(0,a.indexOf(" "));return z(b)?"a "+a:"an "+a}function y(a){var b=a.substr(0,a.indexOf(" "));return z(b)?"viru "+a:"virun "+a}/**
+ * Returns true if the word before the given number loses the '-n' ending.
+ * e.g. 'an 10 Deeg' but 'a 5 Deeg'
+ *
+ * @param number {integer}
+ * @returns {boolean}
+ */
+function z(a){if(a=parseInt(a,10),isNaN(a))return!1;if(a<0)
+// Negative Number --> always true
+return!0;if(a<10)
+// Only 1 digit
+return 4<=a&&a<=7;if(a<100){
+// 2 digits
+var b=a%10,c=a/10;return z(0===b?c:b)}if(a<1e4){
+// 3 or 4 digits --> recursively check first digit
+for(;a>=10;)a/=10;return z(a)}
+// Anything larger than 4 digits: recursively check first n-3 digits
+return a/=1e3,z(a)}function A(a,b,c,d){return b?"kelios sekundės":d?"kelių sekundžių":"kelias sekundes"}function B(a,b,c,d){return b?D(c)[0]:d?D(c)[1]:D(c)[2]}function C(a){return a%10===0||a>10&&a<20}function D(a){return Pa[a].split("_")}function E(a,b,c,d){var e=a+" ";return 1===a?e+B(a,b,c[0],d):b?e+(C(a)?D(c)[1]:D(c)[0]):d?e+D(c)[1]:e+(C(a)?D(c)[1]:D(c)[2])}/**
+ * @param withoutSuffix boolean true = a length of time; false = before/after a period of time.
+ */
+function F(a,b,c){return c?b%10===1&&b%100!==11?a[2]:a[3]:b%10===1&&b%100!==11?a[0]:a[1]}function G(a,b,c){return a+" "+F(Qa[c],a,b)}function H(a,b,c){return F(Qa[c],a,b)}function I(a,b){return b?"dažas sekundes":"dažām sekundēm"}function J(a,b,c,d){var e="";if(b)switch(c){case"s":e="काही सेकंद";break;case"m":e="एक मिनिट";break;case"mm":e="%d मिनिटे";break;case"h":e="एक तास";break;case"hh":e="%d तास";break;case"d":e="एक दिवस";break;case"dd":e="%d दिवस";break;case"M":e="एक महिना";break;case"MM":e="%d महिने";break;case"y":e="एक वर्ष";break;case"yy":e="%d वर्षे"}else switch(c){case"s":e="काही सेकंदां";break;case"m":e="एका मिनिटा";break;case"mm":e="%d मिनिटां";break;case"h":e="एका तासा";break;case"hh":e="%d तासां";break;case"d":e="एका दिवसा";break;case"dd":e="%d दिवसां";break;case"M":e="एका महिन्या";break;case"MM":e="%d महिन्यां";break;case"y":e="एका वर्षा";break;case"yy":e="%d वर्षां"}return e.replace(/%d/i,a)}function K(a){return a%10<5&&a%10>1&&~~(a/10)%10!==1}function L(a,b,c){var d=a+" ";switch(c){case"m":return b?"minuta":"minutę";case"mm":return d+(K(a)?"minuty":"minut");case"h":return b?"godzina":"godzinę";case"hh":return d+(K(a)?"godziny":"godzin");case"MM":return d+(K(a)?"miesiące":"miesięcy");case"yy":return d+(K(a)?"lata":"lat")}}
+//! moment.js locale configuration
+//! locale : Romanian [ro]
+//! author : Vlad Gurdiga : https://github.com/gurdiga
+//! author : Valentin Agachi : https://github.com/avaly
+function M(a,b,c){var d={mm:"minute",hh:"ore",dd:"zile",MM:"luni",yy:"ani"},e=" ";return(a%100>=20||a>=100&&a%100===0)&&(e=" de "),a+e+d[c]}
+//! moment.js locale configuration
+//! locale : Russian [ru]
+//! author : Viktorminator : https://github.com/Viktorminator
+//! Author : Menelion Elensúle : https://github.com/Oire
+//! author : Коренберг Марк : https://github.com/socketpair
+function N(a,b){var c=a.split("_");return b%10===1&&b%100!==11?c[0]:b%10>=2&&b%10<=4&&(b%100<10||b%100>=20)?c[1]:c[2]}function O(a,b,c){var d={mm:b?"минута_минуты_минут":"минуту_минуты_минут",hh:"час_часа_часов",dd:"день_дня_дней",MM:"месяц_месяца_месяцев",yy:"год_года_лет"};return"m"===c?b?"минута":"минуту":a+" "+N(d[c],+a)}function P(a){return a>1&&a<5}function Q(a,b,c,d){var e=a+" ";switch(c){case"s":// a few seconds / in a few seconds / a few seconds ago
+return b||d?"pár sekúnd":"pár sekundami";case"m":// a minute / in a minute / a minute ago
+return b?"minúta":d?"minútu":"minútou";case"mm":// 9 minutes / in 9 minutes / 9 minutes ago
+// 9 minutes / in 9 minutes / 9 minutes ago
+return b||d?e+(P(a)?"minúty":"minút"):e+"minútami";break;case"h":// an hour / in an hour / an hour ago
+return b?"hodina":d?"hodinu":"hodinou";case"hh":// 9 hours / in 9 hours / 9 hours ago
+// 9 hours / in 9 hours / 9 hours ago
+return b||d?e+(P(a)?"hodiny":"hodín"):e+"hodinami";break;case"d":// a day / in a day / a day ago
+return b||d?"deň":"dňom";case"dd":// 9 days / in 9 days / 9 days ago
+// 9 days / in 9 days / 9 days ago
+return b||d?e+(P(a)?"dni":"dní"):e+"dňami";break;case"M":// a month / in a month / a month ago
+return b||d?"mesiac":"mesiacom";case"MM":// 9 months / in 9 months / 9 months ago
+// 9 months / in 9 months / 9 months ago
+return b||d?e+(P(a)?"mesiace":"mesiacov"):e+"mesiacmi";break;case"y":// a year / in a year / a year ago
+return b||d?"rok":"rokom";case"yy":// 9 years / in 9 years / 9 years ago
+// 9 years / in 9 years / 9 years ago
+return b||d?e+(P(a)?"roky":"rokov"):e+"rokmi"}}
+//! moment.js locale configuration
+//! locale : Slovenian [sl]
+//! author : Robert Sedovšek : https://github.com/sedovsek
+function R(a,b,c,d){var e=a+" ";switch(c){case"s":return b||d?"nekaj sekund":"nekaj sekundami";case"m":return b?"ena minuta":"eno minuto";case"mm":return e+=1===a?b?"minuta":"minuto":2===a?b||d?"minuti":"minutama":a<5?b||d?"minute":"minutami":b||d?"minut":"minutami";case"h":return b?"ena ura":"eno uro";case"hh":return e+=1===a?b?"ura":"uro":2===a?b||d?"uri":"urama":a<5?b||d?"ure":"urami":b||d?"ur":"urami";case"d":return b||d?"en dan":"enim dnem";case"dd":return e+=1===a?b||d?"dan":"dnem":2===a?b||d?"dni":"dnevoma":b||d?"dni":"dnevi";case"M":return b||d?"en mesec":"enim mesecem";case"MM":return e+=1===a?b||d?"mesec":"mesecem":2===a?b||d?"meseca":"mesecema":a<5?b||d?"mesece":"meseci":b||d?"mesecev":"meseci";case"y":return b||d?"eno leto":"enim letom";case"yy":return e+=1===a?b||d?"leto":"letom":2===a?b||d?"leti":"letoma":a<5?b||d?"leta":"leti":b||d?"let":"leti"}}function S(a){var b=a;return b=a.indexOf("jaj")!==-1?b.slice(0,-3)+"leS":a.indexOf("jar")!==-1?b.slice(0,-3)+"waQ":a.indexOf("DIS")!==-1?b.slice(0,-3)+"nem":b+" pIq"}function T(a){var b=a;return b=a.indexOf("jaj")!==-1?b.slice(0,-3)+"Hu’":a.indexOf("jar")!==-1?b.slice(0,-3)+"wen":a.indexOf("DIS")!==-1?b.slice(0,-3)+"ben":b+" ret"}function U(a,b,c,d){var e=V(a);switch(c){case"mm":return e+" tup";case"hh":return e+" rep";case"dd":return e+" jaj";case"MM":return e+" jar";case"yy":return e+" DIS"}}function V(a){var b=Math.floor(a%1e3/100),c=Math.floor(a%100/10),d=a%10,e="";return b>0&&(e+=pb[b]+"vatlh"),c>0&&(e+=(""!==e?" ":"")+pb[c]+"maH"),d>0&&(e+=(""!==e?" ":"")+pb[d]),""===e?"pagh":e}function W(a,b,c,d){var e={s:["viensas secunds","'iensas secunds"],m:["'n míut","'iens míut"],mm:[a+" míuts",""+a+" míuts"],h:["'n þora","'iensa þora"],hh:[a+" þoras",""+a+" þoras"],d:["'n ziua","'iensa ziua"],dd:[a+" ziuas",""+a+" ziuas"],M:["'n mes","'iens mes"],MM:[a+" mesen",""+a+" mesen"],y:["'n ar","'iens ar"],yy:[a+" ars",""+a+" ars"]};return d?e[c][0]:b?e[c][0]:e[c][1]}
+//! moment.js locale configuration
+//! locale : Ukrainian [uk]
+//! author : zemlanin : https://github.com/zemlanin
+//! Author : Menelion Elensúle : https://github.com/Oire
+function X(a,b){var c=a.split("_");return b%10===1&&b%100!==11?c[0]:b%10>=2&&b%10<=4&&(b%100<10||b%100>=20)?c[1]:c[2]}function Y(a,b,c){var d={mm:b?"хвилина_хвилини_хвилин":"хвилину_хвилини_хвилин",hh:b?"година_години_годин":"годину_години_годин",dd:"день_дні_днів",MM:"місяць_місяці_місяців",yy:"рік_роки_років"};return"m"===c?b?"хвилина":"хвилину":"h"===c?b?"година":"годину":a+" "+X(d[c],+a)}function Z(a,b){var c={nominative:"неділя_понеділок_вівторок_середа_четвер_п’ятниця_субота".split("_"),accusative:"неділю_понеділок_вівторок_середу_четвер_п’ятницю_суботу".split("_"),genitive:"неділі_понеділка_вівторка_середи_четверга_п’ятниці_суботи".split("_")},d=/(\[[ВвУу]\]) ?dddd/.test(b)?"accusative":/\[?(?:минулої|наступної)? ?\] ?dddd/.test(b)?"genitive":"nominative";return c[d][a.day()]}function $(a){return function(){return a+"о"+(11===this.hours()?"б":"")+"] LT"}}
+//! moment.js locale configuration
+//! locale : Afrikaans [af]
+//! author : Werner Mollentze : https://github.com/wernerm
+a.defineLocale("af",{months:"Januarie_Februarie_Maart_April_Mei_Junie_Julie_Augustus_September_Oktober_November_Desember".split("_"),monthsShort:"Jan_Feb_Mrt_Apr_Mei_Jun_Jul_Aug_Sep_Okt_Nov_Des".split("_"),weekdays:"Sondag_Maandag_Dinsdag_Woensdag_Donderdag_Vrydag_Saterdag".split("_"),weekdaysShort:"Son_Maa_Din_Woe_Don_Vry_Sat".split("_"),weekdaysMin:"So_Ma_Di_Wo_Do_Vr_Sa".split("_"),meridiemParse:/vm|nm/i,isPM:function(a){return/^nm$/i.test(a)},meridiem:function(a,b,c){return a<12?c?"vm":"VM":c?"nm":"NM"},longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Vandag om] LT",nextDay:"[Môre om] LT",nextWeek:"dddd [om] LT",lastDay:"[Gister om] LT",lastWeek:"[Laas] dddd [om] LT",sameElse:"L"},relativeTime:{future:"oor %s",past:"%s gelede",s:"'n paar sekondes",m:"'n minuut",mm:"%d minute",h:"'n uur",hh:"%d ure",d:"'n dag",dd:"%d dae",M:"'n maand",MM:"%d maande",y:"'n jaar",yy:"%d jaar"},ordinalParse:/\d{1,2}(ste|de)/,ordinal:function(a){return a+(1===a||8===a||a>=20?"ste":"de")},week:{dow:1,// Maandag is die eerste dag van die week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Arabic (Algeria) [ar-dz]
+//! author : Noureddine LOUAHEDJ : https://github.com/noureddineme
+a.defineLocale("ar-dz",{months:"جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"),monthsShort:"جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"),weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"احد_اثنين_ثلاثاء_اربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"أح_إث_ثلا_أر_خم_جم_سب".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[اليوم على الساعة] LT",nextDay:"[غدا على الساعة] LT",nextWeek:"dddd [على الساعة] LT",lastDay:"[أمس على الساعة] LT",lastWeek:"dddd [على الساعة] LT",sameElse:"L"},relativeTime:{future:"في %s",past:"منذ %s",s:"ثوان",m:"دقيقة",mm:"%d دقائق",h:"ساعة",hh:"%d ساعات",d:"يوم",dd:"%d أيام",M:"شهر",MM:"%d أشهر",y:"سنة",yy:"%d سنوات"},week:{dow:0,// Sunday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Arabic (Lybia) [ar-ly]
+//! author : Ali Hmer: https://github.com/kikoanis
+var _={1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",0:"0"},aa=function(a){return 0===a?0:1===a?1:2===a?2:a%100>=3&&a%100<=10?3:a%100>=11?4:5},ba={s:["أقل من ثانية","ثانية واحدة",["ثانيتان","ثانيتين"],"%d ثوان","%d ثانية","%d ثانية"],m:["أقل من دقيقة","دقيقة واحدة",["دقيقتان","دقيقتين"],"%d دقائق","%d دقيقة","%d دقيقة"],h:["أقل من ساعة","ساعة واحدة",["ساعتان","ساعتين"],"%d ساعات","%d ساعة","%d ساعة"],d:["أقل من يوم","يوم واحد",["يومان","يومين"],"%d أيام","%d يومًا","%d يوم"],M:["أقل من شهر","شهر واحد",["شهران","شهرين"],"%d أشهر","%d شهرا","%d شهر"],y:["أقل من عام","عام واحد",["عامان","عامين"],"%d أعوام","%d عامًا","%d عام"]},ca=function(a){return function(b,c,d,e){var f=aa(b),g=ba[a][aa(b)];return 2===f&&(g=g[c?0:1]),g.replace(/%d/i,b)}},da=["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر"];a.defineLocale("ar-ly",{months:da,monthsShort:da,weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"D/‏M/‏YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/ص|م/,isPM:function(a){return"م"===a},meridiem:function(a,b,c){return a<12?"ص":"م"},calendar:{sameDay:"[اليوم عند الساعة] LT",nextDay:"[غدًا عند الساعة] LT",nextWeek:"dddd [عند الساعة] LT",lastDay:"[أمس عند الساعة] LT",lastWeek:"dddd [عند الساعة] LT",sameElse:"L"},relativeTime:{future:"بعد %s",past:"منذ %s",s:ca("s"),m:ca("m"),mm:ca("m"),h:ca("h"),hh:ca("h"),d:ca("d"),dd:ca("d"),M:ca("M"),MM:ca("M"),y:ca("y"),yy:ca("y")},preparse:function(a){return a.replace(/\u200f/g,"").replace(/،/g,",")},postformat:function(a){return a.replace(/\d/g,function(a){return _[a]}).replace(/,/g,"،")},week:{dow:6,// Saturday is the first day of the week.
+doy:12}}),
+//! moment.js locale configuration
+//! locale : Arabic (Morocco) [ar-ma]
+//! author : ElFadili Yassine : https://github.com/ElFadiliY
+//! author : Abdel Said : https://github.com/abdelsaid
+a.defineLocale("ar-ma",{months:"يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر".split("_"),monthsShort:"يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر".split("_"),weekdays:"الأحد_الإتنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"احد_اتنين_ثلاثاء_اربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[اليوم على الساعة] LT",nextDay:"[غدا على الساعة] LT",nextWeek:"dddd [على الساعة] LT",lastDay:"[أمس على الساعة] LT",lastWeek:"dddd [على الساعة] LT",sameElse:"L"},relativeTime:{future:"في %s",past:"منذ %s",s:"ثوان",m:"دقيقة",mm:"%d دقائق",h:"ساعة",hh:"%d ساعات",d:"يوم",dd:"%d أيام",M:"شهر",MM:"%d أشهر",y:"سنة",yy:"%d سنوات"},week:{dow:6,// Saturday is the first day of the week.
+doy:12}});
+//! moment.js locale configuration
+//! locale : Arabic (Saudi Arabia) [ar-sa]
+//! author : Suhail Alkowaileet : https://github.com/xsoh
+var ea={1:"١",2:"٢",3:"٣",4:"٤",5:"٥",6:"٦",7:"٧",8:"٨",9:"٩",0:"٠"},fa={"١":"1","٢":"2","٣":"3","٤":"4","٥":"5","٦":"6","٧":"7","٨":"8","٩":"9","٠":"0"};a.defineLocale("ar-sa",{months:"يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"),monthsShort:"يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"),weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/ص|م/,isPM:function(a){return"م"===a},meridiem:function(a,b,c){return a<12?"ص":"م"},calendar:{sameDay:"[اليوم على الساعة] LT",nextDay:"[غدا على الساعة] LT",nextWeek:"dddd [على الساعة] LT",lastDay:"[أمس على الساعة] LT",lastWeek:"dddd [على الساعة] LT",sameElse:"L"},relativeTime:{future:"في %s",past:"منذ %s",s:"ثوان",m:"دقيقة",mm:"%d دقائق",h:"ساعة",hh:"%d ساعات",d:"يوم",dd:"%d أيام",M:"شهر",MM:"%d أشهر",y:"سنة",yy:"%d سنوات"},preparse:function(a){return a.replace(/[١٢٣٤٥٦٧٨٩٠]/g,function(a){return fa[a]}).replace(/،/g,",")},postformat:function(a){return a.replace(/\d/g,function(a){return ea[a]}).replace(/,/g,"،")},week:{dow:0,// Sunday is the first day of the week.
+doy:6}}),
+//! moment.js locale configuration
+//! locale  :  Arabic (Tunisia) [ar-tn]
+//! author : Nader Toukabri : https://github.com/naderio
+a.defineLocale("ar-tn",{months:"جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"),monthsShort:"جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"),weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[اليوم على الساعة] LT",nextDay:"[غدا على الساعة] LT",nextWeek:"dddd [على الساعة] LT",lastDay:"[أمس على الساعة] LT",lastWeek:"dddd [على الساعة] LT",sameElse:"L"},relativeTime:{future:"في %s",past:"منذ %s",s:"ثوان",m:"دقيقة",mm:"%d دقائق",h:"ساعة",hh:"%d ساعات",d:"يوم",dd:"%d أيام",M:"شهر",MM:"%d أشهر",y:"سنة",yy:"%d سنوات"},week:{dow:1,// Monday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Arabic [ar]
+//! author : Abdel Said: https://github.com/abdelsaid
+//! author : Ahmed Elkhatib
+//! author : forabi https://github.com/forabi
+var ga={1:"١",2:"٢",3:"٣",4:"٤",5:"٥",6:"٦",7:"٧",8:"٨",9:"٩",0:"٠"},ha={"١":"1","٢":"2","٣":"3","٤":"4","٥":"5","٦":"6","٧":"7","٨":"8","٩":"9","٠":"0"},ia=function(a){return 0===a?0:1===a?1:2===a?2:a%100>=3&&a%100<=10?3:a%100>=11?4:5},ja={s:["أقل من ثانية","ثانية واحدة",["ثانيتان","ثانيتين"],"%d ثوان","%d ثانية","%d ثانية"],m:["أقل من دقيقة","دقيقة واحدة",["دقيقتان","دقيقتين"],"%d دقائق","%d دقيقة","%d دقيقة"],h:["أقل من ساعة","ساعة واحدة",["ساعتان","ساعتين"],"%d ساعات","%d ساعة","%d ساعة"],d:["أقل من يوم","يوم واحد",["يومان","يومين"],"%d أيام","%d يومًا","%d يوم"],M:["أقل من شهر","شهر واحد",["شهران","شهرين"],"%d أشهر","%d شهرا","%d شهر"],y:["أقل من عام","عام واحد",["عامان","عامين"],"%d أعوام","%d عامًا","%d عام"]},ka=function(a){return function(b,c,d,e){var f=ia(b),g=ja[a][ia(b)];return 2===f&&(g=g[c?0:1]),g.replace(/%d/i,b)}},la=["كانون الثاني يناير","شباط فبراير","آذار مارس","نيسان أبريل","أيار مايو","حزيران يونيو","تموز يوليو","آب أغسطس","أيلول سبتمبر","تشرين الأول أكتوبر","تشرين الثاني نوفمبر","كانون الأول ديسمبر"];a.defineLocale("ar",{months:la,monthsShort:la,weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"D/‏M/‏YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/ص|م/,isPM:function(a){return"م"===a},meridiem:function(a,b,c){return a<12?"ص":"م"},calendar:{sameDay:"[اليوم عند الساعة] LT",nextDay:"[غدًا عند الساعة] LT",nextWeek:"dddd [عند الساعة] LT",lastDay:"[أمس عند الساعة] LT",lastWeek:"dddd [عند الساعة] LT",sameElse:"L"},relativeTime:{future:"بعد %s",past:"منذ %s",s:ka("s"),m:ka("m"),mm:ka("m"),h:ka("h"),hh:ka("h"),d:ka("d"),dd:ka("d"),M:ka("M"),MM:ka("M"),y:ka("y"),yy:ka("y")},preparse:function(a){return a.replace(/\u200f/g,"").replace(/[١٢٣٤٥٦٧٨٩٠]/g,function(a){return ha[a]}).replace(/،/g,",")},postformat:function(a){return a.replace(/\d/g,function(a){return ga[a]}).replace(/,/g,"،")},week:{dow:6,// Saturday is the first day of the week.
+doy:12}});
+//! moment.js locale configuration
+//! locale : Azerbaijani [az]
+//! author : topchiyev : https://github.com/topchiyev
+var ma={1:"-inci",5:"-inci",8:"-inci",70:"-inci",80:"-inci",2:"-nci",7:"-nci",20:"-nci",50:"-nci",3:"-üncü",4:"-üncü",100:"-üncü",6:"-ncı",9:"-uncu",10:"-uncu",30:"-uncu",60:"-ıncı",90:"-ıncı"};a.defineLocale("az",{months:"yanvar_fevral_mart_aprel_may_iyun_iyul_avqust_sentyabr_oktyabr_noyabr_dekabr".split("_"),monthsShort:"yan_fev_mar_apr_may_iyn_iyl_avq_sen_okt_noy_dek".split("_"),weekdays:"Bazar_Bazar ertəsi_Çərşənbə axşamı_Çərşənbə_Cümə axşamı_Cümə_Şənbə".split("_"),weekdaysShort:"Baz_BzE_ÇAx_Çər_CAx_Cüm_Şən".split("_"),weekdaysMin:"Bz_BE_ÇA_Çə_CA_Cü_Şə".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[bugün saat] LT",nextDay:"[sabah saat] LT",nextWeek:"[gələn həftə] dddd [saat] LT",lastDay:"[dünən] LT",lastWeek:"[keçən həftə] dddd [saat] LT",sameElse:"L"},relativeTime:{future:"%s sonra",past:"%s əvvəl",s:"birneçə saniyyə",m:"bir dəqiqə",mm:"%d dəqiqə",h:"bir saat",hh:"%d saat",d:"bir gün",dd:"%d gün",M:"bir ay",MM:"%d ay",y:"bir il",yy:"%d il"},meridiemParse:/gecə|səhər|gündüz|axşam/,isPM:function(a){return/^(gündüz|axşam)$/.test(a)},meridiem:function(a,b,c){return a<4?"gecə":a<12?"səhər":a<17?"gündüz":"axşam"},ordinalParse:/\d{1,2}-(ıncı|inci|nci|üncü|ncı|uncu)/,ordinal:function(a){if(0===a)// special case for zero
+return a+"-ıncı";var b=a%10,c=a%100-b,d=a>=100?100:null;return a+(ma[b]||ma[c]||ma[d])},week:{dow:1,// Monday is the first day of the week.
+doy:7}}),a.defineLocale("be",{months:{format:"студзеня_лютага_сакавіка_красавіка_траўня_чэрвеня_ліпеня_жніўня_верасня_кастрычніка_лістапада_снежня".split("_"),standalone:"студзень_люты_сакавік_красавік_травень_чэрвень_ліпень_жнівень_верасень_кастрычнік_лістапад_снежань".split("_")},monthsShort:"студ_лют_сак_крас_трав_чэрв_ліп_жнів_вер_каст_ліст_снеж".split("_"),weekdays:{format:"нядзелю_панядзелак_аўторак_сераду_чацвер_пятніцу_суботу".split("_"),standalone:"нядзеля_панядзелак_аўторак_серада_чацвер_пятніца_субота".split("_"),isFormat:/\[ ?[Вв] ?(?:мінулую|наступную)? ?\] ?dddd/},weekdaysShort:"нд_пн_ат_ср_чц_пт_сб".split("_"),weekdaysMin:"нд_пн_ат_ср_чц_пт_сб".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY г.",LLL:"D MMMM YYYY г., HH:mm",LLLL:"dddd, D MMMM YYYY г., HH:mm"},calendar:{sameDay:"[Сёння ў] LT",nextDay:"[Заўтра ў] LT",lastDay:"[Учора ў] LT",nextWeek:function(){return"[У] dddd [ў] LT"},lastWeek:function(){switch(this.day()){case 0:case 3:case 5:case 6:return"[У мінулую] dddd [ў] LT";case 1:case 2:case 4:return"[У мінулы] dddd [ў] LT"}},sameElse:"L"},relativeTime:{future:"праз %s",past:"%s таму",s:"некалькі секунд",m:c,mm:c,h:c,hh:c,d:"дзень",dd:c,M:"месяц",MM:c,y:"год",yy:c},meridiemParse:/ночы|раніцы|дня|вечара/,isPM:function(a){return/^(дня|вечара)$/.test(a)},meridiem:function(a,b,c){return a<4?"ночы":a<12?"раніцы":a<17?"дня":"вечара"},ordinalParse:/\d{1,2}-(і|ы|га)/,ordinal:function(a,b){switch(b){case"M":case"d":case"DDD":case"w":case"W":return a%10!==2&&a%10!==3||a%100===12||a%100===13?a+"-ы":a+"-і";case"D":return a+"-га";default:return a}},week:{dow:1,// Monday is the first day of the week.
+doy:7}}),a.defineLocale("bg-x",{parentLocale:"bg"}),
+//! moment.js locale configuration
+//! locale : Bulgarian [bg]
+//! author : Krasen Borisov : https://github.com/kraz
+a.defineLocale("bg",{months:"януари_февруари_март_април_май_юни_юли_август_септември_октомври_ноември_декември".split("_"),monthsShort:"янр_фев_мар_апр_май_юни_юли_авг_сеп_окт_ное_дек".split("_"),weekdays:"неделя_понеделник_вторник_сряда_четвъртък_петък_събота".split("_"),weekdaysShort:"нед_пон_вто_сря_чет_пет_съб".split("_"),weekdaysMin:"нд_пн_вт_ср_чт_пт_сб".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"D.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY H:mm",LLLL:"dddd, D MMMM YYYY H:mm"},calendar:{sameDay:"[Днес в] LT",nextDay:"[Утре в] LT",nextWeek:"dddd [в] LT",lastDay:"[Вчера в] LT",lastWeek:function(){switch(this.day()){case 0:case 3:case 6:return"[В изминалата] dddd [в] LT";case 1:case 2:case 4:case 5:return"[В изминалия] dddd [в] LT"}},sameElse:"L"},relativeTime:{future:"след %s",past:"преди %s",s:"няколко секунди",m:"минута",mm:"%d минути",h:"час",hh:"%d часа",d:"ден",dd:"%d дни",M:"месец",MM:"%d месеца",y:"година",yy:"%d години"},ordinalParse:/\d{1,2}-(ев|ен|ти|ви|ри|ми)/,ordinal:function(a){var b=a%10,c=a%100;return 0===a?a+"-ев":0===c?a+"-ен":c>10&&c<20?a+"-ти":1===b?a+"-ви":2===b?a+"-ри":7===b||8===b?a+"-ми":a+"-ти"},week:{dow:1,// Monday is the first day of the week.
+doy:7}});
+//! moment.js locale configuration
+//! locale : Bengali [bn]
+//! author : Kaushik Gandhi : https://github.com/kaushikgandhi
+var na={1:"১",2:"২",3:"৩",4:"৪",5:"৫",6:"৬",7:"৭",8:"৮",9:"৯",0:"০"},oa={"১":"1","২":"2","৩":"3","৪":"4","৫":"5","৬":"6","৭":"7","৮":"8","৯":"9","০":"0"};a.defineLocale("bn",{months:"জানুয়ারী_ফেব্রুয়ারি_মার্চ_এপ্রিল_মে_জুন_জুলাই_আগস্ট_সেপ্টেম্বর_অক্টোবর_নভেম্বর_ডিসেম্বর".split("_"),monthsShort:"জানু_ফেব_মার্চ_এপ্র_মে_জুন_জুল_আগ_সেপ্ট_অক্টো_নভে_ডিসে".split("_"),weekdays:"রবিবার_সোমবার_মঙ্গলবার_বুধবার_বৃহস্পতিবার_শুক্রবার_শনিবার".split("_"),weekdaysShort:"রবি_সোম_মঙ্গল_বুধ_বৃহস্পতি_শুক্র_শনি".split("_"),weekdaysMin:"রবি_সোম_মঙ্গ_বুধ_বৃহঃ_শুক্র_শনি".split("_"),longDateFormat:{LT:"A h:mm সময়",LTS:"A h:mm:ss সময়",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm সময়",LLLL:"dddd, D MMMM YYYY, A h:mm সময়"},calendar:{sameDay:"[আজ] LT",nextDay:"[আগামীকাল] LT",nextWeek:"dddd, LT",lastDay:"[গতকাল] LT",lastWeek:"[গত] dddd, LT",sameElse:"L"},relativeTime:{future:"%s পরে",past:"%s আগে",s:"কয়েক সেকেন্ড",m:"এক মিনিট",mm:"%d মিনিট",h:"এক ঘন্টা",hh:"%d ঘন্টা",d:"এক দিন",dd:"%d দিন",M:"এক মাস",MM:"%d মাস",y:"এক বছর",yy:"%d বছর"},preparse:function(a){return a.replace(/[১২৩৪৫৬৭৮৯০]/g,function(a){return oa[a]})},postformat:function(a){return a.replace(/\d/g,function(a){return na[a]})},meridiemParse:/রাত|সকাল|দুপুর|বিকাল|রাত/,meridiemHour:function(a,b){return 12===a&&(a=0),"রাত"===b&&a>=4||"দুপুর"===b&&a<5||"বিকাল"===b?a+12:a},meridiem:function(a,b,c){return a<4?"রাত":a<10?"সকাল":a<17?"দুপুর":a<20?"বিকাল":"রাত"},week:{dow:0,// Sunday is the first day of the week.
+doy:6}});
+//! moment.js locale configuration
+//! locale : Tibetan [bo]
+//! author : Thupten N. Chakrishar : https://github.com/vajradog
+var pa={1:"༡",2:"༢",3:"༣",4:"༤",5:"༥",6:"༦",7:"༧",8:"༨",9:"༩",0:"༠"},qa={"༡":"1","༢":"2","༣":"3","༤":"4","༥":"5","༦":"6","༧":"7","༨":"8","༩":"9","༠":"0"};a.defineLocale("bo",{months:"ཟླ་བ་དང་པོ_ཟླ་བ་གཉིས་པ_ཟླ་བ་གསུམ་པ_ཟླ་བ་བཞི་པ_ཟླ་བ་ལྔ་པ_ཟླ་བ་དྲུག་པ_ཟླ་བ་བདུན་པ_ཟླ་བ་བརྒྱད་པ_ཟླ་བ་དགུ་པ_ཟླ་བ་བཅུ་པ_ཟླ་བ་བཅུ་གཅིག་པ_ཟླ་བ་བཅུ་གཉིས་པ".split("_"),monthsShort:"ཟླ་བ་དང་པོ_ཟླ་བ་གཉིས་པ_ཟླ་བ་གསུམ་པ_ཟླ་བ་བཞི་པ_ཟླ་བ་ལྔ་པ_ཟླ་བ་དྲུག་པ_ཟླ་བ་བདུན་པ_ཟླ་བ་བརྒྱད་པ_ཟླ་བ་དགུ་པ_ཟླ་བ་བཅུ་པ_ཟླ་བ་བཅུ་གཅིག་པ_ཟླ་བ་བཅུ་གཉིས་པ".split("_"),weekdays:"གཟའ་ཉི་མ་_གཟའ་ཟླ་བ་_གཟའ་མིག་དམར་_གཟའ་ལྷག་པ་_གཟའ་ཕུར་བུ_གཟའ་པ་སངས་_གཟའ་སྤེན་པ་".split("_"),weekdaysShort:"ཉི་མ་_ཟླ་བ་_མིག་དམར་_ལྷག་པ་_ཕུར་བུ_པ་སངས་_སྤེན་པ་".split("_"),weekdaysMin:"ཉི་མ་_ཟླ་བ་_མིག་དམར་_ལྷག་པ་_ཕུར་བུ_པ་སངས་_སྤེན་པ་".split("_"),longDateFormat:{LT:"A h:mm",LTS:"A h:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm",LLLL:"dddd, D MMMM YYYY, A h:mm"},calendar:{sameDay:"[དི་རིང] LT",nextDay:"[སང་ཉིན] LT",nextWeek:"[བདུན་ཕྲག་རྗེས་མ], LT",lastDay:"[ཁ་སང] LT",lastWeek:"[བདུན་ཕྲག་མཐའ་མ] dddd, LT",sameElse:"L"},relativeTime:{future:"%s ལ་",past:"%s སྔན་ལ",s:"ལམ་སང",m:"སྐར་མ་གཅིག",mm:"%d སྐར་མ",h:"ཆུ་ཚོད་གཅིག",hh:"%d ཆུ་ཚོད",d:"ཉིན་གཅིག",dd:"%d ཉིན་",M:"ཟླ་བ་གཅིག",MM:"%d ཟླ་བ",y:"ལོ་གཅིག",yy:"%d ལོ"},preparse:function(a){return a.replace(/[༡༢༣༤༥༦༧༨༩༠]/g,function(a){return qa[a]})},postformat:function(a){return a.replace(/\d/g,function(a){return pa[a]})},meridiemParse:/མཚན་མོ|ཞོགས་ཀས|ཉིན་གུང|དགོང་དག|མཚན་མོ/,meridiemHour:function(a,b){return 12===a&&(a=0),"མཚན་མོ"===b&&a>=4||"ཉིན་གུང"===b&&a<5||"དགོང་དག"===b?a+12:a},meridiem:function(a,b,c){return a<4?"མཚན་མོ":a<10?"ཞོགས་ཀས":a<17?"ཉིན་གུང":a<20?"དགོང་དག":"མཚན་མོ"},week:{dow:0,// Sunday is the first day of the week.
+doy:6}}),a.defineLocale("br",{months:"Genver_C'hwevrer_Meurzh_Ebrel_Mae_Mezheven_Gouere_Eost_Gwengolo_Here_Du_Kerzu".split("_"),monthsShort:"Gen_C'hwe_Meu_Ebr_Mae_Eve_Gou_Eos_Gwe_Her_Du_Ker".split("_"),weekdays:"Sul_Lun_Meurzh_Merc'her_Yaou_Gwener_Sadorn".split("_"),weekdaysShort:"Sul_Lun_Meu_Mer_Yao_Gwe_Sad".split("_"),weekdaysMin:"Su_Lu_Me_Mer_Ya_Gw_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"h[e]mm A",LTS:"h[e]mm:ss A",L:"DD/MM/YYYY",LL:"D [a viz] MMMM YYYY",LLL:"D [a viz] MMMM YYYY h[e]mm A",LLLL:"dddd, D [a viz] MMMM YYYY h[e]mm A"},calendar:{sameDay:"[Hiziv da] LT",nextDay:"[Warc'hoazh da] LT",nextWeek:"dddd [da] LT",lastDay:"[Dec'h da] LT",lastWeek:"dddd [paset da] LT",sameElse:"L"},relativeTime:{future:"a-benn %s",past:"%s 'zo",s:"un nebeud segondennoù",m:"ur vunutenn",mm:d,h:"un eur",hh:"%d eur",d:"un devezh",dd:d,M:"ur miz",MM:d,y:"ur bloaz",yy:e},ordinalParse:/\d{1,2}(añ|vet)/,ordinal:function(a){var b=1===a?"añ":"vet";return a+b},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),a.defineLocale("bs",{months:"januar_februar_mart_april_maj_juni_juli_august_septembar_oktobar_novembar_decembar".split("_"),monthsShort:"jan._feb._mar._apr._maj._jun._jul._aug._sep._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota".split("_"),weekdaysShort:"ned._pon._uto._sri._čet._pet._sub.".split("_"),weekdaysMin:"ne_po_ut_sr_če_pe_su".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[danas u] LT",nextDay:"[sutra u] LT",nextWeek:function(){switch(this.day()){case 0:return"[u] [nedjelju] [u] LT";case 3:return"[u] [srijedu] [u] LT";case 6:return"[u] [subotu] [u] LT";case 1:case 2:case 4:case 5:return"[u] dddd [u] LT"}},lastDay:"[jučer u] LT",lastWeek:function(){switch(this.day()){case 0:case 3:return"[prošlu] dddd [u] LT";case 6:return"[prošle] [subote] [u] LT";case 1:case 2:case 4:case 5:return"[prošli] dddd [u] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"prije %s",s:"par sekundi",m:i,mm:i,h:i,hh:i,d:"dan",dd:i,M:"mjesec",MM:i,y:"godinu",yy:i},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:7}}),
+//! moment.js locale configuration
+//! locale : Catalan [ca]
+//! author : Juan G. Hurtado : https://github.com/juanghurtado
+a.defineLocale("ca",{months:"gener_febrer_març_abril_maig_juny_juliol_agost_setembre_octubre_novembre_desembre".split("_"),monthsShort:"gen._febr._mar._abr._mai._jun._jul._ag._set._oct._nov._des.".split("_"),monthsParseExact:!0,weekdays:"diumenge_dilluns_dimarts_dimecres_dijous_divendres_dissabte".split("_"),weekdaysShort:"dg._dl._dt._dc._dj._dv._ds.".split("_"),weekdaysMin:"Dg_Dl_Dt_Dc_Dj_Dv_Ds".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY H:mm",LLLL:"dddd D MMMM YYYY H:mm"},calendar:{sameDay:function(){return"[avui a "+(1!==this.hours()?"les":"la")+"] LT"},nextDay:function(){return"[demà a "+(1!==this.hours()?"les":"la")+"] LT"},nextWeek:function(){return"dddd [a "+(1!==this.hours()?"les":"la")+"] LT"},lastDay:function(){return"[ahir a "+(1!==this.hours()?"les":"la")+"] LT"},lastWeek:function(){return"[el] dddd [passat a "+(1!==this.hours()?"les":"la")+"] LT"},sameElse:"L"},relativeTime:{future:"en %s",past:"fa %s",s:"uns segons",m:"un minut",mm:"%d minuts",h:"una hora",hh:"%d hores",d:"un dia",dd:"%d dies",M:"un mes",MM:"%d mesos",y:"un any",yy:"%d anys"},ordinalParse:/\d{1,2}(r|n|t|è|a)/,ordinal:function(a,b){var c=1===a?"r":2===a?"n":3===a?"r":4===a?"t":"è";return"w"!==b&&"W"!==b||(c="a"),a+c},week:{dow:1,// Monday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Czech [cs]
+//! author : petrbela : https://github.com/petrbela
+var ra="leden_únor_březen_duben_květen_červen_červenec_srpen_září_říjen_listopad_prosinec".split("_"),sa="led_úno_bře_dub_kvě_čvn_čvc_srp_zář_říj_lis_pro".split("_");a.defineLocale("cs",{months:ra,monthsShort:sa,monthsParse:function(a,b){var c,d=[];for(c=0;c<12;c++)
+// use custom parser to solve problem with July (červenec)
+d[c]=new RegExp("^"+a[c]+"$|^"+b[c]+"$","i");return d}(ra,sa),shortMonthsParse:function(a){var b,c=[];for(b=0;b<12;b++)c[b]=new RegExp("^"+a[b]+"$","i");return c}(sa),longMonthsParse:function(a){var b,c=[];for(b=0;b<12;b++)c[b]=new RegExp("^"+a[b]+"$","i");return c}(ra),weekdays:"neděle_pondělí_úterý_středa_čtvrtek_pátek_sobota".split("_"),weekdaysShort:"ne_po_út_st_čt_pá_so".split("_"),weekdaysMin:"ne_po_út_st_čt_pá_so".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd D. MMMM YYYY H:mm",l:"D. M. YYYY"},calendar:{sameDay:"[dnes v] LT",nextDay:"[zítra v] LT",nextWeek:function(){switch(this.day()){case 0:return"[v neděli v] LT";case 1:case 2:return"[v] dddd [v] LT";case 3:return"[ve středu v] LT";case 4:return"[ve čtvrtek v] LT";case 5:return"[v pátek v] LT";case 6:return"[v sobotu v] LT"}},lastDay:"[včera v] LT",lastWeek:function(){switch(this.day()){case 0:return"[minulou neděli v] LT";case 1:case 2:return"[minulé] dddd [v] LT";case 3:return"[minulou středu v] LT";case 4:case 5:return"[minulý] dddd [v] LT";case 6:return"[minulou sobotu v] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"před %s",s:k,m:k,mm:k,h:k,hh:k,d:k,dd:k,M:k,MM:k,y:k,yy:k},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Chuvash [cv]
+//! author : Anatoly Mironov : https://github.com/mirontoli
+a.defineLocale("cv",{months:"кӑрлач_нарӑс_пуш_ака_май_ҫӗртме_утӑ_ҫурла_авӑн_юпа_чӳк_раштав".split("_"),monthsShort:"кӑр_нар_пуш_ака_май_ҫӗр_утӑ_ҫур_авн_юпа_чӳк_раш".split("_"),weekdays:"вырсарникун_тунтикун_ытларикун_юнкун_кӗҫнерникун_эрнекун_шӑматкун".split("_"),weekdaysShort:"выр_тун_ытл_юн_кӗҫ_эрн_шӑм".split("_"),weekdaysMin:"вр_тн_ыт_юн_кҫ_эр_шм".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD-MM-YYYY",LL:"YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ]",LLL:"YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm",LLLL:"dddd, YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm"},calendar:{sameDay:"[Паян] LT [сехетре]",nextDay:"[Ыран] LT [сехетре]",lastDay:"[Ӗнер] LT [сехетре]",nextWeek:"[Ҫитес] dddd LT [сехетре]",lastWeek:"[Иртнӗ] dddd LT [сехетре]",sameElse:"L"},relativeTime:{future:function(a){var b=/сехет$/i.exec(a)?"рен":/ҫул$/i.exec(a)?"тан":"ран";return a+b},past:"%s каялла",s:"пӗр-ик ҫеккунт",m:"пӗр минут",mm:"%d минут",h:"пӗр сехет",hh:"%d сехет",d:"пӗр кун",dd:"%d кун",M:"пӗр уйӑх",MM:"%d уйӑх",y:"пӗр ҫул",yy:"%d ҫул"},ordinalParse:/\d{1,2}-мӗш/,ordinal:"%d-мӗш",week:{dow:1,// Monday is the first day of the week.
+doy:7}}),
+//! moment.js locale configuration
+//! locale : Welsh [cy]
+//! author : Robert Allen : https://github.com/robgallen
+//! author : https://github.com/ryangreaves
+a.defineLocale("cy",{months:"Ionawr_Chwefror_Mawrth_Ebrill_Mai_Mehefin_Gorffennaf_Awst_Medi_Hydref_Tachwedd_Rhagfyr".split("_"),monthsShort:"Ion_Chwe_Maw_Ebr_Mai_Meh_Gor_Aws_Med_Hyd_Tach_Rhag".split("_"),weekdays:"Dydd Sul_Dydd Llun_Dydd Mawrth_Dydd Mercher_Dydd Iau_Dydd Gwener_Dydd Sadwrn".split("_"),weekdaysShort:"Sul_Llun_Maw_Mer_Iau_Gwe_Sad".split("_"),weekdaysMin:"Su_Ll_Ma_Me_Ia_Gw_Sa".split("_"),weekdaysParseExact:!0,
+// time formats are the same as en-gb
+longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Heddiw am] LT",nextDay:"[Yfory am] LT",nextWeek:"dddd [am] LT",lastDay:"[Ddoe am] LT",lastWeek:"dddd [diwethaf am] LT",sameElse:"L"},relativeTime:{future:"mewn %s",past:"%s yn ôl",s:"ychydig eiliadau",m:"munud",mm:"%d munud",h:"awr",hh:"%d awr",d:"diwrnod",dd:"%d diwrnod",M:"mis",MM:"%d mis",y:"blwyddyn",yy:"%d flynedd"},ordinalParse:/\d{1,2}(fed|ain|af|il|ydd|ed|eg)/,
+// traditional ordinal numbers above 31 are not commonly used in colloquial Welsh
+ordinal:function(a){var b=a,c="",d=["","af","il","ydd","ydd","ed","ed","ed","fed","fed","fed",// 1af to 10fed
+"eg","fed","eg","eg","fed","eg","eg","fed","eg","fed"];return b>20?c=40===b||50===b||60===b||80===b||100===b?"fed":"ain":b>0&&(c=d[b]),a+c},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Danish [da]
+//! author : Ulrik Nielsen : https://github.com/mrbase
+a.defineLocale("da",{months:"januar_februar_marts_april_maj_juni_juli_august_september_oktober_november_december".split("_"),monthsShort:"jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec".split("_"),weekdays:"søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag".split("_"),weekdaysShort:"søn_man_tir_ons_tor_fre_lør".split("_"),weekdaysMin:"sø_ma_ti_on_to_fr_lø".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY HH:mm",LLLL:"dddd [d.] D. MMMM YYYY HH:mm"},calendar:{sameDay:"[I dag kl.] LT",nextDay:"[I morgen kl.] LT",nextWeek:"dddd [kl.] LT",lastDay:"[I går kl.] LT",lastWeek:"[sidste] dddd [kl] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"%s siden",s:"få sekunder",m:"et minut",mm:"%d minutter",h:"en time",hh:"%d timer",d:"en dag",dd:"%d dage",M:"en måned",MM:"%d måneder",y:"et år",yy:"%d år"},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),a.defineLocale("de-at",{months:"Jänner_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember".split("_"),monthsShort:"Jän._Febr._Mrz._Apr._Mai_Jun._Jul._Aug._Sept._Okt._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag".split("_"),weekdaysShort:"So._Mo._Di._Mi._Do._Fr._Sa.".split("_"),weekdaysMin:"So_Mo_Di_Mi_Do_Fr_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY HH:mm",LLLL:"dddd, D. MMMM YYYY HH:mm"},calendar:{sameDay:"[heute um] LT [Uhr]",sameElse:"L",nextDay:"[morgen um] LT [Uhr]",nextWeek:"dddd [um] LT [Uhr]",lastDay:"[gestern um] LT [Uhr]",lastWeek:"[letzten] dddd [um] LT [Uhr]"},relativeTime:{future:"in %s",past:"vor %s",s:"ein paar Sekunden",m:l,mm:"%d Minuten",h:l,hh:"%d Stunden",d:l,dd:l,M:l,MM:l,y:l,yy:l},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),a.defineLocale("de",{months:"Januar_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember".split("_"),monthsShort:"Jan._Febr._Mrz._Apr._Mai_Jun._Jul._Aug._Sept._Okt._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag".split("_"),weekdaysShort:"So._Mo._Di._Mi._Do._Fr._Sa.".split("_"),weekdaysMin:"So_Mo_Di_Mi_Do_Fr_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY HH:mm",LLLL:"dddd, D. MMMM YYYY HH:mm"},calendar:{sameDay:"[heute um] LT [Uhr]",sameElse:"L",nextDay:"[morgen um] LT [Uhr]",nextWeek:"dddd [um] LT [Uhr]",lastDay:"[gestern um] LT [Uhr]",lastWeek:"[letzten] dddd [um] LT [Uhr]"},relativeTime:{future:"in %s",past:"vor %s",s:"ein paar Sekunden",m:m,mm:"%d Minuten",h:m,hh:"%d Stunden",d:m,dd:m,M:m,MM:m,y:m,yy:m},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Maldivian [dv]
+//! author : Jawish Hameed : https://github.com/jawish
+var ta=["ޖެނުއަރީ","ފެބްރުއަރީ","މާރިޗު","އޭޕްރީލު","މޭ","ޖޫން","ޖުލައި","އޯގަސްޓު","ސެޕްޓެމްބަރު","އޮކްޓޯބަރު","ނޮވެމްބަރު","ޑިސެމްބަރު"],ua=["އާދިއްތަ","ހޯމަ","އަންގާރަ","ބުދަ","ބުރާސްފަތި","ހުކުރު","ހޮނިހިރު"];a.defineLocale("dv",{months:ta,monthsShort:ta,weekdays:ua,weekdaysShort:ua,weekdaysMin:"އާދި_ހޯމަ_އަން_ބުދަ_ބުރާ_ހުކު_ހޮނި".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"D/M/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/މކ|މފ/,isPM:function(a){return"މފ"===a},meridiem:function(a,b,c){return a<12?"މކ":"މފ"},calendar:{sameDay:"[މިއަދު] LT",nextDay:"[މާދަމާ] LT",nextWeek:"dddd LT",lastDay:"[އިއްޔެ] LT",lastWeek:"[ފާއިތުވި] dddd LT",sameElse:"L"},relativeTime:{future:"ތެރޭގައި %s",past:"ކުރިން %s",s:"ސިކުންތުކޮޅެއް",m:"މިނިޓެއް",mm:"މިނިޓު %d",h:"ގަޑިއިރެއް",hh:"ގަޑިއިރު %d",d:"ދުވަހެއް",dd:"ދުވަސް %d",M:"މަހެއް",MM:"މަސް %d",y:"އަހަރެއް",yy:"އަހަރު %d"},preparse:function(a){return a.replace(/،/g,",")},postformat:function(a){return a.replace(/,/g,"،")},week:{dow:7,// Sunday is the first day of the week.
+doy:12}}),
+//! moment.js locale configuration
+//! locale : Greek [el]
+//! author : Aggelos Karalias : https://github.com/mehiel
+a.defineLocale("el",{monthsNominativeEl:"Ιανουάριος_Φεβρουάριος_Μάρτιος_Απρίλιος_Μάιος_Ιούνιος_Ιούλιος_Αύγουστος_Σεπτέμβριος_Οκτώβριος_Νοέμβριος_Δεκέμβριος".split("_"),monthsGenitiveEl:"Ιανουαρίου_Φεβρουαρίου_Μαρτίου_Απριλίου_Μαΐου_Ιουνίου_Ιουλίου_Αυγούστου_Σεπτεμβρίου_Οκτωβρίου_Νοεμβρίου_Δεκεμβρίου".split("_"),months:function(a,b){return/D/.test(b.substring(0,b.indexOf("MMMM")))?this._monthsGenitiveEl[a.month()]:this._monthsNominativeEl[a.month()]},monthsShort:"Ιαν_Φεβ_Μαρ_Απρ_Μαϊ_Ιουν_Ιουλ_Αυγ_Σεπ_Οκτ_Νοε_Δεκ".split("_"),weekdays:"Κυριακή_Δευτέρα_Τρίτη_Τετάρτη_Πέμπτη_Παρασκευή_Σάββατο".split("_"),weekdaysShort:"Κυρ_Δευ_Τρι_Τετ_Πεμ_Παρ_Σαβ".split("_"),weekdaysMin:"Κυ_Δε_Τρ_Τε_Πε_Πα_Σα".split("_"),meridiem:function(a,b,c){return a>11?c?"μμ":"ΜΜ":c?"πμ":"ΠΜ"},isPM:function(a){return"μ"===(a+"").toLowerCase()[0]},meridiemParse:/[ΠΜ]\.?Μ?\.?/i,longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendarEl:{sameDay:"[Σήμερα {}] LT",nextDay:"[Αύριο {}] LT",nextWeek:"dddd [{}] LT",lastDay:"[Χθες {}] LT",lastWeek:function(){switch(this.day()){case 6:return"[το προηγούμενο] dddd [{}] LT";default:return"[την προηγούμενη] dddd [{}] LT"}},sameElse:"L"},calendar:function(a,b){var c=this._calendarEl[a],d=b&&b.hours();return n(c)&&(c=c.apply(b)),c.replace("{}",d%12===1?"στη":"στις")},relativeTime:{future:"σε %s",past:"%s πριν",s:"λίγα δευτερόλεπτα",m:"ένα λεπτό",mm:"%d λεπτά",h:"μία ώρα",hh:"%d ώρες",d:"μία μέρα",dd:"%d μέρες",M:"ένας μήνας",MM:"%d μήνες",y:"ένας χρόνος",yy:"%d χρόνια"},ordinalParse:/\d{1,2}η/,ordinal:"%dη",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : English (Australia) [en-au]
+//! author : Jared Morse : https://github.com/jarcoal
+a.defineLocale("en-au",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},ordinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(a){var b=a%10,c=1===~~(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : English (Canada) [en-ca]
+//! author : Jonathan Abourbih : https://github.com/jonbca
+a.defineLocale("en-ca",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"YYYY-MM-DD",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},ordinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(a){var b=a%10,c=1===~~(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c}}),
+//! moment.js locale configuration
+//! locale : English (United Kingdom) [en-gb]
+//! author : Chris Gedrim : https://github.com/chrisgedrim
+a.defineLocale("en-gb",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},ordinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(a){var b=a%10,c=1===~~(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : English (Ireland) [en-ie]
+//! author : Chris Cartlidge : https://github.com/chriscartlidge
+a.defineLocale("en-ie",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD-MM-YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},ordinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(a){var b=a%10,c=1===~~(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : English (New Zealand) [en-nz]
+//! author : Luke McGregor : https://github.com/lukemcgregor
+a.defineLocale("en-nz",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},ordinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(a){var b=a%10,c=1===~~(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Esperanto [eo]
+//! author : Colin Dean : https://github.com/colindean
+//! komento: Mi estas malcerta se mi korekte traktis akuzativojn en tiu traduko.
+//!          Se ne, bonvolu korekti kaj avizi min por ke mi povas lerni!
+a.defineLocale("eo",{months:"januaro_februaro_marto_aprilo_majo_junio_julio_aŭgusto_septembro_oktobro_novembro_decembro".split("_"),monthsShort:"jan_feb_mar_apr_maj_jun_jul_aŭg_sep_okt_nov_dec".split("_"),weekdays:"Dimanĉo_Lundo_Mardo_Merkredo_Ĵaŭdo_Vendredo_Sabato".split("_"),weekdaysShort:"Dim_Lun_Mard_Merk_Ĵaŭ_Ven_Sab".split("_"),weekdaysMin:"Di_Lu_Ma_Me_Ĵa_Ve_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"D[-an de] MMMM, YYYY",LLL:"D[-an de] MMMM, YYYY HH:mm",LLLL:"dddd, [la] D[-an de] MMMM, YYYY HH:mm"},meridiemParse:/[ap]\.t\.m/i,isPM:function(a){return"p"===a.charAt(0).toLowerCase()},meridiem:function(a,b,c){return a>11?c?"p.t.m.":"P.T.M.":c?"a.t.m.":"A.T.M."},calendar:{sameDay:"[Hodiaŭ je] LT",nextDay:"[Morgaŭ je] LT",nextWeek:"dddd [je] LT",lastDay:"[Hieraŭ je] LT",lastWeek:"[pasinta] dddd [je] LT",sameElse:"L"},relativeTime:{future:"je %s",past:"antaŭ %s",s:"sekundoj",m:"minuto",mm:"%d minutoj",h:"horo",hh:"%d horoj",d:"tago",//ne 'diurno', ĉar estas uzita por proksimumo
+dd:"%d tagoj",M:"monato",MM:"%d monatoj",y:"jaro",yy:"%d jaroj"},ordinalParse:/\d{1,2}a/,ordinal:"%da",week:{dow:1,// Monday is the first day of the week.
+doy:7}});
+//! moment.js locale configuration
+//! locale : Spanish (Dominican Republic) [es-do]
+var va="ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.".split("_"),wa="ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic".split("_");a.defineLocale("es-do",{months:"enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre".split("_"),monthsShort:function(a,b){return/-MMM-/.test(b)?wa[a.month()]:va[a.month()]},monthsParseExact:!0,weekdays:"domingo_lunes_martes_miércoles_jueves_viernes_sábado".split("_"),weekdaysShort:"dom._lun._mar._mié._jue._vie._sáb.".split("_"),weekdaysMin:"do_lu_ma_mi_ju_vi_sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY h:mm A",LLLL:"dddd, D [de] MMMM [de] YYYY h:mm A"},calendar:{sameDay:function(){return"[hoy a la"+(1!==this.hours()?"s":"")+"] LT"},nextDay:function(){return"[mañana a la"+(1!==this.hours()?"s":"")+"] LT"},nextWeek:function(){return"dddd [a la"+(1!==this.hours()?"s":"")+"] LT"},lastDay:function(){return"[ayer a la"+(1!==this.hours()?"s":"")+"] LT"},lastWeek:function(){return"[el] dddd [pasado a la"+(1!==this.hours()?"s":"")+"] LT"},sameElse:"L"},relativeTime:{future:"en %s",past:"hace %s",s:"unos segundos",m:"un minuto",mm:"%d minutos",h:"una hora",hh:"%d horas",d:"un día",dd:"%d días",M:"un mes",MM:"%d meses",y:"un año",yy:"%d años"},ordinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,// Monday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Spanish [es]
+//! author : Julio Napurí : https://github.com/julionc
+var xa="ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.".split("_"),ya="ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic".split("_");a.defineLocale("es",{months:"enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre".split("_"),monthsShort:function(a,b){return/-MMM-/.test(b)?ya[a.month()]:xa[a.month()]},monthsParseExact:!0,weekdays:"domingo_lunes_martes_miércoles_jueves_viernes_sábado".split("_"),weekdaysShort:"dom._lun._mar._mié._jue._vie._sáb.".split("_"),weekdaysMin:"do_lu_ma_mi_ju_vi_sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY H:mm",LLLL:"dddd, D [de] MMMM [de] YYYY H:mm"},calendar:{sameDay:function(){return"[hoy a la"+(1!==this.hours()?"s":"")+"] LT"},nextDay:function(){return"[mañana a la"+(1!==this.hours()?"s":"")+"] LT"},nextWeek:function(){return"dddd [a la"+(1!==this.hours()?"s":"")+"] LT"},lastDay:function(){return"[ayer a la"+(1!==this.hours()?"s":"")+"] LT"},lastWeek:function(){return"[el] dddd [pasado a la"+(1!==this.hours()?"s":"")+"] LT"},sameElse:"L"},relativeTime:{future:"en %s",past:"hace %s",s:"unos segundos",m:"un minuto",mm:"%d minutos",h:"una hora",hh:"%d horas",d:"un día",dd:"%d días",M:"un mes",MM:"%d meses",y:"un año",yy:"%d años"},ordinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),a.defineLocale("et",{months:"jaanuar_veebruar_märts_aprill_mai_juuni_juuli_august_september_oktoober_november_detsember".split("_"),monthsShort:"jaan_veebr_märts_apr_mai_juuni_juuli_aug_sept_okt_nov_dets".split("_"),weekdays:"pühapäev_esmaspäev_teisipäev_kolmapäev_neljapäev_reede_laupäev".split("_"),weekdaysShort:"P_E_T_K_N_R_L".split("_"),weekdaysMin:"P_E_T_K_N_R_L".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[Täna,] LT",nextDay:"[Homme,] LT",nextWeek:"[Järgmine] dddd LT",lastDay:"[Eile,] LT",lastWeek:"[Eelmine] dddd LT",sameElse:"L"},relativeTime:{future:"%s pärast",past:"%s tagasi",s:o,m:o,mm:o,h:o,hh:o,d:o,dd:"%d päeva",M:o,MM:o,y:o,yy:o},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Basque [eu]
+//! author : Eneko Illarramendi : https://github.com/eillarra
+a.defineLocale("eu",{months:"urtarrila_otsaila_martxoa_apirila_maiatza_ekaina_uztaila_abuztua_iraila_urria_azaroa_abendua".split("_"),monthsShort:"urt._ots._mar._api._mai._eka._uzt._abu._ira._urr._aza._abe.".split("_"),monthsParseExact:!0,weekdays:"igandea_astelehena_asteartea_asteazkena_osteguna_ostirala_larunbata".split("_"),weekdaysShort:"ig._al._ar._az._og._ol._lr.".split("_"),weekdaysMin:"ig_al_ar_az_og_ol_lr".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"YYYY[ko] MMMM[ren] D[a]",LLL:"YYYY[ko] MMMM[ren] D[a] HH:mm",LLLL:"dddd, YYYY[ko] MMMM[ren] D[a] HH:mm",l:"YYYY-M-D",ll:"YYYY[ko] MMM D[a]",lll:"YYYY[ko] MMM D[a] HH:mm",llll:"ddd, YYYY[ko] MMM D[a] HH:mm"},calendar:{sameDay:"[gaur] LT[etan]",nextDay:"[bihar] LT[etan]",nextWeek:"dddd LT[etan]",lastDay:"[atzo] LT[etan]",lastWeek:"[aurreko] dddd LT[etan]",sameElse:"L"},relativeTime:{future:"%s barru",past:"duela %s",s:"segundo batzuk",m:"minutu bat",mm:"%d minutu",h:"ordu bat",hh:"%d ordu",d:"egun bat",dd:"%d egun",M:"hilabete bat",MM:"%d hilabete",y:"urte bat",yy:"%d urte"},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:7}});
+//! moment.js locale configuration
+//! locale : Persian [fa]
+//! author : Ebrahim Byagowi : https://github.com/ebraminio
+var za={1:"۱",2:"۲",3:"۳",4:"۴",5:"۵",6:"۶",7:"۷",8:"۸",9:"۹",0:"۰"},Aa={"۱":"1","۲":"2","۳":"3","۴":"4","۵":"5","۶":"6","۷":"7","۸":"8","۹":"9","۰":"0"};a.defineLocale("fa",{months:"ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر".split("_"),monthsShort:"ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر".split("_"),weekdays:"یک‌شنبه_دوشنبه_سه‌شنبه_چهارشنبه_پنج‌شنبه_جمعه_شنبه".split("_"),weekdaysShort:"یک‌شنبه_دوشنبه_سه‌شنبه_چهارشنبه_پنج‌شنبه_جمعه_شنبه".split("_"),weekdaysMin:"ی_د_س_چ_پ_ج_ش".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},meridiemParse:/قبل از ظهر|بعد از ظهر/,isPM:function(a){return/بعد از ظهر/.test(a)},meridiem:function(a,b,c){return a<12?"قبل از ظهر":"بعد از ظهر"},calendar:{sameDay:"[امروز ساعت] LT",nextDay:"[فردا ساعت] LT",nextWeek:"dddd [ساعت] LT",lastDay:"[دیروز ساعت] LT",lastWeek:"dddd [پیش] [ساعت] LT",sameElse:"L"},relativeTime:{future:"در %s",past:"%s پیش",s:"چندین ثانیه",m:"یک دقیقه",mm:"%d دقیقه",h:"یک ساعت",hh:"%d ساعت",d:"یک روز",dd:"%d روز",M:"یک ماه",MM:"%d ماه",y:"یک سال",yy:"%d سال"},preparse:function(a){return a.replace(/[۰-۹]/g,function(a){return Aa[a]}).replace(/،/g,",")},postformat:function(a){return a.replace(/\d/g,function(a){return za[a]}).replace(/,/g,"،")},ordinalParse:/\d{1,2}م/,ordinal:"%dم",week:{dow:6,// Saturday is the first day of the week.
+doy:12}});
+//! moment.js locale configuration
+//! locale : Finnish [fi]
+//! author : Tarmo Aidantausta : https://github.com/bleadof
+var Ba="nolla yksi kaksi kolme neljä viisi kuusi seitsemän kahdeksan yhdeksän".split(" "),Ca=["nolla","yhden","kahden","kolmen","neljän","viiden","kuuden",Ba[7],Ba[8],Ba[9]];a.defineLocale("fi",{months:"tammikuu_helmikuu_maaliskuu_huhtikuu_toukokuu_kesäkuu_heinäkuu_elokuu_syyskuu_lokakuu_marraskuu_joulukuu".split("_"),monthsShort:"tammi_helmi_maalis_huhti_touko_kesä_heinä_elo_syys_loka_marras_joulu".split("_"),weekdays:"sunnuntai_maanantai_tiistai_keskiviikko_torstai_perjantai_lauantai".split("_"),weekdaysShort:"su_ma_ti_ke_to_pe_la".split("_"),weekdaysMin:"su_ma_ti_ke_to_pe_la".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD.MM.YYYY",LL:"Do MMMM[ta] YYYY",LLL:"Do MMMM[ta] YYYY, [klo] HH.mm",LLLL:"dddd, Do MMMM[ta] YYYY, [klo] HH.mm",l:"D.M.YYYY",ll:"Do MMM YYYY",lll:"Do MMM YYYY, [klo] HH.mm",llll:"ddd, Do MMM YYYY, [klo] HH.mm"},calendar:{sameDay:"[tänään] [klo] LT",nextDay:"[huomenna] [klo] LT",nextWeek:"dddd [klo] LT",lastDay:"[eilen] [klo] LT",lastWeek:"[viime] dddd[na] [klo] LT",sameElse:"L"},relativeTime:{future:"%s päästä",past:"%s sitten",s:p,m:p,mm:p,h:p,hh:p,d:p,dd:p,M:p,MM:p,y:p,yy:p},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Faroese [fo]
+//! author : Ragnar Johannesen : https://github.com/ragnar123
+a.defineLocale("fo",{months:"januar_februar_mars_apríl_mai_juni_juli_august_september_oktober_november_desember".split("_"),monthsShort:"jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des".split("_"),weekdays:"sunnudagur_mánadagur_týsdagur_mikudagur_hósdagur_fríggjadagur_leygardagur".split("_"),weekdaysShort:"sun_mán_týs_mik_hós_frí_ley".split("_"),weekdaysMin:"su_má_tý_mi_hó_fr_le".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D. MMMM, YYYY HH:mm"},calendar:{sameDay:"[Í dag kl.] LT",nextDay:"[Í morgin kl.] LT",nextWeek:"dddd [kl.] LT",lastDay:"[Í gjár kl.] LT",lastWeek:"[síðstu] dddd [kl] LT",sameElse:"L"},relativeTime:{future:"um %s",past:"%s síðani",s:"fá sekund",m:"ein minutt",mm:"%d minuttir",h:"ein tími",hh:"%d tímar",d:"ein dagur",dd:"%d dagar",M:"ein mánaði",MM:"%d mánaðir",y:"eitt ár",yy:"%d ár"},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : French (Canada) [fr-ca]
+//! author : Jonathan Abourbih : https://github.com/jonbca
+a.defineLocale("fr-ca",{months:"janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre".split("_"),monthsShort:"janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.".split("_"),monthsParseExact:!0,weekdays:"dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi".split("_"),weekdaysShort:"dim._lun._mar._mer._jeu._ven._sam.".split("_"),weekdaysMin:"Di_Lu_Ma_Me_Je_Ve_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Aujourd'hui à] LT",nextDay:"[Demain à] LT",nextWeek:"dddd [à] LT",lastDay:"[Hier à] LT",lastWeek:"dddd [dernier à] LT",sameElse:"L"},relativeTime:{future:"dans %s",past:"il y a %s",s:"quelques secondes",m:"une minute",mm:"%d minutes",h:"une heure",hh:"%d heures",d:"un jour",dd:"%d jours",M:"un mois",MM:"%d mois",y:"un an",yy:"%d ans"},ordinalParse:/\d{1,2}(er|e)/,ordinal:function(a){return a+(1===a?"er":"e")}}),
+//! moment.js locale configuration
+//! locale : French (Switzerland) [fr-ch]
+//! author : Gaspard Bucher : https://github.com/gaspard
+a.defineLocale("fr-ch",{months:"janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre".split("_"),monthsShort:"janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.".split("_"),monthsParseExact:!0,weekdays:"dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi".split("_"),weekdaysShort:"dim._lun._mar._mer._jeu._ven._sam.".split("_"),weekdaysMin:"Di_Lu_Ma_Me_Je_Ve_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Aujourd'hui à] LT",nextDay:"[Demain à] LT",nextWeek:"dddd [à] LT",lastDay:"[Hier à] LT",lastWeek:"dddd [dernier à] LT",sameElse:"L"},relativeTime:{future:"dans %s",past:"il y a %s",s:"quelques secondes",m:"une minute",mm:"%d minutes",h:"une heure",hh:"%d heures",d:"un jour",dd:"%d jours",M:"un mois",MM:"%d mois",y:"un an",yy:"%d ans"},ordinalParse:/\d{1,2}(er|e)/,ordinal:function(a){return a+(1===a?"er":"e")},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : French [fr]
+//! author : John Fischer : https://github.com/jfroffice
+a.defineLocale("fr",{months:"janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre".split("_"),monthsShort:"janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.".split("_"),monthsParseExact:!0,weekdays:"dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi".split("_"),weekdaysShort:"dim._lun._mar._mer._jeu._ven._sam.".split("_"),weekdaysMin:"Di_Lu_Ma_Me_Je_Ve_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Aujourd'hui à] LT",nextDay:"[Demain à] LT",nextWeek:"dddd [à] LT",lastDay:"[Hier à] LT",lastWeek:"dddd [dernier à] LT",sameElse:"L"},relativeTime:{future:"dans %s",past:"il y a %s",s:"quelques secondes",m:"une minute",mm:"%d minutes",h:"une heure",hh:"%d heures",d:"un jour",dd:"%d jours",M:"un mois",MM:"%d mois",y:"un an",yy:"%d ans"},ordinalParse:/\d{1,2}(er|)/,ordinal:function(a){return a+(1===a?"er":"")},week:{dow:1,// Monday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Frisian [fy]
+//! author : Robin van der Vliet : https://github.com/robin0van0der0v
+var Da="jan._feb._mrt._apr._mai_jun._jul._aug._sep._okt._nov._des.".split("_"),Ea="jan_feb_mrt_apr_mai_jun_jul_aug_sep_okt_nov_des".split("_");a.defineLocale("fy",{months:"jannewaris_febrewaris_maart_april_maaie_juny_july_augustus_septimber_oktober_novimber_desimber".split("_"),monthsShort:function(a,b){return/-MMM-/.test(b)?Ea[a.month()]:Da[a.month()]},monthsParseExact:!0,weekdays:"snein_moandei_tiisdei_woansdei_tongersdei_freed_sneon".split("_"),weekdaysShort:"si._mo._ti._wo._to._fr._so.".split("_"),weekdaysMin:"Si_Mo_Ti_Wo_To_Fr_So".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD-MM-YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[hjoed om] LT",nextDay:"[moarn om] LT",nextWeek:"dddd [om] LT",lastDay:"[juster om] LT",lastWeek:"[ôfrûne] dddd [om] LT",sameElse:"L"},relativeTime:{future:"oer %s",past:"%s lyn",s:"in pear sekonden",m:"ien minút",mm:"%d minuten",h:"ien oere",hh:"%d oeren",d:"ien dei",dd:"%d dagen",M:"ien moanne",MM:"%d moannen",y:"ien jier",yy:"%d jierren"},ordinalParse:/\d{1,2}(ste|de)/,ordinal:function(a){return a+(1===a||8===a||a>=20?"ste":"de")},week:{dow:1,// Monday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Scottish Gaelic [gd]
+//! author : Jon Ashdown : https://github.com/jonashdown
+var Fa=["Am Faoilleach","An Gearran","Am Màrt","An Giblean","An Cèitean","An t-Ògmhios","An t-Iuchar","An Lùnastal","An t-Sultain","An Dàmhair","An t-Samhain","An Dùbhlachd"],Ga=["Faoi","Gear","Màrt","Gibl","Cèit","Ògmh","Iuch","Lùn","Sult","Dàmh","Samh","Dùbh"],Ha=["Didòmhnaich","Diluain","Dimàirt","Diciadain","Diardaoin","Dihaoine","Disathairne"],Ia=["Did","Dil","Dim","Dic","Dia","Dih","Dis"],Ja=["Dò","Lu","Mà","Ci","Ar","Ha","Sa"];a.defineLocale("gd",{months:Fa,monthsShort:Ga,monthsParseExact:!0,weekdays:Ha,weekdaysShort:Ia,weekdaysMin:Ja,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[An-diugh aig] LT",nextDay:"[A-màireach aig] LT",nextWeek:"dddd [aig] LT",lastDay:"[An-dè aig] LT",lastWeek:"dddd [seo chaidh] [aig] LT",sameElse:"L"},relativeTime:{future:"ann an %s",past:"bho chionn %s",s:"beagan diogan",m:"mionaid",mm:"%d mionaidean",h:"uair",hh:"%d uairean",d:"latha",dd:"%d latha",M:"mìos",MM:"%d mìosan",y:"bliadhna",yy:"%d bliadhna"},ordinalParse:/\d{1,2}(d|na|mh)/,ordinal:function(a){var b=1===a?"d":a%10===2?"na":"mh";return a+b},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Galician [gl]
+//! author : Juan G. Hurtado : https://github.com/juanghurtado
+a.defineLocale("gl",{months:"xaneiro_febreiro_marzo_abril_maio_xuño_xullo_agosto_setembro_outubro_novembro_decembro".split("_"),monthsShort:"xan._feb._mar._abr._mai._xuñ._xul._ago._set._out._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"domingo_luns_martes_mércores_xoves_venres_sábado".split("_"),weekdaysShort:"dom._lun._mar._mér._xov._ven._sáb.".split("_"),weekdaysMin:"do_lu_ma_mé_xo_ve_sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY H:mm",LLLL:"dddd, D [de] MMMM [de] YYYY H:mm"},calendar:{sameDay:function(){return"[hoxe "+(1!==this.hours()?"ás":"á")+"] LT"},nextDay:function(){return"[mañá "+(1!==this.hours()?"ás":"á")+"] LT"},nextWeek:function(){return"dddd ["+(1!==this.hours()?"ás":"a")+"] LT"},lastDay:function(){return"[onte "+(1!==this.hours()?"á":"a")+"] LT"},lastWeek:function(){return"[o] dddd [pasado "+(1!==this.hours()?"ás":"a")+"] LT"},sameElse:"L"},relativeTime:{future:function(a){return 0===a.indexOf("un")?"n"+a:"en "+a},past:"hai %s",s:"uns segundos",m:"un minuto",mm:"%d minutos",h:"unha hora",hh:"%d horas",d:"un día",dd:"%d días",M:"un mes",MM:"%d meses",y:"un ano",yy:"%d anos"},ordinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Hebrew [he]
+//! author : Tomer Cohen : https://github.com/tomer
+//! author : Moshe Simantov : https://github.com/DevelopmentIL
+//! author : Tal Ater : https://github.com/TalAter
+a.defineLocale("he",{months:"ינואר_פברואר_מרץ_אפריל_מאי_יוני_יולי_אוגוסט_ספטמבר_אוקטובר_נובמבר_דצמבר".split("_"),monthsShort:"ינו׳_פבר׳_מרץ_אפר׳_מאי_יוני_יולי_אוג׳_ספט׳_אוק׳_נוב׳_דצמ׳".split("_"),weekdays:"ראשון_שני_שלישי_רביעי_חמישי_שישי_שבת".split("_"),weekdaysShort:"א׳_ב׳_ג׳_ד׳_ה׳_ו׳_ש׳".split("_"),weekdaysMin:"א_ב_ג_ד_ה_ו_ש".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D [ב]MMMM YYYY",LLL:"D [ב]MMMM YYYY HH:mm",LLLL:"dddd, D [ב]MMMM YYYY HH:mm",l:"D/M/YYYY",ll:"D MMM YYYY",lll:"D MMM YYYY HH:mm",llll:"ddd, D MMM YYYY HH:mm"},calendar:{sameDay:"[היום ב־]LT",nextDay:"[מחר ב־]LT",nextWeek:"dddd [בשעה] LT",lastDay:"[אתמול ב־]LT",lastWeek:"[ביום] dddd [האחרון בשעה] LT",sameElse:"L"},relativeTime:{future:"בעוד %s",past:"לפני %s",s:"מספר שניות",m:"דקה",mm:"%d דקות",h:"שעה",hh:function(a){return 2===a?"שעתיים":a+" שעות"},d:"יום",dd:function(a){return 2===a?"יומיים":a+" ימים"},M:"חודש",MM:function(a){return 2===a?"חודשיים":a+" חודשים"},y:"שנה",yy:function(a){return 2===a?"שנתיים":a%10===0&&10!==a?a+" שנה":a+" שנים"}},meridiemParse:/אחה"צ|לפנה"צ|אחרי הצהריים|לפני הצהריים|לפנות בוקר|בבוקר|בערב/i,isPM:function(a){return/^(אחה"צ|אחרי הצהריים|בערב)$/.test(a)},meridiem:function(a,b,c){return a<5?"לפנות בוקר":a<10?"בבוקר":a<12?c?'לפנה"צ':"לפני הצהריים":a<18?c?'אחה"צ':"אחרי הצהריים":"בערב"}});
+//! moment.js locale configuration
+//! locale : Hindi [hi]
+//! author : Mayank Singhal : https://github.com/mayanksinghal
+var Ka={1:"१",2:"२",3:"३",4:"४",5:"५",6:"६",7:"७",8:"८",9:"९",0:"०"},La={"१":"1","२":"2","३":"3","४":"4","५":"5","६":"6","७":"7","८":"8","९":"9","०":"0"};a.defineLocale("hi",{months:"जनवरी_फ़रवरी_मार्च_अप्रैल_मई_जून_जुलाई_अगस्त_सितम्बर_अक्टूबर_नवम्बर_दिसम्बर".split("_"),monthsShort:"जन._फ़र._मार्च_अप्रै._मई_जून_जुल._अग._सित._अक्टू._नव._दिस.".split("_"),monthsParseExact:!0,weekdays:"रविवार_सोमवार_मंगलवार_बुधवार_गुरूवार_शुक्रवार_शनिवार".split("_"),weekdaysShort:"रवि_सोम_मंगल_बुध_गुरू_शुक्र_शनि".split("_"),weekdaysMin:"र_सो_मं_बु_गु_शु_श".split("_"),longDateFormat:{LT:"A h:mm बजे",LTS:"A h:mm:ss बजे",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm बजे",LLLL:"dddd, D MMMM YYYY, A h:mm बजे"},calendar:{sameDay:"[आज] LT",nextDay:"[कल] LT",nextWeek:"dddd, LT",lastDay:"[कल] LT",lastWeek:"[पिछले] dddd, LT",sameElse:"L"},relativeTime:{future:"%s में",past:"%s पहले",s:"कुछ ही क्षण",m:"एक मिनट",mm:"%d मिनट",h:"एक घंटा",hh:"%d घंटे",d:"एक दिन",dd:"%d दिन",M:"एक महीने",MM:"%d महीने",y:"एक वर्ष",yy:"%d वर्ष"},preparse:function(a){return a.replace(/[१२३४५६७८९०]/g,function(a){return La[a]})},postformat:function(a){return a.replace(/\d/g,function(a){return Ka[a]})},
+// Hindi notation for meridiems are quite fuzzy in practice. While there exists
+// a rigid notion of a 'Pahar' it is not used as rigidly in modern Hindi.
+meridiemParse:/रात|सुबह|दोपहर|शाम/,meridiemHour:function(a,b){return 12===a&&(a=0),"रात"===b?a<4?a:a+12:"सुबह"===b?a:"दोपहर"===b?a>=10?a:a+12:"शाम"===b?a+12:void 0},meridiem:function(a,b,c){return a<4?"रात":a<10?"सुबह":a<17?"दोपहर":a<20?"शाम":"रात"},week:{dow:0,// Sunday is the first day of the week.
+doy:6}}),a.defineLocale("hr",{months:{format:"siječnja_veljače_ožujka_travnja_svibnja_lipnja_srpnja_kolovoza_rujna_listopada_studenoga_prosinca".split("_"),standalone:"siječanj_veljača_ožujak_travanj_svibanj_lipanj_srpanj_kolovoz_rujan_listopad_studeni_prosinac".split("_")},monthsShort:"sij._velj._ožu._tra._svi._lip._srp._kol._ruj._lis._stu._pro.".split("_"),monthsParseExact:!0,weekdays:"nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota".split("_"),weekdaysShort:"ned._pon._uto._sri._čet._pet._sub.".split("_"),weekdaysMin:"ne_po_ut_sr_če_pe_su".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[danas u] LT",nextDay:"[sutra u] LT",nextWeek:function(){switch(this.day()){case 0:return"[u] [nedjelju] [u] LT";case 3:return"[u] [srijedu] [u] LT";case 6:return"[u] [subotu] [u] LT";case 1:case 2:case 4:case 5:return"[u] dddd [u] LT"}},lastDay:"[jučer u] LT",lastWeek:function(){switch(this.day()){case 0:case 3:return"[prošlu] dddd [u] LT";case 6:return"[prošle] [subote] [u] LT";case 1:case 2:case 4:case 5:return"[prošli] dddd [u] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"prije %s",s:"par sekundi",m:r,mm:r,h:r,hh:r,d:"dan",dd:r,M:"mjesec",MM:r,y:"godinu",yy:r},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:7}});
+//! moment.js locale configuration
+//! locale : Hungarian [hu]
+//! author : Adam Brunner : https://github.com/adambrunner
+var Ma="vasárnap hétfőn kedden szerdán csütörtökön pénteken szombaton".split(" ");a.defineLocale("hu",{months:"január_február_március_április_május_június_július_augusztus_szeptember_október_november_december".split("_"),monthsShort:"jan_feb_márc_ápr_máj_jún_júl_aug_szept_okt_nov_dec".split("_"),weekdays:"vasárnap_hétfő_kedd_szerda_csütörtök_péntek_szombat".split("_"),weekdaysShort:"vas_hét_kedd_sze_csüt_pén_szo".split("_"),weekdaysMin:"v_h_k_sze_cs_p_szo".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"YYYY.MM.DD.",LL:"YYYY. MMMM D.",LLL:"YYYY. MMMM D. H:mm",LLLL:"YYYY. MMMM D., dddd H:mm"},meridiemParse:/de|du/i,isPM:function(a){return"u"===a.charAt(1).toLowerCase()},meridiem:function(a,b,c){return a<12?c===!0?"de":"DE":c===!0?"du":"DU"},calendar:{sameDay:"[ma] LT[-kor]",nextDay:"[holnap] LT[-kor]",nextWeek:function(){return t.call(this,!0)},lastDay:"[tegnap] LT[-kor]",lastWeek:function(){return t.call(this,!1)},sameElse:"L"},relativeTime:{future:"%s múlva",past:"%s",s:s,m:s,mm:s,h:s,hh:s,d:s,dd:s,M:s,MM:s,y:s,yy:s},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Armenian [hy-am]
+//! author : Armendarabyan : https://github.com/armendarabyan
+a.defineLocale("hy-am",{months:{format:"հունվարի_փետրվարի_մարտի_ապրիլի_մայիսի_հունիսի_հուլիսի_օգոստոսի_սեպտեմբերի_հոկտեմբերի_նոյեմբերի_դեկտեմբերի".split("_"),standalone:"հունվար_փետրվար_մարտ_ապրիլ_մայիս_հունիս_հուլիս_օգոստոս_սեպտեմբեր_հոկտեմբեր_նոյեմբեր_դեկտեմբեր".split("_")},monthsShort:"հնվ_փտր_մրտ_ապր_մյս_հնս_հլս_օգս_սպտ_հկտ_նմբ_դկտ".split("_"),weekdays:"կիրակի_երկուշաբթի_երեքշաբթի_չորեքշաբթի_հինգշաբթի_ուրբաթ_շաբաթ".split("_"),weekdaysShort:"կրկ_երկ_երք_չրք_հնգ_ուրբ_շբթ".split("_"),weekdaysMin:"կրկ_երկ_երք_չրք_հնգ_ուրբ_շբթ".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY թ.",LLL:"D MMMM YYYY թ., HH:mm",LLLL:"dddd, D MMMM YYYY թ., HH:mm"},calendar:{sameDay:"[այսօր] LT",nextDay:"[վաղը] LT",lastDay:"[երեկ] LT",nextWeek:function(){return"dddd [օրը ժամը] LT"},lastWeek:function(){return"[անցած] dddd [օրը ժամը] LT"},sameElse:"L"},relativeTime:{future:"%s հետո",past:"%s առաջ",s:"մի քանի վայրկյան",m:"րոպե",mm:"%d րոպե",h:"ժամ",hh:"%d ժամ",d:"օր",dd:"%d օր",M:"ամիս",MM:"%d ամիս",y:"տարի",yy:"%d տարի"},meridiemParse:/գիշերվա|առավոտվա|ցերեկվա|երեկոյան/,isPM:function(a){return/^(ցերեկվա|երեկոյան)$/.test(a)},meridiem:function(a){return a<4?"գիշերվա":a<12?"առավոտվա":a<17?"ցերեկվա":"երեկոյան"},ordinalParse:/\d{1,2}|\d{1,2}-(ին|րդ)/,ordinal:function(a,b){switch(b){case"DDD":case"w":case"W":case"DDDo":return 1===a?a+"-ին":a+"-րդ";default:return a}},week:{dow:1,// Monday is the first day of the week.
+doy:7}}),
+//! moment.js locale configuration
+//! locale : Indonesian [id]
+//! author : Mohammad Satrio Utomo : https://github.com/tyok
+//! reference: http://id.wikisource.org/wiki/Pedoman_Umum_Ejaan_Bahasa_Indonesia_yang_Disempurnakan
+a.defineLocale("id",{months:"Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_November_Desember".split("_"),monthsShort:"Jan_Feb_Mar_Apr_Mei_Jun_Jul_Ags_Sep_Okt_Nov_Des".split("_"),weekdays:"Minggu_Senin_Selasa_Rabu_Kamis_Jumat_Sabtu".split("_"),weekdaysShort:"Min_Sen_Sel_Rab_Kam_Jum_Sab".split("_"),weekdaysMin:"Mg_Sn_Sl_Rb_Km_Jm_Sb".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/pagi|siang|sore|malam/,meridiemHour:function(a,b){return 12===a&&(a=0),"pagi"===b?a:"siang"===b?a>=11?a:a+12:"sore"===b||"malam"===b?a+12:void 0},meridiem:function(a,b,c){return a<11?"pagi":a<15?"siang":a<19?"sore":"malam"},calendar:{sameDay:"[Hari ini pukul] LT",nextDay:"[Besok pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kemarin pukul] LT",lastWeek:"dddd [lalu pukul] LT",sameElse:"L"},relativeTime:{future:"dalam %s",past:"%s yang lalu",s:"beberapa detik",m:"semenit",mm:"%d menit",h:"sejam",hh:"%d jam",d:"sehari",dd:"%d hari",M:"sebulan",MM:"%d bulan",y:"setahun",yy:"%d tahun"},week:{dow:1,// Monday is the first day of the week.
+doy:7}}),a.defineLocale("is",{months:"janúar_febrúar_mars_apríl_maí_júní_júlí_ágúst_september_október_nóvember_desember".split("_"),monthsShort:"jan_feb_mar_apr_maí_jún_júl_ágú_sep_okt_nóv_des".split("_"),weekdays:"sunnudagur_mánudagur_þriðjudagur_miðvikudagur_fimmtudagur_föstudagur_laugardagur".split("_"),weekdaysShort:"sun_mán_þri_mið_fim_fös_lau".split("_"),weekdaysMin:"Su_Má_Þr_Mi_Fi_Fö_La".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY [kl.] H:mm",LLLL:"dddd, D. MMMM YYYY [kl.] H:mm"},calendar:{sameDay:"[í dag kl.] LT",nextDay:"[á morgun kl.] LT",nextWeek:"dddd [kl.] LT",lastDay:"[í gær kl.] LT",lastWeek:"[síðasta] dddd [kl.] LT",sameElse:"L"},relativeTime:{future:"eftir %s",past:"fyrir %s síðan",s:v,m:v,mm:v,h:"klukkustund",hh:v,d:v,dd:v,M:v,MM:v,y:v,yy:v},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Italian [it]
+//! author : Lorenzo : https://github.com/aliem
+//! author: Mattia Larentis: https://github.com/nostalgiaz
+a.defineLocale("it",{months:"gennaio_febbraio_marzo_aprile_maggio_giugno_luglio_agosto_settembre_ottobre_novembre_dicembre".split("_"),monthsShort:"gen_feb_mar_apr_mag_giu_lug_ago_set_ott_nov_dic".split("_"),weekdays:"Domenica_Lunedì_Martedì_Mercoledì_Giovedì_Venerdì_Sabato".split("_"),weekdaysShort:"Dom_Lun_Mar_Mer_Gio_Ven_Sab".split("_"),weekdaysMin:"Do_Lu_Ma_Me_Gi_Ve_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Oggi alle] LT",nextDay:"[Domani alle] LT",nextWeek:"dddd [alle] LT",lastDay:"[Ieri alle] LT",lastWeek:function(){switch(this.day()){case 0:return"[la scorsa] dddd [alle] LT";default:return"[lo scorso] dddd [alle] LT"}},sameElse:"L"},relativeTime:{future:function(a){return(/^[0-9].+$/.test(a)?"tra":"in")+" "+a},past:"%s fa",s:"alcuni secondi",m:"un minuto",mm:"%d minuti",h:"un'ora",hh:"%d ore",d:"un giorno",dd:"%d giorni",M:"un mese",MM:"%d mesi",y:"un anno",yy:"%d anni"},ordinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Japanese [ja]
+//! author : LI Long : https://github.com/baryon
+a.defineLocale("ja",{months:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"日曜日_月曜日_火曜日_水曜日_木曜日_金曜日_土曜日".split("_"),weekdaysShort:"日_月_火_水_木_金_土".split("_"),weekdaysMin:"日_月_火_水_木_金_土".split("_"),longDateFormat:{LT:"Ah時m分",LTS:"Ah時m分s秒",L:"YYYY/MM/DD",LL:"YYYY年M月D日",LLL:"YYYY年M月D日Ah時m分",LLLL:"YYYY年M月D日Ah時m分 dddd"},meridiemParse:/午前|午後/i,isPM:function(a){return"午後"===a},meridiem:function(a,b,c){return a<12?"午前":"午後"},calendar:{sameDay:"[今日] LT",nextDay:"[明日] LT",nextWeek:"[来週]dddd LT",lastDay:"[昨日] LT",lastWeek:"[前週]dddd LT",sameElse:"L"},ordinalParse:/\d{1,2}日/,ordinal:function(a,b){switch(b){case"d":case"D":case"DDD":return a+"日";default:return a}},relativeTime:{future:"%s後",past:"%s前",s:"数秒",m:"1分",mm:"%d分",h:"1時間",hh:"%d時間",d:"1日",dd:"%d日",M:"1ヶ月",MM:"%dヶ月",y:"1年",yy:"%d年"}}),
+//! moment.js locale configuration
+//! locale : Javanese [jv]
+//! author : Rony Lantip : https://github.com/lantip
+//! reference: http://jv.wikipedia.org/wiki/Basa_Jawa
+a.defineLocale("jv",{months:"Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_Nopember_Desember".split("_"),monthsShort:"Jan_Feb_Mar_Apr_Mei_Jun_Jul_Ags_Sep_Okt_Nop_Des".split("_"),weekdays:"Minggu_Senen_Seloso_Rebu_Kemis_Jemuwah_Septu".split("_"),weekdaysShort:"Min_Sen_Sel_Reb_Kem_Jem_Sep".split("_"),weekdaysMin:"Mg_Sn_Sl_Rb_Km_Jm_Sp".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/enjing|siyang|sonten|ndalu/,meridiemHour:function(a,b){return 12===a&&(a=0),"enjing"===b?a:"siyang"===b?a>=11?a:a+12:"sonten"===b||"ndalu"===b?a+12:void 0},meridiem:function(a,b,c){return a<11?"enjing":a<15?"siyang":a<19?"sonten":"ndalu"},calendar:{sameDay:"[Dinten puniko pukul] LT",nextDay:"[Mbenjang pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kala wingi pukul] LT",lastWeek:"dddd [kepengker pukul] LT",sameElse:"L"},relativeTime:{future:"wonten ing %s",past:"%s ingkang kepengker",s:"sawetawis detik",m:"setunggal menit",mm:"%d menit",h:"setunggal jam",hh:"%d jam",d:"sedinten",dd:"%d dinten",M:"sewulan",MM:"%d wulan",y:"setaun",yy:"%d taun"},week:{dow:1,// Monday is the first day of the week.
+doy:7}}),
+//! moment.js locale configuration
+//! locale : Georgian [ka]
+//! author : Irakli Janiashvili : https://github.com/irakli-janiashvili
+a.defineLocale("ka",{months:{standalone:"იანვარი_თებერვალი_მარტი_აპრილი_მაისი_ივნისი_ივლისი_აგვისტო_სექტემბერი_ოქტომბერი_ნოემბერი_დეკემბერი".split("_"),format:"იანვარს_თებერვალს_მარტს_აპრილის_მაისს_ივნისს_ივლისს_აგვისტს_სექტემბერს_ოქტომბერს_ნოემბერს_დეკემბერს".split("_")},monthsShort:"იან_თებ_მარ_აპრ_მაი_ივნ_ივლ_აგვ_სექ_ოქტ_ნოე_დეკ".split("_"),weekdays:{standalone:"კვირა_ორშაბათი_სამშაბათი_ოთხშაბათი_ხუთშაბათი_პარასკევი_შაბათი".split("_"),format:"კვირას_ორშაბათს_სამშაბათს_ოთხშაბათს_ხუთშაბათს_პარასკევს_შაბათს".split("_"),isFormat:/(წინა|შემდეგ)/},weekdaysShort:"კვი_ორშ_სამ_ოთხ_ხუთ_პარ_შაბ".split("_"),weekdaysMin:"კვ_ორ_სა_ოთ_ხუ_პა_შა".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[დღეს] LT[-ზე]",nextDay:"[ხვალ] LT[-ზე]",lastDay:"[გუშინ] LT[-ზე]",nextWeek:"[შემდეგ] dddd LT[-ზე]",lastWeek:"[წინა] dddd LT-ზე",sameElse:"L"},relativeTime:{future:function(a){return/(წამი|წუთი|საათი|წელი)/.test(a)?a.replace(/ი$/,"ში"):a+"ში"},past:function(a){return/(წამი|წუთი|საათი|დღე|თვე)/.test(a)?a.replace(/(ი|ე)$/,"ის წინ"):/წელი/.test(a)?a.replace(/წელი$/,"წლის წინ"):void 0},s:"რამდენიმე წამი",m:"წუთი",mm:"%d წუთი",h:"საათი",hh:"%d საათი",d:"დღე",dd:"%d დღე",M:"თვე",MM:"%d თვე",y:"წელი",yy:"%d წელი"},ordinalParse:/0|1-ლი|მე-\d{1,2}|\d{1,2}-ე/,ordinal:function(a){return 0===a?a:1===a?a+"-ლი":a<20||a<=100&&a%20===0||a%100===0?"მე-"+a:a+"-ე"},week:{dow:1,doy:7}});
+//! moment.js locale configuration
+//! locale : Kazakh [kk]
+//! authors : Nurlan Rakhimzhanov : https://github.com/nurlan
+var Na={0:"-ші",1:"-ші",2:"-ші",3:"-ші",4:"-ші",5:"-ші",6:"-шы",7:"-ші",8:"-ші",9:"-шы",10:"-шы",20:"-шы",30:"-шы",40:"-шы",50:"-ші",60:"-шы",70:"-ші",80:"-ші",90:"-шы",100:"-ші"};a.defineLocale("kk",{months:"қаңтар_ақпан_наурыз_сәуір_мамыр_маусым_шілде_тамыз_қыркүйек_қазан_қараша_желтоқсан".split("_"),monthsShort:"қаң_ақп_нау_сәу_мам_мау_шіл_там_қыр_қаз_қар_жел".split("_"),weekdays:"жексенбі_дүйсенбі_сейсенбі_сәрсенбі_бейсенбі_жұма_сенбі".split("_"),weekdaysShort:"жек_дүй_сей_сәр_бей_жұм_сен".split("_"),weekdaysMin:"жк_дй_сй_ср_бй_жм_сн".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Бүгін сағат] LT",nextDay:"[Ертең сағат] LT",nextWeek:"dddd [сағат] LT",lastDay:"[Кеше сағат] LT",lastWeek:"[Өткен аптаның] dddd [сағат] LT",sameElse:"L"},relativeTime:{future:"%s ішінде",past:"%s бұрын",s:"бірнеше секунд",m:"бір минут",mm:"%d минут",h:"бір сағат",hh:"%d сағат",d:"бір күн",dd:"%d күн",M:"бір ай",MM:"%d ай",y:"бір жыл",yy:"%d жыл"},ordinalParse:/\d{1,2}-(ші|шы)/,ordinal:function(a){var b=a%10,c=a>=100?100:null;return a+(Na[a]||Na[b]||Na[c])},week:{dow:1,// Monday is the first day of the week.
+doy:7}}),
+//! moment.js locale configuration
+//! locale : Cambodian [km]
+//! author : Kruy Vanna : https://github.com/kruyvanna
+a.defineLocale("km",{months:"មករា_កុម្ភៈ_មីនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ".split("_"),monthsShort:"មករា_កុម្ភៈ_មីនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ".split("_"),weekdays:"អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍".split("_"),weekdaysShort:"អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍".split("_"),weekdaysMin:"អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[ថ្ងៃនេះ ម៉ោង] LT",nextDay:"[ស្អែក ម៉ោង] LT",nextWeek:"dddd [ម៉ោង] LT",lastDay:"[ម្សិលមិញ ម៉ោង] LT",lastWeek:"dddd [សប្តាហ៍មុន] [ម៉ោង] LT",sameElse:"L"},relativeTime:{future:"%sទៀត",past:"%sមុន",s:"ប៉ុន្មានវិនាទី",m:"មួយនាទី",mm:"%d នាទី",h:"មួយម៉ោង",hh:"%d ម៉ោង",d:"មួយថ្ងៃ",dd:"%d ថ្ងៃ",M:"មួយខែ",MM:"%d ខែ",y:"មួយឆ្នាំ",yy:"%d ឆ្នាំ"},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Korean [ko]
+//! author : Kyungwook, Park : https://github.com/kyungw00k
+//! author : Jeeeyul Lee <jeeeyul@gmail.com>
+a.defineLocale("ko",{months:"1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월".split("_"),monthsShort:"1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월".split("_"),weekdays:"일요일_월요일_화요일_수요일_목요일_금요일_토요일".split("_"),weekdaysShort:"일_월_화_수_목_금_토".split("_"),weekdaysMin:"일_월_화_수_목_금_토".split("_"),longDateFormat:{LT:"A h시 m분",LTS:"A h시 m분 s초",L:"YYYY.MM.DD",LL:"YYYY년 MMMM D일",LLL:"YYYY년 MMMM D일 A h시 m분",LLLL:"YYYY년 MMMM D일 dddd A h시 m분"},calendar:{sameDay:"오늘 LT",nextDay:"내일 LT",nextWeek:"dddd LT",lastDay:"어제 LT",lastWeek:"지난주 dddd LT",sameElse:"L"},relativeTime:{future:"%s 후",past:"%s 전",s:"몇 초",ss:"%d초",m:"일분",mm:"%d분",h:"한 시간",hh:"%d시간",d:"하루",dd:"%d일",M:"한 달",MM:"%d달",y:"일 년",yy:"%d년"},ordinalParse:/\d{1,2}일/,ordinal:"%d일",meridiemParse:/오전|오후/,isPM:function(a){return"오후"===a},meridiem:function(a,b,c){return a<12?"오전":"오후"}});
+//! moment.js locale configuration
+//! locale : Kyrgyz [ky]
+//! author : Chyngyz Arystan uulu : https://github.com/chyngyz
+var Oa={0:"-чү",1:"-чи",2:"-чи",3:"-чү",4:"-чү",5:"-чи",6:"-чы",7:"-чи",8:"-чи",9:"-чу",10:"-чу",20:"-чы",30:"-чу",40:"-чы",50:"-чү",60:"-чы",70:"-чи",80:"-чи",90:"-чу",100:"-чү"};a.defineLocale("ky",{months:"январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь".split("_"),monthsShort:"янв_фев_март_апр_май_июнь_июль_авг_сен_окт_ноя_дек".split("_"),weekdays:"Жекшемби_Дүйшөмбү_Шейшемби_Шаршемби_Бейшемби_Жума_Ишемби".split("_"),weekdaysShort:"Жек_Дүй_Шей_Шар_Бей_Жум_Ише".split("_"),weekdaysMin:"Жк_Дй_Шй_Шр_Бй_Жм_Иш".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Бүгүн саат] LT",nextDay:"[Эртең саат] LT",nextWeek:"dddd [саат] LT",lastDay:"[Кече саат] LT",lastWeek:"[Өткен аптанын] dddd [күнү] [саат] LT",sameElse:"L"},relativeTime:{future:"%s ичинде",past:"%s мурун",s:"бирнече секунд",m:"бир мүнөт",mm:"%d мүнөт",h:"бир саат",hh:"%d саат",d:"бир күн",dd:"%d күн",M:"бир ай",MM:"%d ай",y:"бир жыл",yy:"%d жыл"},ordinalParse:/\d{1,2}-(чи|чы|чү|чу)/,ordinal:function(a){var b=a%10,c=a>=100?100:null;return a+(Oa[a]||Oa[b]||Oa[c])},week:{dow:1,// Monday is the first day of the week.
+doy:7}}),a.defineLocale("lb",{months:"Januar_Februar_Mäerz_Abrëll_Mee_Juni_Juli_August_September_Oktober_November_Dezember".split("_"),monthsShort:"Jan._Febr._Mrz._Abr._Mee_Jun._Jul._Aug._Sept._Okt._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Sonndeg_Méindeg_Dënschdeg_Mëttwoch_Donneschdeg_Freideg_Samschdeg".split("_"),weekdaysShort:"So._Mé._Dë._Më._Do._Fr._Sa.".split("_"),weekdaysMin:"So_Mé_Dë_Më_Do_Fr_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm [Auer]",LTS:"H:mm:ss [Auer]",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm [Auer]",LLLL:"dddd, D. MMMM YYYY H:mm [Auer]"},calendar:{sameDay:"[Haut um] LT",sameElse:"L",nextDay:"[Muer um] LT",nextWeek:"dddd [um] LT",lastDay:"[Gëschter um] LT",lastWeek:function(){
+// Different date string for 'Dënschdeg' (Tuesday) and 'Donneschdeg' (Thursday) due to phonological rule
+switch(this.day()){case 2:case 4:return"[Leschten] dddd [um] LT";default:return"[Leschte] dddd [um] LT"}}},relativeTime:{future:x,past:y,s:"e puer Sekonnen",m:w,mm:"%d Minutten",h:w,hh:"%d Stonnen",d:w,dd:"%d Deeg",M:w,MM:"%d Méint",y:w,yy:"%d Joer"},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Lao [lo]
+//! author : Ryan Hart : https://github.com/ryanhart2
+a.defineLocale("lo",{months:"ມັງກອນ_ກຸມພາ_ມີນາ_ເມສາ_ພຶດສະພາ_ມິຖຸນາ_ກໍລະກົດ_ສິງຫາ_ກັນຍາ_ຕຸລາ_ພະຈິກ_ທັນວາ".split("_"),monthsShort:"ມັງກອນ_ກຸມພາ_ມີນາ_ເມສາ_ພຶດສະພາ_ມິຖຸນາ_ກໍລະກົດ_ສິງຫາ_ກັນຍາ_ຕຸລາ_ພະຈິກ_ທັນວາ".split("_"),weekdays:"ອາທິດ_ຈັນ_ອັງຄານ_ພຸດ_ພະຫັດ_ສຸກ_ເສົາ".split("_"),weekdaysShort:"ທິດ_ຈັນ_ອັງຄານ_ພຸດ_ພະຫັດ_ສຸກ_ເສົາ".split("_"),weekdaysMin:"ທ_ຈ_ອຄ_ພ_ພຫ_ສກ_ສ".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"ວັນdddd D MMMM YYYY HH:mm"},meridiemParse:/ຕອນເຊົ້າ|ຕອນແລງ/,isPM:function(a){return"ຕອນແລງ"===a},meridiem:function(a,b,c){return a<12?"ຕອນເຊົ້າ":"ຕອນແລງ"},calendar:{sameDay:"[ມື້ນີ້ເວລາ] LT",nextDay:"[ມື້ອື່ນເວລາ] LT",nextWeek:"[ວັນ]dddd[ໜ້າເວລາ] LT",lastDay:"[ມື້ວານນີ້ເວລາ] LT",lastWeek:"[ວັນ]dddd[ແລ້ວນີ້ເວລາ] LT",sameElse:"L"},relativeTime:{future:"ອີກ %s",past:"%sຜ່ານມາ",s:"ບໍ່ເທົ່າໃດວິນາທີ",m:"1 ນາທີ",mm:"%d ນາທີ",h:"1 ຊົ່ວໂມງ",hh:"%d ຊົ່ວໂມງ",d:"1 ມື້",dd:"%d ມື້",M:"1 ເດືອນ",MM:"%d ເດືອນ",y:"1 ປີ",yy:"%d ປີ"},ordinalParse:/(ທີ່)\d{1,2}/,ordinal:function(a){return"ທີ່"+a}});
+//! moment.js locale configuration
+//! locale : Lithuanian [lt]
+//! author : Mindaugas Mozūras : https://github.com/mmozuras
+var Pa={m:"minutė_minutės_minutę",mm:"minutės_minučių_minutes",h:"valanda_valandos_valandą",hh:"valandos_valandų_valandas",d:"diena_dienos_dieną",dd:"dienos_dienų_dienas",M:"mėnuo_mėnesio_mėnesį",MM:"mėnesiai_mėnesių_mėnesius",y:"metai_metų_metus",yy:"metai_metų_metus"};a.defineLocale("lt",{months:{format:"sausio_vasario_kovo_balandžio_gegužės_birželio_liepos_rugpjūčio_rugsėjo_spalio_lapkričio_gruodžio".split("_"),standalone:"sausis_vasaris_kovas_balandis_gegužė_birželis_liepa_rugpjūtis_rugsėjis_spalis_lapkritis_gruodis".split("_"),isFormat:/D[oD]?(\[[^\[\]]*\]|\s)+MMMM?|MMMM?(\[[^\[\]]*\]|\s)+D[oD]?/},monthsShort:"sau_vas_kov_bal_geg_bir_lie_rgp_rgs_spa_lap_grd".split("_"),weekdays:{format:"sekmadienį_pirmadienį_antradienį_trečiadienį_ketvirtadienį_penktadienį_šeštadienį".split("_"),standalone:"sekmadienis_pirmadienis_antradienis_trečiadienis_ketvirtadienis_penktadienis_šeštadienis".split("_"),isFormat:/dddd HH:mm/},weekdaysShort:"Sek_Pir_Ant_Tre_Ket_Pen_Šeš".split("_"),weekdaysMin:"S_P_A_T_K_Pn_Š".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"YYYY [m.] MMMM D [d.]",LLL:"YYYY [m.] MMMM D [d.], HH:mm [val.]",LLLL:"YYYY [m.] MMMM D [d.], dddd, HH:mm [val.]",l:"YYYY-MM-DD",ll:"YYYY [m.] MMMM D [d.]",lll:"YYYY [m.] MMMM D [d.], HH:mm [val.]",llll:"YYYY [m.] MMMM D [d.], ddd, HH:mm [val.]"},calendar:{sameDay:"[Šiandien] LT",nextDay:"[Rytoj] LT",nextWeek:"dddd LT",lastDay:"[Vakar] LT",lastWeek:"[Praėjusį] dddd LT",sameElse:"L"},relativeTime:{future:"po %s",past:"prieš %s",s:A,m:B,mm:E,h:B,hh:E,d:B,dd:E,M:B,MM:E,y:B,yy:E},ordinalParse:/\d{1,2}-oji/,ordinal:function(a){return a+"-oji"},week:{dow:1,// Monday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Latvian [lv]
+//! author : Kristaps Karlsons : https://github.com/skakri
+//! author : Jānis Elmeris : https://github.com/JanisE
+var Qa={m:"minūtes_minūtēm_minūte_minūtes".split("_"),mm:"minūtes_minūtēm_minūte_minūtes".split("_"),h:"stundas_stundām_stunda_stundas".split("_"),hh:"stundas_stundām_stunda_stundas".split("_"),d:"dienas_dienām_diena_dienas".split("_"),dd:"dienas_dienām_diena_dienas".split("_"),M:"mēneša_mēnešiem_mēnesis_mēneši".split("_"),MM:"mēneša_mēnešiem_mēnesis_mēneši".split("_"),y:"gada_gadiem_gads_gadi".split("_"),yy:"gada_gadiem_gads_gadi".split("_")};a.defineLocale("lv",{months:"janvāris_februāris_marts_aprīlis_maijs_jūnijs_jūlijs_augusts_septembris_oktobris_novembris_decembris".split("_"),monthsShort:"jan_feb_mar_apr_mai_jūn_jūl_aug_sep_okt_nov_dec".split("_"),weekdays:"svētdiena_pirmdiena_otrdiena_trešdiena_ceturtdiena_piektdiena_sestdiena".split("_"),weekdaysShort:"Sv_P_O_T_C_Pk_S".split("_"),weekdaysMin:"Sv_P_O_T_C_Pk_S".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY.",LL:"YYYY. [gada] D. MMMM",LLL:"YYYY. [gada] D. MMMM, HH:mm",LLLL:"YYYY. [gada] D. MMMM, dddd, HH:mm"},calendar:{sameDay:"[Šodien pulksten] LT",nextDay:"[Rīt pulksten] LT",nextWeek:"dddd [pulksten] LT",lastDay:"[Vakar pulksten] LT",lastWeek:"[Pagājušā] dddd [pulksten] LT",sameElse:"L"},relativeTime:{future:"pēc %s",past:"pirms %s",s:I,m:H,mm:G,h:H,hh:G,d:H,dd:G,M:H,MM:G,y:H,yy:G},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Montenegrin [me]
+//! author : Miodrag Nikač <miodrag@restartit.me> : https://github.com/miodragnikac
+var Ra={words:{//Different grammatical cases
+m:["jedan minut","jednog minuta"],mm:["minut","minuta","minuta"],h:["jedan sat","jednog sata"],hh:["sat","sata","sati"],dd:["dan","dana","dana"],MM:["mjesec","mjeseca","mjeseci"],yy:["godina","godine","godina"]},correctGrammaticalCase:function(a,b){return 1===a?b[0]:a>=2&&a<=4?b[1]:b[2]},translate:function(a,b,c){var d=Ra.words[c];return 1===c.length?b?d[0]:d[1]:a+" "+Ra.correctGrammaticalCase(a,d)}};a.defineLocale("me",{months:"januar_februar_mart_april_maj_jun_jul_avgust_septembar_oktobar_novembar_decembar".split("_"),monthsShort:"jan._feb._mar._apr._maj_jun_jul_avg._sep._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota".split("_"),weekdaysShort:"ned._pon._uto._sri._čet._pet._sub.".split("_"),weekdaysMin:"ne_po_ut_sr_če_pe_su".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[danas u] LT",nextDay:"[sjutra u] LT",nextWeek:function(){switch(this.day()){case 0:return"[u] [nedjelju] [u] LT";case 3:return"[u] [srijedu] [u] LT";case 6:return"[u] [subotu] [u] LT";case 1:case 2:case 4:case 5:return"[u] dddd [u] LT"}},lastDay:"[juče u] LT",lastWeek:function(){var a=["[prošle] [nedjelje] [u] LT","[prošlog] [ponedjeljka] [u] LT","[prošlog] [utorka] [u] LT","[prošle] [srijede] [u] LT","[prošlog] [četvrtka] [u] LT","[prošlog] [petka] [u] LT","[prošle] [subote] [u] LT"];return a[this.day()]},sameElse:"L"},relativeTime:{future:"za %s",past:"prije %s",s:"nekoliko sekundi",m:Ra.translate,mm:Ra.translate,h:Ra.translate,hh:Ra.translate,d:"dan",dd:Ra.translate,M:"mjesec",MM:Ra.translate,y:"godinu",yy:Ra.translate},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:7}}),
+//! moment.js locale configuration
+//! locale : Maori [mi]
+//! author : John Corrigan <robbiecloset@gmail.com> : https://github.com/johnideal
+a.defineLocale("mi",{months:"Kohi-tāte_Hui-tanguru_Poutū-te-rangi_Paenga-whāwhā_Haratua_Pipiri_Hōngoingoi_Here-turi-kōkā_Mahuru_Whiringa-ā-nuku_Whiringa-ā-rangi_Hakihea".split("_"),monthsShort:"Kohi_Hui_Pou_Pae_Hara_Pipi_Hōngoi_Here_Mahu_Whi-nu_Whi-ra_Haki".split("_"),monthsRegex:/(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,monthsStrictRegex:/(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,monthsShortRegex:/(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,monthsShortStrictRegex:/(?:['a-z\u0101\u014D\u016B]+\-?){1,2}/i,weekdays:"Rātapu_Mane_Tūrei_Wenerei_Tāite_Paraire_Hātarei".split("_"),weekdaysShort:"Ta_Ma_Tū_We_Tāi_Pa_Hā".split("_"),weekdaysMin:"Ta_Ma_Tū_We_Tāi_Pa_Hā".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [i] HH:mm",LLLL:"dddd, D MMMM YYYY [i] HH:mm"},calendar:{sameDay:"[i teie mahana, i] LT",nextDay:"[apopo i] LT",nextWeek:"dddd [i] LT",lastDay:"[inanahi i] LT",lastWeek:"dddd [whakamutunga i] LT",sameElse:"L"},relativeTime:{future:"i roto i %s",past:"%s i mua",s:"te hēkona ruarua",m:"he meneti",mm:"%d meneti",h:"te haora",hh:"%d haora",d:"he ra",dd:"%d ra",M:"he marama",MM:"%d marama",y:"he tau",yy:"%d tau"},ordinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Macedonian [mk]
+//! author : Borislav Mickov : https://github.com/B0k0
+a.defineLocale("mk",{months:"јануари_февруари_март_април_мај_јуни_јули_август_септември_октомври_ноември_декември".split("_"),monthsShort:"јан_фев_мар_апр_мај_јун_јул_авг_сеп_окт_ное_дек".split("_"),weekdays:"недела_понеделник_вторник_среда_четврток_петок_сабота".split("_"),weekdaysShort:"нед_пон_вто_сре_чет_пет_саб".split("_"),weekdaysMin:"нe_пo_вт_ср_че_пе_сa".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"D.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY H:mm",LLLL:"dddd, D MMMM YYYY H:mm"},calendar:{sameDay:"[Денес во] LT",nextDay:"[Утре во] LT",nextWeek:"[Во] dddd [во] LT",lastDay:"[Вчера во] LT",lastWeek:function(){switch(this.day()){case 0:case 3:case 6:return"[Изминатата] dddd [во] LT";case 1:case 2:case 4:case 5:return"[Изминатиот] dddd [во] LT"}},sameElse:"L"},relativeTime:{future:"после %s",past:"пред %s",s:"неколку секунди",m:"минута",mm:"%d минути",h:"час",hh:"%d часа",d:"ден",dd:"%d дена",M:"месец",MM:"%d месеци",y:"година",yy:"%d години"},ordinalParse:/\d{1,2}-(ев|ен|ти|ви|ри|ми)/,ordinal:function(a){var b=a%10,c=a%100;return 0===a?a+"-ев":0===c?a+"-ен":c>10&&c<20?a+"-ти":1===b?a+"-ви":2===b?a+"-ри":7===b||8===b?a+"-ми":a+"-ти"},week:{dow:1,// Monday is the first day of the week.
+doy:7}}),
+//! moment.js locale configuration
+//! locale : Malayalam [ml]
+//! author : Floyd Pink : https://github.com/floydpink
+a.defineLocale("ml",{months:"ജനുവരി_ഫെബ്രുവരി_മാർച്ച്_ഏപ്രിൽ_മേയ്_ജൂൺ_ജൂലൈ_ഓഗസ്റ്റ്_സെപ്റ്റംബർ_ഒക്ടോബർ_നവംബർ_ഡിസംബർ".split("_"),monthsShort:"ജനു._ഫെബ്രു._മാർ._ഏപ്രി._മേയ്_ജൂൺ_ജൂലൈ._ഓഗ._സെപ്റ്റ._ഒക്ടോ._നവം._ഡിസം.".split("_"),monthsParseExact:!0,weekdays:"ഞായറാഴ്ച_തിങ്കളാഴ്ച_ചൊവ്വാഴ്ച_ബുധനാഴ്ച_വ്യാഴാഴ്ച_വെള്ളിയാഴ്ച_ശനിയാഴ്ച".split("_"),weekdaysShort:"ഞായർ_തിങ്കൾ_ചൊവ്വ_ബുധൻ_വ്യാഴം_വെള്ളി_ശനി".split("_"),weekdaysMin:"ഞാ_തി_ചൊ_ബു_വ്യാ_വെ_ശ".split("_"),longDateFormat:{LT:"A h:mm -നു",LTS:"A h:mm:ss -നു",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm -നു",LLLL:"dddd, D MMMM YYYY, A h:mm -നു"},calendar:{sameDay:"[ഇന്ന്] LT",nextDay:"[നാളെ] LT",nextWeek:"dddd, LT",lastDay:"[ഇന്നലെ] LT",lastWeek:"[കഴിഞ്ഞ] dddd, LT",sameElse:"L"},relativeTime:{future:"%s കഴിഞ്ഞ്",past:"%s മുൻപ്",s:"അൽപ നിമിഷങ്ങൾ",m:"ഒരു മിനിറ്റ്",mm:"%d മിനിറ്റ്",h:"ഒരു മണിക്കൂർ",hh:"%d മണിക്കൂർ",d:"ഒരു ദിവസം",dd:"%d ദിവസം",M:"ഒരു മാസം",MM:"%d മാസം",y:"ഒരു വർഷം",yy:"%d വർഷം"},meridiemParse:/രാത്രി|രാവിലെ|ഉച്ച കഴിഞ്ഞ്|വൈകുന്നേരം|രാത്രി/i,meridiemHour:function(a,b){return 12===a&&(a=0),"രാത്രി"===b&&a>=4||"ഉച്ച കഴിഞ്ഞ്"===b||"വൈകുന്നേരം"===b?a+12:a},meridiem:function(a,b,c){return a<4?"രാത്രി":a<12?"രാവിലെ":a<17?"ഉച്ച കഴിഞ്ഞ്":a<20?"വൈകുന്നേരം":"രാത്രി"}});
+//! moment.js locale configuration
+//! locale : Marathi [mr]
+//! author : Harshad Kale : https://github.com/kalehv
+//! author : Vivek Athalye : https://github.com/vnathalye
+var Sa={1:"१",2:"२",3:"३",4:"४",5:"५",6:"६",7:"७",8:"८",9:"९",0:"०"},Ta={"१":"1","२":"2","३":"3","४":"4","५":"5","६":"6","७":"7","८":"8","९":"9","०":"0"};a.defineLocale("mr",{months:"जानेवारी_फेब्रुवारी_मार्च_एप्रिल_मे_जून_जुलै_ऑगस्ट_सप्टेंबर_ऑक्टोबर_नोव्हेंबर_डिसेंबर".split("_"),monthsShort:"जाने._फेब्रु._मार्च._एप्रि._मे._जून._जुलै._ऑग._सप्टें._ऑक्टो._नोव्हें._डिसें.".split("_"),monthsParseExact:!0,weekdays:"रविवार_सोमवार_मंगळवार_बुधवार_गुरूवार_शुक्रवार_शनिवार".split("_"),weekdaysShort:"रवि_सोम_मंगळ_बुध_गुरू_शुक्र_शनि".split("_"),weekdaysMin:"र_सो_मं_बु_गु_शु_श".split("_"),longDateFormat:{LT:"A h:mm वाजता",LTS:"A h:mm:ss वाजता",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm वाजता",LLLL:"dddd, D MMMM YYYY, A h:mm वाजता"},calendar:{sameDay:"[आज] LT",nextDay:"[उद्या] LT",nextWeek:"dddd, LT",lastDay:"[काल] LT",lastWeek:"[मागील] dddd, LT",sameElse:"L"},relativeTime:{future:"%sमध्ये",past:"%sपूर्वी",s:J,m:J,mm:J,h:J,hh:J,d:J,dd:J,M:J,MM:J,y:J,yy:J},preparse:function(a){return a.replace(/[१२३४५६७८९०]/g,function(a){return Ta[a]})},postformat:function(a){return a.replace(/\d/g,function(a){return Sa[a]})},meridiemParse:/रात्री|सकाळी|दुपारी|सायंकाळी/,meridiemHour:function(a,b){return 12===a&&(a=0),"रात्री"===b?a<4?a:a+12:"सकाळी"===b?a:"दुपारी"===b?a>=10?a:a+12:"सायंकाळी"===b?a+12:void 0},meridiem:function(a,b,c){return a<4?"रात्री":a<10?"सकाळी":a<17?"दुपारी":a<20?"सायंकाळी":"रात्री"},week:{dow:0,// Sunday is the first day of the week.
+doy:6}}),
+//! moment.js locale configuration
+//! locale : Malay [ms-my]
+//! note : DEPRECATED, the correct one is [ms]
+//! author : Weldan Jamili : https://github.com/weldan
+a.defineLocale("ms-my",{months:"Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember".split("_"),monthsShort:"Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis".split("_"),weekdays:"Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu".split("_"),weekdaysShort:"Ahd_Isn_Sel_Rab_Kha_Jum_Sab".split("_"),weekdaysMin:"Ah_Is_Sl_Rb_Km_Jm_Sb".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/pagi|tengahari|petang|malam/,meridiemHour:function(a,b){return 12===a&&(a=0),"pagi"===b?a:"tengahari"===b?a>=11?a:a+12:"petang"===b||"malam"===b?a+12:void 0},meridiem:function(a,b,c){return a<11?"pagi":a<15?"tengahari":a<19?"petang":"malam"},calendar:{sameDay:"[Hari ini pukul] LT",nextDay:"[Esok pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kelmarin pukul] LT",lastWeek:"dddd [lepas pukul] LT",sameElse:"L"},relativeTime:{future:"dalam %s",past:"%s yang lepas",s:"beberapa saat",m:"seminit",mm:"%d minit",h:"sejam",hh:"%d jam",d:"sehari",dd:"%d hari",M:"sebulan",MM:"%d bulan",y:"setahun",yy:"%d tahun"},week:{dow:1,// Monday is the first day of the week.
+doy:7}}),
+//! moment.js locale configuration
+//! locale : Malay [ms]
+//! author : Weldan Jamili : https://github.com/weldan
+a.defineLocale("ms",{months:"Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember".split("_"),monthsShort:"Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis".split("_"),weekdays:"Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu".split("_"),weekdaysShort:"Ahd_Isn_Sel_Rab_Kha_Jum_Sab".split("_"),weekdaysMin:"Ah_Is_Sl_Rb_Km_Jm_Sb".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/pagi|tengahari|petang|malam/,meridiemHour:function(a,b){return 12===a&&(a=0),"pagi"===b?a:"tengahari"===b?a>=11?a:a+12:"petang"===b||"malam"===b?a+12:void 0},meridiem:function(a,b,c){return a<11?"pagi":a<15?"tengahari":a<19?"petang":"malam"},calendar:{sameDay:"[Hari ini pukul] LT",nextDay:"[Esok pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kelmarin pukul] LT",lastWeek:"dddd [lepas pukul] LT",sameElse:"L"},relativeTime:{future:"dalam %s",past:"%s yang lepas",s:"beberapa saat",m:"seminit",mm:"%d minit",h:"sejam",hh:"%d jam",d:"sehari",dd:"%d hari",M:"sebulan",MM:"%d bulan",y:"setahun",yy:"%d tahun"},week:{dow:1,// Monday is the first day of the week.
+doy:7}});
+//! moment.js locale configuration
+//! locale : Burmese [my]
+//! author : Squar team, mysquar.com
+//! author : David Rossellat : https://github.com/gholadr
+//! author : Tin Aung Lin : https://github.com/thanyawzinmin
+var Ua={1:"၁",2:"၂",3:"၃",4:"၄",5:"၅",6:"၆",7:"၇",8:"၈",9:"၉",0:"၀"},Va={"၁":"1","၂":"2","၃":"3","၄":"4","၅":"5","၆":"6","၇":"7","၈":"8","၉":"9","၀":"0"};a.defineLocale("my",{months:"ဇန်နဝါရီ_ဖေဖော်ဝါရီ_မတ်_ဧပြီ_မေ_ဇွန်_ဇူလိုင်_သြဂုတ်_စက်တင်ဘာ_အောက်တိုဘာ_နိုဝင်ဘာ_ဒီဇင်ဘာ".split("_"),monthsShort:"ဇန်_ဖေ_မတ်_ပြီ_မေ_ဇွန်_လိုင်_သြ_စက်_အောက်_နို_ဒီ".split("_"),weekdays:"တနင်္ဂနွေ_တနင်္လာ_အင်္ဂါ_ဗုဒ္ဓဟူး_ကြာသပတေး_သောကြာ_စနေ".split("_"),weekdaysShort:"နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ".split("_"),weekdaysMin:"နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[ယနေ.] LT [မှာ]",nextDay:"[မနက်ဖြန်] LT [မှာ]",nextWeek:"dddd LT [မှာ]",lastDay:"[မနေ.က] LT [မှာ]",lastWeek:"[ပြီးခဲ့သော] dddd LT [မှာ]",sameElse:"L"},relativeTime:{future:"လာမည့် %s မှာ",past:"လွန်ခဲ့သော %s က",s:"စက္ကန်.အနည်းငယ်",m:"တစ်မိနစ်",mm:"%d မိနစ်",h:"တစ်နာရီ",hh:"%d နာရီ",d:"တစ်ရက်",dd:"%d ရက်",M:"တစ်လ",MM:"%d လ",y:"တစ်နှစ်",yy:"%d နှစ်"},preparse:function(a){return a.replace(/[၁၂၃၄၅၆၇၈၉၀]/g,function(a){return Va[a]})},postformat:function(a){return a.replace(/\d/g,function(a){return Ua[a]})},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Norwegian Bokmål [nb]
+//! authors : Espen Hovlandsdal : https://github.com/rexxars
+//!           Sigurd Gartmann : https://github.com/sigurdga
+a.defineLocale("nb",{months:"januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember".split("_"),monthsShort:"jan._feb._mars_april_mai_juni_juli_aug._sep._okt._nov._des.".split("_"),monthsParseExact:!0,weekdays:"søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag".split("_"),weekdaysShort:"sø._ma._ti._on._to._fr._lø.".split("_"),weekdaysMin:"sø_ma_ti_on_to_fr_lø".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY [kl.] HH:mm",LLLL:"dddd D. MMMM YYYY [kl.] HH:mm"},calendar:{sameDay:"[i dag kl.] LT",nextDay:"[i morgen kl.] LT",nextWeek:"dddd [kl.] LT",lastDay:"[i går kl.] LT",lastWeek:"[forrige] dddd [kl.] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"%s siden",s:"noen sekunder",m:"ett minutt",mm:"%d minutter",h:"en time",hh:"%d timer",d:"en dag",dd:"%d dager",M:"en måned",MM:"%d måneder",y:"ett år",yy:"%d år"},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Nepalese [ne]
+//! author : suvash : https://github.com/suvash
+var Wa={1:"१",2:"२",3:"३",4:"४",5:"५",6:"६",7:"७",8:"८",9:"९",0:"०"},Xa={"१":"1","२":"2","३":"3","४":"4","५":"5","६":"6","७":"7","८":"8","९":"9","०":"0"};a.defineLocale("ne",{months:"जनवरी_फेब्रुवरी_मार्च_अप्रिल_मई_जुन_जुलाई_अगष्ट_सेप्टेम्बर_अक्टोबर_नोभेम्बर_डिसेम्बर".split("_"),monthsShort:"जन._फेब्रु._मार्च_अप्रि._मई_जुन_जुलाई._अग._सेप्ट._अक्टो._नोभे._डिसे.".split("_"),monthsParseExact:!0,weekdays:"आइतबार_सोमबार_मङ्गलबार_बुधबार_बिहिबार_शुक्रबार_शनिबार".split("_"),weekdaysShort:"आइत._सोम._मङ्गल._बुध._बिहि._शुक्र._शनि.".split("_"),weekdaysMin:"आ._सो._मं._बु._बि._शु._श.".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"Aको h:mm बजे",LTS:"Aको h:mm:ss बजे",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, Aको h:mm बजे",LLLL:"dddd, D MMMM YYYY, Aको h:mm बजे"},preparse:function(a){return a.replace(/[१२३४५६७८९०]/g,function(a){return Xa[a]})},postformat:function(a){return a.replace(/\d/g,function(a){return Wa[a]})},meridiemParse:/राति|बिहान|दिउँसो|साँझ/,meridiemHour:function(a,b){return 12===a&&(a=0),"राति"===b?a<4?a:a+12:"बिहान"===b?a:"दिउँसो"===b?a>=10?a:a+12:"साँझ"===b?a+12:void 0},meridiem:function(a,b,c){return a<3?"राति":a<12?"बिहान":a<16?"दिउँसो":a<20?"साँझ":"राति"},calendar:{sameDay:"[आज] LT",nextDay:"[भोलि] LT",nextWeek:"[आउँदो] dddd[,] LT",lastDay:"[हिजो] LT",lastWeek:"[गएको] dddd[,] LT",sameElse:"L"},relativeTime:{future:"%sमा",past:"%s अगाडि",s:"केही क्षण",m:"एक मिनेट",mm:"%d मिनेट",h:"एक घण्टा",hh:"%d घण्टा",d:"एक दिन",dd:"%d दिन",M:"एक महिना",MM:"%d महिना",y:"एक बर्ष",yy:"%d बर्ष"},week:{dow:0,// Sunday is the first day of the week.
+doy:6}});
+//! moment.js locale configuration
+//! locale : Dutch (Belgium) [nl-be]
+//! author : Joris Röling : https://github.com/jorisroling
+//! author : Jacob Middag : https://github.com/middagj
+var Ya="jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.".split("_"),Za="jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec".split("_"),$a=[/^jan/i,/^feb/i,/^maart|mrt.?$/i,/^apr/i,/^mei$/i,/^jun[i.]?$/i,/^jul[i.]?$/i,/^aug/i,/^sep/i,/^okt/i,/^nov/i,/^dec/i],_a=/^(januari|februari|maart|april|mei|april|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i;a.defineLocale("nl-be",{months:"januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december".split("_"),monthsShort:function(a,b){return/-MMM-/.test(b)?Za[a.month()]:Ya[a.month()]},monthsRegex:_a,monthsShortRegex:_a,monthsStrictRegex:/^(januari|februari|maart|mei|ju[nl]i|april|augustus|september|oktober|november|december)/i,monthsShortStrictRegex:/^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i,monthsParse:$a,longMonthsParse:$a,shortMonthsParse:$a,weekdays:"zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag".split("_"),weekdaysShort:"zo._ma._di._wo._do._vr._za.".split("_"),weekdaysMin:"Zo_Ma_Di_Wo_Do_Vr_Za".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[vandaag om] LT",nextDay:"[morgen om] LT",nextWeek:"dddd [om] LT",lastDay:"[gisteren om] LT",lastWeek:"[afgelopen] dddd [om] LT",sameElse:"L"},relativeTime:{future:"over %s",past:"%s geleden",s:"een paar seconden",m:"één minuut",mm:"%d minuten",h:"één uur",hh:"%d uur",d:"één dag",dd:"%d dagen",M:"één maand",MM:"%d maanden",y:"één jaar",yy:"%d jaar"},ordinalParse:/\d{1,2}(ste|de)/,ordinal:function(a){return a+(1===a||8===a||a>=20?"ste":"de")},week:{dow:1,// Monday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Dutch [nl]
+//! author : Joris Röling : https://github.com/jorisroling
+//! author : Jacob Middag : https://github.com/middagj
+var ab="jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.".split("_"),bb="jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec".split("_"),cb=[/^jan/i,/^feb/i,/^maart|mrt.?$/i,/^apr/i,/^mei$/i,/^jun[i.]?$/i,/^jul[i.]?$/i,/^aug/i,/^sep/i,/^okt/i,/^nov/i,/^dec/i],db=/^(januari|februari|maart|april|mei|april|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i;a.defineLocale("nl",{months:"januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december".split("_"),monthsShort:function(a,b){return/-MMM-/.test(b)?bb[a.month()]:ab[a.month()]},monthsRegex:db,monthsShortRegex:db,monthsStrictRegex:/^(januari|februari|maart|mei|ju[nl]i|april|augustus|september|oktober|november|december)/i,monthsShortStrictRegex:/^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i,monthsParse:cb,longMonthsParse:cb,shortMonthsParse:cb,weekdays:"zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag".split("_"),weekdaysShort:"zo._ma._di._wo._do._vr._za.".split("_"),weekdaysMin:"Zo_Ma_Di_Wo_Do_Vr_Za".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD-MM-YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[vandaag om] LT",nextDay:"[morgen om] LT",nextWeek:"dddd [om] LT",lastDay:"[gisteren om] LT",lastWeek:"[afgelopen] dddd [om] LT",sameElse:"L"},relativeTime:{future:"over %s",past:"%s geleden",s:"een paar seconden",m:"één minuut",mm:"%d minuten",h:"één uur",hh:"%d uur",d:"één dag",dd:"%d dagen",M:"één maand",MM:"%d maanden",y:"één jaar",yy:"%d jaar"},ordinalParse:/\d{1,2}(ste|de)/,ordinal:function(a){return a+(1===a||8===a||a>=20?"ste":"de")},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Nynorsk [nn]
+//! author : https://github.com/mechuwind
+a.defineLocale("nn",{months:"januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember".split("_"),monthsShort:"jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des".split("_"),weekdays:"sundag_måndag_tysdag_onsdag_torsdag_fredag_laurdag".split("_"),weekdaysShort:"sun_mån_tys_ons_tor_fre_lau".split("_"),weekdaysMin:"su_må_ty_on_to_fr_lø".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY [kl.] H:mm",LLLL:"dddd D. MMMM YYYY [kl.] HH:mm"},calendar:{sameDay:"[I dag klokka] LT",nextDay:"[I morgon klokka] LT",nextWeek:"dddd [klokka] LT",lastDay:"[I går klokka] LT",lastWeek:"[Føregåande] dddd [klokka] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"%s sidan",s:"nokre sekund",m:"eit minutt",mm:"%d minutt",h:"ein time",hh:"%d timar",d:"ein dag",dd:"%d dagar",M:"ein månad",MM:"%d månader",y:"eit år",yy:"%d år"},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Punjabi (India) [pa-in]
+//! author : Harpreet Singh : https://github.com/harpreetkhalsagtbit
+var eb={1:"੧",2:"੨",3:"੩",4:"੪",5:"੫",6:"੬",7:"੭",8:"੮",9:"੯",0:"੦"},fb={"੧":"1","੨":"2","੩":"3","੪":"4","੫":"5","੬":"6","੭":"7","੮":"8","੯":"9","੦":"0"};a.defineLocale("pa-in",{
+// There are months name as per Nanakshahi Calender but they are not used as rigidly in modern Punjabi.
+months:"ਜਨਵਰੀ_ਫ਼ਰਵਰੀ_ਮਾਰਚ_ਅਪ੍ਰੈਲ_ਮਈ_ਜੂਨ_ਜੁਲਾਈ_ਅਗਸਤ_ਸਤੰਬਰ_ਅਕਤੂਬਰ_ਨਵੰਬਰ_ਦਸੰਬਰ".split("_"),monthsShort:"ਜਨਵਰੀ_ਫ਼ਰਵਰੀ_ਮਾਰਚ_ਅਪ੍ਰੈਲ_ਮਈ_ਜੂਨ_ਜੁਲਾਈ_ਅਗਸਤ_ਸਤੰਬਰ_ਅਕਤੂਬਰ_ਨਵੰਬਰ_ਦਸੰਬਰ".split("_"),weekdays:"ਐਤਵਾਰ_ਸੋਮਵਾਰ_ਮੰਗਲਵਾਰ_ਬੁਧਵਾਰ_ਵੀਰਵਾਰ_ਸ਼ੁੱਕਰਵਾਰ_ਸ਼ਨੀਚਰਵਾਰ".split("_"),weekdaysShort:"ਐਤ_ਸੋਮ_ਮੰਗਲ_ਬੁਧ_ਵੀਰ_ਸ਼ੁਕਰ_ਸ਼ਨੀ".split("_"),weekdaysMin:"ਐਤ_ਸੋਮ_ਮੰਗਲ_ਬੁਧ_ਵੀਰ_ਸ਼ੁਕਰ_ਸ਼ਨੀ".split("_"),longDateFormat:{LT:"A h:mm ਵਜੇ",LTS:"A h:mm:ss ਵਜੇ",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm ਵਜੇ",LLLL:"dddd, D MMMM YYYY, A h:mm ਵਜੇ"},calendar:{sameDay:"[ਅਜ] LT",nextDay:"[ਕਲ] LT",nextWeek:"dddd, LT",lastDay:"[ਕਲ] LT",lastWeek:"[ਪਿਛਲੇ] dddd, LT",sameElse:"L"},relativeTime:{future:"%s ਵਿੱਚ",past:"%s ਪਿਛਲੇ",s:"ਕੁਝ ਸਕਿੰਟ",m:"ਇਕ ਮਿੰਟ",mm:"%d ਮਿੰਟ",h:"ਇੱਕ ਘੰਟਾ",hh:"%d ਘੰਟੇ",d:"ਇੱਕ ਦਿਨ",dd:"%d ਦਿਨ",M:"ਇੱਕ ਮਹੀਨਾ",MM:"%d ਮਹੀਨੇ",y:"ਇੱਕ ਸਾਲ",yy:"%d ਸਾਲ"},preparse:function(a){return a.replace(/[੧੨੩੪੫੬੭੮੯੦]/g,function(a){return fb[a]})},postformat:function(a){return a.replace(/\d/g,function(a){return eb[a]})},
+// Punjabi notation for meridiems are quite fuzzy in practice. While there exists
+// a rigid notion of a 'Pahar' it is not used as rigidly in modern Punjabi.
+meridiemParse:/ਰਾਤ|ਸਵੇਰ|ਦੁਪਹਿਰ|ਸ਼ਾਮ/,meridiemHour:function(a,b){return 12===a&&(a=0),"ਰਾਤ"===b?a<4?a:a+12:"ਸਵੇਰ"===b?a:"ਦੁਪਹਿਰ"===b?a>=10?a:a+12:"ਸ਼ਾਮ"===b?a+12:void 0},meridiem:function(a,b,c){return a<4?"ਰਾਤ":a<10?"ਸਵੇਰ":a<17?"ਦੁਪਹਿਰ":a<20?"ਸ਼ਾਮ":"ਰਾਤ"},week:{dow:0,// Sunday is the first day of the week.
+doy:6}});
+//! moment.js locale configuration
+//! locale : Polish [pl]
+//! author : Rafal Hirsz : https://github.com/evoL
+var gb="styczeń_luty_marzec_kwiecień_maj_czerwiec_lipiec_sierpień_wrzesień_październik_listopad_grudzień".split("_"),hb="stycznia_lutego_marca_kwietnia_maja_czerwca_lipca_sierpnia_września_października_listopada_grudnia".split("_");a.defineLocale("pl",{months:function(a,b){return""===b?"("+hb[a.month()]+"|"+gb[a.month()]+")":/D MMMM/.test(b)?hb[a.month()]:gb[a.month()]},monthsShort:"sty_lut_mar_kwi_maj_cze_lip_sie_wrz_paź_lis_gru".split("_"),weekdays:"niedziela_poniedziałek_wtorek_środa_czwartek_piątek_sobota".split("_"),weekdaysShort:"ndz_pon_wt_śr_czw_pt_sob".split("_"),weekdaysMin:"Nd_Pn_Wt_Śr_Cz_Pt_So".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Dziś o] LT",nextDay:"[Jutro o] LT",nextWeek:"[W] dddd [o] LT",lastDay:"[Wczoraj o] LT",lastWeek:function(){switch(this.day()){case 0:return"[W zeszłą niedzielę o] LT";case 3:return"[W zeszłą środę o] LT";case 6:return"[W zeszłą sobotę o] LT";default:return"[W zeszły] dddd [o] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"%s temu",s:"kilka sekund",m:L,mm:L,h:L,hh:L,d:"1 dzień",dd:"%d dni",M:"miesiąc",MM:L,y:"rok",yy:L},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Portuguese (Brazil) [pt-br]
+//! author : Caio Ribeiro Pereira : https://github.com/caio-ribeiro-pereira
+a.defineLocale("pt-br",{months:"Janeiro_Fevereiro_Março_Abril_Maio_Junho_Julho_Agosto_Setembro_Outubro_Novembro_Dezembro".split("_"),monthsShort:"Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez".split("_"),weekdays:"Domingo_Segunda-feira_Terça-feira_Quarta-feira_Quinta-feira_Sexta-feira_Sábado".split("_"),weekdaysShort:"Dom_Seg_Ter_Qua_Qui_Sex_Sáb".split("_"),weekdaysMin:"Dom_2ª_3ª_4ª_5ª_6ª_Sáb".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY [às] HH:mm",LLLL:"dddd, D [de] MMMM [de] YYYY [às] HH:mm"},calendar:{sameDay:"[Hoje às] LT",nextDay:"[Amanhã às] LT",nextWeek:"dddd [às] LT",lastDay:"[Ontem às] LT",lastWeek:function(){// Saturday + Sunday
+return 0===this.day()||6===this.day()?"[Último] dddd [às] LT":"[Última] dddd [às] LT"},sameElse:"L"},relativeTime:{future:"em %s",past:"%s atrás",s:"poucos segundos",m:"um minuto",mm:"%d minutos",h:"uma hora",hh:"%d horas",d:"um dia",dd:"%d dias",M:"um mês",MM:"%d meses",y:"um ano",yy:"%d anos"},ordinalParse:/\d{1,2}º/,ordinal:"%dº"}),
+//! moment.js locale configuration
+//! locale : Portuguese [pt]
+//! author : Jefferson : https://github.com/jalex79
+a.defineLocale("pt",{months:"Janeiro_Fevereiro_Março_Abril_Maio_Junho_Julho_Agosto_Setembro_Outubro_Novembro_Dezembro".split("_"),monthsShort:"Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez".split("_"),weekdays:"Domingo_Segunda-Feira_Terça-Feira_Quarta-Feira_Quinta-Feira_Sexta-Feira_Sábado".split("_"),weekdaysShort:"Dom_Seg_Ter_Qua_Qui_Sex_Sáb".split("_"),weekdaysMin:"Dom_2ª_3ª_4ª_5ª_6ª_Sáb".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY HH:mm",LLLL:"dddd, D [de] MMMM [de] YYYY HH:mm"},calendar:{sameDay:"[Hoje às] LT",nextDay:"[Amanhã às] LT",nextWeek:"dddd [às] LT",lastDay:"[Ontem às] LT",lastWeek:function(){// Saturday + Sunday
+return 0===this.day()||6===this.day()?"[Último] dddd [às] LT":"[Última] dddd [às] LT"},sameElse:"L"},relativeTime:{future:"em %s",past:"há %s",s:"segundos",m:"um minuto",mm:"%d minutos",h:"uma hora",hh:"%d horas",d:"um dia",dd:"%d dias",M:"um mês",MM:"%d meses",y:"um ano",yy:"%d anos"},ordinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),a.defineLocale("ro",{months:"ianuarie_februarie_martie_aprilie_mai_iunie_iulie_august_septembrie_octombrie_noiembrie_decembrie".split("_"),monthsShort:"ian._febr._mart._apr._mai_iun._iul._aug._sept._oct._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"duminică_luni_marți_miercuri_joi_vineri_sâmbătă".split("_"),weekdaysShort:"Dum_Lun_Mar_Mie_Joi_Vin_Sâm".split("_"),weekdaysMin:"Du_Lu_Ma_Mi_Jo_Vi_Sâ".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY H:mm",LLLL:"dddd, D MMMM YYYY H:mm"},calendar:{sameDay:"[azi la] LT",nextDay:"[mâine la] LT",nextWeek:"dddd [la] LT",lastDay:"[ieri la] LT",lastWeek:"[fosta] dddd [la] LT",sameElse:"L"},relativeTime:{future:"peste %s",past:"%s în urmă",s:"câteva secunde",m:"un minut",mm:M,h:"o oră",hh:M,d:"o zi",dd:M,M:"o lună",MM:M,y:"un an",yy:M},week:{dow:1,// Monday is the first day of the week.
+doy:7}});var ib=[/^янв/i,/^фев/i,/^мар/i,/^апр/i,/^ма[йя]/i,/^июн/i,/^июл/i,/^авг/i,/^сен/i,/^окт/i,/^ноя/i,/^дек/i];
+// http://new.gramota.ru/spravka/rules/139-prop : § 103
+// Сокращения месяцев: http://new.gramota.ru/spravka/buro/search-answer?s=242637
+// CLDR data:          http://www.unicode.org/cldr/charts/28/summary/ru.html#1753
+a.defineLocale("ru",{months:{format:"января_февраля_марта_апреля_мая_июня_июля_августа_сентября_октября_ноября_декабря".split("_"),standalone:"январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь".split("_")},monthsShort:{
+// по CLDR именно "июл." и "июн.", но какой смысл менять букву на точку ?
+format:"янв._февр._мар._апр._мая_июня_июля_авг._сент._окт._нояб._дек.".split("_"),standalone:"янв._февр._март_апр._май_июнь_июль_авг._сент._окт._нояб._дек.".split("_")},weekdays:{standalone:"воскресенье_понедельник_вторник_среда_четверг_пятница_суббота".split("_"),format:"воскресенье_понедельник_вторник_среду_четверг_пятницу_субботу".split("_"),isFormat:/\[ ?[Вв] ?(?:прошлую|следующую|эту)? ?\] ?dddd/},weekdaysShort:"вс_пн_вт_ср_чт_пт_сб".split("_"),weekdaysMin:"вс_пн_вт_ср_чт_пт_сб".split("_"),monthsParse:ib,longMonthsParse:ib,shortMonthsParse:ib,
+// полные названия с падежами, по три буквы, для некоторых, по 4 буквы, сокращения с точкой и без точки
+monthsRegex:/^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i,
+// копия предыдущего
+monthsShortRegex:/^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i,
+// полные названия с падежами
+monthsStrictRegex:/^(январ[яь]|феврал[яь]|марта?|апрел[яь]|ма[яй]|июн[яь]|июл[яь]|августа?|сентябр[яь]|октябр[яь]|ноябр[яь]|декабр[яь])/i,
+// Выражение, которое соотвествует только сокращённым формам
+monthsShortStrictRegex:/^(янв\.|февр?\.|мар[т.]|апр\.|ма[яй]|июн[ья.]|июл[ья.]|авг\.|сент?\.|окт\.|нояб?\.|дек\.)/i,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY г.",LLL:"D MMMM YYYY г., HH:mm",LLLL:"dddd, D MMMM YYYY г., HH:mm"},calendar:{sameDay:"[Сегодня в] LT",nextDay:"[Завтра в] LT",lastDay:"[Вчера в] LT",nextWeek:function(a){if(a.week()===this.week())return 2===this.day()?"[Во] dddd [в] LT":"[В] dddd [в] LT";switch(this.day()){case 0:return"[В следующее] dddd [в] LT";case 1:case 2:case 4:return"[В следующий] dddd [в] LT";case 3:case 5:case 6:return"[В следующую] dddd [в] LT"}},lastWeek:function(a){if(a.week()===this.week())return 2===this.day()?"[Во] dddd [в] LT":"[В] dddd [в] LT";switch(this.day()){case 0:return"[В прошлое] dddd [в] LT";case 1:case 2:case 4:return"[В прошлый] dddd [в] LT";case 3:case 5:case 6:return"[В прошлую] dddd [в] LT"}},sameElse:"L"},relativeTime:{future:"через %s",past:"%s назад",s:"несколько секунд",m:O,mm:O,h:"час",hh:O,d:"день",dd:O,M:"месяц",MM:O,y:"год",yy:O},meridiemParse:/ночи|утра|дня|вечера/i,isPM:function(a){return/^(дня|вечера)$/.test(a)},meridiem:function(a,b,c){return a<4?"ночи":a<12?"утра":a<17?"дня":"вечера"},ordinalParse:/\d{1,2}-(й|го|я)/,ordinal:function(a,b){switch(b){case"M":case"d":case"DDD":return a+"-й";case"D":return a+"-го";case"w":case"W":return a+"-я";default:return a}},week:{dow:1,// Monday is the first day of the week.
+doy:7}}),
+//! moment.js locale configuration
+//! locale : Northern Sami [se]
+//! authors : BÃ¥rd Rolstad Henriksen : https://github.com/karamell
+a.defineLocale("se",{months:"ođđajagemánnu_guovvamánnu_njukčamánnu_cuoŋománnu_miessemánnu_geassemánnu_suoidnemánnu_borgemánnu_čakčamánnu_golggotmánnu_skábmamánnu_juovlamánnu".split("_"),monthsShort:"ođđj_guov_njuk_cuo_mies_geas_suoi_borg_čakč_golg_skáb_juov".split("_"),weekdays:"sotnabeaivi_vuossárga_maŋŋebárga_gaskavahkku_duorastat_bearjadat_lávvardat".split("_"),weekdaysShort:"sotn_vuos_maŋ_gask_duor_bear_láv".split("_"),weekdaysMin:"s_v_m_g_d_b_L".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"MMMM D. [b.] YYYY",LLL:"MMMM D. [b.] YYYY [ti.] HH:mm",LLLL:"dddd, MMMM D. [b.] YYYY [ti.] HH:mm"},calendar:{sameDay:"[otne ti] LT",nextDay:"[ihttin ti] LT",nextWeek:"dddd [ti] LT",lastDay:"[ikte ti] LT",lastWeek:"[ovddit] dddd [ti] LT",sameElse:"L"},relativeTime:{future:"%s geažes",past:"maŋit %s",s:"moadde sekunddat",m:"okta minuhta",mm:"%d minuhtat",h:"okta diimmu",hh:"%d diimmut",d:"okta beaivi",dd:"%d beaivvit",M:"okta mánnu",MM:"%d mánut",y:"okta jahki",yy:"%d jagit"},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Sinhalese [si]
+//! author : Sampath Sitinamaluwa : https://github.com/sampathsris
+/*jshint -W100*/
+a.defineLocale("si",{months:"ජනවාරි_පෙබරවාරි_මාර්තු_අප්‍රේල්_මැයි_ජූනි_ජූලි_අගෝස්තු_සැප්තැම්බර්_ඔක්තෝබර්_නොවැම්බර්_දෙසැම්බර්".split("_"),monthsShort:"ජන_පෙබ_මාර්_අප්_මැයි_ජූනි_ජූලි_අගෝ_සැප්_ඔක්_නොවැ_දෙසැ".split("_"),weekdays:"ඉරිදා_සඳුදා_අඟහරුවාදා_බදාදා_බ්‍රහස්පතින්දා_සිකුරාදා_සෙනසුරාදා".split("_"),weekdaysShort:"ඉරි_සඳු_අඟ_බදා_බ්‍රහ_සිකු_සෙන".split("_"),weekdaysMin:"ඉ_ස_අ_බ_බ්‍ර_සි_සෙ".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"a h:mm",LTS:"a h:mm:ss",L:"YYYY/MM/DD",LL:"YYYY MMMM D",LLL:"YYYY MMMM D, a h:mm",LLLL:"YYYY MMMM D [වැනි] dddd, a h:mm:ss"},calendar:{sameDay:"[අද] LT[ට]",nextDay:"[හෙට] LT[ට]",nextWeek:"dddd LT[ට]",lastDay:"[ඊයේ] LT[ට]",lastWeek:"[පසුගිය] dddd LT[ට]",sameElse:"L"},relativeTime:{future:"%sකින්",past:"%sකට පෙර",s:"තත්පර කිහිපය",m:"මිනිත්තුව",mm:"මිනිත්තු %d",h:"පැය",hh:"පැය %d",d:"දිනය",dd:"දින %d",M:"මාසය",MM:"මාස %d",y:"වසර",yy:"වසර %d"},ordinalParse:/\d{1,2} වැනි/,ordinal:function(a){return a+" වැනි"},meridiemParse:/පෙර වරු|පස් වරු|පෙ.ව|ප.ව./,isPM:function(a){return"ප.ව."===a||"පස් වරු"===a},meridiem:function(a,b,c){return a>11?c?"ප.ව.":"පස් වරු":c?"පෙ.ව.":"පෙර වරු"}});
+//! moment.js locale configuration
+//! locale : Slovak [sk]
+//! author : Martin Minka : https://github.com/k2s
+//! based on work of petrbela : https://github.com/petrbela
+var jb="január_február_marec_apríl_máj_jún_júl_august_september_október_november_december".split("_"),kb="jan_feb_mar_apr_máj_jún_júl_aug_sep_okt_nov_dec".split("_");a.defineLocale("sk",{months:jb,monthsShort:kb,weekdays:"nedeľa_pondelok_utorok_streda_štvrtok_piatok_sobota".split("_"),weekdaysShort:"ne_po_ut_st_št_pi_so".split("_"),weekdaysMin:"ne_po_ut_st_št_pi_so".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd D. MMMM YYYY H:mm"},calendar:{sameDay:"[dnes o] LT",nextDay:"[zajtra o] LT",nextWeek:function(){switch(this.day()){case 0:return"[v nedeľu o] LT";case 1:case 2:return"[v] dddd [o] LT";case 3:return"[v stredu o] LT";case 4:return"[vo štvrtok o] LT";case 5:return"[v piatok o] LT";case 6:return"[v sobotu o] LT"}},lastDay:"[včera o] LT",lastWeek:function(){switch(this.day()){case 0:return"[minulú nedeľu o] LT";case 1:case 2:return"[minulý] dddd [o] LT";case 3:return"[minulú stredu o] LT";case 4:case 5:return"[minulý] dddd [o] LT";case 6:return"[minulú sobotu o] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"pred %s",s:Q,m:Q,mm:Q,h:Q,hh:Q,d:Q,dd:Q,M:Q,MM:Q,y:Q,yy:Q},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),a.defineLocale("sl",{months:"januar_februar_marec_april_maj_junij_julij_avgust_september_oktober_november_december".split("_"),monthsShort:"jan._feb._mar._apr._maj._jun._jul._avg._sep._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"nedelja_ponedeljek_torek_sreda_četrtek_petek_sobota".split("_"),weekdaysShort:"ned._pon._tor._sre._čet._pet._sob.".split("_"),weekdaysMin:"ne_po_to_sr_če_pe_so".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[danes ob] LT",nextDay:"[jutri ob] LT",nextWeek:function(){switch(this.day()){case 0:return"[v] [nedeljo] [ob] LT";case 3:return"[v] [sredo] [ob] LT";case 6:return"[v] [soboto] [ob] LT";case 1:case 2:case 4:case 5:return"[v] dddd [ob] LT"}},lastDay:"[včeraj ob] LT",lastWeek:function(){switch(this.day()){case 0:return"[prejšnjo] [nedeljo] [ob] LT";case 3:return"[prejšnjo] [sredo] [ob] LT";case 6:return"[prejšnjo] [soboto] [ob] LT";case 1:case 2:case 4:case 5:return"[prejšnji] dddd [ob] LT"}},sameElse:"L"},relativeTime:{future:"čez %s",past:"pred %s",s:R,m:R,mm:R,h:R,hh:R,d:R,dd:R,M:R,MM:R,y:R,yy:R},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:7}}),
+//! moment.js locale configuration
+//! locale : Albanian [sq]
+//! author : Flakërim Ismani : https://github.com/flakerimi
+//! author : Menelion Elensúle : https://github.com/Oire
+//! author : Oerd Cukalla : https://github.com/oerd
+a.defineLocale("sq",{months:"Janar_Shkurt_Mars_Prill_Maj_Qershor_Korrik_Gusht_Shtator_Tetor_Nëntor_Dhjetor".split("_"),monthsShort:"Jan_Shk_Mar_Pri_Maj_Qer_Kor_Gus_Sht_Tet_Nën_Dhj".split("_"),weekdays:"E Diel_E Hënë_E Martë_E Mërkurë_E Enjte_E Premte_E Shtunë".split("_"),weekdaysShort:"Die_Hën_Mar_Mër_Enj_Pre_Sht".split("_"),weekdaysMin:"D_H_Ma_Më_E_P_Sh".split("_"),weekdaysParseExact:!0,meridiemParse:/PD|MD/,isPM:function(a){return"M"===a.charAt(0)},meridiem:function(a,b,c){return a<12?"PD":"MD"},longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Sot në] LT",nextDay:"[Nesër në] LT",nextWeek:"dddd [në] LT",lastDay:"[Dje në] LT",lastWeek:"dddd [e kaluar në] LT",sameElse:"L"},relativeTime:{future:"në %s",past:"%s më parë",s:"disa sekonda",m:"një minutë",mm:"%d minuta",h:"një orë",hh:"%d orë",d:"një ditë",dd:"%d ditë",M:"një muaj",MM:"%d muaj",y:"një vit",yy:"%d vite"},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Serbian Cyrillic [sr-cyrl]
+//! author : Milan Janačković<milanjanackovic@gmail.com> : https://github.com/milan-j
+var lb={words:{//Different grammatical cases
+m:["један минут","једне минуте"],mm:["минут","минуте","минута"],h:["један сат","једног сата"],hh:["сат","сата","сати"],dd:["дан","дана","дана"],MM:["месец","месеца","месеци"],yy:["година","године","година"]},correctGrammaticalCase:function(a,b){return 1===a?b[0]:a>=2&&a<=4?b[1]:b[2]},translate:function(a,b,c){var d=lb.words[c];return 1===c.length?b?d[0]:d[1]:a+" "+lb.correctGrammaticalCase(a,d)}};a.defineLocale("sr-cyrl",{months:"јануар_фебруар_март_април_мај_јун_јул_август_септембар_октобар_новембар_децембар".split("_"),monthsShort:"јан._феб._мар._апр._мај_јун_јул_авг._сеп._окт._нов._дец.".split("_"),monthsParseExact:!0,weekdays:"недеља_понедељак_уторак_среда_четвртак_петак_субота".split("_"),weekdaysShort:"нед._пон._уто._сре._чет._пет._суб.".split("_"),weekdaysMin:"не_по_ут_ср_че_пе_су".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[данас у] LT",nextDay:"[сутра у] LT",nextWeek:function(){switch(this.day()){case 0:return"[у] [недељу] [у] LT";case 3:return"[у] [среду] [у] LT";case 6:return"[у] [суботу] [у] LT";case 1:case 2:case 4:case 5:return"[у] dddd [у] LT"}},lastDay:"[јуче у] LT",lastWeek:function(){var a=["[прошле] [недеље] [у] LT","[прошлог] [понедељка] [у] LT","[прошлог] [уторка] [у] LT","[прошле] [среде] [у] LT","[прошлог] [четвртка] [у] LT","[прошлог] [петка] [у] LT","[прошле] [суботе] [у] LT"];return a[this.day()]},sameElse:"L"},relativeTime:{future:"за %s",past:"пре %s",s:"неколико секунди",m:lb.translate,mm:lb.translate,h:lb.translate,hh:lb.translate,d:"дан",dd:lb.translate,M:"месец",MM:lb.translate,y:"годину",yy:lb.translate},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:7}});
+//! moment.js locale configuration
+//! locale : Serbian [sr]
+//! author : Milan Janačković<milanjanackovic@gmail.com> : https://github.com/milan-j
+var mb={words:{//Different grammatical cases
+m:["jedan minut","jedne minute"],mm:["minut","minute","minuta"],h:["jedan sat","jednog sata"],hh:["sat","sata","sati"],dd:["dan","dana","dana"],MM:["mesec","meseca","meseci"],yy:["godina","godine","godina"]},correctGrammaticalCase:function(a,b){return 1===a?b[0]:a>=2&&a<=4?b[1]:b[2]},translate:function(a,b,c){var d=mb.words[c];return 1===c.length?b?d[0]:d[1]:a+" "+mb.correctGrammaticalCase(a,d)}};a.defineLocale("sr",{months:"januar_februar_mart_april_maj_jun_jul_avgust_septembar_oktobar_novembar_decembar".split("_"),monthsShort:"jan._feb._mar._apr._maj_jun_jul_avg._sep._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"nedelja_ponedeljak_utorak_sreda_četvrtak_petak_subota".split("_"),weekdaysShort:"ned._pon._uto._sre._čet._pet._sub.".split("_"),weekdaysMin:"ne_po_ut_sr_če_pe_su".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[danas u] LT",nextDay:"[sutra u] LT",nextWeek:function(){switch(this.day()){case 0:return"[u] [nedelju] [u] LT";case 3:return"[u] [sredu] [u] LT";case 6:return"[u] [subotu] [u] LT";case 1:case 2:case 4:case 5:return"[u] dddd [u] LT"}},lastDay:"[juče u] LT",lastWeek:function(){var a=["[prošle] [nedelje] [u] LT","[prošlog] [ponedeljka] [u] LT","[prošlog] [utorka] [u] LT","[prošle] [srede] [u] LT","[prošlog] [četvrtka] [u] LT","[prošlog] [petka] [u] LT","[prošle] [subote] [u] LT"];return a[this.day()]},sameElse:"L"},relativeTime:{future:"za %s",past:"pre %s",s:"nekoliko sekundi",m:mb.translate,mm:mb.translate,h:mb.translate,hh:mb.translate,d:"dan",dd:mb.translate,M:"mesec",MM:mb.translate,y:"godinu",yy:mb.translate},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:7}}),
+//! moment.js locale configuration
+//! locale : siSwati [ss]
+//! author : Nicolai Davies<mail@nicolai.io> : https://github.com/nicolaidavies
+a.defineLocale("ss",{months:"Bhimbidvwane_Indlovana_Indlov'lenkhulu_Mabasa_Inkhwekhweti_Inhlaba_Kholwane_Ingci_Inyoni_Imphala_Lweti_Ingongoni".split("_"),monthsShort:"Bhi_Ina_Inu_Mab_Ink_Inh_Kho_Igc_Iny_Imp_Lwe_Igo".split("_"),weekdays:"Lisontfo_Umsombuluko_Lesibili_Lesitsatfu_Lesine_Lesihlanu_Umgcibelo".split("_"),weekdaysShort:"Lis_Umb_Lsb_Les_Lsi_Lsh_Umg".split("_"),weekdaysMin:"Li_Us_Lb_Lt_Ls_Lh_Ug".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[Namuhla nga] LT",nextDay:"[Kusasa nga] LT",nextWeek:"dddd [nga] LT",lastDay:"[Itolo nga] LT",lastWeek:"dddd [leliphelile] [nga] LT",sameElse:"L"},relativeTime:{future:"nga %s",past:"wenteka nga %s",s:"emizuzwana lomcane",m:"umzuzu",mm:"%d emizuzu",h:"lihora",hh:"%d emahora",d:"lilanga",dd:"%d emalanga",M:"inyanga",MM:"%d tinyanga",y:"umnyaka",yy:"%d iminyaka"},meridiemParse:/ekuseni|emini|entsambama|ebusuku/,meridiem:function(a,b,c){return a<11?"ekuseni":a<15?"emini":a<19?"entsambama":"ebusuku"},meridiemHour:function(a,b){return 12===a&&(a=0),"ekuseni"===b?a:"emini"===b?a>=11?a:a+12:"entsambama"===b||"ebusuku"===b?0===a?0:a+12:void 0},ordinalParse:/\d{1,2}/,ordinal:"%d",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Swedish [sv]
+//! author : Jens Alm : https://github.com/ulmus
+a.defineLocale("sv",{months:"januari_februari_mars_april_maj_juni_juli_augusti_september_oktober_november_december".split("_"),monthsShort:"jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec".split("_"),weekdays:"söndag_måndag_tisdag_onsdag_torsdag_fredag_lördag".split("_"),weekdaysShort:"sön_mån_tis_ons_tor_fre_lör".split("_"),weekdaysMin:"sö_må_ti_on_to_fr_lö".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [kl.] HH:mm",LLLL:"dddd D MMMM YYYY [kl.] HH:mm",lll:"D MMM YYYY HH:mm",llll:"ddd D MMM YYYY HH:mm"},calendar:{sameDay:"[Idag] LT",nextDay:"[Imorgon] LT",lastDay:"[Igår] LT",nextWeek:"[På] dddd LT",lastWeek:"[I] dddd[s] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"för %s sedan",s:"några sekunder",m:"en minut",mm:"%d minuter",h:"en timme",hh:"%d timmar",d:"en dag",dd:"%d dagar",M:"en månad",MM:"%d månader",y:"ett år",yy:"%d år"},ordinalParse:/\d{1,2}(e|a)/,ordinal:function(a){var b=a%10,c=1===~~(a%100/10)?"e":1===b?"a":2===b?"a":"e";return a+c},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Swahili [sw]
+//! author : Fahad Kassim : https://github.com/fadsel
+a.defineLocale("sw",{months:"Januari_Februari_Machi_Aprili_Mei_Juni_Julai_Agosti_Septemba_Oktoba_Novemba_Desemba".split("_"),monthsShort:"Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ago_Sep_Okt_Nov_Des".split("_"),weekdays:"Jumapili_Jumatatu_Jumanne_Jumatano_Alhamisi_Ijumaa_Jumamosi".split("_"),weekdaysShort:"Jpl_Jtat_Jnne_Jtan_Alh_Ijm_Jmos".split("_"),weekdaysMin:"J2_J3_J4_J5_Al_Ij_J1".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[leo saa] LT",nextDay:"[kesho saa] LT",nextWeek:"[wiki ijayo] dddd [saat] LT",lastDay:"[jana] LT",lastWeek:"[wiki iliyopita] dddd [saat] LT",sameElse:"L"},relativeTime:{future:"%s baadaye",past:"tokea %s",s:"hivi punde",m:"dakika moja",mm:"dakika %d",h:"saa limoja",hh:"masaa %d",d:"siku moja",dd:"masiku %d",M:"mwezi mmoja",MM:"miezi %d",y:"mwaka mmoja",yy:"miaka %d"},week:{dow:1,// Monday is the first day of the week.
+doy:7}});
+//! moment.js locale configuration
+//! locale : Tamil [ta]
+//! author : Arjunkumar Krishnamoorthy : https://github.com/tk120404
+var nb={1:"௧",2:"௨",3:"௩",4:"௪",5:"௫",6:"௬",7:"௭",8:"௮",9:"௯",0:"௦"},ob={"௧":"1","௨":"2","௩":"3","௪":"4","௫":"5","௬":"6","௭":"7","௮":"8","௯":"9","௦":"0"};a.defineLocale("ta",{months:"ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்".split("_"),monthsShort:"ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்".split("_"),weekdays:"ஞாயிற்றுக்கிழமை_திங்கட்கிழமை_செவ்வாய்கிழமை_புதன்கிழமை_வியாழக்கிழமை_வெள்ளிக்கிழமை_சனிக்கிழமை".split("_"),weekdaysShort:"ஞாயிறு_திங்கள்_செவ்வாய்_புதன்_வியாழன்_வெள்ளி_சனி".split("_"),weekdaysMin:"ஞா_தி_செ_பு_வி_வெ_ச".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, HH:mm",LLLL:"dddd, D MMMM YYYY, HH:mm"},calendar:{sameDay:"[இன்று] LT",nextDay:"[நாளை] LT",nextWeek:"dddd, LT",lastDay:"[நேற்று] LT",lastWeek:"[கடந்த வாரம்] dddd, LT",sameElse:"L"},relativeTime:{future:"%s இல்",past:"%s முன்",s:"ஒரு சில விநாடிகள்",m:"ஒரு நிமிடம்",mm:"%d நிமிடங்கள்",h:"ஒரு மணி நேரம்",hh:"%d மணி நேரம்",d:"ஒரு நாள்",dd:"%d நாட்கள்",M:"ஒரு மாதம்",MM:"%d மாதங்கள்",y:"ஒரு வருடம்",yy:"%d ஆண்டுகள்"},ordinalParse:/\d{1,2}வது/,ordinal:function(a){return a+"வது"},preparse:function(a){return a.replace(/[௧௨௩௪௫௬௭௮௯௦]/g,function(a){return ob[a]})},postformat:function(a){return a.replace(/\d/g,function(a){return nb[a]})},
+// refer http://ta.wikipedia.org/s/1er1
+meridiemParse:/யாமம்|வைகறை|காலை|நண்பகல்|எற்பாடு|மாலை/,meridiem:function(a,b,c){return a<2?" யாமம்":a<6?" வைகறை":a<10?" காலை":a<14?" நண்பகல்":a<18?" எற்பாடு":a<22?" மாலை":" யாமம்"},meridiemHour:function(a,b){return 12===a&&(a=0),"யாமம்"===b?a<2?a:a+12:"வைகறை"===b||"காலை"===b?a:"நண்பகல்"===b&&a>=10?a:a+12},week:{dow:0,// Sunday is the first day of the week.
+doy:6}}),
+//! moment.js locale configuration
+//! locale : Telugu [te]
+//! author : Krishna Chaitanya Thota : https://github.com/kcthota
+a.defineLocale("te",{months:"జనవరి_ఫిబ్రవరి_మార్చి_ఏప్రిల్_మే_జూన్_జూలై_ఆగస్టు_సెప్టెంబర్_అక్టోబర్_నవంబర్_డిసెంబర్".split("_"),monthsShort:"జన._ఫిబ్ర._మార్చి_ఏప్రి._మే_జూన్_జూలై_ఆగ._సెప్._అక్టో._నవ._డిసె.".split("_"),monthsParseExact:!0,weekdays:"ఆదివారం_సోమవారం_మంగళవారం_బుధవారం_గురువారం_శుక్రవారం_శనివారం".split("_"),weekdaysShort:"ఆది_సోమ_మంగళ_బుధ_గురు_శుక్ర_శని".split("_"),weekdaysMin:"ఆ_సో_మం_బు_గు_శు_శ".split("_"),longDateFormat:{LT:"A h:mm",LTS:"A h:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm",LLLL:"dddd, D MMMM YYYY, A h:mm"},calendar:{sameDay:"[నేడు] LT",nextDay:"[రేపు] LT",nextWeek:"dddd, LT",lastDay:"[నిన్న] LT",lastWeek:"[గత] dddd, LT",sameElse:"L"},relativeTime:{future:"%s లో",past:"%s క్రితం",s:"కొన్ని క్షణాలు",m:"ఒక నిమిషం",mm:"%d నిమిషాలు",h:"ఒక గంట",hh:"%d గంటలు",d:"ఒక రోజు",dd:"%d రోజులు",M:"ఒక నెల",MM:"%d నెలలు",y:"ఒక సంవత్సరం",yy:"%d సంవత్సరాలు"},ordinalParse:/\d{1,2}వ/,ordinal:"%dవ",meridiemParse:/రాత్రి|ఉదయం|మధ్యాహ్నం|సాయంత్రం/,meridiemHour:function(a,b){return 12===a&&(a=0),"రాత్రి"===b?a<4?a:a+12:"ఉదయం"===b?a:"మధ్యాహ్నం"===b?a>=10?a:a+12:"సాయంత్రం"===b?a+12:void 0},meridiem:function(a,b,c){return a<4?"రాత్రి":a<10?"ఉదయం":a<17?"మధ్యాహ్నం":a<20?"సాయంత్రం":"రాత్రి"},week:{dow:0,// Sunday is the first day of the week.
+doy:6}}),
+//! moment.js locale configuration
+//! locale : Tetun Dili (East Timor) [tet]
+//! author : Joshua Brooks : https://github.com/joshbrooks
+//! author : Onorio De J. Afonso : https://github.com/marobo
+a.defineLocale("tet",{months:"Janeiru_Fevereiru_Marsu_Abril_Maiu_Juniu_Juliu_Augustu_Setembru_Outubru_Novembru_Dezembru".split("_"),monthsShort:"Jan_Fev_Mar_Abr_Mai_Jun_Jul_Aug_Set_Out_Nov_Dez".split("_"),weekdays:"Domingu_Segunda_Tersa_Kuarta_Kinta_Sexta_Sabadu".split("_"),weekdaysShort:"Dom_Seg_Ters_Kua_Kint_Sext_Sab".split("_"),weekdaysMin:"Do_Seg_Te_Ku_Ki_Sex_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Ohin iha] LT",nextDay:"[Aban iha] LT",nextWeek:"dddd [iha] LT",lastDay:"[Horiseik iha] LT",lastWeek:"dddd [semana kotuk] [iha] LT",sameElse:"L"},relativeTime:{future:"iha %s",past:"%s liuba",s:"minutu balun",m:"minutu ida",mm:"minutus %d",h:"horas ida",hh:"horas %d",d:"loron ida",dd:"loron %d",M:"fulan ida",MM:"fulan %d",y:"tinan ida",yy:"tinan %d"},ordinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(a){var b=a%10,c=1===~~(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Thai [th]
+//! author : Kridsada Thanabulpong : https://github.com/sirn
+a.defineLocale("th",{months:"มกราคม_กุมภาพันธ์_มีนาคม_เมษายน_พฤษภาคม_มิถุนายน_กรกฎาคม_สิงหาคม_กันยายน_ตุลาคม_พฤศจิกายน_ธันวาคม".split("_"),monthsShort:"ม.ค._ก.พ._มี.ค._เม.ย._พ.ค._มิ.ย._ก.ค._ส.ค._ก.ย._ต.ค._พ.ย._ธ.ค.".split("_"),monthsParseExact:!0,weekdays:"อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัสบดี_ศุกร์_เสาร์".split("_"),weekdaysShort:"อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัส_ศุกร์_เสาร์".split("_"),// yes, three characters difference
+weekdaysMin:"อา._จ._อ._พ._พฤ._ศ._ส.".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"YYYY/MM/DD",LL:"D MMMM YYYY",LLL:"D MMMM YYYY เวลา H:mm",LLLL:"วันddddที่ D MMMM YYYY เวลา H:mm"},meridiemParse:/ก่อนเที่ยง|หลังเที่ยง/,isPM:function(a){return"หลังเที่ยง"===a},meridiem:function(a,b,c){return a<12?"ก่อนเที่ยง":"หลังเที่ยง"},calendar:{sameDay:"[วันนี้ เวลา] LT",nextDay:"[พรุ่งนี้ เวลา] LT",nextWeek:"dddd[หน้า เวลา] LT",lastDay:"[เมื่อวานนี้ เวลา] LT",lastWeek:"[วัน]dddd[ที่แล้ว เวลา] LT",sameElse:"L"},relativeTime:{future:"อีก %s",past:"%sที่แล้ว",s:"ไม่กี่วินาที",m:"1 นาที",mm:"%d นาที",h:"1 ชั่วโมง",hh:"%d ชั่วโมง",d:"1 วัน",dd:"%d วัน",M:"1 เดือน",MM:"%d เดือน",y:"1 ปี",yy:"%d ปี"}}),
+//! moment.js locale configuration
+//! locale : Tagalog (Philippines) [tl-ph]
+//! author : Dan Hagman : https://github.com/hagmandan
+a.defineLocale("tl-ph",{months:"Enero_Pebrero_Marso_Abril_Mayo_Hunyo_Hulyo_Agosto_Setyembre_Oktubre_Nobyembre_Disyembre".split("_"),monthsShort:"Ene_Peb_Mar_Abr_May_Hun_Hul_Ago_Set_Okt_Nob_Dis".split("_"),weekdays:"Linggo_Lunes_Martes_Miyerkules_Huwebes_Biyernes_Sabado".split("_"),weekdaysShort:"Lin_Lun_Mar_Miy_Huw_Biy_Sab".split("_"),weekdaysMin:"Li_Lu_Ma_Mi_Hu_Bi_Sab".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"MM/D/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY HH:mm",LLLL:"dddd, MMMM DD, YYYY HH:mm"},calendar:{sameDay:"LT [ngayong araw]",nextDay:"[Bukas ng] LT",nextWeek:"LT [sa susunod na] dddd",lastDay:"LT [kahapon]",lastWeek:"LT [noong nakaraang] dddd",sameElse:"L"},relativeTime:{future:"sa loob ng %s",past:"%s ang nakalipas",s:"ilang segundo",m:"isang minuto",mm:"%d minuto",h:"isang oras",hh:"%d oras",d:"isang araw",dd:"%d araw",M:"isang buwan",MM:"%d buwan",y:"isang taon",yy:"%d taon"},ordinalParse:/\d{1,2}/,ordinal:function(a){return a},week:{dow:1,// Monday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Klingon [tlh]
+//! author : Dominika Kruk : https://github.com/amaranthrose
+var pb="pagh_wa’_cha’_wej_loS_vagh_jav_Soch_chorgh_Hut".split("_");a.defineLocale("tlh",{months:"tera’ jar wa’_tera’ jar cha’_tera’ jar wej_tera’ jar loS_tera’ jar vagh_tera’ jar jav_tera’ jar Soch_tera’ jar chorgh_tera’ jar Hut_tera’ jar wa’maH_tera’ jar wa’maH wa’_tera’ jar wa’maH cha’".split("_"),monthsShort:"jar wa’_jar cha’_jar wej_jar loS_jar vagh_jar jav_jar Soch_jar chorgh_jar Hut_jar wa’maH_jar wa’maH wa’_jar wa’maH cha’".split("_"),monthsParseExact:!0,weekdays:"lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj".split("_"),weekdaysShort:"lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj".split("_"),weekdaysMin:"lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[DaHjaj] LT",nextDay:"[wa’leS] LT",nextWeek:"LLL",lastDay:"[wa’Hu’] LT",lastWeek:"LLL",sameElse:"L"},relativeTime:{future:S,past:T,s:"puS lup",m:"wa’ tup",mm:U,h:"wa’ rep",hh:U,d:"wa’ jaj",dd:U,M:"wa’ jar",MM:U,y:"wa’ DIS",yy:U},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Turkish [tr]
+//! authors : Erhan Gundogan : https://github.com/erhangundogan,
+//!           Burak YiÄŸit Kaya: https://github.com/BYK
+var qb={1:"'inci",5:"'inci",8:"'inci",70:"'inci",80:"'inci",2:"'nci",7:"'nci",20:"'nci",50:"'nci",3:"'üncü",4:"'üncü",100:"'üncü",6:"'ncı",9:"'uncu",10:"'uncu",30:"'uncu",60:"'ıncı",90:"'ıncı"};
+//! moment.js locale configuration
+//! locale : Talossan [tzl]
+//! author : Robin van der Vliet : https://github.com/robin0van0der0v
+//! author : Iustì Canun
+// After the year there should be a slash and the amount of years since December 26, 1979 in Roman numerals.
+// This is currently too difficult (maybe even impossible) to add.
+//! moment.js locale configuration
+//! locale : Central Atlas Tamazight Latin [tzm-latn]
+//! author : Abdel Said : https://github.com/abdelsaid
+//! moment.js locale configuration
+//! locale : Central Atlas Tamazight [tzm]
+//! author : Abdel Said : https://github.com/abdelsaid
+//! moment.js locale configuration
+//! locale : Uzbek [uz]
+//! author : Sardor Muminov : https://github.com/muminoff
+//! moment.js locale configuration
+//! locale : Vietnamese [vi]
+//! author : Bang Nguyen : https://github.com/bangnk
+//! moment.js locale configuration
+//! locale : Pseudo [x-pseudo]
+//! author : Andrew Hood : https://github.com/andrewhood125
+//! moment.js locale configuration
+//! locale : Chinese (China) [zh-cn]
+//! author : suupic : https://github.com/suupic
+//! author : Zeno Zeng : https://github.com/zenozeng
+//! moment.js locale configuration
+//! locale : Chinese (Hong Kong) [zh-hk]
+//! author : Ben : https://github.com/ben-lin
+//! author : Chris Lam : https://github.com/hehachris
+//! author : Konstantin : https://github.com/skfd
+//! moment.js locale configuration
+//! locale : Chinese (Taiwan) [zh-tw]
+//! author : Ben : https://github.com/ben-lin
+//! author : Chris Lam : https://github.com/hehachris
+return a.defineLocale("tr",{months:"Ocak_Şubat_Mart_Nisan_Mayıs_Haziran_Temmuz_Ağustos_Eylül_Ekim_Kasım_Aralık".split("_"),monthsShort:"Oca_Şub_Mar_Nis_May_Haz_Tem_Ağu_Eyl_Eki_Kas_Ara".split("_"),weekdays:"Pazar_Pazartesi_Salı_Çarşamba_Perşembe_Cuma_Cumartesi".split("_"),weekdaysShort:"Paz_Pts_Sal_Çar_Per_Cum_Cts".split("_"),weekdaysMin:"Pz_Pt_Sa_Ça_Pe_Cu_Ct".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[bugün saat] LT",nextDay:"[yarın saat] LT",nextWeek:"[haftaya] dddd [saat] LT",lastDay:"[dün] LT",lastWeek:"[geçen hafta] dddd [saat] LT",sameElse:"L"},relativeTime:{future:"%s sonra",past:"%s önce",s:"birkaç saniye",m:"bir dakika",mm:"%d dakika",h:"bir saat",hh:"%d saat",d:"bir gün",dd:"%d gün",M:"bir ay",MM:"%d ay",y:"bir yıl",yy:"%d yıl"},ordinalParse:/\d{1,2}'(inci|nci|üncü|ncı|uncu|ıncı)/,ordinal:function(a){if(0===a)// special case for zero
+return a+"'ıncı";var b=a%10,c=a%100-b,d=a>=100?100:null;return a+(qb[b]||qb[c]||qb[d])},week:{dow:1,// Monday is the first day of the week.
+doy:7}}),a.defineLocale("tzl",{months:"Januar_Fevraglh_Març_Avrïu_Mai_Gün_Julia_Guscht_Setemvar_Listopäts_Noemvar_Zecemvar".split("_"),monthsShort:"Jan_Fev_Mar_Avr_Mai_Gün_Jul_Gus_Set_Lis_Noe_Zec".split("_"),weekdays:"Súladi_Lúneçi_Maitzi_Márcuri_Xhúadi_Viénerçi_Sáturi".split("_"),weekdaysShort:"Súl_Lún_Mai_Már_Xhú_Vié_Sát".split("_"),weekdaysMin:"Sú_Lú_Ma_Má_Xh_Vi_Sá".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD.MM.YYYY",LL:"D. MMMM [dallas] YYYY",LLL:"D. MMMM [dallas] YYYY HH.mm",LLLL:"dddd, [li] D. MMMM [dallas] YYYY HH.mm"},meridiemParse:/d\'o|d\'a/i,isPM:function(a){return"d'o"===a.toLowerCase()},meridiem:function(a,b,c){return a>11?c?"d'o":"D'O":c?"d'a":"D'A"},calendar:{sameDay:"[oxhi à] LT",nextDay:"[demà à] LT",nextWeek:"dddd [à] LT",lastDay:"[ieiri à] LT",lastWeek:"[sür el] dddd [lasteu à] LT",sameElse:"L"},relativeTime:{future:"osprei %s",past:"ja%s",s:W,m:W,mm:W,h:W,hh:W,d:W,dd:W,M:W,MM:W,y:W,yy:W},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),a.defineLocale("tzm-latn",{months:"innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir".split("_"),monthsShort:"innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir".split("_"),weekdays:"asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas".split("_"),weekdaysShort:"asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas".split("_"),weekdaysMin:"asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[asdkh g] LT",nextDay:"[aska g] LT",nextWeek:"dddd [g] LT",lastDay:"[assant g] LT",lastWeek:"dddd [g] LT",sameElse:"L"},relativeTime:{future:"dadkh s yan %s",past:"yan %s",s:"imik",m:"minuḍ",mm:"%d minuḍ",h:"saɛa",hh:"%d tassaɛin",d:"ass",dd:"%d ossan",M:"ayowr",MM:"%d iyyirn",y:"asgas",yy:"%d isgasn"},week:{dow:6,// Saturday is the first day of the week.
+doy:12}}),a.defineLocale("tzm",{months:"ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ".split("_"),monthsShort:"ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ".split("_"),weekdays:"ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ".split("_"),weekdaysShort:"ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ".split("_"),weekdaysMin:"ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[ⴰⵙⴷⵅ ⴴ] LT",nextDay:"[ⴰⵙⴽⴰ ⴴ] LT",nextWeek:"dddd [ⴴ] LT",lastDay:"[ⴰⵚⴰⵏⵜ ⴴ] LT",lastWeek:"dddd [ⴴ] LT",sameElse:"L"},relativeTime:{future:"ⴷⴰⴷⵅ ⵙ ⵢⴰⵏ %s",past:"ⵢⴰⵏ %s",s:"ⵉⵎⵉⴽ",m:"ⵎⵉⵏⵓⴺ",mm:"%d ⵎⵉⵏⵓⴺ",h:"ⵙⴰⵄⴰ",hh:"%d ⵜⴰⵙⵙⴰⵄⵉⵏ",d:"ⴰⵙⵙ",dd:"%d oⵙⵙⴰⵏ",M:"ⴰⵢoⵓⵔ",MM:"%d ⵉⵢⵢⵉⵔⵏ",y:"ⴰⵙⴳⴰⵙ",yy:"%d ⵉⵙⴳⴰⵙⵏ"},week:{dow:6,// Saturday is the first day of the week.
+doy:12}}),a.defineLocale("uk",{months:{format:"січня_лютого_березня_квітня_травня_червня_липня_серпня_вересня_жовтня_листопада_грудня".split("_"),standalone:"січень_лютий_березень_квітень_травень_червень_липень_серпень_вересень_жовтень_листопад_грудень".split("_")},monthsShort:"січ_лют_бер_квіт_трав_черв_лип_серп_вер_жовт_лист_груд".split("_"),weekdays:Z,weekdaysShort:"нд_пн_вт_ср_чт_пт_сб".split("_"),weekdaysMin:"нд_пн_вт_ср_чт_пт_сб".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY р.",LLL:"D MMMM YYYY р., HH:mm",LLLL:"dddd, D MMMM YYYY р., HH:mm"},calendar:{sameDay:$("[Сьогодні "),nextDay:$("[Завтра "),lastDay:$("[Вчора "),nextWeek:$("[У] dddd ["),lastWeek:function(){switch(this.day()){case 0:case 3:case 5:case 6:return $("[Минулої] dddd [").call(this);case 1:case 2:case 4:return $("[Минулого] dddd [").call(this)}},sameElse:"L"},relativeTime:{future:"за %s",past:"%s тому",s:"декілька секунд",m:Y,mm:Y,h:"годину",hh:Y,d:"день",dd:Y,M:"місяць",MM:Y,y:"рік",yy:Y},
+// M. E.: those two are virtually unused but a user might want to implement them for his/her website for some reason
+meridiemParse:/ночі|ранку|дня|вечора/,isPM:function(a){return/^(дня|вечора)$/.test(a)},meridiem:function(a,b,c){return a<4?"ночі":a<12?"ранку":a<17?"дня":"вечора"},ordinalParse:/\d{1,2}-(й|го)/,ordinal:function(a,b){switch(b){case"M":case"d":case"DDD":case"w":case"W":return a+"-й";case"D":return a+"-го";default:return a}},week:{dow:1,// Monday is the first day of the week.
+doy:7}}),a.defineLocale("uz",{months:"январ_феврал_март_апрел_май_июн_июл_август_сентябр_октябр_ноябр_декабр".split("_"),monthsShort:"янв_фев_мар_апр_май_июн_июл_авг_сен_окт_ноя_дек".split("_"),weekdays:"Якшанба_Душанба_Сешанба_Чоршанба_Пайшанба_Жума_Шанба".split("_"),weekdaysShort:"Якш_Душ_Сеш_Чор_Пай_Жум_Шан".split("_"),weekdaysMin:"Як_Ду_Се_Чо_Па_Жу_Ша".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"D MMMM YYYY, dddd HH:mm"},calendar:{sameDay:"[Бугун соат] LT [да]",nextDay:"[Эртага] LT [да]",nextWeek:"dddd [куни соат] LT [да]",lastDay:"[Кеча соат] LT [да]",lastWeek:"[Утган] dddd [куни соат] LT [да]",sameElse:"L"},relativeTime:{future:"Якин %s ичида",past:"Бир неча %s олдин",s:"фурсат",m:"бир дакика",mm:"%d дакика",h:"бир соат",hh:"%d соат",d:"бир кун",dd:"%d кун",M:"бир ой",MM:"%d ой",y:"бир йил",yy:"%d йил"},week:{dow:1,// Monday is the first day of the week.
+doy:7}}),a.defineLocale("vi",{months:"tháng 1_tháng 2_tháng 3_tháng 4_tháng 5_tháng 6_tháng 7_tháng 8_tháng 9_tháng 10_tháng 11_tháng 12".split("_"),monthsShort:"Th01_Th02_Th03_Th04_Th05_Th06_Th07_Th08_Th09_Th10_Th11_Th12".split("_"),monthsParseExact:!0,weekdays:"chủ nhật_thứ hai_thứ ba_thứ tư_thứ năm_thứ sáu_thứ bảy".split("_"),weekdaysShort:"CN_T2_T3_T4_T5_T6_T7".split("_"),weekdaysMin:"CN_T2_T3_T4_T5_T6_T7".split("_"),weekdaysParseExact:!0,meridiemParse:/sa|ch/i,isPM:function(a){return/^ch$/i.test(a)},meridiem:function(a,b,c){return a<12?c?"sa":"SA":c?"ch":"CH"},longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM [năm] YYYY",LLL:"D MMMM [năm] YYYY HH:mm",LLLL:"dddd, D MMMM [năm] YYYY HH:mm",l:"DD/M/YYYY",ll:"D MMM YYYY",lll:"D MMM YYYY HH:mm",llll:"ddd, D MMM YYYY HH:mm"},calendar:{sameDay:"[Hôm nay lúc] LT",nextDay:"[Ngày mai lúc] LT",nextWeek:"dddd [tuần tới lúc] LT",lastDay:"[Hôm qua lúc] LT",lastWeek:"dddd [tuần rồi lúc] LT",sameElse:"L"},relativeTime:{future:"%s tới",past:"%s trước",s:"vài giây",m:"một phút",mm:"%d phút",h:"một giờ",hh:"%d giờ",d:"một ngày",dd:"%d ngày",M:"một tháng",MM:"%d tháng",y:"một năm",yy:"%d năm"},ordinalParse:/\d{1,2}/,ordinal:function(a){return a},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),a.defineLocale("x-pseudo",{months:"J~áñúá~rý_F~ébrú~árý_~Márc~h_Áp~ríl_~Máý_~Júñé~_Júl~ý_Áú~gúst~_Sép~témb~ér_Ó~ctób~ér_Ñ~óvém~bér_~Décé~mbér".split("_"),monthsShort:"J~áñ_~Féb_~Már_~Ápr_~Máý_~Júñ_~Júl_~Áúg_~Sép_~Óct_~Ñóv_~Déc".split("_"),monthsParseExact:!0,weekdays:"S~úñdá~ý_Mó~ñdáý~_Túé~sdáý~_Wéd~ñésd~áý_T~húrs~dáý_~Fríd~áý_S~átúr~dáý".split("_"),weekdaysShort:"S~úñ_~Móñ_~Túé_~Wéd_~Thú_~Frí_~Sát".split("_"),weekdaysMin:"S~ú_Mó~_Tú_~Wé_T~h_Fr~_Sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[T~ódá~ý át] LT",nextDay:"[T~ómó~rró~w át] LT",nextWeek:"dddd [át] LT",lastDay:"[Ý~ést~érdá~ý át] LT",lastWeek:"[L~ást] dddd [át] LT",sameElse:"L"},relativeTime:{future:"í~ñ %s",past:"%s á~gó",s:"á ~féw ~sécó~ñds",m:"á ~míñ~úté",mm:"%d m~íñú~tés",h:"á~ñ hó~úr",hh:"%d h~óúrs",d:"á ~dáý",dd:"%d d~áýs",M:"á ~móñ~th",MM:"%d m~óñt~hs",y:"á ~ýéár",yy:"%d ý~éárs"},ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(a){var b=a%10,c=1===~~(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),a.defineLocale("zh-cn",{months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"周日_周一_周二_周三_周四_周五_周六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),longDateFormat:{LT:"Ah点mm分",LTS:"Ah点m分s秒",L:"YYYY-MM-DD",LL:"YYYY年MMMD日",LLL:"YYYY年MMMD日Ah点mm分",LLLL:"YYYY年MMMD日ddddAh点mm分",l:"YYYY-MM-DD",ll:"YYYY年MMMD日",lll:"YYYY年MMMD日Ah点mm分",llll:"YYYY年MMMD日ddddAh点mm分"},meridiemParse:/凌晨|早上|上午|中午|下午|晚上/,meridiemHour:function(a,b){return 12===a&&(a=0),"凌晨"===b||"早上"===b||"上午"===b?a:"下午"===b||"晚上"===b?a+12:a>=11?a:a+12},meridiem:function(a,b,c){var d=100*a+b;return d<600?"凌晨":d<900?"早上":d<1130?"上午":d<1230?"中午":d<1800?"下午":"晚上"},calendar:{sameDay:function(){return 0===this.minutes()?"[今天]Ah[点整]":"[今天]LT"},nextDay:function(){return 0===this.minutes()?"[明天]Ah[点整]":"[明天]LT"},lastDay:function(){return 0===this.minutes()?"[昨天]Ah[点整]":"[昨天]LT"},nextWeek:function(){var b,c;return b=a().startOf("week"),c=this.diff(b,"days")>=7?"[下]":"[本]",0===this.minutes()?c+"dddAh点整":c+"dddAh点mm"},lastWeek:function(){var b,c;return b=a().startOf("week"),c=this.unix()<b.unix()?"[上]":"[本]",0===this.minutes()?c+"dddAh点整":c+"dddAh点mm"},sameElse:"LL"},ordinalParse:/\d{1,2}(日|月|周)/,ordinal:function(a,b){switch(b){case"d":case"D":case"DDD":return a+"日";case"M":return a+"月";case"w":case"W":return a+"周";default:return a}},relativeTime:{future:"%s内",past:"%s前",s:"几秒",m:"1 分钟",mm:"%d 分钟",h:"1 小时",hh:"%d 小时",d:"1 天",dd:"%d 天",M:"1 个月",MM:"%d 个月",y:"1 年",yy:"%d 年"},week:{
+// GB/T 7408-1994《数据元和交换格式·信息交换·日期和时间表示法》与ISO 8601:1988等效
+dow:1,// Monday is the first day of the week.
+doy:4}}),a.defineLocale("zh-hk",{months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"週日_週一_週二_週三_週四_週五_週六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),longDateFormat:{LT:"Ah點mm分",LTS:"Ah點m分s秒",L:"YYYY年MMMD日",LL:"YYYY年MMMD日",LLL:"YYYY年MMMD日Ah點mm分",LLLL:"YYYY年MMMD日ddddAh點mm分",l:"YYYY年MMMD日",ll:"YYYY年MMMD日",lll:"YYYY年MMMD日Ah點mm分",llll:"YYYY年MMMD日ddddAh點mm分"},meridiemParse:/凌晨|早上|上午|中午|下午|晚上/,meridiemHour:function(a,b){return 12===a&&(a=0),"凌晨"===b||"早上"===b||"上午"===b?a:"中午"===b?a>=11?a:a+12:"下午"===b||"晚上"===b?a+12:void 0},meridiem:function(a,b,c){var d=100*a+b;return d<600?"凌晨":d<900?"早上":d<1130?"上午":d<1230?"中午":d<1800?"下午":"晚上"},calendar:{sameDay:"[今天]LT",nextDay:"[明天]LT",nextWeek:"[下]ddddLT",lastDay:"[昨天]LT",lastWeek:"[上]ddddLT",sameElse:"L"},ordinalParse:/\d{1,2}(日|月|週)/,ordinal:function(a,b){switch(b){case"d":case"D":case"DDD":return a+"日";case"M":return a+"月";case"w":case"W":return a+"週";default:return a}},relativeTime:{future:"%s內",past:"%s前",s:"幾秒",m:"1 分鐘",mm:"%d 分鐘",h:"1 小時",hh:"%d 小時",d:"1 天",dd:"%d 天",M:"1 個月",MM:"%d 個月",y:"1 年",yy:"%d 年"}}),a.defineLocale("zh-tw",{months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"週日_週一_週二_週三_週四_週五_週六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),longDateFormat:{LT:"Ah點mm分",LTS:"Ah點m分s秒",L:"YYYY年MMMD日",LL:"YYYY年MMMD日",LLL:"YYYY年MMMD日Ah點mm分",LLLL:"YYYY年MMMD日ddddAh點mm分",l:"YYYY年MMMD日",ll:"YYYY年MMMD日",lll:"YYYY年MMMD日Ah點mm分",llll:"YYYY年MMMD日ddddAh點mm分"},meridiemParse:/凌晨|早上|上午|中午|下午|晚上/,meridiemHour:function(a,b){return 12===a&&(a=0),"凌晨"===b||"早上"===b||"上午"===b?a:"中午"===b?a>=11?a:a+12:"下午"===b||"晚上"===b?a+12:void 0},meridiem:function(a,b,c){var d=100*a+b;return d<600?"凌晨":d<900?"早上":d<1130?"上午":d<1230?"中午":d<1800?"下午":"晚上"},calendar:{sameDay:"[今天]LT",nextDay:"[明天]LT",nextWeek:"[下]ddddLT",lastDay:"[昨天]LT",lastWeek:"[上]ddddLT",sameElse:"L"},ordinalParse:/\d{1,2}(日|月|週)/,ordinal:function(a,b){switch(b){case"d":case"D":case"DDD":return a+"日";case"M":return a+"月";case"w":case"W":return a+"週";default:return a}},relativeTime:{future:"%s內",past:"%s前",s:"幾秒",m:"1 分鐘",mm:"%d 分鐘",h:"1 小時",hh:"%d 小時",d:"1 天",dd:"%d 天",M:"1 個月",MM:"%d 個月",y:"1 年",yy:"%d 年"}}),a.locale("en"),a});
\ No newline at end of file
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/min/moment-with-locales.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/min/moment-with-locales.js
new file mode 100644
index 0000000000000000000000000000000000000000..8da001b3f4c5e9c2bea2590efa0e0a30e91b6be9
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/min/moment-with-locales.js
@@ -0,0 +1,12862 @@
+;(function (global, factory) {
+    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+    typeof define === 'function' && define.amd ? define(factory) :
+    global.moment = factory()
+}(this, (function () { 'use strict';
+
+var hookCallback;
+
+function hooks () {
+    return hookCallback.apply(null, arguments);
+}
+
+// This is done to register the method called with moment()
+// without creating circular dependencies.
+function setHookCallback (callback) {
+    hookCallback = callback;
+}
+
+function isArray(input) {
+    return input instanceof Array || Object.prototype.toString.call(input) === '[object Array]';
+}
+
+function isObject(input) {
+    // IE8 will treat undefined and null as object if it wasn't for
+    // input != null
+    return input != null && Object.prototype.toString.call(input) === '[object Object]';
+}
+
+function isObjectEmpty(obj) {
+    var k;
+    for (k in obj) {
+        // even if its not own property I'd still call it non-empty
+        return false;
+    }
+    return true;
+}
+
+function isNumber(input) {
+    return typeof value === 'number' || Object.prototype.toString.call(input) === '[object Number]';
+}
+
+function isDate(input) {
+    return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
+}
+
+function map(arr, fn) {
+    var res = [], i;
+    for (i = 0; i < arr.length; ++i) {
+        res.push(fn(arr[i], i));
+    }
+    return res;
+}
+
+function hasOwnProp(a, b) {
+    return Object.prototype.hasOwnProperty.call(a, b);
+}
+
+function extend(a, b) {
+    for (var i in b) {
+        if (hasOwnProp(b, i)) {
+            a[i] = b[i];
+        }
+    }
+
+    if (hasOwnProp(b, 'toString')) {
+        a.toString = b.toString;
+    }
+
+    if (hasOwnProp(b, 'valueOf')) {
+        a.valueOf = b.valueOf;
+    }
+
+    return a;
+}
+
+function createUTC (input, format, locale, strict) {
+    return createLocalOrUTC(input, format, locale, strict, true).utc();
+}
+
+function defaultParsingFlags() {
+    // We need to deep clone this object.
+    return {
+        empty           : false,
+        unusedTokens    : [],
+        unusedInput     : [],
+        overflow        : -2,
+        charsLeftOver   : 0,
+        nullInput       : false,
+        invalidMonth    : null,
+        invalidFormat   : false,
+        userInvalidated : false,
+        iso             : false,
+        parsedDateParts : [],
+        meridiem        : null
+    };
+}
+
+function getParsingFlags(m) {
+    if (m._pf == null) {
+        m._pf = defaultParsingFlags();
+    }
+    return m._pf;
+}
+
+var some;
+if (Array.prototype.some) {
+    some = Array.prototype.some;
+} else {
+    some = function (fun) {
+        var t = Object(this);
+        var len = t.length >>> 0;
+
+        for (var i = 0; i < len; i++) {
+            if (i in t && fun.call(this, t[i], i, t)) {
+                return true;
+            }
+        }
+
+        return false;
+    };
+}
+
+var some$1 = some;
+
+function isValid(m) {
+    if (m._isValid == null) {
+        var flags = getParsingFlags(m);
+        var parsedParts = some$1.call(flags.parsedDateParts, function (i) {
+            return i != null;
+        });
+        var isNowValid = !isNaN(m._d.getTime()) &&
+            flags.overflow < 0 &&
+            !flags.empty &&
+            !flags.invalidMonth &&
+            !flags.invalidWeekday &&
+            !flags.nullInput &&
+            !flags.invalidFormat &&
+            !flags.userInvalidated &&
+            (!flags.meridiem || (flags.meridiem && parsedParts));
+
+        if (m._strict) {
+            isNowValid = isNowValid &&
+                flags.charsLeftOver === 0 &&
+                flags.unusedTokens.length === 0 &&
+                flags.bigHour === undefined;
+        }
+
+        if (Object.isFrozen == null || !Object.isFrozen(m)) {
+            m._isValid = isNowValid;
+        }
+        else {
+            return isNowValid;
+        }
+    }
+    return m._isValid;
+}
+
+function createInvalid (flags) {
+    var m = createUTC(NaN);
+    if (flags != null) {
+        extend(getParsingFlags(m), flags);
+    }
+    else {
+        getParsingFlags(m).userInvalidated = true;
+    }
+
+    return m;
+}
+
+function isUndefined(input) {
+    return input === void 0;
+}
+
+// Plugins that add properties should also add the key here (null value),
+// so we can properly clone ourselves.
+var momentProperties = hooks.momentProperties = [];
+
+function copyConfig(to, from) {
+    var i, prop, val;
+
+    if (!isUndefined(from._isAMomentObject)) {
+        to._isAMomentObject = from._isAMomentObject;
+    }
+    if (!isUndefined(from._i)) {
+        to._i = from._i;
+    }
+    if (!isUndefined(from._f)) {
+        to._f = from._f;
+    }
+    if (!isUndefined(from._l)) {
+        to._l = from._l;
+    }
+    if (!isUndefined(from._strict)) {
+        to._strict = from._strict;
+    }
+    if (!isUndefined(from._tzm)) {
+        to._tzm = from._tzm;
+    }
+    if (!isUndefined(from._isUTC)) {
+        to._isUTC = from._isUTC;
+    }
+    if (!isUndefined(from._offset)) {
+        to._offset = from._offset;
+    }
+    if (!isUndefined(from._pf)) {
+        to._pf = getParsingFlags(from);
+    }
+    if (!isUndefined(from._locale)) {
+        to._locale = from._locale;
+    }
+
+    if (momentProperties.length > 0) {
+        for (i in momentProperties) {
+            prop = momentProperties[i];
+            val = from[prop];
+            if (!isUndefined(val)) {
+                to[prop] = val;
+            }
+        }
+    }
+
+    return to;
+}
+
+var updateInProgress = false;
+
+// Moment prototype object
+function Moment(config) {
+    copyConfig(this, config);
+    this._d = new Date(config._d != null ? config._d.getTime() : NaN);
+    // Prevent infinite loop in case updateOffset creates new moment
+    // objects.
+    if (updateInProgress === false) {
+        updateInProgress = true;
+        hooks.updateOffset(this);
+        updateInProgress = false;
+    }
+}
+
+function isMoment (obj) {
+    return obj instanceof Moment || (obj != null && obj._isAMomentObject != null);
+}
+
+function absFloor (number) {
+    if (number < 0) {
+        // -0 -> 0
+        return Math.ceil(number) || 0;
+    } else {
+        return Math.floor(number);
+    }
+}
+
+function toInt(argumentForCoercion) {
+    var coercedNumber = +argumentForCoercion,
+        value = 0;
+
+    if (coercedNumber !== 0 && isFinite(coercedNumber)) {
+        value = absFloor(coercedNumber);
+    }
+
+    return value;
+}
+
+// compare two arrays, return the number of differences
+function compareArrays(array1, array2, dontConvert) {
+    var len = Math.min(array1.length, array2.length),
+        lengthDiff = Math.abs(array1.length - array2.length),
+        diffs = 0,
+        i;
+    for (i = 0; i < len; i++) {
+        if ((dontConvert && array1[i] !== array2[i]) ||
+            (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) {
+            diffs++;
+        }
+    }
+    return diffs + lengthDiff;
+}
+
+function warn(msg) {
+    if (hooks.suppressDeprecationWarnings === false &&
+            (typeof console !==  'undefined') && console.warn) {
+        console.warn('Deprecation warning: ' + msg);
+    }
+}
+
+function deprecate(msg, fn) {
+    var firstTime = true;
+
+    return extend(function () {
+        if (hooks.deprecationHandler != null) {
+            hooks.deprecationHandler(null, msg);
+        }
+        if (firstTime) {
+            var args = [];
+            var arg;
+            for (var i = 0; i < arguments.length; i++) {
+                arg = '';
+                if (typeof arguments[i] === 'object') {
+                    arg += '\n[' + i + '] ';
+                    for (var key in arguments[0]) {
+                        arg += key + ': ' + arguments[0][key] + ', ';
+                    }
+                    arg = arg.slice(0, -2); // Remove trailing comma and space
+                } else {
+                    arg = arguments[i];
+                }
+                args.push(arg);
+            }
+            warn(msg + '\nArguments: ' + Array.prototype.slice.call(args).join('') + '\n' + (new Error()).stack);
+            firstTime = false;
+        }
+        return fn.apply(this, arguments);
+    }, fn);
+}
+
+var deprecations = {};
+
+function deprecateSimple(name, msg) {
+    if (hooks.deprecationHandler != null) {
+        hooks.deprecationHandler(name, msg);
+    }
+    if (!deprecations[name]) {
+        warn(msg);
+        deprecations[name] = true;
+    }
+}
+
+hooks.suppressDeprecationWarnings = false;
+hooks.deprecationHandler = null;
+
+function isFunction(input) {
+    return input instanceof Function || Object.prototype.toString.call(input) === '[object Function]';
+}
+
+function set (config) {
+    var prop, i;
+    for (i in config) {
+        prop = config[i];
+        if (isFunction(prop)) {
+            this[i] = prop;
+        } else {
+            this['_' + i] = prop;
+        }
+    }
+    this._config = config;
+    // Lenient ordinal parsing accepts just a number in addition to
+    // number + (possibly) stuff coming from _ordinalParseLenient.
+    this._ordinalParseLenient = new RegExp(this._ordinalParse.source + '|' + (/\d{1,2}/).source);
+}
+
+function mergeConfigs(parentConfig, childConfig) {
+    var res = extend({}, parentConfig), prop;
+    for (prop in childConfig) {
+        if (hasOwnProp(childConfig, prop)) {
+            if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) {
+                res[prop] = {};
+                extend(res[prop], parentConfig[prop]);
+                extend(res[prop], childConfig[prop]);
+            } else if (childConfig[prop] != null) {
+                res[prop] = childConfig[prop];
+            } else {
+                delete res[prop];
+            }
+        }
+    }
+    for (prop in parentConfig) {
+        if (hasOwnProp(parentConfig, prop) &&
+                !hasOwnProp(childConfig, prop) &&
+                isObject(parentConfig[prop])) {
+            // make sure changes to properties don't modify parent config
+            res[prop] = extend({}, res[prop]);
+        }
+    }
+    return res;
+}
+
+function Locale(config) {
+    if (config != null) {
+        this.set(config);
+    }
+}
+
+var keys;
+
+if (Object.keys) {
+    keys = Object.keys;
+} else {
+    keys = function (obj) {
+        var i, res = [];
+        for (i in obj) {
+            if (hasOwnProp(obj, i)) {
+                res.push(i);
+            }
+        }
+        return res;
+    };
+}
+
+var keys$1 = keys;
+
+var defaultCalendar = {
+    sameDay : '[Today at] LT',
+    nextDay : '[Tomorrow at] LT',
+    nextWeek : 'dddd [at] LT',
+    lastDay : '[Yesterday at] LT',
+    lastWeek : '[Last] dddd [at] LT',
+    sameElse : 'L'
+};
+
+function calendar (key, mom, now) {
+    var output = this._calendar[key] || this._calendar['sameElse'];
+    return isFunction(output) ? output.call(mom, now) : output;
+}
+
+var defaultLongDateFormat = {
+    LTS  : 'h:mm:ss A',
+    LT   : 'h:mm A',
+    L    : 'MM/DD/YYYY',
+    LL   : 'MMMM D, YYYY',
+    LLL  : 'MMMM D, YYYY h:mm A',
+    LLLL : 'dddd, MMMM D, YYYY h:mm A'
+};
+
+function longDateFormat (key) {
+    var format = this._longDateFormat[key],
+        formatUpper = this._longDateFormat[key.toUpperCase()];
+
+    if (format || !formatUpper) {
+        return format;
+    }
+
+    this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) {
+        return val.slice(1);
+    });
+
+    return this._longDateFormat[key];
+}
+
+var defaultInvalidDate = 'Invalid date';
+
+function invalidDate () {
+    return this._invalidDate;
+}
+
+var defaultOrdinal = '%d';
+var defaultOrdinalParse = /\d{1,2}/;
+
+function ordinal (number) {
+    return this._ordinal.replace('%d', number);
+}
+
+var defaultRelativeTime = {
+    future : 'in %s',
+    past   : '%s ago',
+    s  : 'a few seconds',
+    m  : 'a minute',
+    mm : '%d minutes',
+    h  : 'an hour',
+    hh : '%d hours',
+    d  : 'a day',
+    dd : '%d days',
+    M  : 'a month',
+    MM : '%d months',
+    y  : 'a year',
+    yy : '%d years'
+};
+
+function relativeTime (number, withoutSuffix, string, isFuture) {
+    var output = this._relativeTime[string];
+    return (isFunction(output)) ?
+        output(number, withoutSuffix, string, isFuture) :
+        output.replace(/%d/i, number);
+}
+
+function pastFuture (diff, output) {
+    var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
+    return isFunction(format) ? format(output) : format.replace(/%s/i, output);
+}
+
+var aliases = {};
+
+function addUnitAlias (unit, shorthand) {
+    var lowerCase = unit.toLowerCase();
+    aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit;
+}
+
+function normalizeUnits(units) {
+    return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined;
+}
+
+function normalizeObjectUnits(inputObject) {
+    var normalizedInput = {},
+        normalizedProp,
+        prop;
+
+    for (prop in inputObject) {
+        if (hasOwnProp(inputObject, prop)) {
+            normalizedProp = normalizeUnits(prop);
+            if (normalizedProp) {
+                normalizedInput[normalizedProp] = inputObject[prop];
+            }
+        }
+    }
+
+    return normalizedInput;
+}
+
+var priorities = {};
+
+function addUnitPriority(unit, priority) {
+    priorities[unit] = priority;
+}
+
+function getPrioritizedUnits(unitsObj) {
+    var units = [];
+    for (var u in unitsObj) {
+        units.push({unit: u, priority: priorities[u]});
+    }
+    units.sort(function (a, b) {
+        return a.priority - b.priority;
+    });
+    return units;
+}
+
+function makeGetSet (unit, keepTime) {
+    return function (value) {
+        if (value != null) {
+            set$1(this, unit, value);
+            hooks.updateOffset(this, keepTime);
+            return this;
+        } else {
+            return get(this, unit);
+        }
+    };
+}
+
+function get (mom, unit) {
+    return mom.isValid() ?
+        mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() : NaN;
+}
+
+function set$1 (mom, unit, value) {
+    if (mom.isValid()) {
+        mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
+    }
+}
+
+// MOMENTS
+
+function stringGet (units) {
+    units = normalizeUnits(units);
+    if (isFunction(this[units])) {
+        return this[units]();
+    }
+    return this;
+}
+
+
+function stringSet (units, value) {
+    if (typeof units === 'object') {
+        units = normalizeObjectUnits(units);
+        var prioritized = getPrioritizedUnits(units);
+        for (var i = 0; i < prioritized.length; i++) {
+            this[prioritized[i].unit](units[prioritized[i].unit]);
+        }
+    } else {
+        units = normalizeUnits(units);
+        if (isFunction(this[units])) {
+            return this[units](value);
+        }
+    }
+    return this;
+}
+
+function zeroFill(number, targetLength, forceSign) {
+    var absNumber = '' + Math.abs(number),
+        zerosToFill = targetLength - absNumber.length,
+        sign = number >= 0;
+    return (sign ? (forceSign ? '+' : '') : '-') +
+        Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber;
+}
+
+var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g;
+
+var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g;
+
+var formatFunctions = {};
+
+var formatTokenFunctions = {};
+
+// token:    'M'
+// padded:   ['MM', 2]
+// ordinal:  'Mo'
+// callback: function () { this.month() + 1 }
+function addFormatToken (token, padded, ordinal, callback) {
+    var func = callback;
+    if (typeof callback === 'string') {
+        func = function () {
+            return this[callback]();
+        };
+    }
+    if (token) {
+        formatTokenFunctions[token] = func;
+    }
+    if (padded) {
+        formatTokenFunctions[padded[0]] = function () {
+            return zeroFill(func.apply(this, arguments), padded[1], padded[2]);
+        };
+    }
+    if (ordinal) {
+        formatTokenFunctions[ordinal] = function () {
+            return this.localeData().ordinal(func.apply(this, arguments), token);
+        };
+    }
+}
+
+function removeFormattingTokens(input) {
+    if (input.match(/\[[\s\S]/)) {
+        return input.replace(/^\[|\]$/g, '');
+    }
+    return input.replace(/\\/g, '');
+}
+
+function makeFormatFunction(format) {
+    var array = format.match(formattingTokens), i, length;
+
+    for (i = 0, length = array.length; i < length; i++) {
+        if (formatTokenFunctions[array[i]]) {
+            array[i] = formatTokenFunctions[array[i]];
+        } else {
+            array[i] = removeFormattingTokens(array[i]);
+        }
+    }
+
+    return function (mom) {
+        var output = '', i;
+        for (i = 0; i < length; i++) {
+            output += array[i] instanceof Function ? array[i].call(mom, format) : array[i];
+        }
+        return output;
+    };
+}
+
+// format date using native date object
+function formatMoment(m, format) {
+    if (!m.isValid()) {
+        return m.localeData().invalidDate();
+    }
+
+    format = expandFormat(format, m.localeData());
+    formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format);
+
+    return formatFunctions[format](m);
+}
+
+function expandFormat(format, locale) {
+    var i = 5;
+
+    function replaceLongDateFormatTokens(input) {
+        return locale.longDateFormat(input) || input;
+    }
+
+    localFormattingTokens.lastIndex = 0;
+    while (i >= 0 && localFormattingTokens.test(format)) {
+        format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
+        localFormattingTokens.lastIndex = 0;
+        i -= 1;
+    }
+
+    return format;
+}
+
+var match1         = /\d/;            //       0 - 9
+var match2         = /\d\d/;          //      00 - 99
+var match3         = /\d{3}/;         //     000 - 999
+var match4         = /\d{4}/;         //    0000 - 9999
+var match6         = /[+-]?\d{6}/;    // -999999 - 999999
+var match1to2      = /\d\d?/;         //       0 - 99
+var match3to4      = /\d\d\d\d?/;     //     999 - 9999
+var match5to6      = /\d\d\d\d\d\d?/; //   99999 - 999999
+var match1to3      = /\d{1,3}/;       //       0 - 999
+var match1to4      = /\d{1,4}/;       //       0 - 9999
+var match1to6      = /[+-]?\d{1,6}/;  // -999999 - 999999
+
+var matchUnsigned  = /\d+/;           //       0 - inf
+var matchSigned    = /[+-]?\d+/;      //    -inf - inf
+
+var matchOffset    = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z
+var matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi; // +00 -00 +00:00 -00:00 +0000 -0000 or Z
+
+var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123
+
+// any word (or two) characters or numbers including two/three word month in arabic.
+// includes scottish gaelic two word and hyphenated months
+var matchWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i;
+
+
+var regexes = {};
+
+function addRegexToken (token, regex, strictRegex) {
+    regexes[token] = isFunction(regex) ? regex : function (isStrict, localeData) {
+        return (isStrict && strictRegex) ? strictRegex : regex;
+    };
+}
+
+function getParseRegexForToken (token, config) {
+    if (!hasOwnProp(regexes, token)) {
+        return new RegExp(unescapeFormat(token));
+    }
+
+    return regexes[token](config._strict, config._locale);
+}
+
+// Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
+function unescapeFormat(s) {
+    return regexEscape(s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
+        return p1 || p2 || p3 || p4;
+    }));
+}
+
+function regexEscape(s) {
+    return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
+}
+
+var tokens = {};
+
+function addParseToken (token, callback) {
+    var i, func = callback;
+    if (typeof token === 'string') {
+        token = [token];
+    }
+    if (isNumber(callback)) {
+        func = function (input, array) {
+            array[callback] = toInt(input);
+        };
+    }
+    for (i = 0; i < token.length; i++) {
+        tokens[token[i]] = func;
+    }
+}
+
+function addWeekParseToken (token, callback) {
+    addParseToken(token, function (input, array, config, token) {
+        config._w = config._w || {};
+        callback(input, config._w, config, token);
+    });
+}
+
+function addTimeToArrayFromToken(token, input, config) {
+    if (input != null && hasOwnProp(tokens, token)) {
+        tokens[token](input, config._a, config, token);
+    }
+}
+
+var YEAR = 0;
+var MONTH = 1;
+var DATE = 2;
+var HOUR = 3;
+var MINUTE = 4;
+var SECOND = 5;
+var MILLISECOND = 6;
+var WEEK = 7;
+var WEEKDAY = 8;
+
+var indexOf;
+
+if (Array.prototype.indexOf) {
+    indexOf = Array.prototype.indexOf;
+} else {
+    indexOf = function (o) {
+        // I know
+        var i;
+        for (i = 0; i < this.length; ++i) {
+            if (this[i] === o) {
+                return i;
+            }
+        }
+        return -1;
+    };
+}
+
+var indexOf$1 = indexOf;
+
+function daysInMonth(year, month) {
+    return new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
+}
+
+// FORMATTING
+
+addFormatToken('M', ['MM', 2], 'Mo', function () {
+    return this.month() + 1;
+});
+
+addFormatToken('MMM', 0, 0, function (format) {
+    return this.localeData().monthsShort(this, format);
+});
+
+addFormatToken('MMMM', 0, 0, function (format) {
+    return this.localeData().months(this, format);
+});
+
+// ALIASES
+
+addUnitAlias('month', 'M');
+
+// PRIORITY
+
+addUnitPriority('month', 8);
+
+// PARSING
+
+addRegexToken('M',    match1to2);
+addRegexToken('MM',   match1to2, match2);
+addRegexToken('MMM',  function (isStrict, locale) {
+    return locale.monthsShortRegex(isStrict);
+});
+addRegexToken('MMMM', function (isStrict, locale) {
+    return locale.monthsRegex(isStrict);
+});
+
+addParseToken(['M', 'MM'], function (input, array) {
+    array[MONTH] = toInt(input) - 1;
+});
+
+addParseToken(['MMM', 'MMMM'], function (input, array, config, token) {
+    var month = config._locale.monthsParse(input, token, config._strict);
+    // if we didn't find a month name, mark the date as invalid.
+    if (month != null) {
+        array[MONTH] = month;
+    } else {
+        getParsingFlags(config).invalidMonth = input;
+    }
+});
+
+// LOCALES
+
+var MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/;
+var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_');
+function localeMonths (m, format) {
+    if (!m) {
+        return this._months;
+    }
+    return isArray(this._months) ? this._months[m.month()] :
+        this._months[(this._months.isFormat || MONTHS_IN_FORMAT).test(format) ? 'format' : 'standalone'][m.month()];
+}
+
+var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_');
+function localeMonthsShort (m, format) {
+    if (!m) {
+        return this._monthsShort;
+    }
+    return isArray(this._monthsShort) ? this._monthsShort[m.month()] :
+        this._monthsShort[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()];
+}
+
+function handleStrictParse(monthName, format, strict) {
+    var i, ii, mom, llc = monthName.toLocaleLowerCase();
+    if (!this._monthsParse) {
+        // this is not used
+        this._monthsParse = [];
+        this._longMonthsParse = [];
+        this._shortMonthsParse = [];
+        for (i = 0; i < 12; ++i) {
+            mom = createUTC([2000, i]);
+            this._shortMonthsParse[i] = this.monthsShort(mom, '').toLocaleLowerCase();
+            this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase();
+        }
+    }
+
+    if (strict) {
+        if (format === 'MMM') {
+            ii = indexOf$1.call(this._shortMonthsParse, llc);
+            return ii !== -1 ? ii : null;
+        } else {
+            ii = indexOf$1.call(this._longMonthsParse, llc);
+            return ii !== -1 ? ii : null;
+        }
+    } else {
+        if (format === 'MMM') {
+            ii = indexOf$1.call(this._shortMonthsParse, llc);
+            if (ii !== -1) {
+                return ii;
+            }
+            ii = indexOf$1.call(this._longMonthsParse, llc);
+            return ii !== -1 ? ii : null;
+        } else {
+            ii = indexOf$1.call(this._longMonthsParse, llc);
+            if (ii !== -1) {
+                return ii;
+            }
+            ii = indexOf$1.call(this._shortMonthsParse, llc);
+            return ii !== -1 ? ii : null;
+        }
+    }
+}
+
+function localeMonthsParse (monthName, format, strict) {
+    var i, mom, regex;
+
+    if (this._monthsParseExact) {
+        return handleStrictParse.call(this, monthName, format, strict);
+    }
+
+    if (!this._monthsParse) {
+        this._monthsParse = [];
+        this._longMonthsParse = [];
+        this._shortMonthsParse = [];
+    }
+
+    // TODO: add sorting
+    // Sorting makes sure if one month (or abbr) is a prefix of another
+    // see sorting in computeMonthsParse
+    for (i = 0; i < 12; i++) {
+        // make the regex if we don't have it already
+        mom = createUTC([2000, i]);
+        if (strict && !this._longMonthsParse[i]) {
+            this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');
+            this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');
+        }
+        if (!strict && !this._monthsParse[i]) {
+            regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
+            this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
+        }
+        // test the regex
+        if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {
+            return i;
+        } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {
+            return i;
+        } else if (!strict && this._monthsParse[i].test(monthName)) {
+            return i;
+        }
+    }
+}
+
+// MOMENTS
+
+function setMonth (mom, value) {
+    var dayOfMonth;
+
+    if (!mom.isValid()) {
+        // No op
+        return mom;
+    }
+
+    if (typeof value === 'string') {
+        if (/^\d+$/.test(value)) {
+            value = toInt(value);
+        } else {
+            value = mom.localeData().monthsParse(value);
+            // TODO: Another silent failure?
+            if (!isNumber(value)) {
+                return mom;
+            }
+        }
+    }
+
+    dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));
+    mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
+    return mom;
+}
+
+function getSetMonth (value) {
+    if (value != null) {
+        setMonth(this, value);
+        hooks.updateOffset(this, true);
+        return this;
+    } else {
+        return get(this, 'Month');
+    }
+}
+
+function getDaysInMonth () {
+    return daysInMonth(this.year(), this.month());
+}
+
+var defaultMonthsShortRegex = matchWord;
+function monthsShortRegex (isStrict) {
+    if (this._monthsParseExact) {
+        if (!hasOwnProp(this, '_monthsRegex')) {
+            computeMonthsParse.call(this);
+        }
+        if (isStrict) {
+            return this._monthsShortStrictRegex;
+        } else {
+            return this._monthsShortRegex;
+        }
+    } else {
+        if (!hasOwnProp(this, '_monthsShortRegex')) {
+            this._monthsShortRegex = defaultMonthsShortRegex;
+        }
+        return this._monthsShortStrictRegex && isStrict ?
+            this._monthsShortStrictRegex : this._monthsShortRegex;
+    }
+}
+
+var defaultMonthsRegex = matchWord;
+function monthsRegex (isStrict) {
+    if (this._monthsParseExact) {
+        if (!hasOwnProp(this, '_monthsRegex')) {
+            computeMonthsParse.call(this);
+        }
+        if (isStrict) {
+            return this._monthsStrictRegex;
+        } else {
+            return this._monthsRegex;
+        }
+    } else {
+        if (!hasOwnProp(this, '_monthsRegex')) {
+            this._monthsRegex = defaultMonthsRegex;
+        }
+        return this._monthsStrictRegex && isStrict ?
+            this._monthsStrictRegex : this._monthsRegex;
+    }
+}
+
+function computeMonthsParse () {
+    function cmpLenRev(a, b) {
+        return b.length - a.length;
+    }
+
+    var shortPieces = [], longPieces = [], mixedPieces = [],
+        i, mom;
+    for (i = 0; i < 12; i++) {
+        // make the regex if we don't have it already
+        mom = createUTC([2000, i]);
+        shortPieces.push(this.monthsShort(mom, ''));
+        longPieces.push(this.months(mom, ''));
+        mixedPieces.push(this.months(mom, ''));
+        mixedPieces.push(this.monthsShort(mom, ''));
+    }
+    // Sorting makes sure if one month (or abbr) is a prefix of another it
+    // will match the longer piece.
+    shortPieces.sort(cmpLenRev);
+    longPieces.sort(cmpLenRev);
+    mixedPieces.sort(cmpLenRev);
+    for (i = 0; i < 12; i++) {
+        shortPieces[i] = regexEscape(shortPieces[i]);
+        longPieces[i] = regexEscape(longPieces[i]);
+    }
+    for (i = 0; i < 24; i++) {
+        mixedPieces[i] = regexEscape(mixedPieces[i]);
+    }
+
+    this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
+    this._monthsShortRegex = this._monthsRegex;
+    this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
+    this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
+}
+
+// FORMATTING
+
+addFormatToken('Y', 0, 0, function () {
+    var y = this.year();
+    return y <= 9999 ? '' + y : '+' + y;
+});
+
+addFormatToken(0, ['YY', 2], 0, function () {
+    return this.year() % 100;
+});
+
+addFormatToken(0, ['YYYY',   4],       0, 'year');
+addFormatToken(0, ['YYYYY',  5],       0, 'year');
+addFormatToken(0, ['YYYYYY', 6, true], 0, 'year');
+
+// ALIASES
+
+addUnitAlias('year', 'y');
+
+// PRIORITIES
+
+addUnitPriority('year', 1);
+
+// PARSING
+
+addRegexToken('Y',      matchSigned);
+addRegexToken('YY',     match1to2, match2);
+addRegexToken('YYYY',   match1to4, match4);
+addRegexToken('YYYYY',  match1to6, match6);
+addRegexToken('YYYYYY', match1to6, match6);
+
+addParseToken(['YYYYY', 'YYYYYY'], YEAR);
+addParseToken('YYYY', function (input, array) {
+    array[YEAR] = input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input);
+});
+addParseToken('YY', function (input, array) {
+    array[YEAR] = hooks.parseTwoDigitYear(input);
+});
+addParseToken('Y', function (input, array) {
+    array[YEAR] = parseInt(input, 10);
+});
+
+// HELPERS
+
+function daysInYear(year) {
+    return isLeapYear(year) ? 366 : 365;
+}
+
+function isLeapYear(year) {
+    return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
+}
+
+// HOOKS
+
+hooks.parseTwoDigitYear = function (input) {
+    return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
+};
+
+// MOMENTS
+
+var getSetYear = makeGetSet('FullYear', true);
+
+function getIsLeapYear () {
+    return isLeapYear(this.year());
+}
+
+function createDate (y, m, d, h, M, s, ms) {
+    //can't just apply() to create a date:
+    //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply
+    var date = new Date(y, m, d, h, M, s, ms);
+
+    //the date constructor remaps years 0-99 to 1900-1999
+    if (y < 100 && y >= 0 && isFinite(date.getFullYear())) {
+        date.setFullYear(y);
+    }
+    return date;
+}
+
+function createUTCDate (y) {
+    var date = new Date(Date.UTC.apply(null, arguments));
+
+    //the Date.UTC function remaps years 0-99 to 1900-1999
+    if (y < 100 && y >= 0 && isFinite(date.getUTCFullYear())) {
+        date.setUTCFullYear(y);
+    }
+    return date;
+}
+
+// start-of-first-week - start-of-year
+function firstWeekOffset(year, dow, doy) {
+    var // first-week day -- which january is always in the first week (4 for iso, 1 for other)
+        fwd = 7 + dow - doy,
+        // first-week day local weekday -- which local weekday is fwd
+        fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7;
+
+    return -fwdlw + fwd - 1;
+}
+
+//http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
+function dayOfYearFromWeeks(year, week, weekday, dow, doy) {
+    var localWeekday = (7 + weekday - dow) % 7,
+        weekOffset = firstWeekOffset(year, dow, doy),
+        dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset,
+        resYear, resDayOfYear;
+
+    if (dayOfYear <= 0) {
+        resYear = year - 1;
+        resDayOfYear = daysInYear(resYear) + dayOfYear;
+    } else if (dayOfYear > daysInYear(year)) {
+        resYear = year + 1;
+        resDayOfYear = dayOfYear - daysInYear(year);
+    } else {
+        resYear = year;
+        resDayOfYear = dayOfYear;
+    }
+
+    return {
+        year: resYear,
+        dayOfYear: resDayOfYear
+    };
+}
+
+function weekOfYear(mom, dow, doy) {
+    var weekOffset = firstWeekOffset(mom.year(), dow, doy),
+        week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1,
+        resWeek, resYear;
+
+    if (week < 1) {
+        resYear = mom.year() - 1;
+        resWeek = week + weeksInYear(resYear, dow, doy);
+    } else if (week > weeksInYear(mom.year(), dow, doy)) {
+        resWeek = week - weeksInYear(mom.year(), dow, doy);
+        resYear = mom.year() + 1;
+    } else {
+        resYear = mom.year();
+        resWeek = week;
+    }
+
+    return {
+        week: resWeek,
+        year: resYear
+    };
+}
+
+function weeksInYear(year, dow, doy) {
+    var weekOffset = firstWeekOffset(year, dow, doy),
+        weekOffsetNext = firstWeekOffset(year + 1, dow, doy);
+    return (daysInYear(year) - weekOffset + weekOffsetNext) / 7;
+}
+
+// FORMATTING
+
+addFormatToken('w', ['ww', 2], 'wo', 'week');
+addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek');
+
+// ALIASES
+
+addUnitAlias('week', 'w');
+addUnitAlias('isoWeek', 'W');
+
+// PRIORITIES
+
+addUnitPriority('week', 5);
+addUnitPriority('isoWeek', 5);
+
+// PARSING
+
+addRegexToken('w',  match1to2);
+addRegexToken('ww', match1to2, match2);
+addRegexToken('W',  match1to2);
+addRegexToken('WW', match1to2, match2);
+
+addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) {
+    week[token.substr(0, 1)] = toInt(input);
+});
+
+// HELPERS
+
+// LOCALES
+
+function localeWeek (mom) {
+    return weekOfYear(mom, this._week.dow, this._week.doy).week;
+}
+
+var defaultLocaleWeek = {
+    dow : 0, // Sunday is the first day of the week.
+    doy : 6  // The week that contains Jan 1st is the first week of the year.
+};
+
+function localeFirstDayOfWeek () {
+    return this._week.dow;
+}
+
+function localeFirstDayOfYear () {
+    return this._week.doy;
+}
+
+// MOMENTS
+
+function getSetWeek (input) {
+    var week = this.localeData().week(this);
+    return input == null ? week : this.add((input - week) * 7, 'd');
+}
+
+function getSetISOWeek (input) {
+    var week = weekOfYear(this, 1, 4).week;
+    return input == null ? week : this.add((input - week) * 7, 'd');
+}
+
+// FORMATTING
+
+addFormatToken('d', 0, 'do', 'day');
+
+addFormatToken('dd', 0, 0, function (format) {
+    return this.localeData().weekdaysMin(this, format);
+});
+
+addFormatToken('ddd', 0, 0, function (format) {
+    return this.localeData().weekdaysShort(this, format);
+});
+
+addFormatToken('dddd', 0, 0, function (format) {
+    return this.localeData().weekdays(this, format);
+});
+
+addFormatToken('e', 0, 0, 'weekday');
+addFormatToken('E', 0, 0, 'isoWeekday');
+
+// ALIASES
+
+addUnitAlias('day', 'd');
+addUnitAlias('weekday', 'e');
+addUnitAlias('isoWeekday', 'E');
+
+// PRIORITY
+addUnitPriority('day', 11);
+addUnitPriority('weekday', 11);
+addUnitPriority('isoWeekday', 11);
+
+// PARSING
+
+addRegexToken('d',    match1to2);
+addRegexToken('e',    match1to2);
+addRegexToken('E',    match1to2);
+addRegexToken('dd',   function (isStrict, locale) {
+    return locale.weekdaysMinRegex(isStrict);
+});
+addRegexToken('ddd',   function (isStrict, locale) {
+    return locale.weekdaysShortRegex(isStrict);
+});
+addRegexToken('dddd',   function (isStrict, locale) {
+    return locale.weekdaysRegex(isStrict);
+});
+
+addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) {
+    var weekday = config._locale.weekdaysParse(input, token, config._strict);
+    // if we didn't get a weekday name, mark the date as invalid
+    if (weekday != null) {
+        week.d = weekday;
+    } else {
+        getParsingFlags(config).invalidWeekday = input;
+    }
+});
+
+addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) {
+    week[token] = toInt(input);
+});
+
+// HELPERS
+
+function parseWeekday(input, locale) {
+    if (typeof input !== 'string') {
+        return input;
+    }
+
+    if (!isNaN(input)) {
+        return parseInt(input, 10);
+    }
+
+    input = locale.weekdaysParse(input);
+    if (typeof input === 'number') {
+        return input;
+    }
+
+    return null;
+}
+
+function parseIsoWeekday(input, locale) {
+    if (typeof input === 'string') {
+        return locale.weekdaysParse(input) % 7 || 7;
+    }
+    return isNaN(input) ? null : input;
+}
+
+// LOCALES
+
+var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_');
+function localeWeekdays (m, format) {
+    if (!m) {
+        return this._weekdays;
+    }
+    return isArray(this._weekdays) ? this._weekdays[m.day()] :
+        this._weekdays[this._weekdays.isFormat.test(format) ? 'format' : 'standalone'][m.day()];
+}
+
+var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_');
+function localeWeekdaysShort (m) {
+    return (m) ? this._weekdaysShort[m.day()] : this._weekdaysShort;
+}
+
+var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_');
+function localeWeekdaysMin (m) {
+    return (m) ? this._weekdaysMin[m.day()] : this._weekdaysMin;
+}
+
+function handleStrictParse$1(weekdayName, format, strict) {
+    var i, ii, mom, llc = weekdayName.toLocaleLowerCase();
+    if (!this._weekdaysParse) {
+        this._weekdaysParse = [];
+        this._shortWeekdaysParse = [];
+        this._minWeekdaysParse = [];
+
+        for (i = 0; i < 7; ++i) {
+            mom = createUTC([2000, 1]).day(i);
+            this._minWeekdaysParse[i] = this.weekdaysMin(mom, '').toLocaleLowerCase();
+            this._shortWeekdaysParse[i] = this.weekdaysShort(mom, '').toLocaleLowerCase();
+            this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase();
+        }
+    }
+
+    if (strict) {
+        if (format === 'dddd') {
+            ii = indexOf$1.call(this._weekdaysParse, llc);
+            return ii !== -1 ? ii : null;
+        } else if (format === 'ddd') {
+            ii = indexOf$1.call(this._shortWeekdaysParse, llc);
+            return ii !== -1 ? ii : null;
+        } else {
+            ii = indexOf$1.call(this._minWeekdaysParse, llc);
+            return ii !== -1 ? ii : null;
+        }
+    } else {
+        if (format === 'dddd') {
+            ii = indexOf$1.call(this._weekdaysParse, llc);
+            if (ii !== -1) {
+                return ii;
+            }
+            ii = indexOf$1.call(this._shortWeekdaysParse, llc);
+            if (ii !== -1) {
+                return ii;
+            }
+            ii = indexOf$1.call(this._minWeekdaysParse, llc);
+            return ii !== -1 ? ii : null;
+        } else if (format === 'ddd') {
+            ii = indexOf$1.call(this._shortWeekdaysParse, llc);
+            if (ii !== -1) {
+                return ii;
+            }
+            ii = indexOf$1.call(this._weekdaysParse, llc);
+            if (ii !== -1) {
+                return ii;
+            }
+            ii = indexOf$1.call(this._minWeekdaysParse, llc);
+            return ii !== -1 ? ii : null;
+        } else {
+            ii = indexOf$1.call(this._minWeekdaysParse, llc);
+            if (ii !== -1) {
+                return ii;
+            }
+            ii = indexOf$1.call(this._weekdaysParse, llc);
+            if (ii !== -1) {
+                return ii;
+            }
+            ii = indexOf$1.call(this._shortWeekdaysParse, llc);
+            return ii !== -1 ? ii : null;
+        }
+    }
+}
+
+function localeWeekdaysParse (weekdayName, format, strict) {
+    var i, mom, regex;
+
+    if (this._weekdaysParseExact) {
+        return handleStrictParse$1.call(this, weekdayName, format, strict);
+    }
+
+    if (!this._weekdaysParse) {
+        this._weekdaysParse = [];
+        this._minWeekdaysParse = [];
+        this._shortWeekdaysParse = [];
+        this._fullWeekdaysParse = [];
+    }
+
+    for (i = 0; i < 7; i++) {
+        // make the regex if we don't have it already
+
+        mom = createUTC([2000, 1]).day(i);
+        if (strict && !this._fullWeekdaysParse[i]) {
+            this._fullWeekdaysParse[i] = new RegExp('^' + this.weekdays(mom, '').replace('.', '\.?') + '$', 'i');
+            this._shortWeekdaysParse[i] = new RegExp('^' + this.weekdaysShort(mom, '').replace('.', '\.?') + '$', 'i');
+            this._minWeekdaysParse[i] = new RegExp('^' + this.weekdaysMin(mom, '').replace('.', '\.?') + '$', 'i');
+        }
+        if (!this._weekdaysParse[i]) {
+            regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
+            this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
+        }
+        // test the regex
+        if (strict && format === 'dddd' && this._fullWeekdaysParse[i].test(weekdayName)) {
+            return i;
+        } else if (strict && format === 'ddd' && this._shortWeekdaysParse[i].test(weekdayName)) {
+            return i;
+        } else if (strict && format === 'dd' && this._minWeekdaysParse[i].test(weekdayName)) {
+            return i;
+        } else if (!strict && this._weekdaysParse[i].test(weekdayName)) {
+            return i;
+        }
+    }
+}
+
+// MOMENTS
+
+function getSetDayOfWeek (input) {
+    if (!this.isValid()) {
+        return input != null ? this : NaN;
+    }
+    var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
+    if (input != null) {
+        input = parseWeekday(input, this.localeData());
+        return this.add(input - day, 'd');
+    } else {
+        return day;
+    }
+}
+
+function getSetLocaleDayOfWeek (input) {
+    if (!this.isValid()) {
+        return input != null ? this : NaN;
+    }
+    var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;
+    return input == null ? weekday : this.add(input - weekday, 'd');
+}
+
+function getSetISODayOfWeek (input) {
+    if (!this.isValid()) {
+        return input != null ? this : NaN;
+    }
+
+    // behaves the same as moment#day except
+    // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
+    // as a setter, sunday should belong to the previous week.
+
+    if (input != null) {
+        var weekday = parseIsoWeekday(input, this.localeData());
+        return this.day(this.day() % 7 ? weekday : weekday - 7);
+    } else {
+        return this.day() || 7;
+    }
+}
+
+var defaultWeekdaysRegex = matchWord;
+function weekdaysRegex (isStrict) {
+    if (this._weekdaysParseExact) {
+        if (!hasOwnProp(this, '_weekdaysRegex')) {
+            computeWeekdaysParse.call(this);
+        }
+        if (isStrict) {
+            return this._weekdaysStrictRegex;
+        } else {
+            return this._weekdaysRegex;
+        }
+    } else {
+        if (!hasOwnProp(this, '_weekdaysRegex')) {
+            this._weekdaysRegex = defaultWeekdaysRegex;
+        }
+        return this._weekdaysStrictRegex && isStrict ?
+            this._weekdaysStrictRegex : this._weekdaysRegex;
+    }
+}
+
+var defaultWeekdaysShortRegex = matchWord;
+function weekdaysShortRegex (isStrict) {
+    if (this._weekdaysParseExact) {
+        if (!hasOwnProp(this, '_weekdaysRegex')) {
+            computeWeekdaysParse.call(this);
+        }
+        if (isStrict) {
+            return this._weekdaysShortStrictRegex;
+        } else {
+            return this._weekdaysShortRegex;
+        }
+    } else {
+        if (!hasOwnProp(this, '_weekdaysShortRegex')) {
+            this._weekdaysShortRegex = defaultWeekdaysShortRegex;
+        }
+        return this._weekdaysShortStrictRegex && isStrict ?
+            this._weekdaysShortStrictRegex : this._weekdaysShortRegex;
+    }
+}
+
+var defaultWeekdaysMinRegex = matchWord;
+function weekdaysMinRegex (isStrict) {
+    if (this._weekdaysParseExact) {
+        if (!hasOwnProp(this, '_weekdaysRegex')) {
+            computeWeekdaysParse.call(this);
+        }
+        if (isStrict) {
+            return this._weekdaysMinStrictRegex;
+        } else {
+            return this._weekdaysMinRegex;
+        }
+    } else {
+        if (!hasOwnProp(this, '_weekdaysMinRegex')) {
+            this._weekdaysMinRegex = defaultWeekdaysMinRegex;
+        }
+        return this._weekdaysMinStrictRegex && isStrict ?
+            this._weekdaysMinStrictRegex : this._weekdaysMinRegex;
+    }
+}
+
+
+function computeWeekdaysParse () {
+    function cmpLenRev(a, b) {
+        return b.length - a.length;
+    }
+
+    var minPieces = [], shortPieces = [], longPieces = [], mixedPieces = [],
+        i, mom, minp, shortp, longp;
+    for (i = 0; i < 7; i++) {
+        // make the regex if we don't have it already
+        mom = createUTC([2000, 1]).day(i);
+        minp = this.weekdaysMin(mom, '');
+        shortp = this.weekdaysShort(mom, '');
+        longp = this.weekdays(mom, '');
+        minPieces.push(minp);
+        shortPieces.push(shortp);
+        longPieces.push(longp);
+        mixedPieces.push(minp);
+        mixedPieces.push(shortp);
+        mixedPieces.push(longp);
+    }
+    // Sorting makes sure if one weekday (or abbr) is a prefix of another it
+    // will match the longer piece.
+    minPieces.sort(cmpLenRev);
+    shortPieces.sort(cmpLenRev);
+    longPieces.sort(cmpLenRev);
+    mixedPieces.sort(cmpLenRev);
+    for (i = 0; i < 7; i++) {
+        shortPieces[i] = regexEscape(shortPieces[i]);
+        longPieces[i] = regexEscape(longPieces[i]);
+        mixedPieces[i] = regexEscape(mixedPieces[i]);
+    }
+
+    this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
+    this._weekdaysShortRegex = this._weekdaysRegex;
+    this._weekdaysMinRegex = this._weekdaysRegex;
+
+    this._weekdaysStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
+    this._weekdaysShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
+    this._weekdaysMinStrictRegex = new RegExp('^(' + minPieces.join('|') + ')', 'i');
+}
+
+// FORMATTING
+
+function hFormat() {
+    return this.hours() % 12 || 12;
+}
+
+function kFormat() {
+    return this.hours() || 24;
+}
+
+addFormatToken('H', ['HH', 2], 0, 'hour');
+addFormatToken('h', ['hh', 2], 0, hFormat);
+addFormatToken('k', ['kk', 2], 0, kFormat);
+
+addFormatToken('hmm', 0, 0, function () {
+    return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2);
+});
+
+addFormatToken('hmmss', 0, 0, function () {
+    return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2) +
+        zeroFill(this.seconds(), 2);
+});
+
+addFormatToken('Hmm', 0, 0, function () {
+    return '' + this.hours() + zeroFill(this.minutes(), 2);
+});
+
+addFormatToken('Hmmss', 0, 0, function () {
+    return '' + this.hours() + zeroFill(this.minutes(), 2) +
+        zeroFill(this.seconds(), 2);
+});
+
+function meridiem (token, lowercase) {
+    addFormatToken(token, 0, 0, function () {
+        return this.localeData().meridiem(this.hours(), this.minutes(), lowercase);
+    });
+}
+
+meridiem('a', true);
+meridiem('A', false);
+
+// ALIASES
+
+addUnitAlias('hour', 'h');
+
+// PRIORITY
+addUnitPriority('hour', 13);
+
+// PARSING
+
+function matchMeridiem (isStrict, locale) {
+    return locale._meridiemParse;
+}
+
+addRegexToken('a',  matchMeridiem);
+addRegexToken('A',  matchMeridiem);
+addRegexToken('H',  match1to2);
+addRegexToken('h',  match1to2);
+addRegexToken('HH', match1to2, match2);
+addRegexToken('hh', match1to2, match2);
+
+addRegexToken('hmm', match3to4);
+addRegexToken('hmmss', match5to6);
+addRegexToken('Hmm', match3to4);
+addRegexToken('Hmmss', match5to6);
+
+addParseToken(['H', 'HH'], HOUR);
+addParseToken(['a', 'A'], function (input, array, config) {
+    config._isPm = config._locale.isPM(input);
+    config._meridiem = input;
+});
+addParseToken(['h', 'hh'], function (input, array, config) {
+    array[HOUR] = toInt(input);
+    getParsingFlags(config).bigHour = true;
+});
+addParseToken('hmm', function (input, array, config) {
+    var pos = input.length - 2;
+    array[HOUR] = toInt(input.substr(0, pos));
+    array[MINUTE] = toInt(input.substr(pos));
+    getParsingFlags(config).bigHour = true;
+});
+addParseToken('hmmss', function (input, array, config) {
+    var pos1 = input.length - 4;
+    var pos2 = input.length - 2;
+    array[HOUR] = toInt(input.substr(0, pos1));
+    array[MINUTE] = toInt(input.substr(pos1, 2));
+    array[SECOND] = toInt(input.substr(pos2));
+    getParsingFlags(config).bigHour = true;
+});
+addParseToken('Hmm', function (input, array, config) {
+    var pos = input.length - 2;
+    array[HOUR] = toInt(input.substr(0, pos));
+    array[MINUTE] = toInt(input.substr(pos));
+});
+addParseToken('Hmmss', function (input, array, config) {
+    var pos1 = input.length - 4;
+    var pos2 = input.length - 2;
+    array[HOUR] = toInt(input.substr(0, pos1));
+    array[MINUTE] = toInt(input.substr(pos1, 2));
+    array[SECOND] = toInt(input.substr(pos2));
+});
+
+// LOCALES
+
+function localeIsPM (input) {
+    // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
+    // Using charAt should be more compatible.
+    return ((input + '').toLowerCase().charAt(0) === 'p');
+}
+
+var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i;
+function localeMeridiem (hours, minutes, isLower) {
+    if (hours > 11) {
+        return isLower ? 'pm' : 'PM';
+    } else {
+        return isLower ? 'am' : 'AM';
+    }
+}
+
+
+// MOMENTS
+
+// Setting the hour should keep the time, because the user explicitly
+// specified which hour he wants. So trying to maintain the same hour (in
+// a new timezone) makes sense. Adding/subtracting hours does not follow
+// this rule.
+var getSetHour = makeGetSet('Hours', true);
+
+// months
+// week
+// weekdays
+// meridiem
+var baseConfig = {
+    calendar: defaultCalendar,
+    longDateFormat: defaultLongDateFormat,
+    invalidDate: defaultInvalidDate,
+    ordinal: defaultOrdinal,
+    ordinalParse: defaultOrdinalParse,
+    relativeTime: defaultRelativeTime,
+
+    months: defaultLocaleMonths,
+    monthsShort: defaultLocaleMonthsShort,
+
+    week: defaultLocaleWeek,
+
+    weekdays: defaultLocaleWeekdays,
+    weekdaysMin: defaultLocaleWeekdaysMin,
+    weekdaysShort: defaultLocaleWeekdaysShort,
+
+    meridiemParse: defaultLocaleMeridiemParse
+};
+
+// internal storage for locale config files
+var locales = {};
+var localeFamilies = {};
+var globalLocale;
+
+function normalizeLocale(key) {
+    return key ? key.toLowerCase().replace('_', '-') : key;
+}
+
+// pick the locale from the array
+// try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
+// substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
+function chooseLocale(names) {
+    var i = 0, j, next, locale, split;
+
+    while (i < names.length) {
+        split = normalizeLocale(names[i]).split('-');
+        j = split.length;
+        next = normalizeLocale(names[i + 1]);
+        next = next ? next.split('-') : null;
+        while (j > 0) {
+            locale = loadLocale(split.slice(0, j).join('-'));
+            if (locale) {
+                return locale;
+            }
+            if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
+                //the next array item is better than a shallower substring of this one
+                break;
+            }
+            j--;
+        }
+        i++;
+    }
+    return null;
+}
+
+function loadLocale(name) {
+    var oldLocale = null;
+    // TODO: Find a better way to register and load all the locales in Node
+    if (!locales[name] && (typeof module !== 'undefined') &&
+            module && module.exports) {
+        try {
+            oldLocale = globalLocale._abbr;
+            require('./locale/' + name);
+            // because defineLocale currently also sets the global locale, we
+            // want to undo that for lazy loaded locales
+            getSetGlobalLocale(oldLocale);
+        } catch (e) { }
+    }
+    return locales[name];
+}
+
+// This function will load locale and then set the global locale.  If
+// no arguments are passed in, it will simply return the current global
+// locale key.
+function getSetGlobalLocale (key, values) {
+    var data;
+    if (key) {
+        if (isUndefined(values)) {
+            data = getLocale(key);
+        }
+        else {
+            data = defineLocale(key, values);
+        }
+
+        if (data) {
+            // moment.duration._locale = moment._locale = data;
+            globalLocale = data;
+        }
+    }
+
+    return globalLocale._abbr;
+}
+
+function defineLocale (name, config) {
+    if (config !== null) {
+        var parentConfig = baseConfig;
+        config.abbr = name;
+        if (locales[name] != null) {
+            deprecateSimple('defineLocaleOverride',
+                    'use moment.updateLocale(localeName, config) to change ' +
+                    'an existing locale. moment.defineLocale(localeName, ' +
+                    'config) should only be used for creating a new locale ' +
+                    'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.');
+            parentConfig = locales[name]._config;
+        } else if (config.parentLocale != null) {
+            if (locales[config.parentLocale] != null) {
+                parentConfig = locales[config.parentLocale]._config;
+            } else {
+                if (!localeFamilies[config.parentLocale]) {
+                    localeFamilies[config.parentLocale] = [];
+                }
+                localeFamilies[config.parentLocale].push({
+                    name: name,
+                    config: config
+                });
+                return null;
+            }
+        }
+        locales[name] = new Locale(mergeConfigs(parentConfig, config));
+
+        if (localeFamilies[name]) {
+            localeFamilies[name].forEach(function (x) {
+                defineLocale(x.name, x.config);
+            });
+        }
+
+        // backwards compat for now: also set the locale
+        // make sure we set the locale AFTER all child locales have been
+        // created, so we won't end up with the child locale set.
+        getSetGlobalLocale(name);
+
+
+        return locales[name];
+    } else {
+        // useful for testing
+        delete locales[name];
+        return null;
+    }
+}
+
+function updateLocale(name, config) {
+    if (config != null) {
+        var locale, parentConfig = baseConfig;
+        // MERGE
+        if (locales[name] != null) {
+            parentConfig = locales[name]._config;
+        }
+        config = mergeConfigs(parentConfig, config);
+        locale = new Locale(config);
+        locale.parentLocale = locales[name];
+        locales[name] = locale;
+
+        // backwards compat for now: also set the locale
+        getSetGlobalLocale(name);
+    } else {
+        // pass null for config to unupdate, useful for tests
+        if (locales[name] != null) {
+            if (locales[name].parentLocale != null) {
+                locales[name] = locales[name].parentLocale;
+            } else if (locales[name] != null) {
+                delete locales[name];
+            }
+        }
+    }
+    return locales[name];
+}
+
+// returns locale data
+function getLocale (key) {
+    var locale;
+
+    if (key && key._locale && key._locale._abbr) {
+        key = key._locale._abbr;
+    }
+
+    if (!key) {
+        return globalLocale;
+    }
+
+    if (!isArray(key)) {
+        //short-circuit everything else
+        locale = loadLocale(key);
+        if (locale) {
+            return locale;
+        }
+        key = [key];
+    }
+
+    return chooseLocale(key);
+}
+
+function listLocales() {
+    return keys$1(locales);
+}
+
+function checkOverflow (m) {
+    var overflow;
+    var a = m._a;
+
+    if (a && getParsingFlags(m).overflow === -2) {
+        overflow =
+            a[MONTH]       < 0 || a[MONTH]       > 11  ? MONTH :
+            a[DATE]        < 1 || a[DATE]        > daysInMonth(a[YEAR], a[MONTH]) ? DATE :
+            a[HOUR]        < 0 || a[HOUR]        > 24 || (a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0)) ? HOUR :
+            a[MINUTE]      < 0 || a[MINUTE]      > 59  ? MINUTE :
+            a[SECOND]      < 0 || a[SECOND]      > 59  ? SECOND :
+            a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND :
+            -1;
+
+        if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
+            overflow = DATE;
+        }
+        if (getParsingFlags(m)._overflowWeeks && overflow === -1) {
+            overflow = WEEK;
+        }
+        if (getParsingFlags(m)._overflowWeekday && overflow === -1) {
+            overflow = WEEKDAY;
+        }
+
+        getParsingFlags(m).overflow = overflow;
+    }
+
+    return m;
+}
+
+// iso 8601 regex
+// 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
+var extendedIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
+var basicIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
+
+var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/;
+
+var isoDates = [
+    ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/],
+    ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/],
+    ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/],
+    ['GGGG-[W]WW', /\d{4}-W\d\d/, false],
+    ['YYYY-DDD', /\d{4}-\d{3}/],
+    ['YYYY-MM', /\d{4}-\d\d/, false],
+    ['YYYYYYMMDD', /[+-]\d{10}/],
+    ['YYYYMMDD', /\d{8}/],
+    // YYYYMM is NOT allowed by the standard
+    ['GGGG[W]WWE', /\d{4}W\d{3}/],
+    ['GGGG[W]WW', /\d{4}W\d{2}/, false],
+    ['YYYYDDD', /\d{7}/]
+];
+
+// iso time formats and regexes
+var isoTimes = [
+    ['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/],
+    ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/],
+    ['HH:mm:ss', /\d\d:\d\d:\d\d/],
+    ['HH:mm', /\d\d:\d\d/],
+    ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/],
+    ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/],
+    ['HHmmss', /\d\d\d\d\d\d/],
+    ['HHmm', /\d\d\d\d/],
+    ['HH', /\d\d/]
+];
+
+var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i;
+
+// date from iso format
+function configFromISO(config) {
+    var i, l,
+        string = config._i,
+        match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string),
+        allowTime, dateFormat, timeFormat, tzFormat;
+
+    if (match) {
+        getParsingFlags(config).iso = true;
+
+        for (i = 0, l = isoDates.length; i < l; i++) {
+            if (isoDates[i][1].exec(match[1])) {
+                dateFormat = isoDates[i][0];
+                allowTime = isoDates[i][2] !== false;
+                break;
+            }
+        }
+        if (dateFormat == null) {
+            config._isValid = false;
+            return;
+        }
+        if (match[3]) {
+            for (i = 0, l = isoTimes.length; i < l; i++) {
+                if (isoTimes[i][1].exec(match[3])) {
+                    // match[2] should be 'T' or space
+                    timeFormat = (match[2] || ' ') + isoTimes[i][0];
+                    break;
+                }
+            }
+            if (timeFormat == null) {
+                config._isValid = false;
+                return;
+            }
+        }
+        if (!allowTime && timeFormat != null) {
+            config._isValid = false;
+            return;
+        }
+        if (match[4]) {
+            if (tzRegex.exec(match[4])) {
+                tzFormat = 'Z';
+            } else {
+                config._isValid = false;
+                return;
+            }
+        }
+        config._f = dateFormat + (timeFormat || '') + (tzFormat || '');
+        configFromStringAndFormat(config);
+    } else {
+        config._isValid = false;
+    }
+}
+
+// date from iso format or fallback
+function configFromString(config) {
+    var matched = aspNetJsonRegex.exec(config._i);
+
+    if (matched !== null) {
+        config._d = new Date(+matched[1]);
+        return;
+    }
+
+    configFromISO(config);
+    if (config._isValid === false) {
+        delete config._isValid;
+        hooks.createFromInputFallback(config);
+    }
+}
+
+hooks.createFromInputFallback = deprecate(
+    'value provided is not in a recognized ISO format. moment construction falls back to js Date(), ' +
+    'which is not reliable across all browsers and versions. Non ISO date formats are ' +
+    'discouraged and will be removed in an upcoming major release. Please refer to ' +
+    'http://momentjs.com/guides/#/warnings/js-date/ for more info.',
+    function (config) {
+        config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
+    }
+);
+
+// Pick the first defined of two or three arguments.
+function defaults(a, b, c) {
+    if (a != null) {
+        return a;
+    }
+    if (b != null) {
+        return b;
+    }
+    return c;
+}
+
+function currentDateArray(config) {
+    // hooks is actually the exported moment object
+    var nowValue = new Date(hooks.now());
+    if (config._useUTC) {
+        return [nowValue.getUTCFullYear(), nowValue.getUTCMonth(), nowValue.getUTCDate()];
+    }
+    return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()];
+}
+
+// convert an array to a date.
+// the array should mirror the parameters below
+// note: all values past the year are optional and will default to the lowest possible value.
+// [year, month, day , hour, minute, second, millisecond]
+function configFromArray (config) {
+    var i, date, input = [], currentDate, yearToUse;
+
+    if (config._d) {
+        return;
+    }
+
+    currentDate = currentDateArray(config);
+
+    //compute day of the year from weeks and weekdays
+    if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
+        dayOfYearFromWeekInfo(config);
+    }
+
+    //if the day of the year is set, figure out what it is
+    if (config._dayOfYear) {
+        yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);
+
+        if (config._dayOfYear > daysInYear(yearToUse)) {
+            getParsingFlags(config)._overflowDayOfYear = true;
+        }
+
+        date = createUTCDate(yearToUse, 0, config._dayOfYear);
+        config._a[MONTH] = date.getUTCMonth();
+        config._a[DATE] = date.getUTCDate();
+    }
+
+    // Default to current date.
+    // * if no year, month, day of month are given, default to today
+    // * if day of month is given, default month and year
+    // * if month is given, default only year
+    // * if year is given, don't default anything
+    for (i = 0; i < 3 && config._a[i] == null; ++i) {
+        config._a[i] = input[i] = currentDate[i];
+    }
+
+    // Zero out whatever was not defaulted, including time
+    for (; i < 7; i++) {
+        config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
+    }
+
+    // Check for 24:00:00.000
+    if (config._a[HOUR] === 24 &&
+            config._a[MINUTE] === 0 &&
+            config._a[SECOND] === 0 &&
+            config._a[MILLISECOND] === 0) {
+        config._nextDay = true;
+        config._a[HOUR] = 0;
+    }
+
+    config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input);
+    // Apply timezone offset from input. The actual utcOffset can be changed
+    // with parseZone.
+    if (config._tzm != null) {
+        config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
+    }
+
+    if (config._nextDay) {
+        config._a[HOUR] = 24;
+    }
+}
+
+function dayOfYearFromWeekInfo(config) {
+    var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow;
+
+    w = config._w;
+    if (w.GG != null || w.W != null || w.E != null) {
+        dow = 1;
+        doy = 4;
+
+        // TODO: We need to take the current isoWeekYear, but that depends on
+        // how we interpret now (local, utc, fixed offset). So create
+        // a now version of current config (take local/utc/offset flags, and
+        // create now).
+        weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(createLocal(), 1, 4).year);
+        week = defaults(w.W, 1);
+        weekday = defaults(w.E, 1);
+        if (weekday < 1 || weekday > 7) {
+            weekdayOverflow = true;
+        }
+    } else {
+        dow = config._locale._week.dow;
+        doy = config._locale._week.doy;
+
+        var curWeek = weekOfYear(createLocal(), dow, doy);
+
+        weekYear = defaults(w.gg, config._a[YEAR], curWeek.year);
+
+        // Default to current week.
+        week = defaults(w.w, curWeek.week);
+
+        if (w.d != null) {
+            // weekday -- low day numbers are considered next week
+            weekday = w.d;
+            if (weekday < 0 || weekday > 6) {
+                weekdayOverflow = true;
+            }
+        } else if (w.e != null) {
+            // local weekday -- counting starts from begining of week
+            weekday = w.e + dow;
+            if (w.e < 0 || w.e > 6) {
+                weekdayOverflow = true;
+            }
+        } else {
+            // default to begining of week
+            weekday = dow;
+        }
+    }
+    if (week < 1 || week > weeksInYear(weekYear, dow, doy)) {
+        getParsingFlags(config)._overflowWeeks = true;
+    } else if (weekdayOverflow != null) {
+        getParsingFlags(config)._overflowWeekday = true;
+    } else {
+        temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy);
+        config._a[YEAR] = temp.year;
+        config._dayOfYear = temp.dayOfYear;
+    }
+}
+
+// constant that refers to the ISO standard
+hooks.ISO_8601 = function () {};
+
+// date from string and format string
+function configFromStringAndFormat(config) {
+    // TODO: Move this to another part of the creation flow to prevent circular deps
+    if (config._f === hooks.ISO_8601) {
+        configFromISO(config);
+        return;
+    }
+
+    config._a = [];
+    getParsingFlags(config).empty = true;
+
+    // This array is used to make a Date, either with `new Date` or `Date.UTC`
+    var string = '' + config._i,
+        i, parsedInput, tokens, token, skipped,
+        stringLength = string.length,
+        totalParsedInputLength = 0;
+
+    tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];
+
+    for (i = 0; i < tokens.length; i++) {
+        token = tokens[i];
+        parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];
+        // console.log('token', token, 'parsedInput', parsedInput,
+        //         'regex', getParseRegexForToken(token, config));
+        if (parsedInput) {
+            skipped = string.substr(0, string.indexOf(parsedInput));
+            if (skipped.length > 0) {
+                getParsingFlags(config).unusedInput.push(skipped);
+            }
+            string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
+            totalParsedInputLength += parsedInput.length;
+        }
+        // don't parse if it's not a known token
+        if (formatTokenFunctions[token]) {
+            if (parsedInput) {
+                getParsingFlags(config).empty = false;
+            }
+            else {
+                getParsingFlags(config).unusedTokens.push(token);
+            }
+            addTimeToArrayFromToken(token, parsedInput, config);
+        }
+        else if (config._strict && !parsedInput) {
+            getParsingFlags(config).unusedTokens.push(token);
+        }
+    }
+
+    // add remaining unparsed input length to the string
+    getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength;
+    if (string.length > 0) {
+        getParsingFlags(config).unusedInput.push(string);
+    }
+
+    // clear _12h flag if hour is <= 12
+    if (config._a[HOUR] <= 12 &&
+        getParsingFlags(config).bigHour === true &&
+        config._a[HOUR] > 0) {
+        getParsingFlags(config).bigHour = undefined;
+    }
+
+    getParsingFlags(config).parsedDateParts = config._a.slice(0);
+    getParsingFlags(config).meridiem = config._meridiem;
+    // handle meridiem
+    config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem);
+
+    configFromArray(config);
+    checkOverflow(config);
+}
+
+
+function meridiemFixWrap (locale, hour, meridiem) {
+    var isPm;
+
+    if (meridiem == null) {
+        // nothing to do
+        return hour;
+    }
+    if (locale.meridiemHour != null) {
+        return locale.meridiemHour(hour, meridiem);
+    } else if (locale.isPM != null) {
+        // Fallback
+        isPm = locale.isPM(meridiem);
+        if (isPm && hour < 12) {
+            hour += 12;
+        }
+        if (!isPm && hour === 12) {
+            hour = 0;
+        }
+        return hour;
+    } else {
+        // this is not supposed to happen
+        return hour;
+    }
+}
+
+// date from string and array of format strings
+function configFromStringAndArray(config) {
+    var tempConfig,
+        bestMoment,
+
+        scoreToBeat,
+        i,
+        currentScore;
+
+    if (config._f.length === 0) {
+        getParsingFlags(config).invalidFormat = true;
+        config._d = new Date(NaN);
+        return;
+    }
+
+    for (i = 0; i < config._f.length; i++) {
+        currentScore = 0;
+        tempConfig = copyConfig({}, config);
+        if (config._useUTC != null) {
+            tempConfig._useUTC = config._useUTC;
+        }
+        tempConfig._f = config._f[i];
+        configFromStringAndFormat(tempConfig);
+
+        if (!isValid(tempConfig)) {
+            continue;
+        }
+
+        // if there is any input that was not parsed add a penalty for that format
+        currentScore += getParsingFlags(tempConfig).charsLeftOver;
+
+        //or tokens
+        currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;
+
+        getParsingFlags(tempConfig).score = currentScore;
+
+        if (scoreToBeat == null || currentScore < scoreToBeat) {
+            scoreToBeat = currentScore;
+            bestMoment = tempConfig;
+        }
+    }
+
+    extend(config, bestMoment || tempConfig);
+}
+
+function configFromObject(config) {
+    if (config._d) {
+        return;
+    }
+
+    var i = normalizeObjectUnits(config._i);
+    config._a = map([i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond], function (obj) {
+        return obj && parseInt(obj, 10);
+    });
+
+    configFromArray(config);
+}
+
+function createFromConfig (config) {
+    var res = new Moment(checkOverflow(prepareConfig(config)));
+    if (res._nextDay) {
+        // Adding is smart enough around DST
+        res.add(1, 'd');
+        res._nextDay = undefined;
+    }
+
+    return res;
+}
+
+function prepareConfig (config) {
+    var input = config._i,
+        format = config._f;
+
+    config._locale = config._locale || getLocale(config._l);
+
+    if (input === null || (format === undefined && input === '')) {
+        return createInvalid({nullInput: true});
+    }
+
+    if (typeof input === 'string') {
+        config._i = input = config._locale.preparse(input);
+    }
+
+    if (isMoment(input)) {
+        return new Moment(checkOverflow(input));
+    } else if (isDate(input)) {
+        config._d = input;
+    } else if (isArray(format)) {
+        configFromStringAndArray(config);
+    } else if (format) {
+        configFromStringAndFormat(config);
+    }  else {
+        configFromInput(config);
+    }
+
+    if (!isValid(config)) {
+        config._d = null;
+    }
+
+    return config;
+}
+
+function configFromInput(config) {
+    var input = config._i;
+    if (input === undefined) {
+        config._d = new Date(hooks.now());
+    } else if (isDate(input)) {
+        config._d = new Date(input.valueOf());
+    } else if (typeof input === 'string') {
+        configFromString(config);
+    } else if (isArray(input)) {
+        config._a = map(input.slice(0), function (obj) {
+            return parseInt(obj, 10);
+        });
+        configFromArray(config);
+    } else if (typeof(input) === 'object') {
+        configFromObject(config);
+    } else if (isNumber(input)) {
+        // from milliseconds
+        config._d = new Date(input);
+    } else {
+        hooks.createFromInputFallback(config);
+    }
+}
+
+function createLocalOrUTC (input, format, locale, strict, isUTC) {
+    var c = {};
+
+    if (locale === true || locale === false) {
+        strict = locale;
+        locale = undefined;
+    }
+
+    if ((isObject(input) && isObjectEmpty(input)) ||
+            (isArray(input) && input.length === 0)) {
+        input = undefined;
+    }
+    // object construction must be done this way.
+    // https://github.com/moment/moment/issues/1423
+    c._isAMomentObject = true;
+    c._useUTC = c._isUTC = isUTC;
+    c._l = locale;
+    c._i = input;
+    c._f = format;
+    c._strict = strict;
+
+    return createFromConfig(c);
+}
+
+function createLocal (input, format, locale, strict) {
+    return createLocalOrUTC(input, format, locale, strict, false);
+}
+
+var prototypeMin = deprecate(
+    'moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/',
+    function () {
+        var other = createLocal.apply(null, arguments);
+        if (this.isValid() && other.isValid()) {
+            return other < this ? this : other;
+        } else {
+            return createInvalid();
+        }
+    }
+);
+
+var prototypeMax = deprecate(
+    'moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/',
+    function () {
+        var other = createLocal.apply(null, arguments);
+        if (this.isValid() && other.isValid()) {
+            return other > this ? this : other;
+        } else {
+            return createInvalid();
+        }
+    }
+);
+
+// Pick a moment m from moments so that m[fn](other) is true for all
+// other. This relies on the function fn to be transitive.
+//
+// moments should either be an array of moment objects or an array, whose
+// first element is an array of moment objects.
+function pickBy(fn, moments) {
+    var res, i;
+    if (moments.length === 1 && isArray(moments[0])) {
+        moments = moments[0];
+    }
+    if (!moments.length) {
+        return createLocal();
+    }
+    res = moments[0];
+    for (i = 1; i < moments.length; ++i) {
+        if (!moments[i].isValid() || moments[i][fn](res)) {
+            res = moments[i];
+        }
+    }
+    return res;
+}
+
+// TODO: Use [].sort instead?
+function min () {
+    var args = [].slice.call(arguments, 0);
+
+    return pickBy('isBefore', args);
+}
+
+function max () {
+    var args = [].slice.call(arguments, 0);
+
+    return pickBy('isAfter', args);
+}
+
+var now = function () {
+    return Date.now ? Date.now() : +(new Date());
+};
+
+function Duration (duration) {
+    var normalizedInput = normalizeObjectUnits(duration),
+        years = normalizedInput.year || 0,
+        quarters = normalizedInput.quarter || 0,
+        months = normalizedInput.month || 0,
+        weeks = normalizedInput.week || 0,
+        days = normalizedInput.day || 0,
+        hours = normalizedInput.hour || 0,
+        minutes = normalizedInput.minute || 0,
+        seconds = normalizedInput.second || 0,
+        milliseconds = normalizedInput.millisecond || 0;
+
+    // representation for dateAddRemove
+    this._milliseconds = +milliseconds +
+        seconds * 1e3 + // 1000
+        minutes * 6e4 + // 1000 * 60
+        hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
+    // Because of dateAddRemove treats 24 hours as different from a
+    // day when working around DST, we need to store them separately
+    this._days = +days +
+        weeks * 7;
+    // It is impossible translate months into days without knowing
+    // which months you are are talking about, so we have to store
+    // it separately.
+    this._months = +months +
+        quarters * 3 +
+        years * 12;
+
+    this._data = {};
+
+    this._locale = getLocale();
+
+    this._bubble();
+}
+
+function isDuration (obj) {
+    return obj instanceof Duration;
+}
+
+function absRound (number) {
+    if (number < 0) {
+        return Math.round(-1 * number) * -1;
+    } else {
+        return Math.round(number);
+    }
+}
+
+// FORMATTING
+
+function offset (token, separator) {
+    addFormatToken(token, 0, 0, function () {
+        var offset = this.utcOffset();
+        var sign = '+';
+        if (offset < 0) {
+            offset = -offset;
+            sign = '-';
+        }
+        return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~(offset) % 60, 2);
+    });
+}
+
+offset('Z', ':');
+offset('ZZ', '');
+
+// PARSING
+
+addRegexToken('Z',  matchShortOffset);
+addRegexToken('ZZ', matchShortOffset);
+addParseToken(['Z', 'ZZ'], function (input, array, config) {
+    config._useUTC = true;
+    config._tzm = offsetFromString(matchShortOffset, input);
+});
+
+// HELPERS
+
+// timezone chunker
+// '+10:00' > ['10',  '00']
+// '-1530'  > ['-15', '30']
+var chunkOffset = /([\+\-]|\d\d)/gi;
+
+function offsetFromString(matcher, string) {
+    var matches = (string || '').match(matcher);
+
+    if (matches === null) {
+        return null;
+    }
+
+    var chunk   = matches[matches.length - 1] || [];
+    var parts   = (chunk + '').match(chunkOffset) || ['-', 0, 0];
+    var minutes = +(parts[1] * 60) + toInt(parts[2]);
+
+    return minutes === 0 ?
+      0 :
+      parts[0] === '+' ? minutes : -minutes;
+}
+
+// Return a moment from input, that is local/utc/zone equivalent to model.
+function cloneWithOffset(input, model) {
+    var res, diff;
+    if (model._isUTC) {
+        res = model.clone();
+        diff = (isMoment(input) || isDate(input) ? input.valueOf() : createLocal(input).valueOf()) - res.valueOf();
+        // Use low-level api, because this fn is low-level api.
+        res._d.setTime(res._d.valueOf() + diff);
+        hooks.updateOffset(res, false);
+        return res;
+    } else {
+        return createLocal(input).local();
+    }
+}
+
+function getDateOffset (m) {
+    // On Firefox.24 Date#getTimezoneOffset returns a floating point.
+    // https://github.com/moment/moment/pull/1871
+    return -Math.round(m._d.getTimezoneOffset() / 15) * 15;
+}
+
+// HOOKS
+
+// This function will be called whenever a moment is mutated.
+// It is intended to keep the offset in sync with the timezone.
+hooks.updateOffset = function () {};
+
+// MOMENTS
+
+// keepLocalTime = true means only change the timezone, without
+// affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
+// 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
+// +0200, so we adjust the time as needed, to be valid.
+//
+// Keeping the time actually adds/subtracts (one hour)
+// from the actual represented time. That is why we call updateOffset
+// a second time. In case it wants us to change the offset again
+// _changeInProgress == true case, then we have to adjust, because
+// there is no such time in the given timezone.
+function getSetOffset (input, keepLocalTime) {
+    var offset = this._offset || 0,
+        localAdjust;
+    if (!this.isValid()) {
+        return input != null ? this : NaN;
+    }
+    if (input != null) {
+        if (typeof input === 'string') {
+            input = offsetFromString(matchShortOffset, input);
+            if (input === null) {
+                return this;
+            }
+        } else if (Math.abs(input) < 16) {
+            input = input * 60;
+        }
+        if (!this._isUTC && keepLocalTime) {
+            localAdjust = getDateOffset(this);
+        }
+        this._offset = input;
+        this._isUTC = true;
+        if (localAdjust != null) {
+            this.add(localAdjust, 'm');
+        }
+        if (offset !== input) {
+            if (!keepLocalTime || this._changeInProgress) {
+                addSubtract(this, createDuration(input - offset, 'm'), 1, false);
+            } else if (!this._changeInProgress) {
+                this._changeInProgress = true;
+                hooks.updateOffset(this, true);
+                this._changeInProgress = null;
+            }
+        }
+        return this;
+    } else {
+        return this._isUTC ? offset : getDateOffset(this);
+    }
+}
+
+function getSetZone (input, keepLocalTime) {
+    if (input != null) {
+        if (typeof input !== 'string') {
+            input = -input;
+        }
+
+        this.utcOffset(input, keepLocalTime);
+
+        return this;
+    } else {
+        return -this.utcOffset();
+    }
+}
+
+function setOffsetToUTC (keepLocalTime) {
+    return this.utcOffset(0, keepLocalTime);
+}
+
+function setOffsetToLocal (keepLocalTime) {
+    if (this._isUTC) {
+        this.utcOffset(0, keepLocalTime);
+        this._isUTC = false;
+
+        if (keepLocalTime) {
+            this.subtract(getDateOffset(this), 'm');
+        }
+    }
+    return this;
+}
+
+function setOffsetToParsedOffset () {
+    if (this._tzm != null) {
+        this.utcOffset(this._tzm);
+    } else if (typeof this._i === 'string') {
+        var tZone = offsetFromString(matchOffset, this._i);
+        if (tZone != null) {
+            this.utcOffset(tZone);
+        }
+        else {
+            this.utcOffset(0, true);
+        }
+    }
+    return this;
+}
+
+function hasAlignedHourOffset (input) {
+    if (!this.isValid()) {
+        return false;
+    }
+    input = input ? createLocal(input).utcOffset() : 0;
+
+    return (this.utcOffset() - input) % 60 === 0;
+}
+
+function isDaylightSavingTime () {
+    return (
+        this.utcOffset() > this.clone().month(0).utcOffset() ||
+        this.utcOffset() > this.clone().month(5).utcOffset()
+    );
+}
+
+function isDaylightSavingTimeShifted () {
+    if (!isUndefined(this._isDSTShifted)) {
+        return this._isDSTShifted;
+    }
+
+    var c = {};
+
+    copyConfig(c, this);
+    c = prepareConfig(c);
+
+    if (c._a) {
+        var other = c._isUTC ? createUTC(c._a) : createLocal(c._a);
+        this._isDSTShifted = this.isValid() &&
+            compareArrays(c._a, other.toArray()) > 0;
+    } else {
+        this._isDSTShifted = false;
+    }
+
+    return this._isDSTShifted;
+}
+
+function isLocal () {
+    return this.isValid() ? !this._isUTC : false;
+}
+
+function isUtcOffset () {
+    return this.isValid() ? this._isUTC : false;
+}
+
+function isUtc () {
+    return this.isValid() ? this._isUTC && this._offset === 0 : false;
+}
+
+// ASP.NET json date format regex
+var aspNetRegex = /^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/;
+
+// from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
+// somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
+// and further modified to allow for strings containing both week and day
+var isoRegex = /^(-)?P(?:(-?[0-9,.]*)Y)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)W)?(?:(-?[0-9,.]*)D)?(?:T(?:(-?[0-9,.]*)H)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)S)?)?$/;
+
+function createDuration (input, key) {
+    var duration = input,
+        // matching against regexp is expensive, do it on demand
+        match = null,
+        sign,
+        ret,
+        diffRes;
+
+    if (isDuration(input)) {
+        duration = {
+            ms : input._milliseconds,
+            d  : input._days,
+            M  : input._months
+        };
+    } else if (isNumber(input)) {
+        duration = {};
+        if (key) {
+            duration[key] = input;
+        } else {
+            duration.milliseconds = input;
+        }
+    } else if (!!(match = aspNetRegex.exec(input))) {
+        sign = (match[1] === '-') ? -1 : 1;
+        duration = {
+            y  : 0,
+            d  : toInt(match[DATE])                         * sign,
+            h  : toInt(match[HOUR])                         * sign,
+            m  : toInt(match[MINUTE])                       * sign,
+            s  : toInt(match[SECOND])                       * sign,
+            ms : toInt(absRound(match[MILLISECOND] * 1000)) * sign // the millisecond decimal point is included in the match
+        };
+    } else if (!!(match = isoRegex.exec(input))) {
+        sign = (match[1] === '-') ? -1 : 1;
+        duration = {
+            y : parseIso(match[2], sign),
+            M : parseIso(match[3], sign),
+            w : parseIso(match[4], sign),
+            d : parseIso(match[5], sign),
+            h : parseIso(match[6], sign),
+            m : parseIso(match[7], sign),
+            s : parseIso(match[8], sign)
+        };
+    } else if (duration == null) {// checks for null or undefined
+        duration = {};
+    } else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) {
+        diffRes = momentsDifference(createLocal(duration.from), createLocal(duration.to));
+
+        duration = {};
+        duration.ms = diffRes.milliseconds;
+        duration.M = diffRes.months;
+    }
+
+    ret = new Duration(duration);
+
+    if (isDuration(input) && hasOwnProp(input, '_locale')) {
+        ret._locale = input._locale;
+    }
+
+    return ret;
+}
+
+createDuration.fn = Duration.prototype;
+
+function parseIso (inp, sign) {
+    // We'd normally use ~~inp for this, but unfortunately it also
+    // converts floats to ints.
+    // inp may be undefined, so careful calling replace on it.
+    var res = inp && parseFloat(inp.replace(',', '.'));
+    // apply sign while we're at it
+    return (isNaN(res) ? 0 : res) * sign;
+}
+
+function positiveMomentsDifference(base, other) {
+    var res = {milliseconds: 0, months: 0};
+
+    res.months = other.month() - base.month() +
+        (other.year() - base.year()) * 12;
+    if (base.clone().add(res.months, 'M').isAfter(other)) {
+        --res.months;
+    }
+
+    res.milliseconds = +other - +(base.clone().add(res.months, 'M'));
+
+    return res;
+}
+
+function momentsDifference(base, other) {
+    var res;
+    if (!(base.isValid() && other.isValid())) {
+        return {milliseconds: 0, months: 0};
+    }
+
+    other = cloneWithOffset(other, base);
+    if (base.isBefore(other)) {
+        res = positiveMomentsDifference(base, other);
+    } else {
+        res = positiveMomentsDifference(other, base);
+        res.milliseconds = -res.milliseconds;
+        res.months = -res.months;
+    }
+
+    return res;
+}
+
+// TODO: remove 'name' arg after deprecation is removed
+function createAdder(direction, name) {
+    return function (val, period) {
+        var dur, tmp;
+        //invert the arguments, but complain about it
+        if (period !== null && !isNaN(+period)) {
+            deprecateSimple(name, 'moment().' + name  + '(period, number) is deprecated. Please use moment().' + name + '(number, period). ' +
+            'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.');
+            tmp = val; val = period; period = tmp;
+        }
+
+        val = typeof val === 'string' ? +val : val;
+        dur = createDuration(val, period);
+        addSubtract(this, dur, direction);
+        return this;
+    };
+}
+
+function addSubtract (mom, duration, isAdding, updateOffset) {
+    var milliseconds = duration._milliseconds,
+        days = absRound(duration._days),
+        months = absRound(duration._months);
+
+    if (!mom.isValid()) {
+        // No op
+        return;
+    }
+
+    updateOffset = updateOffset == null ? true : updateOffset;
+
+    if (milliseconds) {
+        mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding);
+    }
+    if (days) {
+        set$1(mom, 'Date', get(mom, 'Date') + days * isAdding);
+    }
+    if (months) {
+        setMonth(mom, get(mom, 'Month') + months * isAdding);
+    }
+    if (updateOffset) {
+        hooks.updateOffset(mom, days || months);
+    }
+}
+
+var add      = createAdder(1, 'add');
+var subtract = createAdder(-1, 'subtract');
+
+function getCalendarFormat(myMoment, now) {
+    var diff = myMoment.diff(now, 'days', true);
+    return diff < -6 ? 'sameElse' :
+            diff < -1 ? 'lastWeek' :
+            diff < 0 ? 'lastDay' :
+            diff < 1 ? 'sameDay' :
+            diff < 2 ? 'nextDay' :
+            diff < 7 ? 'nextWeek' : 'sameElse';
+}
+
+function calendar$1 (time, formats) {
+    // We want to compare the start of today, vs this.
+    // Getting start-of-today depends on whether we're local/utc/offset or not.
+    var now = time || createLocal(),
+        sod = cloneWithOffset(now, this).startOf('day'),
+        format = hooks.calendarFormat(this, sod) || 'sameElse';
+
+    var output = formats && (isFunction(formats[format]) ? formats[format].call(this, now) : formats[format]);
+
+    return this.format(output || this.localeData().calendar(format, this, createLocal(now)));
+}
+
+function clone () {
+    return new Moment(this);
+}
+
+function isAfter (input, units) {
+    var localInput = isMoment(input) ? input : createLocal(input);
+    if (!(this.isValid() && localInput.isValid())) {
+        return false;
+    }
+    units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
+    if (units === 'millisecond') {
+        return this.valueOf() > localInput.valueOf();
+    } else {
+        return localInput.valueOf() < this.clone().startOf(units).valueOf();
+    }
+}
+
+function isBefore (input, units) {
+    var localInput = isMoment(input) ? input : createLocal(input);
+    if (!(this.isValid() && localInput.isValid())) {
+        return false;
+    }
+    units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
+    if (units === 'millisecond') {
+        return this.valueOf() < localInput.valueOf();
+    } else {
+        return this.clone().endOf(units).valueOf() < localInput.valueOf();
+    }
+}
+
+function isBetween (from, to, units, inclusivity) {
+    inclusivity = inclusivity || '()';
+    return (inclusivity[0] === '(' ? this.isAfter(from, units) : !this.isBefore(from, units)) &&
+        (inclusivity[1] === ')' ? this.isBefore(to, units) : !this.isAfter(to, units));
+}
+
+function isSame (input, units) {
+    var localInput = isMoment(input) ? input : createLocal(input),
+        inputMs;
+    if (!(this.isValid() && localInput.isValid())) {
+        return false;
+    }
+    units = normalizeUnits(units || 'millisecond');
+    if (units === 'millisecond') {
+        return this.valueOf() === localInput.valueOf();
+    } else {
+        inputMs = localInput.valueOf();
+        return this.clone().startOf(units).valueOf() <= inputMs && inputMs <= this.clone().endOf(units).valueOf();
+    }
+}
+
+function isSameOrAfter (input, units) {
+    return this.isSame(input, units) || this.isAfter(input,units);
+}
+
+function isSameOrBefore (input, units) {
+    return this.isSame(input, units) || this.isBefore(input,units);
+}
+
+function diff (input, units, asFloat) {
+    var that,
+        zoneDelta,
+        delta, output;
+
+    if (!this.isValid()) {
+        return NaN;
+    }
+
+    that = cloneWithOffset(input, this);
+
+    if (!that.isValid()) {
+        return NaN;
+    }
+
+    zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4;
+
+    units = normalizeUnits(units);
+
+    if (units === 'year' || units === 'month' || units === 'quarter') {
+        output = monthDiff(this, that);
+        if (units === 'quarter') {
+            output = output / 3;
+        } else if (units === 'year') {
+            output = output / 12;
+        }
+    } else {
+        delta = this - that;
+        output = units === 'second' ? delta / 1e3 : // 1000
+            units === 'minute' ? delta / 6e4 : // 1000 * 60
+            units === 'hour' ? delta / 36e5 : // 1000 * 60 * 60
+            units === 'day' ? (delta - zoneDelta) / 864e5 : // 1000 * 60 * 60 * 24, negate dst
+            units === 'week' ? (delta - zoneDelta) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst
+            delta;
+    }
+    return asFloat ? output : absFloor(output);
+}
+
+function monthDiff (a, b) {
+    // difference in months
+    var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()),
+        // b is in (anchor - 1 month, anchor + 1 month)
+        anchor = a.clone().add(wholeMonthDiff, 'months'),
+        anchor2, adjust;
+
+    if (b - anchor < 0) {
+        anchor2 = a.clone().add(wholeMonthDiff - 1, 'months');
+        // linear across the month
+        adjust = (b - anchor) / (anchor - anchor2);
+    } else {
+        anchor2 = a.clone().add(wholeMonthDiff + 1, 'months');
+        // linear across the month
+        adjust = (b - anchor) / (anchor2 - anchor);
+    }
+
+    //check for negative zero, return zero if negative zero
+    return -(wholeMonthDiff + adjust) || 0;
+}
+
+hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ';
+hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]';
+
+function toString () {
+    return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
+}
+
+function toISOString () {
+    var m = this.clone().utc();
+    if (0 < m.year() && m.year() <= 9999) {
+        if (isFunction(Date.prototype.toISOString)) {
+            // native implementation is ~50x faster, use it when we can
+            return this.toDate().toISOString();
+        } else {
+            return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
+        }
+    } else {
+        return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
+    }
+}
+
+/**
+ * Return a human readable representation of a moment that can
+ * also be evaluated to get a new moment which is the same
+ *
+ * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects
+ */
+function inspect () {
+    if (!this.isValid()) {
+        return 'moment.invalid(/* ' + this._i + ' */)';
+    }
+    var func = 'moment';
+    var zone = '';
+    if (!this.isLocal()) {
+        func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone';
+        zone = 'Z';
+    }
+    var prefix = '[' + func + '("]';
+    var year = (0 < this.year() && this.year() <= 9999) ? 'YYYY' : 'YYYYYY';
+    var datetime = '-MM-DD[T]HH:mm:ss.SSS';
+    var suffix = zone + '[")]';
+
+    return this.format(prefix + year + datetime + suffix);
+}
+
+function format (inputString) {
+    if (!inputString) {
+        inputString = this.isUtc() ? hooks.defaultFormatUtc : hooks.defaultFormat;
+    }
+    var output = formatMoment(this, inputString);
+    return this.localeData().postformat(output);
+}
+
+function from (time, withoutSuffix) {
+    if (this.isValid() &&
+            ((isMoment(time) && time.isValid()) ||
+             createLocal(time).isValid())) {
+        return createDuration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix);
+    } else {
+        return this.localeData().invalidDate();
+    }
+}
+
+function fromNow (withoutSuffix) {
+    return this.from(createLocal(), withoutSuffix);
+}
+
+function to (time, withoutSuffix) {
+    if (this.isValid() &&
+            ((isMoment(time) && time.isValid()) ||
+             createLocal(time).isValid())) {
+        return createDuration({from: this, to: time}).locale(this.locale()).humanize(!withoutSuffix);
+    } else {
+        return this.localeData().invalidDate();
+    }
+}
+
+function toNow (withoutSuffix) {
+    return this.to(createLocal(), withoutSuffix);
+}
+
+// If passed a locale key, it will set the locale for this
+// instance.  Otherwise, it will return the locale configuration
+// variables for this instance.
+function locale (key) {
+    var newLocaleData;
+
+    if (key === undefined) {
+        return this._locale._abbr;
+    } else {
+        newLocaleData = getLocale(key);
+        if (newLocaleData != null) {
+            this._locale = newLocaleData;
+        }
+        return this;
+    }
+}
+
+var lang = deprecate(
+    'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.',
+    function (key) {
+        if (key === undefined) {
+            return this.localeData();
+        } else {
+            return this.locale(key);
+        }
+    }
+);
+
+function localeData () {
+    return this._locale;
+}
+
+function startOf (units) {
+    units = normalizeUnits(units);
+    // the following switch intentionally omits break keywords
+    // to utilize falling through the cases.
+    switch (units) {
+        case 'year':
+            this.month(0);
+            /* falls through */
+        case 'quarter':
+        case 'month':
+            this.date(1);
+            /* falls through */
+        case 'week':
+        case 'isoWeek':
+        case 'day':
+        case 'date':
+            this.hours(0);
+            /* falls through */
+        case 'hour':
+            this.minutes(0);
+            /* falls through */
+        case 'minute':
+            this.seconds(0);
+            /* falls through */
+        case 'second':
+            this.milliseconds(0);
+    }
+
+    // weeks are a special case
+    if (units === 'week') {
+        this.weekday(0);
+    }
+    if (units === 'isoWeek') {
+        this.isoWeekday(1);
+    }
+
+    // quarters are also special
+    if (units === 'quarter') {
+        this.month(Math.floor(this.month() / 3) * 3);
+    }
+
+    return this;
+}
+
+function endOf (units) {
+    units = normalizeUnits(units);
+    if (units === undefined || units === 'millisecond') {
+        return this;
+    }
+
+    // 'date' is an alias for 'day', so it should be considered as such.
+    if (units === 'date') {
+        units = 'day';
+    }
+
+    return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms');
+}
+
+function valueOf () {
+    return this._d.valueOf() - ((this._offset || 0) * 60000);
+}
+
+function unix () {
+    return Math.floor(this.valueOf() / 1000);
+}
+
+function toDate () {
+    return new Date(this.valueOf());
+}
+
+function toArray () {
+    var m = this;
+    return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()];
+}
+
+function toObject () {
+    var m = this;
+    return {
+        years: m.year(),
+        months: m.month(),
+        date: m.date(),
+        hours: m.hours(),
+        minutes: m.minutes(),
+        seconds: m.seconds(),
+        milliseconds: m.milliseconds()
+    };
+}
+
+function toJSON () {
+    // new Date(NaN).toJSON() === null
+    return this.isValid() ? this.toISOString() : null;
+}
+
+function isValid$1 () {
+    return isValid(this);
+}
+
+function parsingFlags () {
+    return extend({}, getParsingFlags(this));
+}
+
+function invalidAt () {
+    return getParsingFlags(this).overflow;
+}
+
+function creationData() {
+    return {
+        input: this._i,
+        format: this._f,
+        locale: this._locale,
+        isUTC: this._isUTC,
+        strict: this._strict
+    };
+}
+
+// FORMATTING
+
+addFormatToken(0, ['gg', 2], 0, function () {
+    return this.weekYear() % 100;
+});
+
+addFormatToken(0, ['GG', 2], 0, function () {
+    return this.isoWeekYear() % 100;
+});
+
+function addWeekYearFormatToken (token, getter) {
+    addFormatToken(0, [token, token.length], 0, getter);
+}
+
+addWeekYearFormatToken('gggg',     'weekYear');
+addWeekYearFormatToken('ggggg',    'weekYear');
+addWeekYearFormatToken('GGGG',  'isoWeekYear');
+addWeekYearFormatToken('GGGGG', 'isoWeekYear');
+
+// ALIASES
+
+addUnitAlias('weekYear', 'gg');
+addUnitAlias('isoWeekYear', 'GG');
+
+// PRIORITY
+
+addUnitPriority('weekYear', 1);
+addUnitPriority('isoWeekYear', 1);
+
+
+// PARSING
+
+addRegexToken('G',      matchSigned);
+addRegexToken('g',      matchSigned);
+addRegexToken('GG',     match1to2, match2);
+addRegexToken('gg',     match1to2, match2);
+addRegexToken('GGGG',   match1to4, match4);
+addRegexToken('gggg',   match1to4, match4);
+addRegexToken('GGGGG',  match1to6, match6);
+addRegexToken('ggggg',  match1to6, match6);
+
+addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (input, week, config, token) {
+    week[token.substr(0, 2)] = toInt(input);
+});
+
+addWeekParseToken(['gg', 'GG'], function (input, week, config, token) {
+    week[token] = hooks.parseTwoDigitYear(input);
+});
+
+// MOMENTS
+
+function getSetWeekYear (input) {
+    return getSetWeekYearHelper.call(this,
+            input,
+            this.week(),
+            this.weekday(),
+            this.localeData()._week.dow,
+            this.localeData()._week.doy);
+}
+
+function getSetISOWeekYear (input) {
+    return getSetWeekYearHelper.call(this,
+            input, this.isoWeek(), this.isoWeekday(), 1, 4);
+}
+
+function getISOWeeksInYear () {
+    return weeksInYear(this.year(), 1, 4);
+}
+
+function getWeeksInYear () {
+    var weekInfo = this.localeData()._week;
+    return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
+}
+
+function getSetWeekYearHelper(input, week, weekday, dow, doy) {
+    var weeksTarget;
+    if (input == null) {
+        return weekOfYear(this, dow, doy).year;
+    } else {
+        weeksTarget = weeksInYear(input, dow, doy);
+        if (week > weeksTarget) {
+            week = weeksTarget;
+        }
+        return setWeekAll.call(this, input, week, weekday, dow, doy);
+    }
+}
+
+function setWeekAll(weekYear, week, weekday, dow, doy) {
+    var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy),
+        date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear);
+
+    this.year(date.getUTCFullYear());
+    this.month(date.getUTCMonth());
+    this.date(date.getUTCDate());
+    return this;
+}
+
+// FORMATTING
+
+addFormatToken('Q', 0, 'Qo', 'quarter');
+
+// ALIASES
+
+addUnitAlias('quarter', 'Q');
+
+// PRIORITY
+
+addUnitPriority('quarter', 7);
+
+// PARSING
+
+addRegexToken('Q', match1);
+addParseToken('Q', function (input, array) {
+    array[MONTH] = (toInt(input) - 1) * 3;
+});
+
+// MOMENTS
+
+function getSetQuarter (input) {
+    return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);
+}
+
+// FORMATTING
+
+addFormatToken('D', ['DD', 2], 'Do', 'date');
+
+// ALIASES
+
+addUnitAlias('date', 'D');
+
+// PRIOROITY
+addUnitPriority('date', 9);
+
+// PARSING
+
+addRegexToken('D',  match1to2);
+addRegexToken('DD', match1to2, match2);
+addRegexToken('Do', function (isStrict, locale) {
+    return isStrict ? locale._ordinalParse : locale._ordinalParseLenient;
+});
+
+addParseToken(['D', 'DD'], DATE);
+addParseToken('Do', function (input, array) {
+    array[DATE] = toInt(input.match(match1to2)[0], 10);
+});
+
+// MOMENTS
+
+var getSetDayOfMonth = makeGetSet('Date', true);
+
+// FORMATTING
+
+addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear');
+
+// ALIASES
+
+addUnitAlias('dayOfYear', 'DDD');
+
+// PRIORITY
+addUnitPriority('dayOfYear', 4);
+
+// PARSING
+
+addRegexToken('DDD',  match1to3);
+addRegexToken('DDDD', match3);
+addParseToken(['DDD', 'DDDD'], function (input, array, config) {
+    config._dayOfYear = toInt(input);
+});
+
+// HELPERS
+
+// MOMENTS
+
+function getSetDayOfYear (input) {
+    var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1;
+    return input == null ? dayOfYear : this.add((input - dayOfYear), 'd');
+}
+
+// FORMATTING
+
+addFormatToken('m', ['mm', 2], 0, 'minute');
+
+// ALIASES
+
+addUnitAlias('minute', 'm');
+
+// PRIORITY
+
+addUnitPriority('minute', 14);
+
+// PARSING
+
+addRegexToken('m',  match1to2);
+addRegexToken('mm', match1to2, match2);
+addParseToken(['m', 'mm'], MINUTE);
+
+// MOMENTS
+
+var getSetMinute = makeGetSet('Minutes', false);
+
+// FORMATTING
+
+addFormatToken('s', ['ss', 2], 0, 'second');
+
+// ALIASES
+
+addUnitAlias('second', 's');
+
+// PRIORITY
+
+addUnitPriority('second', 15);
+
+// PARSING
+
+addRegexToken('s',  match1to2);
+addRegexToken('ss', match1to2, match2);
+addParseToken(['s', 'ss'], SECOND);
+
+// MOMENTS
+
+var getSetSecond = makeGetSet('Seconds', false);
+
+// FORMATTING
+
+addFormatToken('S', 0, 0, function () {
+    return ~~(this.millisecond() / 100);
+});
+
+addFormatToken(0, ['SS', 2], 0, function () {
+    return ~~(this.millisecond() / 10);
+});
+
+addFormatToken(0, ['SSS', 3], 0, 'millisecond');
+addFormatToken(0, ['SSSS', 4], 0, function () {
+    return this.millisecond() * 10;
+});
+addFormatToken(0, ['SSSSS', 5], 0, function () {
+    return this.millisecond() * 100;
+});
+addFormatToken(0, ['SSSSSS', 6], 0, function () {
+    return this.millisecond() * 1000;
+});
+addFormatToken(0, ['SSSSSSS', 7], 0, function () {
+    return this.millisecond() * 10000;
+});
+addFormatToken(0, ['SSSSSSSS', 8], 0, function () {
+    return this.millisecond() * 100000;
+});
+addFormatToken(0, ['SSSSSSSSS', 9], 0, function () {
+    return this.millisecond() * 1000000;
+});
+
+
+// ALIASES
+
+addUnitAlias('millisecond', 'ms');
+
+// PRIORITY
+
+addUnitPriority('millisecond', 16);
+
+// PARSING
+
+addRegexToken('S',    match1to3, match1);
+addRegexToken('SS',   match1to3, match2);
+addRegexToken('SSS',  match1to3, match3);
+
+var token;
+for (token = 'SSSS'; token.length <= 9; token += 'S') {
+    addRegexToken(token, matchUnsigned);
+}
+
+function parseMs(input, array) {
+    array[MILLISECOND] = toInt(('0.' + input) * 1000);
+}
+
+for (token = 'S'; token.length <= 9; token += 'S') {
+    addParseToken(token, parseMs);
+}
+// MOMENTS
+
+var getSetMillisecond = makeGetSet('Milliseconds', false);
+
+// FORMATTING
+
+addFormatToken('z',  0, 0, 'zoneAbbr');
+addFormatToken('zz', 0, 0, 'zoneName');
+
+// MOMENTS
+
+function getZoneAbbr () {
+    return this._isUTC ? 'UTC' : '';
+}
+
+function getZoneName () {
+    return this._isUTC ? 'Coordinated Universal Time' : '';
+}
+
+var proto = Moment.prototype;
+
+proto.add               = add;
+proto.calendar          = calendar$1;
+proto.clone             = clone;
+proto.diff              = diff;
+proto.endOf             = endOf;
+proto.format            = format;
+proto.from              = from;
+proto.fromNow           = fromNow;
+proto.to                = to;
+proto.toNow             = toNow;
+proto.get               = stringGet;
+proto.invalidAt         = invalidAt;
+proto.isAfter           = isAfter;
+proto.isBefore          = isBefore;
+proto.isBetween         = isBetween;
+proto.isSame            = isSame;
+proto.isSameOrAfter     = isSameOrAfter;
+proto.isSameOrBefore    = isSameOrBefore;
+proto.isValid           = isValid$1;
+proto.lang              = lang;
+proto.locale            = locale;
+proto.localeData        = localeData;
+proto.max               = prototypeMax;
+proto.min               = prototypeMin;
+proto.parsingFlags      = parsingFlags;
+proto.set               = stringSet;
+proto.startOf           = startOf;
+proto.subtract          = subtract;
+proto.toArray           = toArray;
+proto.toObject          = toObject;
+proto.toDate            = toDate;
+proto.toISOString       = toISOString;
+proto.inspect           = inspect;
+proto.toJSON            = toJSON;
+proto.toString          = toString;
+proto.unix              = unix;
+proto.valueOf           = valueOf;
+proto.creationData      = creationData;
+
+// Year
+proto.year       = getSetYear;
+proto.isLeapYear = getIsLeapYear;
+
+// Week Year
+proto.weekYear    = getSetWeekYear;
+proto.isoWeekYear = getSetISOWeekYear;
+
+// Quarter
+proto.quarter = proto.quarters = getSetQuarter;
+
+// Month
+proto.month       = getSetMonth;
+proto.daysInMonth = getDaysInMonth;
+
+// Week
+proto.week           = proto.weeks        = getSetWeek;
+proto.isoWeek        = proto.isoWeeks     = getSetISOWeek;
+proto.weeksInYear    = getWeeksInYear;
+proto.isoWeeksInYear = getISOWeeksInYear;
+
+// Day
+proto.date       = getSetDayOfMonth;
+proto.day        = proto.days             = getSetDayOfWeek;
+proto.weekday    = getSetLocaleDayOfWeek;
+proto.isoWeekday = getSetISODayOfWeek;
+proto.dayOfYear  = getSetDayOfYear;
+
+// Hour
+proto.hour = proto.hours = getSetHour;
+
+// Minute
+proto.minute = proto.minutes = getSetMinute;
+
+// Second
+proto.second = proto.seconds = getSetSecond;
+
+// Millisecond
+proto.millisecond = proto.milliseconds = getSetMillisecond;
+
+// Offset
+proto.utcOffset            = getSetOffset;
+proto.utc                  = setOffsetToUTC;
+proto.local                = setOffsetToLocal;
+proto.parseZone            = setOffsetToParsedOffset;
+proto.hasAlignedHourOffset = hasAlignedHourOffset;
+proto.isDST                = isDaylightSavingTime;
+proto.isLocal              = isLocal;
+proto.isUtcOffset          = isUtcOffset;
+proto.isUtc                = isUtc;
+proto.isUTC                = isUtc;
+
+// Timezone
+proto.zoneAbbr = getZoneAbbr;
+proto.zoneName = getZoneName;
+
+// Deprecations
+proto.dates  = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth);
+proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth);
+proto.years  = deprecate('years accessor is deprecated. Use year instead', getSetYear);
+proto.zone   = deprecate('moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/', getSetZone);
+proto.isDSTShifted = deprecate('isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information', isDaylightSavingTimeShifted);
+
+function createUnix (input) {
+    return createLocal(input * 1000);
+}
+
+function createInZone () {
+    return createLocal.apply(null, arguments).parseZone();
+}
+
+function preParsePostFormat (string) {
+    return string;
+}
+
+var proto$1 = Locale.prototype;
+
+proto$1.calendar        = calendar;
+proto$1.longDateFormat  = longDateFormat;
+proto$1.invalidDate     = invalidDate;
+proto$1.ordinal         = ordinal;
+proto$1.preparse        = preParsePostFormat;
+proto$1.postformat      = preParsePostFormat;
+proto$1.relativeTime    = relativeTime;
+proto$1.pastFuture      = pastFuture;
+proto$1.set             = set;
+
+// Month
+proto$1.months            =        localeMonths;
+proto$1.monthsShort       =        localeMonthsShort;
+proto$1.monthsParse       =        localeMonthsParse;
+proto$1.monthsRegex       = monthsRegex;
+proto$1.monthsShortRegex  = monthsShortRegex;
+
+// Week
+proto$1.week = localeWeek;
+proto$1.firstDayOfYear = localeFirstDayOfYear;
+proto$1.firstDayOfWeek = localeFirstDayOfWeek;
+
+// Day of Week
+proto$1.weekdays       =        localeWeekdays;
+proto$1.weekdaysMin    =        localeWeekdaysMin;
+proto$1.weekdaysShort  =        localeWeekdaysShort;
+proto$1.weekdaysParse  =        localeWeekdaysParse;
+
+proto$1.weekdaysRegex       =        weekdaysRegex;
+proto$1.weekdaysShortRegex  =        weekdaysShortRegex;
+proto$1.weekdaysMinRegex    =        weekdaysMinRegex;
+
+// Hours
+proto$1.isPM = localeIsPM;
+proto$1.meridiem = localeMeridiem;
+
+function get$1 (format, index, field, setter) {
+    var locale = getLocale();
+    var utc = createUTC().set(setter, index);
+    return locale[field](utc, format);
+}
+
+function listMonthsImpl (format, index, field) {
+    if (isNumber(format)) {
+        index = format;
+        format = undefined;
+    }
+
+    format = format || '';
+
+    if (index != null) {
+        return get$1(format, index, field, 'month');
+    }
+
+    var i;
+    var out = [];
+    for (i = 0; i < 12; i++) {
+        out[i] = get$1(format, i, field, 'month');
+    }
+    return out;
+}
+
+// ()
+// (5)
+// (fmt, 5)
+// (fmt)
+// (true)
+// (true, 5)
+// (true, fmt, 5)
+// (true, fmt)
+function listWeekdaysImpl (localeSorted, format, index, field) {
+    if (typeof localeSorted === 'boolean') {
+        if (isNumber(format)) {
+            index = format;
+            format = undefined;
+        }
+
+        format = format || '';
+    } else {
+        format = localeSorted;
+        index = format;
+        localeSorted = false;
+
+        if (isNumber(format)) {
+            index = format;
+            format = undefined;
+        }
+
+        format = format || '';
+    }
+
+    var locale = getLocale(),
+        shift = localeSorted ? locale._week.dow : 0;
+
+    if (index != null) {
+        return get$1(format, (index + shift) % 7, field, 'day');
+    }
+
+    var i;
+    var out = [];
+    for (i = 0; i < 7; i++) {
+        out[i] = get$1(format, (i + shift) % 7, field, 'day');
+    }
+    return out;
+}
+
+function listMonths (format, index) {
+    return listMonthsImpl(format, index, 'months');
+}
+
+function listMonthsShort (format, index) {
+    return listMonthsImpl(format, index, 'monthsShort');
+}
+
+function listWeekdays (localeSorted, format, index) {
+    return listWeekdaysImpl(localeSorted, format, index, 'weekdays');
+}
+
+function listWeekdaysShort (localeSorted, format, index) {
+    return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort');
+}
+
+function listWeekdaysMin (localeSorted, format, index) {
+    return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin');
+}
+
+getSetGlobalLocale('en', {
+    ordinalParse: /\d{1,2}(th|st|nd|rd)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (toInt(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    }
+});
+
+// Side effect imports
+hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', getSetGlobalLocale);
+hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', getLocale);
+
+var mathAbs = Math.abs;
+
+function abs () {
+    var data           = this._data;
+
+    this._milliseconds = mathAbs(this._milliseconds);
+    this._days         = mathAbs(this._days);
+    this._months       = mathAbs(this._months);
+
+    data.milliseconds  = mathAbs(data.milliseconds);
+    data.seconds       = mathAbs(data.seconds);
+    data.minutes       = mathAbs(data.minutes);
+    data.hours         = mathAbs(data.hours);
+    data.months        = mathAbs(data.months);
+    data.years         = mathAbs(data.years);
+
+    return this;
+}
+
+function addSubtract$1 (duration, input, value, direction) {
+    var other = createDuration(input, value);
+
+    duration._milliseconds += direction * other._milliseconds;
+    duration._days         += direction * other._days;
+    duration._months       += direction * other._months;
+
+    return duration._bubble();
+}
+
+// supports only 2.0-style add(1, 's') or add(duration)
+function add$1 (input, value) {
+    return addSubtract$1(this, input, value, 1);
+}
+
+// supports only 2.0-style subtract(1, 's') or subtract(duration)
+function subtract$1 (input, value) {
+    return addSubtract$1(this, input, value, -1);
+}
+
+function absCeil (number) {
+    if (number < 0) {
+        return Math.floor(number);
+    } else {
+        return Math.ceil(number);
+    }
+}
+
+function bubble () {
+    var milliseconds = this._milliseconds;
+    var days         = this._days;
+    var months       = this._months;
+    var data         = this._data;
+    var seconds, minutes, hours, years, monthsFromDays;
+
+    // if we have a mix of positive and negative values, bubble down first
+    // check: https://github.com/moment/moment/issues/2166
+    if (!((milliseconds >= 0 && days >= 0 && months >= 0) ||
+            (milliseconds <= 0 && days <= 0 && months <= 0))) {
+        milliseconds += absCeil(monthsToDays(months) + days) * 864e5;
+        days = 0;
+        months = 0;
+    }
+
+    // The following code bubbles up values, see the tests for
+    // examples of what that means.
+    data.milliseconds = milliseconds % 1000;
+
+    seconds           = absFloor(milliseconds / 1000);
+    data.seconds      = seconds % 60;
+
+    minutes           = absFloor(seconds / 60);
+    data.minutes      = minutes % 60;
+
+    hours             = absFloor(minutes / 60);
+    data.hours        = hours % 24;
+
+    days += absFloor(hours / 24);
+
+    // convert days to months
+    monthsFromDays = absFloor(daysToMonths(days));
+    months += monthsFromDays;
+    days -= absCeil(monthsToDays(monthsFromDays));
+
+    // 12 months -> 1 year
+    years = absFloor(months / 12);
+    months %= 12;
+
+    data.days   = days;
+    data.months = months;
+    data.years  = years;
+
+    return this;
+}
+
+function daysToMonths (days) {
+    // 400 years have 146097 days (taking into account leap year rules)
+    // 400 years have 12 months === 4800
+    return days * 4800 / 146097;
+}
+
+function monthsToDays (months) {
+    // the reverse of daysToMonths
+    return months * 146097 / 4800;
+}
+
+function as (units) {
+    var days;
+    var months;
+    var milliseconds = this._milliseconds;
+
+    units = normalizeUnits(units);
+
+    if (units === 'month' || units === 'year') {
+        days   = this._days   + milliseconds / 864e5;
+        months = this._months + daysToMonths(days);
+        return units === 'month' ? months : months / 12;
+    } else {
+        // handle milliseconds separately because of floating point math errors (issue #1867)
+        days = this._days + Math.round(monthsToDays(this._months));
+        switch (units) {
+            case 'week'   : return days / 7     + milliseconds / 6048e5;
+            case 'day'    : return days         + milliseconds / 864e5;
+            case 'hour'   : return days * 24    + milliseconds / 36e5;
+            case 'minute' : return days * 1440  + milliseconds / 6e4;
+            case 'second' : return days * 86400 + milliseconds / 1000;
+            // Math.floor prevents floating point math errors here
+            case 'millisecond': return Math.floor(days * 864e5) + milliseconds;
+            default: throw new Error('Unknown unit ' + units);
+        }
+    }
+}
+
+// TODO: Use this.as('ms')?
+function valueOf$1 () {
+    return (
+        this._milliseconds +
+        this._days * 864e5 +
+        (this._months % 12) * 2592e6 +
+        toInt(this._months / 12) * 31536e6
+    );
+}
+
+function makeAs (alias) {
+    return function () {
+        return this.as(alias);
+    };
+}
+
+var asMilliseconds = makeAs('ms');
+var asSeconds      = makeAs('s');
+var asMinutes      = makeAs('m');
+var asHours        = makeAs('h');
+var asDays         = makeAs('d');
+var asWeeks        = makeAs('w');
+var asMonths       = makeAs('M');
+var asYears        = makeAs('y');
+
+function get$2 (units) {
+    units = normalizeUnits(units);
+    return this[units + 's']();
+}
+
+function makeGetter(name) {
+    return function () {
+        return this._data[name];
+    };
+}
+
+var milliseconds = makeGetter('milliseconds');
+var seconds      = makeGetter('seconds');
+var minutes      = makeGetter('minutes');
+var hours        = makeGetter('hours');
+var days         = makeGetter('days');
+var months       = makeGetter('months');
+var years        = makeGetter('years');
+
+function weeks () {
+    return absFloor(this.days() / 7);
+}
+
+var round = Math.round;
+var thresholds = {
+    s: 45,  // seconds to minute
+    m: 45,  // minutes to hour
+    h: 22,  // hours to day
+    d: 26,  // days to month
+    M: 11   // months to year
+};
+
+// helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
+function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {
+    return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
+}
+
+function relativeTime$1 (posNegDuration, withoutSuffix, locale) {
+    var duration = createDuration(posNegDuration).abs();
+    var seconds  = round(duration.as('s'));
+    var minutes  = round(duration.as('m'));
+    var hours    = round(duration.as('h'));
+    var days     = round(duration.as('d'));
+    var months   = round(duration.as('M'));
+    var years    = round(duration.as('y'));
+
+    var a = seconds < thresholds.s && ['s', seconds]  ||
+            minutes <= 1           && ['m']           ||
+            minutes < thresholds.m && ['mm', minutes] ||
+            hours   <= 1           && ['h']           ||
+            hours   < thresholds.h && ['hh', hours]   ||
+            days    <= 1           && ['d']           ||
+            days    < thresholds.d && ['dd', days]    ||
+            months  <= 1           && ['M']           ||
+            months  < thresholds.M && ['MM', months]  ||
+            years   <= 1           && ['y']           || ['yy', years];
+
+    a[2] = withoutSuffix;
+    a[3] = +posNegDuration > 0;
+    a[4] = locale;
+    return substituteTimeAgo.apply(null, a);
+}
+
+// This function allows you to set the rounding function for relative time strings
+function getSetRelativeTimeRounding (roundingFunction) {
+    if (roundingFunction === undefined) {
+        return round;
+    }
+    if (typeof(roundingFunction) === 'function') {
+        round = roundingFunction;
+        return true;
+    }
+    return false;
+}
+
+// This function allows you to set a threshold for relative time strings
+function getSetRelativeTimeThreshold (threshold, limit) {
+    if (thresholds[threshold] === undefined) {
+        return false;
+    }
+    if (limit === undefined) {
+        return thresholds[threshold];
+    }
+    thresholds[threshold] = limit;
+    return true;
+}
+
+function humanize (withSuffix) {
+    var locale = this.localeData();
+    var output = relativeTime$1(this, !withSuffix, locale);
+
+    if (withSuffix) {
+        output = locale.pastFuture(+this, output);
+    }
+
+    return locale.postformat(output);
+}
+
+var abs$1 = Math.abs;
+
+function toISOString$1() {
+    // for ISO strings we do not use the normal bubbling rules:
+    //  * milliseconds bubble up until they become hours
+    //  * days do not bubble at all
+    //  * months bubble up until they become years
+    // This is because there is no context-free conversion between hours and days
+    // (think of clock changes)
+    // and also not between days and months (28-31 days per month)
+    var seconds = abs$1(this._milliseconds) / 1000;
+    var days         = abs$1(this._days);
+    var months       = abs$1(this._months);
+    var minutes, hours, years;
+
+    // 3600 seconds -> 60 minutes -> 1 hour
+    minutes           = absFloor(seconds / 60);
+    hours             = absFloor(minutes / 60);
+    seconds %= 60;
+    minutes %= 60;
+
+    // 12 months -> 1 year
+    years  = absFloor(months / 12);
+    months %= 12;
+
+
+    // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
+    var Y = years;
+    var M = months;
+    var D = days;
+    var h = hours;
+    var m = minutes;
+    var s = seconds;
+    var total = this.asSeconds();
+
+    if (!total) {
+        // this is the same as C#'s (Noda) and python (isodate)...
+        // but not other JS (goog.date)
+        return 'P0D';
+    }
+
+    return (total < 0 ? '-' : '') +
+        'P' +
+        (Y ? Y + 'Y' : '') +
+        (M ? M + 'M' : '') +
+        (D ? D + 'D' : '') +
+        ((h || m || s) ? 'T' : '') +
+        (h ? h + 'H' : '') +
+        (m ? m + 'M' : '') +
+        (s ? s + 'S' : '');
+}
+
+var proto$2 = Duration.prototype;
+
+proto$2.abs            = abs;
+proto$2.add            = add$1;
+proto$2.subtract       = subtract$1;
+proto$2.as             = as;
+proto$2.asMilliseconds = asMilliseconds;
+proto$2.asSeconds      = asSeconds;
+proto$2.asMinutes      = asMinutes;
+proto$2.asHours        = asHours;
+proto$2.asDays         = asDays;
+proto$2.asWeeks        = asWeeks;
+proto$2.asMonths       = asMonths;
+proto$2.asYears        = asYears;
+proto$2.valueOf        = valueOf$1;
+proto$2._bubble        = bubble;
+proto$2.get            = get$2;
+proto$2.milliseconds   = milliseconds;
+proto$2.seconds        = seconds;
+proto$2.minutes        = minutes;
+proto$2.hours          = hours;
+proto$2.days           = days;
+proto$2.weeks          = weeks;
+proto$2.months         = months;
+proto$2.years          = years;
+proto$2.humanize       = humanize;
+proto$2.toISOString    = toISOString$1;
+proto$2.toString       = toISOString$1;
+proto$2.toJSON         = toISOString$1;
+proto$2.locale         = locale;
+proto$2.localeData     = localeData;
+
+// Deprecations
+proto$2.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', toISOString$1);
+proto$2.lang = lang;
+
+// Side effect imports
+
+// FORMATTING
+
+addFormatToken('X', 0, 0, 'unix');
+addFormatToken('x', 0, 0, 'valueOf');
+
+// PARSING
+
+addRegexToken('x', matchSigned);
+addRegexToken('X', matchTimestamp);
+addParseToken('X', function (input, array, config) {
+    config._d = new Date(parseFloat(input, 10) * 1000);
+});
+addParseToken('x', function (input, array, config) {
+    config._d = new Date(toInt(input));
+});
+
+// Side effect imports
+
+//! moment.js
+//! version : 2.16.0
+//! authors : Tim Wood, Iskren Chernev, Moment.js contributors
+//! license : MIT
+//! momentjs.com
+
+hooks.version = '2.16.0';
+
+setHookCallback(createLocal);
+
+hooks.fn                    = proto;
+hooks.min                   = min;
+hooks.max                   = max;
+hooks.now                   = now;
+hooks.utc                   = createUTC;
+hooks.unix                  = createUnix;
+hooks.months                = listMonths;
+hooks.isDate                = isDate;
+hooks.locale                = getSetGlobalLocale;
+hooks.invalid               = createInvalid;
+hooks.duration              = createDuration;
+hooks.isMoment              = isMoment;
+hooks.weekdays              = listWeekdays;
+hooks.parseZone             = createInZone;
+hooks.localeData            = getLocale;
+hooks.isDuration            = isDuration;
+hooks.monthsShort           = listMonthsShort;
+hooks.weekdaysMin           = listWeekdaysMin;
+hooks.defineLocale          = defineLocale;
+hooks.updateLocale          = updateLocale;
+hooks.locales               = listLocales;
+hooks.weekdaysShort         = listWeekdaysShort;
+hooks.normalizeUnits        = normalizeUnits;
+hooks.relativeTimeRounding = getSetRelativeTimeRounding;
+hooks.relativeTimeThreshold = getSetRelativeTimeThreshold;
+hooks.calendarFormat        = getCalendarFormat;
+hooks.prototype             = proto;
+
+//! moment.js locale configuration
+//! locale : Afrikaans [af]
+//! author : Werner Mollentze : https://github.com/wernerm
+
+hooks.defineLocale('af', {
+    months : 'Januarie_Februarie_Maart_April_Mei_Junie_Julie_Augustus_September_Oktober_November_Desember'.split('_'),
+    monthsShort : 'Jan_Feb_Mrt_Apr_Mei_Jun_Jul_Aug_Sep_Okt_Nov_Des'.split('_'),
+    weekdays : 'Sondag_Maandag_Dinsdag_Woensdag_Donderdag_Vrydag_Saterdag'.split('_'),
+    weekdaysShort : 'Son_Maa_Din_Woe_Don_Vry_Sat'.split('_'),
+    weekdaysMin : 'So_Ma_Di_Wo_Do_Vr_Sa'.split('_'),
+    meridiemParse: /vm|nm/i,
+    isPM : function (input) {
+        return /^nm$/i.test(input);
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 12) {
+            return isLower ? 'vm' : 'VM';
+        } else {
+            return isLower ? 'nm' : 'NM';
+        }
+    },
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[Vandag om] LT',
+        nextDay : '[Môre om] LT',
+        nextWeek : 'dddd [om] LT',
+        lastDay : '[Gister om] LT',
+        lastWeek : '[Laas] dddd [om] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'oor %s',
+        past : '%s gelede',
+        s : '\'n paar sekondes',
+        m : '\'n minuut',
+        mm : '%d minute',
+        h : '\'n uur',
+        hh : '%d ure',
+        d : '\'n dag',
+        dd : '%d dae',
+        M : '\'n maand',
+        MM : '%d maande',
+        y : '\'n jaar',
+        yy : '%d jaar'
+    },
+    ordinalParse: /\d{1,2}(ste|de)/,
+    ordinal : function (number) {
+        return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de'); // Thanks to Joris Röling : https://github.com/jjupiter
+    },
+    week : {
+        dow : 1, // Maandag is die eerste dag van die week.
+        doy : 4  // Die week wat die 4de Januarie bevat is die eerste week van die jaar.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Arabic (Algeria) [ar-dz]
+//! author : Noureddine LOUAHEDJ : https://github.com/noureddineme
+
+hooks.defineLocale('ar-dz', {
+    months : 'جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
+    monthsShort : 'جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
+    weekdays : 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
+    weekdaysShort : 'احد_اثنين_ثلاثاء_اربعاء_خميس_جمعة_سبت'.split('_'),
+    weekdaysMin : 'أح_إث_ثلا_أر_خم_جم_سب'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[اليوم على الساعة] LT',
+        nextDay: '[غدا على الساعة] LT',
+        nextWeek: 'dddd [على الساعة] LT',
+        lastDay: '[أمس على الساعة] LT',
+        lastWeek: 'dddd [على الساعة] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'في %s',
+        past : 'منذ %s',
+        s : 'ثوان',
+        m : 'دقيقة',
+        mm : '%d دقائق',
+        h : 'ساعة',
+        hh : '%d ساعات',
+        d : 'يوم',
+        dd : '%d أيام',
+        M : 'شهر',
+        MM : '%d أشهر',
+        y : 'سنة',
+        yy : '%d سنوات'
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 4  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Arabic (Lybia) [ar-ly]
+//! author : Ali Hmer: https://github.com/kikoanis
+
+var symbolMap = {
+    '1': '1',
+    '2': '2',
+    '3': '3',
+    '4': '4',
+    '5': '5',
+    '6': '6',
+    '7': '7',
+    '8': '8',
+    '9': '9',
+    '0': '0'
+};
+var pluralForm = function (n) {
+    return n === 0 ? 0 : n === 1 ? 1 : n === 2 ? 2 : n % 100 >= 3 && n % 100 <= 10 ? 3 : n % 100 >= 11 ? 4 : 5;
+};
+var plurals = {
+    s : ['أقل من ثانية', 'ثانية واحدة', ['ثانيتان', 'ثانيتين'], '%d ثوان', '%d ثانية', '%d ثانية'],
+    m : ['أقل من دقيقة', 'دقيقة واحدة', ['دقيقتان', 'دقيقتين'], '%d دقائق', '%d دقيقة', '%d دقيقة'],
+    h : ['أقل من ساعة', 'ساعة واحدة', ['ساعتان', 'ساعتين'], '%d ساعات', '%d ساعة', '%d ساعة'],
+    d : ['أقل من يوم', 'يوم واحد', ['يومان', 'يومين'], '%d أيام', '%d يومًا', '%d يوم'],
+    M : ['أقل من شهر', 'شهر واحد', ['شهران', 'شهرين'], '%d أشهر', '%d شهرا', '%d شهر'],
+    y : ['أقل من عام', 'عام واحد', ['عامان', 'عامين'], '%d أعوام', '%d عامًا', '%d عام']
+};
+var pluralize = function (u) {
+    return function (number, withoutSuffix, string, isFuture) {
+        var f = pluralForm(number),
+            str = plurals[u][pluralForm(number)];
+        if (f === 2) {
+            str = str[withoutSuffix ? 0 : 1];
+        }
+        return str.replace(/%d/i, number);
+    };
+};
+var months$1 = [
+    'يناير',
+    'فبراير',
+    'مارس',
+    'أبريل',
+    'مايو',
+    'يونيو',
+    'يوليو',
+    'أغسطس',
+    'سبتمبر',
+    'أكتوبر',
+    'نوفمبر',
+    'ديسمبر'
+];
+
+hooks.defineLocale('ar-ly', {
+    months : months$1,
+    monthsShort : months$1,
+    weekdays : 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
+    weekdaysShort : 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'),
+    weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'D/\u200FM/\u200FYYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    meridiemParse: /ص|م/,
+    isPM : function (input) {
+        return 'Ù…' === input;
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return 'ص';
+        } else {
+            return 'Ù…';
+        }
+    },
+    calendar : {
+        sameDay: '[اليوم عند الساعة] LT',
+        nextDay: '[غدًا عند الساعة] LT',
+        nextWeek: 'dddd [عند الساعة] LT',
+        lastDay: '[أمس عند الساعة] LT',
+        lastWeek: 'dddd [عند الساعة] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'بعد %s',
+        past : 'منذ %s',
+        s : pluralize('s'),
+        m : pluralize('m'),
+        mm : pluralize('m'),
+        h : pluralize('h'),
+        hh : pluralize('h'),
+        d : pluralize('d'),
+        dd : pluralize('d'),
+        M : pluralize('M'),
+        MM : pluralize('M'),
+        y : pluralize('y'),
+        yy : pluralize('y')
+    },
+    preparse: function (string) {
+        return string.replace(/\u200f/g, '').replace(/،/g, ',');
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap[match];
+        }).replace(/,/g, '،');
+    },
+    week : {
+        dow : 6, // Saturday is the first day of the week.
+        doy : 12  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Arabic (Morocco) [ar-ma]
+//! author : ElFadili Yassine : https://github.com/ElFadiliY
+//! author : Abdel Said : https://github.com/abdelsaid
+
+hooks.defineLocale('ar-ma', {
+    months : 'يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر'.split('_'),
+    monthsShort : 'يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر'.split('_'),
+    weekdays : 'الأحد_الإتنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
+    weekdaysShort : 'احد_اتنين_ثلاثاء_اربعاء_خميس_جمعة_سبت'.split('_'),
+    weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[اليوم على الساعة] LT',
+        nextDay: '[غدا على الساعة] LT',
+        nextWeek: 'dddd [على الساعة] LT',
+        lastDay: '[أمس على الساعة] LT',
+        lastWeek: 'dddd [على الساعة] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'في %s',
+        past : 'منذ %s',
+        s : 'ثوان',
+        m : 'دقيقة',
+        mm : '%d دقائق',
+        h : 'ساعة',
+        hh : '%d ساعات',
+        d : 'يوم',
+        dd : '%d أيام',
+        M : 'شهر',
+        MM : '%d أشهر',
+        y : 'سنة',
+        yy : '%d سنوات'
+    },
+    week : {
+        dow : 6, // Saturday is the first day of the week.
+        doy : 12  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Arabic (Saudi Arabia) [ar-sa]
+//! author : Suhail Alkowaileet : https://github.com/xsoh
+
+var symbolMap$1 = {
+    '1': 'Ù¡',
+    '2': 'Ù¢',
+    '3': 'Ù£',
+    '4': 'Ù¤',
+    '5': 'Ù¥',
+    '6': 'Ù¦',
+    '7': 'Ù§',
+    '8': 'Ù¨',
+    '9': 'Ù©',
+    '0': 'Ù '
+};
+var numberMap = {
+    'Ù¡': '1',
+    'Ù¢': '2',
+    'Ù£': '3',
+    'Ù¤': '4',
+    'Ù¥': '5',
+    'Ù¦': '6',
+    'Ù§': '7',
+    'Ù¨': '8',
+    'Ù©': '9',
+    'Ù ': '0'
+};
+
+hooks.defineLocale('ar-sa', {
+    months : 'يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
+    monthsShort : 'يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
+    weekdays : 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
+    weekdaysShort : 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'),
+    weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    meridiemParse: /ص|م/,
+    isPM : function (input) {
+        return 'Ù…' === input;
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return 'ص';
+        } else {
+            return 'Ù…';
+        }
+    },
+    calendar : {
+        sameDay: '[اليوم على الساعة] LT',
+        nextDay: '[غدا على الساعة] LT',
+        nextWeek: 'dddd [على الساعة] LT',
+        lastDay: '[أمس على الساعة] LT',
+        lastWeek: 'dddd [على الساعة] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'في %s',
+        past : 'منذ %s',
+        s : 'ثوان',
+        m : 'دقيقة',
+        mm : '%d دقائق',
+        h : 'ساعة',
+        hh : '%d ساعات',
+        d : 'يوم',
+        dd : '%d أيام',
+        M : 'شهر',
+        MM : '%d أشهر',
+        y : 'سنة',
+        yy : '%d سنوات'
+    },
+    preparse: function (string) {
+        return string.replace(/[١٢٣٤٥٦٧٨٩٠]/g, function (match) {
+            return numberMap[match];
+        }).replace(/،/g, ',');
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap$1[match];
+        }).replace(/,/g, '،');
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale  :  Arabic (Tunisia) [ar-tn]
+//! author : Nader Toukabri : https://github.com/naderio
+
+hooks.defineLocale('ar-tn', {
+    months: 'جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
+    monthsShort: 'جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
+    weekdays: 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
+    weekdaysShort: 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'),
+    weekdaysMin: 'ح_ن_ث_ر_خ_ج_س'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat: {
+        LT: 'HH:mm',
+        LTS: 'HH:mm:ss',
+        L: 'DD/MM/YYYY',
+        LL: 'D MMMM YYYY',
+        LLL: 'D MMMM YYYY HH:mm',
+        LLLL: 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar: {
+        sameDay: '[اليوم على الساعة] LT',
+        nextDay: '[غدا على الساعة] LT',
+        nextWeek: 'dddd [على الساعة] LT',
+        lastDay: '[أمس على الساعة] LT',
+        lastWeek: 'dddd [على الساعة] LT',
+        sameElse: 'L'
+    },
+    relativeTime: {
+        future: 'في %s',
+        past: 'منذ %s',
+        s: 'ثوان',
+        m: 'دقيقة',
+        mm: '%d دقائق',
+        h: 'ساعة',
+        hh: '%d ساعات',
+        d: 'يوم',
+        dd: '%d أيام',
+        M: 'شهر',
+        MM: '%d أشهر',
+        y: 'سنة',
+        yy: '%d سنوات'
+    },
+    week: {
+        dow: 1, // Monday is the first day of the week.
+        doy: 4 // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Arabic [ar]
+//! author : Abdel Said: https://github.com/abdelsaid
+//! author : Ahmed Elkhatib
+//! author : forabi https://github.com/forabi
+
+var symbolMap$2 = {
+    '1': 'Ù¡',
+    '2': 'Ù¢',
+    '3': 'Ù£',
+    '4': 'Ù¤',
+    '5': 'Ù¥',
+    '6': 'Ù¦',
+    '7': 'Ù§',
+    '8': 'Ù¨',
+    '9': 'Ù©',
+    '0': 'Ù '
+};
+var numberMap$1 = {
+    'Ù¡': '1',
+    'Ù¢': '2',
+    'Ù£': '3',
+    'Ù¤': '4',
+    'Ù¥': '5',
+    'Ù¦': '6',
+    'Ù§': '7',
+    'Ù¨': '8',
+    'Ù©': '9',
+    'Ù ': '0'
+};
+var pluralForm$1 = function (n) {
+    return n === 0 ? 0 : n === 1 ? 1 : n === 2 ? 2 : n % 100 >= 3 && n % 100 <= 10 ? 3 : n % 100 >= 11 ? 4 : 5;
+};
+var plurals$1 = {
+    s : ['أقل من ثانية', 'ثانية واحدة', ['ثانيتان', 'ثانيتين'], '%d ثوان', '%d ثانية', '%d ثانية'],
+    m : ['أقل من دقيقة', 'دقيقة واحدة', ['دقيقتان', 'دقيقتين'], '%d دقائق', '%d دقيقة', '%d دقيقة'],
+    h : ['أقل من ساعة', 'ساعة واحدة', ['ساعتان', 'ساعتين'], '%d ساعات', '%d ساعة', '%d ساعة'],
+    d : ['أقل من يوم', 'يوم واحد', ['يومان', 'يومين'], '%d أيام', '%d يومًا', '%d يوم'],
+    M : ['أقل من شهر', 'شهر واحد', ['شهران', 'شهرين'], '%d أشهر', '%d شهرا', '%d شهر'],
+    y : ['أقل من عام', 'عام واحد', ['عامان', 'عامين'], '%d أعوام', '%d عامًا', '%d عام']
+};
+var pluralize$1 = function (u) {
+    return function (number, withoutSuffix, string, isFuture) {
+        var f = pluralForm$1(number),
+            str = plurals$1[u][pluralForm$1(number)];
+        if (f === 2) {
+            str = str[withoutSuffix ? 0 : 1];
+        }
+        return str.replace(/%d/i, number);
+    };
+};
+var months$2 = [
+    'كانون الثاني يناير',
+    'شباط فبراير',
+    'آذار مارس',
+    'نيسان أبريل',
+    'أيار مايو',
+    'حزيران يونيو',
+    'تموز يوليو',
+    'آب أغسطس',
+    'أيلول سبتمبر',
+    'تشرين الأول أكتوبر',
+    'تشرين الثاني نوفمبر',
+    'كانون الأول ديسمبر'
+];
+
+hooks.defineLocale('ar', {
+    months : months$2,
+    monthsShort : months$2,
+    weekdays : 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
+    weekdaysShort : 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'),
+    weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'D/\u200FM/\u200FYYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    meridiemParse: /ص|م/,
+    isPM : function (input) {
+        return 'Ù…' === input;
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return 'ص';
+        } else {
+            return 'Ù…';
+        }
+    },
+    calendar : {
+        sameDay: '[اليوم عند الساعة] LT',
+        nextDay: '[غدًا عند الساعة] LT',
+        nextWeek: 'dddd [عند الساعة] LT',
+        lastDay: '[أمس عند الساعة] LT',
+        lastWeek: 'dddd [عند الساعة] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'بعد %s',
+        past : 'منذ %s',
+        s : pluralize$1('s'),
+        m : pluralize$1('m'),
+        mm : pluralize$1('m'),
+        h : pluralize$1('h'),
+        hh : pluralize$1('h'),
+        d : pluralize$1('d'),
+        dd : pluralize$1('d'),
+        M : pluralize$1('M'),
+        MM : pluralize$1('M'),
+        y : pluralize$1('y'),
+        yy : pluralize$1('y')
+    },
+    preparse: function (string) {
+        return string.replace(/\u200f/g, '').replace(/[١٢٣٤٥٦٧٨٩٠]/g, function (match) {
+            return numberMap$1[match];
+        }).replace(/،/g, ',');
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap$2[match];
+        }).replace(/,/g, '،');
+    },
+    week : {
+        dow : 6, // Saturday is the first day of the week.
+        doy : 12  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Azerbaijani [az]
+//! author : topchiyev : https://github.com/topchiyev
+
+var suffixes = {
+    1: '-inci',
+    5: '-inci',
+    8: '-inci',
+    70: '-inci',
+    80: '-inci',
+    2: '-nci',
+    7: '-nci',
+    20: '-nci',
+    50: '-nci',
+    3: '-üncü',
+    4: '-üncü',
+    100: '-üncü',
+    6: '-ncı',
+    9: '-uncu',
+    10: '-uncu',
+    30: '-uncu',
+    60: '-ıncı',
+    90: '-ıncı'
+};
+
+hooks.defineLocale('az', {
+    months : 'yanvar_fevral_mart_aprel_may_iyun_iyul_avqust_sentyabr_oktyabr_noyabr_dekabr'.split('_'),
+    monthsShort : 'yan_fev_mar_apr_may_iyn_iyl_avq_sen_okt_noy_dek'.split('_'),
+    weekdays : 'Bazar_Bazar ertəsi_Çərşənbə axşamı_Çərşənbə_Cümə axşamı_Cümə_Şənbə'.split('_'),
+    weekdaysShort : 'Baz_BzE_ÇAx_Çər_CAx_Cüm_Şən'.split('_'),
+    weekdaysMin : 'Bz_BE_ÇA_Çə_CA_Cü_Şə'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[bugün saat] LT',
+        nextDay : '[sabah saat] LT',
+        nextWeek : '[gələn həftə] dddd [saat] LT',
+        lastDay : '[dünən] LT',
+        lastWeek : '[keçən həftə] dddd [saat] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s sonra',
+        past : '%s əvvəl',
+        s : 'birneçə saniyyə',
+        m : 'bir dəqiqə',
+        mm : '%d dəqiqə',
+        h : 'bir saat',
+        hh : '%d saat',
+        d : 'bir gün',
+        dd : '%d gün',
+        M : 'bir ay',
+        MM : '%d ay',
+        y : 'bir il',
+        yy : '%d il'
+    },
+    meridiemParse: /gecə|səhər|gündüz|axşam/,
+    isPM : function (input) {
+        return /^(gündüz|axşam)$/.test(input);
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'gecÉ™';
+        } else if (hour < 12) {
+            return 'səhər';
+        } else if (hour < 17) {
+            return 'gündüz';
+        } else {
+            return 'axÅŸam';
+        }
+    },
+    ordinalParse: /\d{1,2}-(ıncı|inci|nci|üncü|ncı|uncu)/,
+    ordinal : function (number) {
+        if (number === 0) {  // special case for zero
+            return number + '-ıncı';
+        }
+        var a = number % 10,
+            b = number % 100 - a,
+            c = number >= 100 ? 100 : null;
+        return number + (suffixes[a] || suffixes[b] || suffixes[c]);
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Belarusian [be]
+//! author : Dmitry Demidov : https://github.com/demidov91
+//! author: Praleska: http://praleska.pro/
+//! Author : Menelion Elensúle : https://github.com/Oire
+
+function plural(word, num) {
+    var forms = word.split('_');
+    return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]);
+}
+function relativeTimeWithPlural(number, withoutSuffix, key) {
+    var format = {
+        'mm': withoutSuffix ? 'хвіліна_хвіліны_хвілін' : 'хвіліну_хвіліны_хвілін',
+        'hh': withoutSuffix ? 'гадзіна_гадзіны_гадзін' : 'гадзіну_гадзіны_гадзін',
+        'dd': 'дзень_дні_дзён',
+        'MM': 'месяц_месяцы_месяцаў',
+        'yy': 'год_гады_гадоў'
+    };
+    if (key === 'm') {
+        return withoutSuffix ? 'хвіліна' : 'хвіліну';
+    }
+    else if (key === 'h') {
+        return withoutSuffix ? 'гадзіна' : 'гадзіну';
+    }
+    else {
+        return number + ' ' + plural(format[key], +number);
+    }
+}
+
+hooks.defineLocale('be', {
+    months : {
+        format: 'студзеня_лютага_сакавіка_красавіка_траўня_чэрвеня_ліпеня_жніўня_верасня_кастрычніка_лістапада_снежня'.split('_'),
+        standalone: 'студзень_люты_сакавік_красавік_травень_чэрвень_ліпень_жнівень_верасень_кастрычнік_лістапад_снежань'.split('_')
+    },
+    monthsShort : 'студ_лют_сак_крас_трав_чэрв_ліп_жнів_вер_каст_ліст_снеж'.split('_'),
+    weekdays : {
+        format: 'нядзелю_панядзелак_аўторак_сераду_чацвер_пятніцу_суботу'.split('_'),
+        standalone: 'нядзеля_панядзелак_аўторак_серада_чацвер_пятніца_субота'.split('_'),
+        isFormat: /\[ ?[Вв] ?(?:мінулую|наступную)? ?\] ?dddd/
+    },
+    weekdaysShort : 'нд_пн_ат_ср_чц_пт_сб'.split('_'),
+    weekdaysMin : 'нд_пн_ат_ср_чц_пт_сб'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY г.',
+        LLL : 'D MMMM YYYY г., HH:mm',
+        LLLL : 'dddd, D MMMM YYYY г., HH:mm'
+    },
+    calendar : {
+        sameDay: '[Сёння ў] LT',
+        nextDay: '[Заўтра ў] LT',
+        lastDay: '[Учора ў] LT',
+        nextWeek: function () {
+            return '[У] dddd [ў] LT';
+        },
+        lastWeek: function () {
+            switch (this.day()) {
+                case 0:
+                case 3:
+                case 5:
+                case 6:
+                    return '[У мінулую] dddd [ў] LT';
+                case 1:
+                case 2:
+                case 4:
+                    return '[У мінулы] dddd [ў] LT';
+            }
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'праз %s',
+        past : '%s таму',
+        s : 'некалькі секунд',
+        m : relativeTimeWithPlural,
+        mm : relativeTimeWithPlural,
+        h : relativeTimeWithPlural,
+        hh : relativeTimeWithPlural,
+        d : 'дзень',
+        dd : relativeTimeWithPlural,
+        M : 'месяц',
+        MM : relativeTimeWithPlural,
+        y : 'год',
+        yy : relativeTimeWithPlural
+    },
+    meridiemParse: /ночы|раніцы|дня|вечара/,
+    isPM : function (input) {
+        return /^(дня|вечара)$/.test(input);
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'ночы';
+        } else if (hour < 12) {
+            return 'раніцы';
+        } else if (hour < 17) {
+            return 'дня';
+        } else {
+            return 'вечара';
+        }
+    },
+    ordinalParse: /\d{1,2}-(і|ы|га)/,
+    ordinal: function (number, period) {
+        switch (period) {
+            case 'M':
+            case 'd':
+            case 'DDD':
+            case 'w':
+            case 'W':
+                return (number % 10 === 2 || number % 10 === 3) && (number % 100 !== 12 && number % 100 !== 13) ? number + '-Ñ–' : number + '-Ñ‹';
+            case 'D':
+                return number + '-га';
+            default:
+                return number;
+        }
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+hooks.defineLocale('bg-x', {
+    parentLocale: 'bg'
+});
+
+//! moment.js locale configuration
+//! locale : Bulgarian [bg]
+//! author : Krasen Borisov : https://github.com/kraz
+
+hooks.defineLocale('bg', {
+    months : 'януари_февруари_март_април_май_юни_юли_август_септември_октомври_ноември_декември'.split('_'),
+    monthsShort : 'янр_фев_мар_апр_май_юни_юли_авг_сеп_окт_ное_дек'.split('_'),
+    weekdays : 'неделя_понеделник_вторник_сряда_четвъртък_петък_събота'.split('_'),
+    weekdaysShort : 'нед_пон_вто_сря_чет_пет_съб'.split('_'),
+    weekdaysMin : 'нд_пн_вт_ср_чт_пт_сб'.split('_'),
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'D.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY H:mm',
+        LLLL : 'dddd, D MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay : '[Днес в] LT',
+        nextDay : '[Утре в] LT',
+        nextWeek : 'dddd [в] LT',
+        lastDay : '[Вчера в] LT',
+        lastWeek : function () {
+            switch (this.day()) {
+                case 0:
+                case 3:
+                case 6:
+                    return '[В изминалата] dddd [в] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[В изминалия] dddd [в] LT';
+            }
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'след %s',
+        past : 'преди %s',
+        s : 'няколко секунди',
+        m : 'минута',
+        mm : '%d минути',
+        h : 'час',
+        hh : '%d часа',
+        d : 'ден',
+        dd : '%d дни',
+        M : 'месец',
+        MM : '%d месеца',
+        y : 'година',
+        yy : '%d години'
+    },
+    ordinalParse: /\d{1,2}-(ев|ен|ти|ви|ри|ми)/,
+    ordinal : function (number) {
+        var lastDigit = number % 10,
+            last2Digits = number % 100;
+        if (number === 0) {
+            return number + '-ев';
+        } else if (last2Digits === 0) {
+            return number + '-ен';
+        } else if (last2Digits > 10 && last2Digits < 20) {
+            return number + '-ти';
+        } else if (lastDigit === 1) {
+            return number + '-ви';
+        } else if (lastDigit === 2) {
+            return number + '-ри';
+        } else if (lastDigit === 7 || lastDigit === 8) {
+            return number + '-ми';
+        } else {
+            return number + '-ти';
+        }
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Bengali [bn]
+//! author : Kaushik Gandhi : https://github.com/kaushikgandhi
+
+var symbolMap$3 = {
+    '1': 'à§§',
+    '2': '২',
+    '3': 'à§©',
+    '4': '৪',
+    '5': 'à§«',
+    '6': '৬',
+    '7': 'à§­',
+    '8': 'à§®',
+    '9': '৯',
+    '0': '০'
+};
+var numberMap$2 = {
+    'à§§': '1',
+    '২': '2',
+    'à§©': '3',
+    '৪': '4',
+    'à§«': '5',
+    '৬': '6',
+    'à§­': '7',
+    'à§®': '8',
+    '৯': '9',
+    '০': '0'
+};
+
+hooks.defineLocale('bn', {
+    months : 'জানুয়ারী_ফেব্রুয়ারি_মার্চ_এপ্রিল_মে_জুন_জুলাই_আগস্ট_সেপ্টেম্বর_অক্টোবর_নভেম্বর_ডিসেম্বর'.split('_'),
+    monthsShort : 'জানু_ফেব_মার্চ_এপ্র_মে_জুন_জুল_আগ_সেপ্ট_অক্টো_নভে_ডিসে'.split('_'),
+    weekdays : 'রবিবার_সোমবার_মঙ্গলবার_বুধবার_বৃহস্পতিবার_শুক্রবার_শনিবার'.split('_'),
+    weekdaysShort : 'রবি_সোম_মঙ্গল_বুধ_বৃহস্পতি_শুক্র_শনি'.split('_'),
+    weekdaysMin : 'রবি_সোম_মঙ্গ_বুধ_বৃহঃ_শুক্র_শনি'.split('_'),
+    longDateFormat : {
+        LT : 'A h:mm সময়',
+        LTS : 'A h:mm:ss সময়',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, A h:mm সময়',
+        LLLL : 'dddd, D MMMM YYYY, A h:mm সময়'
+    },
+    calendar : {
+        sameDay : '[আজ] LT',
+        nextDay : '[আগামীকাল] LT',
+        nextWeek : 'dddd, LT',
+        lastDay : '[গতকাল] LT',
+        lastWeek : '[গত] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s পরে',
+        past : '%s আগে',
+        s : 'কয়েক সেকেন্ড',
+        m : 'এক মিনিট',
+        mm : '%d মিনিট',
+        h : 'এক ঘন্টা',
+        hh : '%d ঘন্টা',
+        d : 'এক দিন',
+        dd : '%d দিন',
+        M : 'এক মাস',
+        MM : '%d মাস',
+        y : 'এক বছর',
+        yy : '%d বছর'
+    },
+    preparse: function (string) {
+        return string.replace(/[১২৩৪৫৬৭৮৯০]/g, function (match) {
+            return numberMap$2[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap$3[match];
+        });
+    },
+    meridiemParse: /রাত|সকাল|দুপুর|বিকাল|রাত/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if ((meridiem === 'রাত' && hour >= 4) ||
+                (meridiem === 'দুপুর' && hour < 5) ||
+                meridiem === 'বিকাল') {
+            return hour + 12;
+        } else {
+            return hour;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'রাত';
+        } else if (hour < 10) {
+            return 'সকাল';
+        } else if (hour < 17) {
+            return 'দুপুর';
+        } else if (hour < 20) {
+            return 'বিকাল';
+        } else {
+            return 'রাত';
+        }
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Tibetan [bo]
+//! author : Thupten N. Chakrishar : https://github.com/vajradog
+
+var symbolMap$4 = {
+    '1': '༡',
+    '2': '༢',
+    '3': '༣',
+    '4': '༤',
+    '5': '༥',
+    '6': '༦',
+    '7': '༧',
+    '8': '༨',
+    '9': '༩',
+    '0': '༠'
+};
+var numberMap$3 = {
+    '༡': '1',
+    '༢': '2',
+    '༣': '3',
+    '༤': '4',
+    '༥': '5',
+    '༦': '6',
+    '༧': '7',
+    '༨': '8',
+    '༩': '9',
+    '༠': '0'
+};
+
+hooks.defineLocale('bo', {
+    months : 'ཟླ་བ་དང་པོ_ཟླ་བ་གཉིས་པ_ཟླ་བ་གསུམ་པ_ཟླ་བ་བཞི་པ_ཟླ་བ་ལྔ་པ_ཟླ་བ་དྲུག་པ_ཟླ་བ་བདུན་པ_ཟླ་བ་བརྒྱད་པ_ཟླ་བ་དགུ་པ_ཟླ་བ་བཅུ་པ_ཟླ་བ་བཅུ་གཅིག་པ_ཟླ་བ་བཅུ་གཉིས་པ'.split('_'),
+    monthsShort : 'ཟླ་བ་དང་པོ_ཟླ་བ་གཉིས་པ_ཟླ་བ་གསུམ་པ_ཟླ་བ་བཞི་པ_ཟླ་བ་ལྔ་པ_ཟླ་བ་དྲུག་པ_ཟླ་བ་བདུན་པ_ཟླ་བ་བརྒྱད་པ_ཟླ་བ་དགུ་པ_ཟླ་བ་བཅུ་པ_ཟླ་བ་བཅུ་གཅིག་པ_ཟླ་བ་བཅུ་གཉིས་པ'.split('_'),
+    weekdays : 'གཟའ་ཉི་མ་_གཟའ་ཟླ་བ་_གཟའ་མིག་དམར་_གཟའ་ལྷག་པ་_གཟའ་ཕུར་བུ_གཟའ་པ་སངས་_གཟའ་སྤེན་པ་'.split('_'),
+    weekdaysShort : 'ཉི་མ་_ཟླ་བ་_མིག་དམར་_ལྷག་པ་_ཕུར་བུ_པ་སངས་_སྤེན་པ་'.split('_'),
+    weekdaysMin : 'ཉི་མ་_ཟླ་བ་_མིག་དམར་_ལྷག་པ་_ཕུར་བུ_པ་སངས་_སྤེན་པ་'.split('_'),
+    longDateFormat : {
+        LT : 'A h:mm',
+        LTS : 'A h:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, A h:mm',
+        LLLL : 'dddd, D MMMM YYYY, A h:mm'
+    },
+    calendar : {
+        sameDay : '[དི་རིང] LT',
+        nextDay : '[སང་ཉིན] LT',
+        nextWeek : '[བདུན་ཕྲག་རྗེས་མ], LT',
+        lastDay : '[ཁ་སང] LT',
+        lastWeek : '[བདུན་ཕྲག་མཐའ་མ] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s ལ་',
+        past : '%s སྔན་ལ',
+        s : 'ལམ་སང',
+        m : 'སྐར་མ་གཅིག',
+        mm : '%d སྐར་མ',
+        h : 'ཆུ་ཚོད་གཅིག',
+        hh : '%d ཆུ་ཚོད',
+        d : 'ཉིན་གཅིག',
+        dd : '%d ཉིན་',
+        M : 'ཟླ་བ་གཅིག',
+        MM : '%d ཟླ་བ',
+        y : 'ལོ་གཅིག',
+        yy : '%d ལོ'
+    },
+    preparse: function (string) {
+        return string.replace(/[༡༢༣༤༥༦༧༨༩༠]/g, function (match) {
+            return numberMap$3[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap$4[match];
+        });
+    },
+    meridiemParse: /མཚན་མོ|ཞོགས་ཀས|ཉིན་གུང|དགོང་དག|མཚན་མོ/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if ((meridiem === 'མཚན་མོ' && hour >= 4) ||
+                (meridiem === 'ཉིན་གུང' && hour < 5) ||
+                meridiem === 'དགོང་དག') {
+            return hour + 12;
+        } else {
+            return hour;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'མཚན་མོ';
+        } else if (hour < 10) {
+            return 'ཞོགས་ཀས';
+        } else if (hour < 17) {
+            return 'ཉིན་གུང';
+        } else if (hour < 20) {
+            return 'དགོང་དག';
+        } else {
+            return 'མཚན་མོ';
+        }
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Breton [br]
+//! author : Jean-Baptiste Le Duigou : https://github.com/jbleduigou
+
+function relativeTimeWithMutation(number, withoutSuffix, key) {
+    var format = {
+        'mm': 'munutenn',
+        'MM': 'miz',
+        'dd': 'devezh'
+    };
+    return number + ' ' + mutation(format[key], number);
+}
+function specialMutationForYears(number) {
+    switch (lastNumber(number)) {
+        case 1:
+        case 3:
+        case 4:
+        case 5:
+        case 9:
+            return number + ' bloaz';
+        default:
+            return number + ' vloaz';
+    }
+}
+function lastNumber(number) {
+    if (number > 9) {
+        return lastNumber(number % 10);
+    }
+    return number;
+}
+function mutation(text, number) {
+    if (number === 2) {
+        return softMutation(text);
+    }
+    return text;
+}
+function softMutation(text) {
+    var mutationTable = {
+        'm': 'v',
+        'b': 'v',
+        'd': 'z'
+    };
+    if (mutationTable[text.charAt(0)] === undefined) {
+        return text;
+    }
+    return mutationTable[text.charAt(0)] + text.substring(1);
+}
+
+hooks.defineLocale('br', {
+    months : 'Genver_C\'hwevrer_Meurzh_Ebrel_Mae_Mezheven_Gouere_Eost_Gwengolo_Here_Du_Kerzu'.split('_'),
+    monthsShort : 'Gen_C\'hwe_Meu_Ebr_Mae_Eve_Gou_Eos_Gwe_Her_Du_Ker'.split('_'),
+    weekdays : 'Sul_Lun_Meurzh_Merc\'her_Yaou_Gwener_Sadorn'.split('_'),
+    weekdaysShort : 'Sul_Lun_Meu_Mer_Yao_Gwe_Sad'.split('_'),
+    weekdaysMin : 'Su_Lu_Me_Mer_Ya_Gw_Sa'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'h[e]mm A',
+        LTS : 'h[e]mm:ss A',
+        L : 'DD/MM/YYYY',
+        LL : 'D [a viz] MMMM YYYY',
+        LLL : 'D [a viz] MMMM YYYY h[e]mm A',
+        LLLL : 'dddd, D [a viz] MMMM YYYY h[e]mm A'
+    },
+    calendar : {
+        sameDay : '[Hiziv da] LT',
+        nextDay : '[Warc\'hoazh da] LT',
+        nextWeek : 'dddd [da] LT',
+        lastDay : '[Dec\'h da] LT',
+        lastWeek : 'dddd [paset da] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'a-benn %s',
+        past : '%s \'zo',
+        s : 'un nebeud segondennoù',
+        m : 'ur vunutenn',
+        mm : relativeTimeWithMutation,
+        h : 'un eur',
+        hh : '%d eur',
+        d : 'un devezh',
+        dd : relativeTimeWithMutation,
+        M : 'ur miz',
+        MM : relativeTimeWithMutation,
+        y : 'ur bloaz',
+        yy : specialMutationForYears
+    },
+    ordinalParse: /\d{1,2}(añ|vet)/,
+    ordinal : function (number) {
+        var output = (number === 1) ? 'añ' : 'vet';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Bosnian [bs]
+//! author : Nedim Cholich : https://github.com/frontyard
+//! based on (hr) translation by Bojan Marković
+
+function translate(number, withoutSuffix, key) {
+    var result = number + ' ';
+    switch (key) {
+        case 'm':
+            return withoutSuffix ? 'jedna minuta' : 'jedne minute';
+        case 'mm':
+            if (number === 1) {
+                result += 'minuta';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'minute';
+            } else {
+                result += 'minuta';
+            }
+            return result;
+        case 'h':
+            return withoutSuffix ? 'jedan sat' : 'jednog sata';
+        case 'hh':
+            if (number === 1) {
+                result += 'sat';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'sata';
+            } else {
+                result += 'sati';
+            }
+            return result;
+        case 'dd':
+            if (number === 1) {
+                result += 'dan';
+            } else {
+                result += 'dana';
+            }
+            return result;
+        case 'MM':
+            if (number === 1) {
+                result += 'mjesec';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'mjeseca';
+            } else {
+                result += 'mjeseci';
+            }
+            return result;
+        case 'yy':
+            if (number === 1) {
+                result += 'godina';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'godine';
+            } else {
+                result += 'godina';
+            }
+            return result;
+    }
+}
+
+hooks.defineLocale('bs', {
+    months : 'januar_februar_mart_april_maj_juni_juli_august_septembar_oktobar_novembar_decembar'.split('_'),
+    monthsShort : 'jan._feb._mar._apr._maj._jun._jul._aug._sep._okt._nov._dec.'.split('_'),
+    monthsParseExact: true,
+    weekdays : 'nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota'.split('_'),
+    weekdaysShort : 'ned._pon._uto._sri._čet._pet._sub.'.split('_'),
+    weekdaysMin : 'ne_po_ut_sr_če_pe_su'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY H:mm',
+        LLLL : 'dddd, D. MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay  : '[danas u] LT',
+        nextDay  : '[sutra u] LT',
+        nextWeek : function () {
+            switch (this.day()) {
+                case 0:
+                    return '[u] [nedjelju] [u] LT';
+                case 3:
+                    return '[u] [srijedu] [u] LT';
+                case 6:
+                    return '[u] [subotu] [u] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[u] dddd [u] LT';
+            }
+        },
+        lastDay  : '[jučer u] LT',
+        lastWeek : function () {
+            switch (this.day()) {
+                case 0:
+                case 3:
+                    return '[prošlu] dddd [u] LT';
+                case 6:
+                    return '[prošle] [subote] [u] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[prošli] dddd [u] LT';
+            }
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'za %s',
+        past   : 'prije %s',
+        s      : 'par sekundi',
+        m      : translate,
+        mm     : translate,
+        h      : translate,
+        hh     : translate,
+        d      : 'dan',
+        dd     : translate,
+        M      : 'mjesec',
+        MM     : translate,
+        y      : 'godinu',
+        yy     : translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Catalan [ca]
+//! author : Juan G. Hurtado : https://github.com/juanghurtado
+
+hooks.defineLocale('ca', {
+    months : 'gener_febrer_març_abril_maig_juny_juliol_agost_setembre_octubre_novembre_desembre'.split('_'),
+    monthsShort : 'gen._febr._mar._abr._mai._jun._jul._ag._set._oct._nov._des.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'diumenge_dilluns_dimarts_dimecres_dijous_divendres_dissabte'.split('_'),
+    weekdaysShort : 'dg._dl._dt._dc._dj._dv._ds.'.split('_'),
+    weekdaysMin : 'Dg_Dl_Dt_Dc_Dj_Dv_Ds'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY H:mm',
+        LLLL : 'dddd D MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay : function () {
+            return '[avui a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
+        },
+        nextDay : function () {
+            return '[demà a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
+        },
+        nextWeek : function () {
+            return 'dddd [a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
+        },
+        lastDay : function () {
+            return '[ahir a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
+        },
+        lastWeek : function () {
+            return '[el] dddd [passat a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'en %s',
+        past : 'fa %s',
+        s : 'uns segons',
+        m : 'un minut',
+        mm : '%d minuts',
+        h : 'una hora',
+        hh : '%d hores',
+        d : 'un dia',
+        dd : '%d dies',
+        M : 'un mes',
+        MM : '%d mesos',
+        y : 'un any',
+        yy : '%d anys'
+    },
+    ordinalParse: /\d{1,2}(r|n|t|è|a)/,
+    ordinal : function (number, period) {
+        var output = (number === 1) ? 'r' :
+            (number === 2) ? 'n' :
+            (number === 3) ? 'r' :
+            (number === 4) ? 't' : 'è';
+        if (period === 'w' || period === 'W') {
+            output = 'a';
+        }
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Czech [cs]
+//! author : petrbela : https://github.com/petrbela
+
+var months$3 = 'leden_únor_březen_duben_květen_červen_červenec_srpen_září_říjen_listopad_prosinec'.split('_');
+var monthsShort = 'led_úno_bře_dub_kvě_čvn_čvc_srp_zář_říj_lis_pro'.split('_');
+function plural$1(n) {
+    return (n > 1) && (n < 5) && (~~(n / 10) !== 1);
+}
+function translate$1(number, withoutSuffix, key, isFuture) {
+    var result = number + ' ';
+    switch (key) {
+        case 's':  // a few seconds / in a few seconds / a few seconds ago
+            return (withoutSuffix || isFuture) ? 'pár sekund' : 'pár sekundami';
+        case 'm':  // a minute / in a minute / a minute ago
+            return withoutSuffix ? 'minuta' : (isFuture ? 'minutu' : 'minutou');
+        case 'mm': // 9 minutes / in 9 minutes / 9 minutes ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural$1(number) ? 'minuty' : 'minut');
+            } else {
+                return result + 'minutami';
+            }
+            break;
+        case 'h':  // an hour / in an hour / an hour ago
+            return withoutSuffix ? 'hodina' : (isFuture ? 'hodinu' : 'hodinou');
+        case 'hh': // 9 hours / in 9 hours / 9 hours ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural$1(number) ? 'hodiny' : 'hodin');
+            } else {
+                return result + 'hodinami';
+            }
+            break;
+        case 'd':  // a day / in a day / a day ago
+            return (withoutSuffix || isFuture) ? 'den' : 'dnem';
+        case 'dd': // 9 days / in 9 days / 9 days ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural$1(number) ? 'dny' : 'dní');
+            } else {
+                return result + 'dny';
+            }
+            break;
+        case 'M':  // a month / in a month / a month ago
+            return (withoutSuffix || isFuture) ? 'měsíc' : 'měsícem';
+        case 'MM': // 9 months / in 9 months / 9 months ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural$1(number) ? 'měsíce' : 'měsíců');
+            } else {
+                return result + 'měsíci';
+            }
+            break;
+        case 'y':  // a year / in a year / a year ago
+            return (withoutSuffix || isFuture) ? 'rok' : 'rokem';
+        case 'yy': // 9 years / in 9 years / 9 years ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural$1(number) ? 'roky' : 'let');
+            } else {
+                return result + 'lety';
+            }
+            break;
+    }
+}
+
+hooks.defineLocale('cs', {
+    months : months$3,
+    monthsShort : monthsShort,
+    monthsParse : (function (months, monthsShort) {
+        var i, _monthsParse = [];
+        for (i = 0; i < 12; i++) {
+            // use custom parser to solve problem with July (červenec)
+            _monthsParse[i] = new RegExp('^' + months[i] + '$|^' + monthsShort[i] + '$', 'i');
+        }
+        return _monthsParse;
+    }(months$3, monthsShort)),
+    shortMonthsParse : (function (monthsShort) {
+        var i, _shortMonthsParse = [];
+        for (i = 0; i < 12; i++) {
+            _shortMonthsParse[i] = new RegExp('^' + monthsShort[i] + '$', 'i');
+        }
+        return _shortMonthsParse;
+    }(monthsShort)),
+    longMonthsParse : (function (months) {
+        var i, _longMonthsParse = [];
+        for (i = 0; i < 12; i++) {
+            _longMonthsParse[i] = new RegExp('^' + months[i] + '$', 'i');
+        }
+        return _longMonthsParse;
+    }(months$3)),
+    weekdays : 'neděle_pondělí_úterý_středa_čtvrtek_pátek_sobota'.split('_'),
+    weekdaysShort : 'ne_po_út_st_čt_pá_so'.split('_'),
+    weekdaysMin : 'ne_po_út_st_čt_pá_so'.split('_'),
+    longDateFormat : {
+        LT: 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY H:mm',
+        LLLL : 'dddd D. MMMM YYYY H:mm',
+        l : 'D. M. YYYY'
+    },
+    calendar : {
+        sameDay: '[dnes v] LT',
+        nextDay: '[zítra v] LT',
+        nextWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[v neděli v] LT';
+                case 1:
+                case 2:
+                    return '[v] dddd [v] LT';
+                case 3:
+                    return '[ve středu v] LT';
+                case 4:
+                    return '[ve čtvrtek v] LT';
+                case 5:
+                    return '[v pátek v] LT';
+                case 6:
+                    return '[v sobotu v] LT';
+            }
+        },
+        lastDay: '[včera v] LT',
+        lastWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[minulou neděli v] LT';
+                case 1:
+                case 2:
+                    return '[minulé] dddd [v] LT';
+                case 3:
+                    return '[minulou středu v] LT';
+                case 4:
+                case 5:
+                    return '[minulý] dddd [v] LT';
+                case 6:
+                    return '[minulou sobotu v] LT';
+            }
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'za %s',
+        past : 'před %s',
+        s : translate$1,
+        m : translate$1,
+        mm : translate$1,
+        h : translate$1,
+        hh : translate$1,
+        d : translate$1,
+        dd : translate$1,
+        M : translate$1,
+        MM : translate$1,
+        y : translate$1,
+        yy : translate$1
+    },
+    ordinalParse : /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Chuvash [cv]
+//! author : Anatoly Mironov : https://github.com/mirontoli
+
+hooks.defineLocale('cv', {
+    months : 'кӑрлач_нарӑс_пуш_ака_май_ҫӗртме_утӑ_ҫурла_авӑн_юпа_чӳк_раштав'.split('_'),
+    monthsShort : 'кӑр_нар_пуш_ака_май_ҫӗр_утӑ_ҫур_авн_юпа_чӳк_раш'.split('_'),
+    weekdays : 'вырсарникун_тунтикун_ытларикун_юнкун_кӗҫнерникун_эрнекун_шӑматкун'.split('_'),
+    weekdaysShort : 'выр_тун_ытл_юн_кӗҫ_эрн_шӑм'.split('_'),
+    weekdaysMin : 'вр_тн_ыт_юн_кҫ_эр_шм'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD-MM-YYYY',
+        LL : 'YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ]',
+        LLL : 'YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm',
+        LLLL : 'dddd, YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm'
+    },
+    calendar : {
+        sameDay: '[Паян] LT [сехетре]',
+        nextDay: '[Ыран] LT [сехетре]',
+        lastDay: '[Ӗнер] LT [сехетре]',
+        nextWeek: '[Ҫитес] dddd LT [сехетре]',
+        lastWeek: '[Иртнӗ] dddd LT [сехетре]',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : function (output) {
+            var affix = /сехет$/i.exec(output) ? 'рен' : /ҫул$/i.exec(output) ? 'тан' : 'ран';
+            return output + affix;
+        },
+        past : '%s каялла',
+        s : 'пӗр-ик ҫеккунт',
+        m : 'пӗр минут',
+        mm : '%d минут',
+        h : 'пӗр сехет',
+        hh : '%d сехет',
+        d : 'пӗр кун',
+        dd : '%d кун',
+        M : 'пӗр уйӑх',
+        MM : '%d уйӑх',
+        y : 'пӗр ҫул',
+        yy : '%d ҫул'
+    },
+    ordinalParse: /\d{1,2}-мӗш/,
+    ordinal : '%d-мӗш',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Welsh [cy]
+//! author : Robert Allen : https://github.com/robgallen
+//! author : https://github.com/ryangreaves
+
+hooks.defineLocale('cy', {
+    months: 'Ionawr_Chwefror_Mawrth_Ebrill_Mai_Mehefin_Gorffennaf_Awst_Medi_Hydref_Tachwedd_Rhagfyr'.split('_'),
+    monthsShort: 'Ion_Chwe_Maw_Ebr_Mai_Meh_Gor_Aws_Med_Hyd_Tach_Rhag'.split('_'),
+    weekdays: 'Dydd Sul_Dydd Llun_Dydd Mawrth_Dydd Mercher_Dydd Iau_Dydd Gwener_Dydd Sadwrn'.split('_'),
+    weekdaysShort: 'Sul_Llun_Maw_Mer_Iau_Gwe_Sad'.split('_'),
+    weekdaysMin: 'Su_Ll_Ma_Me_Ia_Gw_Sa'.split('_'),
+    weekdaysParseExact : true,
+    // time formats are the same as en-gb
+    longDateFormat: {
+        LT: 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L: 'DD/MM/YYYY',
+        LL: 'D MMMM YYYY',
+        LLL: 'D MMMM YYYY HH:mm',
+        LLLL: 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar: {
+        sameDay: '[Heddiw am] LT',
+        nextDay: '[Yfory am] LT',
+        nextWeek: 'dddd [am] LT',
+        lastDay: '[Ddoe am] LT',
+        lastWeek: 'dddd [diwethaf am] LT',
+        sameElse: 'L'
+    },
+    relativeTime: {
+        future: 'mewn %s',
+        past: '%s yn ôl',
+        s: 'ychydig eiliadau',
+        m: 'munud',
+        mm: '%d munud',
+        h: 'awr',
+        hh: '%d awr',
+        d: 'diwrnod',
+        dd: '%d diwrnod',
+        M: 'mis',
+        MM: '%d mis',
+        y: 'blwyddyn',
+        yy: '%d flynedd'
+    },
+    ordinalParse: /\d{1,2}(fed|ain|af|il|ydd|ed|eg)/,
+    // traditional ordinal numbers above 31 are not commonly used in colloquial Welsh
+    ordinal: function (number) {
+        var b = number,
+            output = '',
+            lookup = [
+                '', 'af', 'il', 'ydd', 'ydd', 'ed', 'ed', 'ed', 'fed', 'fed', 'fed', // 1af to 10fed
+                'eg', 'fed', 'eg', 'eg', 'fed', 'eg', 'eg', 'fed', 'eg', 'fed' // 11eg to 20fed
+            ];
+        if (b > 20) {
+            if (b === 40 || b === 50 || b === 60 || b === 80 || b === 100) {
+                output = 'fed'; // not 30ain, 70ain or 90ain
+            } else {
+                output = 'ain';
+            }
+        } else if (b > 0) {
+            output = lookup[b];
+        }
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Danish [da]
+//! author : Ulrik Nielsen : https://github.com/mrbase
+
+hooks.defineLocale('da', {
+    months : 'januar_februar_marts_april_maj_juni_juli_august_september_oktober_november_december'.split('_'),
+    monthsShort : 'jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec'.split('_'),
+    weekdays : 'søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag'.split('_'),
+    weekdaysShort : 'søn_man_tir_ons_tor_fre_lør'.split('_'),
+    weekdaysMin : 'sø_ma_ti_on_to_fr_lø'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY HH:mm',
+        LLLL : 'dddd [d.] D. MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[I dag kl.] LT',
+        nextDay : '[I morgen kl.] LT',
+        nextWeek : 'dddd [kl.] LT',
+        lastDay : '[I går kl.] LT',
+        lastWeek : '[sidste] dddd [kl] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'om %s',
+        past : '%s siden',
+        s : 'få sekunder',
+        m : 'et minut',
+        mm : '%d minutter',
+        h : 'en time',
+        hh : '%d timer',
+        d : 'en dag',
+        dd : '%d dage',
+        M : 'en måned',
+        MM : '%d måneder',
+        y : 'et år',
+        yy : '%d år'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : German (Austria) [de-at]
+//! author : lluchs : https://github.com/lluchs
+//! author: Menelion Elensúle: https://github.com/Oire
+//! author : Martin Groller : https://github.com/MadMG
+//! author : Mikolaj Dadela : https://github.com/mik01aj
+
+function processRelativeTime(number, withoutSuffix, key, isFuture) {
+    var format = {
+        'm': ['eine Minute', 'einer Minute'],
+        'h': ['eine Stunde', 'einer Stunde'],
+        'd': ['ein Tag', 'einem Tag'],
+        'dd': [number + ' Tage', number + ' Tagen'],
+        'M': ['ein Monat', 'einem Monat'],
+        'MM': [number + ' Monate', number + ' Monaten'],
+        'y': ['ein Jahr', 'einem Jahr'],
+        'yy': [number + ' Jahre', number + ' Jahren']
+    };
+    return withoutSuffix ? format[key][0] : format[key][1];
+}
+
+hooks.defineLocale('de-at', {
+    months : 'Jänner_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember'.split('_'),
+    monthsShort : 'Jän._Febr._Mrz._Apr._Mai_Jun._Jul._Aug._Sept._Okt._Nov._Dez.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag'.split('_'),
+    weekdaysShort : 'So._Mo._Di._Mi._Do._Fr._Sa.'.split('_'),
+    weekdaysMin : 'So_Mo_Di_Mi_Do_Fr_Sa'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT: 'HH:mm',
+        LTS: 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY HH:mm',
+        LLLL : 'dddd, D. MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[heute um] LT [Uhr]',
+        sameElse: 'L',
+        nextDay: '[morgen um] LT [Uhr]',
+        nextWeek: 'dddd [um] LT [Uhr]',
+        lastDay: '[gestern um] LT [Uhr]',
+        lastWeek: '[letzten] dddd [um] LT [Uhr]'
+    },
+    relativeTime : {
+        future : 'in %s',
+        past : 'vor %s',
+        s : 'ein paar Sekunden',
+        m : processRelativeTime,
+        mm : '%d Minuten',
+        h : processRelativeTime,
+        hh : '%d Stunden',
+        d : processRelativeTime,
+        dd : processRelativeTime,
+        M : processRelativeTime,
+        MM : processRelativeTime,
+        y : processRelativeTime,
+        yy : processRelativeTime
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : German [de]
+//! author : lluchs : https://github.com/lluchs
+//! author: Menelion Elensúle: https://github.com/Oire
+//! author : Mikolaj Dadela : https://github.com/mik01aj
+
+function processRelativeTime$1(number, withoutSuffix, key, isFuture) {
+    var format = {
+        'm': ['eine Minute', 'einer Minute'],
+        'h': ['eine Stunde', 'einer Stunde'],
+        'd': ['ein Tag', 'einem Tag'],
+        'dd': [number + ' Tage', number + ' Tagen'],
+        'M': ['ein Monat', 'einem Monat'],
+        'MM': [number + ' Monate', number + ' Monaten'],
+        'y': ['ein Jahr', 'einem Jahr'],
+        'yy': [number + ' Jahre', number + ' Jahren']
+    };
+    return withoutSuffix ? format[key][0] : format[key][1];
+}
+
+hooks.defineLocale('de', {
+    months : 'Januar_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember'.split('_'),
+    monthsShort : 'Jan._Febr._Mrz._Apr._Mai_Jun._Jul._Aug._Sept._Okt._Nov._Dez.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag'.split('_'),
+    weekdaysShort : 'So._Mo._Di._Mi._Do._Fr._Sa.'.split('_'),
+    weekdaysMin : 'So_Mo_Di_Mi_Do_Fr_Sa'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT: 'HH:mm',
+        LTS: 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY HH:mm',
+        LLLL : 'dddd, D. MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[heute um] LT [Uhr]',
+        sameElse: 'L',
+        nextDay: '[morgen um] LT [Uhr]',
+        nextWeek: 'dddd [um] LT [Uhr]',
+        lastDay: '[gestern um] LT [Uhr]',
+        lastWeek: '[letzten] dddd [um] LT [Uhr]'
+    },
+    relativeTime : {
+        future : 'in %s',
+        past : 'vor %s',
+        s : 'ein paar Sekunden',
+        m : processRelativeTime$1,
+        mm : '%d Minuten',
+        h : processRelativeTime$1,
+        hh : '%d Stunden',
+        d : processRelativeTime$1,
+        dd : processRelativeTime$1,
+        M : processRelativeTime$1,
+        MM : processRelativeTime$1,
+        y : processRelativeTime$1,
+        yy : processRelativeTime$1
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Maldivian [dv]
+//! author : Jawish Hameed : https://github.com/jawish
+
+var months$4 = [
+    'Þ–Þ¬Þ‚ÞªÞ‡Þ¦ÞƒÞ©',
+    'ÞŠÞ¬Þ„Þ°ÞƒÞªÞ‡Þ¦ÞƒÞ©',
+    'Þ‰Þ§ÞƒÞ¨Þ—Þª',
+    'އޭޕްރީލު',
+    'Þ‰Þ­',
+    'Þ–Þ«Þ‚Þ°',
+    'ޖުލައި',
+    'އޯގަސްޓު',
+    'ސެޕްޓެމްބަރު',
+    'Þ‡Þ®Þ†Þ°Þ“Þ¯Þ„Þ¦ÞƒÞª',
+    'Þ‚Þ®ÞˆÞ¬Þ‰Þ°Þ„Þ¦ÞƒÞª',
+    'ޑިސެމްބަރު'
+];
+var weekdays = [
+    'އާދިއްތަ',
+    'Þ€Þ¯Þ‰Þ¦',
+    'Þ‡Þ¦Þ‚Þ°ÞŽÞ§ÞƒÞ¦',
+    'Þ„ÞªÞ‹Þ¦',
+    'ބުރާސްފަތި',
+    'Þ€ÞªÞ†ÞªÞƒÞª',
+    'Þ€Þ®Þ‚Þ¨Þ€Þ¨ÞƒÞª'
+];
+
+hooks.defineLocale('dv', {
+    months : months$4,
+    monthsShort : months$4,
+    weekdays : weekdays,
+    weekdaysShort : weekdays,
+    weekdaysMin : 'Þ‡Þ§Þ‹Þ¨_Þ€Þ¯Þ‰Þ¦_Þ‡Þ¦Þ‚Þ°_Þ„ÞªÞ‹Þ¦_Þ„ÞªÞƒÞ§_Þ€ÞªÞ†Þª_Þ€Þ®Þ‚Þ¨'.split('_'),
+    longDateFormat : {
+
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'D/M/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    meridiemParse: /Þ‰Þ†|Þ‰ÞŠ/,
+    isPM : function (input) {
+        return 'Þ‰ÞŠ' === input;
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return 'Þ‰Þ†';
+        } else {
+            return 'Þ‰ÞŠ';
+        }
+    },
+    calendar : {
+        sameDay : '[Þ‰Þ¨Þ‡Þ¦Þ‹Þª] LT',
+        nextDay : '[Þ‰Þ§Þ‹Þ¦Þ‰Þ§] LT',
+        nextWeek : 'dddd LT',
+        lastDay : '[Þ‡Þ¨Þ‡Þ°Þ”Þ¬] LT',
+        lastWeek : '[ފާއިތުވި] dddd LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'ތެރޭގައި %s',
+        past : 'Þ†ÞªÞƒÞ¨Þ‚Þ° %s',
+        s : 'ސިކުންތުކޮޅެއް',
+        m : 'Þ‰Þ¨Þ‚Þ¨Þ“Þ¬Þ‡Þ°',
+        mm : 'Þ‰Þ¨Þ‚Þ¨Þ“Þª %d',
+        h : 'ÞŽÞ¦Þ‘Þ¨Þ‡Þ¨ÞƒÞ¬Þ‡Þ°',
+        hh : 'ÞŽÞ¦Þ‘Þ¨Þ‡Þ¨ÞƒÞª %d',
+        d : 'Þ‹ÞªÞˆÞ¦Þ€Þ¬Þ‡Þ°',
+        dd : 'ދުވަސް %d',
+        M : 'Þ‰Þ¦Þ€Þ¬Þ‡Þ°',
+        MM : 'މަސް %d',
+        y : 'Þ‡Þ¦Þ€Þ¦ÞƒÞ¬Þ‡Þ°',
+        yy : 'Þ‡Þ¦Þ€Þ¦ÞƒÞª %d'
+    },
+    preparse: function (string) {
+        return string.replace(/،/g, ',');
+    },
+    postformat: function (string) {
+        return string.replace(/,/g, '،');
+    },
+    week : {
+        dow : 7,  // Sunday is the first day of the week.
+        doy : 12  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Greek [el]
+//! author : Aggelos Karalias : https://github.com/mehiel
+
+hooks.defineLocale('el', {
+    monthsNominativeEl : 'Ιανουάριος_Φεβρουάριος_Μάρτιος_Απρίλιος_Μάιος_Ιούνιος_Ιούλιος_Αύγουστος_Σεπτέμβριος_Οκτώβριος_Νοέμβριος_Δεκέμβριος'.split('_'),
+    monthsGenitiveEl : 'Ιανουαρίου_Φεβρουαρίου_Μαρτίου_Απριλίου_Μαΐου_Ιουνίου_Ιουλίου_Αυγούστου_Σεπτεμβρίου_Οκτωβρίου_Νοεμβρίου_Δεκεμβρίου'.split('_'),
+    months : function (momentToFormat, format) {
+        if (/D/.test(format.substring(0, format.indexOf('MMMM')))) { // if there is a day number before 'MMMM'
+            return this._monthsGenitiveEl[momentToFormat.month()];
+        } else {
+            return this._monthsNominativeEl[momentToFormat.month()];
+        }
+    },
+    monthsShort : 'Ιαν_Φεβ_Μαρ_Απρ_Μαϊ_Ιουν_Ιουλ_Αυγ_Σεπ_Οκτ_Νοε_Δεκ'.split('_'),
+    weekdays : 'Κυριακή_Δευτέρα_Τρίτη_Τετάρτη_Πέμπτη_Παρασκευή_Σάββατο'.split('_'),
+    weekdaysShort : 'Κυρ_Δευ_Τρι_Τετ_Πεμ_Παρ_Σαβ'.split('_'),
+    weekdaysMin : 'Κυ_Δε_Τρ_Τε_Πε_Πα_Σα'.split('_'),
+    meridiem : function (hours, minutes, isLower) {
+        if (hours > 11) {
+            return isLower ? 'μμ' : 'ΜΜ';
+        } else {
+            return isLower ? 'πμ' : 'ΠΜ';
+        }
+    },
+    isPM : function (input) {
+        return ((input + '').toLowerCase()[0] === 'μ');
+    },
+    meridiemParse : /[ΠΜ]\.?Μ?\.?/i,
+    longDateFormat : {
+        LT : 'h:mm A',
+        LTS : 'h:mm:ss A',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY h:mm A',
+        LLLL : 'dddd, D MMMM YYYY h:mm A'
+    },
+    calendarEl : {
+        sameDay : '[Σήμερα {}] LT',
+        nextDay : '[Αύριο {}] LT',
+        nextWeek : 'dddd [{}] LT',
+        lastDay : '[Χθες {}] LT',
+        lastWeek : function () {
+            switch (this.day()) {
+                case 6:
+                    return '[το προηγούμενο] dddd [{}] LT';
+                default:
+                    return '[την προηγούμενη] dddd [{}] LT';
+            }
+        },
+        sameElse : 'L'
+    },
+    calendar : function (key, mom) {
+        var output = this._calendarEl[key],
+            hours = mom && mom.hours();
+        if (isFunction(output)) {
+            output = output.apply(mom);
+        }
+        return output.replace('{}', (hours % 12 === 1 ? 'στη' : 'στις'));
+    },
+    relativeTime : {
+        future : 'σε %s',
+        past : '%s πριν',
+        s : 'λίγα δευτερόλεπτα',
+        m : 'ένα λεπτό',
+        mm : '%d λεπτά',
+        h : 'μία ώρα',
+        hh : '%d ώρες',
+        d : 'μία μέρα',
+        dd : '%d μέρες',
+        M : 'ένας μήνας',
+        MM : '%d μήνες',
+        y : 'ένας χρόνος',
+        yy : '%d χρόνια'
+    },
+    ordinalParse: /\d{1,2}η/,
+    ordinal: '%dη',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : English (Australia) [en-au]
+//! author : Jared Morse : https://github.com/jarcoal
+
+hooks.defineLocale('en-au', {
+    months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),
+    monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),
+    weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
+    weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
+    weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'h:mm A',
+        LTS : 'h:mm:ss A',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY h:mm A',
+        LLLL : 'dddd, D MMMM YYYY h:mm A'
+    },
+    calendar : {
+        sameDay : '[Today at] LT',
+        nextDay : '[Tomorrow at] LT',
+        nextWeek : 'dddd [at] LT',
+        lastDay : '[Yesterday at] LT',
+        lastWeek : '[Last] dddd [at] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'in %s',
+        past : '%s ago',
+        s : 'a few seconds',
+        m : 'a minute',
+        mm : '%d minutes',
+        h : 'an hour',
+        hh : '%d hours',
+        d : 'a day',
+        dd : '%d days',
+        M : 'a month',
+        MM : '%d months',
+        y : 'a year',
+        yy : '%d years'
+    },
+    ordinalParse: /\d{1,2}(st|nd|rd|th)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : English (Canada) [en-ca]
+//! author : Jonathan Abourbih : https://github.com/jonbca
+
+hooks.defineLocale('en-ca', {
+    months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),
+    monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),
+    weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
+    weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
+    weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'h:mm A',
+        LTS : 'h:mm:ss A',
+        L : 'YYYY-MM-DD',
+        LL : 'MMMM D, YYYY',
+        LLL : 'MMMM D, YYYY h:mm A',
+        LLLL : 'dddd, MMMM D, YYYY h:mm A'
+    },
+    calendar : {
+        sameDay : '[Today at] LT',
+        nextDay : '[Tomorrow at] LT',
+        nextWeek : 'dddd [at] LT',
+        lastDay : '[Yesterday at] LT',
+        lastWeek : '[Last] dddd [at] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'in %s',
+        past : '%s ago',
+        s : 'a few seconds',
+        m : 'a minute',
+        mm : '%d minutes',
+        h : 'an hour',
+        hh : '%d hours',
+        d : 'a day',
+        dd : '%d days',
+        M : 'a month',
+        MM : '%d months',
+        y : 'a year',
+        yy : '%d years'
+    },
+    ordinalParse: /\d{1,2}(st|nd|rd|th)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    }
+});
+
+//! moment.js locale configuration
+//! locale : English (United Kingdom) [en-gb]
+//! author : Chris Gedrim : https://github.com/chrisgedrim
+
+hooks.defineLocale('en-gb', {
+    months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),
+    monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),
+    weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
+    weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
+    weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[Today at] LT',
+        nextDay : '[Tomorrow at] LT',
+        nextWeek : 'dddd [at] LT',
+        lastDay : '[Yesterday at] LT',
+        lastWeek : '[Last] dddd [at] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'in %s',
+        past : '%s ago',
+        s : 'a few seconds',
+        m : 'a minute',
+        mm : '%d minutes',
+        h : 'an hour',
+        hh : '%d hours',
+        d : 'a day',
+        dd : '%d days',
+        M : 'a month',
+        MM : '%d months',
+        y : 'a year',
+        yy : '%d years'
+    },
+    ordinalParse: /\d{1,2}(st|nd|rd|th)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : English (Ireland) [en-ie]
+//! author : Chris Cartlidge : https://github.com/chriscartlidge
+
+hooks.defineLocale('en-ie', {
+    months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),
+    monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),
+    weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
+    weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
+    weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD-MM-YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[Today at] LT',
+        nextDay : '[Tomorrow at] LT',
+        nextWeek : 'dddd [at] LT',
+        lastDay : '[Yesterday at] LT',
+        lastWeek : '[Last] dddd [at] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'in %s',
+        past : '%s ago',
+        s : 'a few seconds',
+        m : 'a minute',
+        mm : '%d minutes',
+        h : 'an hour',
+        hh : '%d hours',
+        d : 'a day',
+        dd : '%d days',
+        M : 'a month',
+        MM : '%d months',
+        y : 'a year',
+        yy : '%d years'
+    },
+    ordinalParse: /\d{1,2}(st|nd|rd|th)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : English (New Zealand) [en-nz]
+//! author : Luke McGregor : https://github.com/lukemcgregor
+
+hooks.defineLocale('en-nz', {
+    months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),
+    monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),
+    weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
+    weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
+    weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'h:mm A',
+        LTS : 'h:mm:ss A',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY h:mm A',
+        LLLL : 'dddd, D MMMM YYYY h:mm A'
+    },
+    calendar : {
+        sameDay : '[Today at] LT',
+        nextDay : '[Tomorrow at] LT',
+        nextWeek : 'dddd [at] LT',
+        lastDay : '[Yesterday at] LT',
+        lastWeek : '[Last] dddd [at] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'in %s',
+        past : '%s ago',
+        s : 'a few seconds',
+        m : 'a minute',
+        mm : '%d minutes',
+        h : 'an hour',
+        hh : '%d hours',
+        d : 'a day',
+        dd : '%d days',
+        M : 'a month',
+        MM : '%d months',
+        y : 'a year',
+        yy : '%d years'
+    },
+    ordinalParse: /\d{1,2}(st|nd|rd|th)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Esperanto [eo]
+//! author : Colin Dean : https://github.com/colindean
+//! komento: Mi estas malcerta se mi korekte traktis akuzativojn en tiu traduko.
+//!          Se ne, bonvolu korekti kaj avizi min por ke mi povas lerni!
+
+hooks.defineLocale('eo', {
+    months : 'januaro_februaro_marto_aprilo_majo_junio_julio_aÅ­gusto_septembro_oktobro_novembro_decembro'.split('_'),
+    monthsShort : 'jan_feb_mar_apr_maj_jun_jul_aÅ­g_sep_okt_nov_dec'.split('_'),
+    weekdays : 'Dimanĉo_Lundo_Mardo_Merkredo_Ĵaŭdo_Vendredo_Sabato'.split('_'),
+    weekdaysShort : 'Dim_Lun_Mard_Merk_Ä´aÅ­_Ven_Sab'.split('_'),
+    weekdaysMin : 'Di_Lu_Ma_Me_Ä´a_Ve_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'YYYY-MM-DD',
+        LL : 'D[-an de] MMMM, YYYY',
+        LLL : 'D[-an de] MMMM, YYYY HH:mm',
+        LLLL : 'dddd, [la] D[-an de] MMMM, YYYY HH:mm'
+    },
+    meridiemParse: /[ap]\.t\.m/i,
+    isPM: function (input) {
+        return input.charAt(0).toLowerCase() === 'p';
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours > 11) {
+            return isLower ? 'p.t.m.' : 'P.T.M.';
+        } else {
+            return isLower ? 'a.t.m.' : 'A.T.M.';
+        }
+    },
+    calendar : {
+        sameDay : '[HodiaÅ­ je] LT',
+        nextDay : '[MorgaÅ­ je] LT',
+        nextWeek : 'dddd [je] LT',
+        lastDay : '[HieraÅ­ je] LT',
+        lastWeek : '[pasinta] dddd [je] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'je %s',
+        past : 'antaÅ­ %s',
+        s : 'sekundoj',
+        m : 'minuto',
+        mm : '%d minutoj',
+        h : 'horo',
+        hh : '%d horoj',
+        d : 'tago',//ne 'diurno', ĉar estas uzita por proksimumo
+        dd : '%d tagoj',
+        M : 'monato',
+        MM : '%d monatoj',
+        y : 'jaro',
+        yy : '%d jaroj'
+    },
+    ordinalParse: /\d{1,2}a/,
+    ordinal : '%da',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Spanish (Dominican Republic) [es-do]
+
+var monthsShortDot = 'ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.'.split('_');
+var monthsShort$1 = 'ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic'.split('_');
+
+hooks.defineLocale('es-do', {
+    months : 'enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre'.split('_'),
+    monthsShort : function (m, format) {
+        if (/-MMM-/.test(format)) {
+            return monthsShort$1[m.month()];
+        } else {
+            return monthsShortDot[m.month()];
+        }
+    },
+    monthsParseExact : true,
+    weekdays : 'domingo_lunes_martes_miércoles_jueves_viernes_sábado'.split('_'),
+    weekdaysShort : 'dom._lun._mar._mié._jue._vie._sáb.'.split('_'),
+    weekdaysMin : 'do_lu_ma_mi_ju_vi_sá'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'h:mm A',
+        LTS : 'h:mm:ss A',
+        L : 'DD/MM/YYYY',
+        LL : 'D [de] MMMM [de] YYYY',
+        LLL : 'D [de] MMMM [de] YYYY h:mm A',
+        LLLL : 'dddd, D [de] MMMM [de] YYYY h:mm A'
+    },
+    calendar : {
+        sameDay : function () {
+            return '[hoy a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        nextDay : function () {
+            return '[mañana a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        nextWeek : function () {
+            return 'dddd [a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        lastDay : function () {
+            return '[ayer a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        lastWeek : function () {
+            return '[el] dddd [pasado a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'en %s',
+        past : 'hace %s',
+        s : 'unos segundos',
+        m : 'un minuto',
+        mm : '%d minutos',
+        h : 'una hora',
+        hh : '%d horas',
+        d : 'un día',
+        dd : '%d días',
+        M : 'un mes',
+        MM : '%d meses',
+        y : 'un año',
+        yy : '%d años'
+    },
+    ordinalParse : /\d{1,2}º/,
+    ordinal : '%dº',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Spanish [es]
+//! author : Julio Napurí : https://github.com/julionc
+
+var monthsShortDot$1 = 'ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.'.split('_');
+var monthsShort$2 = 'ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic'.split('_');
+
+hooks.defineLocale('es', {
+    months : 'enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre'.split('_'),
+    monthsShort : function (m, format) {
+        if (/-MMM-/.test(format)) {
+            return monthsShort$2[m.month()];
+        } else {
+            return monthsShortDot$1[m.month()];
+        }
+    },
+    monthsParseExact : true,
+    weekdays : 'domingo_lunes_martes_miércoles_jueves_viernes_sábado'.split('_'),
+    weekdaysShort : 'dom._lun._mar._mié._jue._vie._sáb.'.split('_'),
+    weekdaysMin : 'do_lu_ma_mi_ju_vi_sá'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D [de] MMMM [de] YYYY',
+        LLL : 'D [de] MMMM [de] YYYY H:mm',
+        LLLL : 'dddd, D [de] MMMM [de] YYYY H:mm'
+    },
+    calendar : {
+        sameDay : function () {
+            return '[hoy a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        nextDay : function () {
+            return '[mañana a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        nextWeek : function () {
+            return 'dddd [a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        lastDay : function () {
+            return '[ayer a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        lastWeek : function () {
+            return '[el] dddd [pasado a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'en %s',
+        past : 'hace %s',
+        s : 'unos segundos',
+        m : 'un minuto',
+        mm : '%d minutos',
+        h : 'una hora',
+        hh : '%d horas',
+        d : 'un día',
+        dd : '%d días',
+        M : 'un mes',
+        MM : '%d meses',
+        y : 'un año',
+        yy : '%d años'
+    },
+    ordinalParse : /\d{1,2}º/,
+    ordinal : '%dº',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Estonian [et]
+//! author : Henry Kehlmann : https://github.com/madhenry
+//! improvements : Illimar Tambek : https://github.com/ragulka
+
+function processRelativeTime$2(number, withoutSuffix, key, isFuture) {
+    var format = {
+        's' : ['mõne sekundi', 'mõni sekund', 'paar sekundit'],
+        'm' : ['ühe minuti', 'üks minut'],
+        'mm': [number + ' minuti', number + ' minutit'],
+        'h' : ['ühe tunni', 'tund aega', 'üks tund'],
+        'hh': [number + ' tunni', number + ' tundi'],
+        'd' : ['ühe päeva', 'üks päev'],
+        'M' : ['kuu aja', 'kuu aega', 'üks kuu'],
+        'MM': [number + ' kuu', number + ' kuud'],
+        'y' : ['ühe aasta', 'aasta', 'üks aasta'],
+        'yy': [number + ' aasta', number + ' aastat']
+    };
+    if (withoutSuffix) {
+        return format[key][2] ? format[key][2] : format[key][1];
+    }
+    return isFuture ? format[key][0] : format[key][1];
+}
+
+hooks.defineLocale('et', {
+    months        : 'jaanuar_veebruar_märts_aprill_mai_juuni_juuli_august_september_oktoober_november_detsember'.split('_'),
+    monthsShort   : 'jaan_veebr_märts_apr_mai_juuni_juuli_aug_sept_okt_nov_dets'.split('_'),
+    weekdays      : 'pühapäev_esmaspäev_teisipäev_kolmapäev_neljapäev_reede_laupäev'.split('_'),
+    weekdaysShort : 'P_E_T_K_N_R_L'.split('_'),
+    weekdaysMin   : 'P_E_T_K_N_R_L'.split('_'),
+    longDateFormat : {
+        LT   : 'H:mm',
+        LTS : 'H:mm:ss',
+        L    : 'DD.MM.YYYY',
+        LL   : 'D. MMMM YYYY',
+        LLL  : 'D. MMMM YYYY H:mm',
+        LLLL : 'dddd, D. MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay  : '[Täna,] LT',
+        nextDay  : '[Homme,] LT',
+        nextWeek : '[Järgmine] dddd LT',
+        lastDay  : '[Eile,] LT',
+        lastWeek : '[Eelmine] dddd LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s pärast',
+        past   : '%s tagasi',
+        s      : processRelativeTime$2,
+        m      : processRelativeTime$2,
+        mm     : processRelativeTime$2,
+        h      : processRelativeTime$2,
+        hh     : processRelativeTime$2,
+        d      : processRelativeTime$2,
+        dd     : '%d päeva',
+        M      : processRelativeTime$2,
+        MM     : processRelativeTime$2,
+        y      : processRelativeTime$2,
+        yy     : processRelativeTime$2
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Basque [eu]
+//! author : Eneko Illarramendi : https://github.com/eillarra
+
+hooks.defineLocale('eu', {
+    months : 'urtarrila_otsaila_martxoa_apirila_maiatza_ekaina_uztaila_abuztua_iraila_urria_azaroa_abendua'.split('_'),
+    monthsShort : 'urt._ots._mar._api._mai._eka._uzt._abu._ira._urr._aza._abe.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'igandea_astelehena_asteartea_asteazkena_osteguna_ostirala_larunbata'.split('_'),
+    weekdaysShort : 'ig._al._ar._az._og._ol._lr.'.split('_'),
+    weekdaysMin : 'ig_al_ar_az_og_ol_lr'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'YYYY-MM-DD',
+        LL : 'YYYY[ko] MMMM[ren] D[a]',
+        LLL : 'YYYY[ko] MMMM[ren] D[a] HH:mm',
+        LLLL : 'dddd, YYYY[ko] MMMM[ren] D[a] HH:mm',
+        l : 'YYYY-M-D',
+        ll : 'YYYY[ko] MMM D[a]',
+        lll : 'YYYY[ko] MMM D[a] HH:mm',
+        llll : 'ddd, YYYY[ko] MMM D[a] HH:mm'
+    },
+    calendar : {
+        sameDay : '[gaur] LT[etan]',
+        nextDay : '[bihar] LT[etan]',
+        nextWeek : 'dddd LT[etan]',
+        lastDay : '[atzo] LT[etan]',
+        lastWeek : '[aurreko] dddd LT[etan]',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s barru',
+        past : 'duela %s',
+        s : 'segundo batzuk',
+        m : 'minutu bat',
+        mm : '%d minutu',
+        h : 'ordu bat',
+        hh : '%d ordu',
+        d : 'egun bat',
+        dd : '%d egun',
+        M : 'hilabete bat',
+        MM : '%d hilabete',
+        y : 'urte bat',
+        yy : '%d urte'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Persian [fa]
+//! author : Ebrahim Byagowi : https://github.com/ebraminio
+
+var symbolMap$5 = {
+    '1': 'Û±',
+    '2': 'Û²',
+    '3': 'Û³',
+    '4': 'Û´',
+    '5': 'Ûµ',
+    '6': 'Û¶',
+    '7': 'Û·',
+    '8': 'Û¸',
+    '9': 'Û¹',
+    '0': 'Û°'
+};
+var numberMap$4 = {
+    'Û±': '1',
+    'Û²': '2',
+    'Û³': '3',
+    'Û´': '4',
+    'Ûµ': '5',
+    'Û¶': '6',
+    'Û·': '7',
+    'Û¸': '8',
+    'Û¹': '9',
+    'Û°': '0'
+};
+
+hooks.defineLocale('fa', {
+    months : 'ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر'.split('_'),
+    monthsShort : 'ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر'.split('_'),
+    weekdays : 'یک\u200cشنبه_دوشنبه_سه\u200cشنبه_چهارشنبه_پنج\u200cشنبه_جمعه_شنبه'.split('_'),
+    weekdaysShort : 'یک\u200cشنبه_دوشنبه_سه\u200cشنبه_چهارشنبه_پنج\u200cشنبه_جمعه_شنبه'.split('_'),
+    weekdaysMin : 'ی_د_س_چ_پ_ج_ش'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    meridiemParse: /قبل از ظهر|بعد از ظهر/,
+    isPM: function (input) {
+        return /بعد از ظهر/.test(input);
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return 'قبل از ظهر';
+        } else {
+            return 'بعد از ظهر';
+        }
+    },
+    calendar : {
+        sameDay : '[امروز ساعت] LT',
+        nextDay : '[فردا ساعت] LT',
+        nextWeek : 'dddd [ساعت] LT',
+        lastDay : '[دیروز ساعت] LT',
+        lastWeek : 'dddd [پیش] [ساعت] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'در %s',
+        past : '%s پیش',
+        s : 'چندین ثانیه',
+        m : 'یک دقیقه',
+        mm : '%d دقیقه',
+        h : 'یک ساعت',
+        hh : '%d ساعت',
+        d : 'یک روز',
+        dd : '%d روز',
+        M : 'یک ماه',
+        MM : '%d ماه',
+        y : 'یک سال',
+        yy : '%d سال'
+    },
+    preparse: function (string) {
+        return string.replace(/[Û°-Û¹]/g, function (match) {
+            return numberMap$4[match];
+        }).replace(/،/g, ',');
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap$5[match];
+        }).replace(/,/g, '،');
+    },
+    ordinalParse: /\d{1,2}Ù…/,
+    ordinal : '%dÙ…',
+    week : {
+        dow : 6, // Saturday is the first day of the week.
+        doy : 12 // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Finnish [fi]
+//! author : Tarmo Aidantausta : https://github.com/bleadof
+
+var numbersPast = 'nolla yksi kaksi kolme neljä viisi kuusi seitsemän kahdeksan yhdeksän'.split(' ');
+var numbersFuture = [
+        'nolla', 'yhden', 'kahden', 'kolmen', 'neljän', 'viiden', 'kuuden',
+        numbersPast[7], numbersPast[8], numbersPast[9]
+    ];
+function translate$2(number, withoutSuffix, key, isFuture) {
+    var result = '';
+    switch (key) {
+        case 's':
+            return isFuture ? 'muutaman sekunnin' : 'muutama sekunti';
+        case 'm':
+            return isFuture ? 'minuutin' : 'minuutti';
+        case 'mm':
+            result = isFuture ? 'minuutin' : 'minuuttia';
+            break;
+        case 'h':
+            return isFuture ? 'tunnin' : 'tunti';
+        case 'hh':
+            result = isFuture ? 'tunnin' : 'tuntia';
+            break;
+        case 'd':
+            return isFuture ? 'päivän' : 'päivä';
+        case 'dd':
+            result = isFuture ? 'päivän' : 'päivää';
+            break;
+        case 'M':
+            return isFuture ? 'kuukauden' : 'kuukausi';
+        case 'MM':
+            result = isFuture ? 'kuukauden' : 'kuukautta';
+            break;
+        case 'y':
+            return isFuture ? 'vuoden' : 'vuosi';
+        case 'yy':
+            result = isFuture ? 'vuoden' : 'vuotta';
+            break;
+    }
+    result = verbalNumber(number, isFuture) + ' ' + result;
+    return result;
+}
+function verbalNumber(number, isFuture) {
+    return number < 10 ? (isFuture ? numbersFuture[number] : numbersPast[number]) : number;
+}
+
+hooks.defineLocale('fi', {
+    months : 'tammikuu_helmikuu_maaliskuu_huhtikuu_toukokuu_kesäkuu_heinäkuu_elokuu_syyskuu_lokakuu_marraskuu_joulukuu'.split('_'),
+    monthsShort : 'tammi_helmi_maalis_huhti_touko_kesä_heinä_elo_syys_loka_marras_joulu'.split('_'),
+    weekdays : 'sunnuntai_maanantai_tiistai_keskiviikko_torstai_perjantai_lauantai'.split('_'),
+    weekdaysShort : 'su_ma_ti_ke_to_pe_la'.split('_'),
+    weekdaysMin : 'su_ma_ti_ke_to_pe_la'.split('_'),
+    longDateFormat : {
+        LT : 'HH.mm',
+        LTS : 'HH.mm.ss',
+        L : 'DD.MM.YYYY',
+        LL : 'Do MMMM[ta] YYYY',
+        LLL : 'Do MMMM[ta] YYYY, [klo] HH.mm',
+        LLLL : 'dddd, Do MMMM[ta] YYYY, [klo] HH.mm',
+        l : 'D.M.YYYY',
+        ll : 'Do MMM YYYY',
+        lll : 'Do MMM YYYY, [klo] HH.mm',
+        llll : 'ddd, Do MMM YYYY, [klo] HH.mm'
+    },
+    calendar : {
+        sameDay : '[tänään] [klo] LT',
+        nextDay : '[huomenna] [klo] LT',
+        nextWeek : 'dddd [klo] LT',
+        lastDay : '[eilen] [klo] LT',
+        lastWeek : '[viime] dddd[na] [klo] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s päästä',
+        past : '%s sitten',
+        s : translate$2,
+        m : translate$2,
+        mm : translate$2,
+        h : translate$2,
+        hh : translate$2,
+        d : translate$2,
+        dd : translate$2,
+        M : translate$2,
+        MM : translate$2,
+        y : translate$2,
+        yy : translate$2
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Faroese [fo]
+//! author : Ragnar Johannesen : https://github.com/ragnar123
+
+hooks.defineLocale('fo', {
+    months : 'januar_februar_mars_apríl_mai_juni_juli_august_september_oktober_november_desember'.split('_'),
+    monthsShort : 'jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_'),
+    weekdays : 'sunnudagur_mánadagur_týsdagur_mikudagur_hósdagur_fríggjadagur_leygardagur'.split('_'),
+    weekdaysShort : 'sun_mán_týs_mik_hós_frí_ley'.split('_'),
+    weekdaysMin : 'su_má_tý_mi_hó_fr_le'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D. MMMM, YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[Í dag kl.] LT',
+        nextDay : '[Í morgin kl.] LT',
+        nextWeek : 'dddd [kl.] LT',
+        lastDay : '[Í gjár kl.] LT',
+        lastWeek : '[síðstu] dddd [kl] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'um %s',
+        past : '%s síðani',
+        s : 'fá sekund',
+        m : 'ein minutt',
+        mm : '%d minuttir',
+        h : 'ein tími',
+        hh : '%d tímar',
+        d : 'ein dagur',
+        dd : '%d dagar',
+        M : 'ein mánaði',
+        MM : '%d mánaðir',
+        y : 'eitt ár',
+        yy : '%d ár'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : French (Canada) [fr-ca]
+//! author : Jonathan Abourbih : https://github.com/jonbca
+
+hooks.defineLocale('fr-ca', {
+    months : 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split('_'),
+    monthsShort : 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'),
+    weekdaysShort : 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'),
+    weekdaysMin : 'Di_Lu_Ma_Me_Je_Ve_Sa'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'YYYY-MM-DD',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Aujourd\'hui à] LT',
+        nextDay: '[Demain à] LT',
+        nextWeek: 'dddd [à] LT',
+        lastDay: '[Hier à] LT',
+        lastWeek: 'dddd [dernier à] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'dans %s',
+        past : 'il y a %s',
+        s : 'quelques secondes',
+        m : 'une minute',
+        mm : '%d minutes',
+        h : 'une heure',
+        hh : '%d heures',
+        d : 'un jour',
+        dd : '%d jours',
+        M : 'un mois',
+        MM : '%d mois',
+        y : 'un an',
+        yy : '%d ans'
+    },
+    ordinalParse: /\d{1,2}(er|e)/,
+    ordinal : function (number) {
+        return number + (number === 1 ? 'er' : 'e');
+    }
+});
+
+//! moment.js locale configuration
+//! locale : French (Switzerland) [fr-ch]
+//! author : Gaspard Bucher : https://github.com/gaspard
+
+hooks.defineLocale('fr-ch', {
+    months : 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split('_'),
+    monthsShort : 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'),
+    weekdaysShort : 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'),
+    weekdaysMin : 'Di_Lu_Ma_Me_Je_Ve_Sa'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Aujourd\'hui à] LT',
+        nextDay: '[Demain à] LT',
+        nextWeek: 'dddd [à] LT',
+        lastDay: '[Hier à] LT',
+        lastWeek: 'dddd [dernier à] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'dans %s',
+        past : 'il y a %s',
+        s : 'quelques secondes',
+        m : 'une minute',
+        mm : '%d minutes',
+        h : 'une heure',
+        hh : '%d heures',
+        d : 'un jour',
+        dd : '%d jours',
+        M : 'un mois',
+        MM : '%d mois',
+        y : 'un an',
+        yy : '%d ans'
+    },
+    ordinalParse: /\d{1,2}(er|e)/,
+    ordinal : function (number) {
+        return number + (number === 1 ? 'er' : 'e');
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : French [fr]
+//! author : John Fischer : https://github.com/jfroffice
+
+hooks.defineLocale('fr', {
+    months : 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split('_'),
+    monthsShort : 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'),
+    weekdaysShort : 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'),
+    weekdaysMin : 'Di_Lu_Ma_Me_Je_Ve_Sa'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Aujourd\'hui à] LT',
+        nextDay: '[Demain à] LT',
+        nextWeek: 'dddd [à] LT',
+        lastDay: '[Hier à] LT',
+        lastWeek: 'dddd [dernier à] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'dans %s',
+        past : 'il y a %s',
+        s : 'quelques secondes',
+        m : 'une minute',
+        mm : '%d minutes',
+        h : 'une heure',
+        hh : '%d heures',
+        d : 'un jour',
+        dd : '%d jours',
+        M : 'un mois',
+        MM : '%d mois',
+        y : 'un an',
+        yy : '%d ans'
+    },
+    ordinalParse: /\d{1,2}(er|)/,
+    ordinal : function (number) {
+        return number + (number === 1 ? 'er' : '');
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Frisian [fy]
+//! author : Robin van der Vliet : https://github.com/robin0van0der0v
+
+var monthsShortWithDots = 'jan._feb._mrt._apr._mai_jun._jul._aug._sep._okt._nov._des.'.split('_');
+var monthsShortWithoutDots = 'jan_feb_mrt_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_');
+
+hooks.defineLocale('fy', {
+    months : 'jannewaris_febrewaris_maart_april_maaie_juny_july_augustus_septimber_oktober_novimber_desimber'.split('_'),
+    monthsShort : function (m, format) {
+        if (/-MMM-/.test(format)) {
+            return monthsShortWithoutDots[m.month()];
+        } else {
+            return monthsShortWithDots[m.month()];
+        }
+    },
+    monthsParseExact : true,
+    weekdays : 'snein_moandei_tiisdei_woansdei_tongersdei_freed_sneon'.split('_'),
+    weekdaysShort : 'si._mo._ti._wo._to._fr._so.'.split('_'),
+    weekdaysMin : 'Si_Mo_Ti_Wo_To_Fr_So'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD-MM-YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[hjoed om] LT',
+        nextDay: '[moarn om] LT',
+        nextWeek: 'dddd [om] LT',
+        lastDay: '[juster om] LT',
+        lastWeek: '[ôfrûne] dddd [om] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'oer %s',
+        past : '%s lyn',
+        s : 'in pear sekonden',
+        m : 'ien minút',
+        mm : '%d minuten',
+        h : 'ien oere',
+        hh : '%d oeren',
+        d : 'ien dei',
+        dd : '%d dagen',
+        M : 'ien moanne',
+        MM : '%d moannen',
+        y : 'ien jier',
+        yy : '%d jierren'
+    },
+    ordinalParse: /\d{1,2}(ste|de)/,
+    ordinal : function (number) {
+        return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de');
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Scottish Gaelic [gd]
+//! author : Jon Ashdown : https://github.com/jonashdown
+
+var months$5 = [
+    'Am Faoilleach', 'An Gearran', 'Am Màrt', 'An Giblean', 'An Cèitean', 'An t-Ògmhios', 'An t-Iuchar', 'An Lùnastal', 'An t-Sultain', 'An Dàmhair', 'An t-Samhain', 'An Dùbhlachd'
+];
+
+var monthsShort$3 = ['Faoi', 'Gear', 'Màrt', 'Gibl', 'Cèit', 'Ògmh', 'Iuch', 'Lùn', 'Sult', 'Dàmh', 'Samh', 'Dùbh'];
+
+var weekdays$1 = ['Didòmhnaich', 'Diluain', 'Dimàirt', 'Diciadain', 'Diardaoin', 'Dihaoine', 'Disathairne'];
+
+var weekdaysShort = ['Did', 'Dil', 'Dim', 'Dic', 'Dia', 'Dih', 'Dis'];
+
+var weekdaysMin = ['Dò', 'Lu', 'Mà', 'Ci', 'Ar', 'Ha', 'Sa'];
+
+hooks.defineLocale('gd', {
+    months : months$5,
+    monthsShort : monthsShort$3,
+    monthsParseExact : true,
+    weekdays : weekdays$1,
+    weekdaysShort : weekdaysShort,
+    weekdaysMin : weekdaysMin,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[An-diugh aig] LT',
+        nextDay : '[A-màireach aig] LT',
+        nextWeek : 'dddd [aig] LT',
+        lastDay : '[An-dè aig] LT',
+        lastWeek : 'dddd [seo chaidh] [aig] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'ann an %s',
+        past : 'bho chionn %s',
+        s : 'beagan diogan',
+        m : 'mionaid',
+        mm : '%d mionaidean',
+        h : 'uair',
+        hh : '%d uairean',
+        d : 'latha',
+        dd : '%d latha',
+        M : 'mìos',
+        MM : '%d mìosan',
+        y : 'bliadhna',
+        yy : '%d bliadhna'
+    },
+    ordinalParse : /\d{1,2}(d|na|mh)/,
+    ordinal : function (number) {
+        var output = number === 1 ? 'd' : number % 10 === 2 ? 'na' : 'mh';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Galician [gl]
+//! author : Juan G. Hurtado : https://github.com/juanghurtado
+
+hooks.defineLocale('gl', {
+    months : 'xaneiro_febreiro_marzo_abril_maio_xuño_xullo_agosto_setembro_outubro_novembro_decembro'.split('_'),
+    monthsShort : 'xan._feb._mar._abr._mai._xuñ._xul._ago._set._out._nov._dec.'.split('_'),
+    monthsParseExact: true,
+    weekdays : 'domingo_luns_martes_mércores_xoves_venres_sábado'.split('_'),
+    weekdaysShort : 'dom._lun._mar._mér._xov._ven._sáb.'.split('_'),
+    weekdaysMin : 'do_lu_ma_mé_xo_ve_sá'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D [de] MMMM [de] YYYY',
+        LLL : 'D [de] MMMM [de] YYYY H:mm',
+        LLLL : 'dddd, D [de] MMMM [de] YYYY H:mm'
+    },
+    calendar : {
+        sameDay : function () {
+            return '[hoxe ' + ((this.hours() !== 1) ? 'ás' : 'á') + '] LT';
+        },
+        nextDay : function () {
+            return '[mañá ' + ((this.hours() !== 1) ? 'ás' : 'á') + '] LT';
+        },
+        nextWeek : function () {
+            return 'dddd [' + ((this.hours() !== 1) ? 'ás' : 'a') + '] LT';
+        },
+        lastDay : function () {
+            return '[onte ' + ((this.hours() !== 1) ? 'á' : 'a') + '] LT';
+        },
+        lastWeek : function () {
+            return '[o] dddd [pasado ' + ((this.hours() !== 1) ? 'ás' : 'a') + '] LT';
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : function (str) {
+            if (str.indexOf('un') === 0) {
+                return 'n' + str;
+            }
+            return 'en ' + str;
+        },
+        past : 'hai %s',
+        s : 'uns segundos',
+        m : 'un minuto',
+        mm : '%d minutos',
+        h : 'unha hora',
+        hh : '%d horas',
+        d : 'un día',
+        dd : '%d días',
+        M : 'un mes',
+        MM : '%d meses',
+        y : 'un ano',
+        yy : '%d anos'
+    },
+    ordinalParse : /\d{1,2}º/,
+    ordinal : '%dº',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Hebrew [he]
+//! author : Tomer Cohen : https://github.com/tomer
+//! author : Moshe Simantov : https://github.com/DevelopmentIL
+//! author : Tal Ater : https://github.com/TalAter
+
+hooks.defineLocale('he', {
+    months : 'ינואר_פברואר_מרץ_אפריל_מאי_יוני_יולי_אוגוסט_ספטמבר_אוקטובר_נובמבר_דצמבר'.split('_'),
+    monthsShort : 'ינו׳_פבר׳_מרץ_אפר׳_מאי_יוני_יולי_אוג׳_ספט׳_אוק׳_נוב׳_דצמ׳'.split('_'),
+    weekdays : 'ראשון_שני_שלישי_רביעי_חמישי_שישי_שבת'.split('_'),
+    weekdaysShort : 'א׳_ב׳_ג׳_ד׳_ה׳_ו׳_ש׳'.split('_'),
+    weekdaysMin : 'א_ב_ג_ד_ה_ו_ש'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D [ב]MMMM YYYY',
+        LLL : 'D [ב]MMMM YYYY HH:mm',
+        LLLL : 'dddd, D [ב]MMMM YYYY HH:mm',
+        l : 'D/M/YYYY',
+        ll : 'D MMM YYYY',
+        lll : 'D MMM YYYY HH:mm',
+        llll : 'ddd, D MMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[היום ב־]LT',
+        nextDay : '[מחר ב־]LT',
+        nextWeek : 'dddd [בשעה] LT',
+        lastDay : '[אתמול ב־]LT',
+        lastWeek : '[ביום] dddd [האחרון בשעה] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'בעוד %s',
+        past : 'לפני %s',
+        s : 'מספר שניות',
+        m : 'דקה',
+        mm : '%d דקות',
+        h : 'שעה',
+        hh : function (number) {
+            if (number === 2) {
+                return 'שעתיים';
+            }
+            return number + ' שעות';
+        },
+        d : 'יום',
+        dd : function (number) {
+            if (number === 2) {
+                return 'יומיים';
+            }
+            return number + ' ימים';
+        },
+        M : 'חודש',
+        MM : function (number) {
+            if (number === 2) {
+                return 'חודשיים';
+            }
+            return number + ' חודשים';
+        },
+        y : 'שנה',
+        yy : function (number) {
+            if (number === 2) {
+                return 'שנתיים';
+            } else if (number % 10 === 0 && number !== 10) {
+                return number + ' שנה';
+            }
+            return number + ' שנים';
+        }
+    },
+    meridiemParse: /אחה"צ|לפנה"צ|אחרי הצהריים|לפני הצהריים|לפנות בוקר|בבוקר|בערב/i,
+    isPM : function (input) {
+        return /^(אחה"צ|אחרי הצהריים|בערב)$/.test(input);
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 5) {
+            return 'לפנות בוקר';
+        } else if (hour < 10) {
+            return 'בבוקר';
+        } else if (hour < 12) {
+            return isLower ? 'לפנה"צ' : 'לפני הצהריים';
+        } else if (hour < 18) {
+            return isLower ? 'אחה"צ' : 'אחרי הצהריים';
+        } else {
+            return 'בערב';
+        }
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Hindi [hi]
+//! author : Mayank Singhal : https://github.com/mayanksinghal
+
+var symbolMap$6 = {
+    '1': '१',
+    '2': '२',
+    '3': '३',
+    '4': '४',
+    '5': '५',
+    '6': '६',
+    '7': '७',
+    '8': '८',
+    '9': '९',
+    '0': '०'
+};
+var numberMap$5 = {
+    '१': '1',
+    '२': '2',
+    '३': '3',
+    '४': '4',
+    '५': '5',
+    '६': '6',
+    '७': '7',
+    '८': '8',
+    '९': '9',
+    '०': '0'
+};
+
+hooks.defineLocale('hi', {
+    months : 'जनवरी_फ़रवरी_मार्च_अप्रैल_मई_जून_जुलाई_अगस्त_सितम्बर_अक्टूबर_नवम्बर_दिसम्बर'.split('_'),
+    monthsShort : 'जन._फ़र._मार्च_अप्रै._मई_जून_जुल._अग._सित._अक्टू._नव._दिस.'.split('_'),
+    monthsParseExact: true,
+    weekdays : 'रविवार_सोमवार_मंगलवार_बुधवार_गुरूवार_शुक्रवार_शनिवार'.split('_'),
+    weekdaysShort : 'रवि_सोम_मंगल_बुध_गुरू_शुक्र_शनि'.split('_'),
+    weekdaysMin : 'र_सो_मं_बु_गु_शु_श'.split('_'),
+    longDateFormat : {
+        LT : 'A h:mm बजे',
+        LTS : 'A h:mm:ss बजे',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, A h:mm बजे',
+        LLLL : 'dddd, D MMMM YYYY, A h:mm बजे'
+    },
+    calendar : {
+        sameDay : '[आज] LT',
+        nextDay : '[कल] LT',
+        nextWeek : 'dddd, LT',
+        lastDay : '[कल] LT',
+        lastWeek : '[पिछले] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s में',
+        past : '%s पहले',
+        s : 'कुछ ही क्षण',
+        m : 'एक मिनट',
+        mm : '%d मिनट',
+        h : 'एक घंटा',
+        hh : '%d घंटे',
+        d : 'एक दिन',
+        dd : '%d दिन',
+        M : 'एक महीने',
+        MM : '%d महीने',
+        y : 'एक वर्ष',
+        yy : '%d वर्ष'
+    },
+    preparse: function (string) {
+        return string.replace(/[१२३४५६७८९०]/g, function (match) {
+            return numberMap$5[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap$6[match];
+        });
+    },
+    // Hindi notation for meridiems are quite fuzzy in practice. While there exists
+    // a rigid notion of a 'Pahar' it is not used as rigidly in modern Hindi.
+    meridiemParse: /रात|सुबह|दोपहर|शाम/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'रात') {
+            return hour < 4 ? hour : hour + 12;
+        } else if (meridiem === 'सुबह') {
+            return hour;
+        } else if (meridiem === 'दोपहर') {
+            return hour >= 10 ? hour : hour + 12;
+        } else if (meridiem === 'शाम') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'रात';
+        } else if (hour < 10) {
+            return 'सुबह';
+        } else if (hour < 17) {
+            return 'दोपहर';
+        } else if (hour < 20) {
+            return 'शाम';
+        } else {
+            return 'रात';
+        }
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Croatian [hr]
+//! author : Bojan Marković : https://github.com/bmarkovic
+
+function translate$3(number, withoutSuffix, key) {
+    var result = number + ' ';
+    switch (key) {
+        case 'm':
+            return withoutSuffix ? 'jedna minuta' : 'jedne minute';
+        case 'mm':
+            if (number === 1) {
+                result += 'minuta';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'minute';
+            } else {
+                result += 'minuta';
+            }
+            return result;
+        case 'h':
+            return withoutSuffix ? 'jedan sat' : 'jednog sata';
+        case 'hh':
+            if (number === 1) {
+                result += 'sat';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'sata';
+            } else {
+                result += 'sati';
+            }
+            return result;
+        case 'dd':
+            if (number === 1) {
+                result += 'dan';
+            } else {
+                result += 'dana';
+            }
+            return result;
+        case 'MM':
+            if (number === 1) {
+                result += 'mjesec';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'mjeseca';
+            } else {
+                result += 'mjeseci';
+            }
+            return result;
+        case 'yy':
+            if (number === 1) {
+                result += 'godina';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'godine';
+            } else {
+                result += 'godina';
+            }
+            return result;
+    }
+}
+
+hooks.defineLocale('hr', {
+    months : {
+        format: 'siječnja_veljače_ožujka_travnja_svibnja_lipnja_srpnja_kolovoza_rujna_listopada_studenoga_prosinca'.split('_'),
+        standalone: 'siječanj_veljača_ožujak_travanj_svibanj_lipanj_srpanj_kolovoz_rujan_listopad_studeni_prosinac'.split('_')
+    },
+    monthsShort : 'sij._velj._ožu._tra._svi._lip._srp._kol._ruj._lis._stu._pro.'.split('_'),
+    monthsParseExact: true,
+    weekdays : 'nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota'.split('_'),
+    weekdaysShort : 'ned._pon._uto._sri._čet._pet._sub.'.split('_'),
+    weekdaysMin : 'ne_po_ut_sr_če_pe_su'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY H:mm',
+        LLLL : 'dddd, D. MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay  : '[danas u] LT',
+        nextDay  : '[sutra u] LT',
+        nextWeek : function () {
+            switch (this.day()) {
+                case 0:
+                    return '[u] [nedjelju] [u] LT';
+                case 3:
+                    return '[u] [srijedu] [u] LT';
+                case 6:
+                    return '[u] [subotu] [u] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[u] dddd [u] LT';
+            }
+        },
+        lastDay  : '[jučer u] LT',
+        lastWeek : function () {
+            switch (this.day()) {
+                case 0:
+                case 3:
+                    return '[prošlu] dddd [u] LT';
+                case 6:
+                    return '[prošle] [subote] [u] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[prošli] dddd [u] LT';
+            }
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'za %s',
+        past   : 'prije %s',
+        s      : 'par sekundi',
+        m      : translate$3,
+        mm     : translate$3,
+        h      : translate$3,
+        hh     : translate$3,
+        d      : 'dan',
+        dd     : translate$3,
+        M      : 'mjesec',
+        MM     : translate$3,
+        y      : 'godinu',
+        yy     : translate$3
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Hungarian [hu]
+//! author : Adam Brunner : https://github.com/adambrunner
+
+var weekEndings = 'vasárnap hétfőn kedden szerdán csütörtökön pénteken szombaton'.split(' ');
+function translate$4(number, withoutSuffix, key, isFuture) {
+    var num = number,
+        suffix;
+    switch (key) {
+        case 's':
+            return (isFuture || withoutSuffix) ? 'néhány másodperc' : 'néhány másodperce';
+        case 'm':
+            return 'egy' + (isFuture || withoutSuffix ? ' perc' : ' perce');
+        case 'mm':
+            return num + (isFuture || withoutSuffix ? ' perc' : ' perce');
+        case 'h':
+            return 'egy' + (isFuture || withoutSuffix ? ' óra' : ' órája');
+        case 'hh':
+            return num + (isFuture || withoutSuffix ? ' óra' : ' órája');
+        case 'd':
+            return 'egy' + (isFuture || withoutSuffix ? ' nap' : ' napja');
+        case 'dd':
+            return num + (isFuture || withoutSuffix ? ' nap' : ' napja');
+        case 'M':
+            return 'egy' + (isFuture || withoutSuffix ? ' hónap' : ' hónapja');
+        case 'MM':
+            return num + (isFuture || withoutSuffix ? ' hónap' : ' hónapja');
+        case 'y':
+            return 'egy' + (isFuture || withoutSuffix ? ' év' : ' éve');
+        case 'yy':
+            return num + (isFuture || withoutSuffix ? ' év' : ' éve');
+    }
+    return '';
+}
+function week(isFuture) {
+    return (isFuture ? '' : '[múlt] ') + '[' + weekEndings[this.day()] + '] LT[-kor]';
+}
+
+hooks.defineLocale('hu', {
+    months : 'január_február_március_április_május_június_július_augusztus_szeptember_október_november_december'.split('_'),
+    monthsShort : 'jan_feb_márc_ápr_máj_jún_júl_aug_szept_okt_nov_dec'.split('_'),
+    weekdays : 'vasárnap_hétfő_kedd_szerda_csütörtök_péntek_szombat'.split('_'),
+    weekdaysShort : 'vas_hét_kedd_sze_csüt_pén_szo'.split('_'),
+    weekdaysMin : 'v_h_k_sze_cs_p_szo'.split('_'),
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'YYYY.MM.DD.',
+        LL : 'YYYY. MMMM D.',
+        LLL : 'YYYY. MMMM D. H:mm',
+        LLLL : 'YYYY. MMMM D., dddd H:mm'
+    },
+    meridiemParse: /de|du/i,
+    isPM: function (input) {
+        return input.charAt(1).toLowerCase() === 'u';
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 12) {
+            return isLower === true ? 'de' : 'DE';
+        } else {
+            return isLower === true ? 'du' : 'DU';
+        }
+    },
+    calendar : {
+        sameDay : '[ma] LT[-kor]',
+        nextDay : '[holnap] LT[-kor]',
+        nextWeek : function () {
+            return week.call(this, true);
+        },
+        lastDay : '[tegnap] LT[-kor]',
+        lastWeek : function () {
+            return week.call(this, false);
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s múlva',
+        past : '%s',
+        s : translate$4,
+        m : translate$4,
+        mm : translate$4,
+        h : translate$4,
+        hh : translate$4,
+        d : translate$4,
+        dd : translate$4,
+        M : translate$4,
+        MM : translate$4,
+        y : translate$4,
+        yy : translate$4
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Armenian [hy-am]
+//! author : Armendarabyan : https://github.com/armendarabyan
+
+hooks.defineLocale('hy-am', {
+    months : {
+        format: 'Õ°Õ¸Ö‚Õ¶Õ¾Õ¡Ö€Õ«_ÖƒÕ¥Õ¿Ö€Õ¾Õ¡Ö€Õ«_Õ´Õ¡Ö€Õ¿Õ«_Õ¡ÕºÖ€Õ«Õ¬Õ«_Õ´Õ¡ÕµÕ«Õ½Õ«_Õ°Õ¸Ö‚Õ¶Õ«Õ½Õ«_Õ°Õ¸Ö‚Õ¬Õ«Õ½Õ«_Ö…Õ£Õ¸Õ½Õ¿Õ¸Õ½Õ«_Õ½Õ¥ÕºÕ¿Õ¥Õ´Õ¢Õ¥Ö€Õ«_Õ°Õ¸Õ¯Õ¿Õ¥Õ´Õ¢Õ¥Ö€Õ«_Õ¶Õ¸ÕµÕ¥Õ´Õ¢Õ¥Ö€Õ«_Õ¤Õ¥Õ¯Õ¿Õ¥Õ´Õ¢Õ¥Ö€Õ«'.split('_'),
+        standalone: 'Õ°Õ¸Ö‚Õ¶Õ¾Õ¡Ö€_ÖƒÕ¥Õ¿Ö€Õ¾Õ¡Ö€_Õ´Õ¡Ö€Õ¿_Õ¡ÕºÖ€Õ«Õ¬_Õ´Õ¡ÕµÕ«Õ½_Õ°Õ¸Ö‚Õ¶Õ«Õ½_Õ°Õ¸Ö‚Õ¬Õ«Õ½_Ö…Õ£Õ¸Õ½Õ¿Õ¸Õ½_Õ½Õ¥ÕºÕ¿Õ¥Õ´Õ¢Õ¥Ö€_Õ°Õ¸Õ¯Õ¿Õ¥Õ´Õ¢Õ¥Ö€_Õ¶Õ¸ÕµÕ¥Õ´Õ¢Õ¥Ö€_Õ¤Õ¥Õ¯Õ¿Õ¥Õ´Õ¢Õ¥Ö€'.split('_')
+    },
+    monthsShort : 'Õ°Õ¶Õ¾_ÖƒÕ¿Ö€_Õ´Ö€Õ¿_Õ¡ÕºÖ€_Õ´ÕµÕ½_Õ°Õ¶Õ½_Õ°Õ¬Õ½_Ö…Õ£Õ½_Õ½ÕºÕ¿_Õ°Õ¯Õ¿_Õ¶Õ´Õ¢_Õ¤Õ¯Õ¿'.split('_'),
+    weekdays : 'Õ¯Õ«Ö€Õ¡Õ¯Õ«_Õ¥Ö€Õ¯Õ¸Ö‚Õ·Õ¡Õ¢Õ©Õ«_Õ¥Ö€Õ¥Ö„Õ·Õ¡Õ¢Õ©Õ«_Õ¹Õ¸Ö€Õ¥Ö„Õ·Õ¡Õ¢Õ©Õ«_Õ°Õ«Õ¶Õ£Õ·Õ¡Õ¢Õ©Õ«_Õ¸Ö‚Ö€Õ¢Õ¡Õ©_Õ·Õ¡Õ¢Õ¡Õ©'.split('_'),
+    weekdaysShort : 'Õ¯Ö€Õ¯_Õ¥Ö€Õ¯_Õ¥Ö€Ö„_Õ¹Ö€Ö„_Õ°Õ¶Õ£_Õ¸Ö‚Ö€Õ¢_Õ·Õ¢Õ©'.split('_'),
+    weekdaysMin : 'Õ¯Ö€Õ¯_Õ¥Ö€Õ¯_Õ¥Ö€Ö„_Õ¹Ö€Ö„_Õ°Õ¶Õ£_Õ¸Ö‚Ö€Õ¢_Õ·Õ¢Õ©'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY Õ©.',
+        LLL : 'D MMMM YYYY Õ©., HH:mm',
+        LLLL : 'dddd, D MMMM YYYY Õ©., HH:mm'
+    },
+    calendar : {
+        sameDay: '[Õ¡ÕµÕ½Ö…Ö€] LT',
+        nextDay: '[Õ¾Õ¡Õ²Õ¨] LT',
+        lastDay: '[Õ¥Ö€Õ¥Õ¯] LT',
+        nextWeek: function () {
+            return 'dddd [Ö…Ö€Õ¨ ÕªÕ¡Õ´Õ¨] LT';
+        },
+        lastWeek: function () {
+            return '[անցած] dddd [օրը ժամը] LT';
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : '%s Õ°Õ¥Õ¿Õ¸',
+        past : '%s Õ¡Õ¼Õ¡Õ»',
+        s : 'Õ´Õ« Ö„Õ¡Õ¶Õ« Õ¾Õ¡ÕµÖ€Õ¯ÕµÕ¡Õ¶',
+        m : 'Ö€Õ¸ÕºÕ¥',
+        mm : '%d Ö€Õ¸ÕºÕ¥',
+        h : 'ÕªÕ¡Õ´',
+        hh : '%d ÕªÕ¡Õ´',
+        d : 'Ö…Ö€',
+        dd : '%d Ö…Ö€',
+        M : 'Õ¡Õ´Õ«Õ½',
+        MM : '%d Õ¡Õ´Õ«Õ½',
+        y : 'Õ¿Õ¡Ö€Õ«',
+        yy : '%d Õ¿Õ¡Ö€Õ«'
+    },
+    meridiemParse: /գիշերվա|առավոտվա|ցերեկվա|երեկոյան/,
+    isPM: function (input) {
+        return /^(ցերեկվա|երեկոյան)$/.test(input);
+    },
+    meridiem : function (hour) {
+        if (hour < 4) {
+            return 'Õ£Õ«Õ·Õ¥Ö€Õ¾Õ¡';
+        } else if (hour < 12) {
+            return 'Õ¡Õ¼Õ¡Õ¾Õ¸Õ¿Õ¾Õ¡';
+        } else if (hour < 17) {
+            return 'ցերեկվա';
+        } else {
+            return 'Õ¥Ö€Õ¥Õ¯Õ¸ÕµÕ¡Õ¶';
+        }
+    },
+    ordinalParse: /\d{1,2}|\d{1,2}-(Õ«Õ¶|Ö€Õ¤)/,
+    ordinal: function (number, period) {
+        switch (period) {
+            case 'DDD':
+            case 'w':
+            case 'W':
+            case 'DDDo':
+                if (number === 1) {
+                    return number + '-Õ«Õ¶';
+                }
+                return number + '-Ö€Õ¤';
+            default:
+                return number;
+        }
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Indonesian [id]
+//! author : Mohammad Satrio Utomo : https://github.com/tyok
+//! reference: http://id.wikisource.org/wiki/Pedoman_Umum_Ejaan_Bahasa_Indonesia_yang_Disempurnakan
+
+hooks.defineLocale('id', {
+    months : 'Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_November_Desember'.split('_'),
+    monthsShort : 'Jan_Feb_Mar_Apr_Mei_Jun_Jul_Ags_Sep_Okt_Nov_Des'.split('_'),
+    weekdays : 'Minggu_Senin_Selasa_Rabu_Kamis_Jumat_Sabtu'.split('_'),
+    weekdaysShort : 'Min_Sen_Sel_Rab_Kam_Jum_Sab'.split('_'),
+    weekdaysMin : 'Mg_Sn_Sl_Rb_Km_Jm_Sb'.split('_'),
+    longDateFormat : {
+        LT : 'HH.mm',
+        LTS : 'HH.mm.ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY [pukul] HH.mm',
+        LLLL : 'dddd, D MMMM YYYY [pukul] HH.mm'
+    },
+    meridiemParse: /pagi|siang|sore|malam/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'pagi') {
+            return hour;
+        } else if (meridiem === 'siang') {
+            return hour >= 11 ? hour : hour + 12;
+        } else if (meridiem === 'sore' || meridiem === 'malam') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 11) {
+            return 'pagi';
+        } else if (hours < 15) {
+            return 'siang';
+        } else if (hours < 19) {
+            return 'sore';
+        } else {
+            return 'malam';
+        }
+    },
+    calendar : {
+        sameDay : '[Hari ini pukul] LT',
+        nextDay : '[Besok pukul] LT',
+        nextWeek : 'dddd [pukul] LT',
+        lastDay : '[Kemarin pukul] LT',
+        lastWeek : 'dddd [lalu pukul] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'dalam %s',
+        past : '%s yang lalu',
+        s : 'beberapa detik',
+        m : 'semenit',
+        mm : '%d menit',
+        h : 'sejam',
+        hh : '%d jam',
+        d : 'sehari',
+        dd : '%d hari',
+        M : 'sebulan',
+        MM : '%d bulan',
+        y : 'setahun',
+        yy : '%d tahun'
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Icelandic [is]
+//! author : Hinrik Örn Sigurðsson : https://github.com/hinrik
+
+function plural$2(n) {
+    if (n % 100 === 11) {
+        return true;
+    } else if (n % 10 === 1) {
+        return false;
+    }
+    return true;
+}
+function translate$5(number, withoutSuffix, key, isFuture) {
+    var result = number + ' ';
+    switch (key) {
+        case 's':
+            return withoutSuffix || isFuture ? 'nokkrar sekúndur' : 'nokkrum sekúndum';
+        case 'm':
+            return withoutSuffix ? 'mínúta' : 'mínútu';
+        case 'mm':
+            if (plural$2(number)) {
+                return result + (withoutSuffix || isFuture ? 'mínútur' : 'mínútum');
+            } else if (withoutSuffix) {
+                return result + 'mínúta';
+            }
+            return result + 'mínútu';
+        case 'hh':
+            if (plural$2(number)) {
+                return result + (withoutSuffix || isFuture ? 'klukkustundir' : 'klukkustundum');
+            }
+            return result + 'klukkustund';
+        case 'd':
+            if (withoutSuffix) {
+                return 'dagur';
+            }
+            return isFuture ? 'dag' : 'degi';
+        case 'dd':
+            if (plural$2(number)) {
+                if (withoutSuffix) {
+                    return result + 'dagar';
+                }
+                return result + (isFuture ? 'daga' : 'dögum');
+            } else if (withoutSuffix) {
+                return result + 'dagur';
+            }
+            return result + (isFuture ? 'dag' : 'degi');
+        case 'M':
+            if (withoutSuffix) {
+                return 'mánuður';
+            }
+            return isFuture ? 'mánuð' : 'mánuði';
+        case 'MM':
+            if (plural$2(number)) {
+                if (withoutSuffix) {
+                    return result + 'mánuðir';
+                }
+                return result + (isFuture ? 'mánuði' : 'mánuðum');
+            } else if (withoutSuffix) {
+                return result + 'mánuður';
+            }
+            return result + (isFuture ? 'mánuð' : 'mánuði');
+        case 'y':
+            return withoutSuffix || isFuture ? 'ár' : 'ári';
+        case 'yy':
+            if (plural$2(number)) {
+                return result + (withoutSuffix || isFuture ? 'ár' : 'árum');
+            }
+            return result + (withoutSuffix || isFuture ? 'ár' : 'ári');
+    }
+}
+
+hooks.defineLocale('is', {
+    months : 'janúar_febrúar_mars_apríl_maí_júní_júlí_ágúst_september_október_nóvember_desember'.split('_'),
+    monthsShort : 'jan_feb_mar_apr_maí_jún_júl_ágú_sep_okt_nóv_des'.split('_'),
+    weekdays : 'sunnudagur_mánudagur_þriðjudagur_miðvikudagur_fimmtudagur_föstudagur_laugardagur'.split('_'),
+    weekdaysShort : 'sun_mán_þri_mið_fim_fös_lau'.split('_'),
+    weekdaysMin : 'Su_Má_Þr_Mi_Fi_Fö_La'.split('_'),
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY [kl.] H:mm',
+        LLLL : 'dddd, D. MMMM YYYY [kl.] H:mm'
+    },
+    calendar : {
+        sameDay : '[í dag kl.] LT',
+        nextDay : '[á morgun kl.] LT',
+        nextWeek : 'dddd [kl.] LT',
+        lastDay : '[í gær kl.] LT',
+        lastWeek : '[síðasta] dddd [kl.] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'eftir %s',
+        past : 'fyrir %s síðan',
+        s : translate$5,
+        m : translate$5,
+        mm : translate$5,
+        h : 'klukkustund',
+        hh : translate$5,
+        d : translate$5,
+        dd : translate$5,
+        M : translate$5,
+        MM : translate$5,
+        y : translate$5,
+        yy : translate$5
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Italian [it]
+//! author : Lorenzo : https://github.com/aliem
+//! author: Mattia Larentis: https://github.com/nostalgiaz
+
+hooks.defineLocale('it', {
+    months : 'gennaio_febbraio_marzo_aprile_maggio_giugno_luglio_agosto_settembre_ottobre_novembre_dicembre'.split('_'),
+    monthsShort : 'gen_feb_mar_apr_mag_giu_lug_ago_set_ott_nov_dic'.split('_'),
+    weekdays : 'Domenica_Lunedì_Martedì_Mercoledì_Giovedì_Venerdì_Sabato'.split('_'),
+    weekdaysShort : 'Dom_Lun_Mar_Mer_Gio_Ven_Sab'.split('_'),
+    weekdaysMin : 'Do_Lu_Ma_Me_Gi_Ve_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Oggi alle] LT',
+        nextDay: '[Domani alle] LT',
+        nextWeek: 'dddd [alle] LT',
+        lastDay: '[Ieri alle] LT',
+        lastWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[la scorsa] dddd [alle] LT';
+                default:
+                    return '[lo scorso] dddd [alle] LT';
+            }
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : function (s) {
+            return ((/^[0-9].+$/).test(s) ? 'tra' : 'in') + ' ' + s;
+        },
+        past : '%s fa',
+        s : 'alcuni secondi',
+        m : 'un minuto',
+        mm : '%d minuti',
+        h : 'un\'ora',
+        hh : '%d ore',
+        d : 'un giorno',
+        dd : '%d giorni',
+        M : 'un mese',
+        MM : '%d mesi',
+        y : 'un anno',
+        yy : '%d anni'
+    },
+    ordinalParse : /\d{1,2}º/,
+    ordinal: '%dº',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Japanese [ja]
+//! author : LI Long : https://github.com/baryon
+
+hooks.defineLocale('ja', {
+    months : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
+    monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
+    weekdays : '日曜日_月曜日_火曜日_水曜日_木曜日_金曜日_土曜日'.split('_'),
+    weekdaysShort : '日_月_火_水_木_金_土'.split('_'),
+    weekdaysMin : '日_月_火_水_木_金_土'.split('_'),
+    longDateFormat : {
+        LT : 'Ah時m分',
+        LTS : 'Ah時m分s秒',
+        L : 'YYYY/MM/DD',
+        LL : 'YYYY年M月D日',
+        LLL : 'YYYY年M月D日Ah時m分',
+        LLLL : 'YYYY年M月D日Ah時m分 dddd'
+    },
+    meridiemParse: /午前|午後/i,
+    isPM : function (input) {
+        return input === '午後';
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return '午前';
+        } else {
+            return '午後';
+        }
+    },
+    calendar : {
+        sameDay : '[今日] LT',
+        nextDay : '[明日] LT',
+        nextWeek : '[来週]dddd LT',
+        lastDay : '[昨日] LT',
+        lastWeek : '[前週]dddd LT',
+        sameElse : 'L'
+    },
+    ordinalParse : /\d{1,2}æ—¥/,
+    ordinal : function (number, period) {
+        switch (period) {
+            case 'd':
+            case 'D':
+            case 'DDD':
+                return number + 'æ—¥';
+            default:
+                return number;
+        }
+    },
+    relativeTime : {
+        future : '%s後',
+        past : '%s前',
+        s : 'æ•°ç§’',
+        m : '1分',
+        mm : '%d分',
+        h : '1時間',
+        hh : '%d時間',
+        d : '1æ—¥',
+        dd : '%dæ—¥',
+        M : '1ヶ月',
+        MM : '%dヶ月',
+        y : '1å¹´',
+        yy : '%då¹´'
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Javanese [jv]
+//! author : Rony Lantip : https://github.com/lantip
+//! reference: http://jv.wikipedia.org/wiki/Basa_Jawa
+
+hooks.defineLocale('jv', {
+    months : 'Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_Nopember_Desember'.split('_'),
+    monthsShort : 'Jan_Feb_Mar_Apr_Mei_Jun_Jul_Ags_Sep_Okt_Nop_Des'.split('_'),
+    weekdays : 'Minggu_Senen_Seloso_Rebu_Kemis_Jemuwah_Septu'.split('_'),
+    weekdaysShort : 'Min_Sen_Sel_Reb_Kem_Jem_Sep'.split('_'),
+    weekdaysMin : 'Mg_Sn_Sl_Rb_Km_Jm_Sp'.split('_'),
+    longDateFormat : {
+        LT : 'HH.mm',
+        LTS : 'HH.mm.ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY [pukul] HH.mm',
+        LLLL : 'dddd, D MMMM YYYY [pukul] HH.mm'
+    },
+    meridiemParse: /enjing|siyang|sonten|ndalu/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'enjing') {
+            return hour;
+        } else if (meridiem === 'siyang') {
+            return hour >= 11 ? hour : hour + 12;
+        } else if (meridiem === 'sonten' || meridiem === 'ndalu') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 11) {
+            return 'enjing';
+        } else if (hours < 15) {
+            return 'siyang';
+        } else if (hours < 19) {
+            return 'sonten';
+        } else {
+            return 'ndalu';
+        }
+    },
+    calendar : {
+        sameDay : '[Dinten puniko pukul] LT',
+        nextDay : '[Mbenjang pukul] LT',
+        nextWeek : 'dddd [pukul] LT',
+        lastDay : '[Kala wingi pukul] LT',
+        lastWeek : 'dddd [kepengker pukul] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'wonten ing %s',
+        past : '%s ingkang kepengker',
+        s : 'sawetawis detik',
+        m : 'setunggal menit',
+        mm : '%d menit',
+        h : 'setunggal jam',
+        hh : '%d jam',
+        d : 'sedinten',
+        dd : '%d dinten',
+        M : 'sewulan',
+        MM : '%d wulan',
+        y : 'setaun',
+        yy : '%d taun'
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Georgian [ka]
+//! author : Irakli Janiashvili : https://github.com/irakli-janiashvili
+
+hooks.defineLocale('ka', {
+    months : {
+        standalone: 'იანვარი_თებერვალი_მარტი_აპრილი_მაისი_ივნისი_ივლისი_აგვისტო_სექტემბერი_ოქტომბერი_ნოემბერი_დეკემბერი'.split('_'),
+        format: 'იანვარს_თებერვალს_მარტს_აპრილის_მაისს_ივნისს_ივლისს_აგვისტს_სექტემბერს_ოქტომბერს_ნოემბერს_დეკემბერს'.split('_')
+    },
+    monthsShort : 'იან_თებ_მარ_აპრ_მაი_ივნ_ივლ_აგვ_სექ_ოქტ_ნოე_დეკ'.split('_'),
+    weekdays : {
+        standalone: 'კვირა_ორშაბათი_სამშაბათი_ოთხშაბათი_ხუთშაბათი_პარასკევი_შაბათი'.split('_'),
+        format: 'კვირას_ორშაბათს_სამშაბათს_ოთხშაბათს_ხუთშაბათს_პარასკევს_შაბათს'.split('_'),
+        isFormat: /(წინა|შემდეგ)/
+    },
+    weekdaysShort : 'კვი_ორშ_სამ_ოთხ_ხუთ_პარ_შაბ'.split('_'),
+    weekdaysMin : 'კვ_ორ_სა_ოთ_ხუ_პა_შა'.split('_'),
+    longDateFormat : {
+        LT : 'h:mm A',
+        LTS : 'h:mm:ss A',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY h:mm A',
+        LLLL : 'dddd, D MMMM YYYY h:mm A'
+    },
+    calendar : {
+        sameDay : '[დღეს] LT[-ზე]',
+        nextDay : '[ხვალ] LT[-ზე]',
+        lastDay : '[გუშინ] LT[-ზე]',
+        nextWeek : '[შემდეგ] dddd LT[-ზე]',
+        lastWeek : '[წინა] dddd LT-ზე',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : function (s) {
+            return (/(წამი|წუთი|საათი|წელი)/).test(s) ?
+                s.replace(/ი$/, 'ში') :
+                s + 'ში';
+        },
+        past : function (s) {
+            if ((/(წამი|წუთი|საათი|დღე|თვე)/).test(s)) {
+                return s.replace(/(ი|ე)$/, 'ის წინ');
+            }
+            if ((/წელი/).test(s)) {
+                return s.replace(/წელი$/, 'წლის წინ');
+            }
+        },
+        s : 'რამდენიმე წამი',
+        m : 'წუთი',
+        mm : '%d წუთი',
+        h : 'საათი',
+        hh : '%d საათი',
+        d : 'დღე',
+        dd : '%d დღე',
+        M : 'თვე',
+        MM : '%d თვე',
+        y : 'წელი',
+        yy : '%d წელი'
+    },
+    ordinalParse: /0|1-ლი|მე-\d{1,2}|\d{1,2}-ე/,
+    ordinal : function (number) {
+        if (number === 0) {
+            return number;
+        }
+        if (number === 1) {
+            return number + '-ლი';
+        }
+        if ((number < 20) || (number <= 100 && (number % 20 === 0)) || (number % 100 === 0)) {
+            return 'მე-' + number;
+        }
+        return number + '-ე';
+    },
+    week : {
+        dow : 1,
+        doy : 7
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Kazakh [kk]
+//! authors : Nurlan Rakhimzhanov : https://github.com/nurlan
+
+var suffixes$1 = {
+    0: '-ші',
+    1: '-ші',
+    2: '-ші',
+    3: '-ші',
+    4: '-ші',
+    5: '-ші',
+    6: '-шы',
+    7: '-ші',
+    8: '-ші',
+    9: '-шы',
+    10: '-шы',
+    20: '-шы',
+    30: '-шы',
+    40: '-шы',
+    50: '-ші',
+    60: '-шы',
+    70: '-ші',
+    80: '-ші',
+    90: '-шы',
+    100: '-ші'
+};
+
+hooks.defineLocale('kk', {
+    months : 'қаңтар_ақпан_наурыз_сәуір_мамыр_маусым_шілде_тамыз_қыркүйек_қазан_қараша_желтоқсан'.split('_'),
+    monthsShort : 'қаң_ақп_нау_сәу_мам_мау_шіл_там_қыр_қаз_қар_жел'.split('_'),
+    weekdays : 'жексенбі_дүйсенбі_сейсенбі_сәрсенбі_бейсенбі_жұма_сенбі'.split('_'),
+    weekdaysShort : 'жек_дүй_сей_сәр_бей_жұм_сен'.split('_'),
+    weekdaysMin : 'жк_дй_сй_ср_бй_жм_сн'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[Бүгін сағат] LT',
+        nextDay : '[Ертең сағат] LT',
+        nextWeek : 'dddd [сағат] LT',
+        lastDay : '[Кеше сағат] LT',
+        lastWeek : '[Өткен аптаның] dddd [сағат] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s ішінде',
+        past : '%s бұрын',
+        s : 'бірнеше секунд',
+        m : 'бір минут',
+        mm : '%d минут',
+        h : 'бір сағат',
+        hh : '%d сағат',
+        d : 'бір күн',
+        dd : '%d күн',
+        M : 'бір ай',
+        MM : '%d ай',
+        y : 'бір жыл',
+        yy : '%d жыл'
+    },
+    ordinalParse: /\d{1,2}-(ші|шы)/,
+    ordinal : function (number) {
+        var a = number % 10,
+            b = number >= 100 ? 100 : null;
+        return number + (suffixes$1[number] || suffixes$1[a] || suffixes$1[b]);
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Cambodian [km]
+//! author : Kruy Vanna : https://github.com/kruyvanna
+
+hooks.defineLocale('km', {
+    months: 'មករា_កុម្ភៈ_មីនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ'.split('_'),
+    monthsShort: 'មករា_កុម្ភៈ_មីនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ'.split('_'),
+    weekdays: 'អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍'.split('_'),
+    weekdaysShort: 'អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍'.split('_'),
+    weekdaysMin: 'អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍'.split('_'),
+    longDateFormat: {
+        LT: 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L: 'DD/MM/YYYY',
+        LL: 'D MMMM YYYY',
+        LLL: 'D MMMM YYYY HH:mm',
+        LLLL: 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar: {
+        sameDay: '[ថ្ងៃនេះ ម៉ោង] LT',
+        nextDay: '[ស្អែក ម៉ោង] LT',
+        nextWeek: 'dddd [ម៉ោង] LT',
+        lastDay: '[ម្សិលមិញ ម៉ោង] LT',
+        lastWeek: 'dddd [សប្តាហ៍មុន] [ម៉ោង] LT',
+        sameElse: 'L'
+    },
+    relativeTime: {
+        future: '%sទៀត',
+        past: '%sមុន',
+        s: 'ប៉ុន្មានវិនាទី',
+        m: 'មួយនាទី',
+        mm: '%d នាទី',
+        h: 'មួយម៉ោង',
+        hh: '%d ម៉ោង',
+        d: 'មួយថ្ងៃ',
+        dd: '%d ថ្ងៃ',
+        M: 'មួយខែ',
+        MM: '%d ខែ',
+        y: 'មួយឆ្នាំ',
+        yy: '%d ឆ្នាំ'
+    },
+    week: {
+        dow: 1, // Monday is the first day of the week.
+        doy: 4 // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Korean [ko]
+//! author : Kyungwook, Park : https://github.com/kyungw00k
+//! author : Jeeeyul Lee <jeeeyul@gmail.com>
+
+hooks.defineLocale('ko', {
+    months : '1ì›”_2ì›”_3ì›”_4ì›”_5ì›”_6ì›”_7ì›”_8ì›”_9ì›”_10ì›”_11ì›”_12ì›”'.split('_'),
+    monthsShort : '1ì›”_2ì›”_3ì›”_4ì›”_5ì›”_6ì›”_7ì›”_8ì›”_9ì›”_10ì›”_11ì›”_12ì›”'.split('_'),
+    weekdays : '일요일_월요일_화요일_수요일_목요일_금요일_토요일'.split('_'),
+    weekdaysShort : '일_월_화_수_목_금_토'.split('_'),
+    weekdaysMin : '일_월_화_수_목_금_토'.split('_'),
+    longDateFormat : {
+        LT : 'A h시 m분',
+        LTS : 'A h시 m분 s초',
+        L : 'YYYY.MM.DD',
+        LL : 'YYYY년 MMMM D일',
+        LLL : 'YYYY년 MMMM D일 A h시 m분',
+        LLLL : 'YYYY년 MMMM D일 dddd A h시 m분'
+    },
+    calendar : {
+        sameDay : '오늘 LT',
+        nextDay : '내일 LT',
+        nextWeek : 'dddd LT',
+        lastDay : '어제 LT',
+        lastWeek : '지난주 dddd LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s 후',
+        past : '%s ì „',
+        s : '몇 초',
+        ss : '%dì´ˆ',
+        m : '일분',
+        mm : '%dë¶„',
+        h : '한 시간',
+        hh : '%d시간',
+        d : '하루',
+        dd : '%d일',
+        M : '한 달',
+        MM : '%d달',
+        y : '일 년',
+        yy : '%dë…„'
+    },
+    ordinalParse : /\d{1,2}일/,
+    ordinal : '%d일',
+    meridiemParse : /오전|오후/,
+    isPM : function (token) {
+        return token === '오후';
+    },
+    meridiem : function (hour, minute, isUpper) {
+        return hour < 12 ? '오전' : '오후';
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Kyrgyz [ky]
+//! author : Chyngyz Arystan uulu : https://github.com/chyngyz
+
+
+var suffixes$2 = {
+    0: '-чү',
+    1: '-чи',
+    2: '-чи',
+    3: '-чү',
+    4: '-чү',
+    5: '-чи',
+    6: '-чы',
+    7: '-чи',
+    8: '-чи',
+    9: '-чу',
+    10: '-чу',
+    20: '-чы',
+    30: '-чу',
+    40: '-чы',
+    50: '-чү',
+    60: '-чы',
+    70: '-чи',
+    80: '-чи',
+    90: '-чу',
+    100: '-чү'
+};
+
+hooks.defineLocale('ky', {
+    months : 'январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь'.split('_'),
+    monthsShort : 'янв_фев_март_апр_май_июнь_июль_авг_сен_окт_ноя_дек'.split('_'),
+    weekdays : 'Жекшемби_Дүйшөмбү_Шейшемби_Шаршемби_Бейшемби_Жума_Ишемби'.split('_'),
+    weekdaysShort : 'Жек_Дүй_Шей_Шар_Бей_Жум_Ише'.split('_'),
+    weekdaysMin : 'Жк_Дй_Шй_Шр_Бй_Жм_Иш'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[Бүгүн саат] LT',
+        nextDay : '[Эртең саат] LT',
+        nextWeek : 'dddd [саат] LT',
+        lastDay : '[Кече саат] LT',
+        lastWeek : '[Өткен аптанын] dddd [күнү] [саат] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s ичинде',
+        past : '%s мурун',
+        s : 'бирнече секунд',
+        m : 'бир мүнөт',
+        mm : '%d мүнөт',
+        h : 'бир саат',
+        hh : '%d саат',
+        d : 'бир күн',
+        dd : '%d күн',
+        M : 'бир ай',
+        MM : '%d ай',
+        y : 'бир жыл',
+        yy : '%d жыл'
+    },
+    ordinalParse: /\d{1,2}-(чи|чы|чү|чу)/,
+    ordinal : function (number) {
+        var a = number % 10,
+            b = number >= 100 ? 100 : null;
+        return number + (suffixes$2[number] || suffixes$2[a] || suffixes$2[b]);
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Luxembourgish [lb]
+//! author : mweimerskirch : https://github.com/mweimerskirch
+//! author : David Raison : https://github.com/kwisatz
+
+function processRelativeTime$3(number, withoutSuffix, key, isFuture) {
+    var format = {
+        'm': ['eng Minutt', 'enger Minutt'],
+        'h': ['eng Stonn', 'enger Stonn'],
+        'd': ['een Dag', 'engem Dag'],
+        'M': ['ee Mount', 'engem Mount'],
+        'y': ['ee Joer', 'engem Joer']
+    };
+    return withoutSuffix ? format[key][0] : format[key][1];
+}
+function processFutureTime(string) {
+    var number = string.substr(0, string.indexOf(' '));
+    if (eifelerRegelAppliesToNumber(number)) {
+        return 'a ' + string;
+    }
+    return 'an ' + string;
+}
+function processPastTime(string) {
+    var number = string.substr(0, string.indexOf(' '));
+    if (eifelerRegelAppliesToNumber(number)) {
+        return 'viru ' + string;
+    }
+    return 'virun ' + string;
+}
+/**
+ * Returns true if the word before the given number loses the '-n' ending.
+ * e.g. 'an 10 Deeg' but 'a 5 Deeg'
+ *
+ * @param number {integer}
+ * @returns {boolean}
+ */
+function eifelerRegelAppliesToNumber(number) {
+    number = parseInt(number, 10);
+    if (isNaN(number)) {
+        return false;
+    }
+    if (number < 0) {
+        // Negative Number --> always true
+        return true;
+    } else if (number < 10) {
+        // Only 1 digit
+        if (4 <= number && number <= 7) {
+            return true;
+        }
+        return false;
+    } else if (number < 100) {
+        // 2 digits
+        var lastDigit = number % 10, firstDigit = number / 10;
+        if (lastDigit === 0) {
+            return eifelerRegelAppliesToNumber(firstDigit);
+        }
+        return eifelerRegelAppliesToNumber(lastDigit);
+    } else if (number < 10000) {
+        // 3 or 4 digits --> recursively check first digit
+        while (number >= 10) {
+            number = number / 10;
+        }
+        return eifelerRegelAppliesToNumber(number);
+    } else {
+        // Anything larger than 4 digits: recursively check first n-3 digits
+        number = number / 1000;
+        return eifelerRegelAppliesToNumber(number);
+    }
+}
+
+hooks.defineLocale('lb', {
+    months: 'Januar_Februar_Mäerz_Abrëll_Mee_Juni_Juli_August_September_Oktober_November_Dezember'.split('_'),
+    monthsShort: 'Jan._Febr._Mrz._Abr._Mee_Jun._Jul._Aug._Sept._Okt._Nov._Dez.'.split('_'),
+    monthsParseExact : true,
+    weekdays: 'Sonndeg_Méindeg_Dënschdeg_Mëttwoch_Donneschdeg_Freideg_Samschdeg'.split('_'),
+    weekdaysShort: 'So._Mé._Dë._Më._Do._Fr._Sa.'.split('_'),
+    weekdaysMin: 'So_Mé_Dë_Më_Do_Fr_Sa'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat: {
+        LT: 'H:mm [Auer]',
+        LTS: 'H:mm:ss [Auer]',
+        L: 'DD.MM.YYYY',
+        LL: 'D. MMMM YYYY',
+        LLL: 'D. MMMM YYYY H:mm [Auer]',
+        LLLL: 'dddd, D. MMMM YYYY H:mm [Auer]'
+    },
+    calendar: {
+        sameDay: '[Haut um] LT',
+        sameElse: 'L',
+        nextDay: '[Muer um] LT',
+        nextWeek: 'dddd [um] LT',
+        lastDay: '[Gëschter um] LT',
+        lastWeek: function () {
+            // Different date string for 'Dënschdeg' (Tuesday) and 'Donneschdeg' (Thursday) due to phonological rule
+            switch (this.day()) {
+                case 2:
+                case 4:
+                    return '[Leschten] dddd [um] LT';
+                default:
+                    return '[Leschte] dddd [um] LT';
+            }
+        }
+    },
+    relativeTime : {
+        future : processFutureTime,
+        past : processPastTime,
+        s : 'e puer Sekonnen',
+        m : processRelativeTime$3,
+        mm : '%d Minutten',
+        h : processRelativeTime$3,
+        hh : '%d Stonnen',
+        d : processRelativeTime$3,
+        dd : '%d Deeg',
+        M : processRelativeTime$3,
+        MM : '%d Méint',
+        y : processRelativeTime$3,
+        yy : '%d Joer'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal: '%d.',
+    week: {
+        dow: 1, // Monday is the first day of the week.
+        doy: 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Lao [lo]
+//! author : Ryan Hart : https://github.com/ryanhart2
+
+hooks.defineLocale('lo', {
+    months : 'ມັງກອນ_ກຸມພາ_ມີນາ_ເມສາ_ພຶດສະພາ_ມິຖຸນາ_ກໍລະກົດ_ສິງຫາ_ກັນຍາ_ຕຸລາ_ພະຈິກ_ທັນວາ'.split('_'),
+    monthsShort : 'ມັງກອນ_ກຸມພາ_ມີນາ_ເມສາ_ພຶດສະພາ_ມິຖຸນາ_ກໍລະກົດ_ສິງຫາ_ກັນຍາ_ຕຸລາ_ພະຈິກ_ທັນວາ'.split('_'),
+    weekdays : 'ອາທິດ_ຈັນ_ອັງຄານ_ພຸດ_ພະຫັດ_ສຸກ_ເສົາ'.split('_'),
+    weekdaysShort : 'ທິດ_ຈັນ_ອັງຄານ_ພຸດ_ພະຫັດ_ສຸກ_ເສົາ'.split('_'),
+    weekdaysMin : 'ທ_ຈ_ອຄ_ພ_ພຫ_ສກ_ສ'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'ວັນdddd D MMMM YYYY HH:mm'
+    },
+    meridiemParse: /ຕອນເຊົ້າ|ຕອນແລງ/,
+    isPM: function (input) {
+        return input === 'ຕອນແລງ';
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return 'ຕອນເຊົ້າ';
+        } else {
+            return 'ຕອນແລງ';
+        }
+    },
+    calendar : {
+        sameDay : '[ມື້ນີ້ເວລາ] LT',
+        nextDay : '[ມື້ອື່ນເວລາ] LT',
+        nextWeek : '[ວັນ]dddd[ໜ້າເວລາ] LT',
+        lastDay : '[ມື້ວານນີ້ເວລາ] LT',
+        lastWeek : '[ວັນ]dddd[ແລ້ວນີ້ເວລາ] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'ອີກ %s',
+        past : '%sຜ່ານມາ',
+        s : 'ບໍ່ເທົ່າໃດວິນາທີ',
+        m : '1 ນາທີ',
+        mm : '%d ນາທີ',
+        h : '1 ຊົ່ວໂມງ',
+        hh : '%d ຊົ່ວໂມງ',
+        d : '1 ມື້',
+        dd : '%d ມື້',
+        M : '1 ເດືອນ',
+        MM : '%d ເດືອນ',
+        y : '1 ປີ',
+        yy : '%d ປີ'
+    },
+    ordinalParse: /(ທີ່)\d{1,2}/,
+    ordinal : function (number) {
+        return 'ທີ່' + number;
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Lithuanian [lt]
+//! author : Mindaugas Mozūras : https://github.com/mmozuras
+
+var units = {
+    'm' : 'minutÄ—_minutÄ—s_minutÄ™',
+    'mm': 'minutės_minučių_minutes',
+    'h' : 'valanda_valandos_valandÄ…',
+    'hh': 'valandos_valandų_valandas',
+    'd' : 'diena_dienos_dienÄ…',
+    'dd': 'dienos_dienų_dienas',
+    'M' : 'mėnuo_mėnesio_mėnesį',
+    'MM': 'mėnesiai_mėnesių_mėnesius',
+    'y' : 'metai_metų_metus',
+    'yy': 'metai_metų_metus'
+};
+function translateSeconds(number, withoutSuffix, key, isFuture) {
+    if (withoutSuffix) {
+        return 'kelios sekundÄ—s';
+    } else {
+        return isFuture ? 'kelių sekundžių' : 'kelias sekundes';
+    }
+}
+function translateSingular(number, withoutSuffix, key, isFuture) {
+    return withoutSuffix ? forms(key)[0] : (isFuture ? forms(key)[1] : forms(key)[2]);
+}
+function special(number) {
+    return number % 10 === 0 || (number > 10 && number < 20);
+}
+function forms(key) {
+    return units[key].split('_');
+}
+function translate$6(number, withoutSuffix, key, isFuture) {
+    var result = number + ' ';
+    if (number === 1) {
+        return result + translateSingular(number, withoutSuffix, key[0], isFuture);
+    } else if (withoutSuffix) {
+        return result + (special(number) ? forms(key)[1] : forms(key)[0]);
+    } else {
+        if (isFuture) {
+            return result + forms(key)[1];
+        } else {
+            return result + (special(number) ? forms(key)[1] : forms(key)[2]);
+        }
+    }
+}
+hooks.defineLocale('lt', {
+    months : {
+        format: 'sausio_vasario_kovo_balandžio_gegužės_birželio_liepos_rugpjūčio_rugsėjo_spalio_lapkričio_gruodžio'.split('_'),
+        standalone: 'sausis_vasaris_kovas_balandis_gegužė_birželis_liepa_rugpjūtis_rugsėjis_spalis_lapkritis_gruodis'.split('_'),
+        isFormat: /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?|MMMM?(\[[^\[\]]*\]|\s)+D[oD]?/
+    },
+    monthsShort : 'sau_vas_kov_bal_geg_bir_lie_rgp_rgs_spa_lap_grd'.split('_'),
+    weekdays : {
+        format: 'sekmadienį_pirmadienį_antradienį_trečiadienį_ketvirtadienį_penktadienį_šeštadienį'.split('_'),
+        standalone: 'sekmadienis_pirmadienis_antradienis_trečiadienis_ketvirtadienis_penktadienis_šeštadienis'.split('_'),
+        isFormat: /dddd HH:mm/
+    },
+    weekdaysShort : 'Sek_Pir_Ant_Tre_Ket_Pen_Šeš'.split('_'),
+    weekdaysMin : 'S_P_A_T_K_Pn_Å '.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'YYYY-MM-DD',
+        LL : 'YYYY [m.] MMMM D [d.]',
+        LLL : 'YYYY [m.] MMMM D [d.], HH:mm [val.]',
+        LLLL : 'YYYY [m.] MMMM D [d.], dddd, HH:mm [val.]',
+        l : 'YYYY-MM-DD',
+        ll : 'YYYY [m.] MMMM D [d.]',
+        lll : 'YYYY [m.] MMMM D [d.], HH:mm [val.]',
+        llll : 'YYYY [m.] MMMM D [d.], ddd, HH:mm [val.]'
+    },
+    calendar : {
+        sameDay : '[Å iandien] LT',
+        nextDay : '[Rytoj] LT',
+        nextWeek : 'dddd LT',
+        lastDay : '[Vakar] LT',
+        lastWeek : '[Praėjusį] dddd LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'po %s',
+        past : 'prieš %s',
+        s : translateSeconds,
+        m : translateSingular,
+        mm : translate$6,
+        h : translateSingular,
+        hh : translate$6,
+        d : translateSingular,
+        dd : translate$6,
+        M : translateSingular,
+        MM : translate$6,
+        y : translateSingular,
+        yy : translate$6
+    },
+    ordinalParse: /\d{1,2}-oji/,
+    ordinal : function (number) {
+        return number + '-oji';
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Latvian [lv]
+//! author : Kristaps Karlsons : https://github.com/skakri
+//! author : Jānis Elmeris : https://github.com/JanisE
+
+var units$1 = {
+    'm': 'minūtes_minūtēm_minūte_minūtes'.split('_'),
+    'mm': 'minūtes_minūtēm_minūte_minūtes'.split('_'),
+    'h': 'stundas_stundām_stunda_stundas'.split('_'),
+    'hh': 'stundas_stundām_stunda_stundas'.split('_'),
+    'd': 'dienas_dienām_diena_dienas'.split('_'),
+    'dd': 'dienas_dienām_diena_dienas'.split('_'),
+    'M': 'mēneša_mēnešiem_mēnesis_mēneši'.split('_'),
+    'MM': 'mēneša_mēnešiem_mēnesis_mēneši'.split('_'),
+    'y': 'gada_gadiem_gads_gadi'.split('_'),
+    'yy': 'gada_gadiem_gads_gadi'.split('_')
+};
+/**
+ * @param withoutSuffix boolean true = a length of time; false = before/after a period of time.
+ */
+function format$1(forms, number, withoutSuffix) {
+    if (withoutSuffix) {
+        // E.g. "21 minūte", "3 minūtes".
+        return number % 10 === 1 && number % 100 !== 11 ? forms[2] : forms[3];
+    } else {
+        // E.g. "21 minūtes" as in "pēc 21 minūtes".
+        // E.g. "3 minūtēm" as in "pēc 3 minūtēm".
+        return number % 10 === 1 && number % 100 !== 11 ? forms[0] : forms[1];
+    }
+}
+function relativeTimeWithPlural$1(number, withoutSuffix, key) {
+    return number + ' ' + format$1(units$1[key], number, withoutSuffix);
+}
+function relativeTimeWithSingular(number, withoutSuffix, key) {
+    return format$1(units$1[key], number, withoutSuffix);
+}
+function relativeSeconds(number, withoutSuffix) {
+    return withoutSuffix ? 'dažas sekundes' : 'dažām sekundēm';
+}
+
+hooks.defineLocale('lv', {
+    months : 'janvāris_februāris_marts_aprīlis_maijs_jūnijs_jūlijs_augusts_septembris_oktobris_novembris_decembris'.split('_'),
+    monthsShort : 'jan_feb_mar_apr_mai_jūn_jūl_aug_sep_okt_nov_dec'.split('_'),
+    weekdays : 'svētdiena_pirmdiena_otrdiena_trešdiena_ceturtdiena_piektdiena_sestdiena'.split('_'),
+    weekdaysShort : 'Sv_P_O_T_C_Pk_S'.split('_'),
+    weekdaysMin : 'Sv_P_O_T_C_Pk_S'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY.',
+        LL : 'YYYY. [gada] D. MMMM',
+        LLL : 'YYYY. [gada] D. MMMM, HH:mm',
+        LLLL : 'YYYY. [gada] D. MMMM, dddd, HH:mm'
+    },
+    calendar : {
+        sameDay : '[Å odien pulksten] LT',
+        nextDay : '[Rīt pulksten] LT',
+        nextWeek : 'dddd [pulksten] LT',
+        lastDay : '[Vakar pulksten] LT',
+        lastWeek : '[Pagājušā] dddd [pulksten] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'pēc %s',
+        past : 'pirms %s',
+        s : relativeSeconds,
+        m : relativeTimeWithSingular,
+        mm : relativeTimeWithPlural$1,
+        h : relativeTimeWithSingular,
+        hh : relativeTimeWithPlural$1,
+        d : relativeTimeWithSingular,
+        dd : relativeTimeWithPlural$1,
+        M : relativeTimeWithSingular,
+        MM : relativeTimeWithPlural$1,
+        y : relativeTimeWithSingular,
+        yy : relativeTimeWithPlural$1
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Montenegrin [me]
+//! author : Miodrag Nikač <miodrag@restartit.me> : https://github.com/miodragnikac
+
+var translator = {
+    words: { //Different grammatical cases
+        m: ['jedan minut', 'jednog minuta'],
+        mm: ['minut', 'minuta', 'minuta'],
+        h: ['jedan sat', 'jednog sata'],
+        hh: ['sat', 'sata', 'sati'],
+        dd: ['dan', 'dana', 'dana'],
+        MM: ['mjesec', 'mjeseca', 'mjeseci'],
+        yy: ['godina', 'godine', 'godina']
+    },
+    correctGrammaticalCase: function (number, wordKey) {
+        return number === 1 ? wordKey[0] : (number >= 2 && number <= 4 ? wordKey[1] : wordKey[2]);
+    },
+    translate: function (number, withoutSuffix, key) {
+        var wordKey = translator.words[key];
+        if (key.length === 1) {
+            return withoutSuffix ? wordKey[0] : wordKey[1];
+        } else {
+            return number + ' ' + translator.correctGrammaticalCase(number, wordKey);
+        }
+    }
+};
+
+hooks.defineLocale('me', {
+    months: 'januar_februar_mart_april_maj_jun_jul_avgust_septembar_oktobar_novembar_decembar'.split('_'),
+    monthsShort: 'jan._feb._mar._apr._maj_jun_jul_avg._sep._okt._nov._dec.'.split('_'),
+    monthsParseExact : true,
+    weekdays: 'nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota'.split('_'),
+    weekdaysShort: 'ned._pon._uto._sri._čet._pet._sub.'.split('_'),
+    weekdaysMin: 'ne_po_ut_sr_če_pe_su'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat: {
+        LT: 'H:mm',
+        LTS : 'H:mm:ss',
+        L: 'DD.MM.YYYY',
+        LL: 'D. MMMM YYYY',
+        LLL: 'D. MMMM YYYY H:mm',
+        LLLL: 'dddd, D. MMMM YYYY H:mm'
+    },
+    calendar: {
+        sameDay: '[danas u] LT',
+        nextDay: '[sjutra u] LT',
+
+        nextWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[u] [nedjelju] [u] LT';
+                case 3:
+                    return '[u] [srijedu] [u] LT';
+                case 6:
+                    return '[u] [subotu] [u] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[u] dddd [u] LT';
+            }
+        },
+        lastDay  : '[juče u] LT',
+        lastWeek : function () {
+            var lastWeekDays = [
+                '[prošle] [nedjelje] [u] LT',
+                '[prošlog] [ponedjeljka] [u] LT',
+                '[prošlog] [utorka] [u] LT',
+                '[prošle] [srijede] [u] LT',
+                '[prošlog] [četvrtka] [u] LT',
+                '[prošlog] [petka] [u] LT',
+                '[prošle] [subote] [u] LT'
+            ];
+            return lastWeekDays[this.day()];
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'za %s',
+        past   : 'prije %s',
+        s      : 'nekoliko sekundi',
+        m      : translator.translate,
+        mm     : translator.translate,
+        h      : translator.translate,
+        hh     : translator.translate,
+        d      : 'dan',
+        dd     : translator.translate,
+        M      : 'mjesec',
+        MM     : translator.translate,
+        y      : 'godinu',
+        yy     : translator.translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Maori [mi]
+//! author : John Corrigan <robbiecloset@gmail.com> : https://github.com/johnideal
+
+hooks.defineLocale('mi', {
+    months: 'Kohi-tāte_Hui-tanguru_Poutū-te-rangi_Paenga-whāwhā_Haratua_Pipiri_Hōngoingoi_Here-turi-kōkā_Mahuru_Whiringa-ā-nuku_Whiringa-ā-rangi_Hakihea'.split('_'),
+    monthsShort: 'Kohi_Hui_Pou_Pae_Hara_Pipi_Hōngoi_Here_Mahu_Whi-nu_Whi-ra_Haki'.split('_'),
+    monthsRegex: /(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,
+    monthsStrictRegex: /(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,
+    monthsShortRegex: /(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,
+    monthsShortStrictRegex: /(?:['a-z\u0101\u014D\u016B]+\-?){1,2}/i,
+    weekdays: 'Rātapu_Mane_Tūrei_Wenerei_Tāite_Paraire_Hātarei'.split('_'),
+    weekdaysShort: 'Ta_Ma_Tū_We_Tāi_Pa_Hā'.split('_'),
+    weekdaysMin: 'Ta_Ma_Tū_We_Tāi_Pa_Hā'.split('_'),
+    longDateFormat: {
+        LT: 'HH:mm',
+        LTS: 'HH:mm:ss',
+        L: 'DD/MM/YYYY',
+        LL: 'D MMMM YYYY',
+        LLL: 'D MMMM YYYY [i] HH:mm',
+        LLLL: 'dddd, D MMMM YYYY [i] HH:mm'
+    },
+    calendar: {
+        sameDay: '[i teie mahana, i] LT',
+        nextDay: '[apopo i] LT',
+        nextWeek: 'dddd [i] LT',
+        lastDay: '[inanahi i] LT',
+        lastWeek: 'dddd [whakamutunga i] LT',
+        sameElse: 'L'
+    },
+    relativeTime: {
+        future: 'i roto i %s',
+        past: '%s i mua',
+        s: 'te hēkona ruarua',
+        m: 'he meneti',
+        mm: '%d meneti',
+        h: 'te haora',
+        hh: '%d haora',
+        d: 'he ra',
+        dd: '%d ra',
+        M: 'he marama',
+        MM: '%d marama',
+        y: 'he tau',
+        yy: '%d tau'
+    },
+    ordinalParse: /\d{1,2}º/,
+    ordinal: '%dº',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Macedonian [mk]
+//! author : Borislav Mickov : https://github.com/B0k0
+
+hooks.defineLocale('mk', {
+    months : 'јануари_февруари_март_април_мај_јуни_јули_август_септември_октомври_ноември_декември'.split('_'),
+    monthsShort : 'јан_фев_мар_апр_мај_јун_јул_авг_сеп_окт_ное_дек'.split('_'),
+    weekdays : 'недела_понеделник_вторник_среда_четврток_петок_сабота'.split('_'),
+    weekdaysShort : 'нед_пон_вто_сре_чет_пет_саб'.split('_'),
+    weekdaysMin : 'нe_пo_вт_ср_че_пе_сa'.split('_'),
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'D.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY H:mm',
+        LLLL : 'dddd, D MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay : '[Денес во] LT',
+        nextDay : '[Утре во] LT',
+        nextWeek : '[Во] dddd [во] LT',
+        lastDay : '[Вчера во] LT',
+        lastWeek : function () {
+            switch (this.day()) {
+                case 0:
+                case 3:
+                case 6:
+                    return '[Изминатата] dddd [во] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[Изминатиот] dddd [во] LT';
+            }
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'после %s',
+        past : 'пред %s',
+        s : 'неколку секунди',
+        m : 'минута',
+        mm : '%d минути',
+        h : 'час',
+        hh : '%d часа',
+        d : 'ден',
+        dd : '%d дена',
+        M : 'месец',
+        MM : '%d месеци',
+        y : 'година',
+        yy : '%d години'
+    },
+    ordinalParse: /\d{1,2}-(ев|ен|ти|ви|ри|ми)/,
+    ordinal : function (number) {
+        var lastDigit = number % 10,
+            last2Digits = number % 100;
+        if (number === 0) {
+            return number + '-ев';
+        } else if (last2Digits === 0) {
+            return number + '-ен';
+        } else if (last2Digits > 10 && last2Digits < 20) {
+            return number + '-ти';
+        } else if (lastDigit === 1) {
+            return number + '-ви';
+        } else if (lastDigit === 2) {
+            return number + '-ри';
+        } else if (lastDigit === 7 || lastDigit === 8) {
+            return number + '-ми';
+        } else {
+            return number + '-ти';
+        }
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Malayalam [ml]
+//! author : Floyd Pink : https://github.com/floydpink
+
+hooks.defineLocale('ml', {
+    months : 'ജനുവരി_ഫെബ്രുവരി_മാർച്ച്_ഏപ്രിൽ_മേയ്_ജൂൺ_ജൂലൈ_ഓഗസ്റ്റ്_സെപ്റ്റംബർ_ഒക്ടോബർ_നവംബർ_ഡിസംബർ'.split('_'),
+    monthsShort : 'ജനു._ഫെബ്രു._മാർ._ഏപ്രി._മേയ്_ജൂൺ_ജൂലൈ._ഓഗ._സെപ്റ്റ._ഒക്ടോ._നവം._ഡിസം.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'ഞായറാഴ്ച_തിങ്കളാഴ്ച_ചൊവ്വാഴ്ച_ബുധനാഴ്ച_വ്യാഴാഴ്ച_വെള്ളിയാഴ്ച_ശനിയാഴ്ച'.split('_'),
+    weekdaysShort : 'ഞായർ_തിങ്കൾ_ചൊവ്വ_ബുധൻ_വ്യാഴം_വെള്ളി_ശനി'.split('_'),
+    weekdaysMin : 'ഞാ_തി_ചൊ_ബു_വ്യാ_വെ_ശ'.split('_'),
+    longDateFormat : {
+        LT : 'A h:mm -നു',
+        LTS : 'A h:mm:ss -നു',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, A h:mm -നു',
+        LLLL : 'dddd, D MMMM YYYY, A h:mm -നു'
+    },
+    calendar : {
+        sameDay : '[ഇന്ന്] LT',
+        nextDay : '[നാളെ] LT',
+        nextWeek : 'dddd, LT',
+        lastDay : '[ഇന്നലെ] LT',
+        lastWeek : '[കഴിഞ്ഞ] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s കഴിഞ്ഞ്',
+        past : '%s മുൻപ്',
+        s : 'അൽപ നിമിഷങ്ങൾ',
+        m : 'ഒരു മിനിറ്റ്',
+        mm : '%d മിനിറ്റ്',
+        h : 'ഒരു മണിക്കൂർ',
+        hh : '%d മണിക്കൂർ',
+        d : 'ഒരു ദിവസം',
+        dd : '%d ദിവസം',
+        M : 'ഒരു മാസം',
+        MM : '%d മാസം',
+        y : 'ഒരു വർഷം',
+        yy : '%d വർഷം'
+    },
+    meridiemParse: /രാത്രി|രാവിലെ|ഉച്ച കഴിഞ്ഞ്|വൈകുന്നേരം|രാത്രി/i,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if ((meridiem === 'രാത്രി' && hour >= 4) ||
+                meridiem === 'ഉച്ച കഴിഞ്ഞ്' ||
+                meridiem === 'വൈകുന്നേരം') {
+            return hour + 12;
+        } else {
+            return hour;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'രാത്രി';
+        } else if (hour < 12) {
+            return 'രാവിലെ';
+        } else if (hour < 17) {
+            return 'ഉച്ച കഴിഞ്ഞ്';
+        } else if (hour < 20) {
+            return 'വൈകുന്നേരം';
+        } else {
+            return 'രാത്രി';
+        }
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Marathi [mr]
+//! author : Harshad Kale : https://github.com/kalehv
+//! author : Vivek Athalye : https://github.com/vnathalye
+
+var symbolMap$7 = {
+    '1': '१',
+    '2': '२',
+    '3': '३',
+    '4': '४',
+    '5': '५',
+    '6': '६',
+    '7': '७',
+    '8': '८',
+    '9': '९',
+    '0': '०'
+};
+var numberMap$6 = {
+    '१': '1',
+    '२': '2',
+    '३': '3',
+    '४': '4',
+    '५': '5',
+    '६': '6',
+    '७': '7',
+    '८': '8',
+    '९': '9',
+    '०': '0'
+};
+
+function relativeTimeMr(number, withoutSuffix, string, isFuture)
+{
+    var output = '';
+    if (withoutSuffix) {
+        switch (string) {
+            case 's': output = 'काही सेकंद'; break;
+            case 'm': output = 'एक मिनिट'; break;
+            case 'mm': output = '%d मिनिटे'; break;
+            case 'h': output = 'एक तास'; break;
+            case 'hh': output = '%d तास'; break;
+            case 'd': output = 'एक दिवस'; break;
+            case 'dd': output = '%d दिवस'; break;
+            case 'M': output = 'एक महिना'; break;
+            case 'MM': output = '%d महिने'; break;
+            case 'y': output = 'एक वर्ष'; break;
+            case 'yy': output = '%d वर्षे'; break;
+        }
+    }
+    else {
+        switch (string) {
+            case 's': output = 'काही सेकंदां'; break;
+            case 'm': output = 'एका मिनिटा'; break;
+            case 'mm': output = '%d मिनिटां'; break;
+            case 'h': output = 'एका तासा'; break;
+            case 'hh': output = '%d तासां'; break;
+            case 'd': output = 'एका दिवसा'; break;
+            case 'dd': output = '%d दिवसां'; break;
+            case 'M': output = 'एका महिन्या'; break;
+            case 'MM': output = '%d महिन्यां'; break;
+            case 'y': output = 'एका वर्षा'; break;
+            case 'yy': output = '%d वर्षां'; break;
+        }
+    }
+    return output.replace(/%d/i, number);
+}
+
+hooks.defineLocale('mr', {
+    months : 'जानेवारी_फेब्रुवारी_मार्च_एप्रिल_मे_जून_जुलै_ऑगस्ट_सप्टेंबर_ऑक्टोबर_नोव्हेंबर_डिसेंबर'.split('_'),
+    monthsShort: 'जाने._फेब्रु._मार्च._एप्रि._मे._जून._जुलै._ऑग._सप्टें._ऑक्टो._नोव्हें._डिसें.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'रविवार_सोमवार_मंगळवार_बुधवार_गुरूवार_शुक्रवार_शनिवार'.split('_'),
+    weekdaysShort : 'रवि_सोम_मंगळ_बुध_गुरू_शुक्र_शनि'.split('_'),
+    weekdaysMin : 'र_सो_मं_बु_गु_शु_श'.split('_'),
+    longDateFormat : {
+        LT : 'A h:mm वाजता',
+        LTS : 'A h:mm:ss वाजता',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, A h:mm वाजता',
+        LLLL : 'dddd, D MMMM YYYY, A h:mm वाजता'
+    },
+    calendar : {
+        sameDay : '[आज] LT',
+        nextDay : '[उद्या] LT',
+        nextWeek : 'dddd, LT',
+        lastDay : '[काल] LT',
+        lastWeek: '[मागील] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future: '%sमध्ये',
+        past: '%sपूर्वी',
+        s: relativeTimeMr,
+        m: relativeTimeMr,
+        mm: relativeTimeMr,
+        h: relativeTimeMr,
+        hh: relativeTimeMr,
+        d: relativeTimeMr,
+        dd: relativeTimeMr,
+        M: relativeTimeMr,
+        MM: relativeTimeMr,
+        y: relativeTimeMr,
+        yy: relativeTimeMr
+    },
+    preparse: function (string) {
+        return string.replace(/[१२३४५६७८९०]/g, function (match) {
+            return numberMap$6[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap$7[match];
+        });
+    },
+    meridiemParse: /रात्री|सकाळी|दुपारी|सायंकाळी/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'रात्री') {
+            return hour < 4 ? hour : hour + 12;
+        } else if (meridiem === 'सकाळी') {
+            return hour;
+        } else if (meridiem === 'दुपारी') {
+            return hour >= 10 ? hour : hour + 12;
+        } else if (meridiem === 'सायंकाळी') {
+            return hour + 12;
+        }
+    },
+    meridiem: function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'रात्री';
+        } else if (hour < 10) {
+            return 'सकाळी';
+        } else if (hour < 17) {
+            return 'दुपारी';
+        } else if (hour < 20) {
+            return 'सायंकाळी';
+        } else {
+            return 'रात्री';
+        }
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Malay [ms-my]
+//! note : DEPRECATED, the correct one is [ms]
+//! author : Weldan Jamili : https://github.com/weldan
+
+hooks.defineLocale('ms-my', {
+    months : 'Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember'.split('_'),
+    monthsShort : 'Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis'.split('_'),
+    weekdays : 'Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu'.split('_'),
+    weekdaysShort : 'Ahd_Isn_Sel_Rab_Kha_Jum_Sab'.split('_'),
+    weekdaysMin : 'Ah_Is_Sl_Rb_Km_Jm_Sb'.split('_'),
+    longDateFormat : {
+        LT : 'HH.mm',
+        LTS : 'HH.mm.ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY [pukul] HH.mm',
+        LLLL : 'dddd, D MMMM YYYY [pukul] HH.mm'
+    },
+    meridiemParse: /pagi|tengahari|petang|malam/,
+    meridiemHour: function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'pagi') {
+            return hour;
+        } else if (meridiem === 'tengahari') {
+            return hour >= 11 ? hour : hour + 12;
+        } else if (meridiem === 'petang' || meridiem === 'malam') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 11) {
+            return 'pagi';
+        } else if (hours < 15) {
+            return 'tengahari';
+        } else if (hours < 19) {
+            return 'petang';
+        } else {
+            return 'malam';
+        }
+    },
+    calendar : {
+        sameDay : '[Hari ini pukul] LT',
+        nextDay : '[Esok pukul] LT',
+        nextWeek : 'dddd [pukul] LT',
+        lastDay : '[Kelmarin pukul] LT',
+        lastWeek : 'dddd [lepas pukul] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'dalam %s',
+        past : '%s yang lepas',
+        s : 'beberapa saat',
+        m : 'seminit',
+        mm : '%d minit',
+        h : 'sejam',
+        hh : '%d jam',
+        d : 'sehari',
+        dd : '%d hari',
+        M : 'sebulan',
+        MM : '%d bulan',
+        y : 'setahun',
+        yy : '%d tahun'
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Malay [ms]
+//! author : Weldan Jamili : https://github.com/weldan
+
+hooks.defineLocale('ms', {
+    months : 'Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember'.split('_'),
+    monthsShort : 'Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis'.split('_'),
+    weekdays : 'Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu'.split('_'),
+    weekdaysShort : 'Ahd_Isn_Sel_Rab_Kha_Jum_Sab'.split('_'),
+    weekdaysMin : 'Ah_Is_Sl_Rb_Km_Jm_Sb'.split('_'),
+    longDateFormat : {
+        LT : 'HH.mm',
+        LTS : 'HH.mm.ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY [pukul] HH.mm',
+        LLLL : 'dddd, D MMMM YYYY [pukul] HH.mm'
+    },
+    meridiemParse: /pagi|tengahari|petang|malam/,
+    meridiemHour: function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'pagi') {
+            return hour;
+        } else if (meridiem === 'tengahari') {
+            return hour >= 11 ? hour : hour + 12;
+        } else if (meridiem === 'petang' || meridiem === 'malam') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 11) {
+            return 'pagi';
+        } else if (hours < 15) {
+            return 'tengahari';
+        } else if (hours < 19) {
+            return 'petang';
+        } else {
+            return 'malam';
+        }
+    },
+    calendar : {
+        sameDay : '[Hari ini pukul] LT',
+        nextDay : '[Esok pukul] LT',
+        nextWeek : 'dddd [pukul] LT',
+        lastDay : '[Kelmarin pukul] LT',
+        lastWeek : 'dddd [lepas pukul] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'dalam %s',
+        past : '%s yang lepas',
+        s : 'beberapa saat',
+        m : 'seminit',
+        mm : '%d minit',
+        h : 'sejam',
+        hh : '%d jam',
+        d : 'sehari',
+        dd : '%d hari',
+        M : 'sebulan',
+        MM : '%d bulan',
+        y : 'setahun',
+        yy : '%d tahun'
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Burmese [my]
+//! author : Squar team, mysquar.com
+//! author : David Rossellat : https://github.com/gholadr
+//! author : Tin Aung Lin : https://github.com/thanyawzinmin
+
+var symbolMap$8 = {
+    '1': '၁',
+    '2': '၂',
+    '3': '၃',
+    '4': '၄',
+    '5': '၅',
+    '6': '၆',
+    '7': '၇',
+    '8': '၈',
+    '9': '၉',
+    '0': '၀'
+};
+var numberMap$7 = {
+    '၁': '1',
+    '၂': '2',
+    '၃': '3',
+    '၄': '4',
+    '၅': '5',
+    '၆': '6',
+    '၇': '7',
+    '၈': '8',
+    '၉': '9',
+    '၀': '0'
+};
+
+hooks.defineLocale('my', {
+    months: 'ဇန်နဝါရီ_ဖေဖော်ဝါရီ_မတ်_ဧပြီ_မေ_ဇွန်_ဇူလိုင်_သြဂုတ်_စက်တင်ဘာ_အောက်တိုဘာ_နိုဝင်ဘာ_ဒီဇင်ဘာ'.split('_'),
+    monthsShort: 'ဇန်_ဖေ_မတ်_ပြီ_မေ_ဇွန်_လိုင်_သြ_စက်_အောက်_နို_ဒီ'.split('_'),
+    weekdays: 'တနင်္ဂနွေ_တနင်္လာ_အင်္ဂါ_ဗုဒ္ဓဟူး_ကြာသပတေး_သောကြာ_စနေ'.split('_'),
+    weekdaysShort: 'နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ'.split('_'),
+    weekdaysMin: 'နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ'.split('_'),
+
+    longDateFormat: {
+        LT: 'HH:mm',
+        LTS: 'HH:mm:ss',
+        L: 'DD/MM/YYYY',
+        LL: 'D MMMM YYYY',
+        LLL: 'D MMMM YYYY HH:mm',
+        LLLL: 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar: {
+        sameDay: '[ယနေ.] LT [မှာ]',
+        nextDay: '[မနက်ဖြန်] LT [မှာ]',
+        nextWeek: 'dddd LT [မှာ]',
+        lastDay: '[မနေ.က] LT [မှာ]',
+        lastWeek: '[ပြီးခဲ့သော] dddd LT [မှာ]',
+        sameElse: 'L'
+    },
+    relativeTime: {
+        future: 'လာမည့် %s မှာ',
+        past: 'လွန်ခဲ့သော %s က',
+        s: 'စက္ကန်.အနည်းငယ်',
+        m: 'တစ်မိနစ်',
+        mm: '%d မိနစ်',
+        h: 'တစ်နာရီ',
+        hh: '%d နာရီ',
+        d: 'တစ်ရက်',
+        dd: '%d ရက်',
+        M: 'တစ်လ',
+        MM: '%d လ',
+        y: 'တစ်နှစ်',
+        yy: '%d နှစ်'
+    },
+    preparse: function (string) {
+        return string.replace(/[၁၂၃၄၅၆၇၈၉၀]/g, function (match) {
+            return numberMap$7[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap$8[match];
+        });
+    },
+    week: {
+        dow: 1, // Monday is the first day of the week.
+        doy: 4 // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Norwegian Bokmål [nb]
+//! authors : Espen Hovlandsdal : https://github.com/rexxars
+//!           Sigurd Gartmann : https://github.com/sigurdga
+
+hooks.defineLocale('nb', {
+    months : 'januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember'.split('_'),
+    monthsShort : 'jan._feb._mars_april_mai_juni_juli_aug._sep._okt._nov._des.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag'.split('_'),
+    weekdaysShort : 'sø._ma._ti._on._to._fr._lø.'.split('_'),
+    weekdaysMin : 'sø_ma_ti_on_to_fr_lø'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY [kl.] HH:mm',
+        LLLL : 'dddd D. MMMM YYYY [kl.] HH:mm'
+    },
+    calendar : {
+        sameDay: '[i dag kl.] LT',
+        nextDay: '[i morgen kl.] LT',
+        nextWeek: 'dddd [kl.] LT',
+        lastDay: '[i går kl.] LT',
+        lastWeek: '[forrige] dddd [kl.] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'om %s',
+        past : '%s siden',
+        s : 'noen sekunder',
+        m : 'ett minutt',
+        mm : '%d minutter',
+        h : 'en time',
+        hh : '%d timer',
+        d : 'en dag',
+        dd : '%d dager',
+        M : 'en måned',
+        MM : '%d måneder',
+        y : 'ett år',
+        yy : '%d år'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Nepalese [ne]
+//! author : suvash : https://github.com/suvash
+
+var symbolMap$9 = {
+    '1': '१',
+    '2': '२',
+    '3': '३',
+    '4': '४',
+    '5': '५',
+    '6': '६',
+    '7': '७',
+    '8': '८',
+    '9': '९',
+    '0': '०'
+};
+var numberMap$8 = {
+    '१': '1',
+    '२': '2',
+    '३': '3',
+    '४': '4',
+    '५': '5',
+    '६': '6',
+    '७': '7',
+    '८': '8',
+    '९': '9',
+    '०': '0'
+};
+
+hooks.defineLocale('ne', {
+    months : 'जनवरी_फेब्रुवरी_मार्च_अप्रिल_मई_जुन_जुलाई_अगष्ट_सेप्टेम्बर_अक्टोबर_नोभेम्बर_डिसेम्बर'.split('_'),
+    monthsShort : 'जन._फेब्रु._मार्च_अप्रि._मई_जुन_जुलाई._अग._सेप्ट._अक्टो._नोभे._डिसे.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'आइतबार_सोमबार_मङ्गलबार_बुधबार_बिहिबार_शुक्रबार_शनिबार'.split('_'),
+    weekdaysShort : 'आइत._सोम._मङ्गल._बुध._बिहि._शुक्र._शनि.'.split('_'),
+    weekdaysMin : 'आ._सो._मं._बु._बि._शु._श.'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'Aको h:mm बजे',
+        LTS : 'Aको h:mm:ss बजे',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, Aको h:mm बजे',
+        LLLL : 'dddd, D MMMM YYYY, Aको h:mm बजे'
+    },
+    preparse: function (string) {
+        return string.replace(/[१२३४५६७८९०]/g, function (match) {
+            return numberMap$8[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap$9[match];
+        });
+    },
+    meridiemParse: /राति|बिहान|दिउँसो|साँझ/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'राति') {
+            return hour < 4 ? hour : hour + 12;
+        } else if (meridiem === 'बिहान') {
+            return hour;
+        } else if (meridiem === 'दिउँसो') {
+            return hour >= 10 ? hour : hour + 12;
+        } else if (meridiem === 'साँझ') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 3) {
+            return 'राति';
+        } else if (hour < 12) {
+            return 'बिहान';
+        } else if (hour < 16) {
+            return 'दिउँसो';
+        } else if (hour < 20) {
+            return 'साँझ';
+        } else {
+            return 'राति';
+        }
+    },
+    calendar : {
+        sameDay : '[आज] LT',
+        nextDay : '[भोलि] LT',
+        nextWeek : '[आउँदो] dddd[,] LT',
+        lastDay : '[हिजो] LT',
+        lastWeek : '[गएको] dddd[,] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%sमा',
+        past : '%s अगाडि',
+        s : 'केही क्षण',
+        m : 'एक मिनेट',
+        mm : '%d मिनेट',
+        h : 'एक घण्टा',
+        hh : '%d घण्टा',
+        d : 'एक दिन',
+        dd : '%d दिन',
+        M : 'एक महिना',
+        MM : '%d महिना',
+        y : 'एक बर्ष',
+        yy : '%d बर्ष'
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Dutch (Belgium) [nl-be]
+//! author : Joris Röling : https://github.com/jorisroling
+//! author : Jacob Middag : https://github.com/middagj
+
+var monthsShortWithDots$1 = 'jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.'.split('_');
+var monthsShortWithoutDots$1 = 'jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec'.split('_');
+
+var monthsParse = [/^jan/i, /^feb/i, /^maart|mrt.?$/i, /^apr/i, /^mei$/i, /^jun[i.]?$/i, /^jul[i.]?$/i, /^aug/i, /^sep/i, /^okt/i, /^nov/i, /^dec/i];
+var monthsRegex$1 = /^(januari|februari|maart|april|mei|april|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i;
+
+hooks.defineLocale('nl-be', {
+    months : 'januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december'.split('_'),
+    monthsShort : function (m, format) {
+        if (/-MMM-/.test(format)) {
+            return monthsShortWithoutDots$1[m.month()];
+        } else {
+            return monthsShortWithDots$1[m.month()];
+        }
+    },
+
+    monthsRegex: monthsRegex$1,
+    monthsShortRegex: monthsRegex$1,
+    monthsStrictRegex: /^(januari|februari|maart|mei|ju[nl]i|april|augustus|september|oktober|november|december)/i,
+    monthsShortStrictRegex: /^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i,
+
+    monthsParse : monthsParse,
+    longMonthsParse : monthsParse,
+    shortMonthsParse : monthsParse,
+
+    weekdays : 'zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag'.split('_'),
+    weekdaysShort : 'zo._ma._di._wo._do._vr._za.'.split('_'),
+    weekdaysMin : 'Zo_Ma_Di_Wo_Do_Vr_Za'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[vandaag om] LT',
+        nextDay: '[morgen om] LT',
+        nextWeek: 'dddd [om] LT',
+        lastDay: '[gisteren om] LT',
+        lastWeek: '[afgelopen] dddd [om] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'over %s',
+        past : '%s geleden',
+        s : 'een paar seconden',
+        m : 'één minuut',
+        mm : '%d minuten',
+        h : 'één uur',
+        hh : '%d uur',
+        d : 'één dag',
+        dd : '%d dagen',
+        M : 'één maand',
+        MM : '%d maanden',
+        y : 'één jaar',
+        yy : '%d jaar'
+    },
+    ordinalParse: /\d{1,2}(ste|de)/,
+    ordinal : function (number) {
+        return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de');
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Dutch [nl]
+//! author : Joris Röling : https://github.com/jorisroling
+//! author : Jacob Middag : https://github.com/middagj
+
+var monthsShortWithDots$2 = 'jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.'.split('_');
+var monthsShortWithoutDots$2 = 'jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec'.split('_');
+
+var monthsParse$1 = [/^jan/i, /^feb/i, /^maart|mrt.?$/i, /^apr/i, /^mei$/i, /^jun[i.]?$/i, /^jul[i.]?$/i, /^aug/i, /^sep/i, /^okt/i, /^nov/i, /^dec/i];
+var monthsRegex$2 = /^(januari|februari|maart|april|mei|april|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i;
+
+hooks.defineLocale('nl', {
+    months : 'januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december'.split('_'),
+    monthsShort : function (m, format) {
+        if (/-MMM-/.test(format)) {
+            return monthsShortWithoutDots$2[m.month()];
+        } else {
+            return monthsShortWithDots$2[m.month()];
+        }
+    },
+
+    monthsRegex: monthsRegex$2,
+    monthsShortRegex: monthsRegex$2,
+    monthsStrictRegex: /^(januari|februari|maart|mei|ju[nl]i|april|augustus|september|oktober|november|december)/i,
+    monthsShortStrictRegex: /^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i,
+
+    monthsParse : monthsParse$1,
+    longMonthsParse : monthsParse$1,
+    shortMonthsParse : monthsParse$1,
+
+    weekdays : 'zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag'.split('_'),
+    weekdaysShort : 'zo._ma._di._wo._do._vr._za.'.split('_'),
+    weekdaysMin : 'Zo_Ma_Di_Wo_Do_Vr_Za'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD-MM-YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[vandaag om] LT',
+        nextDay: '[morgen om] LT',
+        nextWeek: 'dddd [om] LT',
+        lastDay: '[gisteren om] LT',
+        lastWeek: '[afgelopen] dddd [om] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'over %s',
+        past : '%s geleden',
+        s : 'een paar seconden',
+        m : 'één minuut',
+        mm : '%d minuten',
+        h : 'één uur',
+        hh : '%d uur',
+        d : 'één dag',
+        dd : '%d dagen',
+        M : 'één maand',
+        MM : '%d maanden',
+        y : 'één jaar',
+        yy : '%d jaar'
+    },
+    ordinalParse: /\d{1,2}(ste|de)/,
+    ordinal : function (number) {
+        return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de');
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Nynorsk [nn]
+//! author : https://github.com/mechuwind
+
+hooks.defineLocale('nn', {
+    months : 'januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember'.split('_'),
+    monthsShort : 'jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_'),
+    weekdays : 'sundag_måndag_tysdag_onsdag_torsdag_fredag_laurdag'.split('_'),
+    weekdaysShort : 'sun_mån_tys_ons_tor_fre_lau'.split('_'),
+    weekdaysMin : 'su_må_ty_on_to_fr_lø'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY [kl.] H:mm',
+        LLLL : 'dddd D. MMMM YYYY [kl.] HH:mm'
+    },
+    calendar : {
+        sameDay: '[I dag klokka] LT',
+        nextDay: '[I morgon klokka] LT',
+        nextWeek: 'dddd [klokka] LT',
+        lastDay: '[I går klokka] LT',
+        lastWeek: '[Føregåande] dddd [klokka] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'om %s',
+        past : '%s sidan',
+        s : 'nokre sekund',
+        m : 'eit minutt',
+        mm : '%d minutt',
+        h : 'ein time',
+        hh : '%d timar',
+        d : 'ein dag',
+        dd : '%d dagar',
+        M : 'ein månad',
+        MM : '%d månader',
+        y : 'eit år',
+        yy : '%d år'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Punjabi (India) [pa-in]
+//! author : Harpreet Singh : https://github.com/harpreetkhalsagtbit
+
+var symbolMap$10 = {
+    '1': 'à©§',
+    '2': '੨',
+    '3': 'à©©',
+    '4': '੪',
+    '5': 'à©«',
+    '6': '੬',
+    '7': 'à©­',
+    '8': 'à©®',
+    '9': '੯',
+    '0': '੦'
+};
+var numberMap$9 = {
+    'à©§': '1',
+    '੨': '2',
+    'à©©': '3',
+    '੪': '4',
+    'à©«': '5',
+    '੬': '6',
+    'à©­': '7',
+    'à©®': '8',
+    '੯': '9',
+    '੦': '0'
+};
+
+hooks.defineLocale('pa-in', {
+    // There are months name as per Nanakshahi Calender but they are not used as rigidly in modern Punjabi.
+    months : 'ਜਨਵਰੀ_ਫ਼ਰਵਰੀ_ਮਾਰਚ_ਅਪ੍ਰੈਲ_ਮਈ_ਜੂਨ_ਜੁਲਾਈ_ਅਗਸਤ_ਸਤੰਬਰ_ਅਕਤੂਬਰ_ਨਵੰਬਰ_ਦਸੰਬਰ'.split('_'),
+    monthsShort : 'ਜਨਵਰੀ_ਫ਼ਰਵਰੀ_ਮਾਰਚ_ਅਪ੍ਰੈਲ_ਮਈ_ਜੂਨ_ਜੁਲਾਈ_ਅਗਸਤ_ਸਤੰਬਰ_ਅਕਤੂਬਰ_ਨਵੰਬਰ_ਦਸੰਬਰ'.split('_'),
+    weekdays : 'ਐਤਵਾਰ_ਸੋਮਵਾਰ_ਮੰਗਲਵਾਰ_ਬੁਧਵਾਰ_ਵੀਰਵਾਰ_ਸ਼ੁੱਕਰਵਾਰ_ਸ਼ਨੀਚਰਵਾਰ'.split('_'),
+    weekdaysShort : 'ਐਤ_ਸੋਮ_ਮੰਗਲ_ਬੁਧ_ਵੀਰ_ਸ਼ੁਕਰ_ਸ਼ਨੀ'.split('_'),
+    weekdaysMin : 'ਐਤ_ਸੋਮ_ਮੰਗਲ_ਬੁਧ_ਵੀਰ_ਸ਼ੁਕਰ_ਸ਼ਨੀ'.split('_'),
+    longDateFormat : {
+        LT : 'A h:mm ਵਜੇ',
+        LTS : 'A h:mm:ss ਵਜੇ',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, A h:mm ਵਜੇ',
+        LLLL : 'dddd, D MMMM YYYY, A h:mm ਵਜੇ'
+    },
+    calendar : {
+        sameDay : '[ਅਜ] LT',
+        nextDay : '[ਕਲ] LT',
+        nextWeek : 'dddd, LT',
+        lastDay : '[ਕਲ] LT',
+        lastWeek : '[ਪਿਛਲੇ] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s ਵਿੱਚ',
+        past : '%s ਪਿਛਲੇ',
+        s : 'ਕੁਝ ਸਕਿੰਟ',
+        m : 'ਇਕ ਮਿੰਟ',
+        mm : '%d ਮਿੰਟ',
+        h : 'ਇੱਕ ਘੰਟਾ',
+        hh : '%d ਘੰਟੇ',
+        d : 'ਇੱਕ ਦਿਨ',
+        dd : '%d ਦਿਨ',
+        M : 'ਇੱਕ ਮਹੀਨਾ',
+        MM : '%d ਮਹੀਨੇ',
+        y : 'ਇੱਕ ਸਾਲ',
+        yy : '%d ਸਾਲ'
+    },
+    preparse: function (string) {
+        return string.replace(/[੧੨੩੪੫੬੭੮੯੦]/g, function (match) {
+            return numberMap$9[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap$10[match];
+        });
+    },
+    // Punjabi notation for meridiems are quite fuzzy in practice. While there exists
+    // a rigid notion of a 'Pahar' it is not used as rigidly in modern Punjabi.
+    meridiemParse: /ਰਾਤ|ਸਵੇਰ|ਦੁਪਹਿਰ|ਸ਼ਾਮ/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'ਰਾਤ') {
+            return hour < 4 ? hour : hour + 12;
+        } else if (meridiem === 'ਸਵੇਰ') {
+            return hour;
+        } else if (meridiem === 'ਦੁਪਹਿਰ') {
+            return hour >= 10 ? hour : hour + 12;
+        } else if (meridiem === 'ਸ਼ਾਮ') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'ਰਾਤ';
+        } else if (hour < 10) {
+            return 'ਸਵੇਰ';
+        } else if (hour < 17) {
+            return 'ਦੁਪਹਿਰ';
+        } else if (hour < 20) {
+            return 'ਸ਼ਾਮ';
+        } else {
+            return 'ਰਾਤ';
+        }
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Polish [pl]
+//! author : Rafal Hirsz : https://github.com/evoL
+
+var monthsNominative = 'styczeń_luty_marzec_kwiecień_maj_czerwiec_lipiec_sierpień_wrzesień_październik_listopad_grudzień'.split('_');
+var monthsSubjective = 'stycznia_lutego_marca_kwietnia_maja_czerwca_lipca_sierpnia_września_października_listopada_grudnia'.split('_');
+function plural$3(n) {
+    return (n % 10 < 5) && (n % 10 > 1) && ((~~(n / 10) % 10) !== 1);
+}
+function translate$7(number, withoutSuffix, key) {
+    var result = number + ' ';
+    switch (key) {
+        case 'm':
+            return withoutSuffix ? 'minuta' : 'minutÄ™';
+        case 'mm':
+            return result + (plural$3(number) ? 'minuty' : 'minut');
+        case 'h':
+            return withoutSuffix  ? 'godzina'  : 'godzinÄ™';
+        case 'hh':
+            return result + (plural$3(number) ? 'godziny' : 'godzin');
+        case 'MM':
+            return result + (plural$3(number) ? 'miesiące' : 'miesięcy');
+        case 'yy':
+            return result + (plural$3(number) ? 'lata' : 'lat');
+    }
+}
+
+hooks.defineLocale('pl', {
+    months : function (momentToFormat, format) {
+        if (format === '') {
+            // Hack: if format empty we know this is used to generate
+            // RegExp by moment. Give then back both valid forms of months
+            // in RegExp ready format.
+            return '(' + monthsSubjective[momentToFormat.month()] + '|' + monthsNominative[momentToFormat.month()] + ')';
+        } else if (/D MMMM/.test(format)) {
+            return monthsSubjective[momentToFormat.month()];
+        } else {
+            return monthsNominative[momentToFormat.month()];
+        }
+    },
+    monthsShort : 'sty_lut_mar_kwi_maj_cze_lip_sie_wrz_paź_lis_gru'.split('_'),
+    weekdays : 'niedziela_poniedziałek_wtorek_środa_czwartek_piątek_sobota'.split('_'),
+    weekdaysShort : 'ndz_pon_wt_śr_czw_pt_sob'.split('_'),
+    weekdaysMin : 'Nd_Pn_Wt_Åšr_Cz_Pt_So'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[DziÅ› o] LT',
+        nextDay: '[Jutro o] LT',
+        nextWeek: '[W] dddd [o] LT',
+        lastDay: '[Wczoraj o] LT',
+        lastWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[W zeszłą niedzielę o] LT';
+                case 3:
+                    return '[W zeszłą środę o] LT';
+                case 6:
+                    return '[W zeszłą sobotę o] LT';
+                default:
+                    return '[W zeszły] dddd [o] LT';
+            }
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'za %s',
+        past : '%s temu',
+        s : 'kilka sekund',
+        m : translate$7,
+        mm : translate$7,
+        h : translate$7,
+        hh : translate$7,
+        d : '1 dzień',
+        dd : '%d dni',
+        M : 'miesiÄ…c',
+        MM : translate$7,
+        y : 'rok',
+        yy : translate$7
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Portuguese (Brazil) [pt-br]
+//! author : Caio Ribeiro Pereira : https://github.com/caio-ribeiro-pereira
+
+hooks.defineLocale('pt-br', {
+    months : 'Janeiro_Fevereiro_Março_Abril_Maio_Junho_Julho_Agosto_Setembro_Outubro_Novembro_Dezembro'.split('_'),
+    monthsShort : 'Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez'.split('_'),
+    weekdays : 'Domingo_Segunda-feira_Terça-feira_Quarta-feira_Quinta-feira_Sexta-feira_Sábado'.split('_'),
+    weekdaysShort : 'Dom_Seg_Ter_Qua_Qui_Sex_Sáb'.split('_'),
+    weekdaysMin : 'Dom_2ª_3ª_4ª_5ª_6ª_Sáb'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D [de] MMMM [de] YYYY',
+        LLL : 'D [de] MMMM [de] YYYY [às] HH:mm',
+        LLLL : 'dddd, D [de] MMMM [de] YYYY [às] HH:mm'
+    },
+    calendar : {
+        sameDay: '[Hoje às] LT',
+        nextDay: '[Amanhã às] LT',
+        nextWeek: 'dddd [às] LT',
+        lastDay: '[Ontem às] LT',
+        lastWeek: function () {
+            return (this.day() === 0 || this.day() === 6) ?
+                '[Último] dddd [às] LT' : // Saturday + Sunday
+                '[Última] dddd [às] LT'; // Monday - Friday
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'em %s',
+        past : '%s atrás',
+        s : 'poucos segundos',
+        m : 'um minuto',
+        mm : '%d minutos',
+        h : 'uma hora',
+        hh : '%d horas',
+        d : 'um dia',
+        dd : '%d dias',
+        M : 'um mês',
+        MM : '%d meses',
+        y : 'um ano',
+        yy : '%d anos'
+    },
+    ordinalParse: /\d{1,2}º/,
+    ordinal : '%dº'
+});
+
+//! moment.js locale configuration
+//! locale : Portuguese [pt]
+//! author : Jefferson : https://github.com/jalex79
+
+hooks.defineLocale('pt', {
+    months : 'Janeiro_Fevereiro_Março_Abril_Maio_Junho_Julho_Agosto_Setembro_Outubro_Novembro_Dezembro'.split('_'),
+    monthsShort : 'Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez'.split('_'),
+    weekdays : 'Domingo_Segunda-Feira_Terça-Feira_Quarta-Feira_Quinta-Feira_Sexta-Feira_Sábado'.split('_'),
+    weekdaysShort : 'Dom_Seg_Ter_Qua_Qui_Sex_Sáb'.split('_'),
+    weekdaysMin : 'Dom_2ª_3ª_4ª_5ª_6ª_Sáb'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D [de] MMMM [de] YYYY',
+        LLL : 'D [de] MMMM [de] YYYY HH:mm',
+        LLLL : 'dddd, D [de] MMMM [de] YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Hoje às] LT',
+        nextDay: '[Amanhã às] LT',
+        nextWeek: 'dddd [às] LT',
+        lastDay: '[Ontem às] LT',
+        lastWeek: function () {
+            return (this.day() === 0 || this.day() === 6) ?
+                '[Último] dddd [às] LT' : // Saturday + Sunday
+                '[Última] dddd [às] LT'; // Monday - Friday
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'em %s',
+        past : 'há %s',
+        s : 'segundos',
+        m : 'um minuto',
+        mm : '%d minutos',
+        h : 'uma hora',
+        hh : '%d horas',
+        d : 'um dia',
+        dd : '%d dias',
+        M : 'um mês',
+        MM : '%d meses',
+        y : 'um ano',
+        yy : '%d anos'
+    },
+    ordinalParse: /\d{1,2}º/,
+    ordinal : '%dº',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Romanian [ro]
+//! author : Vlad Gurdiga : https://github.com/gurdiga
+//! author : Valentin Agachi : https://github.com/avaly
+
+function relativeTimeWithPlural$2(number, withoutSuffix, key) {
+    var format = {
+            'mm': 'minute',
+            'hh': 'ore',
+            'dd': 'zile',
+            'MM': 'luni',
+            'yy': 'ani'
+        },
+        separator = ' ';
+    if (number % 100 >= 20 || (number >= 100 && number % 100 === 0)) {
+        separator = ' de ';
+    }
+    return number + separator + format[key];
+}
+
+hooks.defineLocale('ro', {
+    months : 'ianuarie_februarie_martie_aprilie_mai_iunie_iulie_august_septembrie_octombrie_noiembrie_decembrie'.split('_'),
+    monthsShort : 'ian._febr._mart._apr._mai_iun._iul._aug._sept._oct._nov._dec.'.split('_'),
+    monthsParseExact: true,
+    weekdays : 'duminică_luni_marți_miercuri_joi_vineri_sâmbătă'.split('_'),
+    weekdaysShort : 'Dum_Lun_Mar_Mie_Joi_Vin_Sâm'.split('_'),
+    weekdaysMin : 'Du_Lu_Ma_Mi_Jo_Vi_Sâ'.split('_'),
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY H:mm',
+        LLLL : 'dddd, D MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay: '[azi la] LT',
+        nextDay: '[mâine la] LT',
+        nextWeek: 'dddd [la] LT',
+        lastDay: '[ieri la] LT',
+        lastWeek: '[fosta] dddd [la] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'peste %s',
+        past : '%s în urmă',
+        s : 'câteva secunde',
+        m : 'un minut',
+        mm : relativeTimeWithPlural$2,
+        h : 'o oră',
+        hh : relativeTimeWithPlural$2,
+        d : 'o zi',
+        dd : relativeTimeWithPlural$2,
+        M : 'o lună',
+        MM : relativeTimeWithPlural$2,
+        y : 'un an',
+        yy : relativeTimeWithPlural$2
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Russian [ru]
+//! author : Viktorminator : https://github.com/Viktorminator
+//! Author : Menelion Elensúle : https://github.com/Oire
+//! author : Коренберг Марк : https://github.com/socketpair
+
+function plural$4(word, num) {
+    var forms = word.split('_');
+    return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]);
+}
+function relativeTimeWithPlural$3(number, withoutSuffix, key) {
+    var format = {
+        'mm': withoutSuffix ? 'минута_минуты_минут' : 'минуту_минуты_минут',
+        'hh': 'час_часа_часов',
+        'dd': 'день_дня_дней',
+        'MM': 'месяц_месяца_месяцев',
+        'yy': 'год_года_лет'
+    };
+    if (key === 'm') {
+        return withoutSuffix ? 'минута' : 'минуту';
+    }
+    else {
+        return number + ' ' + plural$4(format[key], +number);
+    }
+}
+var monthsParse$2 = [/^янв/i, /^фев/i, /^мар/i, /^апр/i, /^ма[йя]/i, /^июн/i, /^июл/i, /^авг/i, /^сен/i, /^окт/i, /^ноя/i, /^дек/i];
+
+// http://new.gramota.ru/spravka/rules/139-prop : § 103
+// Сокращения месяцев: http://new.gramota.ru/spravka/buro/search-answer?s=242637
+// CLDR data:          http://www.unicode.org/cldr/charts/28/summary/ru.html#1753
+hooks.defineLocale('ru', {
+    months : {
+        format: 'января_февраля_марта_апреля_мая_июня_июля_августа_сентября_октября_ноября_декабря'.split('_'),
+        standalone: 'январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь'.split('_')
+    },
+    monthsShort : {
+        // по CLDR именно "июл." и "июн.", но какой смысл менять букву на точку ?
+        format: 'янв._февр._мар._апр._мая_июня_июля_авг._сент._окт._нояб._дек.'.split('_'),
+        standalone: 'янв._февр._март_апр._май_июнь_июль_авг._сент._окт._нояб._дек.'.split('_')
+    },
+    weekdays : {
+        standalone: 'воскресенье_понедельник_вторник_среда_четверг_пятница_суббота'.split('_'),
+        format: 'воскресенье_понедельник_вторник_среду_четверг_пятницу_субботу'.split('_'),
+        isFormat: /\[ ?[Вв] ?(?:прошлую|следующую|эту)? ?\] ?dddd/
+    },
+    weekdaysShort : 'вс_пн_вт_ср_чт_пт_сб'.split('_'),
+    weekdaysMin : 'вс_пн_вт_ср_чт_пт_сб'.split('_'),
+    monthsParse : monthsParse$2,
+    longMonthsParse : monthsParse$2,
+    shortMonthsParse : monthsParse$2,
+
+    // полные названия с падежами, по три буквы, для некоторых, по 4 буквы, сокращения с точкой и без точки
+    monthsRegex: /^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i,
+
+    // копия предыдущего
+    monthsShortRegex: /^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i,
+
+    // полные названия с падежами
+    monthsStrictRegex: /^(январ[яь]|феврал[яь]|марта?|апрел[яь]|ма[яй]|июн[яь]|июл[яь]|августа?|сентябр[яь]|октябр[яь]|ноябр[яь]|декабр[яь])/i,
+
+    // Выражение, которое соотвествует только сокращённым формам
+    monthsShortStrictRegex: /^(янв\.|февр?\.|мар[т.]|апр\.|ма[яй]|июн[ья.]|июл[ья.]|авг\.|сент?\.|окт\.|нояб?\.|дек\.)/i,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY г.',
+        LLL : 'D MMMM YYYY г., HH:mm',
+        LLLL : 'dddd, D MMMM YYYY г., HH:mm'
+    },
+    calendar : {
+        sameDay: '[Сегодня в] LT',
+        nextDay: '[Завтра в] LT',
+        lastDay: '[Вчера в] LT',
+        nextWeek: function (now) {
+            if (now.week() !== this.week()) {
+                switch (this.day()) {
+                    case 0:
+                        return '[В следующее] dddd [в] LT';
+                    case 1:
+                    case 2:
+                    case 4:
+                        return '[В следующий] dddd [в] LT';
+                    case 3:
+                    case 5:
+                    case 6:
+                        return '[В следующую] dddd [в] LT';
+                }
+            } else {
+                if (this.day() === 2) {
+                    return '[Во] dddd [в] LT';
+                } else {
+                    return '[В] dddd [в] LT';
+                }
+            }
+        },
+        lastWeek: function (now) {
+            if (now.week() !== this.week()) {
+                switch (this.day()) {
+                    case 0:
+                        return '[В прошлое] dddd [в] LT';
+                    case 1:
+                    case 2:
+                    case 4:
+                        return '[В прошлый] dddd [в] LT';
+                    case 3:
+                    case 5:
+                    case 6:
+                        return '[В прошлую] dddd [в] LT';
+                }
+            } else {
+                if (this.day() === 2) {
+                    return '[Во] dddd [в] LT';
+                } else {
+                    return '[В] dddd [в] LT';
+                }
+            }
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'через %s',
+        past : '%s назад',
+        s : 'несколько секунд',
+        m : relativeTimeWithPlural$3,
+        mm : relativeTimeWithPlural$3,
+        h : 'час',
+        hh : relativeTimeWithPlural$3,
+        d : 'день',
+        dd : relativeTimeWithPlural$3,
+        M : 'месяц',
+        MM : relativeTimeWithPlural$3,
+        y : 'год',
+        yy : relativeTimeWithPlural$3
+    },
+    meridiemParse: /ночи|утра|дня|вечера/i,
+    isPM : function (input) {
+        return /^(дня|вечера)$/.test(input);
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'ночи';
+        } else if (hour < 12) {
+            return 'утра';
+        } else if (hour < 17) {
+            return 'дня';
+        } else {
+            return 'вечера';
+        }
+    },
+    ordinalParse: /\d{1,2}-(й|го|я)/,
+    ordinal: function (number, period) {
+        switch (period) {
+            case 'M':
+            case 'd':
+            case 'DDD':
+                return number + '-й';
+            case 'D':
+                return number + '-го';
+            case 'w':
+            case 'W':
+                return number + '-я';
+            default:
+                return number;
+        }
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Northern Sami [se]
+//! authors : BÃ¥rd Rolstad Henriksen : https://github.com/karamell
+
+
+hooks.defineLocale('se', {
+    months : 'ođđajagemánnu_guovvamánnu_njukčamánnu_cuoŋománnu_miessemánnu_geassemánnu_suoidnemánnu_borgemánnu_čakčamánnu_golggotmánnu_skábmamánnu_juovlamánnu'.split('_'),
+    monthsShort : 'ođđj_guov_njuk_cuo_mies_geas_suoi_borg_čakč_golg_skáb_juov'.split('_'),
+    weekdays : 'sotnabeaivi_vuossárga_maŋŋebárga_gaskavahkku_duorastat_bearjadat_lávvardat'.split('_'),
+    weekdaysShort : 'sotn_vuos_maŋ_gask_duor_bear_láv'.split('_'),
+    weekdaysMin : 's_v_m_g_d_b_L'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'MMMM D. [b.] YYYY',
+        LLL : 'MMMM D. [b.] YYYY [ti.] HH:mm',
+        LLLL : 'dddd, MMMM D. [b.] YYYY [ti.] HH:mm'
+    },
+    calendar : {
+        sameDay: '[otne ti] LT',
+        nextDay: '[ihttin ti] LT',
+        nextWeek: 'dddd [ti] LT',
+        lastDay: '[ikte ti] LT',
+        lastWeek: '[ovddit] dddd [ti] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : '%s geažes',
+        past : 'maŋit %s',
+        s : 'moadde sekunddat',
+        m : 'okta minuhta',
+        mm : '%d minuhtat',
+        h : 'okta diimmu',
+        hh : '%d diimmut',
+        d : 'okta beaivi',
+        dd : '%d beaivvit',
+        M : 'okta mánnu',
+        MM : '%d mánut',
+        y : 'okta jahki',
+        yy : '%d jagit'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Sinhalese [si]
+//! author : Sampath Sitinamaluwa : https://github.com/sampathsris
+
+/*jshint -W100*/
+hooks.defineLocale('si', {
+    months : 'ජනවාරි_පෙබරවාරි_මාර්තු_අප්‍රේල්_මැයි_ජූනි_ජූලි_අගෝස්තු_සැප්තැම්බර්_ඔක්තෝබර්_නොවැම්බර්_දෙසැම්බර්'.split('_'),
+    monthsShort : 'ජන_පෙබ_මාර්_අප්_මැයි_ජූනි_ජූලි_අගෝ_සැප්_ඔක්_නොවැ_දෙසැ'.split('_'),
+    weekdays : 'ඉරිදා_සඳුදා_අඟහරුවාදා_බදාදා_බ්‍රහස්පතින්දා_සිකුරාදා_සෙනසුරාදා'.split('_'),
+    weekdaysShort : 'ඉරි_සඳු_අඟ_බදා_බ්‍රහ_සිකු_සෙන'.split('_'),
+    weekdaysMin : 'ඉ_ස_අ_බ_බ්‍ර_සි_සෙ'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'a h:mm',
+        LTS : 'a h:mm:ss',
+        L : 'YYYY/MM/DD',
+        LL : 'YYYY MMMM D',
+        LLL : 'YYYY MMMM D, a h:mm',
+        LLLL : 'YYYY MMMM D [වැනි] dddd, a h:mm:ss'
+    },
+    calendar : {
+        sameDay : '[අද] LT[ට]',
+        nextDay : '[හෙට] LT[ට]',
+        nextWeek : 'dddd LT[à¶§]',
+        lastDay : '[ඊයේ] LT[ට]',
+        lastWeek : '[පසුගිය] dddd LT[ට]',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%sකින්',
+        past : '%sකට පෙර',
+        s : 'තත්පර කිහිපය',
+        m : 'මිනිත්තුව',
+        mm : 'මිනිත්තු %d',
+        h : 'පැය',
+        hh : 'පැය %d',
+        d : 'දිනය',
+        dd : 'දින %d',
+        M : 'මාසය',
+        MM : 'මාස %d',
+        y : 'වසර',
+        yy : 'වසර %d'
+    },
+    ordinalParse: /\d{1,2} වැනි/,
+    ordinal : function (number) {
+        return number + ' වැනි';
+    },
+    meridiemParse : /පෙර වරු|පස් වරු|පෙ.ව|ප.ව./,
+    isPM : function (input) {
+        return input === 'ප.ව.' || input === 'පස් වරු';
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours > 11) {
+            return isLower ? 'ප.ව.' : 'පස් වරු';
+        } else {
+            return isLower ? 'පෙ.ව.' : 'පෙර වරු';
+        }
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Slovak [sk]
+//! author : Martin Minka : https://github.com/k2s
+//! based on work of petrbela : https://github.com/petrbela
+
+var months$6 = 'január_február_marec_apríl_máj_jún_júl_august_september_október_november_december'.split('_');
+var monthsShort$4 = 'jan_feb_mar_apr_máj_jún_júl_aug_sep_okt_nov_dec'.split('_');
+function plural$5(n) {
+    return (n > 1) && (n < 5);
+}
+function translate$8(number, withoutSuffix, key, isFuture) {
+    var result = number + ' ';
+    switch (key) {
+        case 's':  // a few seconds / in a few seconds / a few seconds ago
+            return (withoutSuffix || isFuture) ? 'pár sekúnd' : 'pár sekundami';
+        case 'm':  // a minute / in a minute / a minute ago
+            return withoutSuffix ? 'minúta' : (isFuture ? 'minútu' : 'minútou');
+        case 'mm': // 9 minutes / in 9 minutes / 9 minutes ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural$5(number) ? 'minúty' : 'minút');
+            } else {
+                return result + 'minútami';
+            }
+            break;
+        case 'h':  // an hour / in an hour / an hour ago
+            return withoutSuffix ? 'hodina' : (isFuture ? 'hodinu' : 'hodinou');
+        case 'hh': // 9 hours / in 9 hours / 9 hours ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural$5(number) ? 'hodiny' : 'hodín');
+            } else {
+                return result + 'hodinami';
+            }
+            break;
+        case 'd':  // a day / in a day / a day ago
+            return (withoutSuffix || isFuture) ? 'deň' : 'dňom';
+        case 'dd': // 9 days / in 9 days / 9 days ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural$5(number) ? 'dni' : 'dní');
+            } else {
+                return result + 'dňami';
+            }
+            break;
+        case 'M':  // a month / in a month / a month ago
+            return (withoutSuffix || isFuture) ? 'mesiac' : 'mesiacom';
+        case 'MM': // 9 months / in 9 months / 9 months ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural$5(number) ? 'mesiace' : 'mesiacov');
+            } else {
+                return result + 'mesiacmi';
+            }
+            break;
+        case 'y':  // a year / in a year / a year ago
+            return (withoutSuffix || isFuture) ? 'rok' : 'rokom';
+        case 'yy': // 9 years / in 9 years / 9 years ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural$5(number) ? 'roky' : 'rokov');
+            } else {
+                return result + 'rokmi';
+            }
+            break;
+    }
+}
+
+hooks.defineLocale('sk', {
+    months : months$6,
+    monthsShort : monthsShort$4,
+    weekdays : 'nedeľa_pondelok_utorok_streda_štvrtok_piatok_sobota'.split('_'),
+    weekdaysShort : 'ne_po_ut_st_št_pi_so'.split('_'),
+    weekdaysMin : 'ne_po_ut_st_št_pi_so'.split('_'),
+    longDateFormat : {
+        LT: 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY H:mm',
+        LLLL : 'dddd D. MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay: '[dnes o] LT',
+        nextDay: '[zajtra o] LT',
+        nextWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[v nedeľu o] LT';
+                case 1:
+                case 2:
+                    return '[v] dddd [o] LT';
+                case 3:
+                    return '[v stredu o] LT';
+                case 4:
+                    return '[vo štvrtok o] LT';
+                case 5:
+                    return '[v piatok o] LT';
+                case 6:
+                    return '[v sobotu o] LT';
+            }
+        },
+        lastDay: '[včera o] LT',
+        lastWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[minulú nedeľu o] LT';
+                case 1:
+                case 2:
+                    return '[minulý] dddd [o] LT';
+                case 3:
+                    return '[minulú stredu o] LT';
+                case 4:
+                case 5:
+                    return '[minulý] dddd [o] LT';
+                case 6:
+                    return '[minulú sobotu o] LT';
+            }
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'za %s',
+        past : 'pred %s',
+        s : translate$8,
+        m : translate$8,
+        mm : translate$8,
+        h : translate$8,
+        hh : translate$8,
+        d : translate$8,
+        dd : translate$8,
+        M : translate$8,
+        MM : translate$8,
+        y : translate$8,
+        yy : translate$8
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Slovenian [sl]
+//! author : Robert Sedovšek : https://github.com/sedovsek
+
+function processRelativeTime$4(number, withoutSuffix, key, isFuture) {
+    var result = number + ' ';
+    switch (key) {
+        case 's':
+            return withoutSuffix || isFuture ? 'nekaj sekund' : 'nekaj sekundami';
+        case 'm':
+            return withoutSuffix ? 'ena minuta' : 'eno minuto';
+        case 'mm':
+            if (number === 1) {
+                result += withoutSuffix ? 'minuta' : 'minuto';
+            } else if (number === 2) {
+                result += withoutSuffix || isFuture ? 'minuti' : 'minutama';
+            } else if (number < 5) {
+                result += withoutSuffix || isFuture ? 'minute' : 'minutami';
+            } else {
+                result += withoutSuffix || isFuture ? 'minut' : 'minutami';
+            }
+            return result;
+        case 'h':
+            return withoutSuffix ? 'ena ura' : 'eno uro';
+        case 'hh':
+            if (number === 1) {
+                result += withoutSuffix ? 'ura' : 'uro';
+            } else if (number === 2) {
+                result += withoutSuffix || isFuture ? 'uri' : 'urama';
+            } else if (number < 5) {
+                result += withoutSuffix || isFuture ? 'ure' : 'urami';
+            } else {
+                result += withoutSuffix || isFuture ? 'ur' : 'urami';
+            }
+            return result;
+        case 'd':
+            return withoutSuffix || isFuture ? 'en dan' : 'enim dnem';
+        case 'dd':
+            if (number === 1) {
+                result += withoutSuffix || isFuture ? 'dan' : 'dnem';
+            } else if (number === 2) {
+                result += withoutSuffix || isFuture ? 'dni' : 'dnevoma';
+            } else {
+                result += withoutSuffix || isFuture ? 'dni' : 'dnevi';
+            }
+            return result;
+        case 'M':
+            return withoutSuffix || isFuture ? 'en mesec' : 'enim mesecem';
+        case 'MM':
+            if (number === 1) {
+                result += withoutSuffix || isFuture ? 'mesec' : 'mesecem';
+            } else if (number === 2) {
+                result += withoutSuffix || isFuture ? 'meseca' : 'mesecema';
+            } else if (number < 5) {
+                result += withoutSuffix || isFuture ? 'mesece' : 'meseci';
+            } else {
+                result += withoutSuffix || isFuture ? 'mesecev' : 'meseci';
+            }
+            return result;
+        case 'y':
+            return withoutSuffix || isFuture ? 'eno leto' : 'enim letom';
+        case 'yy':
+            if (number === 1) {
+                result += withoutSuffix || isFuture ? 'leto' : 'letom';
+            } else if (number === 2) {
+                result += withoutSuffix || isFuture ? 'leti' : 'letoma';
+            } else if (number < 5) {
+                result += withoutSuffix || isFuture ? 'leta' : 'leti';
+            } else {
+                result += withoutSuffix || isFuture ? 'let' : 'leti';
+            }
+            return result;
+    }
+}
+
+hooks.defineLocale('sl', {
+    months : 'januar_februar_marec_april_maj_junij_julij_avgust_september_oktober_november_december'.split('_'),
+    monthsShort : 'jan._feb._mar._apr._maj._jun._jul._avg._sep._okt._nov._dec.'.split('_'),
+    monthsParseExact: true,
+    weekdays : 'nedelja_ponedeljek_torek_sreda_četrtek_petek_sobota'.split('_'),
+    weekdaysShort : 'ned._pon._tor._sre._čet._pet._sob.'.split('_'),
+    weekdaysMin : 'ne_po_to_sr_če_pe_so'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY H:mm',
+        LLLL : 'dddd, D. MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay  : '[danes ob] LT',
+        nextDay  : '[jutri ob] LT',
+
+        nextWeek : function () {
+            switch (this.day()) {
+                case 0:
+                    return '[v] [nedeljo] [ob] LT';
+                case 3:
+                    return '[v] [sredo] [ob] LT';
+                case 6:
+                    return '[v] [soboto] [ob] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[v] dddd [ob] LT';
+            }
+        },
+        lastDay  : '[včeraj ob] LT',
+        lastWeek : function () {
+            switch (this.day()) {
+                case 0:
+                    return '[prejšnjo] [nedeljo] [ob] LT';
+                case 3:
+                    return '[prejšnjo] [sredo] [ob] LT';
+                case 6:
+                    return '[prejšnjo] [soboto] [ob] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[prejšnji] dddd [ob] LT';
+            }
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'čez %s',
+        past   : 'pred %s',
+        s      : processRelativeTime$4,
+        m      : processRelativeTime$4,
+        mm     : processRelativeTime$4,
+        h      : processRelativeTime$4,
+        hh     : processRelativeTime$4,
+        d      : processRelativeTime$4,
+        dd     : processRelativeTime$4,
+        M      : processRelativeTime$4,
+        MM     : processRelativeTime$4,
+        y      : processRelativeTime$4,
+        yy     : processRelativeTime$4
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Albanian [sq]
+//! author : Flakërim Ismani : https://github.com/flakerimi
+//! author : Menelion Elensúle : https://github.com/Oire
+//! author : Oerd Cukalla : https://github.com/oerd
+
+hooks.defineLocale('sq', {
+    months : 'Janar_Shkurt_Mars_Prill_Maj_Qershor_Korrik_Gusht_Shtator_Tetor_Nëntor_Dhjetor'.split('_'),
+    monthsShort : 'Jan_Shk_Mar_Pri_Maj_Qer_Kor_Gus_Sht_Tet_Nën_Dhj'.split('_'),
+    weekdays : 'E Diel_E Hënë_E Martë_E Mërkurë_E Enjte_E Premte_E Shtunë'.split('_'),
+    weekdaysShort : 'Die_Hën_Mar_Mër_Enj_Pre_Sht'.split('_'),
+    weekdaysMin : 'D_H_Ma_Më_E_P_Sh'.split('_'),
+    weekdaysParseExact : true,
+    meridiemParse: /PD|MD/,
+    isPM: function (input) {
+        return input.charAt(0) === 'M';
+    },
+    meridiem : function (hours, minutes, isLower) {
+        return hours < 12 ? 'PD' : 'MD';
+    },
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[Sot në] LT',
+        nextDay : '[Nesër në] LT',
+        nextWeek : 'dddd [në] LT',
+        lastDay : '[Dje në] LT',
+        lastWeek : 'dddd [e kaluar në] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'në %s',
+        past : '%s më parë',
+        s : 'disa sekonda',
+        m : 'një minutë',
+        mm : '%d minuta',
+        h : 'një orë',
+        hh : '%d orë',
+        d : 'një ditë',
+        dd : '%d ditë',
+        M : 'një muaj',
+        MM : '%d muaj',
+        y : 'një vit',
+        yy : '%d vite'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Serbian Cyrillic [sr-cyrl]
+//! author : Milan Janačković<milanjanackovic@gmail.com> : https://github.com/milan-j
+
+var translator$1 = {
+    words: { //Different grammatical cases
+        m: ['један минут', 'једне минуте'],
+        mm: ['минут', 'минуте', 'минута'],
+        h: ['један сат', 'једног сата'],
+        hh: ['сат', 'сата', 'сати'],
+        dd: ['дан', 'дана', 'дана'],
+        MM: ['месец', 'месеца', 'месеци'],
+        yy: ['година', 'године', 'година']
+    },
+    correctGrammaticalCase: function (number, wordKey) {
+        return number === 1 ? wordKey[0] : (number >= 2 && number <= 4 ? wordKey[1] : wordKey[2]);
+    },
+    translate: function (number, withoutSuffix, key) {
+        var wordKey = translator$1.words[key];
+        if (key.length === 1) {
+            return withoutSuffix ? wordKey[0] : wordKey[1];
+        } else {
+            return number + ' ' + translator$1.correctGrammaticalCase(number, wordKey);
+        }
+    }
+};
+
+hooks.defineLocale('sr-cyrl', {
+    months: 'јануар_фебруар_март_април_мај_јун_јул_август_септембар_октобар_новембар_децембар'.split('_'),
+    monthsShort: 'јан._феб._мар._апр._мај_јун_јул_авг._сеп._окт._нов._дец.'.split('_'),
+    monthsParseExact: true,
+    weekdays: 'недеља_понедељак_уторак_среда_четвртак_петак_субота'.split('_'),
+    weekdaysShort: 'нед._пон._уто._сре._чет._пет._суб.'.split('_'),
+    weekdaysMin: 'не_по_ут_ср_че_пе_су'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat: {
+        LT: 'H:mm',
+        LTS : 'H:mm:ss',
+        L: 'DD.MM.YYYY',
+        LL: 'D. MMMM YYYY',
+        LLL: 'D. MMMM YYYY H:mm',
+        LLLL: 'dddd, D. MMMM YYYY H:mm'
+    },
+    calendar: {
+        sameDay: '[данас у] LT',
+        nextDay: '[сутра у] LT',
+        nextWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[у] [недељу] [у] LT';
+                case 3:
+                    return '[у] [среду] [у] LT';
+                case 6:
+                    return '[у] [суботу] [у] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[у] dddd [у] LT';
+            }
+        },
+        lastDay  : '[јуче у] LT',
+        lastWeek : function () {
+            var lastWeekDays = [
+                '[прошле] [недеље] [у] LT',
+                '[прошлог] [понедељка] [у] LT',
+                '[прошлог] [уторка] [у] LT',
+                '[прошле] [среде] [у] LT',
+                '[прошлог] [четвртка] [у] LT',
+                '[прошлог] [петка] [у] LT',
+                '[прошле] [суботе] [у] LT'
+            ];
+            return lastWeekDays[this.day()];
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'за %s',
+        past   : 'пре %s',
+        s      : 'неколико секунди',
+        m      : translator$1.translate,
+        mm     : translator$1.translate,
+        h      : translator$1.translate,
+        hh     : translator$1.translate,
+        d      : 'дан',
+        dd     : translator$1.translate,
+        M      : 'месец',
+        MM     : translator$1.translate,
+        y      : 'годину',
+        yy     : translator$1.translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Serbian [sr]
+//! author : Milan Janačković<milanjanackovic@gmail.com> : https://github.com/milan-j
+
+var translator$2 = {
+    words: { //Different grammatical cases
+        m: ['jedan minut', 'jedne minute'],
+        mm: ['minut', 'minute', 'minuta'],
+        h: ['jedan sat', 'jednog sata'],
+        hh: ['sat', 'sata', 'sati'],
+        dd: ['dan', 'dana', 'dana'],
+        MM: ['mesec', 'meseca', 'meseci'],
+        yy: ['godina', 'godine', 'godina']
+    },
+    correctGrammaticalCase: function (number, wordKey) {
+        return number === 1 ? wordKey[0] : (number >= 2 && number <= 4 ? wordKey[1] : wordKey[2]);
+    },
+    translate: function (number, withoutSuffix, key) {
+        var wordKey = translator$2.words[key];
+        if (key.length === 1) {
+            return withoutSuffix ? wordKey[0] : wordKey[1];
+        } else {
+            return number + ' ' + translator$2.correctGrammaticalCase(number, wordKey);
+        }
+    }
+};
+
+hooks.defineLocale('sr', {
+    months: 'januar_februar_mart_april_maj_jun_jul_avgust_septembar_oktobar_novembar_decembar'.split('_'),
+    monthsShort: 'jan._feb._mar._apr._maj_jun_jul_avg._sep._okt._nov._dec.'.split('_'),
+    monthsParseExact: true,
+    weekdays: 'nedelja_ponedeljak_utorak_sreda_četvrtak_petak_subota'.split('_'),
+    weekdaysShort: 'ned._pon._uto._sre._čet._pet._sub.'.split('_'),
+    weekdaysMin: 'ne_po_ut_sr_če_pe_su'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat: {
+        LT: 'H:mm',
+        LTS : 'H:mm:ss',
+        L: 'DD.MM.YYYY',
+        LL: 'D. MMMM YYYY',
+        LLL: 'D. MMMM YYYY H:mm',
+        LLLL: 'dddd, D. MMMM YYYY H:mm'
+    },
+    calendar: {
+        sameDay: '[danas u] LT',
+        nextDay: '[sutra u] LT',
+        nextWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[u] [nedelju] [u] LT';
+                case 3:
+                    return '[u] [sredu] [u] LT';
+                case 6:
+                    return '[u] [subotu] [u] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[u] dddd [u] LT';
+            }
+        },
+        lastDay  : '[juče u] LT',
+        lastWeek : function () {
+            var lastWeekDays = [
+                '[prošle] [nedelje] [u] LT',
+                '[prošlog] [ponedeljka] [u] LT',
+                '[prošlog] [utorka] [u] LT',
+                '[prošle] [srede] [u] LT',
+                '[prošlog] [četvrtka] [u] LT',
+                '[prošlog] [petka] [u] LT',
+                '[prošle] [subote] [u] LT'
+            ];
+            return lastWeekDays[this.day()];
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'za %s',
+        past   : 'pre %s',
+        s      : 'nekoliko sekundi',
+        m      : translator$2.translate,
+        mm     : translator$2.translate,
+        h      : translator$2.translate,
+        hh     : translator$2.translate,
+        d      : 'dan',
+        dd     : translator$2.translate,
+        M      : 'mesec',
+        MM     : translator$2.translate,
+        y      : 'godinu',
+        yy     : translator$2.translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : siSwati [ss]
+//! author : Nicolai Davies<mail@nicolai.io> : https://github.com/nicolaidavies
+
+
+hooks.defineLocale('ss', {
+    months : "Bhimbidvwane_Indlovana_Indlov'lenkhulu_Mabasa_Inkhwekhweti_Inhlaba_Kholwane_Ingci_Inyoni_Imphala_Lweti_Ingongoni".split('_'),
+    monthsShort : 'Bhi_Ina_Inu_Mab_Ink_Inh_Kho_Igc_Iny_Imp_Lwe_Igo'.split('_'),
+    weekdays : 'Lisontfo_Umsombuluko_Lesibili_Lesitsatfu_Lesine_Lesihlanu_Umgcibelo'.split('_'),
+    weekdaysShort : 'Lis_Umb_Lsb_Les_Lsi_Lsh_Umg'.split('_'),
+    weekdaysMin : 'Li_Us_Lb_Lt_Ls_Lh_Ug'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'h:mm A',
+        LTS : 'h:mm:ss A',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY h:mm A',
+        LLLL : 'dddd, D MMMM YYYY h:mm A'
+    },
+    calendar : {
+        sameDay : '[Namuhla nga] LT',
+        nextDay : '[Kusasa nga] LT',
+        nextWeek : 'dddd [nga] LT',
+        lastDay : '[Itolo nga] LT',
+        lastWeek : 'dddd [leliphelile] [nga] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'nga %s',
+        past : 'wenteka nga %s',
+        s : 'emizuzwana lomcane',
+        m : 'umzuzu',
+        mm : '%d emizuzu',
+        h : 'lihora',
+        hh : '%d emahora',
+        d : 'lilanga',
+        dd : '%d emalanga',
+        M : 'inyanga',
+        MM : '%d tinyanga',
+        y : 'umnyaka',
+        yy : '%d iminyaka'
+    },
+    meridiemParse: /ekuseni|emini|entsambama|ebusuku/,
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 11) {
+            return 'ekuseni';
+        } else if (hours < 15) {
+            return 'emini';
+        } else if (hours < 19) {
+            return 'entsambama';
+        } else {
+            return 'ebusuku';
+        }
+    },
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'ekuseni') {
+            return hour;
+        } else if (meridiem === 'emini') {
+            return hour >= 11 ? hour : hour + 12;
+        } else if (meridiem === 'entsambama' || meridiem === 'ebusuku') {
+            if (hour === 0) {
+                return 0;
+            }
+            return hour + 12;
+        }
+    },
+    ordinalParse: /\d{1,2}/,
+    ordinal : '%d',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Swedish [sv]
+//! author : Jens Alm : https://github.com/ulmus
+
+hooks.defineLocale('sv', {
+    months : 'januari_februari_mars_april_maj_juni_juli_augusti_september_oktober_november_december'.split('_'),
+    monthsShort : 'jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec'.split('_'),
+    weekdays : 'söndag_måndag_tisdag_onsdag_torsdag_fredag_lördag'.split('_'),
+    weekdaysShort : 'sön_mån_tis_ons_tor_fre_lör'.split('_'),
+    weekdaysMin : 'sö_må_ti_on_to_fr_lö'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'YYYY-MM-DD',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY [kl.] HH:mm',
+        LLLL : 'dddd D MMMM YYYY [kl.] HH:mm',
+        lll : 'D MMM YYYY HH:mm',
+        llll : 'ddd D MMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Idag] LT',
+        nextDay: '[Imorgon] LT',
+        lastDay: '[Igår] LT',
+        nextWeek: '[PÃ¥] dddd LT',
+        lastWeek: '[I] dddd[s] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'om %s',
+        past : 'för %s sedan',
+        s : 'några sekunder',
+        m : 'en minut',
+        mm : '%d minuter',
+        h : 'en timme',
+        hh : '%d timmar',
+        d : 'en dag',
+        dd : '%d dagar',
+        M : 'en månad',
+        MM : '%d månader',
+        y : 'ett år',
+        yy : '%d år'
+    },
+    ordinalParse: /\d{1,2}(e|a)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'e' :
+            (b === 1) ? 'a' :
+            (b === 2) ? 'a' :
+            (b === 3) ? 'e' : 'e';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Swahili [sw]
+//! author : Fahad Kassim : https://github.com/fadsel
+
+hooks.defineLocale('sw', {
+    months : 'Januari_Februari_Machi_Aprili_Mei_Juni_Julai_Agosti_Septemba_Oktoba_Novemba_Desemba'.split('_'),
+    monthsShort : 'Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ago_Sep_Okt_Nov_Des'.split('_'),
+    weekdays : 'Jumapili_Jumatatu_Jumanne_Jumatano_Alhamisi_Ijumaa_Jumamosi'.split('_'),
+    weekdaysShort : 'Jpl_Jtat_Jnne_Jtan_Alh_Ijm_Jmos'.split('_'),
+    weekdaysMin : 'J2_J3_J4_J5_Al_Ij_J1'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[leo saa] LT',
+        nextDay : '[kesho saa] LT',
+        nextWeek : '[wiki ijayo] dddd [saat] LT',
+        lastDay : '[jana] LT',
+        lastWeek : '[wiki iliyopita] dddd [saat] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s baadaye',
+        past : 'tokea %s',
+        s : 'hivi punde',
+        m : 'dakika moja',
+        mm : 'dakika %d',
+        h : 'saa limoja',
+        hh : 'masaa %d',
+        d : 'siku moja',
+        dd : 'masiku %d',
+        M : 'mwezi mmoja',
+        MM : 'miezi %d',
+        y : 'mwaka mmoja',
+        yy : 'miaka %d'
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Tamil [ta]
+//! author : Arjunkumar Krishnamoorthy : https://github.com/tk120404
+
+var symbolMap$11 = {
+    '1': '௧',
+    '2': '௨',
+    '3': '௩',
+    '4': '௪',
+    '5': '௫',
+    '6': '௬',
+    '7': '௭',
+    '8': '௮',
+    '9': '௯',
+    '0': '௦'
+};
+var numberMap$10 = {
+    '௧': '1',
+    '௨': '2',
+    '௩': '3',
+    '௪': '4',
+    '௫': '5',
+    '௬': '6',
+    '௭': '7',
+    '௮': '8',
+    '௯': '9',
+    '௦': '0'
+};
+
+hooks.defineLocale('ta', {
+    months : 'ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்'.split('_'),
+    monthsShort : 'ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்'.split('_'),
+    weekdays : 'ஞாயிற்றுக்கிழமை_திங்கட்கிழமை_செவ்வாய்கிழமை_புதன்கிழமை_வியாழக்கிழமை_வெள்ளிக்கிழமை_சனிக்கிழமை'.split('_'),
+    weekdaysShort : 'ஞாயிறு_திங்கள்_செவ்வாய்_புதன்_வியாழன்_வெள்ளி_சனி'.split('_'),
+    weekdaysMin : 'ஞா_தி_செ_பு_வி_வெ_ச'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, HH:mm',
+        LLLL : 'dddd, D MMMM YYYY, HH:mm'
+    },
+    calendar : {
+        sameDay : '[இன்று] LT',
+        nextDay : '[நாளை] LT',
+        nextWeek : 'dddd, LT',
+        lastDay : '[நேற்று] LT',
+        lastWeek : '[கடந்த வாரம்] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s இல்',
+        past : '%s முன்',
+        s : 'ஒரு சில விநாடிகள்',
+        m : 'ஒரு நிமிடம்',
+        mm : '%d நிமிடங்கள்',
+        h : 'ஒரு மணி நேரம்',
+        hh : '%d மணி நேரம்',
+        d : 'ஒரு நாள்',
+        dd : '%d நாட்கள்',
+        M : 'ஒரு மாதம்',
+        MM : '%d மாதங்கள்',
+        y : 'ஒரு வருடம்',
+        yy : '%d ஆண்டுகள்'
+    },
+    ordinalParse: /\d{1,2}வது/,
+    ordinal : function (number) {
+        return number + 'வது';
+    },
+    preparse: function (string) {
+        return string.replace(/[௧௨௩௪௫௬௭௮௯௦]/g, function (match) {
+            return numberMap$10[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap$11[match];
+        });
+    },
+    // refer http://ta.wikipedia.org/s/1er1
+    meridiemParse: /யாமம்|வைகறை|காலை|நண்பகல்|எற்பாடு|மாலை/,
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 2) {
+            return ' யாமம்';
+        } else if (hour < 6) {
+            return ' வைகறை';  // வைகறை
+        } else if (hour < 10) {
+            return ' காலை'; // காலை
+        } else if (hour < 14) {
+            return ' நண்பகல்'; // நண்பகல்
+        } else if (hour < 18) {
+            return ' எற்பாடு'; // எற்பாடு
+        } else if (hour < 22) {
+            return ' மாலை'; // மாலை
+        } else {
+            return ' யாமம்';
+        }
+    },
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'யாமம்') {
+            return hour < 2 ? hour : hour + 12;
+        } else if (meridiem === 'வைகறை' || meridiem === 'காலை') {
+            return hour;
+        } else if (meridiem === 'நண்பகல்') {
+            return hour >= 10 ? hour : hour + 12;
+        } else {
+            return hour + 12;
+        }
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Telugu [te]
+//! author : Krishna Chaitanya Thota : https://github.com/kcthota
+
+hooks.defineLocale('te', {
+    months : 'జనవరి_ఫిబ్రవరి_మార్చి_ఏప్రిల్_మే_జూన్_జూలై_ఆగస్టు_సెప్టెంబర్_అక్టోబర్_నవంబర్_డిసెంబర్'.split('_'),
+    monthsShort : 'జన._ఫిబ్ర._మార్చి_ఏప్రి._మే_జూన్_జూలై_ఆగ._సెప్._అక్టో._నవ._డిసె.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'ఆదివారం_సోమవారం_మంగళవారం_బుధవారం_గురువారం_శుక్రవారం_శనివారం'.split('_'),
+    weekdaysShort : 'ఆది_సోమ_మంగళ_బుధ_గురు_శుక్ర_శని'.split('_'),
+    weekdaysMin : 'ఆ_సో_మం_బు_గు_శు_శ'.split('_'),
+    longDateFormat : {
+        LT : 'A h:mm',
+        LTS : 'A h:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, A h:mm',
+        LLLL : 'dddd, D MMMM YYYY, A h:mm'
+    },
+    calendar : {
+        sameDay : '[నేడు] LT',
+        nextDay : '[రేపు] LT',
+        nextWeek : 'dddd, LT',
+        lastDay : '[నిన్న] LT',
+        lastWeek : '[à°—à°¤] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s లో',
+        past : '%s క్రితం',
+        s : 'కొన్ని క్షణాలు',
+        m : 'ఒక నిమిషం',
+        mm : '%d నిమిషాలు',
+        h : 'à°’à°• à°—à°‚à°Ÿ',
+        hh : '%d గంటలు',
+        d : 'ఒక రోజు',
+        dd : '%d రోజులు',
+        M : 'ఒక నెల',
+        MM : '%d నెలలు',
+        y : 'ఒక సంవత్సరం',
+        yy : '%d సంవత్సరాలు'
+    },
+    ordinalParse : /\d{1,2}à°µ/,
+    ordinal : '%dà°µ',
+    meridiemParse: /రాత్రి|ఉదయం|మధ్యాహ్నం|సాయంత్రం/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'రాత్రి') {
+            return hour < 4 ? hour : hour + 12;
+        } else if (meridiem === 'ఉదయం') {
+            return hour;
+        } else if (meridiem === 'మధ్యాహ్నం') {
+            return hour >= 10 ? hour : hour + 12;
+        } else if (meridiem === 'సాయంత్రం') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'రాత్రి';
+        } else if (hour < 10) {
+            return 'ఉదయం';
+        } else if (hour < 17) {
+            return 'మధ్యాహ్నం';
+        } else if (hour < 20) {
+            return 'సాయంత్రం';
+        } else {
+            return 'రాత్రి';
+        }
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Tetun Dili (East Timor) [tet]
+//! author : Joshua Brooks : https://github.com/joshbrooks
+//! author : Onorio De J. Afonso : https://github.com/marobo
+
+hooks.defineLocale('tet', {
+    months : 'Janeiru_Fevereiru_Marsu_Abril_Maiu_Juniu_Juliu_Augustu_Setembru_Outubru_Novembru_Dezembru'.split('_'),
+    monthsShort : 'Jan_Fev_Mar_Abr_Mai_Jun_Jul_Aug_Set_Out_Nov_Dez'.split('_'),
+    weekdays : 'Domingu_Segunda_Tersa_Kuarta_Kinta_Sexta_Sabadu'.split('_'),
+    weekdaysShort : 'Dom_Seg_Ters_Kua_Kint_Sext_Sab'.split('_'),
+    weekdaysMin : 'Do_Seg_Te_Ku_Ki_Sex_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Ohin iha] LT',
+        nextDay: '[Aban iha] LT',
+        nextWeek: 'dddd [iha] LT',
+        lastDay: '[Horiseik iha] LT',
+        lastWeek: 'dddd [semana kotuk] [iha] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'iha %s',
+        past : '%s liuba',
+        s : 'minutu balun',
+        m : 'minutu ida',
+        mm : 'minutus %d',
+        h : 'horas ida',
+        hh : 'horas %d',
+        d : 'loron ida',
+        dd : 'loron %d',
+        M : 'fulan ida',
+        MM : 'fulan %d',
+        y : 'tinan ida',
+        yy : 'tinan %d'
+    },
+    ordinalParse: /\d{1,2}(st|nd|rd|th)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Thai [th]
+//! author : Kridsada Thanabulpong : https://github.com/sirn
+
+hooks.defineLocale('th', {
+    months : 'มกราคม_กุมภาพันธ์_มีนาคม_เมษายน_พฤษภาคม_มิถุนายน_กรกฎาคม_สิงหาคม_กันยายน_ตุลาคม_พฤศจิกายน_ธันวาคม'.split('_'),
+    monthsShort : 'ม.ค._ก.พ._มี.ค._เม.ย._พ.ค._มิ.ย._ก.ค._ส.ค._ก.ย._ต.ค._พ.ย._ธ.ค.'.split('_'),
+    monthsParseExact: true,
+    weekdays : 'อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัสบดี_ศุกร์_เสาร์'.split('_'),
+    weekdaysShort : 'อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัส_ศุกร์_เสาร์'.split('_'), // yes, three characters difference
+    weekdaysMin : 'อา._จ._อ._พ._พฤ._ศ._ส.'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'YYYY/MM/DD',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY เวลา H:mm',
+        LLLL : 'วันddddที่ D MMMM YYYY เวลา H:mm'
+    },
+    meridiemParse: /ก่อนเที่ยง|หลังเที่ยง/,
+    isPM: function (input) {
+        return input === 'หลังเที่ยง';
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return 'ก่อนเที่ยง';
+        } else {
+            return 'หลังเที่ยง';
+        }
+    },
+    calendar : {
+        sameDay : '[วันนี้ เวลา] LT',
+        nextDay : '[พรุ่งนี้ เวลา] LT',
+        nextWeek : 'dddd[หน้า เวลา] LT',
+        lastDay : '[เมื่อวานนี้ เวลา] LT',
+        lastWeek : '[วัน]dddd[ที่แล้ว เวลา] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'อีก %s',
+        past : '%sที่แล้ว',
+        s : 'ไม่กี่วินาที',
+        m : '1 นาที',
+        mm : '%d นาที',
+        h : '1 ชั่วโมง',
+        hh : '%d ชั่วโมง',
+        d : '1 วัน',
+        dd : '%d วัน',
+        M : '1 เดือน',
+        MM : '%d เดือน',
+        y : '1 ปี',
+        yy : '%d ปี'
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Tagalog (Philippines) [tl-ph]
+//! author : Dan Hagman : https://github.com/hagmandan
+
+hooks.defineLocale('tl-ph', {
+    months : 'Enero_Pebrero_Marso_Abril_Mayo_Hunyo_Hulyo_Agosto_Setyembre_Oktubre_Nobyembre_Disyembre'.split('_'),
+    monthsShort : 'Ene_Peb_Mar_Abr_May_Hun_Hul_Ago_Set_Okt_Nob_Dis'.split('_'),
+    weekdays : 'Linggo_Lunes_Martes_Miyerkules_Huwebes_Biyernes_Sabado'.split('_'),
+    weekdaysShort : 'Lin_Lun_Mar_Miy_Huw_Biy_Sab'.split('_'),
+    weekdaysMin : 'Li_Lu_Ma_Mi_Hu_Bi_Sab'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'MM/D/YYYY',
+        LL : 'MMMM D, YYYY',
+        LLL : 'MMMM D, YYYY HH:mm',
+        LLLL : 'dddd, MMMM DD, YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: 'LT [ngayong araw]',
+        nextDay: '[Bukas ng] LT',
+        nextWeek: 'LT [sa susunod na] dddd',
+        lastDay: 'LT [kahapon]',
+        lastWeek: 'LT [noong nakaraang] dddd',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'sa loob ng %s',
+        past : '%s ang nakalipas',
+        s : 'ilang segundo',
+        m : 'isang minuto',
+        mm : '%d minuto',
+        h : 'isang oras',
+        hh : '%d oras',
+        d : 'isang araw',
+        dd : '%d araw',
+        M : 'isang buwan',
+        MM : '%d buwan',
+        y : 'isang taon',
+        yy : '%d taon'
+    },
+    ordinalParse: /\d{1,2}/,
+    ordinal : function (number) {
+        return number;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Klingon [tlh]
+//! author : Dominika Kruk : https://github.com/amaranthrose
+
+var numbersNouns = 'pagh_wa’_cha’_wej_loS_vagh_jav_Soch_chorgh_Hut'.split('_');
+
+function translateFuture(output) {
+    var time = output;
+    time = (output.indexOf('jaj') !== -1) ?
+    time.slice(0, -3) + 'leS' :
+    (output.indexOf('jar') !== -1) ?
+    time.slice(0, -3) + 'waQ' :
+    (output.indexOf('DIS') !== -1) ?
+    time.slice(0, -3) + 'nem' :
+    time + ' pIq';
+    return time;
+}
+
+function translatePast(output) {
+    var time = output;
+    time = (output.indexOf('jaj') !== -1) ?
+    time.slice(0, -3) + 'Hu’' :
+    (output.indexOf('jar') !== -1) ?
+    time.slice(0, -3) + 'wen' :
+    (output.indexOf('DIS') !== -1) ?
+    time.slice(0, -3) + 'ben' :
+    time + ' ret';
+    return time;
+}
+
+function translate$9(number, withoutSuffix, string, isFuture) {
+    var numberNoun = numberAsNoun(number);
+    switch (string) {
+        case 'mm':
+            return numberNoun + ' tup';
+        case 'hh':
+            return numberNoun + ' rep';
+        case 'dd':
+            return numberNoun + ' jaj';
+        case 'MM':
+            return numberNoun + ' jar';
+        case 'yy':
+            return numberNoun + ' DIS';
+    }
+}
+
+function numberAsNoun(number) {
+    var hundred = Math.floor((number % 1000) / 100),
+    ten = Math.floor((number % 100) / 10),
+    one = number % 10,
+    word = '';
+    if (hundred > 0) {
+        word += numbersNouns[hundred] + 'vatlh';
+    }
+    if (ten > 0) {
+        word += ((word !== '') ? ' ' : '') + numbersNouns[ten] + 'maH';
+    }
+    if (one > 0) {
+        word += ((word !== '') ? ' ' : '') + numbersNouns[one];
+    }
+    return (word === '') ? 'pagh' : word;
+}
+
+hooks.defineLocale('tlh', {
+    months : 'tera’ jar wa’_tera’ jar cha’_tera’ jar wej_tera’ jar loS_tera’ jar vagh_tera’ jar jav_tera’ jar Soch_tera’ jar chorgh_tera’ jar Hut_tera’ jar wa’maH_tera’ jar wa’maH wa’_tera’ jar wa’maH cha’'.split('_'),
+    monthsShort : 'jar wa’_jar cha’_jar wej_jar loS_jar vagh_jar jav_jar Soch_jar chorgh_jar Hut_jar wa’maH_jar wa’maH wa’_jar wa’maH cha’'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj'.split('_'),
+    weekdaysShort : 'lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj'.split('_'),
+    weekdaysMin : 'lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[DaHjaj] LT',
+        nextDay: '[wa’leS] LT',
+        nextWeek: 'LLL',
+        lastDay: '[wa’Hu’] LT',
+        lastWeek: 'LLL',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : translateFuture,
+        past : translatePast,
+        s : 'puS lup',
+        m : 'wa’ tup',
+        mm : translate$9,
+        h : 'wa’ rep',
+        hh : translate$9,
+        d : 'wa’ jaj',
+        dd : translate$9,
+        M : 'wa’ jar',
+        MM : translate$9,
+        y : 'wa’ DIS',
+        yy : translate$9
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Turkish [tr]
+//! authors : Erhan Gundogan : https://github.com/erhangundogan,
+//!           Burak YiÄŸit Kaya: https://github.com/BYK
+
+var suffixes$3 = {
+    1: '\'inci',
+    5: '\'inci',
+    8: '\'inci',
+    70: '\'inci',
+    80: '\'inci',
+    2: '\'nci',
+    7: '\'nci',
+    20: '\'nci',
+    50: '\'nci',
+    3: '\'üncü',
+    4: '\'üncü',
+    100: '\'üncü',
+    6: '\'ncı',
+    9: '\'uncu',
+    10: '\'uncu',
+    30: '\'uncu',
+    60: '\'ıncı',
+    90: '\'ıncı'
+};
+
+hooks.defineLocale('tr', {
+    months : 'Ocak_Şubat_Mart_Nisan_Mayıs_Haziran_Temmuz_Ağustos_Eylül_Ekim_Kasım_Aralık'.split('_'),
+    monthsShort : 'Oca_Åžub_Mar_Nis_May_Haz_Tem_AÄŸu_Eyl_Eki_Kas_Ara'.split('_'),
+    weekdays : 'Pazar_Pazartesi_Salı_Çarşamba_Perşembe_Cuma_Cumartesi'.split('_'),
+    weekdaysShort : 'Paz_Pts_Sal_Çar_Per_Cum_Cts'.split('_'),
+    weekdaysMin : 'Pz_Pt_Sa_Ça_Pe_Cu_Ct'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[bugün saat] LT',
+        nextDay : '[yarın saat] LT',
+        nextWeek : '[haftaya] dddd [saat] LT',
+        lastDay : '[dün] LT',
+        lastWeek : '[geçen hafta] dddd [saat] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s sonra',
+        past : '%s önce',
+        s : 'birkaç saniye',
+        m : 'bir dakika',
+        mm : '%d dakika',
+        h : 'bir saat',
+        hh : '%d saat',
+        d : 'bir gün',
+        dd : '%d gün',
+        M : 'bir ay',
+        MM : '%d ay',
+        y : 'bir yıl',
+        yy : '%d yıl'
+    },
+    ordinalParse: /\d{1,2}'(inci|nci|üncü|ncı|uncu|ıncı)/,
+    ordinal : function (number) {
+        if (number === 0) {  // special case for zero
+            return number + '\'ıncı';
+        }
+        var a = number % 10,
+            b = number % 100 - a,
+            c = number >= 100 ? 100 : null;
+        return number + (suffixes$3[a] || suffixes$3[b] || suffixes$3[c]);
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Talossan [tzl]
+//! author : Robin van der Vliet : https://github.com/robin0van0der0v
+//! author : Iustì Canun
+
+// After the year there should be a slash and the amount of years since December 26, 1979 in Roman numerals.
+// This is currently too difficult (maybe even impossible) to add.
+hooks.defineLocale('tzl', {
+    months : 'Januar_Fevraglh_Març_Avrïu_Mai_Gün_Julia_Guscht_Setemvar_Listopäts_Noemvar_Zecemvar'.split('_'),
+    monthsShort : 'Jan_Fev_Mar_Avr_Mai_Gün_Jul_Gus_Set_Lis_Noe_Zec'.split('_'),
+    weekdays : 'Súladi_Lúneçi_Maitzi_Márcuri_Xhúadi_Viénerçi_Sáturi'.split('_'),
+    weekdaysShort : 'Súl_Lún_Mai_Már_Xhú_Vié_Sát'.split('_'),
+    weekdaysMin : 'Sú_Lú_Ma_Má_Xh_Vi_Sá'.split('_'),
+    longDateFormat : {
+        LT : 'HH.mm',
+        LTS : 'HH.mm.ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM [dallas] YYYY',
+        LLL : 'D. MMMM [dallas] YYYY HH.mm',
+        LLLL : 'dddd, [li] D. MMMM [dallas] YYYY HH.mm'
+    },
+    meridiemParse: /d\'o|d\'a/i,
+    isPM : function (input) {
+        return 'd\'o' === input.toLowerCase();
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours > 11) {
+            return isLower ? 'd\'o' : 'D\'O';
+        } else {
+            return isLower ? 'd\'a' : 'D\'A';
+        }
+    },
+    calendar : {
+        sameDay : '[oxhi à] LT',
+        nextDay : '[demà à] LT',
+        nextWeek : 'dddd [à] LT',
+        lastDay : '[ieiri à] LT',
+        lastWeek : '[sür el] dddd [lasteu à] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'osprei %s',
+        past : 'ja%s',
+        s : processRelativeTime$5,
+        m : processRelativeTime$5,
+        mm : processRelativeTime$5,
+        h : processRelativeTime$5,
+        hh : processRelativeTime$5,
+        d : processRelativeTime$5,
+        dd : processRelativeTime$5,
+        M : processRelativeTime$5,
+        MM : processRelativeTime$5,
+        y : processRelativeTime$5,
+        yy : processRelativeTime$5
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+function processRelativeTime$5(number, withoutSuffix, key, isFuture) {
+    var format = {
+        's': ['viensas secunds', '\'iensas secunds'],
+        'm': ['\'n míut', '\'iens míut'],
+        'mm': [number + ' míuts', '' + number + ' míuts'],
+        'h': ['\'n þora', '\'iensa þora'],
+        'hh': [number + ' þoras', '' + number + ' þoras'],
+        'd': ['\'n ziua', '\'iensa ziua'],
+        'dd': [number + ' ziuas', '' + number + ' ziuas'],
+        'M': ['\'n mes', '\'iens mes'],
+        'MM': [number + ' mesen', '' + number + ' mesen'],
+        'y': ['\'n ar', '\'iens ar'],
+        'yy': [number + ' ars', '' + number + ' ars']
+    };
+    return isFuture ? format[key][0] : (withoutSuffix ? format[key][0] : format[key][1]);
+}
+
+//! moment.js locale configuration
+//! locale : Central Atlas Tamazight Latin [tzm-latn]
+//! author : Abdel Said : https://github.com/abdelsaid
+
+hooks.defineLocale('tzm-latn', {
+    months : 'innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir'.split('_'),
+    monthsShort : 'innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir'.split('_'),
+    weekdays : 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'),
+    weekdaysShort : 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'),
+    weekdaysMin : 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[asdkh g] LT',
+        nextDay: '[aska g] LT',
+        nextWeek: 'dddd [g] LT',
+        lastDay: '[assant g] LT',
+        lastWeek: 'dddd [g] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'dadkh s yan %s',
+        past : 'yan %s',
+        s : 'imik',
+        m : 'minuḍ',
+        mm : '%d minuḍ',
+        h : 'saɛa',
+        hh : '%d tassaɛin',
+        d : 'ass',
+        dd : '%d ossan',
+        M : 'ayowr',
+        MM : '%d iyyirn',
+        y : 'asgas',
+        yy : '%d isgasn'
+    },
+    week : {
+        dow : 6, // Saturday is the first day of the week.
+        doy : 12  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Central Atlas Tamazight [tzm]
+//! author : Abdel Said : https://github.com/abdelsaid
+
+hooks.defineLocale('tzm', {
+    months : 'ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ'.split('_'),
+    monthsShort : 'ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ'.split('_'),
+    weekdays : 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'),
+    weekdaysShort : 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'),
+    weekdaysMin : 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS: 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[ⴰⵙⴷⵅ ⴴ] LT',
+        nextDay: '[ⴰⵙⴽⴰ ⴴ] LT',
+        nextWeek: 'dddd [â´´] LT',
+        lastDay: '[ⴰⵚⴰⵏⵜ ⴴ] LT',
+        lastWeek: 'dddd [â´´] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'ⴷⴰⴷⵅ ⵙ ⵢⴰⵏ %s',
+        past : 'ⵢⴰⵏ %s',
+        s : 'ⵉⵎⵉⴽ',
+        m : 'ⵎⵉⵏⵓⴺ',
+        mm : '%d ⵎⵉⵏⵓⴺ',
+        h : 'ⵙⴰⵄⴰ',
+        hh : '%d ⵜⴰⵙⵙⴰⵄⵉⵏ',
+        d : 'ⴰⵙⵙ',
+        dd : '%d oⵙⵙⴰⵏ',
+        M : 'ⴰⵢoⵓⵔ',
+        MM : '%d ⵉⵢⵢⵉⵔⵏ',
+        y : 'ⴰⵙⴳⴰⵙ',
+        yy : '%d ⵉⵙⴳⴰⵙⵏ'
+    },
+    week : {
+        dow : 6, // Saturday is the first day of the week.
+        doy : 12  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Ukrainian [uk]
+//! author : zemlanin : https://github.com/zemlanin
+//! Author : Menelion Elensúle : https://github.com/Oire
+
+function plural$6(word, num) {
+    var forms = word.split('_');
+    return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]);
+}
+function relativeTimeWithPlural$4(number, withoutSuffix, key) {
+    var format = {
+        'mm': withoutSuffix ? 'хвилина_хвилини_хвилин' : 'хвилину_хвилини_хвилин',
+        'hh': withoutSuffix ? 'година_години_годин' : 'годину_години_годин',
+        'dd': 'день_дні_днів',
+        'MM': 'місяць_місяці_місяців',
+        'yy': 'рік_роки_років'
+    };
+    if (key === 'm') {
+        return withoutSuffix ? 'хвилина' : 'хвилину';
+    }
+    else if (key === 'h') {
+        return withoutSuffix ? 'година' : 'годину';
+    }
+    else {
+        return number + ' ' + plural$6(format[key], +number);
+    }
+}
+function weekdaysCaseReplace(m, format) {
+    var weekdays = {
+        'nominative': 'неділя_понеділок_вівторок_середа_четвер_п’ятниця_субота'.split('_'),
+        'accusative': 'неділю_понеділок_вівторок_середу_четвер_п’ятницю_суботу'.split('_'),
+        'genitive': 'неділі_понеділка_вівторка_середи_четверга_п’ятниці_суботи'.split('_')
+    },
+    nounCase = (/(\[[ВвУу]\]) ?dddd/).test(format) ?
+        'accusative' :
+        ((/\[?(?:минулої|наступної)? ?\] ?dddd/).test(format) ?
+            'genitive' :
+            'nominative');
+    return weekdays[nounCase][m.day()];
+}
+function processHoursFunction(str) {
+    return function () {
+        return str + 'о' + (this.hours() === 11 ? 'б' : '') + '] LT';
+    };
+}
+
+hooks.defineLocale('uk', {
+    months : {
+        'format': 'січня_лютого_березня_квітня_травня_червня_липня_серпня_вересня_жовтня_листопада_грудня'.split('_'),
+        'standalone': 'січень_лютий_березень_квітень_травень_червень_липень_серпень_вересень_жовтень_листопад_грудень'.split('_')
+    },
+    monthsShort : 'січ_лют_бер_квіт_трав_черв_лип_серп_вер_жовт_лист_груд'.split('_'),
+    weekdays : weekdaysCaseReplace,
+    weekdaysShort : 'нд_пн_вт_ср_чт_пт_сб'.split('_'),
+    weekdaysMin : 'нд_пн_вт_ср_чт_пт_сб'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY р.',
+        LLL : 'D MMMM YYYY р., HH:mm',
+        LLLL : 'dddd, D MMMM YYYY р., HH:mm'
+    },
+    calendar : {
+        sameDay: processHoursFunction('[Сьогодні '),
+        nextDay: processHoursFunction('[Завтра '),
+        lastDay: processHoursFunction('[Вчора '),
+        nextWeek: processHoursFunction('[У] dddd ['),
+        lastWeek: function () {
+            switch (this.day()) {
+                case 0:
+                case 3:
+                case 5:
+                case 6:
+                    return processHoursFunction('[Минулої] dddd [').call(this);
+                case 1:
+                case 2:
+                case 4:
+                    return processHoursFunction('[Минулого] dddd [').call(this);
+            }
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'за %s',
+        past : '%s тому',
+        s : 'декілька секунд',
+        m : relativeTimeWithPlural$4,
+        mm : relativeTimeWithPlural$4,
+        h : 'годину',
+        hh : relativeTimeWithPlural$4,
+        d : 'день',
+        dd : relativeTimeWithPlural$4,
+        M : 'місяць',
+        MM : relativeTimeWithPlural$4,
+        y : 'рік',
+        yy : relativeTimeWithPlural$4
+    },
+    // M. E.: those two are virtually unused but a user might want to implement them for his/her website for some reason
+    meridiemParse: /ночі|ранку|дня|вечора/,
+    isPM: function (input) {
+        return /^(дня|вечора)$/.test(input);
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'ночі';
+        } else if (hour < 12) {
+            return 'ранку';
+        } else if (hour < 17) {
+            return 'дня';
+        } else {
+            return 'вечора';
+        }
+    },
+    ordinalParse: /\d{1,2}-(й|го)/,
+    ordinal: function (number, period) {
+        switch (period) {
+            case 'M':
+            case 'd':
+            case 'DDD':
+            case 'w':
+            case 'W':
+                return number + '-й';
+            case 'D':
+                return number + '-го';
+            default:
+                return number;
+        }
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Uzbek [uz]
+//! author : Sardor Muminov : https://github.com/muminoff
+
+hooks.defineLocale('uz', {
+    months : 'январ_феврал_март_апрел_май_июн_июл_август_сентябр_октябр_ноябр_декабр'.split('_'),
+    monthsShort : 'янв_фев_мар_апр_май_июн_июл_авг_сен_окт_ноя_дек'.split('_'),
+    weekdays : 'Якшанба_Душанба_Сешанба_Чоршанба_Пайшанба_Жума_Шанба'.split('_'),
+    weekdaysShort : 'Якш_Душ_Сеш_Чор_Пай_Жум_Шан'.split('_'),
+    weekdaysMin : 'Як_Ду_Се_Чо_Па_Жу_Ша'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'D MMMM YYYY, dddd HH:mm'
+    },
+    calendar : {
+        sameDay : '[Бугун соат] LT [да]',
+        nextDay : '[Эртага] LT [да]',
+        nextWeek : 'dddd [куни соат] LT [да]',
+        lastDay : '[Кеча соат] LT [да]',
+        lastWeek : '[Утган] dddd [куни соат] LT [да]',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'Якин %s ичида',
+        past : 'Бир неча %s олдин',
+        s : 'фурсат',
+        m : 'бир дакика',
+        mm : '%d дакика',
+        h : 'бир соат',
+        hh : '%d соат',
+        d : 'бир кун',
+        dd : '%d кун',
+        M : 'бир ой',
+        MM : '%d ой',
+        y : 'бир йил',
+        yy : '%d йил'
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Vietnamese [vi]
+//! author : Bang Nguyen : https://github.com/bangnk
+
+hooks.defineLocale('vi', {
+    months : 'tháng 1_tháng 2_tháng 3_tháng 4_tháng 5_tháng 6_tháng 7_tháng 8_tháng 9_tháng 10_tháng 11_tháng 12'.split('_'),
+    monthsShort : 'Th01_Th02_Th03_Th04_Th05_Th06_Th07_Th08_Th09_Th10_Th11_Th12'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'chủ nhật_thứ hai_thứ ba_thứ tư_thứ năm_thứ sáu_thứ bảy'.split('_'),
+    weekdaysShort : 'CN_T2_T3_T4_T5_T6_T7'.split('_'),
+    weekdaysMin : 'CN_T2_T3_T4_T5_T6_T7'.split('_'),
+    weekdaysParseExact : true,
+    meridiemParse: /sa|ch/i,
+    isPM : function (input) {
+        return /^ch$/i.test(input);
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 12) {
+            return isLower ? 'sa' : 'SA';
+        } else {
+            return isLower ? 'ch' : 'CH';
+        }
+    },
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM [năm] YYYY',
+        LLL : 'D MMMM [năm] YYYY HH:mm',
+        LLLL : 'dddd, D MMMM [năm] YYYY HH:mm',
+        l : 'DD/M/YYYY',
+        ll : 'D MMM YYYY',
+        lll : 'D MMM YYYY HH:mm',
+        llll : 'ddd, D MMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Hôm nay lúc] LT',
+        nextDay: '[Ngày mai lúc] LT',
+        nextWeek: 'dddd [tuần tới lúc] LT',
+        lastDay: '[Hôm qua lúc] LT',
+        lastWeek: 'dddd [tuần rồi lúc] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : '%s tá»›i',
+        past : '%s trước',
+        s : 'vài giây',
+        m : 'một phút',
+        mm : '%d phút',
+        h : 'một giờ',
+        hh : '%d giờ',
+        d : 'một ngày',
+        dd : '%d ngày',
+        M : 'một tháng',
+        MM : '%d tháng',
+        y : 'một năm',
+        yy : '%d năm'
+    },
+    ordinalParse: /\d{1,2}/,
+    ordinal : function (number) {
+        return number;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Pseudo [x-pseudo]
+//! author : Andrew Hood : https://github.com/andrewhood125
+
+hooks.defineLocale('x-pseudo', {
+    months : 'J~áñúá~rý_F~ébrú~árý_~Márc~h_Áp~ríl_~Máý_~Júñé~_Júl~ý_Áú~gúst~_Sép~témb~ér_Ó~ctób~ér_Ñ~óvém~bér_~Décé~mbér'.split('_'),
+    monthsShort : 'J~áñ_~Féb_~Már_~Ápr_~Máý_~Júñ_~Júl_~Áúg_~Sép_~Óct_~Ñóv_~Déc'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'S~úñdá~ý_Mó~ñdáý~_Túé~sdáý~_Wéd~ñésd~áý_T~húrs~dáý_~Fríd~áý_S~átúr~dáý'.split('_'),
+    weekdaysShort : 'S~úñ_~Móñ_~Túé_~Wéd_~Thú_~Frí_~Sát'.split('_'),
+    weekdaysMin : 'S~ú_Mó~_Tú_~Wé_T~h_Fr~_Sá'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[T~ódá~ý át] LT',
+        nextDay : '[T~ómó~rró~w át] LT',
+        nextWeek : 'dddd [át] LT',
+        lastDay : '[Ý~ést~érdá~ý át] LT',
+        lastWeek : '[L~ást] dddd [át] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'í~ñ %s',
+        past : '%s á~gó',
+        s : 'á ~féw ~sécó~ñds',
+        m : 'á ~míñ~úté',
+        mm : '%d m~íñú~tés',
+        h : 'á~ñ hó~úr',
+        hh : '%d h~óúrs',
+        d : 'á ~dáý',
+        dd : '%d d~áýs',
+        M : 'á ~móñ~th',
+        MM : '%d m~óñt~hs',
+        y : 'á ~ýéár',
+        yy : '%d ý~éárs'
+    },
+    ordinalParse: /\d{1,2}(th|st|nd|rd)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Chinese (China) [zh-cn]
+//! author : suupic : https://github.com/suupic
+//! author : Zeno Zeng : https://github.com/zenozeng
+
+hooks.defineLocale('zh-cn', {
+    months : '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'),
+    monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
+    weekdays : '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'),
+    weekdaysShort : '周日_周一_周二_周三_周四_周五_周六'.split('_'),
+    weekdaysMin : '日_一_二_三_四_五_六'.split('_'),
+    longDateFormat : {
+        LT : 'Ah点mm分',
+        LTS : 'Ah点m分s秒',
+        L : 'YYYY-MM-DD',
+        LL : 'YYYYå¹´MMMDæ—¥',
+        LLL : 'YYYY年MMMD日Ah点mm分',
+        LLLL : 'YYYY年MMMD日ddddAh点mm分',
+        l : 'YYYY-MM-DD',
+        ll : 'YYYYå¹´MMMDæ—¥',
+        lll : 'YYYY年MMMD日Ah点mm分',
+        llll : 'YYYY年MMMD日ddddAh点mm分'
+    },
+    meridiemParse: /凌晨|早上|上午|中午|下午|晚上/,
+    meridiemHour: function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === '凌晨' || meridiem === '早上' ||
+                meridiem === '上午') {
+            return hour;
+        } else if (meridiem === '下午' || meridiem === '晚上') {
+            return hour + 12;
+        } else {
+            // '中午'
+            return hour >= 11 ? hour : hour + 12;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        var hm = hour * 100 + minute;
+        if (hm < 600) {
+            return '凌晨';
+        } else if (hm < 900) {
+            return '早上';
+        } else if (hm < 1130) {
+            return '上午';
+        } else if (hm < 1230) {
+            return '中午';
+        } else if (hm < 1800) {
+            return '下午';
+        } else {
+            return '晚上';
+        }
+    },
+    calendar : {
+        sameDay : function () {
+            return this.minutes() === 0 ? '[今天]Ah[点整]' : '[今天]LT';
+        },
+        nextDay : function () {
+            return this.minutes() === 0 ? '[明天]Ah[点整]' : '[明天]LT';
+        },
+        lastDay : function () {
+            return this.minutes() === 0 ? '[昨天]Ah[点整]' : '[昨天]LT';
+        },
+        nextWeek : function () {
+            var startOfWeek, prefix;
+            startOfWeek = hooks().startOf('week');
+            prefix = this.diff(startOfWeek, 'days') >= 7 ? '[下]' : '[本]';
+            return this.minutes() === 0 ? prefix + 'dddAh点整' : prefix + 'dddAh点mm';
+        },
+        lastWeek : function () {
+            var startOfWeek, prefix;
+            startOfWeek = hooks().startOf('week');
+            prefix = this.unix() < startOfWeek.unix()  ? '[上]' : '[本]';
+            return this.minutes() === 0 ? prefix + 'dddAh点整' : prefix + 'dddAh点mm';
+        },
+        sameElse : 'LL'
+    },
+    ordinalParse: /\d{1,2}(日|月|周)/,
+    ordinal : function (number, period) {
+        switch (period) {
+            case 'd':
+            case 'D':
+            case 'DDD':
+                return number + 'æ—¥';
+            case 'M':
+                return number + '月';
+            case 'w':
+            case 'W':
+                return number + '周';
+            default:
+                return number;
+        }
+    },
+    relativeTime : {
+        future : '%s内',
+        past : '%s前',
+        s : '几秒',
+        m : '1 分钟',
+        mm : '%d 分钟',
+        h : '1 小时',
+        hh : '%d 小时',
+        d : '1 天',
+        dd : '%d 天',
+        M : '1 个月',
+        MM : '%d 个月',
+        y : '1 å¹´',
+        yy : '%d å¹´'
+    },
+    week : {
+        // GB/T 7408-1994《数据元和交换格式·信息交换·日期和时间表示法》与ISO 8601:1988等效
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Chinese (Hong Kong) [zh-hk]
+//! author : Ben : https://github.com/ben-lin
+//! author : Chris Lam : https://github.com/hehachris
+//! author : Konstantin : https://github.com/skfd
+
+hooks.defineLocale('zh-hk', {
+    months : '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'),
+    monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
+    weekdays : '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'),
+    weekdaysShort : '週日_週一_週二_週三_週四_週五_週六'.split('_'),
+    weekdaysMin : '日_一_二_三_四_五_六'.split('_'),
+    longDateFormat : {
+        LT : 'Ah點mm分',
+        LTS : 'Ah點m分s秒',
+        L : 'YYYYå¹´MMMDæ—¥',
+        LL : 'YYYYå¹´MMMDæ—¥',
+        LLL : 'YYYY年MMMD日Ah點mm分',
+        LLLL : 'YYYY年MMMD日ddddAh點mm分',
+        l : 'YYYYå¹´MMMDæ—¥',
+        ll : 'YYYYå¹´MMMDæ—¥',
+        lll : 'YYYY年MMMD日Ah點mm分',
+        llll : 'YYYY年MMMD日ddddAh點mm分'
+    },
+    meridiemParse: /凌晨|早上|上午|中午|下午|晚上/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === '凌晨' || meridiem === '早上' || meridiem === '上午') {
+            return hour;
+        } else if (meridiem === '中午') {
+            return hour >= 11 ? hour : hour + 12;
+        } else if (meridiem === '下午' || meridiem === '晚上') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        var hm = hour * 100 + minute;
+        if (hm < 600) {
+            return '凌晨';
+        } else if (hm < 900) {
+            return '早上';
+        } else if (hm < 1130) {
+            return '上午';
+        } else if (hm < 1230) {
+            return '中午';
+        } else if (hm < 1800) {
+            return '下午';
+        } else {
+            return '晚上';
+        }
+    },
+    calendar : {
+        sameDay : '[今天]LT',
+        nextDay : '[明天]LT',
+        nextWeek : '[下]ddddLT',
+        lastDay : '[昨天]LT',
+        lastWeek : '[上]ddddLT',
+        sameElse : 'L'
+    },
+    ordinalParse: /\d{1,2}(日|月|週)/,
+    ordinal : function (number, period) {
+        switch (period) {
+            case 'd' :
+            case 'D' :
+            case 'DDD' :
+                return number + 'æ—¥';
+            case 'M' :
+                return number + '月';
+            case 'w' :
+            case 'W' :
+                return number + '週';
+            default :
+                return number;
+        }
+    },
+    relativeTime : {
+        future : '%så…§',
+        past : '%s前',
+        s : '幾秒',
+        m : '1 分鐘',
+        mm : '%d 分鐘',
+        h : '1 小時',
+        hh : '%d 小時',
+        d : '1 天',
+        dd : '%d 天',
+        M : '1 個月',
+        MM : '%d 個月',
+        y : '1 å¹´',
+        yy : '%d å¹´'
+    }
+});
+
+//! moment.js locale configuration
+//! locale : Chinese (Taiwan) [zh-tw]
+//! author : Ben : https://github.com/ben-lin
+//! author : Chris Lam : https://github.com/hehachris
+
+hooks.defineLocale('zh-tw', {
+    months : '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'),
+    monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
+    weekdays : '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'),
+    weekdaysShort : '週日_週一_週二_週三_週四_週五_週六'.split('_'),
+    weekdaysMin : '日_一_二_三_四_五_六'.split('_'),
+    longDateFormat : {
+        LT : 'Ah點mm分',
+        LTS : 'Ah點m分s秒',
+        L : 'YYYYå¹´MMMDæ—¥',
+        LL : 'YYYYå¹´MMMDæ—¥',
+        LLL : 'YYYY年MMMD日Ah點mm分',
+        LLLL : 'YYYY年MMMD日ddddAh點mm分',
+        l : 'YYYYå¹´MMMDæ—¥',
+        ll : 'YYYYå¹´MMMDæ—¥',
+        lll : 'YYYY年MMMD日Ah點mm分',
+        llll : 'YYYY年MMMD日ddddAh點mm分'
+    },
+    meridiemParse: /凌晨|早上|上午|中午|下午|晚上/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === '凌晨' || meridiem === '早上' || meridiem === '上午') {
+            return hour;
+        } else if (meridiem === '中午') {
+            return hour >= 11 ? hour : hour + 12;
+        } else if (meridiem === '下午' || meridiem === '晚上') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        var hm = hour * 100 + minute;
+        if (hm < 600) {
+            return '凌晨';
+        } else if (hm < 900) {
+            return '早上';
+        } else if (hm < 1130) {
+            return '上午';
+        } else if (hm < 1230) {
+            return '中午';
+        } else if (hm < 1800) {
+            return '下午';
+        } else {
+            return '晚上';
+        }
+    },
+    calendar : {
+        sameDay : '[今天]LT',
+        nextDay : '[明天]LT',
+        nextWeek : '[下]ddddLT',
+        lastDay : '[昨天]LT',
+        lastWeek : '[上]ddddLT',
+        sameElse : 'L'
+    },
+    ordinalParse: /\d{1,2}(日|月|週)/,
+    ordinal : function (number, period) {
+        switch (period) {
+            case 'd' :
+            case 'D' :
+            case 'DDD' :
+                return number + 'æ—¥';
+            case 'M' :
+                return number + '月';
+            case 'w' :
+            case 'W' :
+                return number + '週';
+            default :
+                return number;
+        }
+    },
+    relativeTime : {
+        future : '%så…§',
+        past : '%s前',
+        s : '幾秒',
+        m : '1 分鐘',
+        mm : '%d 分鐘',
+        h : '1 小時',
+        hh : '%d 小時',
+        d : '1 天',
+        dd : '%d 天',
+        M : '1 個月',
+        MM : '%d 個月',
+        y : '1 å¹´',
+        yy : '%d å¹´'
+    }
+});
+
+hooks.locale('en');
+
+return hooks;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/min/moment-with-locales.min.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/min/moment-with-locales.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..ec919a5c654463f6cc081a0a95cdec7375dceb5f
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/min/moment-with-locales.min.js
@@ -0,0 +1,1212 @@
+!function(a,b){"object"==typeof exports&&"undefined"!=typeof module?module.exports=b():"function"==typeof define&&define.amd?define(b):a.moment=b()}(this,function(){"use strict";function a(){return le.apply(null,arguments)}
+// This is done to register the method called with moment()
+// without creating circular dependencies.
+function b(a){le=a}function c(a){return a instanceof Array||"[object Array]"===Object.prototype.toString.call(a)}function d(a){
+// IE8 will treat undefined and null as object if it wasn't for
+// input != null
+return null!=a&&"[object Object]"===Object.prototype.toString.call(a)}function e(a){var b;for(b in a)
+// even if its not own property I'd still call it non-empty
+return!1;return!0}function f(a){return"number"==typeof value||"[object Number]"===Object.prototype.toString.call(a)}function g(a){return a instanceof Date||"[object Date]"===Object.prototype.toString.call(a)}function h(a,b){var c,d=[];for(c=0;c<a.length;++c)d.push(b(a[c],c));return d}function i(a,b){return Object.prototype.hasOwnProperty.call(a,b)}function j(a,b){for(var c in b)i(b,c)&&(a[c]=b[c]);return i(b,"toString")&&(a.toString=b.toString),i(b,"valueOf")&&(a.valueOf=b.valueOf),a}function k(a,b,c,d){return rb(a,b,c,d,!0).utc()}function l(){
+// We need to deep clone this object.
+return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1,parsedDateParts:[],meridiem:null}}function m(a){return null==a._pf&&(a._pf=l()),a._pf}function n(a){if(null==a._isValid){var b=m(a),c=ne.call(b.parsedDateParts,function(a){return null!=a}),d=!isNaN(a._d.getTime())&&b.overflow<0&&!b.empty&&!b.invalidMonth&&!b.invalidWeekday&&!b.nullInput&&!b.invalidFormat&&!b.userInvalidated&&(!b.meridiem||b.meridiem&&c);if(a._strict&&(d=d&&0===b.charsLeftOver&&0===b.unusedTokens.length&&void 0===b.bigHour),null!=Object.isFrozen&&Object.isFrozen(a))return d;a._isValid=d}return a._isValid}function o(a){var b=k(NaN);return null!=a?j(m(b),a):m(b).userInvalidated=!0,b}function p(a){return void 0===a}function q(a,b){var c,d,e;if(p(b._isAMomentObject)||(a._isAMomentObject=b._isAMomentObject),p(b._i)||(a._i=b._i),p(b._f)||(a._f=b._f),p(b._l)||(a._l=b._l),p(b._strict)||(a._strict=b._strict),p(b._tzm)||(a._tzm=b._tzm),p(b._isUTC)||(a._isUTC=b._isUTC),p(b._offset)||(a._offset=b._offset),p(b._pf)||(a._pf=m(b)),p(b._locale)||(a._locale=b._locale),oe.length>0)for(c in oe)d=oe[c],e=b[d],p(e)||(a[d]=e);return a}
+// Moment prototype object
+function r(b){q(this,b),this._d=new Date(null!=b._d?b._d.getTime():NaN),
+// Prevent infinite loop in case updateOffset creates new moment
+// objects.
+pe===!1&&(pe=!0,a.updateOffset(this),pe=!1)}function s(a){return a instanceof r||null!=a&&null!=a._isAMomentObject}function t(a){return a<0?Math.ceil(a)||0:Math.floor(a)}function u(a){var b=+a,c=0;return 0!==b&&isFinite(b)&&(c=t(b)),c}
+// compare two arrays, return the number of differences
+function v(a,b,c){var d,e=Math.min(a.length,b.length),f=Math.abs(a.length-b.length),g=0;for(d=0;d<e;d++)(c&&a[d]!==b[d]||!c&&u(a[d])!==u(b[d]))&&g++;return g+f}function w(b){a.suppressDeprecationWarnings===!1&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+b)}function x(b,c){var d=!0;return j(function(){if(null!=a.deprecationHandler&&a.deprecationHandler(null,b),d){for(var e,f=[],g=0;g<arguments.length;g++){if(e="","object"==typeof arguments[g]){e+="\n["+g+"] ";for(var h in arguments[0])e+=h+": "+arguments[0][h]+", ";e=e.slice(0,-2)}else e=arguments[g];f.push(e)}w(b+"\nArguments: "+Array.prototype.slice.call(f).join("")+"\n"+(new Error).stack),d=!1}return c.apply(this,arguments)},c)}function y(b,c){null!=a.deprecationHandler&&a.deprecationHandler(b,c),qe[b]||(w(c),qe[b]=!0)}function z(a){return a instanceof Function||"[object Function]"===Object.prototype.toString.call(a)}function A(a){var b,c;for(c in a)b=a[c],z(b)?this[c]=b:this["_"+c]=b;this._config=a,
+// Lenient ordinal parsing accepts just a number in addition to
+// number + (possibly) stuff coming from _ordinalParseLenient.
+this._ordinalParseLenient=new RegExp(this._ordinalParse.source+"|"+/\d{1,2}/.source)}function B(a,b){var c,e=j({},a);for(c in b)i(b,c)&&(d(a[c])&&d(b[c])?(e[c]={},j(e[c],a[c]),j(e[c],b[c])):null!=b[c]?e[c]=b[c]:delete e[c]);for(c in a)i(a,c)&&!i(b,c)&&d(a[c])&&(
+// make sure changes to properties don't modify parent config
+e[c]=j({},e[c]));return e}function C(a){null!=a&&this.set(a)}function D(a,b,c){var d=this._calendar[a]||this._calendar.sameElse;return z(d)?d.call(b,c):d}function E(a){var b=this._longDateFormat[a],c=this._longDateFormat[a.toUpperCase()];return b||!c?b:(this._longDateFormat[a]=c.replace(/MMMM|MM|DD|dddd/g,function(a){return a.slice(1)}),this._longDateFormat[a])}function F(){return this._invalidDate}function G(a){return this._ordinal.replace("%d",a)}function H(a,b,c,d){var e=this._relativeTime[c];return z(e)?e(a,b,c,d):e.replace(/%d/i,a)}function I(a,b){var c=this._relativeTime[a>0?"future":"past"];return z(c)?c(b):c.replace(/%s/i,b)}function J(a,b){var c=a.toLowerCase();Ae[c]=Ae[c+"s"]=Ae[b]=a}function K(a){return"string"==typeof a?Ae[a]||Ae[a.toLowerCase()]:void 0}function L(a){var b,c,d={};for(c in a)i(a,c)&&(b=K(c),b&&(d[b]=a[c]));return d}function M(a,b){Be[a]=b}function N(a){var b=[];for(var c in a)b.push({unit:c,priority:Be[c]});return b.sort(function(a,b){return a.priority-b.priority}),b}function O(b,c){return function(d){return null!=d?(Q(this,b,d),a.updateOffset(this,c),this):P(this,b)}}function P(a,b){return a.isValid()?a._d["get"+(a._isUTC?"UTC":"")+b]():NaN}function Q(a,b,c){a.isValid()&&a._d["set"+(a._isUTC?"UTC":"")+b](c)}
+// MOMENTS
+function R(a){return a=K(a),z(this[a])?this[a]():this}function S(a,b){if("object"==typeof a){a=L(a);for(var c=N(a),d=0;d<c.length;d++)this[c[d].unit](a[c[d].unit])}else if(a=K(a),z(this[a]))return this[a](b);return this}function T(a,b,c){var d=""+Math.abs(a),e=b-d.length,f=a>=0;return(f?c?"+":"":"-")+Math.pow(10,Math.max(0,e)).toString().substr(1)+d}
+// token:    'M'
+// padded:   ['MM', 2]
+// ordinal:  'Mo'
+// callback: function () { this.month() + 1 }
+function U(a,b,c,d){var e=d;"string"==typeof d&&(e=function(){return this[d]()}),a&&(Fe[a]=e),b&&(Fe[b[0]]=function(){return T(e.apply(this,arguments),b[1],b[2])}),c&&(Fe[c]=function(){return this.localeData().ordinal(e.apply(this,arguments),a)})}function V(a){return a.match(/\[[\s\S]/)?a.replace(/^\[|\]$/g,""):a.replace(/\\/g,"")}function W(a){var b,c,d=a.match(Ce);for(b=0,c=d.length;b<c;b++)Fe[d[b]]?d[b]=Fe[d[b]]:d[b]=V(d[b]);return function(b){var e,f="";for(e=0;e<c;e++)f+=d[e]instanceof Function?d[e].call(b,a):d[e];return f}}
+// format date using native date object
+function X(a,b){return a.isValid()?(b=Y(b,a.localeData()),Ee[b]=Ee[b]||W(b),Ee[b](a)):a.localeData().invalidDate()}function Y(a,b){function c(a){return b.longDateFormat(a)||a}var d=5;for(De.lastIndex=0;d>=0&&De.test(a);)a=a.replace(De,c),De.lastIndex=0,d-=1;return a}function Z(a,b,c){Xe[a]=z(b)?b:function(a,d){return a&&c?c:b}}function $(a,b){return i(Xe,a)?Xe[a](b._strict,b._locale):new RegExp(_(a))}
+// Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
+function _(a){return aa(a.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(a,b,c,d,e){return b||c||d||e}))}function aa(a){return a.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function ba(a,b){var c,d=b;for("string"==typeof a&&(a=[a]),f(b)&&(d=function(a,c){c[b]=u(a)}),c=0;c<a.length;c++)Ye[a[c]]=d}function ca(a,b){ba(a,function(a,c,d,e){d._w=d._w||{},b(a,d._w,d,e)})}function da(a,b,c){null!=b&&i(Ye,a)&&Ye[a](b,c._a,c,a)}function ea(a,b){return new Date(Date.UTC(a,b+1,0)).getUTCDate()}function fa(a,b){return a?c(this._months)?this._months[a.month()]:this._months[(this._months.isFormat||hf).test(b)?"format":"standalone"][a.month()]:this._months}function ga(a,b){return a?c(this._monthsShort)?this._monthsShort[a.month()]:this._monthsShort[hf.test(b)?"format":"standalone"][a.month()]:this._monthsShort}function ha(a,b,c){var d,e,f,g=a.toLocaleLowerCase();if(!this._monthsParse)for(
+// this is not used
+this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[],d=0;d<12;++d)f=k([2e3,d]),this._shortMonthsParse[d]=this.monthsShort(f,"").toLocaleLowerCase(),this._longMonthsParse[d]=this.months(f,"").toLocaleLowerCase();return c?"MMM"===b?(e=gf.call(this._shortMonthsParse,g),e!==-1?e:null):(e=gf.call(this._longMonthsParse,g),e!==-1?e:null):"MMM"===b?(e=gf.call(this._shortMonthsParse,g),e!==-1?e:(e=gf.call(this._longMonthsParse,g),e!==-1?e:null)):(e=gf.call(this._longMonthsParse,g),e!==-1?e:(e=gf.call(this._shortMonthsParse,g),e!==-1?e:null))}function ia(a,b,c){var d,e,f;if(this._monthsParseExact)return ha.call(this,a,b,c);
+// TODO: add sorting
+// Sorting makes sure if one month (or abbr) is a prefix of another
+// see sorting in computeMonthsParse
+for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),d=0;d<12;d++){
+// test the regex
+if(
+// make the regex if we don't have it already
+e=k([2e3,d]),c&&!this._longMonthsParse[d]&&(this._longMonthsParse[d]=new RegExp("^"+this.months(e,"").replace(".","")+"$","i"),this._shortMonthsParse[d]=new RegExp("^"+this.monthsShort(e,"").replace(".","")+"$","i")),c||this._monthsParse[d]||(f="^"+this.months(e,"")+"|^"+this.monthsShort(e,""),this._monthsParse[d]=new RegExp(f.replace(".",""),"i")),c&&"MMMM"===b&&this._longMonthsParse[d].test(a))return d;if(c&&"MMM"===b&&this._shortMonthsParse[d].test(a))return d;if(!c&&this._monthsParse[d].test(a))return d}}
+// MOMENTS
+function ja(a,b){var c;if(!a.isValid())
+// No op
+return a;if("string"==typeof b)if(/^\d+$/.test(b))b=u(b);else
+// TODO: Another silent failure?
+if(b=a.localeData().monthsParse(b),!f(b))return a;return c=Math.min(a.date(),ea(a.year(),b)),a._d["set"+(a._isUTC?"UTC":"")+"Month"](b,c),a}function ka(b){return null!=b?(ja(this,b),a.updateOffset(this,!0),this):P(this,"Month")}function la(){return ea(this.year(),this.month())}function ma(a){return this._monthsParseExact?(i(this,"_monthsRegex")||oa.call(this),a?this._monthsShortStrictRegex:this._monthsShortRegex):(i(this,"_monthsShortRegex")||(this._monthsShortRegex=lf),this._monthsShortStrictRegex&&a?this._monthsShortStrictRegex:this._monthsShortRegex)}function na(a){return this._monthsParseExact?(i(this,"_monthsRegex")||oa.call(this),a?this._monthsStrictRegex:this._monthsRegex):(i(this,"_monthsRegex")||(this._monthsRegex=mf),this._monthsStrictRegex&&a?this._monthsStrictRegex:this._monthsRegex)}function oa(){function a(a,b){return b.length-a.length}var b,c,d=[],e=[],f=[];for(b=0;b<12;b++)
+// make the regex if we don't have it already
+c=k([2e3,b]),d.push(this.monthsShort(c,"")),e.push(this.months(c,"")),f.push(this.months(c,"")),f.push(this.monthsShort(c,""));for(
+// Sorting makes sure if one month (or abbr) is a prefix of another it
+// will match the longer piece.
+d.sort(a),e.sort(a),f.sort(a),b=0;b<12;b++)d[b]=aa(d[b]),e[b]=aa(e[b]);for(b=0;b<24;b++)f[b]=aa(f[b]);this._monthsRegex=new RegExp("^("+f.join("|")+")","i"),this._monthsShortRegex=this._monthsRegex,this._monthsStrictRegex=new RegExp("^("+e.join("|")+")","i"),this._monthsShortStrictRegex=new RegExp("^("+d.join("|")+")","i")}
+// HELPERS
+function pa(a){return qa(a)?366:365}function qa(a){return a%4===0&&a%100!==0||a%400===0}function ra(){return qa(this.year())}function sa(a,b,c,d,e,f,g){
+//can't just apply() to create a date:
+//http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply
+var h=new Date(a,b,c,d,e,f,g);
+//the date constructor remaps years 0-99 to 1900-1999
+return a<100&&a>=0&&isFinite(h.getFullYear())&&h.setFullYear(a),h}function ta(a){var b=new Date(Date.UTC.apply(null,arguments));
+//the Date.UTC function remaps years 0-99 to 1900-1999
+return a<100&&a>=0&&isFinite(b.getUTCFullYear())&&b.setUTCFullYear(a),b}
+// start-of-first-week - start-of-year
+function ua(a,b,c){var// first-week day -- which january is always in the first week (4 for iso, 1 for other)
+d=7+b-c,
+// first-week day local weekday -- which local weekday is fwd
+e=(7+ta(a,0,d).getUTCDay()-b)%7;return-e+d-1}
+//http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
+function va(a,b,c,d,e){var f,g,h=(7+c-d)%7,i=ua(a,d,e),j=1+7*(b-1)+h+i;return j<=0?(f=a-1,g=pa(f)+j):j>pa(a)?(f=a+1,g=j-pa(a)):(f=a,g=j),{year:f,dayOfYear:g}}function wa(a,b,c){var d,e,f=ua(a.year(),b,c),g=Math.floor((a.dayOfYear()-f-1)/7)+1;return g<1?(e=a.year()-1,d=g+xa(e,b,c)):g>xa(a.year(),b,c)?(d=g-xa(a.year(),b,c),e=a.year()+1):(e=a.year(),d=g),{week:d,year:e}}function xa(a,b,c){var d=ua(a,b,c),e=ua(a+1,b,c);return(pa(a)-d+e)/7}
+// HELPERS
+// LOCALES
+function ya(a){return wa(a,this._week.dow,this._week.doy).week}function za(){return this._week.dow}function Aa(){return this._week.doy}
+// MOMENTS
+function Ba(a){var b=this.localeData().week(this);return null==a?b:this.add(7*(a-b),"d")}function Ca(a){var b=wa(this,1,4).week;return null==a?b:this.add(7*(a-b),"d")}
+// HELPERS
+function Da(a,b){return"string"!=typeof a?a:isNaN(a)?(a=b.weekdaysParse(a),"number"==typeof a?a:null):parseInt(a,10)}function Ea(a,b){return"string"==typeof a?b.weekdaysParse(a)%7||7:isNaN(a)?null:a}function Fa(a,b){return a?c(this._weekdays)?this._weekdays[a.day()]:this._weekdays[this._weekdays.isFormat.test(b)?"format":"standalone"][a.day()]:this._weekdays}function Ga(a){return a?this._weekdaysShort[a.day()]:this._weekdaysShort}function Ha(a){return a?this._weekdaysMin[a.day()]:this._weekdaysMin}function Ia(a,b,c){var d,e,f,g=a.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],d=0;d<7;++d)f=k([2e3,1]).day(d),this._minWeekdaysParse[d]=this.weekdaysMin(f,"").toLocaleLowerCase(),this._shortWeekdaysParse[d]=this.weekdaysShort(f,"").toLocaleLowerCase(),this._weekdaysParse[d]=this.weekdays(f,"").toLocaleLowerCase();return c?"dddd"===b?(e=gf.call(this._weekdaysParse,g),e!==-1?e:null):"ddd"===b?(e=gf.call(this._shortWeekdaysParse,g),e!==-1?e:null):(e=gf.call(this._minWeekdaysParse,g),e!==-1?e:null):"dddd"===b?(e=gf.call(this._weekdaysParse,g),e!==-1?e:(e=gf.call(this._shortWeekdaysParse,g),e!==-1?e:(e=gf.call(this._minWeekdaysParse,g),e!==-1?e:null))):"ddd"===b?(e=gf.call(this._shortWeekdaysParse,g),e!==-1?e:(e=gf.call(this._weekdaysParse,g),e!==-1?e:(e=gf.call(this._minWeekdaysParse,g),e!==-1?e:null))):(e=gf.call(this._minWeekdaysParse,g),e!==-1?e:(e=gf.call(this._weekdaysParse,g),e!==-1?e:(e=gf.call(this._shortWeekdaysParse,g),e!==-1?e:null)))}function Ja(a,b,c){var d,e,f;if(this._weekdaysParseExact)return Ia.call(this,a,b,c);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),d=0;d<7;d++){
+// test the regex
+if(
+// make the regex if we don't have it already
+e=k([2e3,1]).day(d),c&&!this._fullWeekdaysParse[d]&&(this._fullWeekdaysParse[d]=new RegExp("^"+this.weekdays(e,"").replace(".",".?")+"$","i"),this._shortWeekdaysParse[d]=new RegExp("^"+this.weekdaysShort(e,"").replace(".",".?")+"$","i"),this._minWeekdaysParse[d]=new RegExp("^"+this.weekdaysMin(e,"").replace(".",".?")+"$","i")),this._weekdaysParse[d]||(f="^"+this.weekdays(e,"")+"|^"+this.weekdaysShort(e,"")+"|^"+this.weekdaysMin(e,""),this._weekdaysParse[d]=new RegExp(f.replace(".",""),"i")),c&&"dddd"===b&&this._fullWeekdaysParse[d].test(a))return d;if(c&&"ddd"===b&&this._shortWeekdaysParse[d].test(a))return d;if(c&&"dd"===b&&this._minWeekdaysParse[d].test(a))return d;if(!c&&this._weekdaysParse[d].test(a))return d}}
+// MOMENTS
+function Ka(a){if(!this.isValid())return null!=a?this:NaN;var b=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=a?(a=Da(a,this.localeData()),this.add(a-b,"d")):b}function La(a){if(!this.isValid())return null!=a?this:NaN;var b=(this.day()+7-this.localeData()._week.dow)%7;return null==a?b:this.add(a-b,"d")}function Ma(a){if(!this.isValid())return null!=a?this:NaN;
+// behaves the same as moment#day except
+// as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
+// as a setter, sunday should belong to the previous week.
+if(null!=a){var b=Ea(a,this.localeData());return this.day(this.day()%7?b:b-7)}return this.day()||7}function Na(a){return this._weekdaysParseExact?(i(this,"_weekdaysRegex")||Qa.call(this),a?this._weekdaysStrictRegex:this._weekdaysRegex):(i(this,"_weekdaysRegex")||(this._weekdaysRegex=sf),this._weekdaysStrictRegex&&a?this._weekdaysStrictRegex:this._weekdaysRegex)}function Oa(a){return this._weekdaysParseExact?(i(this,"_weekdaysRegex")||Qa.call(this),a?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(i(this,"_weekdaysShortRegex")||(this._weekdaysShortRegex=tf),this._weekdaysShortStrictRegex&&a?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)}function Pa(a){return this._weekdaysParseExact?(i(this,"_weekdaysRegex")||Qa.call(this),a?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(i(this,"_weekdaysMinRegex")||(this._weekdaysMinRegex=uf),this._weekdaysMinStrictRegex&&a?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)}function Qa(){function a(a,b){return b.length-a.length}var b,c,d,e,f,g=[],h=[],i=[],j=[];for(b=0;b<7;b++)
+// make the regex if we don't have it already
+c=k([2e3,1]).day(b),d=this.weekdaysMin(c,""),e=this.weekdaysShort(c,""),f=this.weekdays(c,""),g.push(d),h.push(e),i.push(f),j.push(d),j.push(e),j.push(f);for(
+// Sorting makes sure if one weekday (or abbr) is a prefix of another it
+// will match the longer piece.
+g.sort(a),h.sort(a),i.sort(a),j.sort(a),b=0;b<7;b++)h[b]=aa(h[b]),i[b]=aa(i[b]),j[b]=aa(j[b]);this._weekdaysRegex=new RegExp("^("+j.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+i.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+h.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+g.join("|")+")","i")}
+// FORMATTING
+function Ra(){return this.hours()%12||12}function Sa(){return this.hours()||24}function Ta(a,b){U(a,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),b)})}
+// PARSING
+function Ua(a,b){return b._meridiemParse}
+// LOCALES
+function Va(a){
+// IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
+// Using charAt should be more compatible.
+return"p"===(a+"").toLowerCase().charAt(0)}function Wa(a,b,c){return a>11?c?"pm":"PM":c?"am":"AM"}function Xa(a){return a?a.toLowerCase().replace("_","-"):a}
+// pick the locale from the array
+// try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
+// substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
+function Ya(a){for(var b,c,d,e,f=0;f<a.length;){for(e=Xa(a[f]).split("-"),b=e.length,c=Xa(a[f+1]),c=c?c.split("-"):null;b>0;){if(d=Za(e.slice(0,b).join("-")))return d;if(c&&c.length>=b&&v(e,c,!0)>=b-1)
+//the next array item is better than a shallower substring of this one
+break;b--}f++}return null}function Za(a){var b=null;
+// TODO: Find a better way to register and load all the locales in Node
+if(!zf[a]&&"undefined"!=typeof module&&module&&module.exports)try{b=vf._abbr,require("./locale/"+a),
+// because defineLocale currently also sets the global locale, we
+// want to undo that for lazy loaded locales
+$a(b)}catch(a){}return zf[a]}
+// This function will load locale and then set the global locale.  If
+// no arguments are passed in, it will simply return the current global
+// locale key.
+function $a(a,b){var c;
+// moment.duration._locale = moment._locale = data;
+return a&&(c=p(b)?bb(a):_a(a,b),c&&(vf=c)),vf._abbr}function _a(a,b){if(null!==b){var c=yf;if(b.abbr=a,null!=zf[a])y("defineLocaleOverride","use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."),c=zf[a]._config;else if(null!=b.parentLocale){if(null==zf[b.parentLocale])return Af[b.parentLocale]||(Af[b.parentLocale]=[]),Af[b.parentLocale].push({name:a,config:b}),null;c=zf[b.parentLocale]._config}
+// backwards compat for now: also set the locale
+// make sure we set the locale AFTER all child locales have been
+// created, so we won't end up with the child locale set.
+return zf[a]=new C(B(c,b)),Af[a]&&Af[a].forEach(function(a){_a(a.name,a.config)}),$a(a),zf[a]}
+// useful for testing
+return delete zf[a],null}function ab(a,b){if(null!=b){var c,d=yf;
+// MERGE
+null!=zf[a]&&(d=zf[a]._config),b=B(d,b),c=new C(b),c.parentLocale=zf[a],zf[a]=c,
+// backwards compat for now: also set the locale
+$a(a)}else
+// pass null for config to unupdate, useful for tests
+null!=zf[a]&&(null!=zf[a].parentLocale?zf[a]=zf[a].parentLocale:null!=zf[a]&&delete zf[a]);return zf[a]}
+// returns locale data
+function bb(a){var b;if(a&&a._locale&&a._locale._abbr&&(a=a._locale._abbr),!a)return vf;if(!c(a)){if(
+//short-circuit everything else
+b=Za(a))return b;a=[a]}return Ya(a)}function cb(){return te(zf)}function db(a){var b,c=a._a;return c&&m(a).overflow===-2&&(b=c[$e]<0||c[$e]>11?$e:c[_e]<1||c[_e]>ea(c[Ze],c[$e])?_e:c[af]<0||c[af]>24||24===c[af]&&(0!==c[bf]||0!==c[cf]||0!==c[df])?af:c[bf]<0||c[bf]>59?bf:c[cf]<0||c[cf]>59?cf:c[df]<0||c[df]>999?df:-1,m(a)._overflowDayOfYear&&(b<Ze||b>_e)&&(b=_e),m(a)._overflowWeeks&&b===-1&&(b=ef),m(a)._overflowWeekday&&b===-1&&(b=ff),m(a).overflow=b),a}
+// date from iso format
+function eb(a){var b,c,d,e,f,g,h=a._i,i=Bf.exec(h)||Cf.exec(h);if(i){for(m(a).iso=!0,b=0,c=Ef.length;b<c;b++)if(Ef[b][1].exec(i[1])){e=Ef[b][0],d=Ef[b][2]!==!1;break}if(null==e)return void(a._isValid=!1);if(i[3]){for(b=0,c=Ff.length;b<c;b++)if(Ff[b][1].exec(i[3])){
+// match[2] should be 'T' or space
+f=(i[2]||" ")+Ff[b][0];break}if(null==f)return void(a._isValid=!1)}if(!d&&null!=f)return void(a._isValid=!1);if(i[4]){if(!Df.exec(i[4]))return void(a._isValid=!1);g="Z"}a._f=e+(f||"")+(g||""),kb(a)}else a._isValid=!1}
+// date from iso format or fallback
+function fb(b){var c=Gf.exec(b._i);return null!==c?void(b._d=new Date(+c[1])):(eb(b),void(b._isValid===!1&&(delete b._isValid,a.createFromInputFallback(b))))}
+// Pick the first defined of two or three arguments.
+function gb(a,b,c){return null!=a?a:null!=b?b:c}function hb(b){
+// hooks is actually the exported moment object
+var c=new Date(a.now());return b._useUTC?[c.getUTCFullYear(),c.getUTCMonth(),c.getUTCDate()]:[c.getFullYear(),c.getMonth(),c.getDate()]}
+// convert an array to a date.
+// the array should mirror the parameters below
+// note: all values past the year are optional and will default to the lowest possible value.
+// [year, month, day , hour, minute, second, millisecond]
+function ib(a){var b,c,d,e,f=[];if(!a._d){
+// Default to current date.
+// * if no year, month, day of month are given, default to today
+// * if day of month is given, default month and year
+// * if month is given, default only year
+// * if year is given, don't default anything
+for(d=hb(a),
+//compute day of the year from weeks and weekdays
+a._w&&null==a._a[_e]&&null==a._a[$e]&&jb(a),
+//if the day of the year is set, figure out what it is
+a._dayOfYear&&(e=gb(a._a[Ze],d[Ze]),a._dayOfYear>pa(e)&&(m(a)._overflowDayOfYear=!0),c=ta(e,0,a._dayOfYear),a._a[$e]=c.getUTCMonth(),a._a[_e]=c.getUTCDate()),b=0;b<3&&null==a._a[b];++b)a._a[b]=f[b]=d[b];
+// Zero out whatever was not defaulted, including time
+for(;b<7;b++)a._a[b]=f[b]=null==a._a[b]?2===b?1:0:a._a[b];
+// Check for 24:00:00.000
+24===a._a[af]&&0===a._a[bf]&&0===a._a[cf]&&0===a._a[df]&&(a._nextDay=!0,a._a[af]=0),a._d=(a._useUTC?ta:sa).apply(null,f),
+// Apply timezone offset from input. The actual utcOffset can be changed
+// with parseZone.
+null!=a._tzm&&a._d.setUTCMinutes(a._d.getUTCMinutes()-a._tzm),a._nextDay&&(a._a[af]=24)}}function jb(a){var b,c,d,e,f,g,h,i;if(b=a._w,null!=b.GG||null!=b.W||null!=b.E)f=1,g=4,
+// TODO: We need to take the current isoWeekYear, but that depends on
+// how we interpret now (local, utc, fixed offset). So create
+// a now version of current config (take local/utc/offset flags, and
+// create now).
+c=gb(b.GG,a._a[Ze],wa(sb(),1,4).year),d=gb(b.W,1),e=gb(b.E,1),(e<1||e>7)&&(i=!0);else{f=a._locale._week.dow,g=a._locale._week.doy;var j=wa(sb(),f,g);c=gb(b.gg,a._a[Ze],j.year),
+// Default to current week.
+d=gb(b.w,j.week),null!=b.d?(
+// weekday -- low day numbers are considered next week
+e=b.d,(e<0||e>6)&&(i=!0)):null!=b.e?(
+// local weekday -- counting starts from begining of week
+e=b.e+f,(b.e<0||b.e>6)&&(i=!0)):
+// default to begining of week
+e=f}d<1||d>xa(c,f,g)?m(a)._overflowWeeks=!0:null!=i?m(a)._overflowWeekday=!0:(h=va(c,d,e,f,g),a._a[Ze]=h.year,a._dayOfYear=h.dayOfYear)}
+// date from string and format string
+function kb(b){
+// TODO: Move this to another part of the creation flow to prevent circular deps
+if(b._f===a.ISO_8601)return void eb(b);b._a=[],m(b).empty=!0;
+// This array is used to make a Date, either with `new Date` or `Date.UTC`
+var c,d,e,f,g,h=""+b._i,i=h.length,j=0;for(e=Y(b._f,b._locale).match(Ce)||[],c=0;c<e.length;c++)f=e[c],d=(h.match($(f,b))||[])[0],
+// console.log('token', token, 'parsedInput', parsedInput,
+//         'regex', getParseRegexForToken(token, config));
+d&&(g=h.substr(0,h.indexOf(d)),g.length>0&&m(b).unusedInput.push(g),h=h.slice(h.indexOf(d)+d.length),j+=d.length),
+// don't parse if it's not a known token
+Fe[f]?(d?m(b).empty=!1:m(b).unusedTokens.push(f),da(f,d,b)):b._strict&&!d&&m(b).unusedTokens.push(f);
+// add remaining unparsed input length to the string
+m(b).charsLeftOver=i-j,h.length>0&&m(b).unusedInput.push(h),
+// clear _12h flag if hour is <= 12
+b._a[af]<=12&&m(b).bigHour===!0&&b._a[af]>0&&(m(b).bigHour=void 0),m(b).parsedDateParts=b._a.slice(0),m(b).meridiem=b._meridiem,
+// handle meridiem
+b._a[af]=lb(b._locale,b._a[af],b._meridiem),ib(b),db(b)}function lb(a,b,c){var d;
+// Fallback
+return null==c?b:null!=a.meridiemHour?a.meridiemHour(b,c):null!=a.isPM?(d=a.isPM(c),d&&b<12&&(b+=12),d||12!==b||(b=0),b):b}
+// date from string and array of format strings
+function mb(a){var b,c,d,e,f;if(0===a._f.length)return m(a).invalidFormat=!0,void(a._d=new Date(NaN));for(e=0;e<a._f.length;e++)f=0,b=q({},a),null!=a._useUTC&&(b._useUTC=a._useUTC),b._f=a._f[e],kb(b),n(b)&&(
+// if there is any input that was not parsed add a penalty for that format
+f+=m(b).charsLeftOver,
+//or tokens
+f+=10*m(b).unusedTokens.length,m(b).score=f,(null==d||f<d)&&(d=f,c=b));j(a,c||b)}function nb(a){if(!a._d){var b=L(a._i);a._a=h([b.year,b.month,b.day||b.date,b.hour,b.minute,b.second,b.millisecond],function(a){return a&&parseInt(a,10)}),ib(a)}}function ob(a){var b=new r(db(pb(a)));
+// Adding is smart enough around DST
+return b._nextDay&&(b.add(1,"d"),b._nextDay=void 0),b}function pb(a){var b=a._i,d=a._f;return a._locale=a._locale||bb(a._l),null===b||void 0===d&&""===b?o({nullInput:!0}):("string"==typeof b&&(a._i=b=a._locale.preparse(b)),s(b)?new r(db(b)):(g(b)?a._d=b:c(d)?mb(a):d?kb(a):qb(a),n(a)||(a._d=null),a))}function qb(b){var d=b._i;void 0===d?b._d=new Date(a.now()):g(d)?b._d=new Date(d.valueOf()):"string"==typeof d?fb(b):c(d)?(b._a=h(d.slice(0),function(a){return parseInt(a,10)}),ib(b)):"object"==typeof d?nb(b):f(d)?
+// from milliseconds
+b._d=new Date(d):a.createFromInputFallback(b)}function rb(a,b,f,g,h){var i={};
+// object construction must be done this way.
+// https://github.com/moment/moment/issues/1423
+return f!==!0&&f!==!1||(g=f,f=void 0),(d(a)&&e(a)||c(a)&&0===a.length)&&(a=void 0),i._isAMomentObject=!0,i._useUTC=i._isUTC=h,i._l=f,i._i=a,i._f=b,i._strict=g,ob(i)}function sb(a,b,c,d){return rb(a,b,c,d,!1)}
+// Pick a moment m from moments so that m[fn](other) is true for all
+// other. This relies on the function fn to be transitive.
+//
+// moments should either be an array of moment objects or an array, whose
+// first element is an array of moment objects.
+function tb(a,b){var d,e;if(1===b.length&&c(b[0])&&(b=b[0]),!b.length)return sb();for(d=b[0],e=1;e<b.length;++e)b[e].isValid()&&!b[e][a](d)||(d=b[e]);return d}
+// TODO: Use [].sort instead?
+function ub(){var a=[].slice.call(arguments,0);return tb("isBefore",a)}function vb(){var a=[].slice.call(arguments,0);return tb("isAfter",a)}function wb(a){var b=L(a),c=b.year||0,d=b.quarter||0,e=b.month||0,f=b.week||0,g=b.day||0,h=b.hour||0,i=b.minute||0,j=b.second||0,k=b.millisecond||0;
+// representation for dateAddRemove
+this._milliseconds=+k+1e3*j+// 1000
+6e4*i+// 1000 * 60
+1e3*h*60*60,//using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
+// Because of dateAddRemove treats 24 hours as different from a
+// day when working around DST, we need to store them separately
+this._days=+g+7*f,
+// It is impossible translate months into days without knowing
+// which months you are are talking about, so we have to store
+// it separately.
+this._months=+e+3*d+12*c,this._data={},this._locale=bb(),this._bubble()}function xb(a){return a instanceof wb}function yb(a){return a<0?Math.round(-1*a)*-1:Math.round(a)}
+// FORMATTING
+function zb(a,b){U(a,0,0,function(){var a=this.utcOffset(),c="+";return a<0&&(a=-a,c="-"),c+T(~~(a/60),2)+b+T(~~a%60,2)})}function Ab(a,b){var c=(b||"").match(a);if(null===c)return null;var d=c[c.length-1]||[],e=(d+"").match(Kf)||["-",0,0],f=+(60*e[1])+u(e[2]);return 0===f?0:"+"===e[0]?f:-f}
+// Return a moment from input, that is local/utc/zone equivalent to model.
+function Bb(b,c){var d,e;
+// Use low-level api, because this fn is low-level api.
+return c._isUTC?(d=c.clone(),e=(s(b)||g(b)?b.valueOf():sb(b).valueOf())-d.valueOf(),d._d.setTime(d._d.valueOf()+e),a.updateOffset(d,!1),d):sb(b).local()}function Cb(a){
+// On Firefox.24 Date#getTimezoneOffset returns a floating point.
+// https://github.com/moment/moment/pull/1871
+return 15*-Math.round(a._d.getTimezoneOffset()/15)}
+// MOMENTS
+// keepLocalTime = true means only change the timezone, without
+// affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
+// 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
+// +0200, so we adjust the time as needed, to be valid.
+//
+// Keeping the time actually adds/subtracts (one hour)
+// from the actual represented time. That is why we call updateOffset
+// a second time. In case it wants us to change the offset again
+// _changeInProgress == true case, then we have to adjust, because
+// there is no such time in the given timezone.
+function Db(b,c){var d,e=this._offset||0;if(!this.isValid())return null!=b?this:NaN;if(null!=b){if("string"==typeof b){if(b=Ab(Ue,b),null===b)return this}else Math.abs(b)<16&&(b=60*b);return!this._isUTC&&c&&(d=Cb(this)),this._offset=b,this._isUTC=!0,null!=d&&this.add(d,"m"),e!==b&&(!c||this._changeInProgress?Tb(this,Ob(b-e,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,a.updateOffset(this,!0),this._changeInProgress=null)),this}return this._isUTC?e:Cb(this)}function Eb(a,b){return null!=a?("string"!=typeof a&&(a=-a),this.utcOffset(a,b),this):-this.utcOffset()}function Fb(a){return this.utcOffset(0,a)}function Gb(a){return this._isUTC&&(this.utcOffset(0,a),this._isUTC=!1,a&&this.subtract(Cb(this),"m")),this}function Hb(){if(null!=this._tzm)this.utcOffset(this._tzm);else if("string"==typeof this._i){var a=Ab(Te,this._i);null!=a?this.utcOffset(a):this.utcOffset(0,!0)}return this}function Ib(a){return!!this.isValid()&&(a=a?sb(a).utcOffset():0,(this.utcOffset()-a)%60===0)}function Jb(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function Kb(){if(!p(this._isDSTShifted))return this._isDSTShifted;var a={};if(q(a,this),a=pb(a),a._a){var b=a._isUTC?k(a._a):sb(a._a);this._isDSTShifted=this.isValid()&&v(a._a,b.toArray())>0}else this._isDSTShifted=!1;return this._isDSTShifted}function Lb(){return!!this.isValid()&&!this._isUTC}function Mb(){return!!this.isValid()&&this._isUTC}function Nb(){return!!this.isValid()&&(this._isUTC&&0===this._offset)}function Ob(a,b){var c,d,e,g=a,
+// matching against regexp is expensive, do it on demand
+h=null;// checks for null or undefined
+return xb(a)?g={ms:a._milliseconds,d:a._days,M:a._months}:f(a)?(g={},b?g[b]=a:g.milliseconds=a):(h=Lf.exec(a))?(c="-"===h[1]?-1:1,g={y:0,d:u(h[_e])*c,h:u(h[af])*c,m:u(h[bf])*c,s:u(h[cf])*c,ms:u(yb(1e3*h[df]))*c}):(h=Mf.exec(a))?(c="-"===h[1]?-1:1,g={y:Pb(h[2],c),M:Pb(h[3],c),w:Pb(h[4],c),d:Pb(h[5],c),h:Pb(h[6],c),m:Pb(h[7],c),s:Pb(h[8],c)}):null==g?g={}:"object"==typeof g&&("from"in g||"to"in g)&&(e=Rb(sb(g.from),sb(g.to)),g={},g.ms=e.milliseconds,g.M=e.months),d=new wb(g),xb(a)&&i(a,"_locale")&&(d._locale=a._locale),d}function Pb(a,b){
+// We'd normally use ~~inp for this, but unfortunately it also
+// converts floats to ints.
+// inp may be undefined, so careful calling replace on it.
+var c=a&&parseFloat(a.replace(",","."));
+// apply sign while we're at it
+return(isNaN(c)?0:c)*b}function Qb(a,b){var c={milliseconds:0,months:0};return c.months=b.month()-a.month()+12*(b.year()-a.year()),a.clone().add(c.months,"M").isAfter(b)&&--c.months,c.milliseconds=+b-+a.clone().add(c.months,"M"),c}function Rb(a,b){var c;return a.isValid()&&b.isValid()?(b=Bb(b,a),a.isBefore(b)?c=Qb(a,b):(c=Qb(b,a),c.milliseconds=-c.milliseconds,c.months=-c.months),c):{milliseconds:0,months:0}}
+// TODO: remove 'name' arg after deprecation is removed
+function Sb(a,b){return function(c,d){var e,f;
+//invert the arguments, but complain about it
+return null===d||isNaN(+d)||(y(b,"moment()."+b+"(period, number) is deprecated. Please use moment()."+b+"(number, period). See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info."),f=c,c=d,d=f),c="string"==typeof c?+c:c,e=Ob(c,d),Tb(this,e,a),this}}function Tb(b,c,d,e){var f=c._milliseconds,g=yb(c._days),h=yb(c._months);b.isValid()&&(e=null==e||e,f&&b._d.setTime(b._d.valueOf()+f*d),g&&Q(b,"Date",P(b,"Date")+g*d),h&&ja(b,P(b,"Month")+h*d),e&&a.updateOffset(b,g||h))}function Ub(a,b){var c=a.diff(b,"days",!0);return c<-6?"sameElse":c<-1?"lastWeek":c<0?"lastDay":c<1?"sameDay":c<2?"nextDay":c<7?"nextWeek":"sameElse"}function Vb(b,c){
+// We want to compare the start of today, vs this.
+// Getting start-of-today depends on whether we're local/utc/offset or not.
+var d=b||sb(),e=Bb(d,this).startOf("day"),f=a.calendarFormat(this,e)||"sameElse",g=c&&(z(c[f])?c[f].call(this,d):c[f]);return this.format(g||this.localeData().calendar(f,this,sb(d)))}function Wb(){return new r(this)}function Xb(a,b){var c=s(a)?a:sb(a);return!(!this.isValid()||!c.isValid())&&(b=K(p(b)?"millisecond":b),"millisecond"===b?this.valueOf()>c.valueOf():c.valueOf()<this.clone().startOf(b).valueOf())}function Yb(a,b){var c=s(a)?a:sb(a);return!(!this.isValid()||!c.isValid())&&(b=K(p(b)?"millisecond":b),"millisecond"===b?this.valueOf()<c.valueOf():this.clone().endOf(b).valueOf()<c.valueOf())}function Zb(a,b,c,d){return d=d||"()",("("===d[0]?this.isAfter(a,c):!this.isBefore(a,c))&&(")"===d[1]?this.isBefore(b,c):!this.isAfter(b,c))}function $b(a,b){var c,d=s(a)?a:sb(a);return!(!this.isValid()||!d.isValid())&&(b=K(b||"millisecond"),"millisecond"===b?this.valueOf()===d.valueOf():(c=d.valueOf(),this.clone().startOf(b).valueOf()<=c&&c<=this.clone().endOf(b).valueOf()))}function _b(a,b){return this.isSame(a,b)||this.isAfter(a,b)}function ac(a,b){return this.isSame(a,b)||this.isBefore(a,b)}function bc(a,b,c){var d,e,f,g;// 1000
+// 1000 * 60
+// 1000 * 60 * 60
+// 1000 * 60 * 60 * 24, negate dst
+// 1000 * 60 * 60 * 24 * 7, negate dst
+return this.isValid()?(d=Bb(a,this),d.isValid()?(e=6e4*(d.utcOffset()-this.utcOffset()),b=K(b),"year"===b||"month"===b||"quarter"===b?(g=cc(this,d),"quarter"===b?g/=3:"year"===b&&(g/=12)):(f=this-d,g="second"===b?f/1e3:"minute"===b?f/6e4:"hour"===b?f/36e5:"day"===b?(f-e)/864e5:"week"===b?(f-e)/6048e5:f),c?g:t(g)):NaN):NaN}function cc(a,b){
+// difference in months
+var c,d,e=12*(b.year()-a.year())+(b.month()-a.month()),
+// b is in (anchor - 1 month, anchor + 1 month)
+f=a.clone().add(e,"months");
+//check for negative zero, return zero if negative zero
+// linear across the month
+// linear across the month
+return b-f<0?(c=a.clone().add(e-1,"months"),d=(b-f)/(f-c)):(c=a.clone().add(e+1,"months"),d=(b-f)/(c-f)),-(e+d)||0}function dc(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")}function ec(){var a=this.clone().utc();return 0<a.year()&&a.year()<=9999?z(Date.prototype.toISOString)?this.toDate().toISOString():X(a,"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]"):X(a,"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]")}/**
+ * Return a human readable representation of a moment that can
+ * also be evaluated to get a new moment which is the same
+ *
+ * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects
+ */
+function fc(){if(!this.isValid())return"moment.invalid(/* "+this._i+" */)";var a="moment",b="";this.isLocal()||(a=0===this.utcOffset()?"moment.utc":"moment.parseZone",b="Z");var c="["+a+'("]',d=0<this.year()&&this.year()<=9999?"YYYY":"YYYYYY",e="-MM-DD[T]HH:mm:ss.SSS",f=b+'[")]';return this.format(c+d+e+f)}function gc(b){b||(b=this.isUtc()?a.defaultFormatUtc:a.defaultFormat);var c=X(this,b);return this.localeData().postformat(c)}function hc(a,b){return this.isValid()&&(s(a)&&a.isValid()||sb(a).isValid())?Ob({to:this,from:a}).locale(this.locale()).humanize(!b):this.localeData().invalidDate()}function ic(a){return this.from(sb(),a)}function jc(a,b){return this.isValid()&&(s(a)&&a.isValid()||sb(a).isValid())?Ob({from:this,to:a}).locale(this.locale()).humanize(!b):this.localeData().invalidDate()}function kc(a){return this.to(sb(),a)}
+// If passed a locale key, it will set the locale for this
+// instance.  Otherwise, it will return the locale configuration
+// variables for this instance.
+function lc(a){var b;return void 0===a?this._locale._abbr:(b=bb(a),null!=b&&(this._locale=b),this)}function mc(){return this._locale}function nc(a){
+// the following switch intentionally omits break keywords
+// to utilize falling through the cases.
+switch(a=K(a)){case"year":this.month(0);/* falls through */
+case"quarter":case"month":this.date(1);/* falls through */
+case"week":case"isoWeek":case"day":case"date":this.hours(0);/* falls through */
+case"hour":this.minutes(0);/* falls through */
+case"minute":this.seconds(0);/* falls through */
+case"second":this.milliseconds(0)}
+// weeks are a special case
+// quarters are also special
+return"week"===a&&this.weekday(0),"isoWeek"===a&&this.isoWeekday(1),"quarter"===a&&this.month(3*Math.floor(this.month()/3)),this}function oc(a){
+// 'date' is an alias for 'day', so it should be considered as such.
+return a=K(a),void 0===a||"millisecond"===a?this:("date"===a&&(a="day"),this.startOf(a).add(1,"isoWeek"===a?"week":a).subtract(1,"ms"))}function pc(){return this._d.valueOf()-6e4*(this._offset||0)}function qc(){return Math.floor(this.valueOf()/1e3)}function rc(){return new Date(this.valueOf())}function sc(){var a=this;return[a.year(),a.month(),a.date(),a.hour(),a.minute(),a.second(),a.millisecond()]}function tc(){var a=this;return{years:a.year(),months:a.month(),date:a.date(),hours:a.hours(),minutes:a.minutes(),seconds:a.seconds(),milliseconds:a.milliseconds()}}function uc(){
+// new Date(NaN).toJSON() === null
+return this.isValid()?this.toISOString():null}function vc(){return n(this)}function wc(){return j({},m(this))}function xc(){return m(this).overflow}function yc(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}}function zc(a,b){U(0,[a,a.length],0,b)}
+// MOMENTS
+function Ac(a){return Ec.call(this,a,this.week(),this.weekday(),this.localeData()._week.dow,this.localeData()._week.doy)}function Bc(a){return Ec.call(this,a,this.isoWeek(),this.isoWeekday(),1,4)}function Cc(){return xa(this.year(),1,4)}function Dc(){var a=this.localeData()._week;return xa(this.year(),a.dow,a.doy)}function Ec(a,b,c,d,e){var f;return null==a?wa(this,d,e).year:(f=xa(a,d,e),b>f&&(b=f),Fc.call(this,a,b,c,d,e))}function Fc(a,b,c,d,e){var f=va(a,b,c,d,e),g=ta(f.year,0,f.dayOfYear);return this.year(g.getUTCFullYear()),this.month(g.getUTCMonth()),this.date(g.getUTCDate()),this}
+// MOMENTS
+function Gc(a){return null==a?Math.ceil((this.month()+1)/3):this.month(3*(a-1)+this.month()%3)}
+// HELPERS
+// MOMENTS
+function Hc(a){var b=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==a?b:this.add(a-b,"d")}function Ic(a,b){b[df]=u(1e3*("0."+a))}
+// MOMENTS
+function Jc(){return this._isUTC?"UTC":""}function Kc(){return this._isUTC?"Coordinated Universal Time":""}function Lc(a){return sb(1e3*a)}function Mc(){return sb.apply(null,arguments).parseZone()}function Nc(a){return a}function Oc(a,b,c,d){var e=bb(),f=k().set(d,b);return e[c](f,a)}function Pc(a,b,c){if(f(a)&&(b=a,a=void 0),a=a||"",null!=b)return Oc(a,b,c,"month");var d,e=[];for(d=0;d<12;d++)e[d]=Oc(a,d,c,"month");return e}
+// ()
+// (5)
+// (fmt, 5)
+// (fmt)
+// (true)
+// (true, 5)
+// (true, fmt, 5)
+// (true, fmt)
+function Qc(a,b,c,d){"boolean"==typeof a?(f(b)&&(c=b,b=void 0),b=b||""):(b=a,c=b,a=!1,f(b)&&(c=b,b=void 0),b=b||"");var e=bb(),g=a?e._week.dow:0;if(null!=c)return Oc(b,(c+g)%7,d,"day");var h,i=[];for(h=0;h<7;h++)i[h]=Oc(b,(h+g)%7,d,"day");return i}function Rc(a,b){return Pc(a,b,"months")}function Sc(a,b){return Pc(a,b,"monthsShort")}function Tc(a,b,c){return Qc(a,b,c,"weekdays")}function Uc(a,b,c){return Qc(a,b,c,"weekdaysShort")}function Vc(a,b,c){return Qc(a,b,c,"weekdaysMin")}function Wc(){var a=this._data;return this._milliseconds=Xf(this._milliseconds),this._days=Xf(this._days),this._months=Xf(this._months),a.milliseconds=Xf(a.milliseconds),a.seconds=Xf(a.seconds),a.minutes=Xf(a.minutes),a.hours=Xf(a.hours),a.months=Xf(a.months),a.years=Xf(a.years),this}function Xc(a,b,c,d){var e=Ob(b,c);return a._milliseconds+=d*e._milliseconds,a._days+=d*e._days,a._months+=d*e._months,a._bubble()}
+// supports only 2.0-style add(1, 's') or add(duration)
+function Yc(a,b){return Xc(this,a,b,1)}
+// supports only 2.0-style subtract(1, 's') or subtract(duration)
+function Zc(a,b){return Xc(this,a,b,-1)}function $c(a){return a<0?Math.floor(a):Math.ceil(a)}function _c(){var a,b,c,d,e,f=this._milliseconds,g=this._days,h=this._months,i=this._data;
+// if we have a mix of positive and negative values, bubble down first
+// check: https://github.com/moment/moment/issues/2166
+// The following code bubbles up values, see the tests for
+// examples of what that means.
+// convert days to months
+// 12 months -> 1 year
+return f>=0&&g>=0&&h>=0||f<=0&&g<=0&&h<=0||(f+=864e5*$c(bd(h)+g),g=0,h=0),i.milliseconds=f%1e3,a=t(f/1e3),i.seconds=a%60,b=t(a/60),i.minutes=b%60,c=t(b/60),i.hours=c%24,g+=t(c/24),e=t(ad(g)),h+=e,g-=$c(bd(e)),d=t(h/12),h%=12,i.days=g,i.months=h,i.years=d,this}function ad(a){
+// 400 years have 146097 days (taking into account leap year rules)
+// 400 years have 12 months === 4800
+return 4800*a/146097}function bd(a){
+// the reverse of daysToMonths
+return 146097*a/4800}function cd(a){var b,c,d=this._milliseconds;if(a=K(a),"month"===a||"year"===a)return b=this._days+d/864e5,c=this._months+ad(b),"month"===a?c:c/12;switch(
+// handle milliseconds separately because of floating point math errors (issue #1867)
+b=this._days+Math.round(bd(this._months)),a){case"week":return b/7+d/6048e5;case"day":return b+d/864e5;case"hour":return 24*b+d/36e5;case"minute":return 1440*b+d/6e4;case"second":return 86400*b+d/1e3;
+// Math.floor prevents floating point math errors here
+case"millisecond":return Math.floor(864e5*b)+d;default:throw new Error("Unknown unit "+a)}}
+// TODO: Use this.as('ms')?
+function dd(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*u(this._months/12)}function ed(a){return function(){return this.as(a)}}function fd(a){return a=K(a),this[a+"s"]()}function gd(a){return function(){return this._data[a]}}function hd(){return t(this.days()/7)}
+// helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
+function id(a,b,c,d,e){return e.relativeTime(b||1,!!c,a,d)}function jd(a,b,c){var d=Ob(a).abs(),e=lg(d.as("s")),f=lg(d.as("m")),g=lg(d.as("h")),h=lg(d.as("d")),i=lg(d.as("M")),j=lg(d.as("y")),k=e<mg.s&&["s",e]||f<=1&&["m"]||f<mg.m&&["mm",f]||g<=1&&["h"]||g<mg.h&&["hh",g]||h<=1&&["d"]||h<mg.d&&["dd",h]||i<=1&&["M"]||i<mg.M&&["MM",i]||j<=1&&["y"]||["yy",j];return k[2]=b,k[3]=+a>0,k[4]=c,id.apply(null,k)}
+// This function allows you to set the rounding function for relative time strings
+function kd(a){return void 0===a?lg:"function"==typeof a&&(lg=a,!0)}
+// This function allows you to set a threshold for relative time strings
+function ld(a,b){return void 0!==mg[a]&&(void 0===b?mg[a]:(mg[a]=b,!0))}function md(a){var b=this.localeData(),c=jd(this,!a,b);return a&&(c=b.pastFuture(+this,c)),b.postformat(c)}function nd(){
+// for ISO strings we do not use the normal bubbling rules:
+//  * milliseconds bubble up until they become hours
+//  * days do not bubble at all
+//  * months bubble up until they become years
+// This is because there is no context-free conversion between hours and days
+// (think of clock changes)
+// and also not between days and months (28-31 days per month)
+var a,b,c,d=ng(this._milliseconds)/1e3,e=ng(this._days),f=ng(this._months);
+// 3600 seconds -> 60 minutes -> 1 hour
+a=t(d/60),b=t(a/60),d%=60,a%=60,
+// 12 months -> 1 year
+c=t(f/12),f%=12;
+// inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
+var g=c,h=f,i=e,j=b,k=a,l=d,m=this.asSeconds();return m?(m<0?"-":"")+"P"+(g?g+"Y":"")+(h?h+"M":"")+(i?i+"D":"")+(j||k||l?"T":"")+(j?j+"H":"")+(k?k+"M":"")+(l?l+"S":""):"P0D"}
+//! moment.js locale configuration
+//! locale : Belarusian [be]
+//! author : Dmitry Demidov : https://github.com/demidov91
+//! author: Praleska: http://praleska.pro/
+//! Author : Menelion Elensúle : https://github.com/Oire
+function od(a,b){var c=a.split("_");return b%10===1&&b%100!==11?c[0]:b%10>=2&&b%10<=4&&(b%100<10||b%100>=20)?c[1]:c[2]}function pd(a,b,c){var d={mm:b?"хвіліна_хвіліны_хвілін":"хвіліну_хвіліны_хвілін",hh:b?"гадзіна_гадзіны_гадзін":"гадзіну_гадзіны_гадзін",dd:"дзень_дні_дзён",MM:"месяц_месяцы_месяцаў",yy:"год_гады_гадоў"};return"m"===c?b?"хвіліна":"хвіліну":"h"===c?b?"гадзіна":"гадзіну":a+" "+od(d[c],+a)}
+//! moment.js locale configuration
+//! locale : Breton [br]
+//! author : Jean-Baptiste Le Duigou : https://github.com/jbleduigou
+function qd(a,b,c){var d={mm:"munutenn",MM:"miz",dd:"devezh"};return a+" "+td(d[c],a)}function rd(a){switch(sd(a)){case 1:case 3:case 4:case 5:case 9:return a+" bloaz";default:return a+" vloaz"}}function sd(a){return a>9?sd(a%10):a}function td(a,b){return 2===b?ud(a):a}function ud(a){var b={m:"v",b:"v",d:"z"};return void 0===b[a.charAt(0)]?a:b[a.charAt(0)]+a.substring(1)}
+//! moment.js locale configuration
+//! locale : Bosnian [bs]
+//! author : Nedim Cholich : https://github.com/frontyard
+//! based on (hr) translation by Bojan Marković
+function vd(a,b,c){var d=a+" ";switch(c){case"m":return b?"jedna minuta":"jedne minute";case"mm":return d+=1===a?"minuta":2===a||3===a||4===a?"minute":"minuta";case"h":return b?"jedan sat":"jednog sata";case"hh":return d+=1===a?"sat":2===a||3===a||4===a?"sata":"sati";case"dd":return d+=1===a?"dan":"dana";case"MM":return d+=1===a?"mjesec":2===a||3===a||4===a?"mjeseca":"mjeseci";case"yy":return d+=1===a?"godina":2===a||3===a||4===a?"godine":"godina"}}function wd(a){return a>1&&a<5&&1!==~~(a/10)}function xd(a,b,c,d){var e=a+" ";switch(c){case"s":// a few seconds / in a few seconds / a few seconds ago
+return b||d?"pár sekund":"pár sekundami";case"m":// a minute / in a minute / a minute ago
+return b?"minuta":d?"minutu":"minutou";case"mm":// 9 minutes / in 9 minutes / 9 minutes ago
+// 9 minutes / in 9 minutes / 9 minutes ago
+return b||d?e+(wd(a)?"minuty":"minut"):e+"minutami";break;case"h":// an hour / in an hour / an hour ago
+return b?"hodina":d?"hodinu":"hodinou";case"hh":// 9 hours / in 9 hours / 9 hours ago
+// 9 hours / in 9 hours / 9 hours ago
+return b||d?e+(wd(a)?"hodiny":"hodin"):e+"hodinami";break;case"d":// a day / in a day / a day ago
+return b||d?"den":"dnem";case"dd":// 9 days / in 9 days / 9 days ago
+// 9 days / in 9 days / 9 days ago
+return b||d?e+(wd(a)?"dny":"dní"):e+"dny";break;case"M":// a month / in a month / a month ago
+return b||d?"měsíc":"měsícem";case"MM":// 9 months / in 9 months / 9 months ago
+// 9 months / in 9 months / 9 months ago
+return b||d?e+(wd(a)?"měsíce":"měsíců"):e+"měsíci";break;case"y":// a year / in a year / a year ago
+return b||d?"rok":"rokem";case"yy":// 9 years / in 9 years / 9 years ago
+// 9 years / in 9 years / 9 years ago
+return b||d?e+(wd(a)?"roky":"let"):e+"lety"}}
+//! moment.js locale configuration
+//! locale : German (Austria) [de-at]
+//! author : lluchs : https://github.com/lluchs
+//! author: Menelion Elensúle: https://github.com/Oire
+//! author : Martin Groller : https://github.com/MadMG
+//! author : Mikolaj Dadela : https://github.com/mik01aj
+function yd(a,b,c,d){var e={m:["eine Minute","einer Minute"],h:["eine Stunde","einer Stunde"],d:["ein Tag","einem Tag"],dd:[a+" Tage",a+" Tagen"],M:["ein Monat","einem Monat"],MM:[a+" Monate",a+" Monaten"],y:["ein Jahr","einem Jahr"],yy:[a+" Jahre",a+" Jahren"]};return b?e[c][0]:e[c][1]}
+//! moment.js locale configuration
+//! locale : German [de]
+//! author : lluchs : https://github.com/lluchs
+//! author: Menelion Elensúle: https://github.com/Oire
+//! author : Mikolaj Dadela : https://github.com/mik01aj
+function zd(a,b,c,d){var e={m:["eine Minute","einer Minute"],h:["eine Stunde","einer Stunde"],d:["ein Tag","einem Tag"],dd:[a+" Tage",a+" Tagen"],M:["ein Monat","einem Monat"],MM:[a+" Monate",a+" Monaten"],y:["ein Jahr","einem Jahr"],yy:[a+" Jahre",a+" Jahren"]};return b?e[c][0]:e[c][1]}
+//! moment.js locale configuration
+//! locale : Estonian [et]
+//! author : Henry Kehlmann : https://github.com/madhenry
+//! improvements : Illimar Tambek : https://github.com/ragulka
+function Ad(a,b,c,d){var e={s:["mõne sekundi","mõni sekund","paar sekundit"],m:["ühe minuti","üks minut"],mm:[a+" minuti",a+" minutit"],h:["ühe tunni","tund aega","üks tund"],hh:[a+" tunni",a+" tundi"],d:["ühe päeva","üks päev"],M:["kuu aja","kuu aega","üks kuu"],MM:[a+" kuu",a+" kuud"],y:["ühe aasta","aasta","üks aasta"],yy:[a+" aasta",a+" aastat"]};return b?e[c][2]?e[c][2]:e[c][1]:d?e[c][0]:e[c][1]}function Bd(a,b,c,d){var e="";switch(c){case"s":return d?"muutaman sekunnin":"muutama sekunti";case"m":return d?"minuutin":"minuutti";case"mm":e=d?"minuutin":"minuuttia";break;case"h":return d?"tunnin":"tunti";case"hh":e=d?"tunnin":"tuntia";break;case"d":return d?"päivän":"päivä";case"dd":e=d?"päivän":"päivää";break;case"M":return d?"kuukauden":"kuukausi";case"MM":e=d?"kuukauden":"kuukautta";break;case"y":return d?"vuoden":"vuosi";case"yy":e=d?"vuoden":"vuotta"}return e=Cd(a,d)+" "+e}function Cd(a,b){return a<10?b?Sg[a]:Rg[a]:a}
+//! moment.js locale configuration
+//! locale : Croatian [hr]
+//! author : Bojan Marković : https://github.com/bmarkovic
+function Dd(a,b,c){var d=a+" ";switch(c){case"m":return b?"jedna minuta":"jedne minute";case"mm":return d+=1===a?"minuta":2===a||3===a||4===a?"minute":"minuta";case"h":return b?"jedan sat":"jednog sata";case"hh":return d+=1===a?"sat":2===a||3===a||4===a?"sata":"sati";case"dd":return d+=1===a?"dan":"dana";case"MM":return d+=1===a?"mjesec":2===a||3===a||4===a?"mjeseca":"mjeseci";case"yy":return d+=1===a?"godina":2===a||3===a||4===a?"godine":"godina"}}function Ed(a,b,c,d){var e=a;switch(c){case"s":return d||b?"néhány másodperc":"néhány másodperce";case"m":return"egy"+(d||b?" perc":" perce");case"mm":return e+(d||b?" perc":" perce");case"h":return"egy"+(d||b?" óra":" órája");case"hh":return e+(d||b?" óra":" órája");case"d":return"egy"+(d||b?" nap":" napja");case"dd":return e+(d||b?" nap":" napja");case"M":return"egy"+(d||b?" hónap":" hónapja");case"MM":return e+(d||b?" hónap":" hónapja");case"y":return"egy"+(d||b?" év":" éve");case"yy":return e+(d||b?" év":" éve")}return""}function Fd(a){return(a?"":"[múlt] ")+"["+ah[this.day()]+"] LT[-kor]"}
+//! moment.js locale configuration
+//! locale : Icelandic [is]
+//! author : Hinrik Örn Sigurðsson : https://github.com/hinrik
+function Gd(a){return a%100===11||a%10!==1}function Hd(a,b,c,d){var e=a+" ";switch(c){case"s":return b||d?"nokkrar sekúndur":"nokkrum sekúndum";case"m":return b?"mínúta":"mínútu";case"mm":return Gd(a)?e+(b||d?"mínútur":"mínútum"):b?e+"mínúta":e+"mínútu";case"hh":return Gd(a)?e+(b||d?"klukkustundir":"klukkustundum"):e+"klukkustund";case"d":return b?"dagur":d?"dag":"degi";case"dd":return Gd(a)?b?e+"dagar":e+(d?"daga":"dögum"):b?e+"dagur":e+(d?"dag":"degi");case"M":return b?"mánuður":d?"mánuð":"mánuði";case"MM":return Gd(a)?b?e+"mánuðir":e+(d?"mánuði":"mánuðum"):b?e+"mánuður":e+(d?"mánuð":"mánuði");case"y":return b||d?"ár":"ári";case"yy":return Gd(a)?e+(b||d?"ár":"árum"):e+(b||d?"ár":"ári")}}
+//! moment.js locale configuration
+//! locale : Luxembourgish [lb]
+//! author : mweimerskirch : https://github.com/mweimerskirch
+//! author : David Raison : https://github.com/kwisatz
+function Id(a,b,c,d){var e={m:["eng Minutt","enger Minutt"],h:["eng Stonn","enger Stonn"],d:["een Dag","engem Dag"],M:["ee Mount","engem Mount"],y:["ee Joer","engem Joer"]};return b?e[c][0]:e[c][1]}function Jd(a){var b=a.substr(0,a.indexOf(" "));return Ld(b)?"a "+a:"an "+a}function Kd(a){var b=a.substr(0,a.indexOf(" "));return Ld(b)?"viru "+a:"virun "+a}/**
+ * Returns true if the word before the given number loses the '-n' ending.
+ * e.g. 'an 10 Deeg' but 'a 5 Deeg'
+ *
+ * @param number {integer}
+ * @returns {boolean}
+ */
+function Ld(a){if(a=parseInt(a,10),isNaN(a))return!1;if(a<0)
+// Negative Number --> always true
+return!0;if(a<10)
+// Only 1 digit
+return 4<=a&&a<=7;if(a<100){
+// 2 digits
+var b=a%10,c=a/10;return Ld(0===b?c:b)}if(a<1e4){
+// 3 or 4 digits --> recursively check first digit
+for(;a>=10;)a/=10;return Ld(a)}
+// Anything larger than 4 digits: recursively check first n-3 digits
+return a/=1e3,Ld(a)}function Md(a,b,c,d){return b?"kelios sekundės":d?"kelių sekundžių":"kelias sekundes"}function Nd(a,b,c,d){return b?Pd(c)[0]:d?Pd(c)[1]:Pd(c)[2]}function Od(a){return a%10===0||a>10&&a<20}function Pd(a){return dh[a].split("_")}function Qd(a,b,c,d){var e=a+" ";return 1===a?e+Nd(a,b,c[0],d):b?e+(Od(a)?Pd(c)[1]:Pd(c)[0]):d?e+Pd(c)[1]:e+(Od(a)?Pd(c)[1]:Pd(c)[2])}/**
+ * @param withoutSuffix boolean true = a length of time; false = before/after a period of time.
+ */
+function Rd(a,b,c){return c?b%10===1&&b%100!==11?a[2]:a[3]:b%10===1&&b%100!==11?a[0]:a[1]}function Sd(a,b,c){return a+" "+Rd(eh[c],a,b)}function Td(a,b,c){return Rd(eh[c],a,b)}function Ud(a,b){return b?"dažas sekundes":"dažām sekundēm"}function Vd(a,b,c,d){var e="";if(b)switch(c){case"s":e="काही सेकंद";break;case"m":e="एक मिनिट";break;case"mm":e="%d मिनिटे";break;case"h":e="एक तास";break;case"hh":e="%d तास";break;case"d":e="एक दिवस";break;case"dd":e="%d दिवस";break;case"M":e="एक महिना";break;case"MM":e="%d महिने";break;case"y":e="एक वर्ष";break;case"yy":e="%d वर्षे"}else switch(c){case"s":e="काही सेकंदां";break;case"m":e="एका मिनिटा";break;case"mm":e="%d मिनिटां";break;case"h":e="एका तासा";break;case"hh":e="%d तासां";break;case"d":e="एका दिवसा";break;case"dd":e="%d दिवसां";break;case"M":e="एका महिन्या";break;case"MM":e="%d महिन्यां";break;case"y":e="एका वर्षा";break;case"yy":e="%d वर्षां"}return e.replace(/%d/i,a)}function Wd(a){return a%10<5&&a%10>1&&~~(a/10)%10!==1}function Xd(a,b,c){var d=a+" ";switch(c){case"m":return b?"minuta":"minutę";case"mm":return d+(Wd(a)?"minuty":"minut");case"h":return b?"godzina":"godzinę";case"hh":return d+(Wd(a)?"godziny":"godzin");case"MM":return d+(Wd(a)?"miesiące":"miesięcy");case"yy":return d+(Wd(a)?"lata":"lat")}}
+//! moment.js locale configuration
+//! locale : Romanian [ro]
+//! author : Vlad Gurdiga : https://github.com/gurdiga
+//! author : Valentin Agachi : https://github.com/avaly
+function Yd(a,b,c){var d={mm:"minute",hh:"ore",dd:"zile",MM:"luni",yy:"ani"},e=" ";return(a%100>=20||a>=100&&a%100===0)&&(e=" de "),a+e+d[c]}
+//! moment.js locale configuration
+//! locale : Russian [ru]
+//! author : Viktorminator : https://github.com/Viktorminator
+//! Author : Menelion Elensúle : https://github.com/Oire
+//! author : Коренберг Марк : https://github.com/socketpair
+function Zd(a,b){var c=a.split("_");return b%10===1&&b%100!==11?c[0]:b%10>=2&&b%10<=4&&(b%100<10||b%100>=20)?c[1]:c[2]}function $d(a,b,c){var d={mm:b?"минута_минуты_минут":"минуту_минуты_минут",hh:"час_часа_часов",dd:"день_дня_дней",MM:"месяц_месяца_месяцев",yy:"год_года_лет"};return"m"===c?b?"минута":"минуту":a+" "+Zd(d[c],+a)}function _d(a){return a>1&&a<5}function ae(a,b,c,d){var e=a+" ";switch(c){case"s":// a few seconds / in a few seconds / a few seconds ago
+return b||d?"pár sekúnd":"pár sekundami";case"m":// a minute / in a minute / a minute ago
+return b?"minúta":d?"minútu":"minútou";case"mm":// 9 minutes / in 9 minutes / 9 minutes ago
+// 9 minutes / in 9 minutes / 9 minutes ago
+return b||d?e+(_d(a)?"minúty":"minút"):e+"minútami";break;case"h":// an hour / in an hour / an hour ago
+return b?"hodina":d?"hodinu":"hodinou";case"hh":// 9 hours / in 9 hours / 9 hours ago
+// 9 hours / in 9 hours / 9 hours ago
+return b||d?e+(_d(a)?"hodiny":"hodín"):e+"hodinami";break;case"d":// a day / in a day / a day ago
+return b||d?"deň":"dňom";case"dd":// 9 days / in 9 days / 9 days ago
+// 9 days / in 9 days / 9 days ago
+return b||d?e+(_d(a)?"dni":"dní"):e+"dňami";break;case"M":// a month / in a month / a month ago
+return b||d?"mesiac":"mesiacom";case"MM":// 9 months / in 9 months / 9 months ago
+// 9 months / in 9 months / 9 months ago
+return b||d?e+(_d(a)?"mesiace":"mesiacov"):e+"mesiacmi";break;case"y":// a year / in a year / a year ago
+return b||d?"rok":"rokom";case"yy":// 9 years / in 9 years / 9 years ago
+// 9 years / in 9 years / 9 years ago
+return b||d?e+(_d(a)?"roky":"rokov"):e+"rokmi"}}
+//! moment.js locale configuration
+//! locale : Slovenian [sl]
+//! author : Robert Sedovšek : https://github.com/sedovsek
+function be(a,b,c,d){var e=a+" ";switch(c){case"s":return b||d?"nekaj sekund":"nekaj sekundami";case"m":return b?"ena minuta":"eno minuto";case"mm":return e+=1===a?b?"minuta":"minuto":2===a?b||d?"minuti":"minutama":a<5?b||d?"minute":"minutami":b||d?"minut":"minutami";case"h":return b?"ena ura":"eno uro";case"hh":return e+=1===a?b?"ura":"uro":2===a?b||d?"uri":"urama":a<5?b||d?"ure":"urami":b||d?"ur":"urami";case"d":return b||d?"en dan":"enim dnem";case"dd":return e+=1===a?b||d?"dan":"dnem":2===a?b||d?"dni":"dnevoma":b||d?"dni":"dnevi";case"M":return b||d?"en mesec":"enim mesecem";case"MM":return e+=1===a?b||d?"mesec":"mesecem":2===a?b||d?"meseca":"mesecema":a<5?b||d?"mesece":"meseci":b||d?"mesecev":"meseci";case"y":return b||d?"eno leto":"enim letom";case"yy":return e+=1===a?b||d?"leto":"letom":2===a?b||d?"leti":"letoma":a<5?b||d?"leta":"leti":b||d?"let":"leti"}}function ce(a){var b=a;return b=a.indexOf("jaj")!==-1?b.slice(0,-3)+"leS":a.indexOf("jar")!==-1?b.slice(0,-3)+"waQ":a.indexOf("DIS")!==-1?b.slice(0,-3)+"nem":b+" pIq"}function de(a){var b=a;return b=a.indexOf("jaj")!==-1?b.slice(0,-3)+"Hu’":a.indexOf("jar")!==-1?b.slice(0,-3)+"wen":a.indexOf("DIS")!==-1?b.slice(0,-3)+"ben":b+" ret"}function ee(a,b,c,d){var e=fe(a);switch(c){case"mm":return e+" tup";case"hh":return e+" rep";case"dd":return e+" jaj";case"MM":return e+" jar";case"yy":return e+" DIS"}}function fe(a){var b=Math.floor(a%1e3/100),c=Math.floor(a%100/10),d=a%10,e="";return b>0&&(e+=Fh[b]+"vatlh"),c>0&&(e+=(""!==e?" ":"")+Fh[c]+"maH"),d>0&&(e+=(""!==e?" ":"")+Fh[d]),""===e?"pagh":e}function ge(a,b,c,d){var e={s:["viensas secunds","'iensas secunds"],m:["'n míut","'iens míut"],mm:[a+" míuts",""+a+" míuts"],h:["'n þora","'iensa þora"],hh:[a+" þoras",""+a+" þoras"],d:["'n ziua","'iensa ziua"],dd:[a+" ziuas",""+a+" ziuas"],M:["'n mes","'iens mes"],MM:[a+" mesen",""+a+" mesen"],y:["'n ar","'iens ar"],yy:[a+" ars",""+a+" ars"]};return d?e[c][0]:b?e[c][0]:e[c][1]}
+//! moment.js locale configuration
+//! locale : Ukrainian [uk]
+//! author : zemlanin : https://github.com/zemlanin
+//! Author : Menelion Elensúle : https://github.com/Oire
+function he(a,b){var c=a.split("_");return b%10===1&&b%100!==11?c[0]:b%10>=2&&b%10<=4&&(b%100<10||b%100>=20)?c[1]:c[2]}function ie(a,b,c){var d={mm:b?"хвилина_хвилини_хвилин":"хвилину_хвилини_хвилин",hh:b?"година_години_годин":"годину_години_годин",dd:"день_дні_днів",MM:"місяць_місяці_місяців",yy:"рік_роки_років"};return"m"===c?b?"хвилина":"хвилину":"h"===c?b?"година":"годину":a+" "+he(d[c],+a)}function je(a,b){var c={nominative:"неділя_понеділок_вівторок_середа_четвер_п’ятниця_субота".split("_"),accusative:"неділю_понеділок_вівторок_середу_четвер_п’ятницю_суботу".split("_"),genitive:"неділі_понеділка_вівторка_середи_четверга_п’ятниці_суботи".split("_")},d=/(\[[ВвУу]\]) ?dddd/.test(b)?"accusative":/\[?(?:минулої|наступної)? ?\] ?dddd/.test(b)?"genitive":"nominative";return c[d][a.day()]}function ke(a){return function(){return a+"о"+(11===this.hours()?"б":"")+"] LT"}}var le,me;me=Array.prototype.some?Array.prototype.some:function(a){for(var b=Object(this),c=b.length>>>0,d=0;d<c;d++)if(d in b&&a.call(this,b[d],d,b))return!0;return!1};var ne=me,oe=a.momentProperties=[],pe=!1,qe={};a.suppressDeprecationWarnings=!1,a.deprecationHandler=null;var re;re=Object.keys?Object.keys:function(a){var b,c=[];for(b in a)i(a,b)&&c.push(b);return c};var se,te=re,ue={sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},ve={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},we="Invalid date",xe="%d",ye=/\d{1,2}/,ze={future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},Ae={},Be={},Ce=/(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,De=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,Ee={},Fe={},Ge=/\d/,He=/\d\d/,Ie=/\d{3}/,Je=/\d{4}/,Ke=/[+-]?\d{6}/,Le=/\d\d?/,Me=/\d\d\d\d?/,Ne=/\d\d\d\d\d\d?/,Oe=/\d{1,3}/,Pe=/\d{1,4}/,Qe=/[+-]?\d{1,6}/,Re=/\d+/,Se=/[+-]?\d+/,Te=/Z|[+-]\d\d:?\d\d/gi,Ue=/Z|[+-]\d\d(?::?\d\d)?/gi,Ve=/[+-]?\d+(\.\d{1,3})?/,We=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,Xe={},Ye={},Ze=0,$e=1,_e=2,af=3,bf=4,cf=5,df=6,ef=7,ff=8;se=Array.prototype.indexOf?Array.prototype.indexOf:function(a){
+// I know
+var b;for(b=0;b<this.length;++b)if(this[b]===a)return b;return-1};var gf=se;
+// FORMATTING
+U("M",["MM",2],"Mo",function(){return this.month()+1}),U("MMM",0,0,function(a){return this.localeData().monthsShort(this,a)}),U("MMMM",0,0,function(a){return this.localeData().months(this,a)}),
+// ALIASES
+J("month","M"),
+// PRIORITY
+M("month",8),
+// PARSING
+Z("M",Le),Z("MM",Le,He),Z("MMM",function(a,b){return b.monthsShortRegex(a)}),Z("MMMM",function(a,b){return b.monthsRegex(a)}),ba(["M","MM"],function(a,b){b[$e]=u(a)-1}),ba(["MMM","MMMM"],function(a,b,c,d){var e=c._locale.monthsParse(a,d,c._strict);
+// if we didn't find a month name, mark the date as invalid.
+null!=e?b[$e]=e:m(c).invalidMonth=a});
+// LOCALES
+var hf=/D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/,jf="January_February_March_April_May_June_July_August_September_October_November_December".split("_"),kf="Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),lf=We,mf=We;
+// FORMATTING
+U("Y",0,0,function(){var a=this.year();return a<=9999?""+a:"+"+a}),U(0,["YY",2],0,function(){return this.year()%100}),U(0,["YYYY",4],0,"year"),U(0,["YYYYY",5],0,"year"),U(0,["YYYYYY",6,!0],0,"year"),
+// ALIASES
+J("year","y"),
+// PRIORITIES
+M("year",1),
+// PARSING
+Z("Y",Se),Z("YY",Le,He),Z("YYYY",Pe,Je),Z("YYYYY",Qe,Ke),Z("YYYYYY",Qe,Ke),ba(["YYYYY","YYYYYY"],Ze),ba("YYYY",function(b,c){c[Ze]=2===b.length?a.parseTwoDigitYear(b):u(b)}),ba("YY",function(b,c){c[Ze]=a.parseTwoDigitYear(b)}),ba("Y",function(a,b){b[Ze]=parseInt(a,10)}),
+// HOOKS
+a.parseTwoDigitYear=function(a){return u(a)+(u(a)>68?1900:2e3)};
+// MOMENTS
+var nf=O("FullYear",!0);
+// FORMATTING
+U("w",["ww",2],"wo","week"),U("W",["WW",2],"Wo","isoWeek"),
+// ALIASES
+J("week","w"),J("isoWeek","W"),
+// PRIORITIES
+M("week",5),M("isoWeek",5),
+// PARSING
+Z("w",Le),Z("ww",Le,He),Z("W",Le),Z("WW",Le,He),ca(["w","ww","W","WW"],function(a,b,c,d){b[d.substr(0,1)]=u(a)});var of={dow:0,// Sunday is the first day of the week.
+doy:6};
+// FORMATTING
+U("d",0,"do","day"),U("dd",0,0,function(a){return this.localeData().weekdaysMin(this,a)}),U("ddd",0,0,function(a){return this.localeData().weekdaysShort(this,a)}),U("dddd",0,0,function(a){return this.localeData().weekdays(this,a)}),U("e",0,0,"weekday"),U("E",0,0,"isoWeekday"),
+// ALIASES
+J("day","d"),J("weekday","e"),J("isoWeekday","E"),
+// PRIORITY
+M("day",11),M("weekday",11),M("isoWeekday",11),
+// PARSING
+Z("d",Le),Z("e",Le),Z("E",Le),Z("dd",function(a,b){return b.weekdaysMinRegex(a)}),Z("ddd",function(a,b){return b.weekdaysShortRegex(a)}),Z("dddd",function(a,b){return b.weekdaysRegex(a)}),ca(["dd","ddd","dddd"],function(a,b,c,d){var e=c._locale.weekdaysParse(a,d,c._strict);
+// if we didn't get a weekday name, mark the date as invalid
+null!=e?b.d=e:m(c).invalidWeekday=a}),ca(["d","e","E"],function(a,b,c,d){b[d]=u(a)});
+// LOCALES
+var pf="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),qf="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),rf="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),sf=We,tf=We,uf=We;U("H",["HH",2],0,"hour"),U("h",["hh",2],0,Ra),U("k",["kk",2],0,Sa),U("hmm",0,0,function(){return""+Ra.apply(this)+T(this.minutes(),2)}),U("hmmss",0,0,function(){return""+Ra.apply(this)+T(this.minutes(),2)+T(this.seconds(),2)}),U("Hmm",0,0,function(){return""+this.hours()+T(this.minutes(),2)}),U("Hmmss",0,0,function(){return""+this.hours()+T(this.minutes(),2)+T(this.seconds(),2)}),Ta("a",!0),Ta("A",!1),
+// ALIASES
+J("hour","h"),
+// PRIORITY
+M("hour",13),Z("a",Ua),Z("A",Ua),Z("H",Le),Z("h",Le),Z("HH",Le,He),Z("hh",Le,He),Z("hmm",Me),Z("hmmss",Ne),Z("Hmm",Me),Z("Hmmss",Ne),ba(["H","HH"],af),ba(["a","A"],function(a,b,c){c._isPm=c._locale.isPM(a),c._meridiem=a}),ba(["h","hh"],function(a,b,c){b[af]=u(a),m(c).bigHour=!0}),ba("hmm",function(a,b,c){var d=a.length-2;b[af]=u(a.substr(0,d)),b[bf]=u(a.substr(d)),m(c).bigHour=!0}),ba("hmmss",function(a,b,c){var d=a.length-4,e=a.length-2;b[af]=u(a.substr(0,d)),b[bf]=u(a.substr(d,2)),b[cf]=u(a.substr(e)),m(c).bigHour=!0}),ba("Hmm",function(a,b,c){var d=a.length-2;b[af]=u(a.substr(0,d)),b[bf]=u(a.substr(d))}),ba("Hmmss",function(a,b,c){var d=a.length-4,e=a.length-2;b[af]=u(a.substr(0,d)),b[bf]=u(a.substr(d,2)),b[cf]=u(a.substr(e))});var vf,wf=/[ap]\.?m?\.?/i,xf=O("Hours",!0),yf={calendar:ue,longDateFormat:ve,invalidDate:we,ordinal:xe,ordinalParse:ye,relativeTime:ze,months:jf,monthsShort:kf,week:of,weekdays:pf,weekdaysMin:rf,weekdaysShort:qf,meridiemParse:wf},zf={},Af={},Bf=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Cf=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Df=/Z|[+-]\d\d(?::?\d\d)?/,Ef=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],
+// YYYYMM is NOT allowed by the standard
+["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/]],Ff=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],Gf=/^\/?Date\((\-?\d+)/i;a.createFromInputFallback=x("value provided is not in a recognized ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions. Non ISO date formats are discouraged and will be removed in an upcoming major release. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.",function(a){a._d=new Date(a._i+(a._useUTC?" UTC":""))}),
+// constant that refers to the ISO standard
+a.ISO_8601=function(){};var Hf=x("moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/",function(){var a=sb.apply(null,arguments);return this.isValid()&&a.isValid()?a<this?this:a:o()}),If=x("moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/",function(){var a=sb.apply(null,arguments);return this.isValid()&&a.isValid()?a>this?this:a:o()}),Jf=function(){return Date.now?Date.now():+new Date};zb("Z",":"),zb("ZZ",""),
+// PARSING
+Z("Z",Ue),Z("ZZ",Ue),ba(["Z","ZZ"],function(a,b,c){c._useUTC=!0,c._tzm=Ab(Ue,a)});
+// HELPERS
+// timezone chunker
+// '+10:00' > ['10',  '00']
+// '-1530'  > ['-15', '30']
+var Kf=/([\+\-]|\d\d)/gi;
+// HOOKS
+// This function will be called whenever a moment is mutated.
+// It is intended to keep the offset in sync with the timezone.
+a.updateOffset=function(){};
+// ASP.NET json date format regex
+var Lf=/^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/,Mf=/^(-)?P(?:(-?[0-9,.]*)Y)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)W)?(?:(-?[0-9,.]*)D)?(?:T(?:(-?[0-9,.]*)H)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)S)?)?$/;Ob.fn=wb.prototype;var Nf=Sb(1,"add"),Of=Sb(-1,"subtract");a.defaultFormat="YYYY-MM-DDTHH:mm:ssZ",a.defaultFormatUtc="YYYY-MM-DDTHH:mm:ss[Z]";var Pf=x("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(a){return void 0===a?this.localeData():this.locale(a)});
+// FORMATTING
+U(0,["gg",2],0,function(){return this.weekYear()%100}),U(0,["GG",2],0,function(){return this.isoWeekYear()%100}),zc("gggg","weekYear"),zc("ggggg","weekYear"),zc("GGGG","isoWeekYear"),zc("GGGGG","isoWeekYear"),
+// ALIASES
+J("weekYear","gg"),J("isoWeekYear","GG"),
+// PRIORITY
+M("weekYear",1),M("isoWeekYear",1),
+// PARSING
+Z("G",Se),Z("g",Se),Z("GG",Le,He),Z("gg",Le,He),Z("GGGG",Pe,Je),Z("gggg",Pe,Je),Z("GGGGG",Qe,Ke),Z("ggggg",Qe,Ke),ca(["gggg","ggggg","GGGG","GGGGG"],function(a,b,c,d){b[d.substr(0,2)]=u(a)}),ca(["gg","GG"],function(b,c,d,e){c[e]=a.parseTwoDigitYear(b)}),
+// FORMATTING
+U("Q",0,"Qo","quarter"),
+// ALIASES
+J("quarter","Q"),
+// PRIORITY
+M("quarter",7),
+// PARSING
+Z("Q",Ge),ba("Q",function(a,b){b[$e]=3*(u(a)-1)}),
+// FORMATTING
+U("D",["DD",2],"Do","date"),
+// ALIASES
+J("date","D"),
+// PRIOROITY
+M("date",9),
+// PARSING
+Z("D",Le),Z("DD",Le,He),Z("Do",function(a,b){return a?b._ordinalParse:b._ordinalParseLenient}),ba(["D","DD"],_e),ba("Do",function(a,b){b[_e]=u(a.match(Le)[0],10)});
+// MOMENTS
+var Qf=O("Date",!0);
+// FORMATTING
+U("DDD",["DDDD",3],"DDDo","dayOfYear"),
+// ALIASES
+J("dayOfYear","DDD"),
+// PRIORITY
+M("dayOfYear",4),
+// PARSING
+Z("DDD",Oe),Z("DDDD",Ie),ba(["DDD","DDDD"],function(a,b,c){c._dayOfYear=u(a)}),
+// FORMATTING
+U("m",["mm",2],0,"minute"),
+// ALIASES
+J("minute","m"),
+// PRIORITY
+M("minute",14),
+// PARSING
+Z("m",Le),Z("mm",Le,He),ba(["m","mm"],bf);
+// MOMENTS
+var Rf=O("Minutes",!1);
+// FORMATTING
+U("s",["ss",2],0,"second"),
+// ALIASES
+J("second","s"),
+// PRIORITY
+M("second",15),
+// PARSING
+Z("s",Le),Z("ss",Le,He),ba(["s","ss"],cf);
+// MOMENTS
+var Sf=O("Seconds",!1);
+// FORMATTING
+U("S",0,0,function(){return~~(this.millisecond()/100)}),U(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),U(0,["SSS",3],0,"millisecond"),U(0,["SSSS",4],0,function(){return 10*this.millisecond()}),U(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),U(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),U(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),U(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),U(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),
+// ALIASES
+J("millisecond","ms"),
+// PRIORITY
+M("millisecond",16),
+// PARSING
+Z("S",Oe,Ge),Z("SS",Oe,He),Z("SSS",Oe,Ie);var Tf;for(Tf="SSSS";Tf.length<=9;Tf+="S")Z(Tf,Re);for(Tf="S";Tf.length<=9;Tf+="S")ba(Tf,Ic);
+// MOMENTS
+var Uf=O("Milliseconds",!1);
+// FORMATTING
+U("z",0,0,"zoneAbbr"),U("zz",0,0,"zoneName");var Vf=r.prototype;Vf.add=Nf,Vf.calendar=Vb,Vf.clone=Wb,Vf.diff=bc,Vf.endOf=oc,Vf.format=gc,Vf.from=hc,Vf.fromNow=ic,Vf.to=jc,Vf.toNow=kc,Vf.get=R,Vf.invalidAt=xc,Vf.isAfter=Xb,Vf.isBefore=Yb,Vf.isBetween=Zb,Vf.isSame=$b,Vf.isSameOrAfter=_b,Vf.isSameOrBefore=ac,Vf.isValid=vc,Vf.lang=Pf,Vf.locale=lc,Vf.localeData=mc,Vf.max=If,Vf.min=Hf,Vf.parsingFlags=wc,Vf.set=S,Vf.startOf=nc,Vf.subtract=Of,Vf.toArray=sc,Vf.toObject=tc,Vf.toDate=rc,Vf.toISOString=ec,Vf.inspect=fc,Vf.toJSON=uc,Vf.toString=dc,Vf.unix=qc,Vf.valueOf=pc,Vf.creationData=yc,
+// Year
+Vf.year=nf,Vf.isLeapYear=ra,
+// Week Year
+Vf.weekYear=Ac,Vf.isoWeekYear=Bc,
+// Quarter
+Vf.quarter=Vf.quarters=Gc,
+// Month
+Vf.month=ka,Vf.daysInMonth=la,
+// Week
+Vf.week=Vf.weeks=Ba,Vf.isoWeek=Vf.isoWeeks=Ca,Vf.weeksInYear=Dc,Vf.isoWeeksInYear=Cc,
+// Day
+Vf.date=Qf,Vf.day=Vf.days=Ka,Vf.weekday=La,Vf.isoWeekday=Ma,Vf.dayOfYear=Hc,
+// Hour
+Vf.hour=Vf.hours=xf,
+// Minute
+Vf.minute=Vf.minutes=Rf,
+// Second
+Vf.second=Vf.seconds=Sf,
+// Millisecond
+Vf.millisecond=Vf.milliseconds=Uf,
+// Offset
+Vf.utcOffset=Db,Vf.utc=Fb,Vf.local=Gb,Vf.parseZone=Hb,Vf.hasAlignedHourOffset=Ib,Vf.isDST=Jb,Vf.isLocal=Lb,Vf.isUtcOffset=Mb,Vf.isUtc=Nb,Vf.isUTC=Nb,
+// Timezone
+Vf.zoneAbbr=Jc,Vf.zoneName=Kc,
+// Deprecations
+Vf.dates=x("dates accessor is deprecated. Use date instead.",Qf),Vf.months=x("months accessor is deprecated. Use month instead",ka),Vf.years=x("years accessor is deprecated. Use year instead",nf),Vf.zone=x("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",Eb),Vf.isDSTShifted=x("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",Kb);var Wf=C.prototype;Wf.calendar=D,Wf.longDateFormat=E,Wf.invalidDate=F,Wf.ordinal=G,Wf.preparse=Nc,Wf.postformat=Nc,Wf.relativeTime=H,Wf.pastFuture=I,Wf.set=A,
+// Month
+Wf.months=fa,Wf.monthsShort=ga,Wf.monthsParse=ia,Wf.monthsRegex=na,Wf.monthsShortRegex=ma,
+// Week
+Wf.week=ya,Wf.firstDayOfYear=Aa,Wf.firstDayOfWeek=za,
+// Day of Week
+Wf.weekdays=Fa,Wf.weekdaysMin=Ha,Wf.weekdaysShort=Ga,Wf.weekdaysParse=Ja,Wf.weekdaysRegex=Na,Wf.weekdaysShortRegex=Oa,Wf.weekdaysMinRegex=Pa,
+// Hours
+Wf.isPM=Va,Wf.meridiem=Wa,$a("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(a){var b=a%10,c=1===u(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c}}),
+// Side effect imports
+a.lang=x("moment.lang is deprecated. Use moment.locale instead.",$a),a.langData=x("moment.langData is deprecated. Use moment.localeData instead.",bb);var Xf=Math.abs,Yf=ed("ms"),Zf=ed("s"),$f=ed("m"),_f=ed("h"),ag=ed("d"),bg=ed("w"),cg=ed("M"),dg=ed("y"),eg=gd("milliseconds"),fg=gd("seconds"),gg=gd("minutes"),hg=gd("hours"),ig=gd("days"),jg=gd("months"),kg=gd("years"),lg=Math.round,mg={s:45,// seconds to minute
+m:45,// minutes to hour
+h:22,// hours to day
+d:26,// days to month
+M:11},ng=Math.abs,og=wb.prototype;og.abs=Wc,og.add=Yc,og.subtract=Zc,og.as=cd,og.asMilliseconds=Yf,og.asSeconds=Zf,og.asMinutes=$f,og.asHours=_f,og.asDays=ag,og.asWeeks=bg,og.asMonths=cg,og.asYears=dg,og.valueOf=dd,og._bubble=_c,og.get=fd,og.milliseconds=eg,og.seconds=fg,og.minutes=gg,og.hours=hg,og.days=ig,og.weeks=hd,og.months=jg,og.years=kg,og.humanize=md,og.toISOString=nd,og.toString=nd,og.toJSON=nd,og.locale=lc,og.localeData=mc,
+// Deprecations
+og.toIsoString=x("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",nd),og.lang=Pf,
+// Side effect imports
+// FORMATTING
+U("X",0,0,"unix"),U("x",0,0,"valueOf"),
+// PARSING
+Z("x",Se),Z("X",Ve),ba("X",function(a,b,c){c._d=new Date(1e3*parseFloat(a,10))}),ba("x",function(a,b,c){c._d=new Date(u(a))}),
+// Side effect imports
+//! moment.js
+//! version : 2.16.0
+//! authors : Tim Wood, Iskren Chernev, Moment.js contributors
+//! license : MIT
+//! momentjs.com
+a.version="2.16.0",b(sb),a.fn=Vf,a.min=ub,a.max=vb,a.now=Jf,a.utc=k,a.unix=Lc,a.months=Rc,a.isDate=g,a.locale=$a,a.invalid=o,a.duration=Ob,a.isMoment=s,a.weekdays=Tc,a.parseZone=Mc,a.localeData=bb,a.isDuration=xb,a.monthsShort=Sc,a.weekdaysMin=Vc,a.defineLocale=_a,a.updateLocale=ab,a.locales=cb,a.weekdaysShort=Uc,a.normalizeUnits=K,a.relativeTimeRounding=kd,a.relativeTimeThreshold=ld,a.calendarFormat=Ub,a.prototype=Vf,
+//! moment.js locale configuration
+//! locale : Afrikaans [af]
+//! author : Werner Mollentze : https://github.com/wernerm
+a.defineLocale("af",{months:"Januarie_Februarie_Maart_April_Mei_Junie_Julie_Augustus_September_Oktober_November_Desember".split("_"),monthsShort:"Jan_Feb_Mrt_Apr_Mei_Jun_Jul_Aug_Sep_Okt_Nov_Des".split("_"),weekdays:"Sondag_Maandag_Dinsdag_Woensdag_Donderdag_Vrydag_Saterdag".split("_"),weekdaysShort:"Son_Maa_Din_Woe_Don_Vry_Sat".split("_"),weekdaysMin:"So_Ma_Di_Wo_Do_Vr_Sa".split("_"),meridiemParse:/vm|nm/i,isPM:function(a){return/^nm$/i.test(a)},meridiem:function(a,b,c){return a<12?c?"vm":"VM":c?"nm":"NM"},longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Vandag om] LT",nextDay:"[Môre om] LT",nextWeek:"dddd [om] LT",lastDay:"[Gister om] LT",lastWeek:"[Laas] dddd [om] LT",sameElse:"L"},relativeTime:{future:"oor %s",past:"%s gelede",s:"'n paar sekondes",m:"'n minuut",mm:"%d minute",h:"'n uur",hh:"%d ure",d:"'n dag",dd:"%d dae",M:"'n maand",MM:"%d maande",y:"'n jaar",yy:"%d jaar"},ordinalParse:/\d{1,2}(ste|de)/,ordinal:function(a){return a+(1===a||8===a||a>=20?"ste":"de")},week:{dow:1,// Maandag is die eerste dag van die week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Arabic (Algeria) [ar-dz]
+//! author : Noureddine LOUAHEDJ : https://github.com/noureddineme
+a.defineLocale("ar-dz",{months:"جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"),monthsShort:"جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"),weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"احد_اثنين_ثلاثاء_اربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"أح_إث_ثلا_أر_خم_جم_سب".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[اليوم على الساعة] LT",nextDay:"[غدا على الساعة] LT",nextWeek:"dddd [على الساعة] LT",lastDay:"[أمس على الساعة] LT",lastWeek:"dddd [على الساعة] LT",sameElse:"L"},relativeTime:{future:"في %s",past:"منذ %s",s:"ثوان",m:"دقيقة",mm:"%d دقائق",h:"ساعة",hh:"%d ساعات",d:"يوم",dd:"%d أيام",M:"شهر",MM:"%d أشهر",y:"سنة",yy:"%d سنوات"},week:{dow:0,// Sunday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Arabic (Lybia) [ar-ly]
+//! author : Ali Hmer: https://github.com/kikoanis
+var pg={1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",0:"0"},qg=function(a){return 0===a?0:1===a?1:2===a?2:a%100>=3&&a%100<=10?3:a%100>=11?4:5},rg={s:["أقل من ثانية","ثانية واحدة",["ثانيتان","ثانيتين"],"%d ثوان","%d ثانية","%d ثانية"],m:["أقل من دقيقة","دقيقة واحدة",["دقيقتان","دقيقتين"],"%d دقائق","%d دقيقة","%d دقيقة"],h:["أقل من ساعة","ساعة واحدة",["ساعتان","ساعتين"],"%d ساعات","%d ساعة","%d ساعة"],d:["أقل من يوم","يوم واحد",["يومان","يومين"],"%d أيام","%d يومًا","%d يوم"],M:["أقل من شهر","شهر واحد",["شهران","شهرين"],"%d أشهر","%d شهرا","%d شهر"],y:["أقل من عام","عام واحد",["عامان","عامين"],"%d أعوام","%d عامًا","%d عام"]},sg=function(a){return function(b,c,d,e){var f=qg(b),g=rg[a][qg(b)];return 2===f&&(g=g[c?0:1]),g.replace(/%d/i,b)}},tg=["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر"];a.defineLocale("ar-ly",{months:tg,monthsShort:tg,weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"D/‏M/‏YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/ص|م/,isPM:function(a){return"م"===a},meridiem:function(a,b,c){return a<12?"ص":"م"},calendar:{sameDay:"[اليوم عند الساعة] LT",nextDay:"[غدًا عند الساعة] LT",nextWeek:"dddd [عند الساعة] LT",lastDay:"[أمس عند الساعة] LT",lastWeek:"dddd [عند الساعة] LT",sameElse:"L"},relativeTime:{future:"بعد %s",past:"منذ %s",s:sg("s"),m:sg("m"),mm:sg("m"),h:sg("h"),hh:sg("h"),d:sg("d"),dd:sg("d"),M:sg("M"),MM:sg("M"),y:sg("y"),yy:sg("y")},preparse:function(a){return a.replace(/\u200f/g,"").replace(/،/g,",")},postformat:function(a){return a.replace(/\d/g,function(a){return pg[a]}).replace(/,/g,"،")},week:{dow:6,// Saturday is the first day of the week.
+doy:12}}),
+//! moment.js locale configuration
+//! locale : Arabic (Morocco) [ar-ma]
+//! author : ElFadili Yassine : https://github.com/ElFadiliY
+//! author : Abdel Said : https://github.com/abdelsaid
+a.defineLocale("ar-ma",{months:"يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر".split("_"),monthsShort:"يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر".split("_"),weekdays:"الأحد_الإتنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"احد_اتنين_ثلاثاء_اربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[اليوم على الساعة] LT",nextDay:"[غدا على الساعة] LT",nextWeek:"dddd [على الساعة] LT",lastDay:"[أمس على الساعة] LT",lastWeek:"dddd [على الساعة] LT",sameElse:"L"},relativeTime:{future:"في %s",past:"منذ %s",s:"ثوان",m:"دقيقة",mm:"%d دقائق",h:"ساعة",hh:"%d ساعات",d:"يوم",dd:"%d أيام",M:"شهر",MM:"%d أشهر",y:"سنة",yy:"%d سنوات"},week:{dow:6,// Saturday is the first day of the week.
+doy:12}});
+//! moment.js locale configuration
+//! locale : Arabic (Saudi Arabia) [ar-sa]
+//! author : Suhail Alkowaileet : https://github.com/xsoh
+var ug={1:"١",2:"٢",3:"٣",4:"٤",5:"٥",6:"٦",7:"٧",8:"٨",9:"٩",0:"٠"},vg={"١":"1","٢":"2","٣":"3","٤":"4","٥":"5","٦":"6","٧":"7","٨":"8","٩":"9","٠":"0"};a.defineLocale("ar-sa",{months:"يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"),monthsShort:"يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"),weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/ص|م/,isPM:function(a){return"م"===a},meridiem:function(a,b,c){return a<12?"ص":"م"},calendar:{sameDay:"[اليوم على الساعة] LT",nextDay:"[غدا على الساعة] LT",nextWeek:"dddd [على الساعة] LT",lastDay:"[أمس على الساعة] LT",lastWeek:"dddd [على الساعة] LT",sameElse:"L"},relativeTime:{future:"في %s",past:"منذ %s",s:"ثوان",m:"دقيقة",mm:"%d دقائق",h:"ساعة",hh:"%d ساعات",d:"يوم",dd:"%d أيام",M:"شهر",MM:"%d أشهر",y:"سنة",yy:"%d سنوات"},preparse:function(a){return a.replace(/[١٢٣٤٥٦٧٨٩٠]/g,function(a){return vg[a]}).replace(/،/g,",")},postformat:function(a){return a.replace(/\d/g,function(a){return ug[a]}).replace(/,/g,"،")},week:{dow:0,// Sunday is the first day of the week.
+doy:6}}),
+//! moment.js locale configuration
+//! locale  :  Arabic (Tunisia) [ar-tn]
+//! author : Nader Toukabri : https://github.com/naderio
+a.defineLocale("ar-tn",{months:"جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"),monthsShort:"جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"),weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[اليوم على الساعة] LT",nextDay:"[غدا على الساعة] LT",nextWeek:"dddd [على الساعة] LT",lastDay:"[أمس على الساعة] LT",lastWeek:"dddd [على الساعة] LT",sameElse:"L"},relativeTime:{future:"في %s",past:"منذ %s",s:"ثوان",m:"دقيقة",mm:"%d دقائق",h:"ساعة",hh:"%d ساعات",d:"يوم",dd:"%d أيام",M:"شهر",MM:"%d أشهر",y:"سنة",yy:"%d سنوات"},week:{dow:1,// Monday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Arabic [ar]
+//! author : Abdel Said: https://github.com/abdelsaid
+//! author : Ahmed Elkhatib
+//! author : forabi https://github.com/forabi
+var wg={1:"١",2:"٢",3:"٣",4:"٤",5:"٥",6:"٦",7:"٧",8:"٨",9:"٩",0:"٠"},xg={"١":"1","٢":"2","٣":"3","٤":"4","٥":"5","٦":"6","٧":"7","٨":"8","٩":"9","٠":"0"},yg=function(a){return 0===a?0:1===a?1:2===a?2:a%100>=3&&a%100<=10?3:a%100>=11?4:5},zg={s:["أقل من ثانية","ثانية واحدة",["ثانيتان","ثانيتين"],"%d ثوان","%d ثانية","%d ثانية"],m:["أقل من دقيقة","دقيقة واحدة",["دقيقتان","دقيقتين"],"%d دقائق","%d دقيقة","%d دقيقة"],h:["أقل من ساعة","ساعة واحدة",["ساعتان","ساعتين"],"%d ساعات","%d ساعة","%d ساعة"],d:["أقل من يوم","يوم واحد",["يومان","يومين"],"%d أيام","%d يومًا","%d يوم"],M:["أقل من شهر","شهر واحد",["شهران","شهرين"],"%d أشهر","%d شهرا","%d شهر"],y:["أقل من عام","عام واحد",["عامان","عامين"],"%d أعوام","%d عامًا","%d عام"]},Ag=function(a){return function(b,c,d,e){var f=yg(b),g=zg[a][yg(b)];return 2===f&&(g=g[c?0:1]),g.replace(/%d/i,b)}},Bg=["كانون الثاني يناير","شباط فبراير","آذار مارس","نيسان أبريل","أيار مايو","حزيران يونيو","تموز يوليو","آب أغسطس","أيلول سبتمبر","تشرين الأول أكتوبر","تشرين الثاني نوفمبر","كانون الأول ديسمبر"];a.defineLocale("ar",{months:Bg,monthsShort:Bg,weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"D/‏M/‏YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/ص|م/,isPM:function(a){return"م"===a},meridiem:function(a,b,c){return a<12?"ص":"م"},calendar:{sameDay:"[اليوم عند الساعة] LT",nextDay:"[غدًا عند الساعة] LT",nextWeek:"dddd [عند الساعة] LT",lastDay:"[أمس عند الساعة] LT",lastWeek:"dddd [عند الساعة] LT",sameElse:"L"},relativeTime:{future:"بعد %s",past:"منذ %s",s:Ag("s"),m:Ag("m"),mm:Ag("m"),h:Ag("h"),hh:Ag("h"),d:Ag("d"),dd:Ag("d"),M:Ag("M"),MM:Ag("M"),y:Ag("y"),yy:Ag("y")},preparse:function(a){return a.replace(/\u200f/g,"").replace(/[١٢٣٤٥٦٧٨٩٠]/g,function(a){return xg[a]}).replace(/،/g,",")},postformat:function(a){return a.replace(/\d/g,function(a){return wg[a]}).replace(/,/g,"،")},week:{dow:6,// Saturday is the first day of the week.
+doy:12}});
+//! moment.js locale configuration
+//! locale : Azerbaijani [az]
+//! author : topchiyev : https://github.com/topchiyev
+var Cg={1:"-inci",5:"-inci",8:"-inci",70:"-inci",80:"-inci",2:"-nci",7:"-nci",20:"-nci",50:"-nci",3:"-üncü",4:"-üncü",100:"-üncü",6:"-ncı",9:"-uncu",10:"-uncu",30:"-uncu",60:"-ıncı",90:"-ıncı"};a.defineLocale("az",{months:"yanvar_fevral_mart_aprel_may_iyun_iyul_avqust_sentyabr_oktyabr_noyabr_dekabr".split("_"),monthsShort:"yan_fev_mar_apr_may_iyn_iyl_avq_sen_okt_noy_dek".split("_"),weekdays:"Bazar_Bazar ertəsi_Çərşənbə axşamı_Çərşənbə_Cümə axşamı_Cümə_Şənbə".split("_"),weekdaysShort:"Baz_BzE_ÇAx_Çər_CAx_Cüm_Şən".split("_"),weekdaysMin:"Bz_BE_ÇA_Çə_CA_Cü_Şə".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[bugün saat] LT",nextDay:"[sabah saat] LT",nextWeek:"[gələn həftə] dddd [saat] LT",lastDay:"[dünən] LT",lastWeek:"[keçən həftə] dddd [saat] LT",sameElse:"L"},relativeTime:{future:"%s sonra",past:"%s əvvəl",s:"birneçə saniyyə",m:"bir dəqiqə",mm:"%d dəqiqə",h:"bir saat",hh:"%d saat",d:"bir gün",dd:"%d gün",M:"bir ay",MM:"%d ay",y:"bir il",yy:"%d il"},meridiemParse:/gecə|səhər|gündüz|axşam/,isPM:function(a){return/^(gündüz|axşam)$/.test(a)},meridiem:function(a,b,c){return a<4?"gecə":a<12?"səhər":a<17?"gündüz":"axşam"},ordinalParse:/\d{1,2}-(ıncı|inci|nci|üncü|ncı|uncu)/,ordinal:function(a){if(0===a)// special case for zero
+return a+"-ıncı";var b=a%10,c=a%100-b,d=a>=100?100:null;return a+(Cg[b]||Cg[c]||Cg[d])},week:{dow:1,// Monday is the first day of the week.
+doy:7}}),a.defineLocale("be",{months:{format:"студзеня_лютага_сакавіка_красавіка_траўня_чэрвеня_ліпеня_жніўня_верасня_кастрычніка_лістапада_снежня".split("_"),standalone:"студзень_люты_сакавік_красавік_травень_чэрвень_ліпень_жнівень_верасень_кастрычнік_лістапад_снежань".split("_")},monthsShort:"студ_лют_сак_крас_трав_чэрв_ліп_жнів_вер_каст_ліст_снеж".split("_"),weekdays:{format:"нядзелю_панядзелак_аўторак_сераду_чацвер_пятніцу_суботу".split("_"),standalone:"нядзеля_панядзелак_аўторак_серада_чацвер_пятніца_субота".split("_"),isFormat:/\[ ?[Вв] ?(?:мінулую|наступную)? ?\] ?dddd/},weekdaysShort:"нд_пн_ат_ср_чц_пт_сб".split("_"),weekdaysMin:"нд_пн_ат_ср_чц_пт_сб".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY г.",LLL:"D MMMM YYYY г., HH:mm",LLLL:"dddd, D MMMM YYYY г., HH:mm"},calendar:{sameDay:"[Сёння ў] LT",nextDay:"[Заўтра ў] LT",lastDay:"[Учора ў] LT",nextWeek:function(){return"[У] dddd [ў] LT"},lastWeek:function(){switch(this.day()){case 0:case 3:case 5:case 6:return"[У мінулую] dddd [ў] LT";case 1:case 2:case 4:return"[У мінулы] dddd [ў] LT"}},sameElse:"L"},relativeTime:{future:"праз %s",past:"%s таму",s:"некалькі секунд",m:pd,mm:pd,h:pd,hh:pd,d:"дзень",dd:pd,M:"месяц",MM:pd,y:"год",yy:pd},meridiemParse:/ночы|раніцы|дня|вечара/,isPM:function(a){return/^(дня|вечара)$/.test(a)},meridiem:function(a,b,c){return a<4?"ночы":a<12?"раніцы":a<17?"дня":"вечара"},ordinalParse:/\d{1,2}-(і|ы|га)/,ordinal:function(a,b){switch(b){case"M":case"d":case"DDD":case"w":case"W":return a%10!==2&&a%10!==3||a%100===12||a%100===13?a+"-ы":a+"-і";case"D":return a+"-га";default:return a}},week:{dow:1,// Monday is the first day of the week.
+doy:7}}),a.defineLocale("bg-x",{parentLocale:"bg"}),
+//! moment.js locale configuration
+//! locale : Bulgarian [bg]
+//! author : Krasen Borisov : https://github.com/kraz
+a.defineLocale("bg",{months:"януари_февруари_март_април_май_юни_юли_август_септември_октомври_ноември_декември".split("_"),monthsShort:"янр_фев_мар_апр_май_юни_юли_авг_сеп_окт_ное_дек".split("_"),weekdays:"неделя_понеделник_вторник_сряда_четвъртък_петък_събота".split("_"),weekdaysShort:"нед_пон_вто_сря_чет_пет_съб".split("_"),weekdaysMin:"нд_пн_вт_ср_чт_пт_сб".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"D.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY H:mm",LLLL:"dddd, D MMMM YYYY H:mm"},calendar:{sameDay:"[Днес в] LT",nextDay:"[Утре в] LT",nextWeek:"dddd [в] LT",lastDay:"[Вчера в] LT",lastWeek:function(){switch(this.day()){case 0:case 3:case 6:return"[В изминалата] dddd [в] LT";case 1:case 2:case 4:case 5:return"[В изминалия] dddd [в] LT"}},sameElse:"L"},relativeTime:{future:"след %s",past:"преди %s",s:"няколко секунди",m:"минута",mm:"%d минути",h:"час",hh:"%d часа",d:"ден",dd:"%d дни",M:"месец",MM:"%d месеца",y:"година",yy:"%d години"},ordinalParse:/\d{1,2}-(ев|ен|ти|ви|ри|ми)/,ordinal:function(a){var b=a%10,c=a%100;return 0===a?a+"-ев":0===c?a+"-ен":c>10&&c<20?a+"-ти":1===b?a+"-ви":2===b?a+"-ри":7===b||8===b?a+"-ми":a+"-ти"},week:{dow:1,// Monday is the first day of the week.
+doy:7}});
+//! moment.js locale configuration
+//! locale : Bengali [bn]
+//! author : Kaushik Gandhi : https://github.com/kaushikgandhi
+var Dg={1:"১",2:"২",3:"৩",4:"৪",5:"৫",6:"৬",7:"৭",8:"৮",9:"৯",0:"০"},Eg={"১":"1","২":"2","৩":"3","৪":"4","৫":"5","৬":"6","৭":"7","৮":"8","৯":"9","০":"0"};a.defineLocale("bn",{months:"জানুয়ারী_ফেব্রুয়ারি_মার্চ_এপ্রিল_মে_জুন_জুলাই_আগস্ট_সেপ্টেম্বর_অক্টোবর_নভেম্বর_ডিসেম্বর".split("_"),monthsShort:"জানু_ফেব_মার্চ_এপ্র_মে_জুন_জুল_আগ_সেপ্ট_অক্টো_নভে_ডিসে".split("_"),weekdays:"রবিবার_সোমবার_মঙ্গলবার_বুধবার_বৃহস্পতিবার_শুক্রবার_শনিবার".split("_"),weekdaysShort:"রবি_সোম_মঙ্গল_বুধ_বৃহস্পতি_শুক্র_শনি".split("_"),weekdaysMin:"রবি_সোম_মঙ্গ_বুধ_বৃহঃ_শুক্র_শনি".split("_"),longDateFormat:{LT:"A h:mm সময়",LTS:"A h:mm:ss সময়",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm সময়",LLLL:"dddd, D MMMM YYYY, A h:mm সময়"},calendar:{sameDay:"[আজ] LT",nextDay:"[আগামীকাল] LT",nextWeek:"dddd, LT",lastDay:"[গতকাল] LT",lastWeek:"[গত] dddd, LT",sameElse:"L"},relativeTime:{future:"%s পরে",past:"%s আগে",s:"কয়েক সেকেন্ড",m:"এক মিনিট",mm:"%d মিনিট",h:"এক ঘন্টা",hh:"%d ঘন্টা",d:"এক দিন",dd:"%d দিন",M:"এক মাস",MM:"%d মাস",y:"এক বছর",yy:"%d বছর"},preparse:function(a){return a.replace(/[১২৩৪৫৬৭৮৯০]/g,function(a){return Eg[a]})},postformat:function(a){return a.replace(/\d/g,function(a){return Dg[a]})},meridiemParse:/রাত|সকাল|দুপুর|বিকাল|রাত/,meridiemHour:function(a,b){return 12===a&&(a=0),"রাত"===b&&a>=4||"দুপুর"===b&&a<5||"বিকাল"===b?a+12:a},meridiem:function(a,b,c){return a<4?"রাত":a<10?"সকাল":a<17?"দুপুর":a<20?"বিকাল":"রাত"},week:{dow:0,// Sunday is the first day of the week.
+doy:6}});
+//! moment.js locale configuration
+//! locale : Tibetan [bo]
+//! author : Thupten N. Chakrishar : https://github.com/vajradog
+var Fg={1:"༡",2:"༢",3:"༣",4:"༤",5:"༥",6:"༦",7:"༧",8:"༨",9:"༩",0:"༠"},Gg={"༡":"1","༢":"2","༣":"3","༤":"4","༥":"5","༦":"6","༧":"7","༨":"8","༩":"9","༠":"0"};a.defineLocale("bo",{months:"ཟླ་བ་དང་པོ_ཟླ་བ་གཉིས་པ_ཟླ་བ་གསུམ་པ_ཟླ་བ་བཞི་པ_ཟླ་བ་ལྔ་པ_ཟླ་བ་དྲུག་པ_ཟླ་བ་བདུན་པ_ཟླ་བ་བརྒྱད་པ_ཟླ་བ་དགུ་པ_ཟླ་བ་བཅུ་པ_ཟླ་བ་བཅུ་གཅིག་པ_ཟླ་བ་བཅུ་གཉིས་པ".split("_"),monthsShort:"ཟླ་བ་དང་པོ_ཟླ་བ་གཉིས་པ_ཟླ་བ་གསུམ་པ_ཟླ་བ་བཞི་པ_ཟླ་བ་ལྔ་པ_ཟླ་བ་དྲུག་པ_ཟླ་བ་བདུན་པ_ཟླ་བ་བརྒྱད་པ_ཟླ་བ་དགུ་པ_ཟླ་བ་བཅུ་པ_ཟླ་བ་བཅུ་གཅིག་པ_ཟླ་བ་བཅུ་གཉིས་པ".split("_"),weekdays:"གཟའ་ཉི་མ་_གཟའ་ཟླ་བ་_གཟའ་མིག་དམར་_གཟའ་ལྷག་པ་_གཟའ་ཕུར་བུ_གཟའ་པ་སངས་_གཟའ་སྤེན་པ་".split("_"),weekdaysShort:"ཉི་མ་_ཟླ་བ་_མིག་དམར་_ལྷག་པ་_ཕུར་བུ_པ་སངས་_སྤེན་པ་".split("_"),weekdaysMin:"ཉི་མ་_ཟླ་བ་_མིག་དམར་_ལྷག་པ་_ཕུར་བུ_པ་སངས་_སྤེན་པ་".split("_"),longDateFormat:{LT:"A h:mm",LTS:"A h:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm",LLLL:"dddd, D MMMM YYYY, A h:mm"},calendar:{sameDay:"[དི་རིང] LT",nextDay:"[སང་ཉིན] LT",nextWeek:"[བདུན་ཕྲག་རྗེས་མ], LT",lastDay:"[ཁ་སང] LT",lastWeek:"[བདུན་ཕྲག་མཐའ་མ] dddd, LT",sameElse:"L"},relativeTime:{future:"%s ལ་",past:"%s སྔན་ལ",s:"ལམ་སང",m:"སྐར་མ་གཅིག",mm:"%d སྐར་མ",h:"ཆུ་ཚོད་གཅིག",hh:"%d ཆུ་ཚོད",d:"ཉིན་གཅིག",dd:"%d ཉིན་",M:"ཟླ་བ་གཅིག",MM:"%d ཟླ་བ",y:"ལོ་གཅིག",yy:"%d ལོ"},preparse:function(a){return a.replace(/[༡༢༣༤༥༦༧༨༩༠]/g,function(a){return Gg[a]})},postformat:function(a){return a.replace(/\d/g,function(a){return Fg[a]})},meridiemParse:/མཚན་མོ|ཞོགས་ཀས|ཉིན་གུང|དགོང་དག|མཚན་མོ/,meridiemHour:function(a,b){return 12===a&&(a=0),"མཚན་མོ"===b&&a>=4||"ཉིན་གུང"===b&&a<5||"དགོང་དག"===b?a+12:a},meridiem:function(a,b,c){return a<4?"མཚན་མོ":a<10?"ཞོགས་ཀས":a<17?"ཉིན་གུང":a<20?"དགོང་དག":"མཚན་མོ"},week:{dow:0,// Sunday is the first day of the week.
+doy:6}}),a.defineLocale("br",{months:"Genver_C'hwevrer_Meurzh_Ebrel_Mae_Mezheven_Gouere_Eost_Gwengolo_Here_Du_Kerzu".split("_"),monthsShort:"Gen_C'hwe_Meu_Ebr_Mae_Eve_Gou_Eos_Gwe_Her_Du_Ker".split("_"),weekdays:"Sul_Lun_Meurzh_Merc'her_Yaou_Gwener_Sadorn".split("_"),weekdaysShort:"Sul_Lun_Meu_Mer_Yao_Gwe_Sad".split("_"),weekdaysMin:"Su_Lu_Me_Mer_Ya_Gw_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"h[e]mm A",LTS:"h[e]mm:ss A",L:"DD/MM/YYYY",LL:"D [a viz] MMMM YYYY",LLL:"D [a viz] MMMM YYYY h[e]mm A",LLLL:"dddd, D [a viz] MMMM YYYY h[e]mm A"},calendar:{sameDay:"[Hiziv da] LT",nextDay:"[Warc'hoazh da] LT",nextWeek:"dddd [da] LT",lastDay:"[Dec'h da] LT",lastWeek:"dddd [paset da] LT",sameElse:"L"},relativeTime:{future:"a-benn %s",past:"%s 'zo",s:"un nebeud segondennoù",m:"ur vunutenn",mm:qd,h:"un eur",hh:"%d eur",d:"un devezh",dd:qd,M:"ur miz",MM:qd,y:"ur bloaz",yy:rd},ordinalParse:/\d{1,2}(añ|vet)/,ordinal:function(a){var b=1===a?"añ":"vet";return a+b},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),a.defineLocale("bs",{months:"januar_februar_mart_april_maj_juni_juli_august_septembar_oktobar_novembar_decembar".split("_"),monthsShort:"jan._feb._mar._apr._maj._jun._jul._aug._sep._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota".split("_"),weekdaysShort:"ned._pon._uto._sri._čet._pet._sub.".split("_"),weekdaysMin:"ne_po_ut_sr_če_pe_su".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[danas u] LT",nextDay:"[sutra u] LT",nextWeek:function(){switch(this.day()){case 0:return"[u] [nedjelju] [u] LT";case 3:return"[u] [srijedu] [u] LT";case 6:return"[u] [subotu] [u] LT";case 1:case 2:case 4:case 5:return"[u] dddd [u] LT"}},lastDay:"[jučer u] LT",lastWeek:function(){switch(this.day()){case 0:case 3:return"[prošlu] dddd [u] LT";case 6:return"[prošle] [subote] [u] LT";case 1:case 2:case 4:case 5:return"[prošli] dddd [u] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"prije %s",s:"par sekundi",m:vd,mm:vd,h:vd,hh:vd,d:"dan",dd:vd,M:"mjesec",MM:vd,y:"godinu",yy:vd},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:7}}),
+//! moment.js locale configuration
+//! locale : Catalan [ca]
+//! author : Juan G. Hurtado : https://github.com/juanghurtado
+a.defineLocale("ca",{months:"gener_febrer_març_abril_maig_juny_juliol_agost_setembre_octubre_novembre_desembre".split("_"),monthsShort:"gen._febr._mar._abr._mai._jun._jul._ag._set._oct._nov._des.".split("_"),monthsParseExact:!0,weekdays:"diumenge_dilluns_dimarts_dimecres_dijous_divendres_dissabte".split("_"),weekdaysShort:"dg._dl._dt._dc._dj._dv._ds.".split("_"),weekdaysMin:"Dg_Dl_Dt_Dc_Dj_Dv_Ds".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY H:mm",LLLL:"dddd D MMMM YYYY H:mm"},calendar:{sameDay:function(){return"[avui a "+(1!==this.hours()?"les":"la")+"] LT"},nextDay:function(){return"[demà a "+(1!==this.hours()?"les":"la")+"] LT"},nextWeek:function(){return"dddd [a "+(1!==this.hours()?"les":"la")+"] LT"},lastDay:function(){return"[ahir a "+(1!==this.hours()?"les":"la")+"] LT"},lastWeek:function(){return"[el] dddd [passat a "+(1!==this.hours()?"les":"la")+"] LT"},sameElse:"L"},relativeTime:{future:"en %s",past:"fa %s",s:"uns segons",m:"un minut",mm:"%d minuts",h:"una hora",hh:"%d hores",d:"un dia",dd:"%d dies",M:"un mes",MM:"%d mesos",y:"un any",yy:"%d anys"},ordinalParse:/\d{1,2}(r|n|t|è|a)/,ordinal:function(a,b){var c=1===a?"r":2===a?"n":3===a?"r":4===a?"t":"è";return"w"!==b&&"W"!==b||(c="a"),a+c},week:{dow:1,// Monday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Czech [cs]
+//! author : petrbela : https://github.com/petrbela
+var Hg="leden_únor_březen_duben_květen_červen_červenec_srpen_září_říjen_listopad_prosinec".split("_"),Ig="led_úno_bře_dub_kvě_čvn_čvc_srp_zář_říj_lis_pro".split("_");a.defineLocale("cs",{months:Hg,monthsShort:Ig,monthsParse:function(a,b){var c,d=[];for(c=0;c<12;c++)
+// use custom parser to solve problem with July (červenec)
+d[c]=new RegExp("^"+a[c]+"$|^"+b[c]+"$","i");return d}(Hg,Ig),shortMonthsParse:function(a){var b,c=[];for(b=0;b<12;b++)c[b]=new RegExp("^"+a[b]+"$","i");return c}(Ig),longMonthsParse:function(a){var b,c=[];for(b=0;b<12;b++)c[b]=new RegExp("^"+a[b]+"$","i");return c}(Hg),weekdays:"neděle_pondělí_úterý_středa_čtvrtek_pátek_sobota".split("_"),weekdaysShort:"ne_po_út_st_čt_pá_so".split("_"),weekdaysMin:"ne_po_út_st_čt_pá_so".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd D. MMMM YYYY H:mm",l:"D. M. YYYY"},calendar:{sameDay:"[dnes v] LT",nextDay:"[zítra v] LT",nextWeek:function(){switch(this.day()){case 0:return"[v neděli v] LT";case 1:case 2:return"[v] dddd [v] LT";case 3:return"[ve středu v] LT";case 4:return"[ve čtvrtek v] LT";case 5:return"[v pátek v] LT";case 6:return"[v sobotu v] LT"}},lastDay:"[včera v] LT",lastWeek:function(){switch(this.day()){case 0:return"[minulou neděli v] LT";case 1:case 2:return"[minulé] dddd [v] LT";case 3:return"[minulou středu v] LT";case 4:case 5:return"[minulý] dddd [v] LT";case 6:return"[minulou sobotu v] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"před %s",s:xd,m:xd,mm:xd,h:xd,hh:xd,d:xd,dd:xd,M:xd,MM:xd,y:xd,yy:xd},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Chuvash [cv]
+//! author : Anatoly Mironov : https://github.com/mirontoli
+a.defineLocale("cv",{months:"кӑрлач_нарӑс_пуш_ака_май_ҫӗртме_утӑ_ҫурла_авӑн_юпа_чӳк_раштав".split("_"),monthsShort:"кӑр_нар_пуш_ака_май_ҫӗр_утӑ_ҫур_авн_юпа_чӳк_раш".split("_"),weekdays:"вырсарникун_тунтикун_ытларикун_юнкун_кӗҫнерникун_эрнекун_шӑматкун".split("_"),weekdaysShort:"выр_тун_ытл_юн_кӗҫ_эрн_шӑм".split("_"),weekdaysMin:"вр_тн_ыт_юн_кҫ_эр_шм".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD-MM-YYYY",LL:"YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ]",LLL:"YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm",LLLL:"dddd, YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm"},calendar:{sameDay:"[Паян] LT [сехетре]",nextDay:"[Ыран] LT [сехетре]",lastDay:"[Ӗнер] LT [сехетре]",nextWeek:"[Ҫитес] dddd LT [сехетре]",lastWeek:"[Иртнӗ] dddd LT [сехетре]",sameElse:"L"},relativeTime:{future:function(a){var b=/сехет$/i.exec(a)?"рен":/ҫул$/i.exec(a)?"тан":"ран";return a+b},past:"%s каялла",s:"пӗр-ик ҫеккунт",m:"пӗр минут",mm:"%d минут",h:"пӗр сехет",hh:"%d сехет",d:"пӗр кун",dd:"%d кун",M:"пӗр уйӑх",MM:"%d уйӑх",y:"пӗр ҫул",yy:"%d ҫул"},ordinalParse:/\d{1,2}-мӗш/,ordinal:"%d-мӗш",week:{dow:1,// Monday is the first day of the week.
+doy:7}}),
+//! moment.js locale configuration
+//! locale : Welsh [cy]
+//! author : Robert Allen : https://github.com/robgallen
+//! author : https://github.com/ryangreaves
+a.defineLocale("cy",{months:"Ionawr_Chwefror_Mawrth_Ebrill_Mai_Mehefin_Gorffennaf_Awst_Medi_Hydref_Tachwedd_Rhagfyr".split("_"),monthsShort:"Ion_Chwe_Maw_Ebr_Mai_Meh_Gor_Aws_Med_Hyd_Tach_Rhag".split("_"),weekdays:"Dydd Sul_Dydd Llun_Dydd Mawrth_Dydd Mercher_Dydd Iau_Dydd Gwener_Dydd Sadwrn".split("_"),weekdaysShort:"Sul_Llun_Maw_Mer_Iau_Gwe_Sad".split("_"),weekdaysMin:"Su_Ll_Ma_Me_Ia_Gw_Sa".split("_"),weekdaysParseExact:!0,
+// time formats are the same as en-gb
+longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Heddiw am] LT",nextDay:"[Yfory am] LT",nextWeek:"dddd [am] LT",lastDay:"[Ddoe am] LT",lastWeek:"dddd [diwethaf am] LT",sameElse:"L"},relativeTime:{future:"mewn %s",past:"%s yn ôl",s:"ychydig eiliadau",m:"munud",mm:"%d munud",h:"awr",hh:"%d awr",d:"diwrnod",dd:"%d diwrnod",M:"mis",MM:"%d mis",y:"blwyddyn",yy:"%d flynedd"},ordinalParse:/\d{1,2}(fed|ain|af|il|ydd|ed|eg)/,
+// traditional ordinal numbers above 31 are not commonly used in colloquial Welsh
+ordinal:function(a){var b=a,c="",d=["","af","il","ydd","ydd","ed","ed","ed","fed","fed","fed",// 1af to 10fed
+"eg","fed","eg","eg","fed","eg","eg","fed","eg","fed"];return b>20?c=40===b||50===b||60===b||80===b||100===b?"fed":"ain":b>0&&(c=d[b]),a+c},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Danish [da]
+//! author : Ulrik Nielsen : https://github.com/mrbase
+a.defineLocale("da",{months:"januar_februar_marts_april_maj_juni_juli_august_september_oktober_november_december".split("_"),monthsShort:"jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec".split("_"),weekdays:"søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag".split("_"),weekdaysShort:"søn_man_tir_ons_tor_fre_lør".split("_"),weekdaysMin:"sø_ma_ti_on_to_fr_lø".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY HH:mm",LLLL:"dddd [d.] D. MMMM YYYY HH:mm"},calendar:{sameDay:"[I dag kl.] LT",nextDay:"[I morgen kl.] LT",nextWeek:"dddd [kl.] LT",lastDay:"[I går kl.] LT",lastWeek:"[sidste] dddd [kl] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"%s siden",s:"få sekunder",m:"et minut",mm:"%d minutter",h:"en time",hh:"%d timer",d:"en dag",dd:"%d dage",M:"en måned",MM:"%d måneder",y:"et år",yy:"%d år"},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),a.defineLocale("de-at",{months:"Jänner_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember".split("_"),monthsShort:"Jän._Febr._Mrz._Apr._Mai_Jun._Jul._Aug._Sept._Okt._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag".split("_"),weekdaysShort:"So._Mo._Di._Mi._Do._Fr._Sa.".split("_"),weekdaysMin:"So_Mo_Di_Mi_Do_Fr_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY HH:mm",LLLL:"dddd, D. MMMM YYYY HH:mm"},calendar:{sameDay:"[heute um] LT [Uhr]",sameElse:"L",nextDay:"[morgen um] LT [Uhr]",nextWeek:"dddd [um] LT [Uhr]",lastDay:"[gestern um] LT [Uhr]",lastWeek:"[letzten] dddd [um] LT [Uhr]"},relativeTime:{future:"in %s",past:"vor %s",s:"ein paar Sekunden",m:yd,mm:"%d Minuten",h:yd,hh:"%d Stunden",d:yd,dd:yd,M:yd,MM:yd,y:yd,yy:yd},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),a.defineLocale("de",{months:"Januar_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember".split("_"),monthsShort:"Jan._Febr._Mrz._Apr._Mai_Jun._Jul._Aug._Sept._Okt._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag".split("_"),weekdaysShort:"So._Mo._Di._Mi._Do._Fr._Sa.".split("_"),weekdaysMin:"So_Mo_Di_Mi_Do_Fr_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY HH:mm",LLLL:"dddd, D. MMMM YYYY HH:mm"},calendar:{sameDay:"[heute um] LT [Uhr]",sameElse:"L",nextDay:"[morgen um] LT [Uhr]",nextWeek:"dddd [um] LT [Uhr]",lastDay:"[gestern um] LT [Uhr]",lastWeek:"[letzten] dddd [um] LT [Uhr]"},relativeTime:{future:"in %s",past:"vor %s",s:"ein paar Sekunden",m:zd,mm:"%d Minuten",h:zd,hh:"%d Stunden",d:zd,dd:zd,M:zd,MM:zd,y:zd,yy:zd},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Maldivian [dv]
+//! author : Jawish Hameed : https://github.com/jawish
+var Jg=["ޖެނުއަރީ","ފެބްރުއަރީ","މާރިޗު","އޭޕްރީލު","މޭ","ޖޫން","ޖުލައި","އޯގަސްޓު","ސެޕްޓެމްބަރު","އޮކްޓޯބަރު","ނޮވެމްބަރު","ޑިސެމްބަރު"],Kg=["އާދިއްތަ","ހޯމަ","އަންގާރަ","ބުދަ","ބުރާސްފަތި","ހުކުރު","ހޮނިހިރު"];a.defineLocale("dv",{months:Jg,monthsShort:Jg,weekdays:Kg,weekdaysShort:Kg,weekdaysMin:"އާދި_ހޯމަ_އަން_ބުދަ_ބުރާ_ހުކު_ހޮނި".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"D/M/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/މކ|މފ/,isPM:function(a){return"މފ"===a},meridiem:function(a,b,c){return a<12?"މކ":"މފ"},calendar:{sameDay:"[މިއަދު] LT",nextDay:"[މާދަމާ] LT",nextWeek:"dddd LT",lastDay:"[އިއްޔެ] LT",lastWeek:"[ފާއިތުވި] dddd LT",sameElse:"L"},relativeTime:{future:"ތެރޭގައި %s",past:"ކުރިން %s",s:"ސިކުންތުކޮޅެއް",m:"މިނިޓެއް",mm:"މިނިޓު %d",h:"ގަޑިއިރެއް",hh:"ގަޑިއިރު %d",d:"ދުވަހެއް",dd:"ދުވަސް %d",M:"މަހެއް",MM:"މަސް %d",y:"އަހަރެއް",yy:"އަހަރު %d"},preparse:function(a){return a.replace(/،/g,",")},postformat:function(a){return a.replace(/,/g,"،")},week:{dow:7,// Sunday is the first day of the week.
+doy:12}}),
+//! moment.js locale configuration
+//! locale : Greek [el]
+//! author : Aggelos Karalias : https://github.com/mehiel
+a.defineLocale("el",{monthsNominativeEl:"Ιανουάριος_Φεβρουάριος_Μάρτιος_Απρίλιος_Μάιος_Ιούνιος_Ιούλιος_Αύγουστος_Σεπτέμβριος_Οκτώβριος_Νοέμβριος_Δεκέμβριος".split("_"),monthsGenitiveEl:"Ιανουαρίου_Φεβρουαρίου_Μαρτίου_Απριλίου_Μαΐου_Ιουνίου_Ιουλίου_Αυγούστου_Σεπτεμβρίου_Οκτωβρίου_Νοεμβρίου_Δεκεμβρίου".split("_"),months:function(a,b){return/D/.test(b.substring(0,b.indexOf("MMMM")))?this._monthsGenitiveEl[a.month()]:this._monthsNominativeEl[a.month()]},monthsShort:"Ιαν_Φεβ_Μαρ_Απρ_Μαϊ_Ιουν_Ιουλ_Αυγ_Σεπ_Οκτ_Νοε_Δεκ".split("_"),weekdays:"Κυριακή_Δευτέρα_Τρίτη_Τετάρτη_Πέμπτη_Παρασκευή_Σάββατο".split("_"),weekdaysShort:"Κυρ_Δευ_Τρι_Τετ_Πεμ_Παρ_Σαβ".split("_"),weekdaysMin:"Κυ_Δε_Τρ_Τε_Πε_Πα_Σα".split("_"),meridiem:function(a,b,c){return a>11?c?"μμ":"ΜΜ":c?"πμ":"ΠΜ"},isPM:function(a){return"μ"===(a+"").toLowerCase()[0]},meridiemParse:/[ΠΜ]\.?Μ?\.?/i,longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendarEl:{sameDay:"[Σήμερα {}] LT",nextDay:"[Αύριο {}] LT",nextWeek:"dddd [{}] LT",lastDay:"[Χθες {}] LT",lastWeek:function(){switch(this.day()){case 6:return"[το προηγούμενο] dddd [{}] LT";default:return"[την προηγούμενη] dddd [{}] LT"}},sameElse:"L"},calendar:function(a,b){var c=this._calendarEl[a],d=b&&b.hours();return z(c)&&(c=c.apply(b)),c.replace("{}",d%12===1?"στη":"στις")},relativeTime:{future:"σε %s",past:"%s πριν",s:"λίγα δευτερόλεπτα",m:"ένα λεπτό",mm:"%d λεπτά",h:"μία ώρα",hh:"%d ώρες",d:"μία μέρα",dd:"%d μέρες",M:"ένας μήνας",MM:"%d μήνες",y:"ένας χρόνος",yy:"%d χρόνια"},ordinalParse:/\d{1,2}η/,ordinal:"%dη",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : English (Australia) [en-au]
+//! author : Jared Morse : https://github.com/jarcoal
+a.defineLocale("en-au",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},ordinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(a){var b=a%10,c=1===~~(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : English (Canada) [en-ca]
+//! author : Jonathan Abourbih : https://github.com/jonbca
+a.defineLocale("en-ca",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"YYYY-MM-DD",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},ordinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(a){var b=a%10,c=1===~~(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c}}),
+//! moment.js locale configuration
+//! locale : English (United Kingdom) [en-gb]
+//! author : Chris Gedrim : https://github.com/chrisgedrim
+a.defineLocale("en-gb",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},ordinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(a){var b=a%10,c=1===~~(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : English (Ireland) [en-ie]
+//! author : Chris Cartlidge : https://github.com/chriscartlidge
+a.defineLocale("en-ie",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD-MM-YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},ordinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(a){var b=a%10,c=1===~~(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : English (New Zealand) [en-nz]
+//! author : Luke McGregor : https://github.com/lukemcgregor
+a.defineLocale("en-nz",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},ordinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(a){var b=a%10,c=1===~~(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Esperanto [eo]
+//! author : Colin Dean : https://github.com/colindean
+//! komento: Mi estas malcerta se mi korekte traktis akuzativojn en tiu traduko.
+//!          Se ne, bonvolu korekti kaj avizi min por ke mi povas lerni!
+a.defineLocale("eo",{months:"januaro_februaro_marto_aprilo_majo_junio_julio_aŭgusto_septembro_oktobro_novembro_decembro".split("_"),monthsShort:"jan_feb_mar_apr_maj_jun_jul_aŭg_sep_okt_nov_dec".split("_"),weekdays:"Dimanĉo_Lundo_Mardo_Merkredo_Ĵaŭdo_Vendredo_Sabato".split("_"),weekdaysShort:"Dim_Lun_Mard_Merk_Ĵaŭ_Ven_Sab".split("_"),weekdaysMin:"Di_Lu_Ma_Me_Ĵa_Ve_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"D[-an de] MMMM, YYYY",LLL:"D[-an de] MMMM, YYYY HH:mm",LLLL:"dddd, [la] D[-an de] MMMM, YYYY HH:mm"},meridiemParse:/[ap]\.t\.m/i,isPM:function(a){return"p"===a.charAt(0).toLowerCase()},meridiem:function(a,b,c){return a>11?c?"p.t.m.":"P.T.M.":c?"a.t.m.":"A.T.M."},calendar:{sameDay:"[Hodiaŭ je] LT",nextDay:"[Morgaŭ je] LT",nextWeek:"dddd [je] LT",lastDay:"[Hieraŭ je] LT",lastWeek:"[pasinta] dddd [je] LT",sameElse:"L"},relativeTime:{future:"je %s",past:"antaŭ %s",s:"sekundoj",m:"minuto",mm:"%d minutoj",h:"horo",hh:"%d horoj",d:"tago",//ne 'diurno', ĉar estas uzita por proksimumo
+dd:"%d tagoj",M:"monato",MM:"%d monatoj",y:"jaro",yy:"%d jaroj"},ordinalParse:/\d{1,2}a/,ordinal:"%da",week:{dow:1,// Monday is the first day of the week.
+doy:7}});
+//! moment.js locale configuration
+//! locale : Spanish (Dominican Republic) [es-do]
+var Lg="ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.".split("_"),Mg="ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic".split("_");a.defineLocale("es-do",{months:"enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre".split("_"),monthsShort:function(a,b){return/-MMM-/.test(b)?Mg[a.month()]:Lg[a.month()]},monthsParseExact:!0,weekdays:"domingo_lunes_martes_miércoles_jueves_viernes_sábado".split("_"),weekdaysShort:"dom._lun._mar._mié._jue._vie._sáb.".split("_"),weekdaysMin:"do_lu_ma_mi_ju_vi_sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY h:mm A",LLLL:"dddd, D [de] MMMM [de] YYYY h:mm A"},calendar:{sameDay:function(){return"[hoy a la"+(1!==this.hours()?"s":"")+"] LT"},nextDay:function(){return"[mañana a la"+(1!==this.hours()?"s":"")+"] LT"},nextWeek:function(){return"dddd [a la"+(1!==this.hours()?"s":"")+"] LT"},lastDay:function(){return"[ayer a la"+(1!==this.hours()?"s":"")+"] LT"},lastWeek:function(){return"[el] dddd [pasado a la"+(1!==this.hours()?"s":"")+"] LT"},sameElse:"L"},relativeTime:{future:"en %s",past:"hace %s",s:"unos segundos",m:"un minuto",mm:"%d minutos",h:"una hora",hh:"%d horas",d:"un día",dd:"%d días",M:"un mes",MM:"%d meses",y:"un año",yy:"%d años"},ordinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,// Monday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Spanish [es]
+//! author : Julio Napurí : https://github.com/julionc
+var Ng="ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.".split("_"),Og="ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic".split("_");a.defineLocale("es",{months:"enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre".split("_"),monthsShort:function(a,b){return/-MMM-/.test(b)?Og[a.month()]:Ng[a.month()]},monthsParseExact:!0,weekdays:"domingo_lunes_martes_miércoles_jueves_viernes_sábado".split("_"),weekdaysShort:"dom._lun._mar._mié._jue._vie._sáb.".split("_"),weekdaysMin:"do_lu_ma_mi_ju_vi_sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY H:mm",LLLL:"dddd, D [de] MMMM [de] YYYY H:mm"},calendar:{sameDay:function(){return"[hoy a la"+(1!==this.hours()?"s":"")+"] LT"},nextDay:function(){return"[mañana a la"+(1!==this.hours()?"s":"")+"] LT"},nextWeek:function(){return"dddd [a la"+(1!==this.hours()?"s":"")+"] LT"},lastDay:function(){return"[ayer a la"+(1!==this.hours()?"s":"")+"] LT"},lastWeek:function(){return"[el] dddd [pasado a la"+(1!==this.hours()?"s":"")+"] LT"},sameElse:"L"},relativeTime:{future:"en %s",past:"hace %s",s:"unos segundos",m:"un minuto",mm:"%d minutos",h:"una hora",hh:"%d horas",d:"un día",dd:"%d días",M:"un mes",MM:"%d meses",y:"un año",yy:"%d años"},ordinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),a.defineLocale("et",{months:"jaanuar_veebruar_märts_aprill_mai_juuni_juuli_august_september_oktoober_november_detsember".split("_"),monthsShort:"jaan_veebr_märts_apr_mai_juuni_juuli_aug_sept_okt_nov_dets".split("_"),weekdays:"pühapäev_esmaspäev_teisipäev_kolmapäev_neljapäev_reede_laupäev".split("_"),weekdaysShort:"P_E_T_K_N_R_L".split("_"),weekdaysMin:"P_E_T_K_N_R_L".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[Täna,] LT",nextDay:"[Homme,] LT",nextWeek:"[Järgmine] dddd LT",lastDay:"[Eile,] LT",lastWeek:"[Eelmine] dddd LT",sameElse:"L"},relativeTime:{future:"%s pärast",past:"%s tagasi",s:Ad,m:Ad,mm:Ad,h:Ad,hh:Ad,d:Ad,dd:"%d päeva",M:Ad,MM:Ad,y:Ad,yy:Ad},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Basque [eu]
+//! author : Eneko Illarramendi : https://github.com/eillarra
+a.defineLocale("eu",{months:"urtarrila_otsaila_martxoa_apirila_maiatza_ekaina_uztaila_abuztua_iraila_urria_azaroa_abendua".split("_"),monthsShort:"urt._ots._mar._api._mai._eka._uzt._abu._ira._urr._aza._abe.".split("_"),monthsParseExact:!0,weekdays:"igandea_astelehena_asteartea_asteazkena_osteguna_ostirala_larunbata".split("_"),weekdaysShort:"ig._al._ar._az._og._ol._lr.".split("_"),weekdaysMin:"ig_al_ar_az_og_ol_lr".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"YYYY[ko] MMMM[ren] D[a]",LLL:"YYYY[ko] MMMM[ren] D[a] HH:mm",LLLL:"dddd, YYYY[ko] MMMM[ren] D[a] HH:mm",l:"YYYY-M-D",ll:"YYYY[ko] MMM D[a]",lll:"YYYY[ko] MMM D[a] HH:mm",llll:"ddd, YYYY[ko] MMM D[a] HH:mm"},calendar:{sameDay:"[gaur] LT[etan]",nextDay:"[bihar] LT[etan]",nextWeek:"dddd LT[etan]",lastDay:"[atzo] LT[etan]",lastWeek:"[aurreko] dddd LT[etan]",sameElse:"L"},relativeTime:{future:"%s barru",past:"duela %s",s:"segundo batzuk",m:"minutu bat",mm:"%d minutu",h:"ordu bat",hh:"%d ordu",d:"egun bat",dd:"%d egun",M:"hilabete bat",MM:"%d hilabete",y:"urte bat",yy:"%d urte"},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:7}});
+//! moment.js locale configuration
+//! locale : Persian [fa]
+//! author : Ebrahim Byagowi : https://github.com/ebraminio
+var Pg={1:"۱",2:"۲",3:"۳",4:"۴",5:"۵",6:"۶",7:"۷",8:"۸",9:"۹",0:"۰"},Qg={"۱":"1","۲":"2","۳":"3","۴":"4","۵":"5","۶":"6","۷":"7","۸":"8","۹":"9","۰":"0"};a.defineLocale("fa",{months:"ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر".split("_"),monthsShort:"ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر".split("_"),weekdays:"یک‌شنبه_دوشنبه_سه‌شنبه_چهارشنبه_پنج‌شنبه_جمعه_شنبه".split("_"),weekdaysShort:"یک‌شنبه_دوشنبه_سه‌شنبه_چهارشنبه_پنج‌شنبه_جمعه_شنبه".split("_"),weekdaysMin:"ی_د_س_چ_پ_ج_ش".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},meridiemParse:/قبل از ظهر|بعد از ظهر/,isPM:function(a){return/بعد از ظهر/.test(a)},meridiem:function(a,b,c){return a<12?"قبل از ظهر":"بعد از ظهر"},calendar:{sameDay:"[امروز ساعت] LT",nextDay:"[فردا ساعت] LT",nextWeek:"dddd [ساعت] LT",lastDay:"[دیروز ساعت] LT",lastWeek:"dddd [پیش] [ساعت] LT",sameElse:"L"},relativeTime:{future:"در %s",past:"%s پیش",s:"چندین ثانیه",m:"یک دقیقه",mm:"%d دقیقه",h:"یک ساعت",hh:"%d ساعت",d:"یک روز",dd:"%d روز",M:"یک ماه",MM:"%d ماه",y:"یک سال",yy:"%d سال"},preparse:function(a){return a.replace(/[۰-۹]/g,function(a){return Qg[a]}).replace(/،/g,",")},postformat:function(a){return a.replace(/\d/g,function(a){return Pg[a]}).replace(/,/g,"،")},ordinalParse:/\d{1,2}م/,ordinal:"%dم",week:{dow:6,// Saturday is the first day of the week.
+doy:12}});
+//! moment.js locale configuration
+//! locale : Finnish [fi]
+//! author : Tarmo Aidantausta : https://github.com/bleadof
+var Rg="nolla yksi kaksi kolme neljä viisi kuusi seitsemän kahdeksan yhdeksän".split(" "),Sg=["nolla","yhden","kahden","kolmen","neljän","viiden","kuuden",Rg[7],Rg[8],Rg[9]];a.defineLocale("fi",{months:"tammikuu_helmikuu_maaliskuu_huhtikuu_toukokuu_kesäkuu_heinäkuu_elokuu_syyskuu_lokakuu_marraskuu_joulukuu".split("_"),monthsShort:"tammi_helmi_maalis_huhti_touko_kesä_heinä_elo_syys_loka_marras_joulu".split("_"),weekdays:"sunnuntai_maanantai_tiistai_keskiviikko_torstai_perjantai_lauantai".split("_"),weekdaysShort:"su_ma_ti_ke_to_pe_la".split("_"),weekdaysMin:"su_ma_ti_ke_to_pe_la".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD.MM.YYYY",LL:"Do MMMM[ta] YYYY",LLL:"Do MMMM[ta] YYYY, [klo] HH.mm",LLLL:"dddd, Do MMMM[ta] YYYY, [klo] HH.mm",l:"D.M.YYYY",ll:"Do MMM YYYY",lll:"Do MMM YYYY, [klo] HH.mm",llll:"ddd, Do MMM YYYY, [klo] HH.mm"},calendar:{sameDay:"[tänään] [klo] LT",nextDay:"[huomenna] [klo] LT",nextWeek:"dddd [klo] LT",lastDay:"[eilen] [klo] LT",lastWeek:"[viime] dddd[na] [klo] LT",sameElse:"L"},relativeTime:{future:"%s päästä",past:"%s sitten",s:Bd,m:Bd,mm:Bd,h:Bd,hh:Bd,d:Bd,dd:Bd,M:Bd,MM:Bd,y:Bd,yy:Bd},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Faroese [fo]
+//! author : Ragnar Johannesen : https://github.com/ragnar123
+a.defineLocale("fo",{months:"januar_februar_mars_apríl_mai_juni_juli_august_september_oktober_november_desember".split("_"),monthsShort:"jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des".split("_"),weekdays:"sunnudagur_mánadagur_týsdagur_mikudagur_hósdagur_fríggjadagur_leygardagur".split("_"),weekdaysShort:"sun_mán_týs_mik_hós_frí_ley".split("_"),weekdaysMin:"su_má_tý_mi_hó_fr_le".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D. MMMM, YYYY HH:mm"},calendar:{sameDay:"[Í dag kl.] LT",nextDay:"[Í morgin kl.] LT",nextWeek:"dddd [kl.] LT",lastDay:"[Í gjár kl.] LT",lastWeek:"[síðstu] dddd [kl] LT",sameElse:"L"},relativeTime:{future:"um %s",past:"%s síðani",s:"fá sekund",m:"ein minutt",mm:"%d minuttir",h:"ein tími",hh:"%d tímar",d:"ein dagur",dd:"%d dagar",M:"ein mánaði",MM:"%d mánaðir",y:"eitt ár",yy:"%d ár"},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : French (Canada) [fr-ca]
+//! author : Jonathan Abourbih : https://github.com/jonbca
+a.defineLocale("fr-ca",{months:"janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre".split("_"),monthsShort:"janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.".split("_"),monthsParseExact:!0,weekdays:"dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi".split("_"),weekdaysShort:"dim._lun._mar._mer._jeu._ven._sam.".split("_"),weekdaysMin:"Di_Lu_Ma_Me_Je_Ve_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Aujourd'hui à] LT",nextDay:"[Demain à] LT",nextWeek:"dddd [à] LT",lastDay:"[Hier à] LT",lastWeek:"dddd [dernier à] LT",sameElse:"L"},relativeTime:{future:"dans %s",past:"il y a %s",s:"quelques secondes",m:"une minute",mm:"%d minutes",h:"une heure",hh:"%d heures",d:"un jour",dd:"%d jours",M:"un mois",MM:"%d mois",y:"un an",yy:"%d ans"},ordinalParse:/\d{1,2}(er|e)/,ordinal:function(a){return a+(1===a?"er":"e")}}),
+//! moment.js locale configuration
+//! locale : French (Switzerland) [fr-ch]
+//! author : Gaspard Bucher : https://github.com/gaspard
+a.defineLocale("fr-ch",{months:"janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre".split("_"),monthsShort:"janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.".split("_"),monthsParseExact:!0,weekdays:"dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi".split("_"),weekdaysShort:"dim._lun._mar._mer._jeu._ven._sam.".split("_"),weekdaysMin:"Di_Lu_Ma_Me_Je_Ve_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Aujourd'hui à] LT",nextDay:"[Demain à] LT",nextWeek:"dddd [à] LT",lastDay:"[Hier à] LT",lastWeek:"dddd [dernier à] LT",sameElse:"L"},relativeTime:{future:"dans %s",past:"il y a %s",s:"quelques secondes",m:"une minute",mm:"%d minutes",h:"une heure",hh:"%d heures",d:"un jour",dd:"%d jours",M:"un mois",MM:"%d mois",y:"un an",yy:"%d ans"},ordinalParse:/\d{1,2}(er|e)/,ordinal:function(a){return a+(1===a?"er":"e")},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : French [fr]
+//! author : John Fischer : https://github.com/jfroffice
+a.defineLocale("fr",{months:"janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre".split("_"),monthsShort:"janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.".split("_"),monthsParseExact:!0,weekdays:"dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi".split("_"),weekdaysShort:"dim._lun._mar._mer._jeu._ven._sam.".split("_"),weekdaysMin:"Di_Lu_Ma_Me_Je_Ve_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Aujourd'hui à] LT",nextDay:"[Demain à] LT",nextWeek:"dddd [à] LT",lastDay:"[Hier à] LT",lastWeek:"dddd [dernier à] LT",sameElse:"L"},relativeTime:{future:"dans %s",past:"il y a %s",s:"quelques secondes",m:"une minute",mm:"%d minutes",h:"une heure",hh:"%d heures",d:"un jour",dd:"%d jours",M:"un mois",MM:"%d mois",y:"un an",yy:"%d ans"},ordinalParse:/\d{1,2}(er|)/,ordinal:function(a){return a+(1===a?"er":"")},week:{dow:1,// Monday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Frisian [fy]
+//! author : Robin van der Vliet : https://github.com/robin0van0der0v
+var Tg="jan._feb._mrt._apr._mai_jun._jul._aug._sep._okt._nov._des.".split("_"),Ug="jan_feb_mrt_apr_mai_jun_jul_aug_sep_okt_nov_des".split("_");a.defineLocale("fy",{months:"jannewaris_febrewaris_maart_april_maaie_juny_july_augustus_septimber_oktober_novimber_desimber".split("_"),monthsShort:function(a,b){return/-MMM-/.test(b)?Ug[a.month()]:Tg[a.month()]},monthsParseExact:!0,weekdays:"snein_moandei_tiisdei_woansdei_tongersdei_freed_sneon".split("_"),weekdaysShort:"si._mo._ti._wo._to._fr._so.".split("_"),weekdaysMin:"Si_Mo_Ti_Wo_To_Fr_So".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD-MM-YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[hjoed om] LT",nextDay:"[moarn om] LT",nextWeek:"dddd [om] LT",lastDay:"[juster om] LT",lastWeek:"[ôfrûne] dddd [om] LT",sameElse:"L"},relativeTime:{future:"oer %s",past:"%s lyn",s:"in pear sekonden",m:"ien minút",mm:"%d minuten",h:"ien oere",hh:"%d oeren",d:"ien dei",dd:"%d dagen",M:"ien moanne",MM:"%d moannen",y:"ien jier",yy:"%d jierren"},ordinalParse:/\d{1,2}(ste|de)/,ordinal:function(a){return a+(1===a||8===a||a>=20?"ste":"de")},week:{dow:1,// Monday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Scottish Gaelic [gd]
+//! author : Jon Ashdown : https://github.com/jonashdown
+var Vg=["Am Faoilleach","An Gearran","Am Màrt","An Giblean","An Cèitean","An t-Ògmhios","An t-Iuchar","An Lùnastal","An t-Sultain","An Dàmhair","An t-Samhain","An Dùbhlachd"],Wg=["Faoi","Gear","Màrt","Gibl","Cèit","Ògmh","Iuch","Lùn","Sult","Dàmh","Samh","Dùbh"],Xg=["Didòmhnaich","Diluain","Dimàirt","Diciadain","Diardaoin","Dihaoine","Disathairne"],Yg=["Did","Dil","Dim","Dic","Dia","Dih","Dis"],Zg=["Dò","Lu","Mà","Ci","Ar","Ha","Sa"];a.defineLocale("gd",{months:Vg,monthsShort:Wg,monthsParseExact:!0,weekdays:Xg,weekdaysShort:Yg,weekdaysMin:Zg,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[An-diugh aig] LT",nextDay:"[A-màireach aig] LT",nextWeek:"dddd [aig] LT",lastDay:"[An-dè aig] LT",lastWeek:"dddd [seo chaidh] [aig] LT",sameElse:"L"},relativeTime:{future:"ann an %s",past:"bho chionn %s",s:"beagan diogan",m:"mionaid",mm:"%d mionaidean",h:"uair",hh:"%d uairean",d:"latha",dd:"%d latha",M:"mìos",MM:"%d mìosan",y:"bliadhna",yy:"%d bliadhna"},ordinalParse:/\d{1,2}(d|na|mh)/,ordinal:function(a){var b=1===a?"d":a%10===2?"na":"mh";return a+b},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Galician [gl]
+//! author : Juan G. Hurtado : https://github.com/juanghurtado
+a.defineLocale("gl",{months:"xaneiro_febreiro_marzo_abril_maio_xuño_xullo_agosto_setembro_outubro_novembro_decembro".split("_"),monthsShort:"xan._feb._mar._abr._mai._xuñ._xul._ago._set._out._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"domingo_luns_martes_mércores_xoves_venres_sábado".split("_"),weekdaysShort:"dom._lun._mar._mér._xov._ven._sáb.".split("_"),weekdaysMin:"do_lu_ma_mé_xo_ve_sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY H:mm",LLLL:"dddd, D [de] MMMM [de] YYYY H:mm"},calendar:{sameDay:function(){return"[hoxe "+(1!==this.hours()?"ás":"á")+"] LT"},nextDay:function(){return"[mañá "+(1!==this.hours()?"ás":"á")+"] LT"},nextWeek:function(){return"dddd ["+(1!==this.hours()?"ás":"a")+"] LT"},lastDay:function(){return"[onte "+(1!==this.hours()?"á":"a")+"] LT"},lastWeek:function(){return"[o] dddd [pasado "+(1!==this.hours()?"ás":"a")+"] LT"},sameElse:"L"},relativeTime:{future:function(a){return 0===a.indexOf("un")?"n"+a:"en "+a},past:"hai %s",s:"uns segundos",m:"un minuto",mm:"%d minutos",h:"unha hora",hh:"%d horas",d:"un día",dd:"%d días",M:"un mes",MM:"%d meses",y:"un ano",yy:"%d anos"},ordinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Hebrew [he]
+//! author : Tomer Cohen : https://github.com/tomer
+//! author : Moshe Simantov : https://github.com/DevelopmentIL
+//! author : Tal Ater : https://github.com/TalAter
+a.defineLocale("he",{months:"ינואר_פברואר_מרץ_אפריל_מאי_יוני_יולי_אוגוסט_ספטמבר_אוקטובר_נובמבר_דצמבר".split("_"),monthsShort:"ינו׳_פבר׳_מרץ_אפר׳_מאי_יוני_יולי_אוג׳_ספט׳_אוק׳_נוב׳_דצמ׳".split("_"),weekdays:"ראשון_שני_שלישי_רביעי_חמישי_שישי_שבת".split("_"),weekdaysShort:"א׳_ב׳_ג׳_ד׳_ה׳_ו׳_ש׳".split("_"),weekdaysMin:"א_ב_ג_ד_ה_ו_ש".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D [ב]MMMM YYYY",LLL:"D [ב]MMMM YYYY HH:mm",LLLL:"dddd, D [ב]MMMM YYYY HH:mm",l:"D/M/YYYY",ll:"D MMM YYYY",lll:"D MMM YYYY HH:mm",llll:"ddd, D MMM YYYY HH:mm"},calendar:{sameDay:"[היום ב־]LT",nextDay:"[מחר ב־]LT",nextWeek:"dddd [בשעה] LT",lastDay:"[אתמול ב־]LT",lastWeek:"[ביום] dddd [האחרון בשעה] LT",sameElse:"L"},relativeTime:{future:"בעוד %s",past:"לפני %s",s:"מספר שניות",m:"דקה",mm:"%d דקות",h:"שעה",hh:function(a){return 2===a?"שעתיים":a+" שעות"},d:"יום",dd:function(a){return 2===a?"יומיים":a+" ימים"},M:"חודש",MM:function(a){return 2===a?"חודשיים":a+" חודשים"},y:"שנה",yy:function(a){return 2===a?"שנתיים":a%10===0&&10!==a?a+" שנה":a+" שנים"}},meridiemParse:/אחה"צ|לפנה"צ|אחרי הצהריים|לפני הצהריים|לפנות בוקר|בבוקר|בערב/i,isPM:function(a){return/^(אחה"צ|אחרי הצהריים|בערב)$/.test(a)},meridiem:function(a,b,c){return a<5?"לפנות בוקר":a<10?"בבוקר":a<12?c?'לפנה"צ':"לפני הצהריים":a<18?c?'אחה"צ':"אחרי הצהריים":"בערב"}});
+//! moment.js locale configuration
+//! locale : Hindi [hi]
+//! author : Mayank Singhal : https://github.com/mayanksinghal
+var $g={1:"१",2:"२",3:"३",4:"४",5:"५",6:"६",7:"७",8:"८",9:"९",0:"०"},_g={"१":"1","२":"2","३":"3","४":"4","५":"5","६":"6","७":"7","८":"8","९":"9","०":"0"};a.defineLocale("hi",{months:"जनवरी_फ़रवरी_मार्च_अप्रैल_मई_जून_जुलाई_अगस्त_सितम्बर_अक्टूबर_नवम्बर_दिसम्बर".split("_"),monthsShort:"जन._फ़र._मार्च_अप्रै._मई_जून_जुल._अग._सित._अक्टू._नव._दिस.".split("_"),monthsParseExact:!0,weekdays:"रविवार_सोमवार_मंगलवार_बुधवार_गुरूवार_शुक्रवार_शनिवार".split("_"),weekdaysShort:"रवि_सोम_मंगल_बुध_गुरू_शुक्र_शनि".split("_"),weekdaysMin:"र_सो_मं_बु_गु_शु_श".split("_"),longDateFormat:{LT:"A h:mm बजे",LTS:"A h:mm:ss बजे",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm बजे",LLLL:"dddd, D MMMM YYYY, A h:mm बजे"},calendar:{sameDay:"[आज] LT",nextDay:"[कल] LT",nextWeek:"dddd, LT",lastDay:"[कल] LT",lastWeek:"[पिछले] dddd, LT",sameElse:"L"},relativeTime:{future:"%s में",past:"%s पहले",s:"कुछ ही क्षण",m:"एक मिनट",mm:"%d मिनट",h:"एक घंटा",hh:"%d घंटे",d:"एक दिन",dd:"%d दिन",M:"एक महीने",MM:"%d महीने",y:"एक वर्ष",yy:"%d वर्ष"},preparse:function(a){return a.replace(/[१२३४५६७८९०]/g,function(a){return _g[a]})},postformat:function(a){return a.replace(/\d/g,function(a){return $g[a]})},
+// Hindi notation for meridiems are quite fuzzy in practice. While there exists
+// a rigid notion of a 'Pahar' it is not used as rigidly in modern Hindi.
+meridiemParse:/रात|सुबह|दोपहर|शाम/,meridiemHour:function(a,b){return 12===a&&(a=0),"रात"===b?a<4?a:a+12:"सुबह"===b?a:"दोपहर"===b?a>=10?a:a+12:"शाम"===b?a+12:void 0},meridiem:function(a,b,c){return a<4?"रात":a<10?"सुबह":a<17?"दोपहर":a<20?"शाम":"रात"},week:{dow:0,// Sunday is the first day of the week.
+doy:6}}),a.defineLocale("hr",{months:{format:"siječnja_veljače_ožujka_travnja_svibnja_lipnja_srpnja_kolovoza_rujna_listopada_studenoga_prosinca".split("_"),standalone:"siječanj_veljača_ožujak_travanj_svibanj_lipanj_srpanj_kolovoz_rujan_listopad_studeni_prosinac".split("_")},monthsShort:"sij._velj._ožu._tra._svi._lip._srp._kol._ruj._lis._stu._pro.".split("_"),monthsParseExact:!0,weekdays:"nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota".split("_"),weekdaysShort:"ned._pon._uto._sri._čet._pet._sub.".split("_"),weekdaysMin:"ne_po_ut_sr_če_pe_su".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[danas u] LT",nextDay:"[sutra u] LT",nextWeek:function(){switch(this.day()){case 0:return"[u] [nedjelju] [u] LT";case 3:return"[u] [srijedu] [u] LT";case 6:return"[u] [subotu] [u] LT";case 1:case 2:case 4:case 5:return"[u] dddd [u] LT"}},lastDay:"[jučer u] LT",lastWeek:function(){switch(this.day()){case 0:case 3:return"[prošlu] dddd [u] LT";case 6:return"[prošle] [subote] [u] LT";case 1:case 2:case 4:case 5:return"[prošli] dddd [u] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"prije %s",s:"par sekundi",m:Dd,mm:Dd,h:Dd,hh:Dd,d:"dan",dd:Dd,M:"mjesec",MM:Dd,y:"godinu",yy:Dd},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:7}});
+//! moment.js locale configuration
+//! locale : Hungarian [hu]
+//! author : Adam Brunner : https://github.com/adambrunner
+var ah="vasárnap hétfőn kedden szerdán csütörtökön pénteken szombaton".split(" ");a.defineLocale("hu",{months:"január_február_március_április_május_június_július_augusztus_szeptember_október_november_december".split("_"),monthsShort:"jan_feb_márc_ápr_máj_jún_júl_aug_szept_okt_nov_dec".split("_"),weekdays:"vasárnap_hétfő_kedd_szerda_csütörtök_péntek_szombat".split("_"),weekdaysShort:"vas_hét_kedd_sze_csüt_pén_szo".split("_"),weekdaysMin:"v_h_k_sze_cs_p_szo".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"YYYY.MM.DD.",LL:"YYYY. MMMM D.",LLL:"YYYY. MMMM D. H:mm",LLLL:"YYYY. MMMM D., dddd H:mm"},meridiemParse:/de|du/i,isPM:function(a){return"u"===a.charAt(1).toLowerCase()},meridiem:function(a,b,c){return a<12?c===!0?"de":"DE":c===!0?"du":"DU"},calendar:{sameDay:"[ma] LT[-kor]",nextDay:"[holnap] LT[-kor]",nextWeek:function(){return Fd.call(this,!0)},lastDay:"[tegnap] LT[-kor]",lastWeek:function(){return Fd.call(this,!1)},sameElse:"L"},relativeTime:{future:"%s múlva",past:"%s",s:Ed,m:Ed,mm:Ed,h:Ed,hh:Ed,d:Ed,dd:Ed,M:Ed,MM:Ed,y:Ed,yy:Ed},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Armenian [hy-am]
+//! author : Armendarabyan : https://github.com/armendarabyan
+a.defineLocale("hy-am",{months:{format:"հունվարի_փետրվարի_մարտի_ապրիլի_մայիսի_հունիսի_հուլիսի_օգոստոսի_սեպտեմբերի_հոկտեմբերի_նոյեմբերի_դեկտեմբերի".split("_"),standalone:"հունվար_փետրվար_մարտ_ապրիլ_մայիս_հունիս_հուլիս_օգոստոս_սեպտեմբեր_հոկտեմբեր_նոյեմբեր_դեկտեմբեր".split("_")},monthsShort:"հնվ_փտր_մրտ_ապր_մյս_հնս_հլս_օգս_սպտ_հկտ_նմբ_դկտ".split("_"),weekdays:"կիրակի_երկուշաբթի_երեքշաբթի_չորեքշաբթի_հինգշաբթի_ուրբաթ_շաբաթ".split("_"),weekdaysShort:"կրկ_երկ_երք_չրք_հնգ_ուրբ_շբթ".split("_"),weekdaysMin:"կրկ_երկ_երք_չրք_հնգ_ուրբ_շբթ".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY թ.",LLL:"D MMMM YYYY թ., HH:mm",LLLL:"dddd, D MMMM YYYY թ., HH:mm"},calendar:{sameDay:"[այսօր] LT",nextDay:"[վաղը] LT",lastDay:"[երեկ] LT",nextWeek:function(){return"dddd [օրը ժամը] LT"},lastWeek:function(){return"[անցած] dddd [օրը ժամը] LT"},sameElse:"L"},relativeTime:{future:"%s հետո",past:"%s առաջ",s:"մի քանի վայրկյան",m:"րոպե",mm:"%d րոպե",h:"ժամ",hh:"%d ժամ",d:"օր",dd:"%d օր",M:"ամիս",MM:"%d ամիս",y:"տարի",yy:"%d տարի"},meridiemParse:/գիշերվա|առավոտվա|ցերեկվա|երեկոյան/,isPM:function(a){return/^(ցերեկվա|երեկոյան)$/.test(a)},meridiem:function(a){return a<4?"գիշերվա":a<12?"առավոտվա":a<17?"ցերեկվա":"երեկոյան"},ordinalParse:/\d{1,2}|\d{1,2}-(ին|րդ)/,ordinal:function(a,b){switch(b){case"DDD":case"w":case"W":case"DDDo":return 1===a?a+"-ին":a+"-րդ";default:return a}},week:{dow:1,// Monday is the first day of the week.
+doy:7}}),
+//! moment.js locale configuration
+//! locale : Indonesian [id]
+//! author : Mohammad Satrio Utomo : https://github.com/tyok
+//! reference: http://id.wikisource.org/wiki/Pedoman_Umum_Ejaan_Bahasa_Indonesia_yang_Disempurnakan
+a.defineLocale("id",{months:"Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_November_Desember".split("_"),monthsShort:"Jan_Feb_Mar_Apr_Mei_Jun_Jul_Ags_Sep_Okt_Nov_Des".split("_"),weekdays:"Minggu_Senin_Selasa_Rabu_Kamis_Jumat_Sabtu".split("_"),weekdaysShort:"Min_Sen_Sel_Rab_Kam_Jum_Sab".split("_"),weekdaysMin:"Mg_Sn_Sl_Rb_Km_Jm_Sb".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/pagi|siang|sore|malam/,meridiemHour:function(a,b){return 12===a&&(a=0),"pagi"===b?a:"siang"===b?a>=11?a:a+12:"sore"===b||"malam"===b?a+12:void 0},meridiem:function(a,b,c){return a<11?"pagi":a<15?"siang":a<19?"sore":"malam"},calendar:{sameDay:"[Hari ini pukul] LT",nextDay:"[Besok pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kemarin pukul] LT",lastWeek:"dddd [lalu pukul] LT",sameElse:"L"},relativeTime:{future:"dalam %s",past:"%s yang lalu",s:"beberapa detik",m:"semenit",mm:"%d menit",h:"sejam",hh:"%d jam",d:"sehari",dd:"%d hari",M:"sebulan",MM:"%d bulan",y:"setahun",yy:"%d tahun"},week:{dow:1,// Monday is the first day of the week.
+doy:7}}),a.defineLocale("is",{months:"janúar_febrúar_mars_apríl_maí_júní_júlí_ágúst_september_október_nóvember_desember".split("_"),monthsShort:"jan_feb_mar_apr_maí_jún_júl_ágú_sep_okt_nóv_des".split("_"),weekdays:"sunnudagur_mánudagur_þriðjudagur_miðvikudagur_fimmtudagur_föstudagur_laugardagur".split("_"),weekdaysShort:"sun_mán_þri_mið_fim_fös_lau".split("_"),weekdaysMin:"Su_Má_Þr_Mi_Fi_Fö_La".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY [kl.] H:mm",LLLL:"dddd, D. MMMM YYYY [kl.] H:mm"},calendar:{sameDay:"[í dag kl.] LT",nextDay:"[á morgun kl.] LT",nextWeek:"dddd [kl.] LT",lastDay:"[í gær kl.] LT",lastWeek:"[síðasta] dddd [kl.] LT",sameElse:"L"},relativeTime:{future:"eftir %s",past:"fyrir %s síðan",s:Hd,m:Hd,mm:Hd,h:"klukkustund",hh:Hd,d:Hd,dd:Hd,M:Hd,MM:Hd,y:Hd,yy:Hd},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Italian [it]
+//! author : Lorenzo : https://github.com/aliem
+//! author: Mattia Larentis: https://github.com/nostalgiaz
+a.defineLocale("it",{months:"gennaio_febbraio_marzo_aprile_maggio_giugno_luglio_agosto_settembre_ottobre_novembre_dicembre".split("_"),monthsShort:"gen_feb_mar_apr_mag_giu_lug_ago_set_ott_nov_dic".split("_"),weekdays:"Domenica_Lunedì_Martedì_Mercoledì_Giovedì_Venerdì_Sabato".split("_"),weekdaysShort:"Dom_Lun_Mar_Mer_Gio_Ven_Sab".split("_"),weekdaysMin:"Do_Lu_Ma_Me_Gi_Ve_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Oggi alle] LT",nextDay:"[Domani alle] LT",nextWeek:"dddd [alle] LT",lastDay:"[Ieri alle] LT",lastWeek:function(){switch(this.day()){case 0:return"[la scorsa] dddd [alle] LT";default:return"[lo scorso] dddd [alle] LT"}},sameElse:"L"},relativeTime:{future:function(a){return(/^[0-9].+$/.test(a)?"tra":"in")+" "+a},past:"%s fa",s:"alcuni secondi",m:"un minuto",mm:"%d minuti",h:"un'ora",hh:"%d ore",d:"un giorno",dd:"%d giorni",M:"un mese",MM:"%d mesi",y:"un anno",yy:"%d anni"},ordinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Japanese [ja]
+//! author : LI Long : https://github.com/baryon
+a.defineLocale("ja",{months:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"日曜日_月曜日_火曜日_水曜日_木曜日_金曜日_土曜日".split("_"),weekdaysShort:"日_月_火_水_木_金_土".split("_"),weekdaysMin:"日_月_火_水_木_金_土".split("_"),longDateFormat:{LT:"Ah時m分",LTS:"Ah時m分s秒",L:"YYYY/MM/DD",LL:"YYYY年M月D日",LLL:"YYYY年M月D日Ah時m分",LLLL:"YYYY年M月D日Ah時m分 dddd"},meridiemParse:/午前|午後/i,isPM:function(a){return"午後"===a},meridiem:function(a,b,c){return a<12?"午前":"午後"},calendar:{sameDay:"[今日] LT",nextDay:"[明日] LT",nextWeek:"[来週]dddd LT",lastDay:"[昨日] LT",lastWeek:"[前週]dddd LT",sameElse:"L"},ordinalParse:/\d{1,2}日/,ordinal:function(a,b){switch(b){case"d":case"D":case"DDD":return a+"日";default:return a}},relativeTime:{future:"%s後",past:"%s前",s:"数秒",m:"1分",mm:"%d分",h:"1時間",hh:"%d時間",d:"1日",dd:"%d日",M:"1ヶ月",MM:"%dヶ月",y:"1年",yy:"%d年"}}),
+//! moment.js locale configuration
+//! locale : Javanese [jv]
+//! author : Rony Lantip : https://github.com/lantip
+//! reference: http://jv.wikipedia.org/wiki/Basa_Jawa
+a.defineLocale("jv",{months:"Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_Nopember_Desember".split("_"),monthsShort:"Jan_Feb_Mar_Apr_Mei_Jun_Jul_Ags_Sep_Okt_Nop_Des".split("_"),weekdays:"Minggu_Senen_Seloso_Rebu_Kemis_Jemuwah_Septu".split("_"),weekdaysShort:"Min_Sen_Sel_Reb_Kem_Jem_Sep".split("_"),weekdaysMin:"Mg_Sn_Sl_Rb_Km_Jm_Sp".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/enjing|siyang|sonten|ndalu/,meridiemHour:function(a,b){return 12===a&&(a=0),"enjing"===b?a:"siyang"===b?a>=11?a:a+12:"sonten"===b||"ndalu"===b?a+12:void 0},meridiem:function(a,b,c){return a<11?"enjing":a<15?"siyang":a<19?"sonten":"ndalu"},calendar:{sameDay:"[Dinten puniko pukul] LT",nextDay:"[Mbenjang pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kala wingi pukul] LT",lastWeek:"dddd [kepengker pukul] LT",sameElse:"L"},relativeTime:{future:"wonten ing %s",past:"%s ingkang kepengker",s:"sawetawis detik",m:"setunggal menit",mm:"%d menit",h:"setunggal jam",hh:"%d jam",d:"sedinten",dd:"%d dinten",M:"sewulan",MM:"%d wulan",y:"setaun",yy:"%d taun"},week:{dow:1,// Monday is the first day of the week.
+doy:7}}),
+//! moment.js locale configuration
+//! locale : Georgian [ka]
+//! author : Irakli Janiashvili : https://github.com/irakli-janiashvili
+a.defineLocale("ka",{months:{standalone:"იანვარი_თებერვალი_მარტი_აპრილი_მაისი_ივნისი_ივლისი_აგვისტო_სექტემბერი_ოქტომბერი_ნოემბერი_დეკემბერი".split("_"),format:"იანვარს_თებერვალს_მარტს_აპრილის_მაისს_ივნისს_ივლისს_აგვისტს_სექტემბერს_ოქტომბერს_ნოემბერს_დეკემბერს".split("_")},monthsShort:"იან_თებ_მარ_აპრ_მაი_ივნ_ივლ_აგვ_სექ_ოქტ_ნოე_დეკ".split("_"),weekdays:{standalone:"კვირა_ორშაბათი_სამშაბათი_ოთხშაბათი_ხუთშაბათი_პარასკევი_შაბათი".split("_"),format:"კვირას_ორშაბათს_სამშაბათს_ოთხშაბათს_ხუთშაბათს_პარასკევს_შაბათს".split("_"),isFormat:/(წინა|შემდეგ)/},weekdaysShort:"კვი_ორშ_სამ_ოთხ_ხუთ_პარ_შაბ".split("_"),weekdaysMin:"კვ_ორ_სა_ოთ_ხუ_პა_შა".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[დღეს] LT[-ზე]",nextDay:"[ხვალ] LT[-ზე]",lastDay:"[გუშინ] LT[-ზე]",nextWeek:"[შემდეგ] dddd LT[-ზე]",lastWeek:"[წინა] dddd LT-ზე",sameElse:"L"},relativeTime:{future:function(a){return/(წამი|წუთი|საათი|წელი)/.test(a)?a.replace(/ი$/,"ში"):a+"ში"},past:function(a){return/(წამი|წუთი|საათი|დღე|თვე)/.test(a)?a.replace(/(ი|ე)$/,"ის წინ"):/წელი/.test(a)?a.replace(/წელი$/,"წლის წინ"):void 0},s:"რამდენიმე წამი",m:"წუთი",mm:"%d წუთი",h:"საათი",hh:"%d საათი",d:"დღე",dd:"%d დღე",M:"თვე",MM:"%d თვე",y:"წელი",yy:"%d წელი"},ordinalParse:/0|1-ლი|მე-\d{1,2}|\d{1,2}-ე/,ordinal:function(a){return 0===a?a:1===a?a+"-ლი":a<20||a<=100&&a%20===0||a%100===0?"მე-"+a:a+"-ე"},week:{dow:1,doy:7}});
+//! moment.js locale configuration
+//! locale : Kazakh [kk]
+//! authors : Nurlan Rakhimzhanov : https://github.com/nurlan
+var bh={0:"-ші",1:"-ші",2:"-ші",3:"-ші",4:"-ші",5:"-ші",6:"-шы",7:"-ші",8:"-ші",9:"-шы",10:"-шы",20:"-шы",30:"-шы",40:"-шы",50:"-ші",60:"-шы",70:"-ші",80:"-ші",90:"-шы",100:"-ші"};a.defineLocale("kk",{months:"қаңтар_ақпан_наурыз_сәуір_мамыр_маусым_шілде_тамыз_қыркүйек_қазан_қараша_желтоқсан".split("_"),monthsShort:"қаң_ақп_нау_сәу_мам_мау_шіл_там_қыр_қаз_қар_жел".split("_"),weekdays:"жексенбі_дүйсенбі_сейсенбі_сәрсенбі_бейсенбі_жұма_сенбі".split("_"),weekdaysShort:"жек_дүй_сей_сәр_бей_жұм_сен".split("_"),weekdaysMin:"жк_дй_сй_ср_бй_жм_сн".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Бүгін сағат] LT",nextDay:"[Ертең сағат] LT",nextWeek:"dddd [сағат] LT",lastDay:"[Кеше сағат] LT",lastWeek:"[Өткен аптаның] dddd [сағат] LT",sameElse:"L"},relativeTime:{future:"%s ішінде",past:"%s бұрын",s:"бірнеше секунд",m:"бір минут",mm:"%d минут",h:"бір сағат",hh:"%d сағат",d:"бір күн",dd:"%d күн",M:"бір ай",MM:"%d ай",y:"бір жыл",yy:"%d жыл"},ordinalParse:/\d{1,2}-(ші|шы)/,ordinal:function(a){var b=a%10,c=a>=100?100:null;return a+(bh[a]||bh[b]||bh[c])},week:{dow:1,// Monday is the first day of the week.
+doy:7}}),
+//! moment.js locale configuration
+//! locale : Cambodian [km]
+//! author : Kruy Vanna : https://github.com/kruyvanna
+a.defineLocale("km",{months:"មករា_កុម្ភៈ_មីនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ".split("_"),monthsShort:"មករា_កុម្ភៈ_មីនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ".split("_"),weekdays:"អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍".split("_"),weekdaysShort:"អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍".split("_"),weekdaysMin:"អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[ថ្ងៃនេះ ម៉ោង] LT",nextDay:"[ស្អែក ម៉ោង] LT",nextWeek:"dddd [ម៉ោង] LT",lastDay:"[ម្សិលមិញ ម៉ោង] LT",lastWeek:"dddd [សប្តាហ៍មុន] [ម៉ោង] LT",sameElse:"L"},relativeTime:{future:"%sទៀត",past:"%sមុន",s:"ប៉ុន្មានវិនាទី",m:"មួយនាទី",mm:"%d នាទី",h:"មួយម៉ោង",hh:"%d ម៉ោង",d:"មួយថ្ងៃ",dd:"%d ថ្ងៃ",M:"មួយខែ",MM:"%d ខែ",y:"មួយឆ្នាំ",yy:"%d ឆ្នាំ"},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Korean [ko]
+//! author : Kyungwook, Park : https://github.com/kyungw00k
+//! author : Jeeeyul Lee <jeeeyul@gmail.com>
+a.defineLocale("ko",{months:"1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월".split("_"),monthsShort:"1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월".split("_"),weekdays:"일요일_월요일_화요일_수요일_목요일_금요일_토요일".split("_"),weekdaysShort:"일_월_화_수_목_금_토".split("_"),weekdaysMin:"일_월_화_수_목_금_토".split("_"),longDateFormat:{LT:"A h시 m분",LTS:"A h시 m분 s초",L:"YYYY.MM.DD",LL:"YYYY년 MMMM D일",LLL:"YYYY년 MMMM D일 A h시 m분",LLLL:"YYYY년 MMMM D일 dddd A h시 m분"},calendar:{sameDay:"오늘 LT",nextDay:"내일 LT",nextWeek:"dddd LT",lastDay:"어제 LT",lastWeek:"지난주 dddd LT",sameElse:"L"},relativeTime:{future:"%s 후",past:"%s 전",s:"몇 초",ss:"%d초",m:"일분",mm:"%d분",h:"한 시간",hh:"%d시간",d:"하루",dd:"%d일",M:"한 달",MM:"%d달",y:"일 년",yy:"%d년"},ordinalParse:/\d{1,2}일/,ordinal:"%d일",meridiemParse:/오전|오후/,isPM:function(a){return"오후"===a},meridiem:function(a,b,c){return a<12?"오전":"오후"}});
+//! moment.js locale configuration
+//! locale : Kyrgyz [ky]
+//! author : Chyngyz Arystan uulu : https://github.com/chyngyz
+var ch={0:"-чү",1:"-чи",2:"-чи",3:"-чү",4:"-чү",5:"-чи",6:"-чы",7:"-чи",8:"-чи",9:"-чу",10:"-чу",20:"-чы",30:"-чу",40:"-чы",50:"-чү",60:"-чы",70:"-чи",80:"-чи",90:"-чу",100:"-чү"};a.defineLocale("ky",{months:"январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь".split("_"),monthsShort:"янв_фев_март_апр_май_июнь_июль_авг_сен_окт_ноя_дек".split("_"),weekdays:"Жекшемби_Дүйшөмбү_Шейшемби_Шаршемби_Бейшемби_Жума_Ишемби".split("_"),weekdaysShort:"Жек_Дүй_Шей_Шар_Бей_Жум_Ише".split("_"),weekdaysMin:"Жк_Дй_Шй_Шр_Бй_Жм_Иш".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Бүгүн саат] LT",nextDay:"[Эртең саат] LT",nextWeek:"dddd [саат] LT",lastDay:"[Кече саат] LT",lastWeek:"[Өткен аптанын] dddd [күнү] [саат] LT",sameElse:"L"},relativeTime:{future:"%s ичинде",past:"%s мурун",s:"бирнече секунд",m:"бир мүнөт",mm:"%d мүнөт",h:"бир саат",hh:"%d саат",d:"бир күн",dd:"%d күн",M:"бир ай",MM:"%d ай",y:"бир жыл",yy:"%d жыл"},ordinalParse:/\d{1,2}-(чи|чы|чү|чу)/,ordinal:function(a){var b=a%10,c=a>=100?100:null;return a+(ch[a]||ch[b]||ch[c])},week:{dow:1,// Monday is the first day of the week.
+doy:7}}),a.defineLocale("lb",{months:"Januar_Februar_Mäerz_Abrëll_Mee_Juni_Juli_August_September_Oktober_November_Dezember".split("_"),monthsShort:"Jan._Febr._Mrz._Abr._Mee_Jun._Jul._Aug._Sept._Okt._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Sonndeg_Méindeg_Dënschdeg_Mëttwoch_Donneschdeg_Freideg_Samschdeg".split("_"),weekdaysShort:"So._Mé._Dë._Më._Do._Fr._Sa.".split("_"),weekdaysMin:"So_Mé_Dë_Më_Do_Fr_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm [Auer]",LTS:"H:mm:ss [Auer]",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm [Auer]",LLLL:"dddd, D. MMMM YYYY H:mm [Auer]"},calendar:{sameDay:"[Haut um] LT",sameElse:"L",nextDay:"[Muer um] LT",nextWeek:"dddd [um] LT",lastDay:"[Gëschter um] LT",lastWeek:function(){
+// Different date string for 'Dënschdeg' (Tuesday) and 'Donneschdeg' (Thursday) due to phonological rule
+switch(this.day()){case 2:case 4:return"[Leschten] dddd [um] LT";default:return"[Leschte] dddd [um] LT"}}},relativeTime:{future:Jd,past:Kd,s:"e puer Sekonnen",m:Id,mm:"%d Minutten",h:Id,hh:"%d Stonnen",d:Id,dd:"%d Deeg",M:Id,MM:"%d Méint",y:Id,yy:"%d Joer"},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Lao [lo]
+//! author : Ryan Hart : https://github.com/ryanhart2
+a.defineLocale("lo",{months:"ມັງກອນ_ກຸມພາ_ມີນາ_ເມສາ_ພຶດສະພາ_ມິຖຸນາ_ກໍລະກົດ_ສິງຫາ_ກັນຍາ_ຕຸລາ_ພະຈິກ_ທັນວາ".split("_"),monthsShort:"ມັງກອນ_ກຸມພາ_ມີນາ_ເມສາ_ພຶດສະພາ_ມິຖຸນາ_ກໍລະກົດ_ສິງຫາ_ກັນຍາ_ຕຸລາ_ພະຈິກ_ທັນວາ".split("_"),weekdays:"ອາທິດ_ຈັນ_ອັງຄານ_ພຸດ_ພະຫັດ_ສຸກ_ເສົາ".split("_"),weekdaysShort:"ທິດ_ຈັນ_ອັງຄານ_ພຸດ_ພະຫັດ_ສຸກ_ເສົາ".split("_"),weekdaysMin:"ທ_ຈ_ອຄ_ພ_ພຫ_ສກ_ສ".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"ວັນdddd D MMMM YYYY HH:mm"},meridiemParse:/ຕອນເຊົ້າ|ຕອນແລງ/,isPM:function(a){return"ຕອນແລງ"===a},meridiem:function(a,b,c){return a<12?"ຕອນເຊົ້າ":"ຕອນແລງ"},calendar:{sameDay:"[ມື້ນີ້ເວລາ] LT",nextDay:"[ມື້ອື່ນເວລາ] LT",nextWeek:"[ວັນ]dddd[ໜ້າເວລາ] LT",lastDay:"[ມື້ວານນີ້ເວລາ] LT",lastWeek:"[ວັນ]dddd[ແລ້ວນີ້ເວລາ] LT",sameElse:"L"},relativeTime:{future:"ອີກ %s",past:"%sຜ່ານມາ",s:"ບໍ່ເທົ່າໃດວິນາທີ",m:"1 ນາທີ",mm:"%d ນາທີ",h:"1 ຊົ່ວໂມງ",hh:"%d ຊົ່ວໂມງ",d:"1 ມື້",dd:"%d ມື້",M:"1 ເດືອນ",MM:"%d ເດືອນ",y:"1 ປີ",yy:"%d ປີ"},ordinalParse:/(ທີ່)\d{1,2}/,ordinal:function(a){return"ທີ່"+a}});
+//! moment.js locale configuration
+//! locale : Lithuanian [lt]
+//! author : Mindaugas Mozūras : https://github.com/mmozuras
+var dh={m:"minutė_minutės_minutę",mm:"minutės_minučių_minutes",h:"valanda_valandos_valandą",hh:"valandos_valandų_valandas",d:"diena_dienos_dieną",dd:"dienos_dienų_dienas",M:"mėnuo_mėnesio_mėnesį",MM:"mėnesiai_mėnesių_mėnesius",y:"metai_metų_metus",yy:"metai_metų_metus"};a.defineLocale("lt",{months:{format:"sausio_vasario_kovo_balandžio_gegužės_birželio_liepos_rugpjūčio_rugsėjo_spalio_lapkričio_gruodžio".split("_"),standalone:"sausis_vasaris_kovas_balandis_gegužė_birželis_liepa_rugpjūtis_rugsėjis_spalis_lapkritis_gruodis".split("_"),isFormat:/D[oD]?(\[[^\[\]]*\]|\s)+MMMM?|MMMM?(\[[^\[\]]*\]|\s)+D[oD]?/},monthsShort:"sau_vas_kov_bal_geg_bir_lie_rgp_rgs_spa_lap_grd".split("_"),weekdays:{format:"sekmadienį_pirmadienį_antradienį_trečiadienį_ketvirtadienį_penktadienį_šeštadienį".split("_"),standalone:"sekmadienis_pirmadienis_antradienis_trečiadienis_ketvirtadienis_penktadienis_šeštadienis".split("_"),isFormat:/dddd HH:mm/},weekdaysShort:"Sek_Pir_Ant_Tre_Ket_Pen_Šeš".split("_"),weekdaysMin:"S_P_A_T_K_Pn_Š".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"YYYY [m.] MMMM D [d.]",LLL:"YYYY [m.] MMMM D [d.], HH:mm [val.]",LLLL:"YYYY [m.] MMMM D [d.], dddd, HH:mm [val.]",l:"YYYY-MM-DD",ll:"YYYY [m.] MMMM D [d.]",lll:"YYYY [m.] MMMM D [d.], HH:mm [val.]",llll:"YYYY [m.] MMMM D [d.], ddd, HH:mm [val.]"},calendar:{sameDay:"[Šiandien] LT",nextDay:"[Rytoj] LT",nextWeek:"dddd LT",lastDay:"[Vakar] LT",lastWeek:"[Praėjusį] dddd LT",sameElse:"L"},relativeTime:{future:"po %s",past:"prieš %s",s:Md,m:Nd,mm:Qd,h:Nd,hh:Qd,d:Nd,dd:Qd,M:Nd,MM:Qd,y:Nd,yy:Qd},ordinalParse:/\d{1,2}-oji/,ordinal:function(a){return a+"-oji"},week:{dow:1,// Monday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Latvian [lv]
+//! author : Kristaps Karlsons : https://github.com/skakri
+//! author : Jānis Elmeris : https://github.com/JanisE
+var eh={m:"minūtes_minūtēm_minūte_minūtes".split("_"),mm:"minūtes_minūtēm_minūte_minūtes".split("_"),h:"stundas_stundām_stunda_stundas".split("_"),hh:"stundas_stundām_stunda_stundas".split("_"),d:"dienas_dienām_diena_dienas".split("_"),dd:"dienas_dienām_diena_dienas".split("_"),M:"mēneša_mēnešiem_mēnesis_mēneši".split("_"),MM:"mēneša_mēnešiem_mēnesis_mēneši".split("_"),y:"gada_gadiem_gads_gadi".split("_"),yy:"gada_gadiem_gads_gadi".split("_")};a.defineLocale("lv",{months:"janvāris_februāris_marts_aprīlis_maijs_jūnijs_jūlijs_augusts_septembris_oktobris_novembris_decembris".split("_"),monthsShort:"jan_feb_mar_apr_mai_jūn_jūl_aug_sep_okt_nov_dec".split("_"),weekdays:"svētdiena_pirmdiena_otrdiena_trešdiena_ceturtdiena_piektdiena_sestdiena".split("_"),weekdaysShort:"Sv_P_O_T_C_Pk_S".split("_"),weekdaysMin:"Sv_P_O_T_C_Pk_S".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY.",LL:"YYYY. [gada] D. MMMM",LLL:"YYYY. [gada] D. MMMM, HH:mm",LLLL:"YYYY. [gada] D. MMMM, dddd, HH:mm"},calendar:{sameDay:"[Šodien pulksten] LT",nextDay:"[Rīt pulksten] LT",nextWeek:"dddd [pulksten] LT",lastDay:"[Vakar pulksten] LT",lastWeek:"[Pagājušā] dddd [pulksten] LT",sameElse:"L"},relativeTime:{future:"pēc %s",past:"pirms %s",s:Ud,m:Td,mm:Sd,h:Td,hh:Sd,d:Td,dd:Sd,M:Td,MM:Sd,y:Td,yy:Sd},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Montenegrin [me]
+//! author : Miodrag Nikač <miodrag@restartit.me> : https://github.com/miodragnikac
+var fh={words:{//Different grammatical cases
+m:["jedan minut","jednog minuta"],mm:["minut","minuta","minuta"],h:["jedan sat","jednog sata"],hh:["sat","sata","sati"],dd:["dan","dana","dana"],MM:["mjesec","mjeseca","mjeseci"],yy:["godina","godine","godina"]},correctGrammaticalCase:function(a,b){return 1===a?b[0]:a>=2&&a<=4?b[1]:b[2]},translate:function(a,b,c){var d=fh.words[c];return 1===c.length?b?d[0]:d[1]:a+" "+fh.correctGrammaticalCase(a,d)}};a.defineLocale("me",{months:"januar_februar_mart_april_maj_jun_jul_avgust_septembar_oktobar_novembar_decembar".split("_"),monthsShort:"jan._feb._mar._apr._maj_jun_jul_avg._sep._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota".split("_"),weekdaysShort:"ned._pon._uto._sri._čet._pet._sub.".split("_"),weekdaysMin:"ne_po_ut_sr_če_pe_su".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[danas u] LT",nextDay:"[sjutra u] LT",nextWeek:function(){switch(this.day()){case 0:return"[u] [nedjelju] [u] LT";case 3:return"[u] [srijedu] [u] LT";case 6:return"[u] [subotu] [u] LT";case 1:case 2:case 4:case 5:return"[u] dddd [u] LT"}},lastDay:"[juče u] LT",lastWeek:function(){var a=["[prošle] [nedjelje] [u] LT","[prošlog] [ponedjeljka] [u] LT","[prošlog] [utorka] [u] LT","[prošle] [srijede] [u] LT","[prošlog] [četvrtka] [u] LT","[prošlog] [petka] [u] LT","[prošle] [subote] [u] LT"];return a[this.day()]},sameElse:"L"},relativeTime:{future:"za %s",past:"prije %s",s:"nekoliko sekundi",m:fh.translate,mm:fh.translate,h:fh.translate,hh:fh.translate,d:"dan",dd:fh.translate,M:"mjesec",MM:fh.translate,y:"godinu",yy:fh.translate},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:7}}),
+//! moment.js locale configuration
+//! locale : Maori [mi]
+//! author : John Corrigan <robbiecloset@gmail.com> : https://github.com/johnideal
+a.defineLocale("mi",{months:"Kohi-tāte_Hui-tanguru_Poutū-te-rangi_Paenga-whāwhā_Haratua_Pipiri_Hōngoingoi_Here-turi-kōkā_Mahuru_Whiringa-ā-nuku_Whiringa-ā-rangi_Hakihea".split("_"),monthsShort:"Kohi_Hui_Pou_Pae_Hara_Pipi_Hōngoi_Here_Mahu_Whi-nu_Whi-ra_Haki".split("_"),monthsRegex:/(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,monthsStrictRegex:/(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,monthsShortRegex:/(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,monthsShortStrictRegex:/(?:['a-z\u0101\u014D\u016B]+\-?){1,2}/i,weekdays:"Rātapu_Mane_Tūrei_Wenerei_Tāite_Paraire_Hātarei".split("_"),weekdaysShort:"Ta_Ma_Tū_We_Tāi_Pa_Hā".split("_"),weekdaysMin:"Ta_Ma_Tū_We_Tāi_Pa_Hā".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [i] HH:mm",LLLL:"dddd, D MMMM YYYY [i] HH:mm"},calendar:{sameDay:"[i teie mahana, i] LT",nextDay:"[apopo i] LT",nextWeek:"dddd [i] LT",lastDay:"[inanahi i] LT",lastWeek:"dddd [whakamutunga i] LT",sameElse:"L"},relativeTime:{future:"i roto i %s",past:"%s i mua",s:"te hēkona ruarua",m:"he meneti",mm:"%d meneti",h:"te haora",hh:"%d haora",d:"he ra",dd:"%d ra",M:"he marama",MM:"%d marama",y:"he tau",yy:"%d tau"},ordinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Macedonian [mk]
+//! author : Borislav Mickov : https://github.com/B0k0
+a.defineLocale("mk",{months:"јануари_февруари_март_април_мај_јуни_јули_август_септември_октомври_ноември_декември".split("_"),monthsShort:"јан_фев_мар_апр_мај_јун_јул_авг_сеп_окт_ное_дек".split("_"),weekdays:"недела_понеделник_вторник_среда_четврток_петок_сабота".split("_"),weekdaysShort:"нед_пон_вто_сре_чет_пет_саб".split("_"),weekdaysMin:"нe_пo_вт_ср_че_пе_сa".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"D.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY H:mm",LLLL:"dddd, D MMMM YYYY H:mm"},calendar:{sameDay:"[Денес во] LT",nextDay:"[Утре во] LT",nextWeek:"[Во] dddd [во] LT",lastDay:"[Вчера во] LT",lastWeek:function(){switch(this.day()){case 0:case 3:case 6:return"[Изминатата] dddd [во] LT";case 1:case 2:case 4:case 5:return"[Изминатиот] dddd [во] LT"}},sameElse:"L"},relativeTime:{future:"после %s",past:"пред %s",s:"неколку секунди",m:"минута",mm:"%d минути",h:"час",hh:"%d часа",d:"ден",dd:"%d дена",M:"месец",MM:"%d месеци",y:"година",yy:"%d години"},ordinalParse:/\d{1,2}-(ев|ен|ти|ви|ри|ми)/,ordinal:function(a){var b=a%10,c=a%100;return 0===a?a+"-ев":0===c?a+"-ен":c>10&&c<20?a+"-ти":1===b?a+"-ви":2===b?a+"-ри":7===b||8===b?a+"-ми":a+"-ти"},week:{dow:1,// Monday is the first day of the week.
+doy:7}}),
+//! moment.js locale configuration
+//! locale : Malayalam [ml]
+//! author : Floyd Pink : https://github.com/floydpink
+a.defineLocale("ml",{months:"ജനുവരി_ഫെബ്രുവരി_മാർച്ച്_ഏപ്രിൽ_മേയ്_ജൂൺ_ജൂലൈ_ഓഗസ്റ്റ്_സെപ്റ്റംബർ_ഒക്ടോബർ_നവംബർ_ഡിസംബർ".split("_"),monthsShort:"ജനു._ഫെബ്രു._മാർ._ഏപ്രി._മേയ്_ജൂൺ_ജൂലൈ._ഓഗ._സെപ്റ്റ._ഒക്ടോ._നവം._ഡിസം.".split("_"),monthsParseExact:!0,weekdays:"ഞായറാഴ്ച_തിങ്കളാഴ്ച_ചൊവ്വാഴ്ച_ബുധനാഴ്ച_വ്യാഴാഴ്ച_വെള്ളിയാഴ്ച_ശനിയാഴ്ച".split("_"),weekdaysShort:"ഞായർ_തിങ്കൾ_ചൊവ്വ_ബുധൻ_വ്യാഴം_വെള്ളി_ശനി".split("_"),weekdaysMin:"ഞാ_തി_ചൊ_ബു_വ്യാ_വെ_ശ".split("_"),longDateFormat:{LT:"A h:mm -നു",LTS:"A h:mm:ss -നു",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm -നു",LLLL:"dddd, D MMMM YYYY, A h:mm -നു"},calendar:{sameDay:"[ഇന്ന്] LT",nextDay:"[നാളെ] LT",nextWeek:"dddd, LT",lastDay:"[ഇന്നലെ] LT",lastWeek:"[കഴിഞ്ഞ] dddd, LT",sameElse:"L"},relativeTime:{future:"%s കഴിഞ്ഞ്",past:"%s മുൻപ്",s:"അൽപ നിമിഷങ്ങൾ",m:"ഒരു മിനിറ്റ്",mm:"%d മിനിറ്റ്",h:"ഒരു മണിക്കൂർ",hh:"%d മണിക്കൂർ",d:"ഒരു ദിവസം",dd:"%d ദിവസം",M:"ഒരു മാസം",MM:"%d മാസം",y:"ഒരു വർഷം",yy:"%d വർഷം"},meridiemParse:/രാത്രി|രാവിലെ|ഉച്ച കഴിഞ്ഞ്|വൈകുന്നേരം|രാത്രി/i,meridiemHour:function(a,b){return 12===a&&(a=0),"രാത്രി"===b&&a>=4||"ഉച്ച കഴിഞ്ഞ്"===b||"വൈകുന്നേരം"===b?a+12:a},meridiem:function(a,b,c){return a<4?"രാത്രി":a<12?"രാവിലെ":a<17?"ഉച്ച കഴിഞ്ഞ്":a<20?"വൈകുന്നേരം":"രാത്രി"}});
+//! moment.js locale configuration
+//! locale : Marathi [mr]
+//! author : Harshad Kale : https://github.com/kalehv
+//! author : Vivek Athalye : https://github.com/vnathalye
+var gh={1:"१",2:"२",3:"३",4:"४",5:"५",6:"६",7:"७",8:"८",9:"९",0:"०"},hh={"१":"1","२":"2","३":"3","४":"4","५":"5","६":"6","७":"7","८":"8","९":"9","०":"0"};a.defineLocale("mr",{months:"जानेवारी_फेब्रुवारी_मार्च_एप्रिल_मे_जून_जुलै_ऑगस्ट_सप्टेंबर_ऑक्टोबर_नोव्हेंबर_डिसेंबर".split("_"),monthsShort:"जाने._फेब्रु._मार्च._एप्रि._मे._जून._जुलै._ऑग._सप्टें._ऑक्टो._नोव्हें._डिसें.".split("_"),monthsParseExact:!0,weekdays:"रविवार_सोमवार_मंगळवार_बुधवार_गुरूवार_शुक्रवार_शनिवार".split("_"),weekdaysShort:"रवि_सोम_मंगळ_बुध_गुरू_शुक्र_शनि".split("_"),weekdaysMin:"र_सो_मं_बु_गु_शु_श".split("_"),longDateFormat:{LT:"A h:mm वाजता",LTS:"A h:mm:ss वाजता",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm वाजता",LLLL:"dddd, D MMMM YYYY, A h:mm वाजता"},calendar:{sameDay:"[आज] LT",nextDay:"[उद्या] LT",nextWeek:"dddd, LT",lastDay:"[काल] LT",lastWeek:"[मागील] dddd, LT",sameElse:"L"},relativeTime:{future:"%sमध्ये",past:"%sपूर्वी",s:Vd,m:Vd,mm:Vd,h:Vd,hh:Vd,d:Vd,dd:Vd,M:Vd,MM:Vd,y:Vd,yy:Vd},preparse:function(a){return a.replace(/[१२३४५६७८९०]/g,function(a){return hh[a]})},postformat:function(a){return a.replace(/\d/g,function(a){return gh[a]})},meridiemParse:/रात्री|सकाळी|दुपारी|सायंकाळी/,meridiemHour:function(a,b){return 12===a&&(a=0),"रात्री"===b?a<4?a:a+12:"सकाळी"===b?a:"दुपारी"===b?a>=10?a:a+12:"सायंकाळी"===b?a+12:void 0},meridiem:function(a,b,c){return a<4?"रात्री":a<10?"सकाळी":a<17?"दुपारी":a<20?"सायंकाळी":"रात्री"},week:{dow:0,// Sunday is the first day of the week.
+doy:6}}),
+//! moment.js locale configuration
+//! locale : Malay [ms-my]
+//! note : DEPRECATED, the correct one is [ms]
+//! author : Weldan Jamili : https://github.com/weldan
+a.defineLocale("ms-my",{months:"Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember".split("_"),monthsShort:"Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis".split("_"),weekdays:"Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu".split("_"),weekdaysShort:"Ahd_Isn_Sel_Rab_Kha_Jum_Sab".split("_"),weekdaysMin:"Ah_Is_Sl_Rb_Km_Jm_Sb".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/pagi|tengahari|petang|malam/,meridiemHour:function(a,b){return 12===a&&(a=0),"pagi"===b?a:"tengahari"===b?a>=11?a:a+12:"petang"===b||"malam"===b?a+12:void 0},meridiem:function(a,b,c){return a<11?"pagi":a<15?"tengahari":a<19?"petang":"malam"},calendar:{sameDay:"[Hari ini pukul] LT",nextDay:"[Esok pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kelmarin pukul] LT",lastWeek:"dddd [lepas pukul] LT",sameElse:"L"},relativeTime:{future:"dalam %s",past:"%s yang lepas",s:"beberapa saat",m:"seminit",mm:"%d minit",h:"sejam",hh:"%d jam",d:"sehari",dd:"%d hari",M:"sebulan",MM:"%d bulan",y:"setahun",yy:"%d tahun"},week:{dow:1,// Monday is the first day of the week.
+doy:7}}),
+//! moment.js locale configuration
+//! locale : Malay [ms]
+//! author : Weldan Jamili : https://github.com/weldan
+a.defineLocale("ms",{months:"Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember".split("_"),monthsShort:"Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis".split("_"),weekdays:"Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu".split("_"),weekdaysShort:"Ahd_Isn_Sel_Rab_Kha_Jum_Sab".split("_"),weekdaysMin:"Ah_Is_Sl_Rb_Km_Jm_Sb".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/pagi|tengahari|petang|malam/,meridiemHour:function(a,b){return 12===a&&(a=0),"pagi"===b?a:"tengahari"===b?a>=11?a:a+12:"petang"===b||"malam"===b?a+12:void 0},meridiem:function(a,b,c){return a<11?"pagi":a<15?"tengahari":a<19?"petang":"malam"},calendar:{sameDay:"[Hari ini pukul] LT",nextDay:"[Esok pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kelmarin pukul] LT",lastWeek:"dddd [lepas pukul] LT",sameElse:"L"},relativeTime:{future:"dalam %s",past:"%s yang lepas",s:"beberapa saat",m:"seminit",mm:"%d minit",h:"sejam",hh:"%d jam",d:"sehari",dd:"%d hari",M:"sebulan",MM:"%d bulan",y:"setahun",yy:"%d tahun"},week:{dow:1,// Monday is the first day of the week.
+doy:7}});
+//! moment.js locale configuration
+//! locale : Burmese [my]
+//! author : Squar team, mysquar.com
+//! author : David Rossellat : https://github.com/gholadr
+//! author : Tin Aung Lin : https://github.com/thanyawzinmin
+var ih={1:"၁",2:"၂",3:"၃",4:"၄",5:"၅",6:"၆",7:"၇",8:"၈",9:"၉",0:"၀"},jh={"၁":"1","၂":"2","၃":"3","၄":"4","၅":"5","၆":"6","၇":"7","၈":"8","၉":"9","၀":"0"};a.defineLocale("my",{months:"ဇန်နဝါရီ_ဖေဖော်ဝါရီ_မတ်_ဧပြီ_မေ_ဇွန်_ဇူလိုင်_သြဂုတ်_စက်တင်ဘာ_အောက်တိုဘာ_နိုဝင်ဘာ_ဒီဇင်ဘာ".split("_"),monthsShort:"ဇန်_ဖေ_မတ်_ပြီ_မေ_ဇွန်_လိုင်_သြ_စက်_အောက်_နို_ဒီ".split("_"),weekdays:"တနင်္ဂနွေ_တနင်္လာ_အင်္ဂါ_ဗုဒ္ဓဟူး_ကြာသပတေး_သောကြာ_စနေ".split("_"),weekdaysShort:"နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ".split("_"),weekdaysMin:"နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[ယနေ.] LT [မှာ]",nextDay:"[မနက်ဖြန်] LT [မှာ]",nextWeek:"dddd LT [မှာ]",lastDay:"[မနေ.က] LT [မှာ]",lastWeek:"[ပြီးခဲ့သော] dddd LT [မှာ]",sameElse:"L"},relativeTime:{future:"လာမည့် %s မှာ",past:"လွန်ခဲ့သော %s က",s:"စက္ကန်.အနည်းငယ်",m:"တစ်မိနစ်",mm:"%d မိနစ်",h:"တစ်နာရီ",hh:"%d နာရီ",d:"တစ်ရက်",dd:"%d ရက်",M:"တစ်လ",MM:"%d လ",y:"တစ်နှစ်",yy:"%d နှစ်"},preparse:function(a){return a.replace(/[၁၂၃၄၅၆၇၈၉၀]/g,function(a){return jh[a]})},postformat:function(a){return a.replace(/\d/g,function(a){return ih[a]})},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Norwegian Bokmål [nb]
+//! authors : Espen Hovlandsdal : https://github.com/rexxars
+//!           Sigurd Gartmann : https://github.com/sigurdga
+a.defineLocale("nb",{months:"januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember".split("_"),monthsShort:"jan._feb._mars_april_mai_juni_juli_aug._sep._okt._nov._des.".split("_"),monthsParseExact:!0,weekdays:"søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag".split("_"),weekdaysShort:"sø._ma._ti._on._to._fr._lø.".split("_"),weekdaysMin:"sø_ma_ti_on_to_fr_lø".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY [kl.] HH:mm",LLLL:"dddd D. MMMM YYYY [kl.] HH:mm"},calendar:{sameDay:"[i dag kl.] LT",nextDay:"[i morgen kl.] LT",nextWeek:"dddd [kl.] LT",lastDay:"[i går kl.] LT",lastWeek:"[forrige] dddd [kl.] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"%s siden",s:"noen sekunder",m:"ett minutt",mm:"%d minutter",h:"en time",hh:"%d timer",d:"en dag",dd:"%d dager",M:"en måned",MM:"%d måneder",y:"ett år",yy:"%d år"},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Nepalese [ne]
+//! author : suvash : https://github.com/suvash
+var kh={1:"१",2:"२",3:"३",4:"४",5:"५",6:"६",7:"७",8:"८",9:"९",0:"०"},lh={"१":"1","२":"2","३":"3","४":"4","५":"5","६":"6","७":"7","८":"8","९":"9","०":"0"};a.defineLocale("ne",{months:"जनवरी_फेब्रुवरी_मार्च_अप्रिल_मई_जुन_जुलाई_अगष्ट_सेप्टेम्बर_अक्टोबर_नोभेम्बर_डिसेम्बर".split("_"),monthsShort:"जन._फेब्रु._मार्च_अप्रि._मई_जुन_जुलाई._अग._सेप्ट._अक्टो._नोभे._डिसे.".split("_"),monthsParseExact:!0,weekdays:"आइतबार_सोमबार_मङ्गलबार_बुधबार_बिहिबार_शुक्रबार_शनिबार".split("_"),weekdaysShort:"आइत._सोम._मङ्गल._बुध._बिहि._शुक्र._शनि.".split("_"),weekdaysMin:"आ._सो._मं._बु._बि._शु._श.".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"Aको h:mm बजे",LTS:"Aको h:mm:ss बजे",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, Aको h:mm बजे",LLLL:"dddd, D MMMM YYYY, Aको h:mm बजे"},preparse:function(a){return a.replace(/[१२३४५६७८९०]/g,function(a){return lh[a]})},postformat:function(a){return a.replace(/\d/g,function(a){return kh[a]})},meridiemParse:/राति|बिहान|दिउँसो|साँझ/,meridiemHour:function(a,b){return 12===a&&(a=0),"राति"===b?a<4?a:a+12:"बिहान"===b?a:"दिउँसो"===b?a>=10?a:a+12:"साँझ"===b?a+12:void 0},meridiem:function(a,b,c){return a<3?"राति":a<12?"बिहान":a<16?"दिउँसो":a<20?"साँझ":"राति"},calendar:{sameDay:"[आज] LT",nextDay:"[भोलि] LT",nextWeek:"[आउँदो] dddd[,] LT",lastDay:"[हिजो] LT",lastWeek:"[गएको] dddd[,] LT",sameElse:"L"},relativeTime:{future:"%sमा",past:"%s अगाडि",s:"केही क्षण",m:"एक मिनेट",mm:"%d मिनेट",h:"एक घण्टा",hh:"%d घण्टा",d:"एक दिन",dd:"%d दिन",M:"एक महिना",MM:"%d महिना",y:"एक बर्ष",yy:"%d बर्ष"},week:{dow:0,// Sunday is the first day of the week.
+doy:6}});
+//! moment.js locale configuration
+//! locale : Dutch (Belgium) [nl-be]
+//! author : Joris Röling : https://github.com/jorisroling
+//! author : Jacob Middag : https://github.com/middagj
+var mh="jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.".split("_"),nh="jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec".split("_"),oh=[/^jan/i,/^feb/i,/^maart|mrt.?$/i,/^apr/i,/^mei$/i,/^jun[i.]?$/i,/^jul[i.]?$/i,/^aug/i,/^sep/i,/^okt/i,/^nov/i,/^dec/i],ph=/^(januari|februari|maart|april|mei|april|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i;a.defineLocale("nl-be",{months:"januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december".split("_"),monthsShort:function(a,b){return/-MMM-/.test(b)?nh[a.month()]:mh[a.month()]},monthsRegex:ph,monthsShortRegex:ph,monthsStrictRegex:/^(januari|februari|maart|mei|ju[nl]i|april|augustus|september|oktober|november|december)/i,monthsShortStrictRegex:/^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i,monthsParse:oh,longMonthsParse:oh,shortMonthsParse:oh,weekdays:"zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag".split("_"),weekdaysShort:"zo._ma._di._wo._do._vr._za.".split("_"),weekdaysMin:"Zo_Ma_Di_Wo_Do_Vr_Za".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[vandaag om] LT",nextDay:"[morgen om] LT",nextWeek:"dddd [om] LT",lastDay:"[gisteren om] LT",lastWeek:"[afgelopen] dddd [om] LT",sameElse:"L"},relativeTime:{future:"over %s",past:"%s geleden",s:"een paar seconden",m:"één minuut",mm:"%d minuten",h:"één uur",hh:"%d uur",d:"één dag",dd:"%d dagen",M:"één maand",MM:"%d maanden",y:"één jaar",yy:"%d jaar"},ordinalParse:/\d{1,2}(ste|de)/,ordinal:function(a){return a+(1===a||8===a||a>=20?"ste":"de")},week:{dow:1,// Monday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Dutch [nl]
+//! author : Joris Röling : https://github.com/jorisroling
+//! author : Jacob Middag : https://github.com/middagj
+var qh="jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.".split("_"),rh="jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec".split("_"),sh=[/^jan/i,/^feb/i,/^maart|mrt.?$/i,/^apr/i,/^mei$/i,/^jun[i.]?$/i,/^jul[i.]?$/i,/^aug/i,/^sep/i,/^okt/i,/^nov/i,/^dec/i],th=/^(januari|februari|maart|april|mei|april|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i;a.defineLocale("nl",{months:"januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december".split("_"),monthsShort:function(a,b){return/-MMM-/.test(b)?rh[a.month()]:qh[a.month()]},monthsRegex:th,monthsShortRegex:th,monthsStrictRegex:/^(januari|februari|maart|mei|ju[nl]i|april|augustus|september|oktober|november|december)/i,monthsShortStrictRegex:/^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i,monthsParse:sh,longMonthsParse:sh,shortMonthsParse:sh,weekdays:"zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag".split("_"),weekdaysShort:"zo._ma._di._wo._do._vr._za.".split("_"),weekdaysMin:"Zo_Ma_Di_Wo_Do_Vr_Za".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD-MM-YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[vandaag om] LT",nextDay:"[morgen om] LT",nextWeek:"dddd [om] LT",lastDay:"[gisteren om] LT",lastWeek:"[afgelopen] dddd [om] LT",sameElse:"L"},relativeTime:{future:"over %s",past:"%s geleden",s:"een paar seconden",m:"één minuut",mm:"%d minuten",h:"één uur",hh:"%d uur",d:"één dag",dd:"%d dagen",M:"één maand",MM:"%d maanden",y:"één jaar",yy:"%d jaar"},ordinalParse:/\d{1,2}(ste|de)/,ordinal:function(a){return a+(1===a||8===a||a>=20?"ste":"de")},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Nynorsk [nn]
+//! author : https://github.com/mechuwind
+a.defineLocale("nn",{months:"januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember".split("_"),monthsShort:"jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des".split("_"),weekdays:"sundag_måndag_tysdag_onsdag_torsdag_fredag_laurdag".split("_"),weekdaysShort:"sun_mån_tys_ons_tor_fre_lau".split("_"),weekdaysMin:"su_må_ty_on_to_fr_lø".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY [kl.] H:mm",LLLL:"dddd D. MMMM YYYY [kl.] HH:mm"},calendar:{sameDay:"[I dag klokka] LT",nextDay:"[I morgon klokka] LT",nextWeek:"dddd [klokka] LT",lastDay:"[I går klokka] LT",lastWeek:"[Føregåande] dddd [klokka] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"%s sidan",s:"nokre sekund",m:"eit minutt",mm:"%d minutt",h:"ein time",hh:"%d timar",d:"ein dag",dd:"%d dagar",M:"ein månad",MM:"%d månader",y:"eit år",yy:"%d år"},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Punjabi (India) [pa-in]
+//! author : Harpreet Singh : https://github.com/harpreetkhalsagtbit
+var uh={1:"੧",2:"੨",3:"੩",4:"੪",5:"੫",6:"੬",7:"੭",8:"੮",9:"੯",0:"੦"},vh={"੧":"1","੨":"2","੩":"3","੪":"4","੫":"5","੬":"6","੭":"7","੮":"8","੯":"9","੦":"0"};a.defineLocale("pa-in",{
+// There are months name as per Nanakshahi Calender but they are not used as rigidly in modern Punjabi.
+months:"ਜਨਵਰੀ_ਫ਼ਰਵਰੀ_ਮਾਰਚ_ਅਪ੍ਰੈਲ_ਮਈ_ਜੂਨ_ਜੁਲਾਈ_ਅਗਸਤ_ਸਤੰਬਰ_ਅਕਤੂਬਰ_ਨਵੰਬਰ_ਦਸੰਬਰ".split("_"),monthsShort:"ਜਨਵਰੀ_ਫ਼ਰਵਰੀ_ਮਾਰਚ_ਅਪ੍ਰੈਲ_ਮਈ_ਜੂਨ_ਜੁਲਾਈ_ਅਗਸਤ_ਸਤੰਬਰ_ਅਕਤੂਬਰ_ਨਵੰਬਰ_ਦਸੰਬਰ".split("_"),weekdays:"ਐਤਵਾਰ_ਸੋਮਵਾਰ_ਮੰਗਲਵਾਰ_ਬੁਧਵਾਰ_ਵੀਰਵਾਰ_ਸ਼ੁੱਕਰਵਾਰ_ਸ਼ਨੀਚਰਵਾਰ".split("_"),weekdaysShort:"ਐਤ_ਸੋਮ_ਮੰਗਲ_ਬੁਧ_ਵੀਰ_ਸ਼ੁਕਰ_ਸ਼ਨੀ".split("_"),weekdaysMin:"ਐਤ_ਸੋਮ_ਮੰਗਲ_ਬੁਧ_ਵੀਰ_ਸ਼ੁਕਰ_ਸ਼ਨੀ".split("_"),longDateFormat:{LT:"A h:mm ਵਜੇ",LTS:"A h:mm:ss ਵਜੇ",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm ਵਜੇ",LLLL:"dddd, D MMMM YYYY, A h:mm ਵਜੇ"},calendar:{sameDay:"[ਅਜ] LT",nextDay:"[ਕਲ] LT",nextWeek:"dddd, LT",lastDay:"[ਕਲ] LT",lastWeek:"[ਪਿਛਲੇ] dddd, LT",sameElse:"L"},relativeTime:{future:"%s ਵਿੱਚ",past:"%s ਪਿਛਲੇ",s:"ਕੁਝ ਸਕਿੰਟ",m:"ਇਕ ਮਿੰਟ",mm:"%d ਮਿੰਟ",h:"ਇੱਕ ਘੰਟਾ",hh:"%d ਘੰਟੇ",d:"ਇੱਕ ਦਿਨ",dd:"%d ਦਿਨ",M:"ਇੱਕ ਮਹੀਨਾ",MM:"%d ਮਹੀਨੇ",y:"ਇੱਕ ਸਾਲ",yy:"%d ਸਾਲ"},preparse:function(a){return a.replace(/[੧੨੩੪੫੬੭੮੯੦]/g,function(a){return vh[a]})},postformat:function(a){return a.replace(/\d/g,function(a){return uh[a]})},
+// Punjabi notation for meridiems are quite fuzzy in practice. While there exists
+// a rigid notion of a 'Pahar' it is not used as rigidly in modern Punjabi.
+meridiemParse:/ਰਾਤ|ਸਵੇਰ|ਦੁਪਹਿਰ|ਸ਼ਾਮ/,meridiemHour:function(a,b){return 12===a&&(a=0),"ਰਾਤ"===b?a<4?a:a+12:"ਸਵੇਰ"===b?a:"ਦੁਪਹਿਰ"===b?a>=10?a:a+12:"ਸ਼ਾਮ"===b?a+12:void 0},meridiem:function(a,b,c){return a<4?"ਰਾਤ":a<10?"ਸਵੇਰ":a<17?"ਦੁਪਹਿਰ":a<20?"ਸ਼ਾਮ":"ਰਾਤ"},week:{dow:0,// Sunday is the first day of the week.
+doy:6}});
+//! moment.js locale configuration
+//! locale : Polish [pl]
+//! author : Rafal Hirsz : https://github.com/evoL
+var wh="styczeń_luty_marzec_kwiecień_maj_czerwiec_lipiec_sierpień_wrzesień_październik_listopad_grudzień".split("_"),xh="stycznia_lutego_marca_kwietnia_maja_czerwca_lipca_sierpnia_września_października_listopada_grudnia".split("_");a.defineLocale("pl",{months:function(a,b){return""===b?"("+xh[a.month()]+"|"+wh[a.month()]+")":/D MMMM/.test(b)?xh[a.month()]:wh[a.month()]},monthsShort:"sty_lut_mar_kwi_maj_cze_lip_sie_wrz_paź_lis_gru".split("_"),weekdays:"niedziela_poniedziałek_wtorek_środa_czwartek_piątek_sobota".split("_"),weekdaysShort:"ndz_pon_wt_śr_czw_pt_sob".split("_"),weekdaysMin:"Nd_Pn_Wt_Śr_Cz_Pt_So".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Dziś o] LT",nextDay:"[Jutro o] LT",nextWeek:"[W] dddd [o] LT",lastDay:"[Wczoraj o] LT",lastWeek:function(){switch(this.day()){case 0:return"[W zeszłą niedzielę o] LT";case 3:return"[W zeszłą środę o] LT";case 6:return"[W zeszłą sobotę o] LT";default:return"[W zeszły] dddd [o] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"%s temu",s:"kilka sekund",m:Xd,mm:Xd,h:Xd,hh:Xd,d:"1 dzień",dd:"%d dni",M:"miesiąc",MM:Xd,y:"rok",yy:Xd},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Portuguese (Brazil) [pt-br]
+//! author : Caio Ribeiro Pereira : https://github.com/caio-ribeiro-pereira
+a.defineLocale("pt-br",{months:"Janeiro_Fevereiro_Março_Abril_Maio_Junho_Julho_Agosto_Setembro_Outubro_Novembro_Dezembro".split("_"),monthsShort:"Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez".split("_"),weekdays:"Domingo_Segunda-feira_Terça-feira_Quarta-feira_Quinta-feira_Sexta-feira_Sábado".split("_"),weekdaysShort:"Dom_Seg_Ter_Qua_Qui_Sex_Sáb".split("_"),weekdaysMin:"Dom_2ª_3ª_4ª_5ª_6ª_Sáb".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY [às] HH:mm",LLLL:"dddd, D [de] MMMM [de] YYYY [às] HH:mm"},calendar:{sameDay:"[Hoje às] LT",nextDay:"[Amanhã às] LT",nextWeek:"dddd [às] LT",lastDay:"[Ontem às] LT",lastWeek:function(){// Saturday + Sunday
+return 0===this.day()||6===this.day()?"[Último] dddd [às] LT":"[Última] dddd [às] LT"},sameElse:"L"},relativeTime:{future:"em %s",past:"%s atrás",s:"poucos segundos",m:"um minuto",mm:"%d minutos",h:"uma hora",hh:"%d horas",d:"um dia",dd:"%d dias",M:"um mês",MM:"%d meses",y:"um ano",yy:"%d anos"},ordinalParse:/\d{1,2}º/,ordinal:"%dº"}),
+//! moment.js locale configuration
+//! locale : Portuguese [pt]
+//! author : Jefferson : https://github.com/jalex79
+a.defineLocale("pt",{months:"Janeiro_Fevereiro_Março_Abril_Maio_Junho_Julho_Agosto_Setembro_Outubro_Novembro_Dezembro".split("_"),monthsShort:"Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez".split("_"),weekdays:"Domingo_Segunda-Feira_Terça-Feira_Quarta-Feira_Quinta-Feira_Sexta-Feira_Sábado".split("_"),weekdaysShort:"Dom_Seg_Ter_Qua_Qui_Sex_Sáb".split("_"),weekdaysMin:"Dom_2ª_3ª_4ª_5ª_6ª_Sáb".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY HH:mm",LLLL:"dddd, D [de] MMMM [de] YYYY HH:mm"},calendar:{sameDay:"[Hoje às] LT",nextDay:"[Amanhã às] LT",nextWeek:"dddd [às] LT",lastDay:"[Ontem às] LT",lastWeek:function(){// Saturday + Sunday
+return 0===this.day()||6===this.day()?"[Último] dddd [às] LT":"[Última] dddd [às] LT"},sameElse:"L"},relativeTime:{future:"em %s",past:"há %s",s:"segundos",m:"um minuto",mm:"%d minutos",h:"uma hora",hh:"%d horas",d:"um dia",dd:"%d dias",M:"um mês",MM:"%d meses",y:"um ano",yy:"%d anos"},ordinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),a.defineLocale("ro",{months:"ianuarie_februarie_martie_aprilie_mai_iunie_iulie_august_septembrie_octombrie_noiembrie_decembrie".split("_"),monthsShort:"ian._febr._mart._apr._mai_iun._iul._aug._sept._oct._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"duminică_luni_marți_miercuri_joi_vineri_sâmbătă".split("_"),weekdaysShort:"Dum_Lun_Mar_Mie_Joi_Vin_Sâm".split("_"),weekdaysMin:"Du_Lu_Ma_Mi_Jo_Vi_Sâ".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY H:mm",LLLL:"dddd, D MMMM YYYY H:mm"},calendar:{sameDay:"[azi la] LT",nextDay:"[mâine la] LT",nextWeek:"dddd [la] LT",lastDay:"[ieri la] LT",lastWeek:"[fosta] dddd [la] LT",sameElse:"L"},relativeTime:{future:"peste %s",past:"%s în urmă",s:"câteva secunde",m:"un minut",mm:Yd,h:"o oră",hh:Yd,d:"o zi",dd:Yd,M:"o lună",MM:Yd,y:"un an",yy:Yd},week:{dow:1,// Monday is the first day of the week.
+doy:7}});var yh=[/^янв/i,/^фев/i,/^мар/i,/^апр/i,/^ма[йя]/i,/^июн/i,/^июл/i,/^авг/i,/^сен/i,/^окт/i,/^ноя/i,/^дек/i];
+// http://new.gramota.ru/spravka/rules/139-prop : § 103
+// Сокращения месяцев: http://new.gramota.ru/spravka/buro/search-answer?s=242637
+// CLDR data:          http://www.unicode.org/cldr/charts/28/summary/ru.html#1753
+a.defineLocale("ru",{months:{format:"января_февраля_марта_апреля_мая_июня_июля_августа_сентября_октября_ноября_декабря".split("_"),standalone:"январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь".split("_")},monthsShort:{
+// по CLDR именно "июл." и "июн.", но какой смысл менять букву на точку ?
+format:"янв._февр._мар._апр._мая_июня_июля_авг._сент._окт._нояб._дек.".split("_"),standalone:"янв._февр._март_апр._май_июнь_июль_авг._сент._окт._нояб._дек.".split("_")},weekdays:{standalone:"воскресенье_понедельник_вторник_среда_четверг_пятница_суббота".split("_"),format:"воскресенье_понедельник_вторник_среду_четверг_пятницу_субботу".split("_"),isFormat:/\[ ?[Вв] ?(?:прошлую|следующую|эту)? ?\] ?dddd/},weekdaysShort:"вс_пн_вт_ср_чт_пт_сб".split("_"),weekdaysMin:"вс_пн_вт_ср_чт_пт_сб".split("_"),monthsParse:yh,longMonthsParse:yh,shortMonthsParse:yh,
+// полные названия с падежами, по три буквы, для некоторых, по 4 буквы, сокращения с точкой и без точки
+monthsRegex:/^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i,
+// копия предыдущего
+monthsShortRegex:/^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i,
+// полные названия с падежами
+monthsStrictRegex:/^(январ[яь]|феврал[яь]|марта?|апрел[яь]|ма[яй]|июн[яь]|июл[яь]|августа?|сентябр[яь]|октябр[яь]|ноябр[яь]|декабр[яь])/i,
+// Выражение, которое соотвествует только сокращённым формам
+monthsShortStrictRegex:/^(янв\.|февр?\.|мар[т.]|апр\.|ма[яй]|июн[ья.]|июл[ья.]|авг\.|сент?\.|окт\.|нояб?\.|дек\.)/i,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY г.",LLL:"D MMMM YYYY г., HH:mm",LLLL:"dddd, D MMMM YYYY г., HH:mm"},calendar:{sameDay:"[Сегодня в] LT",nextDay:"[Завтра в] LT",lastDay:"[Вчера в] LT",nextWeek:function(a){if(a.week()===this.week())return 2===this.day()?"[Во] dddd [в] LT":"[В] dddd [в] LT";switch(this.day()){case 0:return"[В следующее] dddd [в] LT";case 1:case 2:case 4:return"[В следующий] dddd [в] LT";case 3:case 5:case 6:return"[В следующую] dddd [в] LT"}},lastWeek:function(a){if(a.week()===this.week())return 2===this.day()?"[Во] dddd [в] LT":"[В] dddd [в] LT";switch(this.day()){case 0:return"[В прошлое] dddd [в] LT";case 1:case 2:case 4:return"[В прошлый] dddd [в] LT";case 3:case 5:case 6:return"[В прошлую] dddd [в] LT"}},sameElse:"L"},relativeTime:{future:"через %s",past:"%s назад",s:"несколько секунд",m:$d,mm:$d,h:"час",hh:$d,d:"день",dd:$d,M:"месяц",MM:$d,y:"год",yy:$d},meridiemParse:/ночи|утра|дня|вечера/i,isPM:function(a){return/^(дня|вечера)$/.test(a)},meridiem:function(a,b,c){return a<4?"ночи":a<12?"утра":a<17?"дня":"вечера"},ordinalParse:/\d{1,2}-(й|го|я)/,ordinal:function(a,b){switch(b){case"M":case"d":case"DDD":return a+"-й";case"D":return a+"-го";case"w":case"W":return a+"-я";default:return a}},week:{dow:1,// Monday is the first day of the week.
+doy:7}}),
+//! moment.js locale configuration
+//! locale : Northern Sami [se]
+//! authors : BÃ¥rd Rolstad Henriksen : https://github.com/karamell
+a.defineLocale("se",{months:"ođđajagemánnu_guovvamánnu_njukčamánnu_cuoŋománnu_miessemánnu_geassemánnu_suoidnemánnu_borgemánnu_čakčamánnu_golggotmánnu_skábmamánnu_juovlamánnu".split("_"),monthsShort:"ođđj_guov_njuk_cuo_mies_geas_suoi_borg_čakč_golg_skáb_juov".split("_"),weekdays:"sotnabeaivi_vuossárga_maŋŋebárga_gaskavahkku_duorastat_bearjadat_lávvardat".split("_"),weekdaysShort:"sotn_vuos_maŋ_gask_duor_bear_láv".split("_"),weekdaysMin:"s_v_m_g_d_b_L".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"MMMM D. [b.] YYYY",LLL:"MMMM D. [b.] YYYY [ti.] HH:mm",LLLL:"dddd, MMMM D. [b.] YYYY [ti.] HH:mm"},calendar:{sameDay:"[otne ti] LT",nextDay:"[ihttin ti] LT",nextWeek:"dddd [ti] LT",lastDay:"[ikte ti] LT",lastWeek:"[ovddit] dddd [ti] LT",sameElse:"L"},relativeTime:{future:"%s geažes",past:"maŋit %s",s:"moadde sekunddat",m:"okta minuhta",mm:"%d minuhtat",h:"okta diimmu",hh:"%d diimmut",d:"okta beaivi",dd:"%d beaivvit",M:"okta mánnu",MM:"%d mánut",y:"okta jahki",yy:"%d jagit"},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Sinhalese [si]
+//! author : Sampath Sitinamaluwa : https://github.com/sampathsris
+/*jshint -W100*/
+a.defineLocale("si",{months:"ජනවාරි_පෙබරවාරි_මාර්තු_අප්‍රේල්_මැයි_ජූනි_ජූලි_අගෝස්තු_සැප්තැම්බර්_ඔක්තෝබර්_නොවැම්බර්_දෙසැම්බර්".split("_"),monthsShort:"ජන_පෙබ_මාර්_අප්_මැයි_ජූනි_ජූලි_අගෝ_සැප්_ඔක්_නොවැ_දෙසැ".split("_"),weekdays:"ඉරිදා_සඳුදා_අඟහරුවාදා_බදාදා_බ්‍රහස්පතින්දා_සිකුරාදා_සෙනසුරාදා".split("_"),weekdaysShort:"ඉරි_සඳු_අඟ_බදා_බ්‍රහ_සිකු_සෙන".split("_"),weekdaysMin:"ඉ_ස_අ_බ_බ්‍ර_සි_සෙ".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"a h:mm",LTS:"a h:mm:ss",L:"YYYY/MM/DD",LL:"YYYY MMMM D",LLL:"YYYY MMMM D, a h:mm",LLLL:"YYYY MMMM D [වැනි] dddd, a h:mm:ss"},calendar:{sameDay:"[අද] LT[ට]",nextDay:"[හෙට] LT[ට]",nextWeek:"dddd LT[ට]",lastDay:"[ඊයේ] LT[ට]",lastWeek:"[පසුගිය] dddd LT[ට]",sameElse:"L"},relativeTime:{future:"%sකින්",past:"%sකට පෙර",s:"තත්පර කිහිපය",m:"මිනිත්තුව",mm:"මිනිත්තු %d",h:"පැය",hh:"පැය %d",d:"දිනය",dd:"දින %d",M:"මාසය",MM:"මාස %d",y:"වසර",yy:"වසර %d"},ordinalParse:/\d{1,2} වැනි/,ordinal:function(a){return a+" වැනි"},meridiemParse:/පෙර වරු|පස් වරු|පෙ.ව|ප.ව./,isPM:function(a){return"ප.ව."===a||"පස් වරු"===a},meridiem:function(a,b,c){return a>11?c?"ප.ව.":"පස් වරු":c?"පෙ.ව.":"පෙර වරු"}});
+//! moment.js locale configuration
+//! locale : Slovak [sk]
+//! author : Martin Minka : https://github.com/k2s
+//! based on work of petrbela : https://github.com/petrbela
+var zh="január_február_marec_apríl_máj_jún_júl_august_september_október_november_december".split("_"),Ah="jan_feb_mar_apr_máj_jún_júl_aug_sep_okt_nov_dec".split("_");a.defineLocale("sk",{months:zh,monthsShort:Ah,weekdays:"nedeľa_pondelok_utorok_streda_štvrtok_piatok_sobota".split("_"),weekdaysShort:"ne_po_ut_st_št_pi_so".split("_"),weekdaysMin:"ne_po_ut_st_št_pi_so".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd D. MMMM YYYY H:mm"},calendar:{sameDay:"[dnes o] LT",nextDay:"[zajtra o] LT",nextWeek:function(){switch(this.day()){case 0:return"[v nedeľu o] LT";case 1:case 2:return"[v] dddd [o] LT";case 3:return"[v stredu o] LT";case 4:return"[vo štvrtok o] LT";case 5:return"[v piatok o] LT";case 6:return"[v sobotu o] LT"}},lastDay:"[včera o] LT",lastWeek:function(){switch(this.day()){case 0:return"[minulú nedeľu o] LT";case 1:case 2:return"[minulý] dddd [o] LT";case 3:return"[minulú stredu o] LT";case 4:case 5:return"[minulý] dddd [o] LT";case 6:return"[minulú sobotu o] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"pred %s",s:ae,m:ae,mm:ae,h:ae,hh:ae,d:ae,dd:ae,M:ae,MM:ae,y:ae,yy:ae},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),a.defineLocale("sl",{months:"januar_februar_marec_april_maj_junij_julij_avgust_september_oktober_november_december".split("_"),monthsShort:"jan._feb._mar._apr._maj._jun._jul._avg._sep._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"nedelja_ponedeljek_torek_sreda_četrtek_petek_sobota".split("_"),weekdaysShort:"ned._pon._tor._sre._čet._pet._sob.".split("_"),weekdaysMin:"ne_po_to_sr_če_pe_so".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[danes ob] LT",nextDay:"[jutri ob] LT",nextWeek:function(){switch(this.day()){case 0:return"[v] [nedeljo] [ob] LT";case 3:return"[v] [sredo] [ob] LT";case 6:return"[v] [soboto] [ob] LT";case 1:case 2:case 4:case 5:return"[v] dddd [ob] LT"}},lastDay:"[včeraj ob] LT",lastWeek:function(){switch(this.day()){case 0:return"[prejšnjo] [nedeljo] [ob] LT";case 3:return"[prejšnjo] [sredo] [ob] LT";case 6:return"[prejšnjo] [soboto] [ob] LT";case 1:case 2:case 4:case 5:return"[prejšnji] dddd [ob] LT"}},sameElse:"L"},relativeTime:{future:"čez %s",past:"pred %s",s:be,m:be,mm:be,h:be,hh:be,d:be,dd:be,M:be,MM:be,y:be,yy:be},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:7}}),
+//! moment.js locale configuration
+//! locale : Albanian [sq]
+//! author : Flakërim Ismani : https://github.com/flakerimi
+//! author : Menelion Elensúle : https://github.com/Oire
+//! author : Oerd Cukalla : https://github.com/oerd
+a.defineLocale("sq",{months:"Janar_Shkurt_Mars_Prill_Maj_Qershor_Korrik_Gusht_Shtator_Tetor_Nëntor_Dhjetor".split("_"),monthsShort:"Jan_Shk_Mar_Pri_Maj_Qer_Kor_Gus_Sht_Tet_Nën_Dhj".split("_"),weekdays:"E Diel_E Hënë_E Martë_E Mërkurë_E Enjte_E Premte_E Shtunë".split("_"),weekdaysShort:"Die_Hën_Mar_Mër_Enj_Pre_Sht".split("_"),weekdaysMin:"D_H_Ma_Më_E_P_Sh".split("_"),weekdaysParseExact:!0,meridiemParse:/PD|MD/,isPM:function(a){return"M"===a.charAt(0)},meridiem:function(a,b,c){return a<12?"PD":"MD"},longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Sot në] LT",nextDay:"[Nesër në] LT",nextWeek:"dddd [në] LT",lastDay:"[Dje në] LT",lastWeek:"dddd [e kaluar në] LT",sameElse:"L"},relativeTime:{future:"në %s",past:"%s më parë",s:"disa sekonda",m:"një minutë",mm:"%d minuta",h:"një orë",hh:"%d orë",d:"një ditë",dd:"%d ditë",M:"një muaj",MM:"%d muaj",y:"një vit",yy:"%d vite"},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Serbian Cyrillic [sr-cyrl]
+//! author : Milan Janačković<milanjanackovic@gmail.com> : https://github.com/milan-j
+var Bh={words:{//Different grammatical cases
+m:["један минут","једне минуте"],mm:["минут","минуте","минута"],h:["један сат","једног сата"],hh:["сат","сата","сати"],dd:["дан","дана","дана"],MM:["месец","месеца","месеци"],yy:["година","године","година"]},correctGrammaticalCase:function(a,b){return 1===a?b[0]:a>=2&&a<=4?b[1]:b[2]},translate:function(a,b,c){var d=Bh.words[c];return 1===c.length?b?d[0]:d[1]:a+" "+Bh.correctGrammaticalCase(a,d)}};a.defineLocale("sr-cyrl",{months:"јануар_фебруар_март_април_мај_јун_јул_август_септембар_октобар_новембар_децембар".split("_"),monthsShort:"јан._феб._мар._апр._мај_јун_јул_авг._сеп._окт._нов._дец.".split("_"),monthsParseExact:!0,weekdays:"недеља_понедељак_уторак_среда_четвртак_петак_субота".split("_"),weekdaysShort:"нед._пон._уто._сре._чет._пет._суб.".split("_"),weekdaysMin:"не_по_ут_ср_че_пе_су".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[данас у] LT",nextDay:"[сутра у] LT",nextWeek:function(){switch(this.day()){case 0:return"[у] [недељу] [у] LT";case 3:return"[у] [среду] [у] LT";case 6:return"[у] [суботу] [у] LT";case 1:case 2:case 4:case 5:return"[у] dddd [у] LT"}},lastDay:"[јуче у] LT",lastWeek:function(){var a=["[прошле] [недеље] [у] LT","[прошлог] [понедељка] [у] LT","[прошлог] [уторка] [у] LT","[прошле] [среде] [у] LT","[прошлог] [четвртка] [у] LT","[прошлог] [петка] [у] LT","[прошле] [суботе] [у] LT"];return a[this.day()]},sameElse:"L"},relativeTime:{future:"за %s",past:"пре %s",s:"неколико секунди",m:Bh.translate,mm:Bh.translate,h:Bh.translate,hh:Bh.translate,d:"дан",dd:Bh.translate,M:"месец",MM:Bh.translate,y:"годину",yy:Bh.translate},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:7}});
+//! moment.js locale configuration
+//! locale : Serbian [sr]
+//! author : Milan Janačković<milanjanackovic@gmail.com> : https://github.com/milan-j
+var Ch={words:{//Different grammatical cases
+m:["jedan minut","jedne minute"],mm:["minut","minute","minuta"],h:["jedan sat","jednog sata"],hh:["sat","sata","sati"],dd:["dan","dana","dana"],MM:["mesec","meseca","meseci"],yy:["godina","godine","godina"]},correctGrammaticalCase:function(a,b){return 1===a?b[0]:a>=2&&a<=4?b[1]:b[2]},translate:function(a,b,c){var d=Ch.words[c];return 1===c.length?b?d[0]:d[1]:a+" "+Ch.correctGrammaticalCase(a,d)}};a.defineLocale("sr",{months:"januar_februar_mart_april_maj_jun_jul_avgust_septembar_oktobar_novembar_decembar".split("_"),monthsShort:"jan._feb._mar._apr._maj_jun_jul_avg._sep._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"nedelja_ponedeljak_utorak_sreda_četvrtak_petak_subota".split("_"),weekdaysShort:"ned._pon._uto._sre._čet._pet._sub.".split("_"),weekdaysMin:"ne_po_ut_sr_če_pe_su".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[danas u] LT",nextDay:"[sutra u] LT",nextWeek:function(){switch(this.day()){case 0:return"[u] [nedelju] [u] LT";case 3:return"[u] [sredu] [u] LT";case 6:return"[u] [subotu] [u] LT";case 1:case 2:case 4:case 5:return"[u] dddd [u] LT"}},lastDay:"[juče u] LT",lastWeek:function(){var a=["[prošle] [nedelje] [u] LT","[prošlog] [ponedeljka] [u] LT","[prošlog] [utorka] [u] LT","[prošle] [srede] [u] LT","[prošlog] [četvrtka] [u] LT","[prošlog] [petka] [u] LT","[prošle] [subote] [u] LT"];return a[this.day()]},sameElse:"L"},relativeTime:{future:"za %s",past:"pre %s",s:"nekoliko sekundi",m:Ch.translate,mm:Ch.translate,h:Ch.translate,hh:Ch.translate,d:"dan",dd:Ch.translate,M:"mesec",MM:Ch.translate,y:"godinu",yy:Ch.translate},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:7}}),
+//! moment.js locale configuration
+//! locale : siSwati [ss]
+//! author : Nicolai Davies<mail@nicolai.io> : https://github.com/nicolaidavies
+a.defineLocale("ss",{months:"Bhimbidvwane_Indlovana_Indlov'lenkhulu_Mabasa_Inkhwekhweti_Inhlaba_Kholwane_Ingci_Inyoni_Imphala_Lweti_Ingongoni".split("_"),monthsShort:"Bhi_Ina_Inu_Mab_Ink_Inh_Kho_Igc_Iny_Imp_Lwe_Igo".split("_"),weekdays:"Lisontfo_Umsombuluko_Lesibili_Lesitsatfu_Lesine_Lesihlanu_Umgcibelo".split("_"),weekdaysShort:"Lis_Umb_Lsb_Les_Lsi_Lsh_Umg".split("_"),weekdaysMin:"Li_Us_Lb_Lt_Ls_Lh_Ug".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[Namuhla nga] LT",nextDay:"[Kusasa nga] LT",nextWeek:"dddd [nga] LT",lastDay:"[Itolo nga] LT",lastWeek:"dddd [leliphelile] [nga] LT",sameElse:"L"},relativeTime:{future:"nga %s",past:"wenteka nga %s",s:"emizuzwana lomcane",m:"umzuzu",mm:"%d emizuzu",h:"lihora",hh:"%d emahora",d:"lilanga",dd:"%d emalanga",M:"inyanga",MM:"%d tinyanga",y:"umnyaka",yy:"%d iminyaka"},meridiemParse:/ekuseni|emini|entsambama|ebusuku/,meridiem:function(a,b,c){return a<11?"ekuseni":a<15?"emini":a<19?"entsambama":"ebusuku"},meridiemHour:function(a,b){return 12===a&&(a=0),"ekuseni"===b?a:"emini"===b?a>=11?a:a+12:"entsambama"===b||"ebusuku"===b?0===a?0:a+12:void 0},ordinalParse:/\d{1,2}/,ordinal:"%d",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Swedish [sv]
+//! author : Jens Alm : https://github.com/ulmus
+a.defineLocale("sv",{months:"januari_februari_mars_april_maj_juni_juli_augusti_september_oktober_november_december".split("_"),monthsShort:"jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec".split("_"),weekdays:"söndag_måndag_tisdag_onsdag_torsdag_fredag_lördag".split("_"),weekdaysShort:"sön_mån_tis_ons_tor_fre_lör".split("_"),weekdaysMin:"sö_må_ti_on_to_fr_lö".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [kl.] HH:mm",LLLL:"dddd D MMMM YYYY [kl.] HH:mm",lll:"D MMM YYYY HH:mm",llll:"ddd D MMM YYYY HH:mm"},calendar:{sameDay:"[Idag] LT",nextDay:"[Imorgon] LT",lastDay:"[Igår] LT",nextWeek:"[På] dddd LT",lastWeek:"[I] dddd[s] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"för %s sedan",s:"några sekunder",m:"en minut",mm:"%d minuter",h:"en timme",hh:"%d timmar",d:"en dag",dd:"%d dagar",M:"en månad",MM:"%d månader",y:"ett år",yy:"%d år"},ordinalParse:/\d{1,2}(e|a)/,ordinal:function(a){var b=a%10,c=1===~~(a%100/10)?"e":1===b?"a":2===b?"a":"e";return a+c},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Swahili [sw]
+//! author : Fahad Kassim : https://github.com/fadsel
+a.defineLocale("sw",{months:"Januari_Februari_Machi_Aprili_Mei_Juni_Julai_Agosti_Septemba_Oktoba_Novemba_Desemba".split("_"),monthsShort:"Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ago_Sep_Okt_Nov_Des".split("_"),weekdays:"Jumapili_Jumatatu_Jumanne_Jumatano_Alhamisi_Ijumaa_Jumamosi".split("_"),weekdaysShort:"Jpl_Jtat_Jnne_Jtan_Alh_Ijm_Jmos".split("_"),weekdaysMin:"J2_J3_J4_J5_Al_Ij_J1".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[leo saa] LT",nextDay:"[kesho saa] LT",nextWeek:"[wiki ijayo] dddd [saat] LT",lastDay:"[jana] LT",lastWeek:"[wiki iliyopita] dddd [saat] LT",sameElse:"L"},relativeTime:{future:"%s baadaye",past:"tokea %s",s:"hivi punde",m:"dakika moja",mm:"dakika %d",h:"saa limoja",hh:"masaa %d",d:"siku moja",dd:"masiku %d",M:"mwezi mmoja",MM:"miezi %d",y:"mwaka mmoja",yy:"miaka %d"},week:{dow:1,// Monday is the first day of the week.
+doy:7}});
+//! moment.js locale configuration
+//! locale : Tamil [ta]
+//! author : Arjunkumar Krishnamoorthy : https://github.com/tk120404
+var Dh={1:"௧",2:"௨",3:"௩",4:"௪",5:"௫",6:"௬",7:"௭",8:"௮",9:"௯",0:"௦"},Eh={"௧":"1","௨":"2","௩":"3","௪":"4","௫":"5","௬":"6","௭":"7","௮":"8","௯":"9","௦":"0"};a.defineLocale("ta",{months:"ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்".split("_"),monthsShort:"ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்".split("_"),weekdays:"ஞாயிற்றுக்கிழமை_திங்கட்கிழமை_செவ்வாய்கிழமை_புதன்கிழமை_வியாழக்கிழமை_வெள்ளிக்கிழமை_சனிக்கிழமை".split("_"),weekdaysShort:"ஞாயிறு_திங்கள்_செவ்வாய்_புதன்_வியாழன்_வெள்ளி_சனி".split("_"),weekdaysMin:"ஞா_தி_செ_பு_வி_வெ_ச".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, HH:mm",LLLL:"dddd, D MMMM YYYY, HH:mm"},calendar:{sameDay:"[இன்று] LT",nextDay:"[நாளை] LT",nextWeek:"dddd, LT",lastDay:"[நேற்று] LT",lastWeek:"[கடந்த வாரம்] dddd, LT",sameElse:"L"},relativeTime:{future:"%s இல்",past:"%s முன்",s:"ஒரு சில விநாடிகள்",m:"ஒரு நிமிடம்",mm:"%d நிமிடங்கள்",h:"ஒரு மணி நேரம்",hh:"%d மணி நேரம்",d:"ஒரு நாள்",dd:"%d நாட்கள்",M:"ஒரு மாதம்",MM:"%d மாதங்கள்",y:"ஒரு வருடம்",yy:"%d ஆண்டுகள்"},ordinalParse:/\d{1,2}வது/,ordinal:function(a){return a+"வது"},preparse:function(a){return a.replace(/[௧௨௩௪௫௬௭௮௯௦]/g,function(a){return Eh[a]})},postformat:function(a){return a.replace(/\d/g,function(a){return Dh[a]})},
+// refer http://ta.wikipedia.org/s/1er1
+meridiemParse:/யாமம்|வைகறை|காலை|நண்பகல்|எற்பாடு|மாலை/,meridiem:function(a,b,c){return a<2?" யாமம்":a<6?" வைகறை":a<10?" காலை":a<14?" நண்பகல்":a<18?" எற்பாடு":a<22?" மாலை":" யாமம்"},meridiemHour:function(a,b){return 12===a&&(a=0),"யாமம்"===b?a<2?a:a+12:"வைகறை"===b||"காலை"===b?a:"நண்பகல்"===b&&a>=10?a:a+12},week:{dow:0,// Sunday is the first day of the week.
+doy:6}}),
+//! moment.js locale configuration
+//! locale : Telugu [te]
+//! author : Krishna Chaitanya Thota : https://github.com/kcthota
+a.defineLocale("te",{months:"జనవరి_ఫిబ్రవరి_మార్చి_ఏప్రిల్_మే_జూన్_జూలై_ఆగస్టు_సెప్టెంబర్_అక్టోబర్_నవంబర్_డిసెంబర్".split("_"),monthsShort:"జన._ఫిబ్ర._మార్చి_ఏప్రి._మే_జూన్_జూలై_ఆగ._సెప్._అక్టో._నవ._డిసె.".split("_"),monthsParseExact:!0,weekdays:"ఆదివారం_సోమవారం_మంగళవారం_బుధవారం_గురువారం_శుక్రవారం_శనివారం".split("_"),weekdaysShort:"ఆది_సోమ_మంగళ_బుధ_గురు_శుక్ర_శని".split("_"),weekdaysMin:"ఆ_సో_మం_బు_గు_శు_శ".split("_"),longDateFormat:{LT:"A h:mm",LTS:"A h:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm",LLLL:"dddd, D MMMM YYYY, A h:mm"},calendar:{sameDay:"[నేడు] LT",nextDay:"[రేపు] LT",nextWeek:"dddd, LT",lastDay:"[నిన్న] LT",lastWeek:"[గత] dddd, LT",sameElse:"L"},relativeTime:{future:"%s లో",past:"%s క్రితం",s:"కొన్ని క్షణాలు",m:"ఒక నిమిషం",mm:"%d నిమిషాలు",h:"ఒక గంట",hh:"%d గంటలు",d:"ఒక రోజు",dd:"%d రోజులు",M:"ఒక నెల",MM:"%d నెలలు",y:"ఒక సంవత్సరం",yy:"%d సంవత్సరాలు"},ordinalParse:/\d{1,2}వ/,ordinal:"%dవ",meridiemParse:/రాత్రి|ఉదయం|మధ్యాహ్నం|సాయంత్రం/,meridiemHour:function(a,b){return 12===a&&(a=0),"రాత్రి"===b?a<4?a:a+12:"ఉదయం"===b?a:"మధ్యాహ్నం"===b?a>=10?a:a+12:"సాయంత్రం"===b?a+12:void 0},meridiem:function(a,b,c){return a<4?"రాత్రి":a<10?"ఉదయం":a<17?"మధ్యాహ్నం":a<20?"సాయంత్రం":"రాత్రి"},week:{dow:0,// Sunday is the first day of the week.
+doy:6}}),
+//! moment.js locale configuration
+//! locale : Tetun Dili (East Timor) [tet]
+//! author : Joshua Brooks : https://github.com/joshbrooks
+//! author : Onorio De J. Afonso : https://github.com/marobo
+a.defineLocale("tet",{months:"Janeiru_Fevereiru_Marsu_Abril_Maiu_Juniu_Juliu_Augustu_Setembru_Outubru_Novembru_Dezembru".split("_"),monthsShort:"Jan_Fev_Mar_Abr_Mai_Jun_Jul_Aug_Set_Out_Nov_Dez".split("_"),weekdays:"Domingu_Segunda_Tersa_Kuarta_Kinta_Sexta_Sabadu".split("_"),weekdaysShort:"Dom_Seg_Ters_Kua_Kint_Sext_Sab".split("_"),weekdaysMin:"Do_Seg_Te_Ku_Ki_Sex_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Ohin iha] LT",nextDay:"[Aban iha] LT",nextWeek:"dddd [iha] LT",lastDay:"[Horiseik iha] LT",lastWeek:"dddd [semana kotuk] [iha] LT",sameElse:"L"},relativeTime:{future:"iha %s",past:"%s liuba",s:"minutu balun",m:"minutu ida",mm:"minutus %d",h:"horas ida",hh:"horas %d",d:"loron ida",dd:"loron %d",M:"fulan ida",MM:"fulan %d",y:"tinan ida",yy:"tinan %d"},ordinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(a){var b=a%10,c=1===~~(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),
+//! moment.js locale configuration
+//! locale : Thai [th]
+//! author : Kridsada Thanabulpong : https://github.com/sirn
+a.defineLocale("th",{months:"มกราคม_กุมภาพันธ์_มีนาคม_เมษายน_พฤษภาคม_มิถุนายน_กรกฎาคม_สิงหาคม_กันยายน_ตุลาคม_พฤศจิกายน_ธันวาคม".split("_"),monthsShort:"ม.ค._ก.พ._มี.ค._เม.ย._พ.ค._มิ.ย._ก.ค._ส.ค._ก.ย._ต.ค._พ.ย._ธ.ค.".split("_"),monthsParseExact:!0,weekdays:"อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัสบดี_ศุกร์_เสาร์".split("_"),weekdaysShort:"อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัส_ศุกร์_เสาร์".split("_"),// yes, three characters difference
+weekdaysMin:"อา._จ._อ._พ._พฤ._ศ._ส.".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"YYYY/MM/DD",LL:"D MMMM YYYY",LLL:"D MMMM YYYY เวลา H:mm",LLLL:"วันddddที่ D MMMM YYYY เวลา H:mm"},meridiemParse:/ก่อนเที่ยง|หลังเที่ยง/,isPM:function(a){return"หลังเที่ยง"===a},meridiem:function(a,b,c){return a<12?"ก่อนเที่ยง":"หลังเที่ยง"},calendar:{sameDay:"[วันนี้ เวลา] LT",nextDay:"[พรุ่งนี้ เวลา] LT",nextWeek:"dddd[หน้า เวลา] LT",lastDay:"[เมื่อวานนี้ เวลา] LT",lastWeek:"[วัน]dddd[ที่แล้ว เวลา] LT",sameElse:"L"},relativeTime:{future:"อีก %s",past:"%sที่แล้ว",s:"ไม่กี่วินาที",m:"1 นาที",mm:"%d นาที",h:"1 ชั่วโมง",hh:"%d ชั่วโมง",d:"1 วัน",dd:"%d วัน",M:"1 เดือน",MM:"%d เดือน",y:"1 ปี",yy:"%d ปี"}}),
+//! moment.js locale configuration
+//! locale : Tagalog (Philippines) [tl-ph]
+//! author : Dan Hagman : https://github.com/hagmandan
+a.defineLocale("tl-ph",{months:"Enero_Pebrero_Marso_Abril_Mayo_Hunyo_Hulyo_Agosto_Setyembre_Oktubre_Nobyembre_Disyembre".split("_"),monthsShort:"Ene_Peb_Mar_Abr_May_Hun_Hul_Ago_Set_Okt_Nob_Dis".split("_"),weekdays:"Linggo_Lunes_Martes_Miyerkules_Huwebes_Biyernes_Sabado".split("_"),weekdaysShort:"Lin_Lun_Mar_Miy_Huw_Biy_Sab".split("_"),weekdaysMin:"Li_Lu_Ma_Mi_Hu_Bi_Sab".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"MM/D/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY HH:mm",LLLL:"dddd, MMMM DD, YYYY HH:mm"},calendar:{sameDay:"LT [ngayong araw]",nextDay:"[Bukas ng] LT",nextWeek:"LT [sa susunod na] dddd",lastDay:"LT [kahapon]",lastWeek:"LT [noong nakaraang] dddd",sameElse:"L"},relativeTime:{future:"sa loob ng %s",past:"%s ang nakalipas",s:"ilang segundo",m:"isang minuto",mm:"%d minuto",h:"isang oras",hh:"%d oras",d:"isang araw",dd:"%d araw",M:"isang buwan",MM:"%d buwan",y:"isang taon",yy:"%d taon"},ordinalParse:/\d{1,2}/,ordinal:function(a){return a},week:{dow:1,// Monday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Klingon [tlh]
+//! author : Dominika Kruk : https://github.com/amaranthrose
+var Fh="pagh_wa’_cha’_wej_loS_vagh_jav_Soch_chorgh_Hut".split("_");a.defineLocale("tlh",{months:"tera’ jar wa’_tera’ jar cha’_tera’ jar wej_tera’ jar loS_tera’ jar vagh_tera’ jar jav_tera’ jar Soch_tera’ jar chorgh_tera’ jar Hut_tera’ jar wa’maH_tera’ jar wa’maH wa’_tera’ jar wa’maH cha’".split("_"),monthsShort:"jar wa’_jar cha’_jar wej_jar loS_jar vagh_jar jav_jar Soch_jar chorgh_jar Hut_jar wa’maH_jar wa’maH wa’_jar wa’maH cha’".split("_"),monthsParseExact:!0,weekdays:"lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj".split("_"),weekdaysShort:"lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj".split("_"),weekdaysMin:"lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[DaHjaj] LT",nextDay:"[wa’leS] LT",nextWeek:"LLL",lastDay:"[wa’Hu’] LT",lastWeek:"LLL",sameElse:"L"},relativeTime:{future:ce,past:de,s:"puS lup",m:"wa’ tup",mm:ee,h:"wa’ rep",hh:ee,d:"wa’ jaj",dd:ee,M:"wa’ jar",MM:ee,y:"wa’ DIS",yy:ee},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}});
+//! moment.js locale configuration
+//! locale : Turkish [tr]
+//! authors : Erhan Gundogan : https://github.com/erhangundogan,
+//!           Burak YiÄŸit Kaya: https://github.com/BYK
+var Gh={1:"'inci",5:"'inci",8:"'inci",70:"'inci",80:"'inci",2:"'nci",7:"'nci",20:"'nci",50:"'nci",3:"'üncü",4:"'üncü",100:"'üncü",6:"'ncı",9:"'uncu",10:"'uncu",30:"'uncu",60:"'ıncı",90:"'ıncı"};
+//! moment.js locale configuration
+//! locale : Talossan [tzl]
+//! author : Robin van der Vliet : https://github.com/robin0van0der0v
+//! author : Iustì Canun
+// After the year there should be a slash and the amount of years since December 26, 1979 in Roman numerals.
+// This is currently too difficult (maybe even impossible) to add.
+//! moment.js locale configuration
+//! locale : Central Atlas Tamazight Latin [tzm-latn]
+//! author : Abdel Said : https://github.com/abdelsaid
+//! moment.js locale configuration
+//! locale : Central Atlas Tamazight [tzm]
+//! author : Abdel Said : https://github.com/abdelsaid
+//! moment.js locale configuration
+//! locale : Uzbek [uz]
+//! author : Sardor Muminov : https://github.com/muminoff
+//! moment.js locale configuration
+//! locale : Vietnamese [vi]
+//! author : Bang Nguyen : https://github.com/bangnk
+//! moment.js locale configuration
+//! locale : Pseudo [x-pseudo]
+//! author : Andrew Hood : https://github.com/andrewhood125
+//! moment.js locale configuration
+//! locale : Chinese (China) [zh-cn]
+//! author : suupic : https://github.com/suupic
+//! author : Zeno Zeng : https://github.com/zenozeng
+//! moment.js locale configuration
+//! locale : Chinese (Hong Kong) [zh-hk]
+//! author : Ben : https://github.com/ben-lin
+//! author : Chris Lam : https://github.com/hehachris
+//! author : Konstantin : https://github.com/skfd
+//! moment.js locale configuration
+//! locale : Chinese (Taiwan) [zh-tw]
+//! author : Ben : https://github.com/ben-lin
+//! author : Chris Lam : https://github.com/hehachris
+return a.defineLocale("tr",{months:"Ocak_Şubat_Mart_Nisan_Mayıs_Haziran_Temmuz_Ağustos_Eylül_Ekim_Kasım_Aralık".split("_"),monthsShort:"Oca_Şub_Mar_Nis_May_Haz_Tem_Ağu_Eyl_Eki_Kas_Ara".split("_"),weekdays:"Pazar_Pazartesi_Salı_Çarşamba_Perşembe_Cuma_Cumartesi".split("_"),weekdaysShort:"Paz_Pts_Sal_Çar_Per_Cum_Cts".split("_"),weekdaysMin:"Pz_Pt_Sa_Ça_Pe_Cu_Ct".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[bugün saat] LT",nextDay:"[yarın saat] LT",nextWeek:"[haftaya] dddd [saat] LT",lastDay:"[dün] LT",lastWeek:"[geçen hafta] dddd [saat] LT",sameElse:"L"},relativeTime:{future:"%s sonra",past:"%s önce",s:"birkaç saniye",m:"bir dakika",mm:"%d dakika",h:"bir saat",hh:"%d saat",d:"bir gün",dd:"%d gün",M:"bir ay",MM:"%d ay",y:"bir yıl",yy:"%d yıl"},ordinalParse:/\d{1,2}'(inci|nci|üncü|ncı|uncu|ıncı)/,ordinal:function(a){if(0===a)// special case for zero
+return a+"'ıncı";var b=a%10,c=a%100-b,d=a>=100?100:null;return a+(Gh[b]||Gh[c]||Gh[d])},week:{dow:1,// Monday is the first day of the week.
+doy:7}}),a.defineLocale("tzl",{months:"Januar_Fevraglh_Març_Avrïu_Mai_Gün_Julia_Guscht_Setemvar_Listopäts_Noemvar_Zecemvar".split("_"),monthsShort:"Jan_Fev_Mar_Avr_Mai_Gün_Jul_Gus_Set_Lis_Noe_Zec".split("_"),weekdays:"Súladi_Lúneçi_Maitzi_Márcuri_Xhúadi_Viénerçi_Sáturi".split("_"),weekdaysShort:"Súl_Lún_Mai_Már_Xhú_Vié_Sát".split("_"),weekdaysMin:"Sú_Lú_Ma_Má_Xh_Vi_Sá".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD.MM.YYYY",LL:"D. MMMM [dallas] YYYY",LLL:"D. MMMM [dallas] YYYY HH.mm",LLLL:"dddd, [li] D. MMMM [dallas] YYYY HH.mm"},meridiemParse:/d\'o|d\'a/i,isPM:function(a){return"d'o"===a.toLowerCase()},meridiem:function(a,b,c){return a>11?c?"d'o":"D'O":c?"d'a":"D'A"},calendar:{sameDay:"[oxhi à] LT",nextDay:"[demà à] LT",nextWeek:"dddd [à] LT",lastDay:"[ieiri à] LT",lastWeek:"[sür el] dddd [lasteu à] LT",sameElse:"L"},relativeTime:{future:"osprei %s",past:"ja%s",s:ge,m:ge,mm:ge,h:ge,hh:ge,d:ge,dd:ge,M:ge,MM:ge,y:ge,yy:ge},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,// Monday is the first day of the week.
+doy:4}}),a.defineLocale("tzm-latn",{months:"innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir".split("_"),monthsShort:"innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir".split("_"),weekdays:"asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas".split("_"),weekdaysShort:"asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas".split("_"),weekdaysMin:"asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[asdkh g] LT",nextDay:"[aska g] LT",nextWeek:"dddd [g] LT",lastDay:"[assant g] LT",lastWeek:"dddd [g] LT",sameElse:"L"},relativeTime:{future:"dadkh s yan %s",past:"yan %s",s:"imik",m:"minuḍ",mm:"%d minuḍ",h:"saɛa",hh:"%d tassaɛin",d:"ass",dd:"%d ossan",M:"ayowr",MM:"%d iyyirn",y:"asgas",yy:"%d isgasn"},week:{dow:6,// Saturday is the first day of the week.
+doy:12}}),a.defineLocale("tzm",{months:"ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ".split("_"),monthsShort:"ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ".split("_"),weekdays:"ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ".split("_"),weekdaysShort:"ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ".split("_"),weekdaysMin:"ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[ⴰⵙⴷⵅ ⴴ] LT",nextDay:"[ⴰⵙⴽⴰ ⴴ] LT",nextWeek:"dddd [ⴴ] LT",lastDay:"[ⴰⵚⴰⵏⵜ ⴴ] LT",lastWeek:"dddd [ⴴ] LT",sameElse:"L"},relativeTime:{future:"ⴷⴰⴷⵅ ⵙ ⵢⴰⵏ %s",past:"ⵢⴰⵏ %s",s:"ⵉⵎⵉⴽ",m:"ⵎⵉⵏⵓⴺ",mm:"%d ⵎⵉⵏⵓⴺ",h:"ⵙⴰⵄⴰ",hh:"%d ⵜⴰⵙⵙⴰⵄⵉⵏ",d:"ⴰⵙⵙ",dd:"%d oⵙⵙⴰⵏ",M:"ⴰⵢoⵓⵔ",MM:"%d ⵉⵢⵢⵉⵔⵏ",y:"ⴰⵙⴳⴰⵙ",yy:"%d ⵉⵙⴳⴰⵙⵏ"},week:{dow:6,// Saturday is the first day of the week.
+doy:12}}),a.defineLocale("uk",{months:{format:"січня_лютого_березня_квітня_травня_червня_липня_серпня_вересня_жовтня_листопада_грудня".split("_"),standalone:"січень_лютий_березень_квітень_травень_червень_липень_серпень_вересень_жовтень_листопад_грудень".split("_")},monthsShort:"січ_лют_бер_квіт_трав_черв_лип_серп_вер_жовт_лист_груд".split("_"),weekdays:je,weekdaysShort:"нд_пн_вт_ср_чт_пт_сб".split("_"),weekdaysMin:"нд_пн_вт_ср_чт_пт_сб".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY р.",LLL:"D MMMM YYYY р., HH:mm",LLLL:"dddd, D MMMM YYYY р., HH:mm"},calendar:{sameDay:ke("[Сьогодні "),nextDay:ke("[Завтра "),lastDay:ke("[Вчора "),nextWeek:ke("[У] dddd ["),lastWeek:function(){switch(this.day()){case 0:case 3:case 5:case 6:return ke("[Минулої] dddd [").call(this);case 1:case 2:case 4:return ke("[Минулого] dddd [").call(this)}},sameElse:"L"},relativeTime:{future:"за %s",past:"%s тому",s:"декілька секунд",m:ie,mm:ie,h:"годину",hh:ie,d:"день",dd:ie,M:"місяць",MM:ie,y:"рік",yy:ie},
+// M. E.: those two are virtually unused but a user might want to implement them for his/her website for some reason
+meridiemParse:/ночі|ранку|дня|вечора/,isPM:function(a){return/^(дня|вечора)$/.test(a)},meridiem:function(a,b,c){return a<4?"ночі":a<12?"ранку":a<17?"дня":"вечора"},ordinalParse:/\d{1,2}-(й|го)/,ordinal:function(a,b){switch(b){case"M":case"d":case"DDD":case"w":case"W":return a+"-й";case"D":return a+"-го";default:return a}},week:{dow:1,// Monday is the first day of the week.
+doy:7}}),a.defineLocale("uz",{months:"январ_феврал_март_апрел_май_июн_июл_август_сентябр_октябр_ноябр_декабр".split("_"),monthsShort:"янв_фев_мар_апр_май_июн_июл_авг_сен_окт_ноя_дек".split("_"),weekdays:"Якшанба_Душанба_Сешанба_Чоршанба_Пайшанба_Жума_Шанба".split("_"),weekdaysShort:"Якш_Душ_Сеш_Чор_Пай_Жум_Шан".split("_"),weekdaysMin:"Як_Ду_Се_Чо_Па_Жу_Ша".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"D MMMM YYYY, dddd HH:mm"},calendar:{sameDay:"[Бугун соат] LT [да]",nextDay:"[Эртага] LT [да]",nextWeek:"dddd [куни соат] LT [да]",lastDay:"[Кеча соат] LT [да]",lastWeek:"[Утган] dddd [куни соат] LT [да]",sameElse:"L"},relativeTime:{future:"Якин %s ичида",past:"Бир неча %s олдин",s:"фурсат",m:"бир дакика",mm:"%d дакика",h:"бир соат",hh:"%d соат",d:"бир кун",dd:"%d кун",M:"бир ой",MM:"%d ой",y:"бир йил",yy:"%d йил"},week:{dow:1,// Monday is the first day of the week.
+doy:7}}),a.defineLocale("vi",{months:"tháng 1_tháng 2_tháng 3_tháng 4_tháng 5_tháng 6_tháng 7_tháng 8_tháng 9_tháng 10_tháng 11_tháng 12".split("_"),monthsShort:"Th01_Th02_Th03_Th04_Th05_Th06_Th07_Th08_Th09_Th10_Th11_Th12".split("_"),monthsParseExact:!0,weekdays:"chủ nhật_thứ hai_thứ ba_thứ tư_thứ năm_thứ sáu_thứ bảy".split("_"),weekdaysShort:"CN_T2_T3_T4_T5_T6_T7".split("_"),weekdaysMin:"CN_T2_T3_T4_T5_T6_T7".split("_"),weekdaysParseExact:!0,meridiemParse:/sa|ch/i,isPM:function(a){return/^ch$/i.test(a)},meridiem:function(a,b,c){return a<12?c?"sa":"SA":c?"ch":"CH"},longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM [năm] YYYY",LLL:"D MMMM [năm] YYYY HH:mm",LLLL:"dddd, D MMMM [năm] YYYY HH:mm",l:"DD/M/YYYY",ll:"D MMM YYYY",lll:"D MMM YYYY HH:mm",llll:"ddd, D MMM YYYY HH:mm"},calendar:{sameDay:"[Hôm nay lúc] LT",nextDay:"[Ngày mai lúc] LT",nextWeek:"dddd [tuần tới lúc] LT",lastDay:"[Hôm qua lúc] LT",lastWeek:"dddd [tuần rồi lúc] LT",sameElse:"L"},relativeTime:{future:"%s tới",past:"%s trước",s:"vài giây",m:"một phút",mm:"%d phút",h:"một giờ",hh:"%d giờ",d:"một ngày",dd:"%d ngày",M:"một tháng",MM:"%d tháng",y:"một năm",yy:"%d năm"},ordinalParse:/\d{1,2}/,ordinal:function(a){return a},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),a.defineLocale("x-pseudo",{months:"J~áñúá~rý_F~ébrú~árý_~Márc~h_Áp~ríl_~Máý_~Júñé~_Júl~ý_Áú~gúst~_Sép~témb~ér_Ó~ctób~ér_Ñ~óvém~bér_~Décé~mbér".split("_"),monthsShort:"J~áñ_~Féb_~Már_~Ápr_~Máý_~Júñ_~Júl_~Áúg_~Sép_~Óct_~Ñóv_~Déc".split("_"),monthsParseExact:!0,weekdays:"S~úñdá~ý_Mó~ñdáý~_Túé~sdáý~_Wéd~ñésd~áý_T~húrs~dáý_~Fríd~áý_S~átúr~dáý".split("_"),weekdaysShort:"S~úñ_~Móñ_~Túé_~Wéd_~Thú_~Frí_~Sát".split("_"),weekdaysMin:"S~ú_Mó~_Tú_~Wé_T~h_Fr~_Sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[T~ódá~ý át] LT",nextDay:"[T~ómó~rró~w át] LT",nextWeek:"dddd [át] LT",lastDay:"[Ý~ést~érdá~ý át] LT",lastWeek:"[L~ást] dddd [át] LT",sameElse:"L"},relativeTime:{future:"í~ñ %s",past:"%s á~gó",s:"á ~féw ~sécó~ñds",m:"á ~míñ~úté",mm:"%d m~íñú~tés",h:"á~ñ hó~úr",hh:"%d h~óúrs",d:"á ~dáý",dd:"%d d~áýs",M:"á ~móñ~th",MM:"%d m~óñt~hs",y:"á ~ýéár",yy:"%d ý~éárs"},ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(a){var b=a%10,c=1===~~(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c},week:{dow:1,// Monday is the first day of the week.
+doy:4}}),a.defineLocale("zh-cn",{months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"周日_周一_周二_周三_周四_周五_周六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),longDateFormat:{LT:"Ah点mm分",LTS:"Ah点m分s秒",L:"YYYY-MM-DD",LL:"YYYY年MMMD日",LLL:"YYYY年MMMD日Ah点mm分",LLLL:"YYYY年MMMD日ddddAh点mm分",l:"YYYY-MM-DD",ll:"YYYY年MMMD日",lll:"YYYY年MMMD日Ah点mm分",llll:"YYYY年MMMD日ddddAh点mm分"},meridiemParse:/凌晨|早上|上午|中午|下午|晚上/,meridiemHour:function(a,b){return 12===a&&(a=0),"凌晨"===b||"早上"===b||"上午"===b?a:"下午"===b||"晚上"===b?a+12:a>=11?a:a+12},meridiem:function(a,b,c){var d=100*a+b;return d<600?"凌晨":d<900?"早上":d<1130?"上午":d<1230?"中午":d<1800?"下午":"晚上"},calendar:{sameDay:function(){return 0===this.minutes()?"[今天]Ah[点整]":"[今天]LT"},nextDay:function(){return 0===this.minutes()?"[明天]Ah[点整]":"[明天]LT"},lastDay:function(){return 0===this.minutes()?"[昨天]Ah[点整]":"[昨天]LT"},nextWeek:function(){var b,c;return b=a().startOf("week"),c=this.diff(b,"days")>=7?"[下]":"[本]",0===this.minutes()?c+"dddAh点整":c+"dddAh点mm"},lastWeek:function(){var b,c;return b=a().startOf("week"),c=this.unix()<b.unix()?"[上]":"[本]",0===this.minutes()?c+"dddAh点整":c+"dddAh点mm"},sameElse:"LL"},ordinalParse:/\d{1,2}(日|月|周)/,ordinal:function(a,b){switch(b){case"d":case"D":case"DDD":return a+"日";case"M":return a+"月";case"w":case"W":return a+"周";default:return a}},relativeTime:{future:"%s内",past:"%s前",s:"几秒",m:"1 分钟",mm:"%d 分钟",h:"1 小时",hh:"%d 小时",d:"1 天",dd:"%d 天",M:"1 个月",MM:"%d 个月",y:"1 年",yy:"%d 年"},week:{
+// GB/T 7408-1994《数据元和交换格式·信息交换·日期和时间表示法》与ISO 8601:1988等效
+dow:1,// Monday is the first day of the week.
+doy:4}}),a.defineLocale("zh-hk",{months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"週日_週一_週二_週三_週四_週五_週六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),longDateFormat:{LT:"Ah點mm分",LTS:"Ah點m分s秒",L:"YYYY年MMMD日",LL:"YYYY年MMMD日",LLL:"YYYY年MMMD日Ah點mm分",LLLL:"YYYY年MMMD日ddddAh點mm分",l:"YYYY年MMMD日",ll:"YYYY年MMMD日",lll:"YYYY年MMMD日Ah點mm分",llll:"YYYY年MMMD日ddddAh點mm分"},meridiemParse:/凌晨|早上|上午|中午|下午|晚上/,meridiemHour:function(a,b){return 12===a&&(a=0),"凌晨"===b||"早上"===b||"上午"===b?a:"中午"===b?a>=11?a:a+12:"下午"===b||"晚上"===b?a+12:void 0},meridiem:function(a,b,c){var d=100*a+b;return d<600?"凌晨":d<900?"早上":d<1130?"上午":d<1230?"中午":d<1800?"下午":"晚上"},calendar:{sameDay:"[今天]LT",nextDay:"[明天]LT",nextWeek:"[下]ddddLT",lastDay:"[昨天]LT",lastWeek:"[上]ddddLT",sameElse:"L"},ordinalParse:/\d{1,2}(日|月|週)/,ordinal:function(a,b){switch(b){case"d":case"D":case"DDD":return a+"日";case"M":return a+"月";case"w":case"W":return a+"週";default:return a}},relativeTime:{future:"%s內",past:"%s前",s:"幾秒",m:"1 分鐘",mm:"%d 分鐘",h:"1 小時",hh:"%d 小時",d:"1 天",dd:"%d 天",M:"1 個月",MM:"%d 個月",y:"1 年",yy:"%d 年"}}),a.defineLocale("zh-tw",{months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"週日_週一_週二_週三_週四_週五_週六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),longDateFormat:{LT:"Ah點mm分",LTS:"Ah點m分s秒",L:"YYYY年MMMD日",LL:"YYYY年MMMD日",LLL:"YYYY年MMMD日Ah點mm分",LLLL:"YYYY年MMMD日ddddAh點mm分",l:"YYYY年MMMD日",ll:"YYYY年MMMD日",lll:"YYYY年MMMD日Ah點mm分",llll:"YYYY年MMMD日ddddAh點mm分"},meridiemParse:/凌晨|早上|上午|中午|下午|晚上/,meridiemHour:function(a,b){return 12===a&&(a=0),"凌晨"===b||"早上"===b||"上午"===b?a:"中午"===b?a>=11?a:a+12:"下午"===b||"晚上"===b?a+12:void 0},meridiem:function(a,b,c){var d=100*a+b;return d<600?"凌晨":d<900?"早上":d<1130?"上午":d<1230?"中午":d<1800?"下午":"晚上"},calendar:{sameDay:"[今天]LT",nextDay:"[明天]LT",nextWeek:"[下]ddddLT",lastDay:"[昨天]LT",lastWeek:"[上]ddddLT",sameElse:"L"},ordinalParse:/\d{1,2}(日|月|週)/,ordinal:function(a,b){switch(b){case"d":case"D":case"DDD":return a+"日";case"M":return a+"月";case"w":case"W":return a+"週";default:return a}},relativeTime:{future:"%s內",past:"%s前",s:"幾秒",m:"1 分鐘",mm:"%d 分鐘",h:"1 小時",hh:"%d 小時",d:"1 天",dd:"%d 天",M:"1 個月",MM:"%d 個月",y:"1 年",yy:"%d 年"}}),a.locale("en"),a});
\ No newline at end of file
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/min/moment.min.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/min/moment.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..097938e26b11b62516b8e065968644fc9d101903
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/min/moment.min.js
@@ -0,0 +1,551 @@
+//! moment.js
+//! version : 2.16.0
+//! authors : Tim Wood, Iskren Chernev, Moment.js contributors
+//! license : MIT
+//! momentjs.com
+!function(a,b){"object"==typeof exports&&"undefined"!=typeof module?module.exports=b():"function"==typeof define&&define.amd?define(b):a.moment=b()}(this,function(){"use strict";function a(){return od.apply(null,arguments)}
+// This is done to register the method called with moment()
+// without creating circular dependencies.
+function b(a){od=a}function c(a){return a instanceof Array||"[object Array]"===Object.prototype.toString.call(a)}function d(a){
+// IE8 will treat undefined and null as object if it wasn't for
+// input != null
+return null!=a&&"[object Object]"===Object.prototype.toString.call(a)}function e(a){var b;for(b in a)
+// even if its not own property I'd still call it non-empty
+return!1;return!0}function f(a){return"number"==typeof value||"[object Number]"===Object.prototype.toString.call(a)}function g(a){return a instanceof Date||"[object Date]"===Object.prototype.toString.call(a)}function h(a,b){var c,d=[];for(c=0;c<a.length;++c)d.push(b(a[c],c));return d}function i(a,b){return Object.prototype.hasOwnProperty.call(a,b)}function j(a,b){for(var c in b)i(b,c)&&(a[c]=b[c]);return i(b,"toString")&&(a.toString=b.toString),i(b,"valueOf")&&(a.valueOf=b.valueOf),a}function k(a,b,c,d){return rb(a,b,c,d,!0).utc()}function l(){
+// We need to deep clone this object.
+return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1,parsedDateParts:[],meridiem:null}}function m(a){return null==a._pf&&(a._pf=l()),a._pf}function n(a){if(null==a._isValid){var b=m(a),c=qd.call(b.parsedDateParts,function(a){return null!=a}),d=!isNaN(a._d.getTime())&&b.overflow<0&&!b.empty&&!b.invalidMonth&&!b.invalidWeekday&&!b.nullInput&&!b.invalidFormat&&!b.userInvalidated&&(!b.meridiem||b.meridiem&&c);if(a._strict&&(d=d&&0===b.charsLeftOver&&0===b.unusedTokens.length&&void 0===b.bigHour),null!=Object.isFrozen&&Object.isFrozen(a))return d;a._isValid=d}return a._isValid}function o(a){var b=k(NaN);return null!=a?j(m(b),a):m(b).userInvalidated=!0,b}function p(a){return void 0===a}function q(a,b){var c,d,e;if(p(b._isAMomentObject)||(a._isAMomentObject=b._isAMomentObject),p(b._i)||(a._i=b._i),p(b._f)||(a._f=b._f),p(b._l)||(a._l=b._l),p(b._strict)||(a._strict=b._strict),p(b._tzm)||(a._tzm=b._tzm),p(b._isUTC)||(a._isUTC=b._isUTC),p(b._offset)||(a._offset=b._offset),p(b._pf)||(a._pf=m(b)),p(b._locale)||(a._locale=b._locale),rd.length>0)for(c in rd)d=rd[c],e=b[d],p(e)||(a[d]=e);return a}
+// Moment prototype object
+function r(b){q(this,b),this._d=new Date(null!=b._d?b._d.getTime():NaN),
+// Prevent infinite loop in case updateOffset creates new moment
+// objects.
+sd===!1&&(sd=!0,a.updateOffset(this),sd=!1)}function s(a){return a instanceof r||null!=a&&null!=a._isAMomentObject}function t(a){return a<0?Math.ceil(a)||0:Math.floor(a)}function u(a){var b=+a,c=0;return 0!==b&&isFinite(b)&&(c=t(b)),c}
+// compare two arrays, return the number of differences
+function v(a,b,c){var d,e=Math.min(a.length,b.length),f=Math.abs(a.length-b.length),g=0;for(d=0;d<e;d++)(c&&a[d]!==b[d]||!c&&u(a[d])!==u(b[d]))&&g++;return g+f}function w(b){a.suppressDeprecationWarnings===!1&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+b)}function x(b,c){var d=!0;return j(function(){if(null!=a.deprecationHandler&&a.deprecationHandler(null,b),d){for(var e,f=[],g=0;g<arguments.length;g++){if(e="","object"==typeof arguments[g]){e+="\n["+g+"] ";for(var h in arguments[0])e+=h+": "+arguments[0][h]+", ";e=e.slice(0,-2)}else e=arguments[g];f.push(e)}w(b+"\nArguments: "+Array.prototype.slice.call(f).join("")+"\n"+(new Error).stack),d=!1}return c.apply(this,arguments)},c)}function y(b,c){null!=a.deprecationHandler&&a.deprecationHandler(b,c),td[b]||(w(c),td[b]=!0)}function z(a){return a instanceof Function||"[object Function]"===Object.prototype.toString.call(a)}function A(a){var b,c;for(c in a)b=a[c],z(b)?this[c]=b:this["_"+c]=b;this._config=a,
+// Lenient ordinal parsing accepts just a number in addition to
+// number + (possibly) stuff coming from _ordinalParseLenient.
+this._ordinalParseLenient=new RegExp(this._ordinalParse.source+"|"+/\d{1,2}/.source)}function B(a,b){var c,e=j({},a);for(c in b)i(b,c)&&(d(a[c])&&d(b[c])?(e[c]={},j(e[c],a[c]),j(e[c],b[c])):null!=b[c]?e[c]=b[c]:delete e[c]);for(c in a)i(a,c)&&!i(b,c)&&d(a[c])&&(
+// make sure changes to properties don't modify parent config
+e[c]=j({},e[c]));return e}function C(a){null!=a&&this.set(a)}function D(a,b,c){var d=this._calendar[a]||this._calendar.sameElse;return z(d)?d.call(b,c):d}function E(a){var b=this._longDateFormat[a],c=this._longDateFormat[a.toUpperCase()];return b||!c?b:(this._longDateFormat[a]=c.replace(/MMMM|MM|DD|dddd/g,function(a){return a.slice(1)}),this._longDateFormat[a])}function F(){return this._invalidDate}function G(a){return this._ordinal.replace("%d",a)}function H(a,b,c,d){var e=this._relativeTime[c];return z(e)?e(a,b,c,d):e.replace(/%d/i,a)}function I(a,b){var c=this._relativeTime[a>0?"future":"past"];return z(c)?c(b):c.replace(/%s/i,b)}function J(a,b){var c=a.toLowerCase();Dd[c]=Dd[c+"s"]=Dd[b]=a}function K(a){return"string"==typeof a?Dd[a]||Dd[a.toLowerCase()]:void 0}function L(a){var b,c,d={};for(c in a)i(a,c)&&(b=K(c),b&&(d[b]=a[c]));return d}function M(a,b){Ed[a]=b}function N(a){var b=[];for(var c in a)b.push({unit:c,priority:Ed[c]});return b.sort(function(a,b){return a.priority-b.priority}),b}function O(b,c){return function(d){return null!=d?(Q(this,b,d),a.updateOffset(this,c),this):P(this,b)}}function P(a,b){return a.isValid()?a._d["get"+(a._isUTC?"UTC":"")+b]():NaN}function Q(a,b,c){a.isValid()&&a._d["set"+(a._isUTC?"UTC":"")+b](c)}
+// MOMENTS
+function R(a){return a=K(a),z(this[a])?this[a]():this}function S(a,b){if("object"==typeof a){a=L(a);for(var c=N(a),d=0;d<c.length;d++)this[c[d].unit](a[c[d].unit])}else if(a=K(a),z(this[a]))return this[a](b);return this}function T(a,b,c){var d=""+Math.abs(a),e=b-d.length,f=a>=0;return(f?c?"+":"":"-")+Math.pow(10,Math.max(0,e)).toString().substr(1)+d}
+// token:    'M'
+// padded:   ['MM', 2]
+// ordinal:  'Mo'
+// callback: function () { this.month() + 1 }
+function U(a,b,c,d){var e=d;"string"==typeof d&&(e=function(){return this[d]()}),a&&(Id[a]=e),b&&(Id[b[0]]=function(){return T(e.apply(this,arguments),b[1],b[2])}),c&&(Id[c]=function(){return this.localeData().ordinal(e.apply(this,arguments),a)})}function V(a){return a.match(/\[[\s\S]/)?a.replace(/^\[|\]$/g,""):a.replace(/\\/g,"")}function W(a){var b,c,d=a.match(Fd);for(b=0,c=d.length;b<c;b++)Id[d[b]]?d[b]=Id[d[b]]:d[b]=V(d[b]);return function(b){var e,f="";for(e=0;e<c;e++)f+=d[e]instanceof Function?d[e].call(b,a):d[e];return f}}
+// format date using native date object
+function X(a,b){return a.isValid()?(b=Y(b,a.localeData()),Hd[b]=Hd[b]||W(b),Hd[b](a)):a.localeData().invalidDate()}function Y(a,b){function c(a){return b.longDateFormat(a)||a}var d=5;for(Gd.lastIndex=0;d>=0&&Gd.test(a);)a=a.replace(Gd,c),Gd.lastIndex=0,d-=1;return a}function Z(a,b,c){$d[a]=z(b)?b:function(a,d){return a&&c?c:b}}function $(a,b){return i($d,a)?$d[a](b._strict,b._locale):new RegExp(_(a))}
+// Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
+function _(a){return aa(a.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(a,b,c,d,e){return b||c||d||e}))}function aa(a){return a.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function ba(a,b){var c,d=b;for("string"==typeof a&&(a=[a]),f(b)&&(d=function(a,c){c[b]=u(a)}),c=0;c<a.length;c++)_d[a[c]]=d}function ca(a,b){ba(a,function(a,c,d,e){d._w=d._w||{},b(a,d._w,d,e)})}function da(a,b,c){null!=b&&i(_d,a)&&_d[a](b,c._a,c,a)}function ea(a,b){return new Date(Date.UTC(a,b+1,0)).getUTCDate()}function fa(a,b){return a?c(this._months)?this._months[a.month()]:this._months[(this._months.isFormat||ke).test(b)?"format":"standalone"][a.month()]:this._months}function ga(a,b){return a?c(this._monthsShort)?this._monthsShort[a.month()]:this._monthsShort[ke.test(b)?"format":"standalone"][a.month()]:this._monthsShort}function ha(a,b,c){var d,e,f,g=a.toLocaleLowerCase();if(!this._monthsParse)for(
+// this is not used
+this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[],d=0;d<12;++d)f=k([2e3,d]),this._shortMonthsParse[d]=this.monthsShort(f,"").toLocaleLowerCase(),this._longMonthsParse[d]=this.months(f,"").toLocaleLowerCase();return c?"MMM"===b?(e=je.call(this._shortMonthsParse,g),e!==-1?e:null):(e=je.call(this._longMonthsParse,g),e!==-1?e:null):"MMM"===b?(e=je.call(this._shortMonthsParse,g),e!==-1?e:(e=je.call(this._longMonthsParse,g),e!==-1?e:null)):(e=je.call(this._longMonthsParse,g),e!==-1?e:(e=je.call(this._shortMonthsParse,g),e!==-1?e:null))}function ia(a,b,c){var d,e,f;if(this._monthsParseExact)return ha.call(this,a,b,c);
+// TODO: add sorting
+// Sorting makes sure if one month (or abbr) is a prefix of another
+// see sorting in computeMonthsParse
+for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),d=0;d<12;d++){
+// test the regex
+if(
+// make the regex if we don't have it already
+e=k([2e3,d]),c&&!this._longMonthsParse[d]&&(this._longMonthsParse[d]=new RegExp("^"+this.months(e,"").replace(".","")+"$","i"),this._shortMonthsParse[d]=new RegExp("^"+this.monthsShort(e,"").replace(".","")+"$","i")),c||this._monthsParse[d]||(f="^"+this.months(e,"")+"|^"+this.monthsShort(e,""),this._monthsParse[d]=new RegExp(f.replace(".",""),"i")),c&&"MMMM"===b&&this._longMonthsParse[d].test(a))return d;if(c&&"MMM"===b&&this._shortMonthsParse[d].test(a))return d;if(!c&&this._monthsParse[d].test(a))return d}}
+// MOMENTS
+function ja(a,b){var c;if(!a.isValid())
+// No op
+return a;if("string"==typeof b)if(/^\d+$/.test(b))b=u(b);else
+// TODO: Another silent failure?
+if(b=a.localeData().monthsParse(b),!f(b))return a;return c=Math.min(a.date(),ea(a.year(),b)),a._d["set"+(a._isUTC?"UTC":"")+"Month"](b,c),a}function ka(b){return null!=b?(ja(this,b),a.updateOffset(this,!0),this):P(this,"Month")}function la(){return ea(this.year(),this.month())}function ma(a){return this._monthsParseExact?(i(this,"_monthsRegex")||oa.call(this),a?this._monthsShortStrictRegex:this._monthsShortRegex):(i(this,"_monthsShortRegex")||(this._monthsShortRegex=ne),this._monthsShortStrictRegex&&a?this._monthsShortStrictRegex:this._monthsShortRegex)}function na(a){return this._monthsParseExact?(i(this,"_monthsRegex")||oa.call(this),a?this._monthsStrictRegex:this._monthsRegex):(i(this,"_monthsRegex")||(this._monthsRegex=oe),this._monthsStrictRegex&&a?this._monthsStrictRegex:this._monthsRegex)}function oa(){function a(a,b){return b.length-a.length}var b,c,d=[],e=[],f=[];for(b=0;b<12;b++)
+// make the regex if we don't have it already
+c=k([2e3,b]),d.push(this.monthsShort(c,"")),e.push(this.months(c,"")),f.push(this.months(c,"")),f.push(this.monthsShort(c,""));for(
+// Sorting makes sure if one month (or abbr) is a prefix of another it
+// will match the longer piece.
+d.sort(a),e.sort(a),f.sort(a),b=0;b<12;b++)d[b]=aa(d[b]),e[b]=aa(e[b]);for(b=0;b<24;b++)f[b]=aa(f[b]);this._monthsRegex=new RegExp("^("+f.join("|")+")","i"),this._monthsShortRegex=this._monthsRegex,this._monthsStrictRegex=new RegExp("^("+e.join("|")+")","i"),this._monthsShortStrictRegex=new RegExp("^("+d.join("|")+")","i")}
+// HELPERS
+function pa(a){return qa(a)?366:365}function qa(a){return a%4===0&&a%100!==0||a%400===0}function ra(){return qa(this.year())}function sa(a,b,c,d,e,f,g){
+//can't just apply() to create a date:
+//http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply
+var h=new Date(a,b,c,d,e,f,g);
+//the date constructor remaps years 0-99 to 1900-1999
+return a<100&&a>=0&&isFinite(h.getFullYear())&&h.setFullYear(a),h}function ta(a){var b=new Date(Date.UTC.apply(null,arguments));
+//the Date.UTC function remaps years 0-99 to 1900-1999
+return a<100&&a>=0&&isFinite(b.getUTCFullYear())&&b.setUTCFullYear(a),b}
+// start-of-first-week - start-of-year
+function ua(a,b,c){var// first-week day -- which january is always in the first week (4 for iso, 1 for other)
+d=7+b-c,
+// first-week day local weekday -- which local weekday is fwd
+e=(7+ta(a,0,d).getUTCDay()-b)%7;return-e+d-1}
+//http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
+function va(a,b,c,d,e){var f,g,h=(7+c-d)%7,i=ua(a,d,e),j=1+7*(b-1)+h+i;return j<=0?(f=a-1,g=pa(f)+j):j>pa(a)?(f=a+1,g=j-pa(a)):(f=a,g=j),{year:f,dayOfYear:g}}function wa(a,b,c){var d,e,f=ua(a.year(),b,c),g=Math.floor((a.dayOfYear()-f-1)/7)+1;return g<1?(e=a.year()-1,d=g+xa(e,b,c)):g>xa(a.year(),b,c)?(d=g-xa(a.year(),b,c),e=a.year()+1):(e=a.year(),d=g),{week:d,year:e}}function xa(a,b,c){var d=ua(a,b,c),e=ua(a+1,b,c);return(pa(a)-d+e)/7}
+// HELPERS
+// LOCALES
+function ya(a){return wa(a,this._week.dow,this._week.doy).week}function za(){return this._week.dow}function Aa(){return this._week.doy}
+// MOMENTS
+function Ba(a){var b=this.localeData().week(this);return null==a?b:this.add(7*(a-b),"d")}function Ca(a){var b=wa(this,1,4).week;return null==a?b:this.add(7*(a-b),"d")}
+// HELPERS
+function Da(a,b){return"string"!=typeof a?a:isNaN(a)?(a=b.weekdaysParse(a),"number"==typeof a?a:null):parseInt(a,10)}function Ea(a,b){return"string"==typeof a?b.weekdaysParse(a)%7||7:isNaN(a)?null:a}function Fa(a,b){return a?c(this._weekdays)?this._weekdays[a.day()]:this._weekdays[this._weekdays.isFormat.test(b)?"format":"standalone"][a.day()]:this._weekdays}function Ga(a){return a?this._weekdaysShort[a.day()]:this._weekdaysShort}function Ha(a){return a?this._weekdaysMin[a.day()]:this._weekdaysMin}function Ia(a,b,c){var d,e,f,g=a.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],d=0;d<7;++d)f=k([2e3,1]).day(d),this._minWeekdaysParse[d]=this.weekdaysMin(f,"").toLocaleLowerCase(),this._shortWeekdaysParse[d]=this.weekdaysShort(f,"").toLocaleLowerCase(),this._weekdaysParse[d]=this.weekdays(f,"").toLocaleLowerCase();return c?"dddd"===b?(e=je.call(this._weekdaysParse,g),e!==-1?e:null):"ddd"===b?(e=je.call(this._shortWeekdaysParse,g),e!==-1?e:null):(e=je.call(this._minWeekdaysParse,g),e!==-1?e:null):"dddd"===b?(e=je.call(this._weekdaysParse,g),e!==-1?e:(e=je.call(this._shortWeekdaysParse,g),e!==-1?e:(e=je.call(this._minWeekdaysParse,g),e!==-1?e:null))):"ddd"===b?(e=je.call(this._shortWeekdaysParse,g),e!==-1?e:(e=je.call(this._weekdaysParse,g),e!==-1?e:(e=je.call(this._minWeekdaysParse,g),e!==-1?e:null))):(e=je.call(this._minWeekdaysParse,g),e!==-1?e:(e=je.call(this._weekdaysParse,g),e!==-1?e:(e=je.call(this._shortWeekdaysParse,g),e!==-1?e:null)))}function Ja(a,b,c){var d,e,f;if(this._weekdaysParseExact)return Ia.call(this,a,b,c);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),d=0;d<7;d++){
+// test the regex
+if(
+// make the regex if we don't have it already
+e=k([2e3,1]).day(d),c&&!this._fullWeekdaysParse[d]&&(this._fullWeekdaysParse[d]=new RegExp("^"+this.weekdays(e,"").replace(".",".?")+"$","i"),this._shortWeekdaysParse[d]=new RegExp("^"+this.weekdaysShort(e,"").replace(".",".?")+"$","i"),this._minWeekdaysParse[d]=new RegExp("^"+this.weekdaysMin(e,"").replace(".",".?")+"$","i")),this._weekdaysParse[d]||(f="^"+this.weekdays(e,"")+"|^"+this.weekdaysShort(e,"")+"|^"+this.weekdaysMin(e,""),this._weekdaysParse[d]=new RegExp(f.replace(".",""),"i")),c&&"dddd"===b&&this._fullWeekdaysParse[d].test(a))return d;if(c&&"ddd"===b&&this._shortWeekdaysParse[d].test(a))return d;if(c&&"dd"===b&&this._minWeekdaysParse[d].test(a))return d;if(!c&&this._weekdaysParse[d].test(a))return d}}
+// MOMENTS
+function Ka(a){if(!this.isValid())return null!=a?this:NaN;var b=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=a?(a=Da(a,this.localeData()),this.add(a-b,"d")):b}function La(a){if(!this.isValid())return null!=a?this:NaN;var b=(this.day()+7-this.localeData()._week.dow)%7;return null==a?b:this.add(a-b,"d")}function Ma(a){if(!this.isValid())return null!=a?this:NaN;
+// behaves the same as moment#day except
+// as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
+// as a setter, sunday should belong to the previous week.
+if(null!=a){var b=Ea(a,this.localeData());return this.day(this.day()%7?b:b-7)}return this.day()||7}function Na(a){return this._weekdaysParseExact?(i(this,"_weekdaysRegex")||Qa.call(this),a?this._weekdaysStrictRegex:this._weekdaysRegex):(i(this,"_weekdaysRegex")||(this._weekdaysRegex=ue),this._weekdaysStrictRegex&&a?this._weekdaysStrictRegex:this._weekdaysRegex)}function Oa(a){return this._weekdaysParseExact?(i(this,"_weekdaysRegex")||Qa.call(this),a?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(i(this,"_weekdaysShortRegex")||(this._weekdaysShortRegex=ve),this._weekdaysShortStrictRegex&&a?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)}function Pa(a){return this._weekdaysParseExact?(i(this,"_weekdaysRegex")||Qa.call(this),a?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(i(this,"_weekdaysMinRegex")||(this._weekdaysMinRegex=we),this._weekdaysMinStrictRegex&&a?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)}function Qa(){function a(a,b){return b.length-a.length}var b,c,d,e,f,g=[],h=[],i=[],j=[];for(b=0;b<7;b++)
+// make the regex if we don't have it already
+c=k([2e3,1]).day(b),d=this.weekdaysMin(c,""),e=this.weekdaysShort(c,""),f=this.weekdays(c,""),g.push(d),h.push(e),i.push(f),j.push(d),j.push(e),j.push(f);for(
+// Sorting makes sure if one weekday (or abbr) is a prefix of another it
+// will match the longer piece.
+g.sort(a),h.sort(a),i.sort(a),j.sort(a),b=0;b<7;b++)h[b]=aa(h[b]),i[b]=aa(i[b]),j[b]=aa(j[b]);this._weekdaysRegex=new RegExp("^("+j.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+i.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+h.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+g.join("|")+")","i")}
+// FORMATTING
+function Ra(){return this.hours()%12||12}function Sa(){return this.hours()||24}function Ta(a,b){U(a,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),b)})}
+// PARSING
+function Ua(a,b){return b._meridiemParse}
+// LOCALES
+function Va(a){
+// IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
+// Using charAt should be more compatible.
+return"p"===(a+"").toLowerCase().charAt(0)}function Wa(a,b,c){return a>11?c?"pm":"PM":c?"am":"AM"}function Xa(a){return a?a.toLowerCase().replace("_","-"):a}
+// pick the locale from the array
+// try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
+// substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
+function Ya(a){for(var b,c,d,e,f=0;f<a.length;){for(e=Xa(a[f]).split("-"),b=e.length,c=Xa(a[f+1]),c=c?c.split("-"):null;b>0;){if(d=Za(e.slice(0,b).join("-")))return d;if(c&&c.length>=b&&v(e,c,!0)>=b-1)
+//the next array item is better than a shallower substring of this one
+break;b--}f++}return null}function Za(a){var b=null;
+// TODO: Find a better way to register and load all the locales in Node
+if(!Be[a]&&"undefined"!=typeof module&&module&&module.exports)try{b=xe._abbr,require("./locale/"+a),
+// because defineLocale currently also sets the global locale, we
+// want to undo that for lazy loaded locales
+$a(b)}catch(a){}return Be[a]}
+// This function will load locale and then set the global locale.  If
+// no arguments are passed in, it will simply return the current global
+// locale key.
+function $a(a,b){var c;
+// moment.duration._locale = moment._locale = data;
+return a&&(c=p(b)?bb(a):_a(a,b),c&&(xe=c)),xe._abbr}function _a(a,b){if(null!==b){var c=Ae;if(b.abbr=a,null!=Be[a])y("defineLocaleOverride","use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."),c=Be[a]._config;else if(null!=b.parentLocale){if(null==Be[b.parentLocale])return Ce[b.parentLocale]||(Ce[b.parentLocale]=[]),Ce[b.parentLocale].push({name:a,config:b}),null;c=Be[b.parentLocale]._config}
+// backwards compat for now: also set the locale
+// make sure we set the locale AFTER all child locales have been
+// created, so we won't end up with the child locale set.
+return Be[a]=new C(B(c,b)),Ce[a]&&Ce[a].forEach(function(a){_a(a.name,a.config)}),$a(a),Be[a]}
+// useful for testing
+return delete Be[a],null}function ab(a,b){if(null!=b){var c,d=Ae;
+// MERGE
+null!=Be[a]&&(d=Be[a]._config),b=B(d,b),c=new C(b),c.parentLocale=Be[a],Be[a]=c,
+// backwards compat for now: also set the locale
+$a(a)}else
+// pass null for config to unupdate, useful for tests
+null!=Be[a]&&(null!=Be[a].parentLocale?Be[a]=Be[a].parentLocale:null!=Be[a]&&delete Be[a]);return Be[a]}
+// returns locale data
+function bb(a){var b;if(a&&a._locale&&a._locale._abbr&&(a=a._locale._abbr),!a)return xe;if(!c(a)){if(
+//short-circuit everything else
+b=Za(a))return b;a=[a]}return Ya(a)}function cb(){return wd(Be)}function db(a){var b,c=a._a;return c&&m(a).overflow===-2&&(b=c[be]<0||c[be]>11?be:c[ce]<1||c[ce]>ea(c[ae],c[be])?ce:c[de]<0||c[de]>24||24===c[de]&&(0!==c[ee]||0!==c[fe]||0!==c[ge])?de:c[ee]<0||c[ee]>59?ee:c[fe]<0||c[fe]>59?fe:c[ge]<0||c[ge]>999?ge:-1,m(a)._overflowDayOfYear&&(b<ae||b>ce)&&(b=ce),m(a)._overflowWeeks&&b===-1&&(b=he),m(a)._overflowWeekday&&b===-1&&(b=ie),m(a).overflow=b),a}
+// date from iso format
+function eb(a){var b,c,d,e,f,g,h=a._i,i=De.exec(h)||Ee.exec(h);if(i){for(m(a).iso=!0,b=0,c=Ge.length;b<c;b++)if(Ge[b][1].exec(i[1])){e=Ge[b][0],d=Ge[b][2]!==!1;break}if(null==e)return void(a._isValid=!1);if(i[3]){for(b=0,c=He.length;b<c;b++)if(He[b][1].exec(i[3])){
+// match[2] should be 'T' or space
+f=(i[2]||" ")+He[b][0];break}if(null==f)return void(a._isValid=!1)}if(!d&&null!=f)return void(a._isValid=!1);if(i[4]){if(!Fe.exec(i[4]))return void(a._isValid=!1);g="Z"}a._f=e+(f||"")+(g||""),kb(a)}else a._isValid=!1}
+// date from iso format or fallback
+function fb(b){var c=Ie.exec(b._i);return null!==c?void(b._d=new Date(+c[1])):(eb(b),void(b._isValid===!1&&(delete b._isValid,a.createFromInputFallback(b))))}
+// Pick the first defined of two or three arguments.
+function gb(a,b,c){return null!=a?a:null!=b?b:c}function hb(b){
+// hooks is actually the exported moment object
+var c=new Date(a.now());return b._useUTC?[c.getUTCFullYear(),c.getUTCMonth(),c.getUTCDate()]:[c.getFullYear(),c.getMonth(),c.getDate()]}
+// convert an array to a date.
+// the array should mirror the parameters below
+// note: all values past the year are optional and will default to the lowest possible value.
+// [year, month, day , hour, minute, second, millisecond]
+function ib(a){var b,c,d,e,f=[];if(!a._d){
+// Default to current date.
+// * if no year, month, day of month are given, default to today
+// * if day of month is given, default month and year
+// * if month is given, default only year
+// * if year is given, don't default anything
+for(d=hb(a),
+//compute day of the year from weeks and weekdays
+a._w&&null==a._a[ce]&&null==a._a[be]&&jb(a),
+//if the day of the year is set, figure out what it is
+a._dayOfYear&&(e=gb(a._a[ae],d[ae]),a._dayOfYear>pa(e)&&(m(a)._overflowDayOfYear=!0),c=ta(e,0,a._dayOfYear),a._a[be]=c.getUTCMonth(),a._a[ce]=c.getUTCDate()),b=0;b<3&&null==a._a[b];++b)a._a[b]=f[b]=d[b];
+// Zero out whatever was not defaulted, including time
+for(;b<7;b++)a._a[b]=f[b]=null==a._a[b]?2===b?1:0:a._a[b];
+// Check for 24:00:00.000
+24===a._a[de]&&0===a._a[ee]&&0===a._a[fe]&&0===a._a[ge]&&(a._nextDay=!0,a._a[de]=0),a._d=(a._useUTC?ta:sa).apply(null,f),
+// Apply timezone offset from input. The actual utcOffset can be changed
+// with parseZone.
+null!=a._tzm&&a._d.setUTCMinutes(a._d.getUTCMinutes()-a._tzm),a._nextDay&&(a._a[de]=24)}}function jb(a){var b,c,d,e,f,g,h,i;if(b=a._w,null!=b.GG||null!=b.W||null!=b.E)f=1,g=4,
+// TODO: We need to take the current isoWeekYear, but that depends on
+// how we interpret now (local, utc, fixed offset). So create
+// a now version of current config (take local/utc/offset flags, and
+// create now).
+c=gb(b.GG,a._a[ae],wa(sb(),1,4).year),d=gb(b.W,1),e=gb(b.E,1),(e<1||e>7)&&(i=!0);else{f=a._locale._week.dow,g=a._locale._week.doy;var j=wa(sb(),f,g);c=gb(b.gg,a._a[ae],j.year),
+// Default to current week.
+d=gb(b.w,j.week),null!=b.d?(
+// weekday -- low day numbers are considered next week
+e=b.d,(e<0||e>6)&&(i=!0)):null!=b.e?(
+// local weekday -- counting starts from begining of week
+e=b.e+f,(b.e<0||b.e>6)&&(i=!0)):
+// default to begining of week
+e=f}d<1||d>xa(c,f,g)?m(a)._overflowWeeks=!0:null!=i?m(a)._overflowWeekday=!0:(h=va(c,d,e,f,g),a._a[ae]=h.year,a._dayOfYear=h.dayOfYear)}
+// date from string and format string
+function kb(b){
+// TODO: Move this to another part of the creation flow to prevent circular deps
+if(b._f===a.ISO_8601)return void eb(b);b._a=[],m(b).empty=!0;
+// This array is used to make a Date, either with `new Date` or `Date.UTC`
+var c,d,e,f,g,h=""+b._i,i=h.length,j=0;for(e=Y(b._f,b._locale).match(Fd)||[],c=0;c<e.length;c++)f=e[c],d=(h.match($(f,b))||[])[0],
+// console.log('token', token, 'parsedInput', parsedInput,
+//         'regex', getParseRegexForToken(token, config));
+d&&(g=h.substr(0,h.indexOf(d)),g.length>0&&m(b).unusedInput.push(g),h=h.slice(h.indexOf(d)+d.length),j+=d.length),
+// don't parse if it's not a known token
+Id[f]?(d?m(b).empty=!1:m(b).unusedTokens.push(f),da(f,d,b)):b._strict&&!d&&m(b).unusedTokens.push(f);
+// add remaining unparsed input length to the string
+m(b).charsLeftOver=i-j,h.length>0&&m(b).unusedInput.push(h),
+// clear _12h flag if hour is <= 12
+b._a[de]<=12&&m(b).bigHour===!0&&b._a[de]>0&&(m(b).bigHour=void 0),m(b).parsedDateParts=b._a.slice(0),m(b).meridiem=b._meridiem,
+// handle meridiem
+b._a[de]=lb(b._locale,b._a[de],b._meridiem),ib(b),db(b)}function lb(a,b,c){var d;
+// Fallback
+return null==c?b:null!=a.meridiemHour?a.meridiemHour(b,c):null!=a.isPM?(d=a.isPM(c),d&&b<12&&(b+=12),d||12!==b||(b=0),b):b}
+// date from string and array of format strings
+function mb(a){var b,c,d,e,f;if(0===a._f.length)return m(a).invalidFormat=!0,void(a._d=new Date(NaN));for(e=0;e<a._f.length;e++)f=0,b=q({},a),null!=a._useUTC&&(b._useUTC=a._useUTC),b._f=a._f[e],kb(b),n(b)&&(
+// if there is any input that was not parsed add a penalty for that format
+f+=m(b).charsLeftOver,
+//or tokens
+f+=10*m(b).unusedTokens.length,m(b).score=f,(null==d||f<d)&&(d=f,c=b));j(a,c||b)}function nb(a){if(!a._d){var b=L(a._i);a._a=h([b.year,b.month,b.day||b.date,b.hour,b.minute,b.second,b.millisecond],function(a){return a&&parseInt(a,10)}),ib(a)}}function ob(a){var b=new r(db(pb(a)));
+// Adding is smart enough around DST
+return b._nextDay&&(b.add(1,"d"),b._nextDay=void 0),b}function pb(a){var b=a._i,d=a._f;return a._locale=a._locale||bb(a._l),null===b||void 0===d&&""===b?o({nullInput:!0}):("string"==typeof b&&(a._i=b=a._locale.preparse(b)),s(b)?new r(db(b)):(g(b)?a._d=b:c(d)?mb(a):d?kb(a):qb(a),n(a)||(a._d=null),a))}function qb(b){var d=b._i;void 0===d?b._d=new Date(a.now()):g(d)?b._d=new Date(d.valueOf()):"string"==typeof d?fb(b):c(d)?(b._a=h(d.slice(0),function(a){return parseInt(a,10)}),ib(b)):"object"==typeof d?nb(b):f(d)?
+// from milliseconds
+b._d=new Date(d):a.createFromInputFallback(b)}function rb(a,b,f,g,h){var i={};
+// object construction must be done this way.
+// https://github.com/moment/moment/issues/1423
+return f!==!0&&f!==!1||(g=f,f=void 0),(d(a)&&e(a)||c(a)&&0===a.length)&&(a=void 0),i._isAMomentObject=!0,i._useUTC=i._isUTC=h,i._l=f,i._i=a,i._f=b,i._strict=g,ob(i)}function sb(a,b,c,d){return rb(a,b,c,d,!1)}
+// Pick a moment m from moments so that m[fn](other) is true for all
+// other. This relies on the function fn to be transitive.
+//
+// moments should either be an array of moment objects or an array, whose
+// first element is an array of moment objects.
+function tb(a,b){var d,e;if(1===b.length&&c(b[0])&&(b=b[0]),!b.length)return sb();for(d=b[0],e=1;e<b.length;++e)b[e].isValid()&&!b[e][a](d)||(d=b[e]);return d}
+// TODO: Use [].sort instead?
+function ub(){var a=[].slice.call(arguments,0);return tb("isBefore",a)}function vb(){var a=[].slice.call(arguments,0);return tb("isAfter",a)}function wb(a){var b=L(a),c=b.year||0,d=b.quarter||0,e=b.month||0,f=b.week||0,g=b.day||0,h=b.hour||0,i=b.minute||0,j=b.second||0,k=b.millisecond||0;
+// representation for dateAddRemove
+this._milliseconds=+k+1e3*j+// 1000
+6e4*i+// 1000 * 60
+1e3*h*60*60,//using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
+// Because of dateAddRemove treats 24 hours as different from a
+// day when working around DST, we need to store them separately
+this._days=+g+7*f,
+// It is impossible translate months into days without knowing
+// which months you are are talking about, so we have to store
+// it separately.
+this._months=+e+3*d+12*c,this._data={},this._locale=bb(),this._bubble()}function xb(a){return a instanceof wb}function yb(a){return a<0?Math.round(-1*a)*-1:Math.round(a)}
+// FORMATTING
+function zb(a,b){U(a,0,0,function(){var a=this.utcOffset(),c="+";return a<0&&(a=-a,c="-"),c+T(~~(a/60),2)+b+T(~~a%60,2)})}function Ab(a,b){var c=(b||"").match(a);if(null===c)return null;var d=c[c.length-1]||[],e=(d+"").match(Me)||["-",0,0],f=+(60*e[1])+u(e[2]);return 0===f?0:"+"===e[0]?f:-f}
+// Return a moment from input, that is local/utc/zone equivalent to model.
+function Bb(b,c){var d,e;
+// Use low-level api, because this fn is low-level api.
+return c._isUTC?(d=c.clone(),e=(s(b)||g(b)?b.valueOf():sb(b).valueOf())-d.valueOf(),d._d.setTime(d._d.valueOf()+e),a.updateOffset(d,!1),d):sb(b).local()}function Cb(a){
+// On Firefox.24 Date#getTimezoneOffset returns a floating point.
+// https://github.com/moment/moment/pull/1871
+return 15*-Math.round(a._d.getTimezoneOffset()/15)}
+// MOMENTS
+// keepLocalTime = true means only change the timezone, without
+// affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
+// 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
+// +0200, so we adjust the time as needed, to be valid.
+//
+// Keeping the time actually adds/subtracts (one hour)
+// from the actual represented time. That is why we call updateOffset
+// a second time. In case it wants us to change the offset again
+// _changeInProgress == true case, then we have to adjust, because
+// there is no such time in the given timezone.
+function Db(b,c){var d,e=this._offset||0;if(!this.isValid())return null!=b?this:NaN;if(null!=b){if("string"==typeof b){if(b=Ab(Xd,b),null===b)return this}else Math.abs(b)<16&&(b=60*b);return!this._isUTC&&c&&(d=Cb(this)),this._offset=b,this._isUTC=!0,null!=d&&this.add(d,"m"),e!==b&&(!c||this._changeInProgress?Tb(this,Ob(b-e,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,a.updateOffset(this,!0),this._changeInProgress=null)),this}return this._isUTC?e:Cb(this)}function Eb(a,b){return null!=a?("string"!=typeof a&&(a=-a),this.utcOffset(a,b),this):-this.utcOffset()}function Fb(a){return this.utcOffset(0,a)}function Gb(a){return this._isUTC&&(this.utcOffset(0,a),this._isUTC=!1,a&&this.subtract(Cb(this),"m")),this}function Hb(){if(null!=this._tzm)this.utcOffset(this._tzm);else if("string"==typeof this._i){var a=Ab(Wd,this._i);null!=a?this.utcOffset(a):this.utcOffset(0,!0)}return this}function Ib(a){return!!this.isValid()&&(a=a?sb(a).utcOffset():0,(this.utcOffset()-a)%60===0)}function Jb(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function Kb(){if(!p(this._isDSTShifted))return this._isDSTShifted;var a={};if(q(a,this),a=pb(a),a._a){var b=a._isUTC?k(a._a):sb(a._a);this._isDSTShifted=this.isValid()&&v(a._a,b.toArray())>0}else this._isDSTShifted=!1;return this._isDSTShifted}function Lb(){return!!this.isValid()&&!this._isUTC}function Mb(){return!!this.isValid()&&this._isUTC}function Nb(){return!!this.isValid()&&(this._isUTC&&0===this._offset)}function Ob(a,b){var c,d,e,g=a,
+// matching against regexp is expensive, do it on demand
+h=null;// checks for null or undefined
+return xb(a)?g={ms:a._milliseconds,d:a._days,M:a._months}:f(a)?(g={},b?g[b]=a:g.milliseconds=a):(h=Ne.exec(a))?(c="-"===h[1]?-1:1,g={y:0,d:u(h[ce])*c,h:u(h[de])*c,m:u(h[ee])*c,s:u(h[fe])*c,ms:u(yb(1e3*h[ge]))*c}):(h=Oe.exec(a))?(c="-"===h[1]?-1:1,g={y:Pb(h[2],c),M:Pb(h[3],c),w:Pb(h[4],c),d:Pb(h[5],c),h:Pb(h[6],c),m:Pb(h[7],c),s:Pb(h[8],c)}):null==g?g={}:"object"==typeof g&&("from"in g||"to"in g)&&(e=Rb(sb(g.from),sb(g.to)),g={},g.ms=e.milliseconds,g.M=e.months),d=new wb(g),xb(a)&&i(a,"_locale")&&(d._locale=a._locale),d}function Pb(a,b){
+// We'd normally use ~~inp for this, but unfortunately it also
+// converts floats to ints.
+// inp may be undefined, so careful calling replace on it.
+var c=a&&parseFloat(a.replace(",","."));
+// apply sign while we're at it
+return(isNaN(c)?0:c)*b}function Qb(a,b){var c={milliseconds:0,months:0};return c.months=b.month()-a.month()+12*(b.year()-a.year()),a.clone().add(c.months,"M").isAfter(b)&&--c.months,c.milliseconds=+b-+a.clone().add(c.months,"M"),c}function Rb(a,b){var c;return a.isValid()&&b.isValid()?(b=Bb(b,a),a.isBefore(b)?c=Qb(a,b):(c=Qb(b,a),c.milliseconds=-c.milliseconds,c.months=-c.months),c):{milliseconds:0,months:0}}
+// TODO: remove 'name' arg after deprecation is removed
+function Sb(a,b){return function(c,d){var e,f;
+//invert the arguments, but complain about it
+return null===d||isNaN(+d)||(y(b,"moment()."+b+"(period, number) is deprecated. Please use moment()."+b+"(number, period). See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info."),f=c,c=d,d=f),c="string"==typeof c?+c:c,e=Ob(c,d),Tb(this,e,a),this}}function Tb(b,c,d,e){var f=c._milliseconds,g=yb(c._days),h=yb(c._months);b.isValid()&&(e=null==e||e,f&&b._d.setTime(b._d.valueOf()+f*d),g&&Q(b,"Date",P(b,"Date")+g*d),h&&ja(b,P(b,"Month")+h*d),e&&a.updateOffset(b,g||h))}function Ub(a,b){var c=a.diff(b,"days",!0);return c<-6?"sameElse":c<-1?"lastWeek":c<0?"lastDay":c<1?"sameDay":c<2?"nextDay":c<7?"nextWeek":"sameElse"}function Vb(b,c){
+// We want to compare the start of today, vs this.
+// Getting start-of-today depends on whether we're local/utc/offset or not.
+var d=b||sb(),e=Bb(d,this).startOf("day"),f=a.calendarFormat(this,e)||"sameElse",g=c&&(z(c[f])?c[f].call(this,d):c[f]);return this.format(g||this.localeData().calendar(f,this,sb(d)))}function Wb(){return new r(this)}function Xb(a,b){var c=s(a)?a:sb(a);return!(!this.isValid()||!c.isValid())&&(b=K(p(b)?"millisecond":b),"millisecond"===b?this.valueOf()>c.valueOf():c.valueOf()<this.clone().startOf(b).valueOf())}function Yb(a,b){var c=s(a)?a:sb(a);return!(!this.isValid()||!c.isValid())&&(b=K(p(b)?"millisecond":b),"millisecond"===b?this.valueOf()<c.valueOf():this.clone().endOf(b).valueOf()<c.valueOf())}function Zb(a,b,c,d){return d=d||"()",("("===d[0]?this.isAfter(a,c):!this.isBefore(a,c))&&(")"===d[1]?this.isBefore(b,c):!this.isAfter(b,c))}function $b(a,b){var c,d=s(a)?a:sb(a);return!(!this.isValid()||!d.isValid())&&(b=K(b||"millisecond"),"millisecond"===b?this.valueOf()===d.valueOf():(c=d.valueOf(),this.clone().startOf(b).valueOf()<=c&&c<=this.clone().endOf(b).valueOf()))}function _b(a,b){return this.isSame(a,b)||this.isAfter(a,b)}function ac(a,b){return this.isSame(a,b)||this.isBefore(a,b)}function bc(a,b,c){var d,e,f,g;// 1000
+// 1000 * 60
+// 1000 * 60 * 60
+// 1000 * 60 * 60 * 24, negate dst
+// 1000 * 60 * 60 * 24 * 7, negate dst
+return this.isValid()?(d=Bb(a,this),d.isValid()?(e=6e4*(d.utcOffset()-this.utcOffset()),b=K(b),"year"===b||"month"===b||"quarter"===b?(g=cc(this,d),"quarter"===b?g/=3:"year"===b&&(g/=12)):(f=this-d,g="second"===b?f/1e3:"minute"===b?f/6e4:"hour"===b?f/36e5:"day"===b?(f-e)/864e5:"week"===b?(f-e)/6048e5:f),c?g:t(g)):NaN):NaN}function cc(a,b){
+// difference in months
+var c,d,e=12*(b.year()-a.year())+(b.month()-a.month()),
+// b is in (anchor - 1 month, anchor + 1 month)
+f=a.clone().add(e,"months");
+//check for negative zero, return zero if negative zero
+// linear across the month
+// linear across the month
+return b-f<0?(c=a.clone().add(e-1,"months"),d=(b-f)/(f-c)):(c=a.clone().add(e+1,"months"),d=(b-f)/(c-f)),-(e+d)||0}function dc(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")}function ec(){var a=this.clone().utc();return 0<a.year()&&a.year()<=9999?z(Date.prototype.toISOString)?this.toDate().toISOString():X(a,"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]"):X(a,"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]")}/**
+ * Return a human readable representation of a moment that can
+ * also be evaluated to get a new moment which is the same
+ *
+ * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects
+ */
+function fc(){if(!this.isValid())return"moment.invalid(/* "+this._i+" */)";var a="moment",b="";this.isLocal()||(a=0===this.utcOffset()?"moment.utc":"moment.parseZone",b="Z");var c="["+a+'("]',d=0<this.year()&&this.year()<=9999?"YYYY":"YYYYYY",e="-MM-DD[T]HH:mm:ss.SSS",f=b+'[")]';return this.format(c+d+e+f)}function gc(b){b||(b=this.isUtc()?a.defaultFormatUtc:a.defaultFormat);var c=X(this,b);return this.localeData().postformat(c)}function hc(a,b){return this.isValid()&&(s(a)&&a.isValid()||sb(a).isValid())?Ob({to:this,from:a}).locale(this.locale()).humanize(!b):this.localeData().invalidDate()}function ic(a){return this.from(sb(),a)}function jc(a,b){return this.isValid()&&(s(a)&&a.isValid()||sb(a).isValid())?Ob({from:this,to:a}).locale(this.locale()).humanize(!b):this.localeData().invalidDate()}function kc(a){return this.to(sb(),a)}
+// If passed a locale key, it will set the locale for this
+// instance.  Otherwise, it will return the locale configuration
+// variables for this instance.
+function lc(a){var b;return void 0===a?this._locale._abbr:(b=bb(a),null!=b&&(this._locale=b),this)}function mc(){return this._locale}function nc(a){
+// the following switch intentionally omits break keywords
+// to utilize falling through the cases.
+switch(a=K(a)){case"year":this.month(0);/* falls through */
+case"quarter":case"month":this.date(1);/* falls through */
+case"week":case"isoWeek":case"day":case"date":this.hours(0);/* falls through */
+case"hour":this.minutes(0);/* falls through */
+case"minute":this.seconds(0);/* falls through */
+case"second":this.milliseconds(0)}
+// weeks are a special case
+// quarters are also special
+return"week"===a&&this.weekday(0),"isoWeek"===a&&this.isoWeekday(1),"quarter"===a&&this.month(3*Math.floor(this.month()/3)),this}function oc(a){
+// 'date' is an alias for 'day', so it should be considered as such.
+return a=K(a),void 0===a||"millisecond"===a?this:("date"===a&&(a="day"),this.startOf(a).add(1,"isoWeek"===a?"week":a).subtract(1,"ms"))}function pc(){return this._d.valueOf()-6e4*(this._offset||0)}function qc(){return Math.floor(this.valueOf()/1e3)}function rc(){return new Date(this.valueOf())}function sc(){var a=this;return[a.year(),a.month(),a.date(),a.hour(),a.minute(),a.second(),a.millisecond()]}function tc(){var a=this;return{years:a.year(),months:a.month(),date:a.date(),hours:a.hours(),minutes:a.minutes(),seconds:a.seconds(),milliseconds:a.milliseconds()}}function uc(){
+// new Date(NaN).toJSON() === null
+return this.isValid()?this.toISOString():null}function vc(){return n(this)}function wc(){return j({},m(this))}function xc(){return m(this).overflow}function yc(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}}function zc(a,b){U(0,[a,a.length],0,b)}
+// MOMENTS
+function Ac(a){return Ec.call(this,a,this.week(),this.weekday(),this.localeData()._week.dow,this.localeData()._week.doy)}function Bc(a){return Ec.call(this,a,this.isoWeek(),this.isoWeekday(),1,4)}function Cc(){return xa(this.year(),1,4)}function Dc(){var a=this.localeData()._week;return xa(this.year(),a.dow,a.doy)}function Ec(a,b,c,d,e){var f;return null==a?wa(this,d,e).year:(f=xa(a,d,e),b>f&&(b=f),Fc.call(this,a,b,c,d,e))}function Fc(a,b,c,d,e){var f=va(a,b,c,d,e),g=ta(f.year,0,f.dayOfYear);return this.year(g.getUTCFullYear()),this.month(g.getUTCMonth()),this.date(g.getUTCDate()),this}
+// MOMENTS
+function Gc(a){return null==a?Math.ceil((this.month()+1)/3):this.month(3*(a-1)+this.month()%3)}
+// HELPERS
+// MOMENTS
+function Hc(a){var b=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==a?b:this.add(a-b,"d")}function Ic(a,b){b[ge]=u(1e3*("0."+a))}
+// MOMENTS
+function Jc(){return this._isUTC?"UTC":""}function Kc(){return this._isUTC?"Coordinated Universal Time":""}function Lc(a){return sb(1e3*a)}function Mc(){return sb.apply(null,arguments).parseZone()}function Nc(a){return a}function Oc(a,b,c,d){var e=bb(),f=k().set(d,b);return e[c](f,a)}function Pc(a,b,c){if(f(a)&&(b=a,a=void 0),a=a||"",null!=b)return Oc(a,b,c,"month");var d,e=[];for(d=0;d<12;d++)e[d]=Oc(a,d,c,"month");return e}
+// ()
+// (5)
+// (fmt, 5)
+// (fmt)
+// (true)
+// (true, 5)
+// (true, fmt, 5)
+// (true, fmt)
+function Qc(a,b,c,d){"boolean"==typeof a?(f(b)&&(c=b,b=void 0),b=b||""):(b=a,c=b,a=!1,f(b)&&(c=b,b=void 0),b=b||"");var e=bb(),g=a?e._week.dow:0;if(null!=c)return Oc(b,(c+g)%7,d,"day");var h,i=[];for(h=0;h<7;h++)i[h]=Oc(b,(h+g)%7,d,"day");return i}function Rc(a,b){return Pc(a,b,"months")}function Sc(a,b){return Pc(a,b,"monthsShort")}function Tc(a,b,c){return Qc(a,b,c,"weekdays")}function Uc(a,b,c){return Qc(a,b,c,"weekdaysShort")}function Vc(a,b,c){return Qc(a,b,c,"weekdaysMin")}function Wc(){var a=this._data;return this._milliseconds=Ze(this._milliseconds),this._days=Ze(this._days),this._months=Ze(this._months),a.milliseconds=Ze(a.milliseconds),a.seconds=Ze(a.seconds),a.minutes=Ze(a.minutes),a.hours=Ze(a.hours),a.months=Ze(a.months),a.years=Ze(a.years),this}function Xc(a,b,c,d){var e=Ob(b,c);return a._milliseconds+=d*e._milliseconds,a._days+=d*e._days,a._months+=d*e._months,a._bubble()}
+// supports only 2.0-style add(1, 's') or add(duration)
+function Yc(a,b){return Xc(this,a,b,1)}
+// supports only 2.0-style subtract(1, 's') or subtract(duration)
+function Zc(a,b){return Xc(this,a,b,-1)}function $c(a){return a<0?Math.floor(a):Math.ceil(a)}function _c(){var a,b,c,d,e,f=this._milliseconds,g=this._days,h=this._months,i=this._data;
+// if we have a mix of positive and negative values, bubble down first
+// check: https://github.com/moment/moment/issues/2166
+// The following code bubbles up values, see the tests for
+// examples of what that means.
+// convert days to months
+// 12 months -> 1 year
+return f>=0&&g>=0&&h>=0||f<=0&&g<=0&&h<=0||(f+=864e5*$c(bd(h)+g),g=0,h=0),i.milliseconds=f%1e3,a=t(f/1e3),i.seconds=a%60,b=t(a/60),i.minutes=b%60,c=t(b/60),i.hours=c%24,g+=t(c/24),e=t(ad(g)),h+=e,g-=$c(bd(e)),d=t(h/12),h%=12,i.days=g,i.months=h,i.years=d,this}function ad(a){
+// 400 years have 146097 days (taking into account leap year rules)
+// 400 years have 12 months === 4800
+return 4800*a/146097}function bd(a){
+// the reverse of daysToMonths
+return 146097*a/4800}function cd(a){var b,c,d=this._milliseconds;if(a=K(a),"month"===a||"year"===a)return b=this._days+d/864e5,c=this._months+ad(b),"month"===a?c:c/12;switch(
+// handle milliseconds separately because of floating point math errors (issue #1867)
+b=this._days+Math.round(bd(this._months)),a){case"week":return b/7+d/6048e5;case"day":return b+d/864e5;case"hour":return 24*b+d/36e5;case"minute":return 1440*b+d/6e4;case"second":return 86400*b+d/1e3;
+// Math.floor prevents floating point math errors here
+case"millisecond":return Math.floor(864e5*b)+d;default:throw new Error("Unknown unit "+a)}}
+// TODO: Use this.as('ms')?
+function dd(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*u(this._months/12)}function ed(a){return function(){return this.as(a)}}function fd(a){return a=K(a),this[a+"s"]()}function gd(a){return function(){return this._data[a]}}function hd(){return t(this.days()/7)}
+// helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
+function id(a,b,c,d,e){return e.relativeTime(b||1,!!c,a,d)}function jd(a,b,c){var d=Ob(a).abs(),e=of(d.as("s")),f=of(d.as("m")),g=of(d.as("h")),h=of(d.as("d")),i=of(d.as("M")),j=of(d.as("y")),k=e<pf.s&&["s",e]||f<=1&&["m"]||f<pf.m&&["mm",f]||g<=1&&["h"]||g<pf.h&&["hh",g]||h<=1&&["d"]||h<pf.d&&["dd",h]||i<=1&&["M"]||i<pf.M&&["MM",i]||j<=1&&["y"]||["yy",j];return k[2]=b,k[3]=+a>0,k[4]=c,id.apply(null,k)}
+// This function allows you to set the rounding function for relative time strings
+function kd(a){return void 0===a?of:"function"==typeof a&&(of=a,!0)}
+// This function allows you to set a threshold for relative time strings
+function ld(a,b){return void 0!==pf[a]&&(void 0===b?pf[a]:(pf[a]=b,!0))}function md(a){var b=this.localeData(),c=jd(this,!a,b);return a&&(c=b.pastFuture(+this,c)),b.postformat(c)}function nd(){
+// for ISO strings we do not use the normal bubbling rules:
+//  * milliseconds bubble up until they become hours
+//  * days do not bubble at all
+//  * months bubble up until they become years
+// This is because there is no context-free conversion between hours and days
+// (think of clock changes)
+// and also not between days and months (28-31 days per month)
+var a,b,c,d=qf(this._milliseconds)/1e3,e=qf(this._days),f=qf(this._months);
+// 3600 seconds -> 60 minutes -> 1 hour
+a=t(d/60),b=t(a/60),d%=60,a%=60,
+// 12 months -> 1 year
+c=t(f/12),f%=12;
+// inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
+var g=c,h=f,i=e,j=b,k=a,l=d,m=this.asSeconds();return m?(m<0?"-":"")+"P"+(g?g+"Y":"")+(h?h+"M":"")+(i?i+"D":"")+(j||k||l?"T":"")+(j?j+"H":"")+(k?k+"M":"")+(l?l+"S":""):"P0D"}var od,pd;pd=Array.prototype.some?Array.prototype.some:function(a){for(var b=Object(this),c=b.length>>>0,d=0;d<c;d++)if(d in b&&a.call(this,b[d],d,b))return!0;return!1};var qd=pd,rd=a.momentProperties=[],sd=!1,td={};a.suppressDeprecationWarnings=!1,a.deprecationHandler=null;var ud;ud=Object.keys?Object.keys:function(a){var b,c=[];for(b in a)i(a,b)&&c.push(b);return c};var vd,wd=ud,xd={sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},yd={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},zd="Invalid date",Ad="%d",Bd=/\d{1,2}/,Cd={future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},Dd={},Ed={},Fd=/(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,Gd=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,Hd={},Id={},Jd=/\d/,Kd=/\d\d/,Ld=/\d{3}/,Md=/\d{4}/,Nd=/[+-]?\d{6}/,Od=/\d\d?/,Pd=/\d\d\d\d?/,Qd=/\d\d\d\d\d\d?/,Rd=/\d{1,3}/,Sd=/\d{1,4}/,Td=/[+-]?\d{1,6}/,Ud=/\d+/,Vd=/[+-]?\d+/,Wd=/Z|[+-]\d\d:?\d\d/gi,Xd=/Z|[+-]\d\d(?::?\d\d)?/gi,Yd=/[+-]?\d+(\.\d{1,3})?/,Zd=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,$d={},_d={},ae=0,be=1,ce=2,de=3,ee=4,fe=5,ge=6,he=7,ie=8;vd=Array.prototype.indexOf?Array.prototype.indexOf:function(a){
+// I know
+var b;for(b=0;b<this.length;++b)if(this[b]===a)return b;return-1};var je=vd;
+// FORMATTING
+U("M",["MM",2],"Mo",function(){return this.month()+1}),U("MMM",0,0,function(a){return this.localeData().monthsShort(this,a)}),U("MMMM",0,0,function(a){return this.localeData().months(this,a)}),
+// ALIASES
+J("month","M"),
+// PRIORITY
+M("month",8),
+// PARSING
+Z("M",Od),Z("MM",Od,Kd),Z("MMM",function(a,b){return b.monthsShortRegex(a)}),Z("MMMM",function(a,b){return b.monthsRegex(a)}),ba(["M","MM"],function(a,b){b[be]=u(a)-1}),ba(["MMM","MMMM"],function(a,b,c,d){var e=c._locale.monthsParse(a,d,c._strict);
+// if we didn't find a month name, mark the date as invalid.
+null!=e?b[be]=e:m(c).invalidMonth=a});
+// LOCALES
+var ke=/D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/,le="January_February_March_April_May_June_July_August_September_October_November_December".split("_"),me="Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),ne=Zd,oe=Zd;
+// FORMATTING
+U("Y",0,0,function(){var a=this.year();return a<=9999?""+a:"+"+a}),U(0,["YY",2],0,function(){return this.year()%100}),U(0,["YYYY",4],0,"year"),U(0,["YYYYY",5],0,"year"),U(0,["YYYYYY",6,!0],0,"year"),
+// ALIASES
+J("year","y"),
+// PRIORITIES
+M("year",1),
+// PARSING
+Z("Y",Vd),Z("YY",Od,Kd),Z("YYYY",Sd,Md),Z("YYYYY",Td,Nd),Z("YYYYYY",Td,Nd),ba(["YYYYY","YYYYYY"],ae),ba("YYYY",function(b,c){c[ae]=2===b.length?a.parseTwoDigitYear(b):u(b)}),ba("YY",function(b,c){c[ae]=a.parseTwoDigitYear(b)}),ba("Y",function(a,b){b[ae]=parseInt(a,10)}),
+// HOOKS
+a.parseTwoDigitYear=function(a){return u(a)+(u(a)>68?1900:2e3)};
+// MOMENTS
+var pe=O("FullYear",!0);
+// FORMATTING
+U("w",["ww",2],"wo","week"),U("W",["WW",2],"Wo","isoWeek"),
+// ALIASES
+J("week","w"),J("isoWeek","W"),
+// PRIORITIES
+M("week",5),M("isoWeek",5),
+// PARSING
+Z("w",Od),Z("ww",Od,Kd),Z("W",Od),Z("WW",Od,Kd),ca(["w","ww","W","WW"],function(a,b,c,d){b[d.substr(0,1)]=u(a)});var qe={dow:0,// Sunday is the first day of the week.
+doy:6};
+// FORMATTING
+U("d",0,"do","day"),U("dd",0,0,function(a){return this.localeData().weekdaysMin(this,a)}),U("ddd",0,0,function(a){return this.localeData().weekdaysShort(this,a)}),U("dddd",0,0,function(a){return this.localeData().weekdays(this,a)}),U("e",0,0,"weekday"),U("E",0,0,"isoWeekday"),
+// ALIASES
+J("day","d"),J("weekday","e"),J("isoWeekday","E"),
+// PRIORITY
+M("day",11),M("weekday",11),M("isoWeekday",11),
+// PARSING
+Z("d",Od),Z("e",Od),Z("E",Od),Z("dd",function(a,b){return b.weekdaysMinRegex(a)}),Z("ddd",function(a,b){return b.weekdaysShortRegex(a)}),Z("dddd",function(a,b){return b.weekdaysRegex(a)}),ca(["dd","ddd","dddd"],function(a,b,c,d){var e=c._locale.weekdaysParse(a,d,c._strict);
+// if we didn't get a weekday name, mark the date as invalid
+null!=e?b.d=e:m(c).invalidWeekday=a}),ca(["d","e","E"],function(a,b,c,d){b[d]=u(a)});
+// LOCALES
+var re="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),se="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),te="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),ue=Zd,ve=Zd,we=Zd;U("H",["HH",2],0,"hour"),U("h",["hh",2],0,Ra),U("k",["kk",2],0,Sa),U("hmm",0,0,function(){return""+Ra.apply(this)+T(this.minutes(),2)}),U("hmmss",0,0,function(){return""+Ra.apply(this)+T(this.minutes(),2)+T(this.seconds(),2)}),U("Hmm",0,0,function(){return""+this.hours()+T(this.minutes(),2)}),U("Hmmss",0,0,function(){return""+this.hours()+T(this.minutes(),2)+T(this.seconds(),2)}),Ta("a",!0),Ta("A",!1),
+// ALIASES
+J("hour","h"),
+// PRIORITY
+M("hour",13),Z("a",Ua),Z("A",Ua),Z("H",Od),Z("h",Od),Z("HH",Od,Kd),Z("hh",Od,Kd),Z("hmm",Pd),Z("hmmss",Qd),Z("Hmm",Pd),Z("Hmmss",Qd),ba(["H","HH"],de),ba(["a","A"],function(a,b,c){c._isPm=c._locale.isPM(a),c._meridiem=a}),ba(["h","hh"],function(a,b,c){b[de]=u(a),m(c).bigHour=!0}),ba("hmm",function(a,b,c){var d=a.length-2;b[de]=u(a.substr(0,d)),b[ee]=u(a.substr(d)),m(c).bigHour=!0}),ba("hmmss",function(a,b,c){var d=a.length-4,e=a.length-2;b[de]=u(a.substr(0,d)),b[ee]=u(a.substr(d,2)),b[fe]=u(a.substr(e)),m(c).bigHour=!0}),ba("Hmm",function(a,b,c){var d=a.length-2;b[de]=u(a.substr(0,d)),b[ee]=u(a.substr(d))}),ba("Hmmss",function(a,b,c){var d=a.length-4,e=a.length-2;b[de]=u(a.substr(0,d)),b[ee]=u(a.substr(d,2)),b[fe]=u(a.substr(e))});var xe,ye=/[ap]\.?m?\.?/i,ze=O("Hours",!0),Ae={calendar:xd,longDateFormat:yd,invalidDate:zd,ordinal:Ad,ordinalParse:Bd,relativeTime:Cd,months:le,monthsShort:me,week:qe,weekdays:re,weekdaysMin:te,weekdaysShort:se,meridiemParse:ye},Be={},Ce={},De=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Ee=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Fe=/Z|[+-]\d\d(?::?\d\d)?/,Ge=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],
+// YYYYMM is NOT allowed by the standard
+["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/]],He=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],Ie=/^\/?Date\((\-?\d+)/i;a.createFromInputFallback=x("value provided is not in a recognized ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions. Non ISO date formats are discouraged and will be removed in an upcoming major release. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.",function(a){a._d=new Date(a._i+(a._useUTC?" UTC":""))}),
+// constant that refers to the ISO standard
+a.ISO_8601=function(){};var Je=x("moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/",function(){var a=sb.apply(null,arguments);return this.isValid()&&a.isValid()?a<this?this:a:o()}),Ke=x("moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/",function(){var a=sb.apply(null,arguments);return this.isValid()&&a.isValid()?a>this?this:a:o()}),Le=function(){return Date.now?Date.now():+new Date};zb("Z",":"),zb("ZZ",""),
+// PARSING
+Z("Z",Xd),Z("ZZ",Xd),ba(["Z","ZZ"],function(a,b,c){c._useUTC=!0,c._tzm=Ab(Xd,a)});
+// HELPERS
+// timezone chunker
+// '+10:00' > ['10',  '00']
+// '-1530'  > ['-15', '30']
+var Me=/([\+\-]|\d\d)/gi;
+// HOOKS
+// This function will be called whenever a moment is mutated.
+// It is intended to keep the offset in sync with the timezone.
+a.updateOffset=function(){};
+// ASP.NET json date format regex
+var Ne=/^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/,Oe=/^(-)?P(?:(-?[0-9,.]*)Y)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)W)?(?:(-?[0-9,.]*)D)?(?:T(?:(-?[0-9,.]*)H)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)S)?)?$/;Ob.fn=wb.prototype;var Pe=Sb(1,"add"),Qe=Sb(-1,"subtract");a.defaultFormat="YYYY-MM-DDTHH:mm:ssZ",a.defaultFormatUtc="YYYY-MM-DDTHH:mm:ss[Z]";var Re=x("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(a){return void 0===a?this.localeData():this.locale(a)});
+// FORMATTING
+U(0,["gg",2],0,function(){return this.weekYear()%100}),U(0,["GG",2],0,function(){return this.isoWeekYear()%100}),zc("gggg","weekYear"),zc("ggggg","weekYear"),zc("GGGG","isoWeekYear"),zc("GGGGG","isoWeekYear"),
+// ALIASES
+J("weekYear","gg"),J("isoWeekYear","GG"),
+// PRIORITY
+M("weekYear",1),M("isoWeekYear",1),
+// PARSING
+Z("G",Vd),Z("g",Vd),Z("GG",Od,Kd),Z("gg",Od,Kd),Z("GGGG",Sd,Md),Z("gggg",Sd,Md),Z("GGGGG",Td,Nd),Z("ggggg",Td,Nd),ca(["gggg","ggggg","GGGG","GGGGG"],function(a,b,c,d){b[d.substr(0,2)]=u(a)}),ca(["gg","GG"],function(b,c,d,e){c[e]=a.parseTwoDigitYear(b)}),
+// FORMATTING
+U("Q",0,"Qo","quarter"),
+// ALIASES
+J("quarter","Q"),
+// PRIORITY
+M("quarter",7),
+// PARSING
+Z("Q",Jd),ba("Q",function(a,b){b[be]=3*(u(a)-1)}),
+// FORMATTING
+U("D",["DD",2],"Do","date"),
+// ALIASES
+J("date","D"),
+// PRIOROITY
+M("date",9),
+// PARSING
+Z("D",Od),Z("DD",Od,Kd),Z("Do",function(a,b){return a?b._ordinalParse:b._ordinalParseLenient}),ba(["D","DD"],ce),ba("Do",function(a,b){b[ce]=u(a.match(Od)[0],10)});
+// MOMENTS
+var Se=O("Date",!0);
+// FORMATTING
+U("DDD",["DDDD",3],"DDDo","dayOfYear"),
+// ALIASES
+J("dayOfYear","DDD"),
+// PRIORITY
+M("dayOfYear",4),
+// PARSING
+Z("DDD",Rd),Z("DDDD",Ld),ba(["DDD","DDDD"],function(a,b,c){c._dayOfYear=u(a)}),
+// FORMATTING
+U("m",["mm",2],0,"minute"),
+// ALIASES
+J("minute","m"),
+// PRIORITY
+M("minute",14),
+// PARSING
+Z("m",Od),Z("mm",Od,Kd),ba(["m","mm"],ee);
+// MOMENTS
+var Te=O("Minutes",!1);
+// FORMATTING
+U("s",["ss",2],0,"second"),
+// ALIASES
+J("second","s"),
+// PRIORITY
+M("second",15),
+// PARSING
+Z("s",Od),Z("ss",Od,Kd),ba(["s","ss"],fe);
+// MOMENTS
+var Ue=O("Seconds",!1);
+// FORMATTING
+U("S",0,0,function(){return~~(this.millisecond()/100)}),U(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),U(0,["SSS",3],0,"millisecond"),U(0,["SSSS",4],0,function(){return 10*this.millisecond()}),U(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),U(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),U(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),U(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),U(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),
+// ALIASES
+J("millisecond","ms"),
+// PRIORITY
+M("millisecond",16),
+// PARSING
+Z("S",Rd,Jd),Z("SS",Rd,Kd),Z("SSS",Rd,Ld);var Ve;for(Ve="SSSS";Ve.length<=9;Ve+="S")Z(Ve,Ud);for(Ve="S";Ve.length<=9;Ve+="S")ba(Ve,Ic);
+// MOMENTS
+var We=O("Milliseconds",!1);
+// FORMATTING
+U("z",0,0,"zoneAbbr"),U("zz",0,0,"zoneName");var Xe=r.prototype;Xe.add=Pe,Xe.calendar=Vb,Xe.clone=Wb,Xe.diff=bc,Xe.endOf=oc,Xe.format=gc,Xe.from=hc,Xe.fromNow=ic,Xe.to=jc,Xe.toNow=kc,Xe.get=R,Xe.invalidAt=xc,Xe.isAfter=Xb,Xe.isBefore=Yb,Xe.isBetween=Zb,Xe.isSame=$b,Xe.isSameOrAfter=_b,Xe.isSameOrBefore=ac,Xe.isValid=vc,Xe.lang=Re,Xe.locale=lc,Xe.localeData=mc,Xe.max=Ke,Xe.min=Je,Xe.parsingFlags=wc,Xe.set=S,Xe.startOf=nc,Xe.subtract=Qe,Xe.toArray=sc,Xe.toObject=tc,Xe.toDate=rc,Xe.toISOString=ec,Xe.inspect=fc,Xe.toJSON=uc,Xe.toString=dc,Xe.unix=qc,Xe.valueOf=pc,Xe.creationData=yc,
+// Year
+Xe.year=pe,Xe.isLeapYear=ra,
+// Week Year
+Xe.weekYear=Ac,Xe.isoWeekYear=Bc,
+// Quarter
+Xe.quarter=Xe.quarters=Gc,
+// Month
+Xe.month=ka,Xe.daysInMonth=la,
+// Week
+Xe.week=Xe.weeks=Ba,Xe.isoWeek=Xe.isoWeeks=Ca,Xe.weeksInYear=Dc,Xe.isoWeeksInYear=Cc,
+// Day
+Xe.date=Se,Xe.day=Xe.days=Ka,Xe.weekday=La,Xe.isoWeekday=Ma,Xe.dayOfYear=Hc,
+// Hour
+Xe.hour=Xe.hours=ze,
+// Minute
+Xe.minute=Xe.minutes=Te,
+// Second
+Xe.second=Xe.seconds=Ue,
+// Millisecond
+Xe.millisecond=Xe.milliseconds=We,
+// Offset
+Xe.utcOffset=Db,Xe.utc=Fb,Xe.local=Gb,Xe.parseZone=Hb,Xe.hasAlignedHourOffset=Ib,Xe.isDST=Jb,Xe.isLocal=Lb,Xe.isUtcOffset=Mb,Xe.isUtc=Nb,Xe.isUTC=Nb,
+// Timezone
+Xe.zoneAbbr=Jc,Xe.zoneName=Kc,
+// Deprecations
+Xe.dates=x("dates accessor is deprecated. Use date instead.",Se),Xe.months=x("months accessor is deprecated. Use month instead",ka),Xe.years=x("years accessor is deprecated. Use year instead",pe),Xe.zone=x("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",Eb),Xe.isDSTShifted=x("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",Kb);var Ye=C.prototype;Ye.calendar=D,Ye.longDateFormat=E,Ye.invalidDate=F,Ye.ordinal=G,Ye.preparse=Nc,Ye.postformat=Nc,Ye.relativeTime=H,Ye.pastFuture=I,Ye.set=A,
+// Month
+Ye.months=fa,Ye.monthsShort=ga,Ye.monthsParse=ia,Ye.monthsRegex=na,Ye.monthsShortRegex=ma,
+// Week
+Ye.week=ya,Ye.firstDayOfYear=Aa,Ye.firstDayOfWeek=za,
+// Day of Week
+Ye.weekdays=Fa,Ye.weekdaysMin=Ha,Ye.weekdaysShort=Ga,Ye.weekdaysParse=Ja,Ye.weekdaysRegex=Na,Ye.weekdaysShortRegex=Oa,Ye.weekdaysMinRegex=Pa,
+// Hours
+Ye.isPM=Va,Ye.meridiem=Wa,$a("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(a){var b=a%10,c=1===u(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c}}),
+// Side effect imports
+a.lang=x("moment.lang is deprecated. Use moment.locale instead.",$a),a.langData=x("moment.langData is deprecated. Use moment.localeData instead.",bb);var Ze=Math.abs,$e=ed("ms"),_e=ed("s"),af=ed("m"),bf=ed("h"),cf=ed("d"),df=ed("w"),ef=ed("M"),ff=ed("y"),gf=gd("milliseconds"),hf=gd("seconds"),jf=gd("minutes"),kf=gd("hours"),lf=gd("days"),mf=gd("months"),nf=gd("years"),of=Math.round,pf={s:45,// seconds to minute
+m:45,// minutes to hour
+h:22,// hours to day
+d:26,// days to month
+M:11},qf=Math.abs,rf=wb.prototype;
+// Deprecations
+// Side effect imports
+// FORMATTING
+// PARSING
+// Side effect imports
+return rf.abs=Wc,rf.add=Yc,rf.subtract=Zc,rf.as=cd,rf.asMilliseconds=$e,rf.asSeconds=_e,rf.asMinutes=af,rf.asHours=bf,rf.asDays=cf,rf.asWeeks=df,rf.asMonths=ef,rf.asYears=ff,rf.valueOf=dd,rf._bubble=_c,rf.get=fd,rf.milliseconds=gf,rf.seconds=hf,rf.minutes=jf,rf.hours=kf,rf.days=lf,rf.weeks=hd,rf.months=mf,rf.years=nf,rf.humanize=md,rf.toISOString=nd,rf.toString=nd,rf.toJSON=nd,rf.locale=lc,rf.localeData=mc,rf.toIsoString=x("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",nd),rf.lang=Re,U("X",0,0,"unix"),U("x",0,0,"valueOf"),Z("x",Vd),Z("X",Yd),ba("X",function(a,b,c){c._d=new Date(1e3*parseFloat(a,10))}),ba("x",function(a,b,c){c._d=new Date(u(a))}),a.version="2.16.0",b(sb),a.fn=Xe,a.min=ub,a.max=vb,a.now=Le,a.utc=k,a.unix=Lc,a.months=Rc,a.isDate=g,a.locale=$a,a.invalid=o,a.duration=Ob,a.isMoment=s,a.weekdays=Tc,a.parseZone=Mc,a.localeData=bb,a.isDuration=xb,a.monthsShort=Sc,a.weekdaysMin=Vc,a.defineLocale=_a,a.updateLocale=ab,a.locales=cb,a.weekdaysShort=Uc,a.normalizeUnits=K,a.relativeTimeRounding=kd,a.relativeTimeThreshold=ld,a.calendarFormat=Ub,a.prototype=Xe,a});
\ No newline at end of file
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/moment.d.ts b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/moment.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..23048bbfbf18d2ac4cfb7662e6be2e895a0e74a0
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/moment.d.ts
@@ -0,0 +1,710 @@
+declare function moment(inp?: moment.MomentInput, format?: moment.MomentFormatSpecification, strict?: boolean): moment.Moment;
+declare function moment(inp?: moment.MomentInput, format?: moment.MomentFormatSpecification, language?: string, strict?: boolean): moment.Moment;
+
+declare namespace moment {
+  type RelativeTimeKey = 's' | 'm' | 'mm' | 'h' | 'hh' | 'd' | 'dd' | 'M' | 'MM' | 'y' | 'yy';
+  type CalendarKey = 'sameDay' | 'nextDay' | 'lastDay' | 'nextWeek' | 'lastWeek' | 'sameElse' | string;
+  type LongDateFormatKey = 'LTS' | 'LT' | 'L' | 'LL' | 'LLL' | 'LLLL' | 'lts' | 'lt' | 'l' | 'll' | 'lll' | 'llll';
+
+  interface Locale {
+    calendar(key?: CalendarKey, m?: Moment, now?: Moment): string;
+
+    longDateFormat(key: LongDateFormatKey): string;
+    invalidDate(): string;
+    ordinal(n: number): string;
+
+    preparse(inp: string): string;
+    postformat(inp: string): string;
+    relativeTime(n: number, withoutSuffix: boolean,
+                 key: RelativeTimeKey, isFuture: boolean): string;
+    pastFuture(diff: number, absRelTime: string): string;
+    set(config: Object): void;
+
+    months(): string[];
+    months(m: Moment, format?: string): string;
+    monthsShort(): string[];
+    monthsShort(m: Moment, format?: string): string;
+    monthsParse(monthName: string, format: string, strict: boolean): number;
+    monthsRegex(strict: boolean): RegExp;
+    monthsShortRegex(strict: boolean): RegExp;
+
+    week(m: Moment): number;
+    firstDayOfYear(): number;
+    firstDayOfWeek(): number;
+
+    weekdays(): string[];
+    weekdays(m: Moment, format?: string): string;
+    weekdaysMin(): string[];
+    weekdaysMin(m: Moment): string;
+    weekdaysShort(): string[];
+    weekdaysShort(m: Moment): string;
+    weekdaysParse(weekdayName: string, format: string, strict: boolean): number;
+    weekdaysRegex(strict: boolean): RegExp;
+    weekdaysShortRegex(strict: boolean): RegExp;
+    weekdaysMinRegex(strict: boolean): RegExp;
+
+    isPM(input: string): boolean;
+    meridiem(hour: number, minute: number, isLower: boolean): string;
+  }
+
+  interface StandaloneFormatSpec {
+    format: string[];
+    standalone: string[];
+    isFormat?: RegExp;
+  }
+
+  interface WeekSpec {
+    dow: number;
+    doy: number;
+  }
+
+  type CalendarSpecVal = string | ((m?: Moment, now?: Moment) => string);
+  interface CalendarSpec {
+    sameDay?: CalendarSpecVal;
+    nextDay?: CalendarSpecVal;
+    lastDay?: CalendarSpecVal;
+    nextWeek?: CalendarSpecVal;
+    lastWeek?: CalendarSpecVal;
+    sameElse?: CalendarSpecVal;
+
+    // any additonal properties might be used with moment.calendarFormat
+    [x: string]: CalendarSpecVal;
+  }
+
+  type RelativeTimeSpecVal = (
+    string |
+    ((n: number, withoutSuffix: boolean,
+      key: RelativeTimeKey, isFuture: boolean) => string)
+  );
+  type RelativeTimeFuturePastVal = string | ((relTime: string) => string);
+
+  interface RelativeTimeSpec {
+    future: RelativeTimeFuturePastVal;
+    past: RelativeTimeFuturePastVal;
+    s: RelativeTimeSpecVal;
+    m: RelativeTimeSpecVal;
+    mm: RelativeTimeSpecVal;
+    h: RelativeTimeSpecVal;
+    hh: RelativeTimeSpecVal;
+    d: RelativeTimeSpecVal;
+    dd: RelativeTimeSpecVal;
+    M: RelativeTimeSpecVal;
+    MM: RelativeTimeSpecVal;
+    y: RelativeTimeSpecVal;
+    yy: RelativeTimeSpecVal;
+  }
+
+  interface LongDateFormatSpec {
+    LTS: string;
+    LT: string;
+    L: string;
+    LL: string;
+    LLL: string;
+    LLLL: string;
+
+    // lets forget for a sec that any upper/lower permutation will also work
+    lts?: string;
+    lt?: string;
+    l?: string;
+    ll?: string;
+    lll?: string;
+    llll?: string;
+  }
+
+  type MonthWeekdayFn = (momentToFormat: Moment, format?: string) => string;
+  type WeekdaySimpleFn = (momentToFormat: Moment) => string;
+
+  interface LocaleSpecification {
+    months?: string[] | StandaloneFormatSpec | MonthWeekdayFn;
+    monthsShort?: string[] | StandaloneFormatSpec | MonthWeekdayFn;
+
+    weekdays?: string[] | StandaloneFormatSpec | MonthWeekdayFn;
+    weekdaysShort?: string[] | StandaloneFormatSpec | WeekdaySimpleFn;
+    weekdaysMin?: string[] | StandaloneFormatSpec | WeekdaySimpleFn;
+
+    meridiemParse?: RegExp;
+    meridiem?: (hour: number, minute:number, isLower: boolean) => string;
+
+    isPM?: (input: string) => boolean;
+
+    longDateFormat?: LongDateFormatSpec;
+    calendar?: CalendarSpec;
+    relativeTime?: RelativeTimeSpec;
+    invalidDate?: string;
+    ordinal?: (n: number) => string;
+    ordinalParse?: RegExp;
+
+    week?: WeekSpec;
+
+    // Allow anything: in general any property that is passed as locale spec is
+    // put in the locale object so it can be used by locale functions
+    [x: string]: any;
+  }
+
+  interface MomentObjectOutput {
+    years: number;
+    /* One digit */
+    months: number;
+    /* Day of the month */
+    date: number;
+    hours: number;
+    minutes: number;
+    seconds: number;
+    milliseconds: number;
+  }
+
+  interface Duration {
+    humanize(withSuffix?: boolean): string;
+
+    abs(): Duration;
+
+    as(units: unitOfTime.Base): number;
+    get(units: unitOfTime.Base): number;
+
+    milliseconds(): number;
+    asMilliseconds(): number;
+
+    seconds(): number;
+    asSeconds(): number;
+
+    minutes(): number;
+    asMinutes(): number;
+
+    hours(): number;
+    asHours(): number;
+
+    days(): number;
+    asDays(): number;
+
+    weeks(): number;
+    asWeeks(): number;
+
+    months(): number;
+    asMonths(): number;
+
+    years(): number;
+    asYears(): number;
+
+    add(inp?: DurationInputArg1, unit?: DurationInputArg2): Duration;
+    subtract(inp?: DurationInputArg1, unit?: DurationInputArg2): Duration;
+
+    locale(): string;
+    locale(locale: LocaleSpecifier): Duration;
+    localeData(): Locale;
+
+    toISOString(): string;
+    toJSON(): string;
+
+    /**
+     * @deprecated since version 2.8.0
+     */
+    lang(locale: LocaleSpecifier): Moment;
+    /**
+     * @deprecated since version 2.8.0
+     */
+    lang(): Locale;
+    /**
+     * @deprecated
+     */
+    toIsoString(): string;
+  }
+
+  interface MomentRelativeTime {
+    future: any;
+    past: any;
+    s: any;
+    m: any;
+    mm: any;
+    h: any;
+    hh: any;
+    d: any;
+    dd: any;
+    M: any;
+    MM: any;
+    y: any;
+    yy: any;
+  }
+
+  interface MomentLongDateFormat {
+    L: string;
+    LL: string;
+    LLL: string;
+    LLLL: string;
+    LT: string;
+    LTS: string;
+
+    l?: string;
+    ll?: string;
+    lll?: string;
+    llll?: string;
+    lt?: string;
+    lts?: string;
+  }
+
+  interface MomentParsingFlags {
+    empty: boolean;
+    unusedTokens: string[];
+    unusedInput: string[];
+    overflow: number;
+    charsLeftOver: number;
+    nullInput: boolean;
+    invalidMonth: string;
+    invalidFormat: boolean;
+    userInvalidated: boolean;
+    iso: boolean;
+    parsedDateParts: any[];
+    meridiem: string;
+  }
+
+  interface MomentParsingFlagsOpt {
+    empty?: boolean;
+    unusedTokens?: string[];
+    unusedInput?: string[];
+    overflow?: number;
+    charsLeftOver?: number;
+    nullInput?: boolean;
+    invalidMonth?: string;
+    invalidFormat?: boolean;
+    userInvalidated?: boolean;
+    iso?: boolean;
+    parsedDateParts?: any[];
+    meridiem?: string;
+  }
+
+  interface MomentBuiltinFormat {
+    __momentBuiltinFormatBrand: any;
+  }
+
+  type MomentFormatSpecification = string | MomentBuiltinFormat | (string | MomentBuiltinFormat)[];
+
+  namespace unitOfTime {
+    type Base = (
+      "year" | "years" | "y" |
+      "month" | "months" | "M" |
+      "week" | "weeks" | "w" |
+      "day" | "days" | "d" |
+      "hour" | "hours" | "h" |
+      "minute" | "minutes" | "m" |
+      "second" | "seconds" | "s" |
+      "millisecond" | "milliseconds" | "ms"
+    );
+
+    type _quarter = "quarter" | "quarters" | "Q";
+    type _isoWeek = "isoWeek" | "isoWeeks" | "W";
+    type _date = "date" | "dates" | "D";
+    type DurationConstructor = Base | _quarter;
+
+    type DurationAs = Base;
+
+    type StartOf = Base | _quarter | _isoWeek | _date;
+
+    type Diff = Base | _quarter;
+
+    type MomentConstructor = Base | _date;
+
+    type All = Base | _quarter | _isoWeek | _date |
+      "weekYear" | "weekYears" | "gg" |
+      "isoWeekYear" | "isoWeekYears" | "GG" |
+      "dayOfYear" | "dayOfYears" | "DDD" |
+      "weekday" | "weekdays" | "e" |
+      "isoWeekday" | "isoWeekdays" | "E";
+  }
+
+  interface MomentInputObject {
+    years?: number;
+    year?: number;
+    y?: number;
+
+    months?: number;
+    month?: number;
+    M?: number;
+
+    days?: number;
+    day?: number;
+    d?: number;
+
+    dates?: number;
+    date?: number;
+    D?: number;
+
+    hours?: number;
+    hour?: number;
+    h?: number;
+
+    minutes?: number;
+    minute?: number;
+    m?: number;
+
+    seconds?: number;
+    second?: number;
+    s?: number;
+
+    milliseconds?: number;
+    millisecond?: number;
+    ms?: number;
+  }
+
+  interface DurationInputObject extends MomentInputObject {
+    quarters?: number;
+    quarter?: number;
+    Q?: number;
+  }
+
+  interface MomentSetObject extends MomentInputObject {
+    weekYears?: number;
+    weekYear?: number;
+    gg?: number;
+
+    isoWeekYears?: number;
+    isoWeekYear?: number;
+    GG?: number;
+
+    quarters?: number;
+    quarter?: number;
+    Q?: number;
+
+    weeks?: number;
+    week?: number;
+    w?: number;
+
+    isoWeeks?: number;
+    isoWeek?: number;
+    W?: number;
+
+    dayOfYears?: number;
+    dayOfYear?: number;
+    DDD?: number;
+
+    weekdays?: number;
+    weekday?: number;
+    e?: number;
+
+    isoWeekdays?: number;
+    isoWeekday?: number;
+    E?: number;
+  }
+
+  interface FromTo {
+    from: MomentInput;
+    to: MomentInput;
+  }
+
+  type MomentInput = Moment | Date | string | number | (number | string)[] | MomentInputObject;
+  type DurationInputArg1 = Duration | number | string | FromTo | DurationInputObject;
+  type DurationInputArg2 = unitOfTime.DurationConstructor;
+  type LocaleSpecifier = string | Moment | Duration | string[];
+
+  interface MomentCreationData {
+    input: string;
+    format: string;
+    locale: Locale;
+    isUTC: boolean;
+    strict: boolean;
+  }
+
+  interface Moment {
+    format(format?: string): string;
+
+    startOf(unitOfTime: unitOfTime.StartOf): Moment;
+    endOf(unitOfTime: unitOfTime.StartOf): Moment;
+
+    add(amount?: DurationInputArg1, unit?: DurationInputArg2): Moment;
+    /**
+     * @deprecated reverse syntax
+     */
+    add(unit: unitOfTime.DurationConstructor, amount: number|string): Moment;
+
+    subtract(amount?: DurationInputArg1, unit?: DurationInputArg2): Moment;
+    /**
+     * @deprecated reverse syntax
+     */
+    subtract(unit: unitOfTime.DurationConstructor, amount: number|string): Moment;
+
+    calendar(time?: MomentInput, formats?: CalendarSpec): string;
+
+    clone(): Moment;
+
+    /**
+     * @return Unix timestamp in milliseconds
+     */
+    valueOf(): number;
+
+    // current date/time in local mode
+    local(keepLocalTime?: boolean): Moment;
+    isLocal(): boolean;
+
+    // current date/time in UTC mode
+    utc(keepLocalTime?: boolean): Moment;
+    isUTC(): boolean;
+    /**
+     * @deprecated use isUTC
+     */
+    isUtc(): boolean;
+
+    parseZone(): Moment;
+    isValid(): boolean;
+    invalidAt(): number;
+
+    hasAlignedHourOffset(other?: MomentInput): boolean;
+
+    creationData(): MomentCreationData;
+    parsingFlags(): MomentParsingFlags;
+
+    year(y: number): Moment;
+    year(): number;
+    /**
+     * @deprecated use year(y)
+     */
+    years(y: number): Moment;
+    /**
+     * @deprecated use year()
+     */
+    years(): number;
+    quarter(): number;
+    quarter(q: number): Moment;
+    quarters(): number;
+    quarters(q: number): Moment;
+    month(M: number|string): Moment;
+    month(): number;
+    /**
+     * @deprecated use month(M)
+     */
+    months(M: number|string): Moment;
+    /**
+     * @deprecated use month()
+     */
+    months(): number;
+    day(d: number|string): Moment;
+    day(): number;
+    days(d: number|string): Moment;
+    days(): number;
+    date(d: number): Moment;
+    date(): number;
+    /**
+     * @deprecated use date(d)
+     */
+    dates(d: number): Moment;
+    /**
+     * @deprecated use date()
+     */
+    dates(): number;
+    hour(h: number): Moment;
+    hour(): number;
+    hours(h: number): Moment;
+    hours(): number;
+    minute(m: number): Moment;
+    minute(): number;
+    minutes(m: number): Moment;
+    minutes(): number;
+    second(s: number): Moment;
+    second(): number;
+    seconds(s: number): Moment;
+    seconds(): number;
+    millisecond(ms: number): Moment;
+    millisecond(): number;
+    milliseconds(ms: number): Moment;
+    milliseconds(): number;
+    weekday(): number;
+    weekday(d: number): Moment;
+    isoWeekday(): number;
+    isoWeekday(d: number|string): Moment;
+    weekYear(): number;
+    weekYear(d: number): Moment;
+    isoWeekYear(): number;
+    isoWeekYear(d: number): Moment;
+    week(): number;
+    week(d: number): Moment;
+    weeks(): number;
+    weeks(d: number): Moment;
+    isoWeek(): number;
+    isoWeek(d: number): Moment;
+    isoWeeks(): number;
+    isoWeeks(d: number): Moment;
+    weeksInYear(): number;
+    isoWeeksInYear(): number;
+    dayOfYear(): number;
+    dayOfYear(d: number): Moment;
+
+    from(inp: MomentInput, suffix?: boolean): string;
+    to(inp: MomentInput, suffix?: boolean): string;
+    fromNow(withoutSuffix?: boolean): string;
+    toNow(withoutPrefix?: boolean): string;
+
+    diff(b: MomentInput, unitOfTime?: unitOfTime.Diff, precise?: boolean): number;
+
+    toArray(): number[];
+    toDate(): Date;
+    toISOString(): string;
+    inspect(): string;
+    toJSON(): string;
+    unix(): number;
+
+    isLeapYear(): boolean;
+    /**
+     * @deprecated in favor of utcOffset
+     */
+    zone(): number;
+    zone(b: number|string): Moment;
+    utcOffset(): number;
+    utcOffset(b: number|string, keepLocalTime?: boolean): Moment;
+    isUTCOffset(): boolean;
+    daysInMonth(): number;
+    isDST(): boolean;
+
+    zoneAbbr(): string;
+    zoneName(): string;
+
+    isBefore(inp?: MomentInput, granularity?: unitOfTime.StartOf): boolean;
+    isAfter(inp?: MomentInput, granularity?: unitOfTime.StartOf): boolean;
+    isSame(inp?: MomentInput, granularity?: unitOfTime.StartOf): boolean;
+    isSameOrAfter(inp?: MomentInput, granularity?: unitOfTime.StartOf): boolean;
+    isSameOrBefore(inp?: MomentInput, granularity?: unitOfTime.StartOf): boolean;
+    isBetween(a: MomentInput, b: MomentInput, granularity?: unitOfTime.StartOf, inclusivity?: "()" | "[)" | "(]" | "[]"): boolean;
+
+    /**
+     * @deprecated as of 2.8.0, use locale
+     */
+    lang(language: LocaleSpecifier): Moment;
+    /**
+     * @deprecated as of 2.8.0, use locale
+     */
+    lang(): Locale;
+
+    locale(): string;
+    locale(locale: LocaleSpecifier): Moment;
+
+    localeData(): Locale;
+
+    /**
+     * @deprecated no reliable implementation
+     */
+    isDSTShifted(): boolean;
+
+    // NOTE(constructor): Same as moment constructor
+    /**
+     * @deprecated as of 2.7.0, use moment.min/max
+     */
+    max(inp?: MomentInput, format?: MomentFormatSpecification, strict?: boolean): Moment;
+    /**
+     * @deprecated as of 2.7.0, use moment.min/max
+     */
+    max(inp?: MomentInput, format?: MomentFormatSpecification, language?: string, strict?: boolean): Moment;
+
+    // NOTE(constructor): Same as moment constructor
+    /**
+     * @deprecated as of 2.7.0, use moment.min/max
+     */
+    min(inp?: MomentInput, format?: MomentFormatSpecification, strict?: boolean): Moment;
+    /**
+     * @deprecated as of 2.7.0, use moment.min/max
+     */
+    min(inp?: MomentInput, format?: MomentFormatSpecification, language?: string, strict?: boolean): Moment;
+
+    get(unit: unitOfTime.All): number;
+    set(unit: unitOfTime.All, value: number): Moment;
+    set(objectLiteral: MomentSetObject): Moment;
+
+    toObject(): MomentObjectOutput;
+  }
+
+  export var version: string;
+  export var fn: Moment;
+
+  // NOTE(constructor): Same as moment constructor
+  export function utc(inp?: MomentInput, format?: MomentFormatSpecification, strict?: boolean): Moment;
+  export function utc(inp?: MomentInput, format?: MomentFormatSpecification, language?: string, strict?: boolean): Moment;
+
+  export function unix(timestamp: number): Moment;
+
+  export function invalid(flags?: MomentParsingFlagsOpt): Moment;
+  export function isMoment(m: any): m is Moment;
+  export function isDate(m: any): m is Date;
+  export function isDuration(d: any): d is Duration;
+
+  /**
+   * @deprecated in 2.8.0
+   */
+  export function lang(language?: string): string;
+  /**
+   * @deprecated in 2.8.0
+   */
+  export function lang(language?: string, definition?: Locale): string;
+
+  export function locale(language?: string): string;
+  export function locale(language?: string[]): string;
+  export function locale(language?: string, definition?: LocaleSpecification): string;
+
+  export function localeData(key?: string | string[]): Locale;
+
+  export function updateLocale(language: string, locale: LocaleSpecification): Locale;
+
+  export function duration(inp?: DurationInputArg1, unit?: DurationInputArg2): Duration;
+
+  // NOTE(constructor): Same as moment constructor
+  export function parseZone(inp?: MomentInput, format?: MomentFormatSpecification, strict?: boolean): Moment;
+  export function parseZone(inp?: MomentInput, format?: MomentFormatSpecification, language?: string, strict?: boolean): Moment;
+
+  export function months(): string[];
+  export function months(index: number): string;
+  export function months(format: string): string[];
+  export function months(format: string, index: number): string;
+  export function monthsShort(): string[];
+  export function monthsShort(index: number): string;
+  export function monthsShort(format: string): string[];
+  export function monthsShort(format: string, index: number): string;
+
+  export function weekdays(): string[];
+  export function weekdays(index: number): string;
+  export function weekdays(format: string): string[];
+  export function weekdays(format: string, index: number): string;
+  export function weekdays(localeSorted: boolean): string[];
+  export function weekdays(localeSorted: boolean, index: number): string;
+  export function weekdays(localeSorted: boolean, format: string): string[];
+  export function weekdays(localeSorted: boolean, format: string, index: number): string;
+  export function weekdaysShort(): string[];
+  export function weekdaysShort(index: number): string;
+  export function weekdaysShort(format: string): string[];
+  export function weekdaysShort(format: string, index: number): string;
+  export function weekdaysShort(localeSorted: boolean): string[];
+  export function weekdaysShort(localeSorted: boolean, index: number): string;
+  export function weekdaysShort(localeSorted: boolean, format: string): string[];
+  export function weekdaysShort(localeSorted: boolean, format: string, index: number): string;
+  export function weekdaysMin(): string[];
+  export function weekdaysMin(index: number): string;
+  export function weekdaysMin(format: string): string[];
+  export function weekdaysMin(format: string, index: number): string;
+  export function weekdaysMin(localeSorted: boolean): string[];
+  export function weekdaysMin(localeSorted: boolean, index: number): string;
+  export function weekdaysMin(localeSorted: boolean, format: string): string[];
+  export function weekdaysMin(localeSorted: boolean, format: string, index: number): string;
+
+  export function min(...moments: MomentInput[]): Moment;
+  export function max(...moments: MomentInput[]): Moment;
+
+  /**
+   * Returns unix time in milliseconds. Overwrite for profit.
+   */
+  export function now(): number;
+
+  export function defineLocale(language: string, localeSpec: LocaleSpecification): Locale;
+  export function updateLocale(language: string, localeSpec: LocaleSpecification): Locale;
+
+  export function locales(): string[];
+
+  export function normalizeUnits(unit: unitOfTime.All): string;
+  export function relativeTimeThreshold(threshold: string): number | boolean;
+  export function relativeTimeThreshold(threshold: string, limit: number): boolean;
+  export function relativeTimeRounding(fn: (num: number) => number): boolean;
+  export function relativeTimeRounding(): (num: number) => number;
+  export function calendarFormat(m: Moment, now: Moment): string;
+
+  /**
+   * Constant used to enable explicit ISO_8601 format parsing.
+   */
+  export var ISO_8601: MomentBuiltinFormat;
+
+  export var defaultFormat: string;
+  export var defaultFormatUtc: string;
+}
+
+export = moment;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/moment.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/moment.js
new file mode 100644
index 0000000000000000000000000000000000000000..3046f1b283159adba14b6500ae8f149157fa066e
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/moment.js
@@ -0,0 +1,4298 @@
+//! moment.js
+//! version : 2.16.0
+//! authors : Tim Wood, Iskren Chernev, Moment.js contributors
+//! license : MIT
+//! momentjs.com
+
+;(function (global, factory) {
+    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+    typeof define === 'function' && define.amd ? define(factory) :
+    global.moment = factory()
+}(this, (function () { 'use strict';
+
+var hookCallback;
+
+function hooks () {
+    return hookCallback.apply(null, arguments);
+}
+
+// This is done to register the method called with moment()
+// without creating circular dependencies.
+function setHookCallback (callback) {
+    hookCallback = callback;
+}
+
+function isArray(input) {
+    return input instanceof Array || Object.prototype.toString.call(input) === '[object Array]';
+}
+
+function isObject(input) {
+    // IE8 will treat undefined and null as object if it wasn't for
+    // input != null
+    return input != null && Object.prototype.toString.call(input) === '[object Object]';
+}
+
+function isObjectEmpty(obj) {
+    var k;
+    for (k in obj) {
+        // even if its not own property I'd still call it non-empty
+        return false;
+    }
+    return true;
+}
+
+function isNumber(input) {
+    return typeof value === 'number' || Object.prototype.toString.call(input) === '[object Number]';
+}
+
+function isDate(input) {
+    return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
+}
+
+function map(arr, fn) {
+    var res = [], i;
+    for (i = 0; i < arr.length; ++i) {
+        res.push(fn(arr[i], i));
+    }
+    return res;
+}
+
+function hasOwnProp(a, b) {
+    return Object.prototype.hasOwnProperty.call(a, b);
+}
+
+function extend(a, b) {
+    for (var i in b) {
+        if (hasOwnProp(b, i)) {
+            a[i] = b[i];
+        }
+    }
+
+    if (hasOwnProp(b, 'toString')) {
+        a.toString = b.toString;
+    }
+
+    if (hasOwnProp(b, 'valueOf')) {
+        a.valueOf = b.valueOf;
+    }
+
+    return a;
+}
+
+function createUTC (input, format, locale, strict) {
+    return createLocalOrUTC(input, format, locale, strict, true).utc();
+}
+
+function defaultParsingFlags() {
+    // We need to deep clone this object.
+    return {
+        empty           : false,
+        unusedTokens    : [],
+        unusedInput     : [],
+        overflow        : -2,
+        charsLeftOver   : 0,
+        nullInput       : false,
+        invalidMonth    : null,
+        invalidFormat   : false,
+        userInvalidated : false,
+        iso             : false,
+        parsedDateParts : [],
+        meridiem        : null
+    };
+}
+
+function getParsingFlags(m) {
+    if (m._pf == null) {
+        m._pf = defaultParsingFlags();
+    }
+    return m._pf;
+}
+
+var some;
+if (Array.prototype.some) {
+    some = Array.prototype.some;
+} else {
+    some = function (fun) {
+        var t = Object(this);
+        var len = t.length >>> 0;
+
+        for (var i = 0; i < len; i++) {
+            if (i in t && fun.call(this, t[i], i, t)) {
+                return true;
+            }
+        }
+
+        return false;
+    };
+}
+
+var some$1 = some;
+
+function isValid(m) {
+    if (m._isValid == null) {
+        var flags = getParsingFlags(m);
+        var parsedParts = some$1.call(flags.parsedDateParts, function (i) {
+            return i != null;
+        });
+        var isNowValid = !isNaN(m._d.getTime()) &&
+            flags.overflow < 0 &&
+            !flags.empty &&
+            !flags.invalidMonth &&
+            !flags.invalidWeekday &&
+            !flags.nullInput &&
+            !flags.invalidFormat &&
+            !flags.userInvalidated &&
+            (!flags.meridiem || (flags.meridiem && parsedParts));
+
+        if (m._strict) {
+            isNowValid = isNowValid &&
+                flags.charsLeftOver === 0 &&
+                flags.unusedTokens.length === 0 &&
+                flags.bigHour === undefined;
+        }
+
+        if (Object.isFrozen == null || !Object.isFrozen(m)) {
+            m._isValid = isNowValid;
+        }
+        else {
+            return isNowValid;
+        }
+    }
+    return m._isValid;
+}
+
+function createInvalid (flags) {
+    var m = createUTC(NaN);
+    if (flags != null) {
+        extend(getParsingFlags(m), flags);
+    }
+    else {
+        getParsingFlags(m).userInvalidated = true;
+    }
+
+    return m;
+}
+
+function isUndefined(input) {
+    return input === void 0;
+}
+
+// Plugins that add properties should also add the key here (null value),
+// so we can properly clone ourselves.
+var momentProperties = hooks.momentProperties = [];
+
+function copyConfig(to, from) {
+    var i, prop, val;
+
+    if (!isUndefined(from._isAMomentObject)) {
+        to._isAMomentObject = from._isAMomentObject;
+    }
+    if (!isUndefined(from._i)) {
+        to._i = from._i;
+    }
+    if (!isUndefined(from._f)) {
+        to._f = from._f;
+    }
+    if (!isUndefined(from._l)) {
+        to._l = from._l;
+    }
+    if (!isUndefined(from._strict)) {
+        to._strict = from._strict;
+    }
+    if (!isUndefined(from._tzm)) {
+        to._tzm = from._tzm;
+    }
+    if (!isUndefined(from._isUTC)) {
+        to._isUTC = from._isUTC;
+    }
+    if (!isUndefined(from._offset)) {
+        to._offset = from._offset;
+    }
+    if (!isUndefined(from._pf)) {
+        to._pf = getParsingFlags(from);
+    }
+    if (!isUndefined(from._locale)) {
+        to._locale = from._locale;
+    }
+
+    if (momentProperties.length > 0) {
+        for (i in momentProperties) {
+            prop = momentProperties[i];
+            val = from[prop];
+            if (!isUndefined(val)) {
+                to[prop] = val;
+            }
+        }
+    }
+
+    return to;
+}
+
+var updateInProgress = false;
+
+// Moment prototype object
+function Moment(config) {
+    copyConfig(this, config);
+    this._d = new Date(config._d != null ? config._d.getTime() : NaN);
+    // Prevent infinite loop in case updateOffset creates new moment
+    // objects.
+    if (updateInProgress === false) {
+        updateInProgress = true;
+        hooks.updateOffset(this);
+        updateInProgress = false;
+    }
+}
+
+function isMoment (obj) {
+    return obj instanceof Moment || (obj != null && obj._isAMomentObject != null);
+}
+
+function absFloor (number) {
+    if (number < 0) {
+        // -0 -> 0
+        return Math.ceil(number) || 0;
+    } else {
+        return Math.floor(number);
+    }
+}
+
+function toInt(argumentForCoercion) {
+    var coercedNumber = +argumentForCoercion,
+        value = 0;
+
+    if (coercedNumber !== 0 && isFinite(coercedNumber)) {
+        value = absFloor(coercedNumber);
+    }
+
+    return value;
+}
+
+// compare two arrays, return the number of differences
+function compareArrays(array1, array2, dontConvert) {
+    var len = Math.min(array1.length, array2.length),
+        lengthDiff = Math.abs(array1.length - array2.length),
+        diffs = 0,
+        i;
+    for (i = 0; i < len; i++) {
+        if ((dontConvert && array1[i] !== array2[i]) ||
+            (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) {
+            diffs++;
+        }
+    }
+    return diffs + lengthDiff;
+}
+
+function warn(msg) {
+    if (hooks.suppressDeprecationWarnings === false &&
+            (typeof console !==  'undefined') && console.warn) {
+        console.warn('Deprecation warning: ' + msg);
+    }
+}
+
+function deprecate(msg, fn) {
+    var firstTime = true;
+
+    return extend(function () {
+        if (hooks.deprecationHandler != null) {
+            hooks.deprecationHandler(null, msg);
+        }
+        if (firstTime) {
+            var args = [];
+            var arg;
+            for (var i = 0; i < arguments.length; i++) {
+                arg = '';
+                if (typeof arguments[i] === 'object') {
+                    arg += '\n[' + i + '] ';
+                    for (var key in arguments[0]) {
+                        arg += key + ': ' + arguments[0][key] + ', ';
+                    }
+                    arg = arg.slice(0, -2); // Remove trailing comma and space
+                } else {
+                    arg = arguments[i];
+                }
+                args.push(arg);
+            }
+            warn(msg + '\nArguments: ' + Array.prototype.slice.call(args).join('') + '\n' + (new Error()).stack);
+            firstTime = false;
+        }
+        return fn.apply(this, arguments);
+    }, fn);
+}
+
+var deprecations = {};
+
+function deprecateSimple(name, msg) {
+    if (hooks.deprecationHandler != null) {
+        hooks.deprecationHandler(name, msg);
+    }
+    if (!deprecations[name]) {
+        warn(msg);
+        deprecations[name] = true;
+    }
+}
+
+hooks.suppressDeprecationWarnings = false;
+hooks.deprecationHandler = null;
+
+function isFunction(input) {
+    return input instanceof Function || Object.prototype.toString.call(input) === '[object Function]';
+}
+
+function set (config) {
+    var prop, i;
+    for (i in config) {
+        prop = config[i];
+        if (isFunction(prop)) {
+            this[i] = prop;
+        } else {
+            this['_' + i] = prop;
+        }
+    }
+    this._config = config;
+    // Lenient ordinal parsing accepts just a number in addition to
+    // number + (possibly) stuff coming from _ordinalParseLenient.
+    this._ordinalParseLenient = new RegExp(this._ordinalParse.source + '|' + (/\d{1,2}/).source);
+}
+
+function mergeConfigs(parentConfig, childConfig) {
+    var res = extend({}, parentConfig), prop;
+    for (prop in childConfig) {
+        if (hasOwnProp(childConfig, prop)) {
+            if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) {
+                res[prop] = {};
+                extend(res[prop], parentConfig[prop]);
+                extend(res[prop], childConfig[prop]);
+            } else if (childConfig[prop] != null) {
+                res[prop] = childConfig[prop];
+            } else {
+                delete res[prop];
+            }
+        }
+    }
+    for (prop in parentConfig) {
+        if (hasOwnProp(parentConfig, prop) &&
+                !hasOwnProp(childConfig, prop) &&
+                isObject(parentConfig[prop])) {
+            // make sure changes to properties don't modify parent config
+            res[prop] = extend({}, res[prop]);
+        }
+    }
+    return res;
+}
+
+function Locale(config) {
+    if (config != null) {
+        this.set(config);
+    }
+}
+
+var keys;
+
+if (Object.keys) {
+    keys = Object.keys;
+} else {
+    keys = function (obj) {
+        var i, res = [];
+        for (i in obj) {
+            if (hasOwnProp(obj, i)) {
+                res.push(i);
+            }
+        }
+        return res;
+    };
+}
+
+var keys$1 = keys;
+
+var defaultCalendar = {
+    sameDay : '[Today at] LT',
+    nextDay : '[Tomorrow at] LT',
+    nextWeek : 'dddd [at] LT',
+    lastDay : '[Yesterday at] LT',
+    lastWeek : '[Last] dddd [at] LT',
+    sameElse : 'L'
+};
+
+function calendar (key, mom, now) {
+    var output = this._calendar[key] || this._calendar['sameElse'];
+    return isFunction(output) ? output.call(mom, now) : output;
+}
+
+var defaultLongDateFormat = {
+    LTS  : 'h:mm:ss A',
+    LT   : 'h:mm A',
+    L    : 'MM/DD/YYYY',
+    LL   : 'MMMM D, YYYY',
+    LLL  : 'MMMM D, YYYY h:mm A',
+    LLLL : 'dddd, MMMM D, YYYY h:mm A'
+};
+
+function longDateFormat (key) {
+    var format = this._longDateFormat[key],
+        formatUpper = this._longDateFormat[key.toUpperCase()];
+
+    if (format || !formatUpper) {
+        return format;
+    }
+
+    this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) {
+        return val.slice(1);
+    });
+
+    return this._longDateFormat[key];
+}
+
+var defaultInvalidDate = 'Invalid date';
+
+function invalidDate () {
+    return this._invalidDate;
+}
+
+var defaultOrdinal = '%d';
+var defaultOrdinalParse = /\d{1,2}/;
+
+function ordinal (number) {
+    return this._ordinal.replace('%d', number);
+}
+
+var defaultRelativeTime = {
+    future : 'in %s',
+    past   : '%s ago',
+    s  : 'a few seconds',
+    m  : 'a minute',
+    mm : '%d minutes',
+    h  : 'an hour',
+    hh : '%d hours',
+    d  : 'a day',
+    dd : '%d days',
+    M  : 'a month',
+    MM : '%d months',
+    y  : 'a year',
+    yy : '%d years'
+};
+
+function relativeTime (number, withoutSuffix, string, isFuture) {
+    var output = this._relativeTime[string];
+    return (isFunction(output)) ?
+        output(number, withoutSuffix, string, isFuture) :
+        output.replace(/%d/i, number);
+}
+
+function pastFuture (diff, output) {
+    var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
+    return isFunction(format) ? format(output) : format.replace(/%s/i, output);
+}
+
+var aliases = {};
+
+function addUnitAlias (unit, shorthand) {
+    var lowerCase = unit.toLowerCase();
+    aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit;
+}
+
+function normalizeUnits(units) {
+    return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined;
+}
+
+function normalizeObjectUnits(inputObject) {
+    var normalizedInput = {},
+        normalizedProp,
+        prop;
+
+    for (prop in inputObject) {
+        if (hasOwnProp(inputObject, prop)) {
+            normalizedProp = normalizeUnits(prop);
+            if (normalizedProp) {
+                normalizedInput[normalizedProp] = inputObject[prop];
+            }
+        }
+    }
+
+    return normalizedInput;
+}
+
+var priorities = {};
+
+function addUnitPriority(unit, priority) {
+    priorities[unit] = priority;
+}
+
+function getPrioritizedUnits(unitsObj) {
+    var units = [];
+    for (var u in unitsObj) {
+        units.push({unit: u, priority: priorities[u]});
+    }
+    units.sort(function (a, b) {
+        return a.priority - b.priority;
+    });
+    return units;
+}
+
+function makeGetSet (unit, keepTime) {
+    return function (value) {
+        if (value != null) {
+            set$1(this, unit, value);
+            hooks.updateOffset(this, keepTime);
+            return this;
+        } else {
+            return get(this, unit);
+        }
+    };
+}
+
+function get (mom, unit) {
+    return mom.isValid() ?
+        mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() : NaN;
+}
+
+function set$1 (mom, unit, value) {
+    if (mom.isValid()) {
+        mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
+    }
+}
+
+// MOMENTS
+
+function stringGet (units) {
+    units = normalizeUnits(units);
+    if (isFunction(this[units])) {
+        return this[units]();
+    }
+    return this;
+}
+
+
+function stringSet (units, value) {
+    if (typeof units === 'object') {
+        units = normalizeObjectUnits(units);
+        var prioritized = getPrioritizedUnits(units);
+        for (var i = 0; i < prioritized.length; i++) {
+            this[prioritized[i].unit](units[prioritized[i].unit]);
+        }
+    } else {
+        units = normalizeUnits(units);
+        if (isFunction(this[units])) {
+            return this[units](value);
+        }
+    }
+    return this;
+}
+
+function zeroFill(number, targetLength, forceSign) {
+    var absNumber = '' + Math.abs(number),
+        zerosToFill = targetLength - absNumber.length,
+        sign = number >= 0;
+    return (sign ? (forceSign ? '+' : '') : '-') +
+        Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber;
+}
+
+var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g;
+
+var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g;
+
+var formatFunctions = {};
+
+var formatTokenFunctions = {};
+
+// token:    'M'
+// padded:   ['MM', 2]
+// ordinal:  'Mo'
+// callback: function () { this.month() + 1 }
+function addFormatToken (token, padded, ordinal, callback) {
+    var func = callback;
+    if (typeof callback === 'string') {
+        func = function () {
+            return this[callback]();
+        };
+    }
+    if (token) {
+        formatTokenFunctions[token] = func;
+    }
+    if (padded) {
+        formatTokenFunctions[padded[0]] = function () {
+            return zeroFill(func.apply(this, arguments), padded[1], padded[2]);
+        };
+    }
+    if (ordinal) {
+        formatTokenFunctions[ordinal] = function () {
+            return this.localeData().ordinal(func.apply(this, arguments), token);
+        };
+    }
+}
+
+function removeFormattingTokens(input) {
+    if (input.match(/\[[\s\S]/)) {
+        return input.replace(/^\[|\]$/g, '');
+    }
+    return input.replace(/\\/g, '');
+}
+
+function makeFormatFunction(format) {
+    var array = format.match(formattingTokens), i, length;
+
+    for (i = 0, length = array.length; i < length; i++) {
+        if (formatTokenFunctions[array[i]]) {
+            array[i] = formatTokenFunctions[array[i]];
+        } else {
+            array[i] = removeFormattingTokens(array[i]);
+        }
+    }
+
+    return function (mom) {
+        var output = '', i;
+        for (i = 0; i < length; i++) {
+            output += array[i] instanceof Function ? array[i].call(mom, format) : array[i];
+        }
+        return output;
+    };
+}
+
+// format date using native date object
+function formatMoment(m, format) {
+    if (!m.isValid()) {
+        return m.localeData().invalidDate();
+    }
+
+    format = expandFormat(format, m.localeData());
+    formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format);
+
+    return formatFunctions[format](m);
+}
+
+function expandFormat(format, locale) {
+    var i = 5;
+
+    function replaceLongDateFormatTokens(input) {
+        return locale.longDateFormat(input) || input;
+    }
+
+    localFormattingTokens.lastIndex = 0;
+    while (i >= 0 && localFormattingTokens.test(format)) {
+        format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
+        localFormattingTokens.lastIndex = 0;
+        i -= 1;
+    }
+
+    return format;
+}
+
+var match1         = /\d/;            //       0 - 9
+var match2         = /\d\d/;          //      00 - 99
+var match3         = /\d{3}/;         //     000 - 999
+var match4         = /\d{4}/;         //    0000 - 9999
+var match6         = /[+-]?\d{6}/;    // -999999 - 999999
+var match1to2      = /\d\d?/;         //       0 - 99
+var match3to4      = /\d\d\d\d?/;     //     999 - 9999
+var match5to6      = /\d\d\d\d\d\d?/; //   99999 - 999999
+var match1to3      = /\d{1,3}/;       //       0 - 999
+var match1to4      = /\d{1,4}/;       //       0 - 9999
+var match1to6      = /[+-]?\d{1,6}/;  // -999999 - 999999
+
+var matchUnsigned  = /\d+/;           //       0 - inf
+var matchSigned    = /[+-]?\d+/;      //    -inf - inf
+
+var matchOffset    = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z
+var matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi; // +00 -00 +00:00 -00:00 +0000 -0000 or Z
+
+var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123
+
+// any word (or two) characters or numbers including two/three word month in arabic.
+// includes scottish gaelic two word and hyphenated months
+var matchWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i;
+
+
+var regexes = {};
+
+function addRegexToken (token, regex, strictRegex) {
+    regexes[token] = isFunction(regex) ? regex : function (isStrict, localeData) {
+        return (isStrict && strictRegex) ? strictRegex : regex;
+    };
+}
+
+function getParseRegexForToken (token, config) {
+    if (!hasOwnProp(regexes, token)) {
+        return new RegExp(unescapeFormat(token));
+    }
+
+    return regexes[token](config._strict, config._locale);
+}
+
+// Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
+function unescapeFormat(s) {
+    return regexEscape(s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
+        return p1 || p2 || p3 || p4;
+    }));
+}
+
+function regexEscape(s) {
+    return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
+}
+
+var tokens = {};
+
+function addParseToken (token, callback) {
+    var i, func = callback;
+    if (typeof token === 'string') {
+        token = [token];
+    }
+    if (isNumber(callback)) {
+        func = function (input, array) {
+            array[callback] = toInt(input);
+        };
+    }
+    for (i = 0; i < token.length; i++) {
+        tokens[token[i]] = func;
+    }
+}
+
+function addWeekParseToken (token, callback) {
+    addParseToken(token, function (input, array, config, token) {
+        config._w = config._w || {};
+        callback(input, config._w, config, token);
+    });
+}
+
+function addTimeToArrayFromToken(token, input, config) {
+    if (input != null && hasOwnProp(tokens, token)) {
+        tokens[token](input, config._a, config, token);
+    }
+}
+
+var YEAR = 0;
+var MONTH = 1;
+var DATE = 2;
+var HOUR = 3;
+var MINUTE = 4;
+var SECOND = 5;
+var MILLISECOND = 6;
+var WEEK = 7;
+var WEEKDAY = 8;
+
+var indexOf;
+
+if (Array.prototype.indexOf) {
+    indexOf = Array.prototype.indexOf;
+} else {
+    indexOf = function (o) {
+        // I know
+        var i;
+        for (i = 0; i < this.length; ++i) {
+            if (this[i] === o) {
+                return i;
+            }
+        }
+        return -1;
+    };
+}
+
+var indexOf$1 = indexOf;
+
+function daysInMonth(year, month) {
+    return new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
+}
+
+// FORMATTING
+
+addFormatToken('M', ['MM', 2], 'Mo', function () {
+    return this.month() + 1;
+});
+
+addFormatToken('MMM', 0, 0, function (format) {
+    return this.localeData().monthsShort(this, format);
+});
+
+addFormatToken('MMMM', 0, 0, function (format) {
+    return this.localeData().months(this, format);
+});
+
+// ALIASES
+
+addUnitAlias('month', 'M');
+
+// PRIORITY
+
+addUnitPriority('month', 8);
+
+// PARSING
+
+addRegexToken('M',    match1to2);
+addRegexToken('MM',   match1to2, match2);
+addRegexToken('MMM',  function (isStrict, locale) {
+    return locale.monthsShortRegex(isStrict);
+});
+addRegexToken('MMMM', function (isStrict, locale) {
+    return locale.monthsRegex(isStrict);
+});
+
+addParseToken(['M', 'MM'], function (input, array) {
+    array[MONTH] = toInt(input) - 1;
+});
+
+addParseToken(['MMM', 'MMMM'], function (input, array, config, token) {
+    var month = config._locale.monthsParse(input, token, config._strict);
+    // if we didn't find a month name, mark the date as invalid.
+    if (month != null) {
+        array[MONTH] = month;
+    } else {
+        getParsingFlags(config).invalidMonth = input;
+    }
+});
+
+// LOCALES
+
+var MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/;
+var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_');
+function localeMonths (m, format) {
+    if (!m) {
+        return this._months;
+    }
+    return isArray(this._months) ? this._months[m.month()] :
+        this._months[(this._months.isFormat || MONTHS_IN_FORMAT).test(format) ? 'format' : 'standalone'][m.month()];
+}
+
+var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_');
+function localeMonthsShort (m, format) {
+    if (!m) {
+        return this._monthsShort;
+    }
+    return isArray(this._monthsShort) ? this._monthsShort[m.month()] :
+        this._monthsShort[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()];
+}
+
+function handleStrictParse(monthName, format, strict) {
+    var i, ii, mom, llc = monthName.toLocaleLowerCase();
+    if (!this._monthsParse) {
+        // this is not used
+        this._monthsParse = [];
+        this._longMonthsParse = [];
+        this._shortMonthsParse = [];
+        for (i = 0; i < 12; ++i) {
+            mom = createUTC([2000, i]);
+            this._shortMonthsParse[i] = this.monthsShort(mom, '').toLocaleLowerCase();
+            this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase();
+        }
+    }
+
+    if (strict) {
+        if (format === 'MMM') {
+            ii = indexOf$1.call(this._shortMonthsParse, llc);
+            return ii !== -1 ? ii : null;
+        } else {
+            ii = indexOf$1.call(this._longMonthsParse, llc);
+            return ii !== -1 ? ii : null;
+        }
+    } else {
+        if (format === 'MMM') {
+            ii = indexOf$1.call(this._shortMonthsParse, llc);
+            if (ii !== -1) {
+                return ii;
+            }
+            ii = indexOf$1.call(this._longMonthsParse, llc);
+            return ii !== -1 ? ii : null;
+        } else {
+            ii = indexOf$1.call(this._longMonthsParse, llc);
+            if (ii !== -1) {
+                return ii;
+            }
+            ii = indexOf$1.call(this._shortMonthsParse, llc);
+            return ii !== -1 ? ii : null;
+        }
+    }
+}
+
+function localeMonthsParse (monthName, format, strict) {
+    var i, mom, regex;
+
+    if (this._monthsParseExact) {
+        return handleStrictParse.call(this, monthName, format, strict);
+    }
+
+    if (!this._monthsParse) {
+        this._monthsParse = [];
+        this._longMonthsParse = [];
+        this._shortMonthsParse = [];
+    }
+
+    // TODO: add sorting
+    // Sorting makes sure if one month (or abbr) is a prefix of another
+    // see sorting in computeMonthsParse
+    for (i = 0; i < 12; i++) {
+        // make the regex if we don't have it already
+        mom = createUTC([2000, i]);
+        if (strict && !this._longMonthsParse[i]) {
+            this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');
+            this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');
+        }
+        if (!strict && !this._monthsParse[i]) {
+            regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
+            this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
+        }
+        // test the regex
+        if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {
+            return i;
+        } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {
+            return i;
+        } else if (!strict && this._monthsParse[i].test(monthName)) {
+            return i;
+        }
+    }
+}
+
+// MOMENTS
+
+function setMonth (mom, value) {
+    var dayOfMonth;
+
+    if (!mom.isValid()) {
+        // No op
+        return mom;
+    }
+
+    if (typeof value === 'string') {
+        if (/^\d+$/.test(value)) {
+            value = toInt(value);
+        } else {
+            value = mom.localeData().monthsParse(value);
+            // TODO: Another silent failure?
+            if (!isNumber(value)) {
+                return mom;
+            }
+        }
+    }
+
+    dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));
+    mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
+    return mom;
+}
+
+function getSetMonth (value) {
+    if (value != null) {
+        setMonth(this, value);
+        hooks.updateOffset(this, true);
+        return this;
+    } else {
+        return get(this, 'Month');
+    }
+}
+
+function getDaysInMonth () {
+    return daysInMonth(this.year(), this.month());
+}
+
+var defaultMonthsShortRegex = matchWord;
+function monthsShortRegex (isStrict) {
+    if (this._monthsParseExact) {
+        if (!hasOwnProp(this, '_monthsRegex')) {
+            computeMonthsParse.call(this);
+        }
+        if (isStrict) {
+            return this._monthsShortStrictRegex;
+        } else {
+            return this._monthsShortRegex;
+        }
+    } else {
+        if (!hasOwnProp(this, '_monthsShortRegex')) {
+            this._monthsShortRegex = defaultMonthsShortRegex;
+        }
+        return this._monthsShortStrictRegex && isStrict ?
+            this._monthsShortStrictRegex : this._monthsShortRegex;
+    }
+}
+
+var defaultMonthsRegex = matchWord;
+function monthsRegex (isStrict) {
+    if (this._monthsParseExact) {
+        if (!hasOwnProp(this, '_monthsRegex')) {
+            computeMonthsParse.call(this);
+        }
+        if (isStrict) {
+            return this._monthsStrictRegex;
+        } else {
+            return this._monthsRegex;
+        }
+    } else {
+        if (!hasOwnProp(this, '_monthsRegex')) {
+            this._monthsRegex = defaultMonthsRegex;
+        }
+        return this._monthsStrictRegex && isStrict ?
+            this._monthsStrictRegex : this._monthsRegex;
+    }
+}
+
+function computeMonthsParse () {
+    function cmpLenRev(a, b) {
+        return b.length - a.length;
+    }
+
+    var shortPieces = [], longPieces = [], mixedPieces = [],
+        i, mom;
+    for (i = 0; i < 12; i++) {
+        // make the regex if we don't have it already
+        mom = createUTC([2000, i]);
+        shortPieces.push(this.monthsShort(mom, ''));
+        longPieces.push(this.months(mom, ''));
+        mixedPieces.push(this.months(mom, ''));
+        mixedPieces.push(this.monthsShort(mom, ''));
+    }
+    // Sorting makes sure if one month (or abbr) is a prefix of another it
+    // will match the longer piece.
+    shortPieces.sort(cmpLenRev);
+    longPieces.sort(cmpLenRev);
+    mixedPieces.sort(cmpLenRev);
+    for (i = 0; i < 12; i++) {
+        shortPieces[i] = regexEscape(shortPieces[i]);
+        longPieces[i] = regexEscape(longPieces[i]);
+    }
+    for (i = 0; i < 24; i++) {
+        mixedPieces[i] = regexEscape(mixedPieces[i]);
+    }
+
+    this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
+    this._monthsShortRegex = this._monthsRegex;
+    this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
+    this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
+}
+
+// FORMATTING
+
+addFormatToken('Y', 0, 0, function () {
+    var y = this.year();
+    return y <= 9999 ? '' + y : '+' + y;
+});
+
+addFormatToken(0, ['YY', 2], 0, function () {
+    return this.year() % 100;
+});
+
+addFormatToken(0, ['YYYY',   4],       0, 'year');
+addFormatToken(0, ['YYYYY',  5],       0, 'year');
+addFormatToken(0, ['YYYYYY', 6, true], 0, 'year');
+
+// ALIASES
+
+addUnitAlias('year', 'y');
+
+// PRIORITIES
+
+addUnitPriority('year', 1);
+
+// PARSING
+
+addRegexToken('Y',      matchSigned);
+addRegexToken('YY',     match1to2, match2);
+addRegexToken('YYYY',   match1to4, match4);
+addRegexToken('YYYYY',  match1to6, match6);
+addRegexToken('YYYYYY', match1to6, match6);
+
+addParseToken(['YYYYY', 'YYYYYY'], YEAR);
+addParseToken('YYYY', function (input, array) {
+    array[YEAR] = input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input);
+});
+addParseToken('YY', function (input, array) {
+    array[YEAR] = hooks.parseTwoDigitYear(input);
+});
+addParseToken('Y', function (input, array) {
+    array[YEAR] = parseInt(input, 10);
+});
+
+// HELPERS
+
+function daysInYear(year) {
+    return isLeapYear(year) ? 366 : 365;
+}
+
+function isLeapYear(year) {
+    return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
+}
+
+// HOOKS
+
+hooks.parseTwoDigitYear = function (input) {
+    return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
+};
+
+// MOMENTS
+
+var getSetYear = makeGetSet('FullYear', true);
+
+function getIsLeapYear () {
+    return isLeapYear(this.year());
+}
+
+function createDate (y, m, d, h, M, s, ms) {
+    //can't just apply() to create a date:
+    //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply
+    var date = new Date(y, m, d, h, M, s, ms);
+
+    //the date constructor remaps years 0-99 to 1900-1999
+    if (y < 100 && y >= 0 && isFinite(date.getFullYear())) {
+        date.setFullYear(y);
+    }
+    return date;
+}
+
+function createUTCDate (y) {
+    var date = new Date(Date.UTC.apply(null, arguments));
+
+    //the Date.UTC function remaps years 0-99 to 1900-1999
+    if (y < 100 && y >= 0 && isFinite(date.getUTCFullYear())) {
+        date.setUTCFullYear(y);
+    }
+    return date;
+}
+
+// start-of-first-week - start-of-year
+function firstWeekOffset(year, dow, doy) {
+    var // first-week day -- which january is always in the first week (4 for iso, 1 for other)
+        fwd = 7 + dow - doy,
+        // first-week day local weekday -- which local weekday is fwd
+        fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7;
+
+    return -fwdlw + fwd - 1;
+}
+
+//http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
+function dayOfYearFromWeeks(year, week, weekday, dow, doy) {
+    var localWeekday = (7 + weekday - dow) % 7,
+        weekOffset = firstWeekOffset(year, dow, doy),
+        dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset,
+        resYear, resDayOfYear;
+
+    if (dayOfYear <= 0) {
+        resYear = year - 1;
+        resDayOfYear = daysInYear(resYear) + dayOfYear;
+    } else if (dayOfYear > daysInYear(year)) {
+        resYear = year + 1;
+        resDayOfYear = dayOfYear - daysInYear(year);
+    } else {
+        resYear = year;
+        resDayOfYear = dayOfYear;
+    }
+
+    return {
+        year: resYear,
+        dayOfYear: resDayOfYear
+    };
+}
+
+function weekOfYear(mom, dow, doy) {
+    var weekOffset = firstWeekOffset(mom.year(), dow, doy),
+        week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1,
+        resWeek, resYear;
+
+    if (week < 1) {
+        resYear = mom.year() - 1;
+        resWeek = week + weeksInYear(resYear, dow, doy);
+    } else if (week > weeksInYear(mom.year(), dow, doy)) {
+        resWeek = week - weeksInYear(mom.year(), dow, doy);
+        resYear = mom.year() + 1;
+    } else {
+        resYear = mom.year();
+        resWeek = week;
+    }
+
+    return {
+        week: resWeek,
+        year: resYear
+    };
+}
+
+function weeksInYear(year, dow, doy) {
+    var weekOffset = firstWeekOffset(year, dow, doy),
+        weekOffsetNext = firstWeekOffset(year + 1, dow, doy);
+    return (daysInYear(year) - weekOffset + weekOffsetNext) / 7;
+}
+
+// FORMATTING
+
+addFormatToken('w', ['ww', 2], 'wo', 'week');
+addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek');
+
+// ALIASES
+
+addUnitAlias('week', 'w');
+addUnitAlias('isoWeek', 'W');
+
+// PRIORITIES
+
+addUnitPriority('week', 5);
+addUnitPriority('isoWeek', 5);
+
+// PARSING
+
+addRegexToken('w',  match1to2);
+addRegexToken('ww', match1to2, match2);
+addRegexToken('W',  match1to2);
+addRegexToken('WW', match1to2, match2);
+
+addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) {
+    week[token.substr(0, 1)] = toInt(input);
+});
+
+// HELPERS
+
+// LOCALES
+
+function localeWeek (mom) {
+    return weekOfYear(mom, this._week.dow, this._week.doy).week;
+}
+
+var defaultLocaleWeek = {
+    dow : 0, // Sunday is the first day of the week.
+    doy : 6  // The week that contains Jan 1st is the first week of the year.
+};
+
+function localeFirstDayOfWeek () {
+    return this._week.dow;
+}
+
+function localeFirstDayOfYear () {
+    return this._week.doy;
+}
+
+// MOMENTS
+
+function getSetWeek (input) {
+    var week = this.localeData().week(this);
+    return input == null ? week : this.add((input - week) * 7, 'd');
+}
+
+function getSetISOWeek (input) {
+    var week = weekOfYear(this, 1, 4).week;
+    return input == null ? week : this.add((input - week) * 7, 'd');
+}
+
+// FORMATTING
+
+addFormatToken('d', 0, 'do', 'day');
+
+addFormatToken('dd', 0, 0, function (format) {
+    return this.localeData().weekdaysMin(this, format);
+});
+
+addFormatToken('ddd', 0, 0, function (format) {
+    return this.localeData().weekdaysShort(this, format);
+});
+
+addFormatToken('dddd', 0, 0, function (format) {
+    return this.localeData().weekdays(this, format);
+});
+
+addFormatToken('e', 0, 0, 'weekday');
+addFormatToken('E', 0, 0, 'isoWeekday');
+
+// ALIASES
+
+addUnitAlias('day', 'd');
+addUnitAlias('weekday', 'e');
+addUnitAlias('isoWeekday', 'E');
+
+// PRIORITY
+addUnitPriority('day', 11);
+addUnitPriority('weekday', 11);
+addUnitPriority('isoWeekday', 11);
+
+// PARSING
+
+addRegexToken('d',    match1to2);
+addRegexToken('e',    match1to2);
+addRegexToken('E',    match1to2);
+addRegexToken('dd',   function (isStrict, locale) {
+    return locale.weekdaysMinRegex(isStrict);
+});
+addRegexToken('ddd',   function (isStrict, locale) {
+    return locale.weekdaysShortRegex(isStrict);
+});
+addRegexToken('dddd',   function (isStrict, locale) {
+    return locale.weekdaysRegex(isStrict);
+});
+
+addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) {
+    var weekday = config._locale.weekdaysParse(input, token, config._strict);
+    // if we didn't get a weekday name, mark the date as invalid
+    if (weekday != null) {
+        week.d = weekday;
+    } else {
+        getParsingFlags(config).invalidWeekday = input;
+    }
+});
+
+addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) {
+    week[token] = toInt(input);
+});
+
+// HELPERS
+
+function parseWeekday(input, locale) {
+    if (typeof input !== 'string') {
+        return input;
+    }
+
+    if (!isNaN(input)) {
+        return parseInt(input, 10);
+    }
+
+    input = locale.weekdaysParse(input);
+    if (typeof input === 'number') {
+        return input;
+    }
+
+    return null;
+}
+
+function parseIsoWeekday(input, locale) {
+    if (typeof input === 'string') {
+        return locale.weekdaysParse(input) % 7 || 7;
+    }
+    return isNaN(input) ? null : input;
+}
+
+// LOCALES
+
+var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_');
+function localeWeekdays (m, format) {
+    if (!m) {
+        return this._weekdays;
+    }
+    return isArray(this._weekdays) ? this._weekdays[m.day()] :
+        this._weekdays[this._weekdays.isFormat.test(format) ? 'format' : 'standalone'][m.day()];
+}
+
+var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_');
+function localeWeekdaysShort (m) {
+    return (m) ? this._weekdaysShort[m.day()] : this._weekdaysShort;
+}
+
+var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_');
+function localeWeekdaysMin (m) {
+    return (m) ? this._weekdaysMin[m.day()] : this._weekdaysMin;
+}
+
+function handleStrictParse$1(weekdayName, format, strict) {
+    var i, ii, mom, llc = weekdayName.toLocaleLowerCase();
+    if (!this._weekdaysParse) {
+        this._weekdaysParse = [];
+        this._shortWeekdaysParse = [];
+        this._minWeekdaysParse = [];
+
+        for (i = 0; i < 7; ++i) {
+            mom = createUTC([2000, 1]).day(i);
+            this._minWeekdaysParse[i] = this.weekdaysMin(mom, '').toLocaleLowerCase();
+            this._shortWeekdaysParse[i] = this.weekdaysShort(mom, '').toLocaleLowerCase();
+            this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase();
+        }
+    }
+
+    if (strict) {
+        if (format === 'dddd') {
+            ii = indexOf$1.call(this._weekdaysParse, llc);
+            return ii !== -1 ? ii : null;
+        } else if (format === 'ddd') {
+            ii = indexOf$1.call(this._shortWeekdaysParse, llc);
+            return ii !== -1 ? ii : null;
+        } else {
+            ii = indexOf$1.call(this._minWeekdaysParse, llc);
+            return ii !== -1 ? ii : null;
+        }
+    } else {
+        if (format === 'dddd') {
+            ii = indexOf$1.call(this._weekdaysParse, llc);
+            if (ii !== -1) {
+                return ii;
+            }
+            ii = indexOf$1.call(this._shortWeekdaysParse, llc);
+            if (ii !== -1) {
+                return ii;
+            }
+            ii = indexOf$1.call(this._minWeekdaysParse, llc);
+            return ii !== -1 ? ii : null;
+        } else if (format === 'ddd') {
+            ii = indexOf$1.call(this._shortWeekdaysParse, llc);
+            if (ii !== -1) {
+                return ii;
+            }
+            ii = indexOf$1.call(this._weekdaysParse, llc);
+            if (ii !== -1) {
+                return ii;
+            }
+            ii = indexOf$1.call(this._minWeekdaysParse, llc);
+            return ii !== -1 ? ii : null;
+        } else {
+            ii = indexOf$1.call(this._minWeekdaysParse, llc);
+            if (ii !== -1) {
+                return ii;
+            }
+            ii = indexOf$1.call(this._weekdaysParse, llc);
+            if (ii !== -1) {
+                return ii;
+            }
+            ii = indexOf$1.call(this._shortWeekdaysParse, llc);
+            return ii !== -1 ? ii : null;
+        }
+    }
+}
+
+function localeWeekdaysParse (weekdayName, format, strict) {
+    var i, mom, regex;
+
+    if (this._weekdaysParseExact) {
+        return handleStrictParse$1.call(this, weekdayName, format, strict);
+    }
+
+    if (!this._weekdaysParse) {
+        this._weekdaysParse = [];
+        this._minWeekdaysParse = [];
+        this._shortWeekdaysParse = [];
+        this._fullWeekdaysParse = [];
+    }
+
+    for (i = 0; i < 7; i++) {
+        // make the regex if we don't have it already
+
+        mom = createUTC([2000, 1]).day(i);
+        if (strict && !this._fullWeekdaysParse[i]) {
+            this._fullWeekdaysParse[i] = new RegExp('^' + this.weekdays(mom, '').replace('.', '\.?') + '$', 'i');
+            this._shortWeekdaysParse[i] = new RegExp('^' + this.weekdaysShort(mom, '').replace('.', '\.?') + '$', 'i');
+            this._minWeekdaysParse[i] = new RegExp('^' + this.weekdaysMin(mom, '').replace('.', '\.?') + '$', 'i');
+        }
+        if (!this._weekdaysParse[i]) {
+            regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
+            this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
+        }
+        // test the regex
+        if (strict && format === 'dddd' && this._fullWeekdaysParse[i].test(weekdayName)) {
+            return i;
+        } else if (strict && format === 'ddd' && this._shortWeekdaysParse[i].test(weekdayName)) {
+            return i;
+        } else if (strict && format === 'dd' && this._minWeekdaysParse[i].test(weekdayName)) {
+            return i;
+        } else if (!strict && this._weekdaysParse[i].test(weekdayName)) {
+            return i;
+        }
+    }
+}
+
+// MOMENTS
+
+function getSetDayOfWeek (input) {
+    if (!this.isValid()) {
+        return input != null ? this : NaN;
+    }
+    var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
+    if (input != null) {
+        input = parseWeekday(input, this.localeData());
+        return this.add(input - day, 'd');
+    } else {
+        return day;
+    }
+}
+
+function getSetLocaleDayOfWeek (input) {
+    if (!this.isValid()) {
+        return input != null ? this : NaN;
+    }
+    var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;
+    return input == null ? weekday : this.add(input - weekday, 'd');
+}
+
+function getSetISODayOfWeek (input) {
+    if (!this.isValid()) {
+        return input != null ? this : NaN;
+    }
+
+    // behaves the same as moment#day except
+    // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
+    // as a setter, sunday should belong to the previous week.
+
+    if (input != null) {
+        var weekday = parseIsoWeekday(input, this.localeData());
+        return this.day(this.day() % 7 ? weekday : weekday - 7);
+    } else {
+        return this.day() || 7;
+    }
+}
+
+var defaultWeekdaysRegex = matchWord;
+function weekdaysRegex (isStrict) {
+    if (this._weekdaysParseExact) {
+        if (!hasOwnProp(this, '_weekdaysRegex')) {
+            computeWeekdaysParse.call(this);
+        }
+        if (isStrict) {
+            return this._weekdaysStrictRegex;
+        } else {
+            return this._weekdaysRegex;
+        }
+    } else {
+        if (!hasOwnProp(this, '_weekdaysRegex')) {
+            this._weekdaysRegex = defaultWeekdaysRegex;
+        }
+        return this._weekdaysStrictRegex && isStrict ?
+            this._weekdaysStrictRegex : this._weekdaysRegex;
+    }
+}
+
+var defaultWeekdaysShortRegex = matchWord;
+function weekdaysShortRegex (isStrict) {
+    if (this._weekdaysParseExact) {
+        if (!hasOwnProp(this, '_weekdaysRegex')) {
+            computeWeekdaysParse.call(this);
+        }
+        if (isStrict) {
+            return this._weekdaysShortStrictRegex;
+        } else {
+            return this._weekdaysShortRegex;
+        }
+    } else {
+        if (!hasOwnProp(this, '_weekdaysShortRegex')) {
+            this._weekdaysShortRegex = defaultWeekdaysShortRegex;
+        }
+        return this._weekdaysShortStrictRegex && isStrict ?
+            this._weekdaysShortStrictRegex : this._weekdaysShortRegex;
+    }
+}
+
+var defaultWeekdaysMinRegex = matchWord;
+function weekdaysMinRegex (isStrict) {
+    if (this._weekdaysParseExact) {
+        if (!hasOwnProp(this, '_weekdaysRegex')) {
+            computeWeekdaysParse.call(this);
+        }
+        if (isStrict) {
+            return this._weekdaysMinStrictRegex;
+        } else {
+            return this._weekdaysMinRegex;
+        }
+    } else {
+        if (!hasOwnProp(this, '_weekdaysMinRegex')) {
+            this._weekdaysMinRegex = defaultWeekdaysMinRegex;
+        }
+        return this._weekdaysMinStrictRegex && isStrict ?
+            this._weekdaysMinStrictRegex : this._weekdaysMinRegex;
+    }
+}
+
+
+function computeWeekdaysParse () {
+    function cmpLenRev(a, b) {
+        return b.length - a.length;
+    }
+
+    var minPieces = [], shortPieces = [], longPieces = [], mixedPieces = [],
+        i, mom, minp, shortp, longp;
+    for (i = 0; i < 7; i++) {
+        // make the regex if we don't have it already
+        mom = createUTC([2000, 1]).day(i);
+        minp = this.weekdaysMin(mom, '');
+        shortp = this.weekdaysShort(mom, '');
+        longp = this.weekdays(mom, '');
+        minPieces.push(minp);
+        shortPieces.push(shortp);
+        longPieces.push(longp);
+        mixedPieces.push(minp);
+        mixedPieces.push(shortp);
+        mixedPieces.push(longp);
+    }
+    // Sorting makes sure if one weekday (or abbr) is a prefix of another it
+    // will match the longer piece.
+    minPieces.sort(cmpLenRev);
+    shortPieces.sort(cmpLenRev);
+    longPieces.sort(cmpLenRev);
+    mixedPieces.sort(cmpLenRev);
+    for (i = 0; i < 7; i++) {
+        shortPieces[i] = regexEscape(shortPieces[i]);
+        longPieces[i] = regexEscape(longPieces[i]);
+        mixedPieces[i] = regexEscape(mixedPieces[i]);
+    }
+
+    this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
+    this._weekdaysShortRegex = this._weekdaysRegex;
+    this._weekdaysMinRegex = this._weekdaysRegex;
+
+    this._weekdaysStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
+    this._weekdaysShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
+    this._weekdaysMinStrictRegex = new RegExp('^(' + minPieces.join('|') + ')', 'i');
+}
+
+// FORMATTING
+
+function hFormat() {
+    return this.hours() % 12 || 12;
+}
+
+function kFormat() {
+    return this.hours() || 24;
+}
+
+addFormatToken('H', ['HH', 2], 0, 'hour');
+addFormatToken('h', ['hh', 2], 0, hFormat);
+addFormatToken('k', ['kk', 2], 0, kFormat);
+
+addFormatToken('hmm', 0, 0, function () {
+    return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2);
+});
+
+addFormatToken('hmmss', 0, 0, function () {
+    return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2) +
+        zeroFill(this.seconds(), 2);
+});
+
+addFormatToken('Hmm', 0, 0, function () {
+    return '' + this.hours() + zeroFill(this.minutes(), 2);
+});
+
+addFormatToken('Hmmss', 0, 0, function () {
+    return '' + this.hours() + zeroFill(this.minutes(), 2) +
+        zeroFill(this.seconds(), 2);
+});
+
+function meridiem (token, lowercase) {
+    addFormatToken(token, 0, 0, function () {
+        return this.localeData().meridiem(this.hours(), this.minutes(), lowercase);
+    });
+}
+
+meridiem('a', true);
+meridiem('A', false);
+
+// ALIASES
+
+addUnitAlias('hour', 'h');
+
+// PRIORITY
+addUnitPriority('hour', 13);
+
+// PARSING
+
+function matchMeridiem (isStrict, locale) {
+    return locale._meridiemParse;
+}
+
+addRegexToken('a',  matchMeridiem);
+addRegexToken('A',  matchMeridiem);
+addRegexToken('H',  match1to2);
+addRegexToken('h',  match1to2);
+addRegexToken('HH', match1to2, match2);
+addRegexToken('hh', match1to2, match2);
+
+addRegexToken('hmm', match3to4);
+addRegexToken('hmmss', match5to6);
+addRegexToken('Hmm', match3to4);
+addRegexToken('Hmmss', match5to6);
+
+addParseToken(['H', 'HH'], HOUR);
+addParseToken(['a', 'A'], function (input, array, config) {
+    config._isPm = config._locale.isPM(input);
+    config._meridiem = input;
+});
+addParseToken(['h', 'hh'], function (input, array, config) {
+    array[HOUR] = toInt(input);
+    getParsingFlags(config).bigHour = true;
+});
+addParseToken('hmm', function (input, array, config) {
+    var pos = input.length - 2;
+    array[HOUR] = toInt(input.substr(0, pos));
+    array[MINUTE] = toInt(input.substr(pos));
+    getParsingFlags(config).bigHour = true;
+});
+addParseToken('hmmss', function (input, array, config) {
+    var pos1 = input.length - 4;
+    var pos2 = input.length - 2;
+    array[HOUR] = toInt(input.substr(0, pos1));
+    array[MINUTE] = toInt(input.substr(pos1, 2));
+    array[SECOND] = toInt(input.substr(pos2));
+    getParsingFlags(config).bigHour = true;
+});
+addParseToken('Hmm', function (input, array, config) {
+    var pos = input.length - 2;
+    array[HOUR] = toInt(input.substr(0, pos));
+    array[MINUTE] = toInt(input.substr(pos));
+});
+addParseToken('Hmmss', function (input, array, config) {
+    var pos1 = input.length - 4;
+    var pos2 = input.length - 2;
+    array[HOUR] = toInt(input.substr(0, pos1));
+    array[MINUTE] = toInt(input.substr(pos1, 2));
+    array[SECOND] = toInt(input.substr(pos2));
+});
+
+// LOCALES
+
+function localeIsPM (input) {
+    // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
+    // Using charAt should be more compatible.
+    return ((input + '').toLowerCase().charAt(0) === 'p');
+}
+
+var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i;
+function localeMeridiem (hours, minutes, isLower) {
+    if (hours > 11) {
+        return isLower ? 'pm' : 'PM';
+    } else {
+        return isLower ? 'am' : 'AM';
+    }
+}
+
+
+// MOMENTS
+
+// Setting the hour should keep the time, because the user explicitly
+// specified which hour he wants. So trying to maintain the same hour (in
+// a new timezone) makes sense. Adding/subtracting hours does not follow
+// this rule.
+var getSetHour = makeGetSet('Hours', true);
+
+// months
+// week
+// weekdays
+// meridiem
+var baseConfig = {
+    calendar: defaultCalendar,
+    longDateFormat: defaultLongDateFormat,
+    invalidDate: defaultInvalidDate,
+    ordinal: defaultOrdinal,
+    ordinalParse: defaultOrdinalParse,
+    relativeTime: defaultRelativeTime,
+
+    months: defaultLocaleMonths,
+    monthsShort: defaultLocaleMonthsShort,
+
+    week: defaultLocaleWeek,
+
+    weekdays: defaultLocaleWeekdays,
+    weekdaysMin: defaultLocaleWeekdaysMin,
+    weekdaysShort: defaultLocaleWeekdaysShort,
+
+    meridiemParse: defaultLocaleMeridiemParse
+};
+
+// internal storage for locale config files
+var locales = {};
+var localeFamilies = {};
+var globalLocale;
+
+function normalizeLocale(key) {
+    return key ? key.toLowerCase().replace('_', '-') : key;
+}
+
+// pick the locale from the array
+// try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
+// substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
+function chooseLocale(names) {
+    var i = 0, j, next, locale, split;
+
+    while (i < names.length) {
+        split = normalizeLocale(names[i]).split('-');
+        j = split.length;
+        next = normalizeLocale(names[i + 1]);
+        next = next ? next.split('-') : null;
+        while (j > 0) {
+            locale = loadLocale(split.slice(0, j).join('-'));
+            if (locale) {
+                return locale;
+            }
+            if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
+                //the next array item is better than a shallower substring of this one
+                break;
+            }
+            j--;
+        }
+        i++;
+    }
+    return null;
+}
+
+function loadLocale(name) {
+    var oldLocale = null;
+    // TODO: Find a better way to register and load all the locales in Node
+    if (!locales[name] && (typeof module !== 'undefined') &&
+            module && module.exports) {
+        try {
+            oldLocale = globalLocale._abbr;
+            require('./locale/' + name);
+            // because defineLocale currently also sets the global locale, we
+            // want to undo that for lazy loaded locales
+            getSetGlobalLocale(oldLocale);
+        } catch (e) { }
+    }
+    return locales[name];
+}
+
+// This function will load locale and then set the global locale.  If
+// no arguments are passed in, it will simply return the current global
+// locale key.
+function getSetGlobalLocale (key, values) {
+    var data;
+    if (key) {
+        if (isUndefined(values)) {
+            data = getLocale(key);
+        }
+        else {
+            data = defineLocale(key, values);
+        }
+
+        if (data) {
+            // moment.duration._locale = moment._locale = data;
+            globalLocale = data;
+        }
+    }
+
+    return globalLocale._abbr;
+}
+
+function defineLocale (name, config) {
+    if (config !== null) {
+        var parentConfig = baseConfig;
+        config.abbr = name;
+        if (locales[name] != null) {
+            deprecateSimple('defineLocaleOverride',
+                    'use moment.updateLocale(localeName, config) to change ' +
+                    'an existing locale. moment.defineLocale(localeName, ' +
+                    'config) should only be used for creating a new locale ' +
+                    'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.');
+            parentConfig = locales[name]._config;
+        } else if (config.parentLocale != null) {
+            if (locales[config.parentLocale] != null) {
+                parentConfig = locales[config.parentLocale]._config;
+            } else {
+                if (!localeFamilies[config.parentLocale]) {
+                    localeFamilies[config.parentLocale] = [];
+                }
+                localeFamilies[config.parentLocale].push({
+                    name: name,
+                    config: config
+                });
+                return null;
+            }
+        }
+        locales[name] = new Locale(mergeConfigs(parentConfig, config));
+
+        if (localeFamilies[name]) {
+            localeFamilies[name].forEach(function (x) {
+                defineLocale(x.name, x.config);
+            });
+        }
+
+        // backwards compat for now: also set the locale
+        // make sure we set the locale AFTER all child locales have been
+        // created, so we won't end up with the child locale set.
+        getSetGlobalLocale(name);
+
+
+        return locales[name];
+    } else {
+        // useful for testing
+        delete locales[name];
+        return null;
+    }
+}
+
+function updateLocale(name, config) {
+    if (config != null) {
+        var locale, parentConfig = baseConfig;
+        // MERGE
+        if (locales[name] != null) {
+            parentConfig = locales[name]._config;
+        }
+        config = mergeConfigs(parentConfig, config);
+        locale = new Locale(config);
+        locale.parentLocale = locales[name];
+        locales[name] = locale;
+
+        // backwards compat for now: also set the locale
+        getSetGlobalLocale(name);
+    } else {
+        // pass null for config to unupdate, useful for tests
+        if (locales[name] != null) {
+            if (locales[name].parentLocale != null) {
+                locales[name] = locales[name].parentLocale;
+            } else if (locales[name] != null) {
+                delete locales[name];
+            }
+        }
+    }
+    return locales[name];
+}
+
+// returns locale data
+function getLocale (key) {
+    var locale;
+
+    if (key && key._locale && key._locale._abbr) {
+        key = key._locale._abbr;
+    }
+
+    if (!key) {
+        return globalLocale;
+    }
+
+    if (!isArray(key)) {
+        //short-circuit everything else
+        locale = loadLocale(key);
+        if (locale) {
+            return locale;
+        }
+        key = [key];
+    }
+
+    return chooseLocale(key);
+}
+
+function listLocales() {
+    return keys$1(locales);
+}
+
+function checkOverflow (m) {
+    var overflow;
+    var a = m._a;
+
+    if (a && getParsingFlags(m).overflow === -2) {
+        overflow =
+            a[MONTH]       < 0 || a[MONTH]       > 11  ? MONTH :
+            a[DATE]        < 1 || a[DATE]        > daysInMonth(a[YEAR], a[MONTH]) ? DATE :
+            a[HOUR]        < 0 || a[HOUR]        > 24 || (a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0)) ? HOUR :
+            a[MINUTE]      < 0 || a[MINUTE]      > 59  ? MINUTE :
+            a[SECOND]      < 0 || a[SECOND]      > 59  ? SECOND :
+            a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND :
+            -1;
+
+        if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
+            overflow = DATE;
+        }
+        if (getParsingFlags(m)._overflowWeeks && overflow === -1) {
+            overflow = WEEK;
+        }
+        if (getParsingFlags(m)._overflowWeekday && overflow === -1) {
+            overflow = WEEKDAY;
+        }
+
+        getParsingFlags(m).overflow = overflow;
+    }
+
+    return m;
+}
+
+// iso 8601 regex
+// 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
+var extendedIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
+var basicIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
+
+var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/;
+
+var isoDates = [
+    ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/],
+    ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/],
+    ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/],
+    ['GGGG-[W]WW', /\d{4}-W\d\d/, false],
+    ['YYYY-DDD', /\d{4}-\d{3}/],
+    ['YYYY-MM', /\d{4}-\d\d/, false],
+    ['YYYYYYMMDD', /[+-]\d{10}/],
+    ['YYYYMMDD', /\d{8}/],
+    // YYYYMM is NOT allowed by the standard
+    ['GGGG[W]WWE', /\d{4}W\d{3}/],
+    ['GGGG[W]WW', /\d{4}W\d{2}/, false],
+    ['YYYYDDD', /\d{7}/]
+];
+
+// iso time formats and regexes
+var isoTimes = [
+    ['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/],
+    ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/],
+    ['HH:mm:ss', /\d\d:\d\d:\d\d/],
+    ['HH:mm', /\d\d:\d\d/],
+    ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/],
+    ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/],
+    ['HHmmss', /\d\d\d\d\d\d/],
+    ['HHmm', /\d\d\d\d/],
+    ['HH', /\d\d/]
+];
+
+var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i;
+
+// date from iso format
+function configFromISO(config) {
+    var i, l,
+        string = config._i,
+        match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string),
+        allowTime, dateFormat, timeFormat, tzFormat;
+
+    if (match) {
+        getParsingFlags(config).iso = true;
+
+        for (i = 0, l = isoDates.length; i < l; i++) {
+            if (isoDates[i][1].exec(match[1])) {
+                dateFormat = isoDates[i][0];
+                allowTime = isoDates[i][2] !== false;
+                break;
+            }
+        }
+        if (dateFormat == null) {
+            config._isValid = false;
+            return;
+        }
+        if (match[3]) {
+            for (i = 0, l = isoTimes.length; i < l; i++) {
+                if (isoTimes[i][1].exec(match[3])) {
+                    // match[2] should be 'T' or space
+                    timeFormat = (match[2] || ' ') + isoTimes[i][0];
+                    break;
+                }
+            }
+            if (timeFormat == null) {
+                config._isValid = false;
+                return;
+            }
+        }
+        if (!allowTime && timeFormat != null) {
+            config._isValid = false;
+            return;
+        }
+        if (match[4]) {
+            if (tzRegex.exec(match[4])) {
+                tzFormat = 'Z';
+            } else {
+                config._isValid = false;
+                return;
+            }
+        }
+        config._f = dateFormat + (timeFormat || '') + (tzFormat || '');
+        configFromStringAndFormat(config);
+    } else {
+        config._isValid = false;
+    }
+}
+
+// date from iso format or fallback
+function configFromString(config) {
+    var matched = aspNetJsonRegex.exec(config._i);
+
+    if (matched !== null) {
+        config._d = new Date(+matched[1]);
+        return;
+    }
+
+    configFromISO(config);
+    if (config._isValid === false) {
+        delete config._isValid;
+        hooks.createFromInputFallback(config);
+    }
+}
+
+hooks.createFromInputFallback = deprecate(
+    'value provided is not in a recognized ISO format. moment construction falls back to js Date(), ' +
+    'which is not reliable across all browsers and versions. Non ISO date formats are ' +
+    'discouraged and will be removed in an upcoming major release. Please refer to ' +
+    'http://momentjs.com/guides/#/warnings/js-date/ for more info.',
+    function (config) {
+        config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
+    }
+);
+
+// Pick the first defined of two or three arguments.
+function defaults(a, b, c) {
+    if (a != null) {
+        return a;
+    }
+    if (b != null) {
+        return b;
+    }
+    return c;
+}
+
+function currentDateArray(config) {
+    // hooks is actually the exported moment object
+    var nowValue = new Date(hooks.now());
+    if (config._useUTC) {
+        return [nowValue.getUTCFullYear(), nowValue.getUTCMonth(), nowValue.getUTCDate()];
+    }
+    return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()];
+}
+
+// convert an array to a date.
+// the array should mirror the parameters below
+// note: all values past the year are optional and will default to the lowest possible value.
+// [year, month, day , hour, minute, second, millisecond]
+function configFromArray (config) {
+    var i, date, input = [], currentDate, yearToUse;
+
+    if (config._d) {
+        return;
+    }
+
+    currentDate = currentDateArray(config);
+
+    //compute day of the year from weeks and weekdays
+    if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
+        dayOfYearFromWeekInfo(config);
+    }
+
+    //if the day of the year is set, figure out what it is
+    if (config._dayOfYear) {
+        yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);
+
+        if (config._dayOfYear > daysInYear(yearToUse)) {
+            getParsingFlags(config)._overflowDayOfYear = true;
+        }
+
+        date = createUTCDate(yearToUse, 0, config._dayOfYear);
+        config._a[MONTH] = date.getUTCMonth();
+        config._a[DATE] = date.getUTCDate();
+    }
+
+    // Default to current date.
+    // * if no year, month, day of month are given, default to today
+    // * if day of month is given, default month and year
+    // * if month is given, default only year
+    // * if year is given, don't default anything
+    for (i = 0; i < 3 && config._a[i] == null; ++i) {
+        config._a[i] = input[i] = currentDate[i];
+    }
+
+    // Zero out whatever was not defaulted, including time
+    for (; i < 7; i++) {
+        config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
+    }
+
+    // Check for 24:00:00.000
+    if (config._a[HOUR] === 24 &&
+            config._a[MINUTE] === 0 &&
+            config._a[SECOND] === 0 &&
+            config._a[MILLISECOND] === 0) {
+        config._nextDay = true;
+        config._a[HOUR] = 0;
+    }
+
+    config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input);
+    // Apply timezone offset from input. The actual utcOffset can be changed
+    // with parseZone.
+    if (config._tzm != null) {
+        config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
+    }
+
+    if (config._nextDay) {
+        config._a[HOUR] = 24;
+    }
+}
+
+function dayOfYearFromWeekInfo(config) {
+    var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow;
+
+    w = config._w;
+    if (w.GG != null || w.W != null || w.E != null) {
+        dow = 1;
+        doy = 4;
+
+        // TODO: We need to take the current isoWeekYear, but that depends on
+        // how we interpret now (local, utc, fixed offset). So create
+        // a now version of current config (take local/utc/offset flags, and
+        // create now).
+        weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(createLocal(), 1, 4).year);
+        week = defaults(w.W, 1);
+        weekday = defaults(w.E, 1);
+        if (weekday < 1 || weekday > 7) {
+            weekdayOverflow = true;
+        }
+    } else {
+        dow = config._locale._week.dow;
+        doy = config._locale._week.doy;
+
+        var curWeek = weekOfYear(createLocal(), dow, doy);
+
+        weekYear = defaults(w.gg, config._a[YEAR], curWeek.year);
+
+        // Default to current week.
+        week = defaults(w.w, curWeek.week);
+
+        if (w.d != null) {
+            // weekday -- low day numbers are considered next week
+            weekday = w.d;
+            if (weekday < 0 || weekday > 6) {
+                weekdayOverflow = true;
+            }
+        } else if (w.e != null) {
+            // local weekday -- counting starts from begining of week
+            weekday = w.e + dow;
+            if (w.e < 0 || w.e > 6) {
+                weekdayOverflow = true;
+            }
+        } else {
+            // default to begining of week
+            weekday = dow;
+        }
+    }
+    if (week < 1 || week > weeksInYear(weekYear, dow, doy)) {
+        getParsingFlags(config)._overflowWeeks = true;
+    } else if (weekdayOverflow != null) {
+        getParsingFlags(config)._overflowWeekday = true;
+    } else {
+        temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy);
+        config._a[YEAR] = temp.year;
+        config._dayOfYear = temp.dayOfYear;
+    }
+}
+
+// constant that refers to the ISO standard
+hooks.ISO_8601 = function () {};
+
+// date from string and format string
+function configFromStringAndFormat(config) {
+    // TODO: Move this to another part of the creation flow to prevent circular deps
+    if (config._f === hooks.ISO_8601) {
+        configFromISO(config);
+        return;
+    }
+
+    config._a = [];
+    getParsingFlags(config).empty = true;
+
+    // This array is used to make a Date, either with `new Date` or `Date.UTC`
+    var string = '' + config._i,
+        i, parsedInput, tokens, token, skipped,
+        stringLength = string.length,
+        totalParsedInputLength = 0;
+
+    tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];
+
+    for (i = 0; i < tokens.length; i++) {
+        token = tokens[i];
+        parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];
+        // console.log('token', token, 'parsedInput', parsedInput,
+        //         'regex', getParseRegexForToken(token, config));
+        if (parsedInput) {
+            skipped = string.substr(0, string.indexOf(parsedInput));
+            if (skipped.length > 0) {
+                getParsingFlags(config).unusedInput.push(skipped);
+            }
+            string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
+            totalParsedInputLength += parsedInput.length;
+        }
+        // don't parse if it's not a known token
+        if (formatTokenFunctions[token]) {
+            if (parsedInput) {
+                getParsingFlags(config).empty = false;
+            }
+            else {
+                getParsingFlags(config).unusedTokens.push(token);
+            }
+            addTimeToArrayFromToken(token, parsedInput, config);
+        }
+        else if (config._strict && !parsedInput) {
+            getParsingFlags(config).unusedTokens.push(token);
+        }
+    }
+
+    // add remaining unparsed input length to the string
+    getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength;
+    if (string.length > 0) {
+        getParsingFlags(config).unusedInput.push(string);
+    }
+
+    // clear _12h flag if hour is <= 12
+    if (config._a[HOUR] <= 12 &&
+        getParsingFlags(config).bigHour === true &&
+        config._a[HOUR] > 0) {
+        getParsingFlags(config).bigHour = undefined;
+    }
+
+    getParsingFlags(config).parsedDateParts = config._a.slice(0);
+    getParsingFlags(config).meridiem = config._meridiem;
+    // handle meridiem
+    config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem);
+
+    configFromArray(config);
+    checkOverflow(config);
+}
+
+
+function meridiemFixWrap (locale, hour, meridiem) {
+    var isPm;
+
+    if (meridiem == null) {
+        // nothing to do
+        return hour;
+    }
+    if (locale.meridiemHour != null) {
+        return locale.meridiemHour(hour, meridiem);
+    } else if (locale.isPM != null) {
+        // Fallback
+        isPm = locale.isPM(meridiem);
+        if (isPm && hour < 12) {
+            hour += 12;
+        }
+        if (!isPm && hour === 12) {
+            hour = 0;
+        }
+        return hour;
+    } else {
+        // this is not supposed to happen
+        return hour;
+    }
+}
+
+// date from string and array of format strings
+function configFromStringAndArray(config) {
+    var tempConfig,
+        bestMoment,
+
+        scoreToBeat,
+        i,
+        currentScore;
+
+    if (config._f.length === 0) {
+        getParsingFlags(config).invalidFormat = true;
+        config._d = new Date(NaN);
+        return;
+    }
+
+    for (i = 0; i < config._f.length; i++) {
+        currentScore = 0;
+        tempConfig = copyConfig({}, config);
+        if (config._useUTC != null) {
+            tempConfig._useUTC = config._useUTC;
+        }
+        tempConfig._f = config._f[i];
+        configFromStringAndFormat(tempConfig);
+
+        if (!isValid(tempConfig)) {
+            continue;
+        }
+
+        // if there is any input that was not parsed add a penalty for that format
+        currentScore += getParsingFlags(tempConfig).charsLeftOver;
+
+        //or tokens
+        currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;
+
+        getParsingFlags(tempConfig).score = currentScore;
+
+        if (scoreToBeat == null || currentScore < scoreToBeat) {
+            scoreToBeat = currentScore;
+            bestMoment = tempConfig;
+        }
+    }
+
+    extend(config, bestMoment || tempConfig);
+}
+
+function configFromObject(config) {
+    if (config._d) {
+        return;
+    }
+
+    var i = normalizeObjectUnits(config._i);
+    config._a = map([i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond], function (obj) {
+        return obj && parseInt(obj, 10);
+    });
+
+    configFromArray(config);
+}
+
+function createFromConfig (config) {
+    var res = new Moment(checkOverflow(prepareConfig(config)));
+    if (res._nextDay) {
+        // Adding is smart enough around DST
+        res.add(1, 'd');
+        res._nextDay = undefined;
+    }
+
+    return res;
+}
+
+function prepareConfig (config) {
+    var input = config._i,
+        format = config._f;
+
+    config._locale = config._locale || getLocale(config._l);
+
+    if (input === null || (format === undefined && input === '')) {
+        return createInvalid({nullInput: true});
+    }
+
+    if (typeof input === 'string') {
+        config._i = input = config._locale.preparse(input);
+    }
+
+    if (isMoment(input)) {
+        return new Moment(checkOverflow(input));
+    } else if (isDate(input)) {
+        config._d = input;
+    } else if (isArray(format)) {
+        configFromStringAndArray(config);
+    } else if (format) {
+        configFromStringAndFormat(config);
+    }  else {
+        configFromInput(config);
+    }
+
+    if (!isValid(config)) {
+        config._d = null;
+    }
+
+    return config;
+}
+
+function configFromInput(config) {
+    var input = config._i;
+    if (input === undefined) {
+        config._d = new Date(hooks.now());
+    } else if (isDate(input)) {
+        config._d = new Date(input.valueOf());
+    } else if (typeof input === 'string') {
+        configFromString(config);
+    } else if (isArray(input)) {
+        config._a = map(input.slice(0), function (obj) {
+            return parseInt(obj, 10);
+        });
+        configFromArray(config);
+    } else if (typeof(input) === 'object') {
+        configFromObject(config);
+    } else if (isNumber(input)) {
+        // from milliseconds
+        config._d = new Date(input);
+    } else {
+        hooks.createFromInputFallback(config);
+    }
+}
+
+function createLocalOrUTC (input, format, locale, strict, isUTC) {
+    var c = {};
+
+    if (locale === true || locale === false) {
+        strict = locale;
+        locale = undefined;
+    }
+
+    if ((isObject(input) && isObjectEmpty(input)) ||
+            (isArray(input) && input.length === 0)) {
+        input = undefined;
+    }
+    // object construction must be done this way.
+    // https://github.com/moment/moment/issues/1423
+    c._isAMomentObject = true;
+    c._useUTC = c._isUTC = isUTC;
+    c._l = locale;
+    c._i = input;
+    c._f = format;
+    c._strict = strict;
+
+    return createFromConfig(c);
+}
+
+function createLocal (input, format, locale, strict) {
+    return createLocalOrUTC(input, format, locale, strict, false);
+}
+
+var prototypeMin = deprecate(
+    'moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/',
+    function () {
+        var other = createLocal.apply(null, arguments);
+        if (this.isValid() && other.isValid()) {
+            return other < this ? this : other;
+        } else {
+            return createInvalid();
+        }
+    }
+);
+
+var prototypeMax = deprecate(
+    'moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/',
+    function () {
+        var other = createLocal.apply(null, arguments);
+        if (this.isValid() && other.isValid()) {
+            return other > this ? this : other;
+        } else {
+            return createInvalid();
+        }
+    }
+);
+
+// Pick a moment m from moments so that m[fn](other) is true for all
+// other. This relies on the function fn to be transitive.
+//
+// moments should either be an array of moment objects or an array, whose
+// first element is an array of moment objects.
+function pickBy(fn, moments) {
+    var res, i;
+    if (moments.length === 1 && isArray(moments[0])) {
+        moments = moments[0];
+    }
+    if (!moments.length) {
+        return createLocal();
+    }
+    res = moments[0];
+    for (i = 1; i < moments.length; ++i) {
+        if (!moments[i].isValid() || moments[i][fn](res)) {
+            res = moments[i];
+        }
+    }
+    return res;
+}
+
+// TODO: Use [].sort instead?
+function min () {
+    var args = [].slice.call(arguments, 0);
+
+    return pickBy('isBefore', args);
+}
+
+function max () {
+    var args = [].slice.call(arguments, 0);
+
+    return pickBy('isAfter', args);
+}
+
+var now = function () {
+    return Date.now ? Date.now() : +(new Date());
+};
+
+function Duration (duration) {
+    var normalizedInput = normalizeObjectUnits(duration),
+        years = normalizedInput.year || 0,
+        quarters = normalizedInput.quarter || 0,
+        months = normalizedInput.month || 0,
+        weeks = normalizedInput.week || 0,
+        days = normalizedInput.day || 0,
+        hours = normalizedInput.hour || 0,
+        minutes = normalizedInput.minute || 0,
+        seconds = normalizedInput.second || 0,
+        milliseconds = normalizedInput.millisecond || 0;
+
+    // representation for dateAddRemove
+    this._milliseconds = +milliseconds +
+        seconds * 1e3 + // 1000
+        minutes * 6e4 + // 1000 * 60
+        hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
+    // Because of dateAddRemove treats 24 hours as different from a
+    // day when working around DST, we need to store them separately
+    this._days = +days +
+        weeks * 7;
+    // It is impossible translate months into days without knowing
+    // which months you are are talking about, so we have to store
+    // it separately.
+    this._months = +months +
+        quarters * 3 +
+        years * 12;
+
+    this._data = {};
+
+    this._locale = getLocale();
+
+    this._bubble();
+}
+
+function isDuration (obj) {
+    return obj instanceof Duration;
+}
+
+function absRound (number) {
+    if (number < 0) {
+        return Math.round(-1 * number) * -1;
+    } else {
+        return Math.round(number);
+    }
+}
+
+// FORMATTING
+
+function offset (token, separator) {
+    addFormatToken(token, 0, 0, function () {
+        var offset = this.utcOffset();
+        var sign = '+';
+        if (offset < 0) {
+            offset = -offset;
+            sign = '-';
+        }
+        return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~(offset) % 60, 2);
+    });
+}
+
+offset('Z', ':');
+offset('ZZ', '');
+
+// PARSING
+
+addRegexToken('Z',  matchShortOffset);
+addRegexToken('ZZ', matchShortOffset);
+addParseToken(['Z', 'ZZ'], function (input, array, config) {
+    config._useUTC = true;
+    config._tzm = offsetFromString(matchShortOffset, input);
+});
+
+// HELPERS
+
+// timezone chunker
+// '+10:00' > ['10',  '00']
+// '-1530'  > ['-15', '30']
+var chunkOffset = /([\+\-]|\d\d)/gi;
+
+function offsetFromString(matcher, string) {
+    var matches = (string || '').match(matcher);
+
+    if (matches === null) {
+        return null;
+    }
+
+    var chunk   = matches[matches.length - 1] || [];
+    var parts   = (chunk + '').match(chunkOffset) || ['-', 0, 0];
+    var minutes = +(parts[1] * 60) + toInt(parts[2]);
+
+    return minutes === 0 ?
+      0 :
+      parts[0] === '+' ? minutes : -minutes;
+}
+
+// Return a moment from input, that is local/utc/zone equivalent to model.
+function cloneWithOffset(input, model) {
+    var res, diff;
+    if (model._isUTC) {
+        res = model.clone();
+        diff = (isMoment(input) || isDate(input) ? input.valueOf() : createLocal(input).valueOf()) - res.valueOf();
+        // Use low-level api, because this fn is low-level api.
+        res._d.setTime(res._d.valueOf() + diff);
+        hooks.updateOffset(res, false);
+        return res;
+    } else {
+        return createLocal(input).local();
+    }
+}
+
+function getDateOffset (m) {
+    // On Firefox.24 Date#getTimezoneOffset returns a floating point.
+    // https://github.com/moment/moment/pull/1871
+    return -Math.round(m._d.getTimezoneOffset() / 15) * 15;
+}
+
+// HOOKS
+
+// This function will be called whenever a moment is mutated.
+// It is intended to keep the offset in sync with the timezone.
+hooks.updateOffset = function () {};
+
+// MOMENTS
+
+// keepLocalTime = true means only change the timezone, without
+// affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
+// 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
+// +0200, so we adjust the time as needed, to be valid.
+//
+// Keeping the time actually adds/subtracts (one hour)
+// from the actual represented time. That is why we call updateOffset
+// a second time. In case it wants us to change the offset again
+// _changeInProgress == true case, then we have to adjust, because
+// there is no such time in the given timezone.
+function getSetOffset (input, keepLocalTime) {
+    var offset = this._offset || 0,
+        localAdjust;
+    if (!this.isValid()) {
+        return input != null ? this : NaN;
+    }
+    if (input != null) {
+        if (typeof input === 'string') {
+            input = offsetFromString(matchShortOffset, input);
+            if (input === null) {
+                return this;
+            }
+        } else if (Math.abs(input) < 16) {
+            input = input * 60;
+        }
+        if (!this._isUTC && keepLocalTime) {
+            localAdjust = getDateOffset(this);
+        }
+        this._offset = input;
+        this._isUTC = true;
+        if (localAdjust != null) {
+            this.add(localAdjust, 'm');
+        }
+        if (offset !== input) {
+            if (!keepLocalTime || this._changeInProgress) {
+                addSubtract(this, createDuration(input - offset, 'm'), 1, false);
+            } else if (!this._changeInProgress) {
+                this._changeInProgress = true;
+                hooks.updateOffset(this, true);
+                this._changeInProgress = null;
+            }
+        }
+        return this;
+    } else {
+        return this._isUTC ? offset : getDateOffset(this);
+    }
+}
+
+function getSetZone (input, keepLocalTime) {
+    if (input != null) {
+        if (typeof input !== 'string') {
+            input = -input;
+        }
+
+        this.utcOffset(input, keepLocalTime);
+
+        return this;
+    } else {
+        return -this.utcOffset();
+    }
+}
+
+function setOffsetToUTC (keepLocalTime) {
+    return this.utcOffset(0, keepLocalTime);
+}
+
+function setOffsetToLocal (keepLocalTime) {
+    if (this._isUTC) {
+        this.utcOffset(0, keepLocalTime);
+        this._isUTC = false;
+
+        if (keepLocalTime) {
+            this.subtract(getDateOffset(this), 'm');
+        }
+    }
+    return this;
+}
+
+function setOffsetToParsedOffset () {
+    if (this._tzm != null) {
+        this.utcOffset(this._tzm);
+    } else if (typeof this._i === 'string') {
+        var tZone = offsetFromString(matchOffset, this._i);
+        if (tZone != null) {
+            this.utcOffset(tZone);
+        }
+        else {
+            this.utcOffset(0, true);
+        }
+    }
+    return this;
+}
+
+function hasAlignedHourOffset (input) {
+    if (!this.isValid()) {
+        return false;
+    }
+    input = input ? createLocal(input).utcOffset() : 0;
+
+    return (this.utcOffset() - input) % 60 === 0;
+}
+
+function isDaylightSavingTime () {
+    return (
+        this.utcOffset() > this.clone().month(0).utcOffset() ||
+        this.utcOffset() > this.clone().month(5).utcOffset()
+    );
+}
+
+function isDaylightSavingTimeShifted () {
+    if (!isUndefined(this._isDSTShifted)) {
+        return this._isDSTShifted;
+    }
+
+    var c = {};
+
+    copyConfig(c, this);
+    c = prepareConfig(c);
+
+    if (c._a) {
+        var other = c._isUTC ? createUTC(c._a) : createLocal(c._a);
+        this._isDSTShifted = this.isValid() &&
+            compareArrays(c._a, other.toArray()) > 0;
+    } else {
+        this._isDSTShifted = false;
+    }
+
+    return this._isDSTShifted;
+}
+
+function isLocal () {
+    return this.isValid() ? !this._isUTC : false;
+}
+
+function isUtcOffset () {
+    return this.isValid() ? this._isUTC : false;
+}
+
+function isUtc () {
+    return this.isValid() ? this._isUTC && this._offset === 0 : false;
+}
+
+// ASP.NET json date format regex
+var aspNetRegex = /^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/;
+
+// from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
+// somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
+// and further modified to allow for strings containing both week and day
+var isoRegex = /^(-)?P(?:(-?[0-9,.]*)Y)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)W)?(?:(-?[0-9,.]*)D)?(?:T(?:(-?[0-9,.]*)H)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)S)?)?$/;
+
+function createDuration (input, key) {
+    var duration = input,
+        // matching against regexp is expensive, do it on demand
+        match = null,
+        sign,
+        ret,
+        diffRes;
+
+    if (isDuration(input)) {
+        duration = {
+            ms : input._milliseconds,
+            d  : input._days,
+            M  : input._months
+        };
+    } else if (isNumber(input)) {
+        duration = {};
+        if (key) {
+            duration[key] = input;
+        } else {
+            duration.milliseconds = input;
+        }
+    } else if (!!(match = aspNetRegex.exec(input))) {
+        sign = (match[1] === '-') ? -1 : 1;
+        duration = {
+            y  : 0,
+            d  : toInt(match[DATE])                         * sign,
+            h  : toInt(match[HOUR])                         * sign,
+            m  : toInt(match[MINUTE])                       * sign,
+            s  : toInt(match[SECOND])                       * sign,
+            ms : toInt(absRound(match[MILLISECOND] * 1000)) * sign // the millisecond decimal point is included in the match
+        };
+    } else if (!!(match = isoRegex.exec(input))) {
+        sign = (match[1] === '-') ? -1 : 1;
+        duration = {
+            y : parseIso(match[2], sign),
+            M : parseIso(match[3], sign),
+            w : parseIso(match[4], sign),
+            d : parseIso(match[5], sign),
+            h : parseIso(match[6], sign),
+            m : parseIso(match[7], sign),
+            s : parseIso(match[8], sign)
+        };
+    } else if (duration == null) {// checks for null or undefined
+        duration = {};
+    } else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) {
+        diffRes = momentsDifference(createLocal(duration.from), createLocal(duration.to));
+
+        duration = {};
+        duration.ms = diffRes.milliseconds;
+        duration.M = diffRes.months;
+    }
+
+    ret = new Duration(duration);
+
+    if (isDuration(input) && hasOwnProp(input, '_locale')) {
+        ret._locale = input._locale;
+    }
+
+    return ret;
+}
+
+createDuration.fn = Duration.prototype;
+
+function parseIso (inp, sign) {
+    // We'd normally use ~~inp for this, but unfortunately it also
+    // converts floats to ints.
+    // inp may be undefined, so careful calling replace on it.
+    var res = inp && parseFloat(inp.replace(',', '.'));
+    // apply sign while we're at it
+    return (isNaN(res) ? 0 : res) * sign;
+}
+
+function positiveMomentsDifference(base, other) {
+    var res = {milliseconds: 0, months: 0};
+
+    res.months = other.month() - base.month() +
+        (other.year() - base.year()) * 12;
+    if (base.clone().add(res.months, 'M').isAfter(other)) {
+        --res.months;
+    }
+
+    res.milliseconds = +other - +(base.clone().add(res.months, 'M'));
+
+    return res;
+}
+
+function momentsDifference(base, other) {
+    var res;
+    if (!(base.isValid() && other.isValid())) {
+        return {milliseconds: 0, months: 0};
+    }
+
+    other = cloneWithOffset(other, base);
+    if (base.isBefore(other)) {
+        res = positiveMomentsDifference(base, other);
+    } else {
+        res = positiveMomentsDifference(other, base);
+        res.milliseconds = -res.milliseconds;
+        res.months = -res.months;
+    }
+
+    return res;
+}
+
+// TODO: remove 'name' arg after deprecation is removed
+function createAdder(direction, name) {
+    return function (val, period) {
+        var dur, tmp;
+        //invert the arguments, but complain about it
+        if (period !== null && !isNaN(+period)) {
+            deprecateSimple(name, 'moment().' + name  + '(period, number) is deprecated. Please use moment().' + name + '(number, period). ' +
+            'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.');
+            tmp = val; val = period; period = tmp;
+        }
+
+        val = typeof val === 'string' ? +val : val;
+        dur = createDuration(val, period);
+        addSubtract(this, dur, direction);
+        return this;
+    };
+}
+
+function addSubtract (mom, duration, isAdding, updateOffset) {
+    var milliseconds = duration._milliseconds,
+        days = absRound(duration._days),
+        months = absRound(duration._months);
+
+    if (!mom.isValid()) {
+        // No op
+        return;
+    }
+
+    updateOffset = updateOffset == null ? true : updateOffset;
+
+    if (milliseconds) {
+        mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding);
+    }
+    if (days) {
+        set$1(mom, 'Date', get(mom, 'Date') + days * isAdding);
+    }
+    if (months) {
+        setMonth(mom, get(mom, 'Month') + months * isAdding);
+    }
+    if (updateOffset) {
+        hooks.updateOffset(mom, days || months);
+    }
+}
+
+var add      = createAdder(1, 'add');
+var subtract = createAdder(-1, 'subtract');
+
+function getCalendarFormat(myMoment, now) {
+    var diff = myMoment.diff(now, 'days', true);
+    return diff < -6 ? 'sameElse' :
+            diff < -1 ? 'lastWeek' :
+            diff < 0 ? 'lastDay' :
+            diff < 1 ? 'sameDay' :
+            diff < 2 ? 'nextDay' :
+            diff < 7 ? 'nextWeek' : 'sameElse';
+}
+
+function calendar$1 (time, formats) {
+    // We want to compare the start of today, vs this.
+    // Getting start-of-today depends on whether we're local/utc/offset or not.
+    var now = time || createLocal(),
+        sod = cloneWithOffset(now, this).startOf('day'),
+        format = hooks.calendarFormat(this, sod) || 'sameElse';
+
+    var output = formats && (isFunction(formats[format]) ? formats[format].call(this, now) : formats[format]);
+
+    return this.format(output || this.localeData().calendar(format, this, createLocal(now)));
+}
+
+function clone () {
+    return new Moment(this);
+}
+
+function isAfter (input, units) {
+    var localInput = isMoment(input) ? input : createLocal(input);
+    if (!(this.isValid() && localInput.isValid())) {
+        return false;
+    }
+    units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
+    if (units === 'millisecond') {
+        return this.valueOf() > localInput.valueOf();
+    } else {
+        return localInput.valueOf() < this.clone().startOf(units).valueOf();
+    }
+}
+
+function isBefore (input, units) {
+    var localInput = isMoment(input) ? input : createLocal(input);
+    if (!(this.isValid() && localInput.isValid())) {
+        return false;
+    }
+    units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
+    if (units === 'millisecond') {
+        return this.valueOf() < localInput.valueOf();
+    } else {
+        return this.clone().endOf(units).valueOf() < localInput.valueOf();
+    }
+}
+
+function isBetween (from, to, units, inclusivity) {
+    inclusivity = inclusivity || '()';
+    return (inclusivity[0] === '(' ? this.isAfter(from, units) : !this.isBefore(from, units)) &&
+        (inclusivity[1] === ')' ? this.isBefore(to, units) : !this.isAfter(to, units));
+}
+
+function isSame (input, units) {
+    var localInput = isMoment(input) ? input : createLocal(input),
+        inputMs;
+    if (!(this.isValid() && localInput.isValid())) {
+        return false;
+    }
+    units = normalizeUnits(units || 'millisecond');
+    if (units === 'millisecond') {
+        return this.valueOf() === localInput.valueOf();
+    } else {
+        inputMs = localInput.valueOf();
+        return this.clone().startOf(units).valueOf() <= inputMs && inputMs <= this.clone().endOf(units).valueOf();
+    }
+}
+
+function isSameOrAfter (input, units) {
+    return this.isSame(input, units) || this.isAfter(input,units);
+}
+
+function isSameOrBefore (input, units) {
+    return this.isSame(input, units) || this.isBefore(input,units);
+}
+
+function diff (input, units, asFloat) {
+    var that,
+        zoneDelta,
+        delta, output;
+
+    if (!this.isValid()) {
+        return NaN;
+    }
+
+    that = cloneWithOffset(input, this);
+
+    if (!that.isValid()) {
+        return NaN;
+    }
+
+    zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4;
+
+    units = normalizeUnits(units);
+
+    if (units === 'year' || units === 'month' || units === 'quarter') {
+        output = monthDiff(this, that);
+        if (units === 'quarter') {
+            output = output / 3;
+        } else if (units === 'year') {
+            output = output / 12;
+        }
+    } else {
+        delta = this - that;
+        output = units === 'second' ? delta / 1e3 : // 1000
+            units === 'minute' ? delta / 6e4 : // 1000 * 60
+            units === 'hour' ? delta / 36e5 : // 1000 * 60 * 60
+            units === 'day' ? (delta - zoneDelta) / 864e5 : // 1000 * 60 * 60 * 24, negate dst
+            units === 'week' ? (delta - zoneDelta) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst
+            delta;
+    }
+    return asFloat ? output : absFloor(output);
+}
+
+function monthDiff (a, b) {
+    // difference in months
+    var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()),
+        // b is in (anchor - 1 month, anchor + 1 month)
+        anchor = a.clone().add(wholeMonthDiff, 'months'),
+        anchor2, adjust;
+
+    if (b - anchor < 0) {
+        anchor2 = a.clone().add(wholeMonthDiff - 1, 'months');
+        // linear across the month
+        adjust = (b - anchor) / (anchor - anchor2);
+    } else {
+        anchor2 = a.clone().add(wholeMonthDiff + 1, 'months');
+        // linear across the month
+        adjust = (b - anchor) / (anchor2 - anchor);
+    }
+
+    //check for negative zero, return zero if negative zero
+    return -(wholeMonthDiff + adjust) || 0;
+}
+
+hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ';
+hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]';
+
+function toString () {
+    return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
+}
+
+function toISOString () {
+    var m = this.clone().utc();
+    if (0 < m.year() && m.year() <= 9999) {
+        if (isFunction(Date.prototype.toISOString)) {
+            // native implementation is ~50x faster, use it when we can
+            return this.toDate().toISOString();
+        } else {
+            return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
+        }
+    } else {
+        return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
+    }
+}
+
+/**
+ * Return a human readable representation of a moment that can
+ * also be evaluated to get a new moment which is the same
+ *
+ * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects
+ */
+function inspect () {
+    if (!this.isValid()) {
+        return 'moment.invalid(/* ' + this._i + ' */)';
+    }
+    var func = 'moment';
+    var zone = '';
+    if (!this.isLocal()) {
+        func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone';
+        zone = 'Z';
+    }
+    var prefix = '[' + func + '("]';
+    var year = (0 < this.year() && this.year() <= 9999) ? 'YYYY' : 'YYYYYY';
+    var datetime = '-MM-DD[T]HH:mm:ss.SSS';
+    var suffix = zone + '[")]';
+
+    return this.format(prefix + year + datetime + suffix);
+}
+
+function format (inputString) {
+    if (!inputString) {
+        inputString = this.isUtc() ? hooks.defaultFormatUtc : hooks.defaultFormat;
+    }
+    var output = formatMoment(this, inputString);
+    return this.localeData().postformat(output);
+}
+
+function from (time, withoutSuffix) {
+    if (this.isValid() &&
+            ((isMoment(time) && time.isValid()) ||
+             createLocal(time).isValid())) {
+        return createDuration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix);
+    } else {
+        return this.localeData().invalidDate();
+    }
+}
+
+function fromNow (withoutSuffix) {
+    return this.from(createLocal(), withoutSuffix);
+}
+
+function to (time, withoutSuffix) {
+    if (this.isValid() &&
+            ((isMoment(time) && time.isValid()) ||
+             createLocal(time).isValid())) {
+        return createDuration({from: this, to: time}).locale(this.locale()).humanize(!withoutSuffix);
+    } else {
+        return this.localeData().invalidDate();
+    }
+}
+
+function toNow (withoutSuffix) {
+    return this.to(createLocal(), withoutSuffix);
+}
+
+// If passed a locale key, it will set the locale for this
+// instance.  Otherwise, it will return the locale configuration
+// variables for this instance.
+function locale (key) {
+    var newLocaleData;
+
+    if (key === undefined) {
+        return this._locale._abbr;
+    } else {
+        newLocaleData = getLocale(key);
+        if (newLocaleData != null) {
+            this._locale = newLocaleData;
+        }
+        return this;
+    }
+}
+
+var lang = deprecate(
+    'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.',
+    function (key) {
+        if (key === undefined) {
+            return this.localeData();
+        } else {
+            return this.locale(key);
+        }
+    }
+);
+
+function localeData () {
+    return this._locale;
+}
+
+function startOf (units) {
+    units = normalizeUnits(units);
+    // the following switch intentionally omits break keywords
+    // to utilize falling through the cases.
+    switch (units) {
+        case 'year':
+            this.month(0);
+            /* falls through */
+        case 'quarter':
+        case 'month':
+            this.date(1);
+            /* falls through */
+        case 'week':
+        case 'isoWeek':
+        case 'day':
+        case 'date':
+            this.hours(0);
+            /* falls through */
+        case 'hour':
+            this.minutes(0);
+            /* falls through */
+        case 'minute':
+            this.seconds(0);
+            /* falls through */
+        case 'second':
+            this.milliseconds(0);
+    }
+
+    // weeks are a special case
+    if (units === 'week') {
+        this.weekday(0);
+    }
+    if (units === 'isoWeek') {
+        this.isoWeekday(1);
+    }
+
+    // quarters are also special
+    if (units === 'quarter') {
+        this.month(Math.floor(this.month() / 3) * 3);
+    }
+
+    return this;
+}
+
+function endOf (units) {
+    units = normalizeUnits(units);
+    if (units === undefined || units === 'millisecond') {
+        return this;
+    }
+
+    // 'date' is an alias for 'day', so it should be considered as such.
+    if (units === 'date') {
+        units = 'day';
+    }
+
+    return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms');
+}
+
+function valueOf () {
+    return this._d.valueOf() - ((this._offset || 0) * 60000);
+}
+
+function unix () {
+    return Math.floor(this.valueOf() / 1000);
+}
+
+function toDate () {
+    return new Date(this.valueOf());
+}
+
+function toArray () {
+    var m = this;
+    return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()];
+}
+
+function toObject () {
+    var m = this;
+    return {
+        years: m.year(),
+        months: m.month(),
+        date: m.date(),
+        hours: m.hours(),
+        minutes: m.minutes(),
+        seconds: m.seconds(),
+        milliseconds: m.milliseconds()
+    };
+}
+
+function toJSON () {
+    // new Date(NaN).toJSON() === null
+    return this.isValid() ? this.toISOString() : null;
+}
+
+function isValid$1 () {
+    return isValid(this);
+}
+
+function parsingFlags () {
+    return extend({}, getParsingFlags(this));
+}
+
+function invalidAt () {
+    return getParsingFlags(this).overflow;
+}
+
+function creationData() {
+    return {
+        input: this._i,
+        format: this._f,
+        locale: this._locale,
+        isUTC: this._isUTC,
+        strict: this._strict
+    };
+}
+
+// FORMATTING
+
+addFormatToken(0, ['gg', 2], 0, function () {
+    return this.weekYear() % 100;
+});
+
+addFormatToken(0, ['GG', 2], 0, function () {
+    return this.isoWeekYear() % 100;
+});
+
+function addWeekYearFormatToken (token, getter) {
+    addFormatToken(0, [token, token.length], 0, getter);
+}
+
+addWeekYearFormatToken('gggg',     'weekYear');
+addWeekYearFormatToken('ggggg',    'weekYear');
+addWeekYearFormatToken('GGGG',  'isoWeekYear');
+addWeekYearFormatToken('GGGGG', 'isoWeekYear');
+
+// ALIASES
+
+addUnitAlias('weekYear', 'gg');
+addUnitAlias('isoWeekYear', 'GG');
+
+// PRIORITY
+
+addUnitPriority('weekYear', 1);
+addUnitPriority('isoWeekYear', 1);
+
+
+// PARSING
+
+addRegexToken('G',      matchSigned);
+addRegexToken('g',      matchSigned);
+addRegexToken('GG',     match1to2, match2);
+addRegexToken('gg',     match1to2, match2);
+addRegexToken('GGGG',   match1to4, match4);
+addRegexToken('gggg',   match1to4, match4);
+addRegexToken('GGGGG',  match1to6, match6);
+addRegexToken('ggggg',  match1to6, match6);
+
+addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (input, week, config, token) {
+    week[token.substr(0, 2)] = toInt(input);
+});
+
+addWeekParseToken(['gg', 'GG'], function (input, week, config, token) {
+    week[token] = hooks.parseTwoDigitYear(input);
+});
+
+// MOMENTS
+
+function getSetWeekYear (input) {
+    return getSetWeekYearHelper.call(this,
+            input,
+            this.week(),
+            this.weekday(),
+            this.localeData()._week.dow,
+            this.localeData()._week.doy);
+}
+
+function getSetISOWeekYear (input) {
+    return getSetWeekYearHelper.call(this,
+            input, this.isoWeek(), this.isoWeekday(), 1, 4);
+}
+
+function getISOWeeksInYear () {
+    return weeksInYear(this.year(), 1, 4);
+}
+
+function getWeeksInYear () {
+    var weekInfo = this.localeData()._week;
+    return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
+}
+
+function getSetWeekYearHelper(input, week, weekday, dow, doy) {
+    var weeksTarget;
+    if (input == null) {
+        return weekOfYear(this, dow, doy).year;
+    } else {
+        weeksTarget = weeksInYear(input, dow, doy);
+        if (week > weeksTarget) {
+            week = weeksTarget;
+        }
+        return setWeekAll.call(this, input, week, weekday, dow, doy);
+    }
+}
+
+function setWeekAll(weekYear, week, weekday, dow, doy) {
+    var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy),
+        date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear);
+
+    this.year(date.getUTCFullYear());
+    this.month(date.getUTCMonth());
+    this.date(date.getUTCDate());
+    return this;
+}
+
+// FORMATTING
+
+addFormatToken('Q', 0, 'Qo', 'quarter');
+
+// ALIASES
+
+addUnitAlias('quarter', 'Q');
+
+// PRIORITY
+
+addUnitPriority('quarter', 7);
+
+// PARSING
+
+addRegexToken('Q', match1);
+addParseToken('Q', function (input, array) {
+    array[MONTH] = (toInt(input) - 1) * 3;
+});
+
+// MOMENTS
+
+function getSetQuarter (input) {
+    return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);
+}
+
+// FORMATTING
+
+addFormatToken('D', ['DD', 2], 'Do', 'date');
+
+// ALIASES
+
+addUnitAlias('date', 'D');
+
+// PRIOROITY
+addUnitPriority('date', 9);
+
+// PARSING
+
+addRegexToken('D',  match1to2);
+addRegexToken('DD', match1to2, match2);
+addRegexToken('Do', function (isStrict, locale) {
+    return isStrict ? locale._ordinalParse : locale._ordinalParseLenient;
+});
+
+addParseToken(['D', 'DD'], DATE);
+addParseToken('Do', function (input, array) {
+    array[DATE] = toInt(input.match(match1to2)[0], 10);
+});
+
+// MOMENTS
+
+var getSetDayOfMonth = makeGetSet('Date', true);
+
+// FORMATTING
+
+addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear');
+
+// ALIASES
+
+addUnitAlias('dayOfYear', 'DDD');
+
+// PRIORITY
+addUnitPriority('dayOfYear', 4);
+
+// PARSING
+
+addRegexToken('DDD',  match1to3);
+addRegexToken('DDDD', match3);
+addParseToken(['DDD', 'DDDD'], function (input, array, config) {
+    config._dayOfYear = toInt(input);
+});
+
+// HELPERS
+
+// MOMENTS
+
+function getSetDayOfYear (input) {
+    var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1;
+    return input == null ? dayOfYear : this.add((input - dayOfYear), 'd');
+}
+
+// FORMATTING
+
+addFormatToken('m', ['mm', 2], 0, 'minute');
+
+// ALIASES
+
+addUnitAlias('minute', 'm');
+
+// PRIORITY
+
+addUnitPriority('minute', 14);
+
+// PARSING
+
+addRegexToken('m',  match1to2);
+addRegexToken('mm', match1to2, match2);
+addParseToken(['m', 'mm'], MINUTE);
+
+// MOMENTS
+
+var getSetMinute = makeGetSet('Minutes', false);
+
+// FORMATTING
+
+addFormatToken('s', ['ss', 2], 0, 'second');
+
+// ALIASES
+
+addUnitAlias('second', 's');
+
+// PRIORITY
+
+addUnitPriority('second', 15);
+
+// PARSING
+
+addRegexToken('s',  match1to2);
+addRegexToken('ss', match1to2, match2);
+addParseToken(['s', 'ss'], SECOND);
+
+// MOMENTS
+
+var getSetSecond = makeGetSet('Seconds', false);
+
+// FORMATTING
+
+addFormatToken('S', 0, 0, function () {
+    return ~~(this.millisecond() / 100);
+});
+
+addFormatToken(0, ['SS', 2], 0, function () {
+    return ~~(this.millisecond() / 10);
+});
+
+addFormatToken(0, ['SSS', 3], 0, 'millisecond');
+addFormatToken(0, ['SSSS', 4], 0, function () {
+    return this.millisecond() * 10;
+});
+addFormatToken(0, ['SSSSS', 5], 0, function () {
+    return this.millisecond() * 100;
+});
+addFormatToken(0, ['SSSSSS', 6], 0, function () {
+    return this.millisecond() * 1000;
+});
+addFormatToken(0, ['SSSSSSS', 7], 0, function () {
+    return this.millisecond() * 10000;
+});
+addFormatToken(0, ['SSSSSSSS', 8], 0, function () {
+    return this.millisecond() * 100000;
+});
+addFormatToken(0, ['SSSSSSSSS', 9], 0, function () {
+    return this.millisecond() * 1000000;
+});
+
+
+// ALIASES
+
+addUnitAlias('millisecond', 'ms');
+
+// PRIORITY
+
+addUnitPriority('millisecond', 16);
+
+// PARSING
+
+addRegexToken('S',    match1to3, match1);
+addRegexToken('SS',   match1to3, match2);
+addRegexToken('SSS',  match1to3, match3);
+
+var token;
+for (token = 'SSSS'; token.length <= 9; token += 'S') {
+    addRegexToken(token, matchUnsigned);
+}
+
+function parseMs(input, array) {
+    array[MILLISECOND] = toInt(('0.' + input) * 1000);
+}
+
+for (token = 'S'; token.length <= 9; token += 'S') {
+    addParseToken(token, parseMs);
+}
+// MOMENTS
+
+var getSetMillisecond = makeGetSet('Milliseconds', false);
+
+// FORMATTING
+
+addFormatToken('z',  0, 0, 'zoneAbbr');
+addFormatToken('zz', 0, 0, 'zoneName');
+
+// MOMENTS
+
+function getZoneAbbr () {
+    return this._isUTC ? 'UTC' : '';
+}
+
+function getZoneName () {
+    return this._isUTC ? 'Coordinated Universal Time' : '';
+}
+
+var proto = Moment.prototype;
+
+proto.add               = add;
+proto.calendar          = calendar$1;
+proto.clone             = clone;
+proto.diff              = diff;
+proto.endOf             = endOf;
+proto.format            = format;
+proto.from              = from;
+proto.fromNow           = fromNow;
+proto.to                = to;
+proto.toNow             = toNow;
+proto.get               = stringGet;
+proto.invalidAt         = invalidAt;
+proto.isAfter           = isAfter;
+proto.isBefore          = isBefore;
+proto.isBetween         = isBetween;
+proto.isSame            = isSame;
+proto.isSameOrAfter     = isSameOrAfter;
+proto.isSameOrBefore    = isSameOrBefore;
+proto.isValid           = isValid$1;
+proto.lang              = lang;
+proto.locale            = locale;
+proto.localeData        = localeData;
+proto.max               = prototypeMax;
+proto.min               = prototypeMin;
+proto.parsingFlags      = parsingFlags;
+proto.set               = stringSet;
+proto.startOf           = startOf;
+proto.subtract          = subtract;
+proto.toArray           = toArray;
+proto.toObject          = toObject;
+proto.toDate            = toDate;
+proto.toISOString       = toISOString;
+proto.inspect           = inspect;
+proto.toJSON            = toJSON;
+proto.toString          = toString;
+proto.unix              = unix;
+proto.valueOf           = valueOf;
+proto.creationData      = creationData;
+
+// Year
+proto.year       = getSetYear;
+proto.isLeapYear = getIsLeapYear;
+
+// Week Year
+proto.weekYear    = getSetWeekYear;
+proto.isoWeekYear = getSetISOWeekYear;
+
+// Quarter
+proto.quarter = proto.quarters = getSetQuarter;
+
+// Month
+proto.month       = getSetMonth;
+proto.daysInMonth = getDaysInMonth;
+
+// Week
+proto.week           = proto.weeks        = getSetWeek;
+proto.isoWeek        = proto.isoWeeks     = getSetISOWeek;
+proto.weeksInYear    = getWeeksInYear;
+proto.isoWeeksInYear = getISOWeeksInYear;
+
+// Day
+proto.date       = getSetDayOfMonth;
+proto.day        = proto.days             = getSetDayOfWeek;
+proto.weekday    = getSetLocaleDayOfWeek;
+proto.isoWeekday = getSetISODayOfWeek;
+proto.dayOfYear  = getSetDayOfYear;
+
+// Hour
+proto.hour = proto.hours = getSetHour;
+
+// Minute
+proto.minute = proto.minutes = getSetMinute;
+
+// Second
+proto.second = proto.seconds = getSetSecond;
+
+// Millisecond
+proto.millisecond = proto.milliseconds = getSetMillisecond;
+
+// Offset
+proto.utcOffset            = getSetOffset;
+proto.utc                  = setOffsetToUTC;
+proto.local                = setOffsetToLocal;
+proto.parseZone            = setOffsetToParsedOffset;
+proto.hasAlignedHourOffset = hasAlignedHourOffset;
+proto.isDST                = isDaylightSavingTime;
+proto.isLocal              = isLocal;
+proto.isUtcOffset          = isUtcOffset;
+proto.isUtc                = isUtc;
+proto.isUTC                = isUtc;
+
+// Timezone
+proto.zoneAbbr = getZoneAbbr;
+proto.zoneName = getZoneName;
+
+// Deprecations
+proto.dates  = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth);
+proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth);
+proto.years  = deprecate('years accessor is deprecated. Use year instead', getSetYear);
+proto.zone   = deprecate('moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/', getSetZone);
+proto.isDSTShifted = deprecate('isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information', isDaylightSavingTimeShifted);
+
+function createUnix (input) {
+    return createLocal(input * 1000);
+}
+
+function createInZone () {
+    return createLocal.apply(null, arguments).parseZone();
+}
+
+function preParsePostFormat (string) {
+    return string;
+}
+
+var proto$1 = Locale.prototype;
+
+proto$1.calendar        = calendar;
+proto$1.longDateFormat  = longDateFormat;
+proto$1.invalidDate     = invalidDate;
+proto$1.ordinal         = ordinal;
+proto$1.preparse        = preParsePostFormat;
+proto$1.postformat      = preParsePostFormat;
+proto$1.relativeTime    = relativeTime;
+proto$1.pastFuture      = pastFuture;
+proto$1.set             = set;
+
+// Month
+proto$1.months            =        localeMonths;
+proto$1.monthsShort       =        localeMonthsShort;
+proto$1.monthsParse       =        localeMonthsParse;
+proto$1.monthsRegex       = monthsRegex;
+proto$1.monthsShortRegex  = monthsShortRegex;
+
+// Week
+proto$1.week = localeWeek;
+proto$1.firstDayOfYear = localeFirstDayOfYear;
+proto$1.firstDayOfWeek = localeFirstDayOfWeek;
+
+// Day of Week
+proto$1.weekdays       =        localeWeekdays;
+proto$1.weekdaysMin    =        localeWeekdaysMin;
+proto$1.weekdaysShort  =        localeWeekdaysShort;
+proto$1.weekdaysParse  =        localeWeekdaysParse;
+
+proto$1.weekdaysRegex       =        weekdaysRegex;
+proto$1.weekdaysShortRegex  =        weekdaysShortRegex;
+proto$1.weekdaysMinRegex    =        weekdaysMinRegex;
+
+// Hours
+proto$1.isPM = localeIsPM;
+proto$1.meridiem = localeMeridiem;
+
+function get$1 (format, index, field, setter) {
+    var locale = getLocale();
+    var utc = createUTC().set(setter, index);
+    return locale[field](utc, format);
+}
+
+function listMonthsImpl (format, index, field) {
+    if (isNumber(format)) {
+        index = format;
+        format = undefined;
+    }
+
+    format = format || '';
+
+    if (index != null) {
+        return get$1(format, index, field, 'month');
+    }
+
+    var i;
+    var out = [];
+    for (i = 0; i < 12; i++) {
+        out[i] = get$1(format, i, field, 'month');
+    }
+    return out;
+}
+
+// ()
+// (5)
+// (fmt, 5)
+// (fmt)
+// (true)
+// (true, 5)
+// (true, fmt, 5)
+// (true, fmt)
+function listWeekdaysImpl (localeSorted, format, index, field) {
+    if (typeof localeSorted === 'boolean') {
+        if (isNumber(format)) {
+            index = format;
+            format = undefined;
+        }
+
+        format = format || '';
+    } else {
+        format = localeSorted;
+        index = format;
+        localeSorted = false;
+
+        if (isNumber(format)) {
+            index = format;
+            format = undefined;
+        }
+
+        format = format || '';
+    }
+
+    var locale = getLocale(),
+        shift = localeSorted ? locale._week.dow : 0;
+
+    if (index != null) {
+        return get$1(format, (index + shift) % 7, field, 'day');
+    }
+
+    var i;
+    var out = [];
+    for (i = 0; i < 7; i++) {
+        out[i] = get$1(format, (i + shift) % 7, field, 'day');
+    }
+    return out;
+}
+
+function listMonths (format, index) {
+    return listMonthsImpl(format, index, 'months');
+}
+
+function listMonthsShort (format, index) {
+    return listMonthsImpl(format, index, 'monthsShort');
+}
+
+function listWeekdays (localeSorted, format, index) {
+    return listWeekdaysImpl(localeSorted, format, index, 'weekdays');
+}
+
+function listWeekdaysShort (localeSorted, format, index) {
+    return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort');
+}
+
+function listWeekdaysMin (localeSorted, format, index) {
+    return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin');
+}
+
+getSetGlobalLocale('en', {
+    ordinalParse: /\d{1,2}(th|st|nd|rd)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (toInt(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    }
+});
+
+// Side effect imports
+hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', getSetGlobalLocale);
+hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', getLocale);
+
+var mathAbs = Math.abs;
+
+function abs () {
+    var data           = this._data;
+
+    this._milliseconds = mathAbs(this._milliseconds);
+    this._days         = mathAbs(this._days);
+    this._months       = mathAbs(this._months);
+
+    data.milliseconds  = mathAbs(data.milliseconds);
+    data.seconds       = mathAbs(data.seconds);
+    data.minutes       = mathAbs(data.minutes);
+    data.hours         = mathAbs(data.hours);
+    data.months        = mathAbs(data.months);
+    data.years         = mathAbs(data.years);
+
+    return this;
+}
+
+function addSubtract$1 (duration, input, value, direction) {
+    var other = createDuration(input, value);
+
+    duration._milliseconds += direction * other._milliseconds;
+    duration._days         += direction * other._days;
+    duration._months       += direction * other._months;
+
+    return duration._bubble();
+}
+
+// supports only 2.0-style add(1, 's') or add(duration)
+function add$1 (input, value) {
+    return addSubtract$1(this, input, value, 1);
+}
+
+// supports only 2.0-style subtract(1, 's') or subtract(duration)
+function subtract$1 (input, value) {
+    return addSubtract$1(this, input, value, -1);
+}
+
+function absCeil (number) {
+    if (number < 0) {
+        return Math.floor(number);
+    } else {
+        return Math.ceil(number);
+    }
+}
+
+function bubble () {
+    var milliseconds = this._milliseconds;
+    var days         = this._days;
+    var months       = this._months;
+    var data         = this._data;
+    var seconds, minutes, hours, years, monthsFromDays;
+
+    // if we have a mix of positive and negative values, bubble down first
+    // check: https://github.com/moment/moment/issues/2166
+    if (!((milliseconds >= 0 && days >= 0 && months >= 0) ||
+            (milliseconds <= 0 && days <= 0 && months <= 0))) {
+        milliseconds += absCeil(monthsToDays(months) + days) * 864e5;
+        days = 0;
+        months = 0;
+    }
+
+    // The following code bubbles up values, see the tests for
+    // examples of what that means.
+    data.milliseconds = milliseconds % 1000;
+
+    seconds           = absFloor(milliseconds / 1000);
+    data.seconds      = seconds % 60;
+
+    minutes           = absFloor(seconds / 60);
+    data.minutes      = minutes % 60;
+
+    hours             = absFloor(minutes / 60);
+    data.hours        = hours % 24;
+
+    days += absFloor(hours / 24);
+
+    // convert days to months
+    monthsFromDays = absFloor(daysToMonths(days));
+    months += monthsFromDays;
+    days -= absCeil(monthsToDays(monthsFromDays));
+
+    // 12 months -> 1 year
+    years = absFloor(months / 12);
+    months %= 12;
+
+    data.days   = days;
+    data.months = months;
+    data.years  = years;
+
+    return this;
+}
+
+function daysToMonths (days) {
+    // 400 years have 146097 days (taking into account leap year rules)
+    // 400 years have 12 months === 4800
+    return days * 4800 / 146097;
+}
+
+function monthsToDays (months) {
+    // the reverse of daysToMonths
+    return months * 146097 / 4800;
+}
+
+function as (units) {
+    var days;
+    var months;
+    var milliseconds = this._milliseconds;
+
+    units = normalizeUnits(units);
+
+    if (units === 'month' || units === 'year') {
+        days   = this._days   + milliseconds / 864e5;
+        months = this._months + daysToMonths(days);
+        return units === 'month' ? months : months / 12;
+    } else {
+        // handle milliseconds separately because of floating point math errors (issue #1867)
+        days = this._days + Math.round(monthsToDays(this._months));
+        switch (units) {
+            case 'week'   : return days / 7     + milliseconds / 6048e5;
+            case 'day'    : return days         + milliseconds / 864e5;
+            case 'hour'   : return days * 24    + milliseconds / 36e5;
+            case 'minute' : return days * 1440  + milliseconds / 6e4;
+            case 'second' : return days * 86400 + milliseconds / 1000;
+            // Math.floor prevents floating point math errors here
+            case 'millisecond': return Math.floor(days * 864e5) + milliseconds;
+            default: throw new Error('Unknown unit ' + units);
+        }
+    }
+}
+
+// TODO: Use this.as('ms')?
+function valueOf$1 () {
+    return (
+        this._milliseconds +
+        this._days * 864e5 +
+        (this._months % 12) * 2592e6 +
+        toInt(this._months / 12) * 31536e6
+    );
+}
+
+function makeAs (alias) {
+    return function () {
+        return this.as(alias);
+    };
+}
+
+var asMilliseconds = makeAs('ms');
+var asSeconds      = makeAs('s');
+var asMinutes      = makeAs('m');
+var asHours        = makeAs('h');
+var asDays         = makeAs('d');
+var asWeeks        = makeAs('w');
+var asMonths       = makeAs('M');
+var asYears        = makeAs('y');
+
+function get$2 (units) {
+    units = normalizeUnits(units);
+    return this[units + 's']();
+}
+
+function makeGetter(name) {
+    return function () {
+        return this._data[name];
+    };
+}
+
+var milliseconds = makeGetter('milliseconds');
+var seconds      = makeGetter('seconds');
+var minutes      = makeGetter('minutes');
+var hours        = makeGetter('hours');
+var days         = makeGetter('days');
+var months       = makeGetter('months');
+var years        = makeGetter('years');
+
+function weeks () {
+    return absFloor(this.days() / 7);
+}
+
+var round = Math.round;
+var thresholds = {
+    s: 45,  // seconds to minute
+    m: 45,  // minutes to hour
+    h: 22,  // hours to day
+    d: 26,  // days to month
+    M: 11   // months to year
+};
+
+// helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
+function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {
+    return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
+}
+
+function relativeTime$1 (posNegDuration, withoutSuffix, locale) {
+    var duration = createDuration(posNegDuration).abs();
+    var seconds  = round(duration.as('s'));
+    var minutes  = round(duration.as('m'));
+    var hours    = round(duration.as('h'));
+    var days     = round(duration.as('d'));
+    var months   = round(duration.as('M'));
+    var years    = round(duration.as('y'));
+
+    var a = seconds < thresholds.s && ['s', seconds]  ||
+            minutes <= 1           && ['m']           ||
+            minutes < thresholds.m && ['mm', minutes] ||
+            hours   <= 1           && ['h']           ||
+            hours   < thresholds.h && ['hh', hours]   ||
+            days    <= 1           && ['d']           ||
+            days    < thresholds.d && ['dd', days]    ||
+            months  <= 1           && ['M']           ||
+            months  < thresholds.M && ['MM', months]  ||
+            years   <= 1           && ['y']           || ['yy', years];
+
+    a[2] = withoutSuffix;
+    a[3] = +posNegDuration > 0;
+    a[4] = locale;
+    return substituteTimeAgo.apply(null, a);
+}
+
+// This function allows you to set the rounding function for relative time strings
+function getSetRelativeTimeRounding (roundingFunction) {
+    if (roundingFunction === undefined) {
+        return round;
+    }
+    if (typeof(roundingFunction) === 'function') {
+        round = roundingFunction;
+        return true;
+    }
+    return false;
+}
+
+// This function allows you to set a threshold for relative time strings
+function getSetRelativeTimeThreshold (threshold, limit) {
+    if (thresholds[threshold] === undefined) {
+        return false;
+    }
+    if (limit === undefined) {
+        return thresholds[threshold];
+    }
+    thresholds[threshold] = limit;
+    return true;
+}
+
+function humanize (withSuffix) {
+    var locale = this.localeData();
+    var output = relativeTime$1(this, !withSuffix, locale);
+
+    if (withSuffix) {
+        output = locale.pastFuture(+this, output);
+    }
+
+    return locale.postformat(output);
+}
+
+var abs$1 = Math.abs;
+
+function toISOString$1() {
+    // for ISO strings we do not use the normal bubbling rules:
+    //  * milliseconds bubble up until they become hours
+    //  * days do not bubble at all
+    //  * months bubble up until they become years
+    // This is because there is no context-free conversion between hours and days
+    // (think of clock changes)
+    // and also not between days and months (28-31 days per month)
+    var seconds = abs$1(this._milliseconds) / 1000;
+    var days         = abs$1(this._days);
+    var months       = abs$1(this._months);
+    var minutes, hours, years;
+
+    // 3600 seconds -> 60 minutes -> 1 hour
+    minutes           = absFloor(seconds / 60);
+    hours             = absFloor(minutes / 60);
+    seconds %= 60;
+    minutes %= 60;
+
+    // 12 months -> 1 year
+    years  = absFloor(months / 12);
+    months %= 12;
+
+
+    // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
+    var Y = years;
+    var M = months;
+    var D = days;
+    var h = hours;
+    var m = minutes;
+    var s = seconds;
+    var total = this.asSeconds();
+
+    if (!total) {
+        // this is the same as C#'s (Noda) and python (isodate)...
+        // but not other JS (goog.date)
+        return 'P0D';
+    }
+
+    return (total < 0 ? '-' : '') +
+        'P' +
+        (Y ? Y + 'Y' : '') +
+        (M ? M + 'M' : '') +
+        (D ? D + 'D' : '') +
+        ((h || m || s) ? 'T' : '') +
+        (h ? h + 'H' : '') +
+        (m ? m + 'M' : '') +
+        (s ? s + 'S' : '');
+}
+
+var proto$2 = Duration.prototype;
+
+proto$2.abs            = abs;
+proto$2.add            = add$1;
+proto$2.subtract       = subtract$1;
+proto$2.as             = as;
+proto$2.asMilliseconds = asMilliseconds;
+proto$2.asSeconds      = asSeconds;
+proto$2.asMinutes      = asMinutes;
+proto$2.asHours        = asHours;
+proto$2.asDays         = asDays;
+proto$2.asWeeks        = asWeeks;
+proto$2.asMonths       = asMonths;
+proto$2.asYears        = asYears;
+proto$2.valueOf        = valueOf$1;
+proto$2._bubble        = bubble;
+proto$2.get            = get$2;
+proto$2.milliseconds   = milliseconds;
+proto$2.seconds        = seconds;
+proto$2.minutes        = minutes;
+proto$2.hours          = hours;
+proto$2.days           = days;
+proto$2.weeks          = weeks;
+proto$2.months         = months;
+proto$2.years          = years;
+proto$2.humanize       = humanize;
+proto$2.toISOString    = toISOString$1;
+proto$2.toString       = toISOString$1;
+proto$2.toJSON         = toISOString$1;
+proto$2.locale         = locale;
+proto$2.localeData     = localeData;
+
+// Deprecations
+proto$2.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', toISOString$1);
+proto$2.lang = lang;
+
+// Side effect imports
+
+// FORMATTING
+
+addFormatToken('X', 0, 0, 'unix');
+addFormatToken('x', 0, 0, 'valueOf');
+
+// PARSING
+
+addRegexToken('x', matchSigned);
+addRegexToken('X', matchTimestamp);
+addParseToken('X', function (input, array, config) {
+    config._d = new Date(parseFloat(input, 10) * 1000);
+});
+addParseToken('x', function (input, array, config) {
+    config._d = new Date(toInt(input));
+});
+
+// Side effect imports
+
+
+hooks.version = '2.16.0';
+
+setHookCallback(createLocal);
+
+hooks.fn                    = proto;
+hooks.min                   = min;
+hooks.max                   = max;
+hooks.now                   = now;
+hooks.utc                   = createUTC;
+hooks.unix                  = createUnix;
+hooks.months                = listMonths;
+hooks.isDate                = isDate;
+hooks.locale                = getSetGlobalLocale;
+hooks.invalid               = createInvalid;
+hooks.duration              = createDuration;
+hooks.isMoment              = isMoment;
+hooks.weekdays              = listWeekdays;
+hooks.parseZone             = createInZone;
+hooks.localeData            = getLocale;
+hooks.isDuration            = isDuration;
+hooks.monthsShort           = listMonthsShort;
+hooks.weekdaysMin           = listWeekdaysMin;
+hooks.defineLocale          = defineLocale;
+hooks.updateLocale          = updateLocale;
+hooks.locales               = listLocales;
+hooks.weekdaysShort         = listWeekdaysShort;
+hooks.normalizeUnits        = normalizeUnits;
+hooks.relativeTimeRounding = getSetRelativeTimeRounding;
+hooks.relativeTimeThreshold = getSetRelativeTimeThreshold;
+hooks.calendarFormat        = getCalendarFormat;
+hooks.prototype             = proto;
+
+return hooks;
+
+})));
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/package.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/package.js
new file mode 100644
index 0000000000000000000000000000000000000000..aba8d502e95c9b5d5b8838b67cd60db20c90dfd3
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/package.js
@@ -0,0 +1,11 @@
+var profile = {
+    resourceTags: {
+        ignore: function(filename, mid){
+            // only include moment/moment
+            return mid != "moment/moment";
+        },
+        amd: function(filename, mid){
+            return /\.js$/.test(filename);
+        }
+    }
+};
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/package.json b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..4871eb9ecaa941d14bdf6f0e04c6471487a931c2
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/package.json
@@ -0,0 +1,162 @@
+{
+  "_args": [
+    [
+      {
+        "raw": "moment@https://registry.npmjs.org/moment/-/moment-2.16.0.tgz",
+        "scope": null,
+        "escapedName": "moment",
+        "name": "moment",
+        "rawSpec": "https://registry.npmjs.org/moment/-/moment-2.16.0.tgz",
+        "spec": "https://registry.npmjs.org/moment/-/moment-2.16.0.tgz",
+        "type": "remote"
+      },
+      "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin"
+    ]
+  ],
+  "_from": "moment@>=2.0.0 <3.0.0",
+  "_id": "moment@2.16.0",
+  "_inCache": true,
+  "_location": "/firebase-admin/moment",
+  "_phantomChildren": {},
+  "_requested": {
+    "raw": "moment@https://registry.npmjs.org/moment/-/moment-2.16.0.tgz",
+    "scope": null,
+    "escapedName": "moment",
+    "name": "moment",
+    "rawSpec": "https://registry.npmjs.org/moment/-/moment-2.16.0.tgz",
+    "spec": "https://registry.npmjs.org/moment/-/moment-2.16.0.tgz",
+    "type": "remote"
+  },
+  "_requiredBy": [
+    "/firebase-admin",
+    "/firebase-admin/joi"
+  ],
+  "_resolved": "https://registry.npmjs.org/moment/-/moment-2.16.0.tgz",
+  "_shasum": "f38f2c97c9889b0ee18fc6cc392e1e443ad2da8e",
+  "_shrinkwrap": null,
+  "_spec": "moment@https://registry.npmjs.org/moment/-/moment-2.16.0.tgz",
+  "_where": "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin",
+  "author": {
+    "name": "Iskren Ivov Chernev",
+    "email": "iskren.chernev@gmail.com",
+    "url": "https://github.com/ichernev"
+  },
+  "bugs": {
+    "url": "https://github.com/moment/moment/issues"
+  },
+  "contributors": [
+    {
+      "name": "Tim Wood",
+      "email": "washwithcare@gmail.com",
+      "url": "http://timwoodcreates.com/"
+    },
+    {
+      "name": "Rocky Meza",
+      "url": "http://rockymeza.com"
+    },
+    {
+      "name": "Matt Johnson",
+      "email": "mj1856@hotmail.com",
+      "url": "http://codeofmatt.com"
+    },
+    {
+      "name": "Isaac Cambron",
+      "email": "isaac@isaaccambron.com",
+      "url": "http://isaaccambron.com"
+    },
+    {
+      "name": "Andre Polykanine",
+      "email": "andre@oire.org",
+      "url": "https://github.com/oire"
+    }
+  ],
+  "dependencies": {},
+  "description": "Parse, validate, manipulate, and display dates",
+  "devDependencies": {
+    "benchmark": "latest",
+    "coveralls": "^2.11.2",
+    "es6-promise": "latest",
+    "grunt": "~0.4",
+    "grunt-benchmark": "latest",
+    "grunt-cli": "latest",
+    "grunt-contrib-clean": "latest",
+    "grunt-contrib-concat": "latest",
+    "grunt-contrib-copy": "latest",
+    "grunt-contrib-jshint": "latest",
+    "grunt-contrib-uglify": "latest",
+    "grunt-contrib-watch": "latest",
+    "grunt-env": "latest",
+    "grunt-exec": "latest",
+    "grunt-jscs": "latest",
+    "grunt-karma": "latest",
+    "grunt-nuget": "latest",
+    "grunt-string-replace": "latest",
+    "karma": "latest",
+    "karma-chrome-launcher": "latest",
+    "karma-firefox-launcher": "latest",
+    "karma-qunit": "latest",
+    "karma-sauce-launcher": "latest",
+    "load-grunt-tasks": "latest",
+    "nyc": "^2.1.4",
+    "qunit": "^0.7.5",
+    "qunit-cli": "^0.1.4",
+    "rollup": "latest",
+    "spacejam": "latest",
+    "typescript": "^1.8.10",
+    "uglify-js": "latest"
+  },
+  "dojoBuild": "package.js",
+  "ender": "./ender.js",
+  "engines": {
+    "node": "*"
+  },
+  "homepage": "http://momentjs.com",
+  "jsnext:main": "./src/moment.js",
+  "jspm": {
+    "files": [
+      "moment.js",
+      "moment.d.ts",
+      "locale"
+    ],
+    "map": {
+      "moment": "./moment"
+    },
+    "buildConfig": {
+      "uglify": true
+    }
+  },
+  "keywords": [
+    "moment",
+    "date",
+    "time",
+    "parse",
+    "format",
+    "validate",
+    "i18n",
+    "l10n",
+    "ender"
+  ],
+  "license": "MIT",
+  "main": "./moment.js",
+  "name": "moment",
+  "optionalDependencies": {},
+  "readme": "[![Join the chat at https://gitter.im/moment/moment](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/moment/moment?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)\n\n[![NPM version][npm-version-image]][npm-url] [![NPM downloads][npm-downloads-image]][npm-url] [![MIT License][license-image]][license-url] [![Build Status][travis-image]][travis-url]\n[![Coverage Status](https://coveralls.io/repos/moment/moment/badge.svg?branch=develop)](https://coveralls.io/r/moment/moment?branch=develop)\n\nA lightweight JavaScript date library for parsing, validating, manipulating, and formatting dates.\n\n**[Documentation](http://momentjs.com/docs/)**\n\n## Port to ECMAScript 6 (version 2.10.0)\n\nMoment 2.10.0 does not bring any new features, but the code is now written in\nECMAScript 6 modules and placed inside `src/`. Previously `moment.js`, `locale/*.js` and\n`test/moment/*.js`, `test/locale/*.js` contained the source of the project. Now\nthe source is in `src/`, temporary build (ECMAScript 5) files are placed under\n`build/umd/` (for running tests during development), and the `moment.js` and\n`locale/*.js` files are updated only on release.\n\nIf you want to use a particular revision of the code, make sure to run\n`grunt transpile update-index`, so `moment.js` and `locales/*.js` are synced\nwith `src/*`. We might place that in a commit hook in the future.\n\n## Upgrading to 2.0.0\n\nThere are a number of small backwards incompatible changes with version 2.0.0. [See the full descriptions here](https://gist.github.com/timrwood/e72f2eef320ed9e37c51#backwards-incompatible-changes)\n\n * Changed language ordinal method to return the number + ordinal instead of just the ordinal.\n\n * Changed two digit year parsing cutoff to match strptime.\n\n * Removed `moment#sod` and `moment#eod` in favor of `moment#startOf` and `moment#endOf`.\n\n * Removed `moment.humanizeDuration()` in favor of `moment.duration().humanize()`.\n\n * Removed the lang data objects from the top level namespace.\n\n * Duplicate `Date` passed to `moment()` instead of referencing it.\n\n## [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md)\n\n## [Contributing](https://github.com/moment/moment/blob/develop/CONTRIBUTING.md)\n\nWe're looking for co-maintainers! If you want to become a master of time please\nwrite to [ichernev](https://github.com/ichernev).\n\n## License\n\nMoment.js is freely distributable under the terms of the [MIT license](https://github.com/moment/moment/blob/develop/LICENSE).\n\n[license-image]: http://img.shields.io/badge/license-MIT-blue.svg?style=flat\n[license-url]: LICENSE\n\n[npm-url]: https://npmjs.org/package/moment\n[npm-version-image]: http://img.shields.io/npm/v/moment.svg?style=flat\n[npm-downloads-image]: http://img.shields.io/npm/dm/moment.svg?style=flat\n\n[travis-url]: http://travis-ci.org/moment/moment\n[travis-image]: http://img.shields.io/travis/moment/moment/develop.svg?style=flat\n",
+  "readmeFilename": "README.md",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/moment/moment.git"
+  },
+  "scripts": {
+    "coverage": "nyc npm test && nyc report",
+    "coveralls": "nyc npm test && nyc report --reporter=text-lcov | coveralls",
+    "test": "grunt test"
+  },
+  "spm": {
+    "main": "moment.js",
+    "output": [
+      "locale/*.js"
+    ]
+  },
+  "typings": "./moment.d.ts",
+  "version": "2.16.0"
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/check-overflow.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/check-overflow.js
new file mode 100644
index 0000000000000000000000000000000000000000..41b539fb7338e18325d9d422a56a86baf172c2d6
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/check-overflow.js
@@ -0,0 +1,34 @@
+import { daysInMonth } from '../units/month';
+import { YEAR, MONTH, DATE, HOUR, MINUTE, SECOND, MILLISECOND, WEEK, WEEKDAY } from '../units/constants';
+import getParsingFlags from '../create/parsing-flags';
+
+export default function checkOverflow (m) {
+    var overflow;
+    var a = m._a;
+
+    if (a && getParsingFlags(m).overflow === -2) {
+        overflow =
+            a[MONTH]       < 0 || a[MONTH]       > 11  ? MONTH :
+            a[DATE]        < 1 || a[DATE]        > daysInMonth(a[YEAR], a[MONTH]) ? DATE :
+            a[HOUR]        < 0 || a[HOUR]        > 24 || (a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0)) ? HOUR :
+            a[MINUTE]      < 0 || a[MINUTE]      > 59  ? MINUTE :
+            a[SECOND]      < 0 || a[SECOND]      > 59  ? SECOND :
+            a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND :
+            -1;
+
+        if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
+            overflow = DATE;
+        }
+        if (getParsingFlags(m)._overflowWeeks && overflow === -1) {
+            overflow = WEEK;
+        }
+        if (getParsingFlags(m)._overflowWeekday && overflow === -1) {
+            overflow = WEEKDAY;
+        }
+
+        getParsingFlags(m).overflow = overflow;
+    }
+
+    return m;
+}
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/date-from-array.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/date-from-array.js
new file mode 100644
index 0000000000000000000000000000000000000000..180f55c717f5a04aff83f95c912a50e62bc01ebd
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/date-from-array.js
@@ -0,0 +1,21 @@
+export function createDate (y, m, d, h, M, s, ms) {
+    //can't just apply() to create a date:
+    //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply
+    var date = new Date(y, m, d, h, M, s, ms);
+
+    //the date constructor remaps years 0-99 to 1900-1999
+    if (y < 100 && y >= 0 && isFinite(date.getFullYear())) {
+        date.setFullYear(y);
+    }
+    return date;
+}
+
+export function createUTCDate (y) {
+    var date = new Date(Date.UTC.apply(null, arguments));
+
+    //the Date.UTC function remaps years 0-99 to 1900-1999
+    if (y < 100 && y >= 0 && isFinite(date.getUTCFullYear())) {
+        date.setUTCFullYear(y);
+    }
+    return date;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/from-anything.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/from-anything.js
new file mode 100644
index 0000000000000000000000000000000000000000..ae76f8544cfafa9418724a5852416ebf09c2b261
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/from-anything.js
@@ -0,0 +1,109 @@
+import isArray from '../utils/is-array';
+import isObject from '../utils/is-object';
+import isObjectEmpty from '../utils/is-object-empty';
+import isNumber from '../utils/is-number';
+import isDate from '../utils/is-date';
+import map from '../utils/map';
+import { createInvalid } from './valid';
+import { Moment, isMoment } from '../moment/constructor';
+import { getLocale } from '../locale/locales';
+import { hooks } from '../utils/hooks';
+import checkOverflow from './check-overflow';
+import { isValid } from './valid';
+
+import { configFromStringAndArray }  from './from-string-and-array';
+import { configFromStringAndFormat } from './from-string-and-format';
+import { configFromString }          from './from-string';
+import { configFromArray }           from './from-array';
+import { configFromObject }          from './from-object';
+
+function createFromConfig (config) {
+    var res = new Moment(checkOverflow(prepareConfig(config)));
+    if (res._nextDay) {
+        // Adding is smart enough around DST
+        res.add(1, 'd');
+        res._nextDay = undefined;
+    }
+
+    return res;
+}
+
+export function prepareConfig (config) {
+    var input = config._i,
+        format = config._f;
+
+    config._locale = config._locale || getLocale(config._l);
+
+    if (input === null || (format === undefined && input === '')) {
+        return createInvalid({nullInput: true});
+    }
+
+    if (typeof input === 'string') {
+        config._i = input = config._locale.preparse(input);
+    }
+
+    if (isMoment(input)) {
+        return new Moment(checkOverflow(input));
+    } else if (isDate(input)) {
+        config._d = input;
+    } else if (isArray(format)) {
+        configFromStringAndArray(config);
+    } else if (format) {
+        configFromStringAndFormat(config);
+    }  else {
+        configFromInput(config);
+    }
+
+    if (!isValid(config)) {
+        config._d = null;
+    }
+
+    return config;
+}
+
+function configFromInput(config) {
+    var input = config._i;
+    if (input === undefined) {
+        config._d = new Date(hooks.now());
+    } else if (isDate(input)) {
+        config._d = new Date(input.valueOf());
+    } else if (typeof input === 'string') {
+        configFromString(config);
+    } else if (isArray(input)) {
+        config._a = map(input.slice(0), function (obj) {
+            return parseInt(obj, 10);
+        });
+        configFromArray(config);
+    } else if (typeof(input) === 'object') {
+        configFromObject(config);
+    } else if (isNumber(input)) {
+        // from milliseconds
+        config._d = new Date(input);
+    } else {
+        hooks.createFromInputFallback(config);
+    }
+}
+
+export function createLocalOrUTC (input, format, locale, strict, isUTC) {
+    var c = {};
+
+    if (locale === true || locale === false) {
+        strict = locale;
+        locale = undefined;
+    }
+
+    if ((isObject(input) && isObjectEmpty(input)) ||
+            (isArray(input) && input.length === 0)) {
+        input = undefined;
+    }
+    // object construction must be done this way.
+    // https://github.com/moment/moment/issues/1423
+    c._isAMomentObject = true;
+    c._useUTC = c._isUTC = isUTC;
+    c._l = locale;
+    c._i = input;
+    c._f = format;
+    c._strict = strict;
+
+    return createFromConfig(c);
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/from-array.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/from-array.js
new file mode 100644
index 0000000000000000000000000000000000000000..3ae35a0bdd2eabe1ea0e555642f1741d868d5304
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/from-array.js
@@ -0,0 +1,140 @@
+import { hooks } from '../utils/hooks';
+import { createDate, createUTCDate } from './date-from-array';
+import { daysInYear } from '../units/year';
+import { weekOfYear, weeksInYear, dayOfYearFromWeeks } from '../units/week-calendar-utils';
+import { YEAR, MONTH, DATE, HOUR, MINUTE, SECOND, MILLISECOND } from '../units/constants';
+import { createLocal } from './local';
+import defaults from '../utils/defaults';
+import getParsingFlags from './parsing-flags';
+
+function currentDateArray(config) {
+    // hooks is actually the exported moment object
+    var nowValue = new Date(hooks.now());
+    if (config._useUTC) {
+        return [nowValue.getUTCFullYear(), nowValue.getUTCMonth(), nowValue.getUTCDate()];
+    }
+    return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()];
+}
+
+// convert an array to a date.
+// the array should mirror the parameters below
+// note: all values past the year are optional and will default to the lowest possible value.
+// [year, month, day , hour, minute, second, millisecond]
+export function configFromArray (config) {
+    var i, date, input = [], currentDate, yearToUse;
+
+    if (config._d) {
+        return;
+    }
+
+    currentDate = currentDateArray(config);
+
+    //compute day of the year from weeks and weekdays
+    if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
+        dayOfYearFromWeekInfo(config);
+    }
+
+    //if the day of the year is set, figure out what it is
+    if (config._dayOfYear) {
+        yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);
+
+        if (config._dayOfYear > daysInYear(yearToUse)) {
+            getParsingFlags(config)._overflowDayOfYear = true;
+        }
+
+        date = createUTCDate(yearToUse, 0, config._dayOfYear);
+        config._a[MONTH] = date.getUTCMonth();
+        config._a[DATE] = date.getUTCDate();
+    }
+
+    // Default to current date.
+    // * if no year, month, day of month are given, default to today
+    // * if day of month is given, default month and year
+    // * if month is given, default only year
+    // * if year is given, don't default anything
+    for (i = 0; i < 3 && config._a[i] == null; ++i) {
+        config._a[i] = input[i] = currentDate[i];
+    }
+
+    // Zero out whatever was not defaulted, including time
+    for (; i < 7; i++) {
+        config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
+    }
+
+    // Check for 24:00:00.000
+    if (config._a[HOUR] === 24 &&
+            config._a[MINUTE] === 0 &&
+            config._a[SECOND] === 0 &&
+            config._a[MILLISECOND] === 0) {
+        config._nextDay = true;
+        config._a[HOUR] = 0;
+    }
+
+    config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input);
+    // Apply timezone offset from input. The actual utcOffset can be changed
+    // with parseZone.
+    if (config._tzm != null) {
+        config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
+    }
+
+    if (config._nextDay) {
+        config._a[HOUR] = 24;
+    }
+}
+
+function dayOfYearFromWeekInfo(config) {
+    var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow;
+
+    w = config._w;
+    if (w.GG != null || w.W != null || w.E != null) {
+        dow = 1;
+        doy = 4;
+
+        // TODO: We need to take the current isoWeekYear, but that depends on
+        // how we interpret now (local, utc, fixed offset). So create
+        // a now version of current config (take local/utc/offset flags, and
+        // create now).
+        weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(createLocal(), 1, 4).year);
+        week = defaults(w.W, 1);
+        weekday = defaults(w.E, 1);
+        if (weekday < 1 || weekday > 7) {
+            weekdayOverflow = true;
+        }
+    } else {
+        dow = config._locale._week.dow;
+        doy = config._locale._week.doy;
+
+        var curWeek = weekOfYear(createLocal(), dow, doy);
+
+        weekYear = defaults(w.gg, config._a[YEAR], curWeek.year);
+
+        // Default to current week.
+        week = defaults(w.w, curWeek.week);
+
+        if (w.d != null) {
+            // weekday -- low day numbers are considered next week
+            weekday = w.d;
+            if (weekday < 0 || weekday > 6) {
+                weekdayOverflow = true;
+            }
+        } else if (w.e != null) {
+            // local weekday -- counting starts from begining of week
+            weekday = w.e + dow;
+            if (w.e < 0 || w.e > 6) {
+                weekdayOverflow = true;
+            }
+        } else {
+            // default to begining of week
+            weekday = dow;
+        }
+    }
+    if (week < 1 || week > weeksInYear(weekYear, dow, doy)) {
+        getParsingFlags(config)._overflowWeeks = true;
+    } else if (weekdayOverflow != null) {
+        getParsingFlags(config)._overflowWeekday = true;
+    } else {
+        temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy);
+        config._a[YEAR] = temp.year;
+        config._dayOfYear = temp.dayOfYear;
+    }
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/from-object.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/from-object.js
new file mode 100644
index 0000000000000000000000000000000000000000..c0bfe9f8d5d3ddaf610bb5d3ae7d9fe8009158bc
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/from-object.js
@@ -0,0 +1,16 @@
+import { normalizeObjectUnits } from '../units/aliases';
+import { configFromArray } from './from-array';
+import map from '../utils/map';
+
+export function configFromObject(config) {
+    if (config._d) {
+        return;
+    }
+
+    var i = normalizeObjectUnits(config._i);
+    config._a = map([i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond], function (obj) {
+        return obj && parseInt(obj, 10);
+    });
+
+    configFromArray(config);
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/from-string-and-array.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/from-string-and-array.js
new file mode 100644
index 0000000000000000000000000000000000000000..1d8a7a806cda2fee37170e4b5615b7acabb555e2
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/from-string-and-array.js
@@ -0,0 +1,50 @@
+import { copyConfig } from '../moment/constructor';
+import { configFromStringAndFormat } from './from-string-and-format';
+import getParsingFlags from './parsing-flags';
+import { isValid } from './valid';
+import extend from '../utils/extend';
+
+// date from string and array of format strings
+export function configFromStringAndArray(config) {
+    var tempConfig,
+        bestMoment,
+
+        scoreToBeat,
+        i,
+        currentScore;
+
+    if (config._f.length === 0) {
+        getParsingFlags(config).invalidFormat = true;
+        config._d = new Date(NaN);
+        return;
+    }
+
+    for (i = 0; i < config._f.length; i++) {
+        currentScore = 0;
+        tempConfig = copyConfig({}, config);
+        if (config._useUTC != null) {
+            tempConfig._useUTC = config._useUTC;
+        }
+        tempConfig._f = config._f[i];
+        configFromStringAndFormat(tempConfig);
+
+        if (!isValid(tempConfig)) {
+            continue;
+        }
+
+        // if there is any input that was not parsed add a penalty for that format
+        currentScore += getParsingFlags(tempConfig).charsLeftOver;
+
+        //or tokens
+        currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;
+
+        getParsingFlags(tempConfig).score = currentScore;
+
+        if (scoreToBeat == null || currentScore < scoreToBeat) {
+            scoreToBeat = currentScore;
+            bestMoment = tempConfig;
+        }
+    }
+
+    extend(config, bestMoment || tempConfig);
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/from-string-and-format.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/from-string-and-format.js
new file mode 100644
index 0000000000000000000000000000000000000000..2ef23515c5509f6168fefbf57578bc1d82060245
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/from-string-and-format.js
@@ -0,0 +1,107 @@
+import { configFromISO } from './from-string';
+import { configFromArray } from './from-array';
+import { getParseRegexForToken }   from '../parse/regex';
+import { addTimeToArrayFromToken } from '../parse/token';
+import { expandFormat, formatTokenFunctions, formattingTokens } from '../format/format';
+import checkOverflow from './check-overflow';
+import { HOUR } from '../units/constants';
+import { hooks } from '../utils/hooks';
+import getParsingFlags from './parsing-flags';
+
+// constant that refers to the ISO standard
+hooks.ISO_8601 = function () {};
+
+// date from string and format string
+export function configFromStringAndFormat(config) {
+    // TODO: Move this to another part of the creation flow to prevent circular deps
+    if (config._f === hooks.ISO_8601) {
+        configFromISO(config);
+        return;
+    }
+
+    config._a = [];
+    getParsingFlags(config).empty = true;
+
+    // This array is used to make a Date, either with `new Date` or `Date.UTC`
+    var string = '' + config._i,
+        i, parsedInput, tokens, token, skipped,
+        stringLength = string.length,
+        totalParsedInputLength = 0;
+
+    tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];
+
+    for (i = 0; i < tokens.length; i++) {
+        token = tokens[i];
+        parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];
+        // console.log('token', token, 'parsedInput', parsedInput,
+        //         'regex', getParseRegexForToken(token, config));
+        if (parsedInput) {
+            skipped = string.substr(0, string.indexOf(parsedInput));
+            if (skipped.length > 0) {
+                getParsingFlags(config).unusedInput.push(skipped);
+            }
+            string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
+            totalParsedInputLength += parsedInput.length;
+        }
+        // don't parse if it's not a known token
+        if (formatTokenFunctions[token]) {
+            if (parsedInput) {
+                getParsingFlags(config).empty = false;
+            }
+            else {
+                getParsingFlags(config).unusedTokens.push(token);
+            }
+            addTimeToArrayFromToken(token, parsedInput, config);
+        }
+        else if (config._strict && !parsedInput) {
+            getParsingFlags(config).unusedTokens.push(token);
+        }
+    }
+
+    // add remaining unparsed input length to the string
+    getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength;
+    if (string.length > 0) {
+        getParsingFlags(config).unusedInput.push(string);
+    }
+
+    // clear _12h flag if hour is <= 12
+    if (config._a[HOUR] <= 12 &&
+        getParsingFlags(config).bigHour === true &&
+        config._a[HOUR] > 0) {
+        getParsingFlags(config).bigHour = undefined;
+    }
+
+    getParsingFlags(config).parsedDateParts = config._a.slice(0);
+    getParsingFlags(config).meridiem = config._meridiem;
+    // handle meridiem
+    config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem);
+
+    configFromArray(config);
+    checkOverflow(config);
+}
+
+
+function meridiemFixWrap (locale, hour, meridiem) {
+    var isPm;
+
+    if (meridiem == null) {
+        // nothing to do
+        return hour;
+    }
+    if (locale.meridiemHour != null) {
+        return locale.meridiemHour(hour, meridiem);
+    } else if (locale.isPM != null) {
+        // Fallback
+        isPm = locale.isPM(meridiem);
+        if (isPm && hour < 12) {
+            hour += 12;
+        }
+        if (!isPm && hour === 12) {
+            hour = 0;
+        }
+        return hour;
+    } else {
+        // this is not supposed to happen
+        return hour;
+    }
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/from-string.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/from-string.js
new file mode 100644
index 0000000000000000000000000000000000000000..63df05ea8dab7c074acfac01575771d9bc3b5941
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/from-string.js
@@ -0,0 +1,120 @@
+import { configFromStringAndFormat } from './from-string-and-format';
+import { hooks } from '../utils/hooks';
+import { deprecate } from '../utils/deprecate';
+import getParsingFlags from './parsing-flags';
+
+// iso 8601 regex
+// 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
+var extendedIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
+var basicIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
+
+var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/;
+
+var isoDates = [
+    ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/],
+    ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/],
+    ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/],
+    ['GGGG-[W]WW', /\d{4}-W\d\d/, false],
+    ['YYYY-DDD', /\d{4}-\d{3}/],
+    ['YYYY-MM', /\d{4}-\d\d/, false],
+    ['YYYYYYMMDD', /[+-]\d{10}/],
+    ['YYYYMMDD', /\d{8}/],
+    // YYYYMM is NOT allowed by the standard
+    ['GGGG[W]WWE', /\d{4}W\d{3}/],
+    ['GGGG[W]WW', /\d{4}W\d{2}/, false],
+    ['YYYYDDD', /\d{7}/]
+];
+
+// iso time formats and regexes
+var isoTimes = [
+    ['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/],
+    ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/],
+    ['HH:mm:ss', /\d\d:\d\d:\d\d/],
+    ['HH:mm', /\d\d:\d\d/],
+    ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/],
+    ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/],
+    ['HHmmss', /\d\d\d\d\d\d/],
+    ['HHmm', /\d\d\d\d/],
+    ['HH', /\d\d/]
+];
+
+var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i;
+
+// date from iso format
+export function configFromISO(config) {
+    var i, l,
+        string = config._i,
+        match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string),
+        allowTime, dateFormat, timeFormat, tzFormat;
+
+    if (match) {
+        getParsingFlags(config).iso = true;
+
+        for (i = 0, l = isoDates.length; i < l; i++) {
+            if (isoDates[i][1].exec(match[1])) {
+                dateFormat = isoDates[i][0];
+                allowTime = isoDates[i][2] !== false;
+                break;
+            }
+        }
+        if (dateFormat == null) {
+            config._isValid = false;
+            return;
+        }
+        if (match[3]) {
+            for (i = 0, l = isoTimes.length; i < l; i++) {
+                if (isoTimes[i][1].exec(match[3])) {
+                    // match[2] should be 'T' or space
+                    timeFormat = (match[2] || ' ') + isoTimes[i][0];
+                    break;
+                }
+            }
+            if (timeFormat == null) {
+                config._isValid = false;
+                return;
+            }
+        }
+        if (!allowTime && timeFormat != null) {
+            config._isValid = false;
+            return;
+        }
+        if (match[4]) {
+            if (tzRegex.exec(match[4])) {
+                tzFormat = 'Z';
+            } else {
+                config._isValid = false;
+                return;
+            }
+        }
+        config._f = dateFormat + (timeFormat || '') + (tzFormat || '');
+        configFromStringAndFormat(config);
+    } else {
+        config._isValid = false;
+    }
+}
+
+// date from iso format or fallback
+export function configFromString(config) {
+    var matched = aspNetJsonRegex.exec(config._i);
+
+    if (matched !== null) {
+        config._d = new Date(+matched[1]);
+        return;
+    }
+
+    configFromISO(config);
+    if (config._isValid === false) {
+        delete config._isValid;
+        hooks.createFromInputFallback(config);
+    }
+}
+
+hooks.createFromInputFallback = deprecate(
+    'value provided is not in a recognized ISO format. moment construction falls back to js Date(), ' +
+    'which is not reliable across all browsers and versions. Non ISO date formats are ' +
+    'discouraged and will be removed in an upcoming major release. Please refer to ' +
+    'http://momentjs.com/guides/#/warnings/js-date/ for more info.',
+    function (config) {
+        config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
+    }
+);
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/local.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/local.js
new file mode 100644
index 0000000000000000000000000000000000000000..88c1e26928959138e65c4d0792a19f65acb64b9d
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/local.js
@@ -0,0 +1,5 @@
+import { createLocalOrUTC } from './from-anything';
+
+export function createLocal (input, format, locale, strict) {
+    return createLocalOrUTC(input, format, locale, strict, false);
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/parsing-flags.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/parsing-flags.js
new file mode 100644
index 0000000000000000000000000000000000000000..5a4220013a37d7bdee2566d33598845f5ab7f391
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/parsing-flags.js
@@ -0,0 +1,24 @@
+function defaultParsingFlags() {
+    // We need to deep clone this object.
+    return {
+        empty           : false,
+        unusedTokens    : [],
+        unusedInput     : [],
+        overflow        : -2,
+        charsLeftOver   : 0,
+        nullInput       : false,
+        invalidMonth    : null,
+        invalidFormat   : false,
+        userInvalidated : false,
+        iso             : false,
+        parsedDateParts : [],
+        meridiem        : null
+    };
+}
+
+export default function getParsingFlags(m) {
+    if (m._pf == null) {
+        m._pf = defaultParsingFlags();
+    }
+    return m._pf;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/utc.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/utc.js
new file mode 100644
index 0000000000000000000000000000000000000000..96139530e26d39bbee1ba3e3a1897c8bc3ee842f
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/utc.js
@@ -0,0 +1,5 @@
+import { createLocalOrUTC } from './from-anything';
+
+export function createUTC (input, format, locale, strict) {
+    return createLocalOrUTC(input, format, locale, strict, true).utc();
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/valid.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/valid.js
new file mode 100644
index 0000000000000000000000000000000000000000..96b1cf615dcad122085251967bea851a4a283818
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/create/valid.js
@@ -0,0 +1,49 @@
+import extend from '../utils/extend';
+import { createUTC } from './utc';
+import getParsingFlags from '../create/parsing-flags';
+import some from '../utils/some';
+
+export function isValid(m) {
+    if (m._isValid == null) {
+        var flags = getParsingFlags(m);
+        var parsedParts = some.call(flags.parsedDateParts, function (i) {
+            return i != null;
+        });
+        var isNowValid = !isNaN(m._d.getTime()) &&
+            flags.overflow < 0 &&
+            !flags.empty &&
+            !flags.invalidMonth &&
+            !flags.invalidWeekday &&
+            !flags.nullInput &&
+            !flags.invalidFormat &&
+            !flags.userInvalidated &&
+            (!flags.meridiem || (flags.meridiem && parsedParts));
+
+        if (m._strict) {
+            isNowValid = isNowValid &&
+                flags.charsLeftOver === 0 &&
+                flags.unusedTokens.length === 0 &&
+                flags.bigHour === undefined;
+        }
+
+        if (Object.isFrozen == null || !Object.isFrozen(m)) {
+            m._isValid = isNowValid;
+        }
+        else {
+            return isNowValid;
+        }
+    }
+    return m._isValid;
+}
+
+export function createInvalid (flags) {
+    var m = createUTC(NaN);
+    if (flags != null) {
+        extend(getParsingFlags(m), flags);
+    }
+    else {
+        getParsingFlags(m).userInvalidated = true;
+    }
+
+    return m;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/abs.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/abs.js
new file mode 100644
index 0000000000000000000000000000000000000000..103a4cf9b304487ce3de819769bc01fef5489af7
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/abs.js
@@ -0,0 +1,18 @@
+var mathAbs = Math.abs;
+
+export function abs () {
+    var data           = this._data;
+
+    this._milliseconds = mathAbs(this._milliseconds);
+    this._days         = mathAbs(this._days);
+    this._months       = mathAbs(this._months);
+
+    data.milliseconds  = mathAbs(data.milliseconds);
+    data.seconds       = mathAbs(data.seconds);
+    data.minutes       = mathAbs(data.minutes);
+    data.hours         = mathAbs(data.hours);
+    data.months        = mathAbs(data.months);
+    data.years         = mathAbs(data.years);
+
+    return this;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/add-subtract.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/add-subtract.js
new file mode 100644
index 0000000000000000000000000000000000000000..3b44e186fcc21a21444698fa41690b172a6be18c
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/add-subtract.js
@@ -0,0 +1,21 @@
+import { createDuration } from './create';
+
+function addSubtract (duration, input, value, direction) {
+    var other = createDuration(input, value);
+
+    duration._milliseconds += direction * other._milliseconds;
+    duration._days         += direction * other._days;
+    duration._months       += direction * other._months;
+
+    return duration._bubble();
+}
+
+// supports only 2.0-style add(1, 's') or add(duration)
+export function add (input, value) {
+    return addSubtract(this, input, value, 1);
+}
+
+// supports only 2.0-style subtract(1, 's') or subtract(duration)
+export function subtract (input, value) {
+    return addSubtract(this, input, value, -1);
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/as.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/as.js
new file mode 100644
index 0000000000000000000000000000000000000000..03ecd6dab2571180214facd47e16097eaa037673
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/as.js
@@ -0,0 +1,55 @@
+import { daysToMonths, monthsToDays } from './bubble';
+import { normalizeUnits } from '../units/aliases';
+import toInt from '../utils/to-int';
+
+export function as (units) {
+    var days;
+    var months;
+    var milliseconds = this._milliseconds;
+
+    units = normalizeUnits(units);
+
+    if (units === 'month' || units === 'year') {
+        days   = this._days   + milliseconds / 864e5;
+        months = this._months + daysToMonths(days);
+        return units === 'month' ? months : months / 12;
+    } else {
+        // handle milliseconds separately because of floating point math errors (issue #1867)
+        days = this._days + Math.round(monthsToDays(this._months));
+        switch (units) {
+            case 'week'   : return days / 7     + milliseconds / 6048e5;
+            case 'day'    : return days         + milliseconds / 864e5;
+            case 'hour'   : return days * 24    + milliseconds / 36e5;
+            case 'minute' : return days * 1440  + milliseconds / 6e4;
+            case 'second' : return days * 86400 + milliseconds / 1000;
+            // Math.floor prevents floating point math errors here
+            case 'millisecond': return Math.floor(days * 864e5) + milliseconds;
+            default: throw new Error('Unknown unit ' + units);
+        }
+    }
+}
+
+// TODO: Use this.as('ms')?
+export function valueOf () {
+    return (
+        this._milliseconds +
+        this._days * 864e5 +
+        (this._months % 12) * 2592e6 +
+        toInt(this._months / 12) * 31536e6
+    );
+}
+
+function makeAs (alias) {
+    return function () {
+        return this.as(alias);
+    };
+}
+
+export var asMilliseconds = makeAs('ms');
+export var asSeconds      = makeAs('s');
+export var asMinutes      = makeAs('m');
+export var asHours        = makeAs('h');
+export var asDays         = makeAs('d');
+export var asWeeks        = makeAs('w');
+export var asMonths       = makeAs('M');
+export var asYears        = makeAs('y');
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/bubble.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/bubble.js
new file mode 100644
index 0000000000000000000000000000000000000000..0c4a336ec47d3b89fa3e077be878a4caa7d7c7a4
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/bubble.js
@@ -0,0 +1,61 @@
+import absFloor from '../utils/abs-floor';
+import absCeil from '../utils/abs-ceil';
+import { createUTCDate } from '../create/date-from-array';
+
+export function bubble () {
+    var milliseconds = this._milliseconds;
+    var days         = this._days;
+    var months       = this._months;
+    var data         = this._data;
+    var seconds, minutes, hours, years, monthsFromDays;
+
+    // if we have a mix of positive and negative values, bubble down first
+    // check: https://github.com/moment/moment/issues/2166
+    if (!((milliseconds >= 0 && days >= 0 && months >= 0) ||
+            (milliseconds <= 0 && days <= 0 && months <= 0))) {
+        milliseconds += absCeil(monthsToDays(months) + days) * 864e5;
+        days = 0;
+        months = 0;
+    }
+
+    // The following code bubbles up values, see the tests for
+    // examples of what that means.
+    data.milliseconds = milliseconds % 1000;
+
+    seconds           = absFloor(milliseconds / 1000);
+    data.seconds      = seconds % 60;
+
+    minutes           = absFloor(seconds / 60);
+    data.minutes      = minutes % 60;
+
+    hours             = absFloor(minutes / 60);
+    data.hours        = hours % 24;
+
+    days += absFloor(hours / 24);
+
+    // convert days to months
+    monthsFromDays = absFloor(daysToMonths(days));
+    months += monthsFromDays;
+    days -= absCeil(monthsToDays(monthsFromDays));
+
+    // 12 months -> 1 year
+    years = absFloor(months / 12);
+    months %= 12;
+
+    data.days   = days;
+    data.months = months;
+    data.years  = years;
+
+    return this;
+}
+
+export function daysToMonths (days) {
+    // 400 years have 146097 days (taking into account leap year rules)
+    // 400 years have 12 months === 4800
+    return days * 4800 / 146097;
+}
+
+export function monthsToDays (months) {
+    // the reverse of daysToMonths
+    return months * 146097 / 4800;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/constructor.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/constructor.js
new file mode 100644
index 0000000000000000000000000000000000000000..fb01c7041375a208f10d50007037751e89c298d3
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/constructor.js
@@ -0,0 +1,41 @@
+import { normalizeObjectUnits } from '../units/aliases';
+import { getLocale } from '../locale/locales';
+
+export function Duration (duration) {
+    var normalizedInput = normalizeObjectUnits(duration),
+        years = normalizedInput.year || 0,
+        quarters = normalizedInput.quarter || 0,
+        months = normalizedInput.month || 0,
+        weeks = normalizedInput.week || 0,
+        days = normalizedInput.day || 0,
+        hours = normalizedInput.hour || 0,
+        minutes = normalizedInput.minute || 0,
+        seconds = normalizedInput.second || 0,
+        milliseconds = normalizedInput.millisecond || 0;
+
+    // representation for dateAddRemove
+    this._milliseconds = +milliseconds +
+        seconds * 1e3 + // 1000
+        minutes * 6e4 + // 1000 * 60
+        hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
+    // Because of dateAddRemove treats 24 hours as different from a
+    // day when working around DST, we need to store them separately
+    this._days = +days +
+        weeks * 7;
+    // It is impossible translate months into days without knowing
+    // which months you are are talking about, so we have to store
+    // it separately.
+    this._months = +months +
+        quarters * 3 +
+        years * 12;
+
+    this._data = {};
+
+    this._locale = getLocale();
+
+    this._bubble();
+}
+
+export function isDuration (obj) {
+    return obj instanceof Duration;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/create.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/create.js
new file mode 100644
index 0000000000000000000000000000000000000000..09af9e24f7be5813a5413f9ab03c9b67eb5647eb
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/create.js
@@ -0,0 +1,120 @@
+import { Duration, isDuration } from './constructor';
+import isNumber from '../utils/is-number';
+import toInt from '../utils/to-int';
+import absRound from '../utils/abs-round';
+import hasOwnProp from '../utils/has-own-prop';
+import { DATE, HOUR, MINUTE, SECOND, MILLISECOND } from '../units/constants';
+import { cloneWithOffset } from '../units/offset';
+import { createLocal } from '../create/local';
+
+// ASP.NET json date format regex
+var aspNetRegex = /^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/;
+
+// from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
+// somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
+// and further modified to allow for strings containing both week and day
+var isoRegex = /^(-)?P(?:(-?[0-9,.]*)Y)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)W)?(?:(-?[0-9,.]*)D)?(?:T(?:(-?[0-9,.]*)H)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)S)?)?$/;
+
+export function createDuration (input, key) {
+    var duration = input,
+        // matching against regexp is expensive, do it on demand
+        match = null,
+        sign,
+        ret,
+        diffRes;
+
+    if (isDuration(input)) {
+        duration = {
+            ms : input._milliseconds,
+            d  : input._days,
+            M  : input._months
+        };
+    } else if (isNumber(input)) {
+        duration = {};
+        if (key) {
+            duration[key] = input;
+        } else {
+            duration.milliseconds = input;
+        }
+    } else if (!!(match = aspNetRegex.exec(input))) {
+        sign = (match[1] === '-') ? -1 : 1;
+        duration = {
+            y  : 0,
+            d  : toInt(match[DATE])                         * sign,
+            h  : toInt(match[HOUR])                         * sign,
+            m  : toInt(match[MINUTE])                       * sign,
+            s  : toInt(match[SECOND])                       * sign,
+            ms : toInt(absRound(match[MILLISECOND] * 1000)) * sign // the millisecond decimal point is included in the match
+        };
+    } else if (!!(match = isoRegex.exec(input))) {
+        sign = (match[1] === '-') ? -1 : 1;
+        duration = {
+            y : parseIso(match[2], sign),
+            M : parseIso(match[3], sign),
+            w : parseIso(match[4], sign),
+            d : parseIso(match[5], sign),
+            h : parseIso(match[6], sign),
+            m : parseIso(match[7], sign),
+            s : parseIso(match[8], sign)
+        };
+    } else if (duration == null) {// checks for null or undefined
+        duration = {};
+    } else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) {
+        diffRes = momentsDifference(createLocal(duration.from), createLocal(duration.to));
+
+        duration = {};
+        duration.ms = diffRes.milliseconds;
+        duration.M = diffRes.months;
+    }
+
+    ret = new Duration(duration);
+
+    if (isDuration(input) && hasOwnProp(input, '_locale')) {
+        ret._locale = input._locale;
+    }
+
+    return ret;
+}
+
+createDuration.fn = Duration.prototype;
+
+function parseIso (inp, sign) {
+    // We'd normally use ~~inp for this, but unfortunately it also
+    // converts floats to ints.
+    // inp may be undefined, so careful calling replace on it.
+    var res = inp && parseFloat(inp.replace(',', '.'));
+    // apply sign while we're at it
+    return (isNaN(res) ? 0 : res) * sign;
+}
+
+function positiveMomentsDifference(base, other) {
+    var res = {milliseconds: 0, months: 0};
+
+    res.months = other.month() - base.month() +
+        (other.year() - base.year()) * 12;
+    if (base.clone().add(res.months, 'M').isAfter(other)) {
+        --res.months;
+    }
+
+    res.milliseconds = +other - +(base.clone().add(res.months, 'M'));
+
+    return res;
+}
+
+function momentsDifference(base, other) {
+    var res;
+    if (!(base.isValid() && other.isValid())) {
+        return {milliseconds: 0, months: 0};
+    }
+
+    other = cloneWithOffset(other, base);
+    if (base.isBefore(other)) {
+        res = positiveMomentsDifference(base, other);
+    } else {
+        res = positiveMomentsDifference(other, base);
+        res.milliseconds = -res.milliseconds;
+        res.months = -res.months;
+    }
+
+    return res;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/duration.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/duration.js
new file mode 100644
index 0000000000000000000000000000000000000000..528b568121fbd4a98a270ae8fd54bd738ece2aa1
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/duration.js
@@ -0,0 +1,16 @@
+// Side effect imports
+import './prototype';
+
+import { createDuration } from './create';
+import { isDuration } from './constructor';
+import {
+    getSetRelativeTimeRounding,
+    getSetRelativeTimeThreshold
+} from './humanize';
+
+export {
+    createDuration,
+    isDuration,
+    getSetRelativeTimeRounding,
+    getSetRelativeTimeThreshold
+};
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/get.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/get.js
new file mode 100644
index 0000000000000000000000000000000000000000..6dafacdd8603d41c43c618783a60a52f0d9c7b52
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/get.js
@@ -0,0 +1,25 @@
+import { normalizeUnits } from '../units/aliases';
+import absFloor from '../utils/abs-floor';
+
+export function get (units) {
+    units = normalizeUnits(units);
+    return this[units + 's']();
+}
+
+function makeGetter(name) {
+    return function () {
+        return this._data[name];
+    };
+}
+
+export var milliseconds = makeGetter('milliseconds');
+export var seconds      = makeGetter('seconds');
+export var minutes      = makeGetter('minutes');
+export var hours        = makeGetter('hours');
+export var days         = makeGetter('days');
+export var months       = makeGetter('months');
+export var years        = makeGetter('years');
+
+export function weeks () {
+    return absFloor(this.days() / 7);
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/humanize.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/humanize.js
new file mode 100644
index 0000000000000000000000000000000000000000..6120d404bcaead521c767015b299693bd4c804a9
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/humanize.js
@@ -0,0 +1,76 @@
+import { createDuration } from './create';
+
+var round = Math.round;
+var thresholds = {
+    s: 45,  // seconds to minute
+    m: 45,  // minutes to hour
+    h: 22,  // hours to day
+    d: 26,  // days to month
+    M: 11   // months to year
+};
+
+// helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
+function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {
+    return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
+}
+
+function relativeTime (posNegDuration, withoutSuffix, locale) {
+    var duration = createDuration(posNegDuration).abs();
+    var seconds  = round(duration.as('s'));
+    var minutes  = round(duration.as('m'));
+    var hours    = round(duration.as('h'));
+    var days     = round(duration.as('d'));
+    var months   = round(duration.as('M'));
+    var years    = round(duration.as('y'));
+
+    var a = seconds < thresholds.s && ['s', seconds]  ||
+            minutes <= 1           && ['m']           ||
+            minutes < thresholds.m && ['mm', minutes] ||
+            hours   <= 1           && ['h']           ||
+            hours   < thresholds.h && ['hh', hours]   ||
+            days    <= 1           && ['d']           ||
+            days    < thresholds.d && ['dd', days]    ||
+            months  <= 1           && ['M']           ||
+            months  < thresholds.M && ['MM', months]  ||
+            years   <= 1           && ['y']           || ['yy', years];
+
+    a[2] = withoutSuffix;
+    a[3] = +posNegDuration > 0;
+    a[4] = locale;
+    return substituteTimeAgo.apply(null, a);
+}
+
+// This function allows you to set the rounding function for relative time strings
+export function getSetRelativeTimeRounding (roundingFunction) {
+    if (roundingFunction === undefined) {
+        return round;
+    }
+    if (typeof(roundingFunction) === 'function') {
+        round = roundingFunction;
+        return true;
+    }
+    return false;
+}
+
+// This function allows you to set a threshold for relative time strings
+export function getSetRelativeTimeThreshold (threshold, limit) {
+    if (thresholds[threshold] === undefined) {
+        return false;
+    }
+    if (limit === undefined) {
+        return thresholds[threshold];
+    }
+    thresholds[threshold] = limit;
+    return true;
+}
+
+export function humanize (withSuffix) {
+    var locale = this.localeData();
+    var output = relativeTime(this, !withSuffix, locale);
+
+    if (withSuffix) {
+        output = locale.pastFuture(+this, output);
+    }
+
+    return locale.postformat(output);
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/iso-string.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/iso-string.js
new file mode 100644
index 0000000000000000000000000000000000000000..f33a968da8eebc8d1bd4e7277d502801e6187607
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/iso-string.js
@@ -0,0 +1,52 @@
+import absFloor from '../utils/abs-floor';
+var abs = Math.abs;
+
+export function toISOString() {
+    // for ISO strings we do not use the normal bubbling rules:
+    //  * milliseconds bubble up until they become hours
+    //  * days do not bubble at all
+    //  * months bubble up until they become years
+    // This is because there is no context-free conversion between hours and days
+    // (think of clock changes)
+    // and also not between days and months (28-31 days per month)
+    var seconds = abs(this._milliseconds) / 1000;
+    var days         = abs(this._days);
+    var months       = abs(this._months);
+    var minutes, hours, years;
+
+    // 3600 seconds -> 60 minutes -> 1 hour
+    minutes           = absFloor(seconds / 60);
+    hours             = absFloor(minutes / 60);
+    seconds %= 60;
+    minutes %= 60;
+
+    // 12 months -> 1 year
+    years  = absFloor(months / 12);
+    months %= 12;
+
+
+    // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
+    var Y = years;
+    var M = months;
+    var D = days;
+    var h = hours;
+    var m = minutes;
+    var s = seconds;
+    var total = this.asSeconds();
+
+    if (!total) {
+        // this is the same as C#'s (Noda) and python (isodate)...
+        // but not other JS (goog.date)
+        return 'P0D';
+    }
+
+    return (total < 0 ? '-' : '') +
+        'P' +
+        (Y ? Y + 'Y' : '') +
+        (M ? M + 'M' : '') +
+        (D ? D + 'D' : '') +
+        ((h || m || s) ? 'T' : '') +
+        (h ? h + 'H' : '') +
+        (m ? m + 'M' : '') +
+        (s ? s + 'S' : '');
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/prototype.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/prototype.js
new file mode 100644
index 0000000000000000000000000000000000000000..0257ff9b501c84e3fba8aeebca204ba18df4168c
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/duration/prototype.js
@@ -0,0 +1,48 @@
+import { Duration } from './constructor';
+
+var proto = Duration.prototype;
+
+import { abs } from './abs';
+import { add, subtract } from './add-subtract';
+import { as, asMilliseconds, asSeconds, asMinutes, asHours, asDays, asWeeks, asMonths, asYears, valueOf } from './as';
+import { bubble } from './bubble';
+import { get, milliseconds, seconds, minutes, hours, days, months, years, weeks } from './get';
+import { humanize } from './humanize';
+import { toISOString } from './iso-string';
+import { lang, locale, localeData } from '../moment/locale';
+
+proto.abs            = abs;
+proto.add            = add;
+proto.subtract       = subtract;
+proto.as             = as;
+proto.asMilliseconds = asMilliseconds;
+proto.asSeconds      = asSeconds;
+proto.asMinutes      = asMinutes;
+proto.asHours        = asHours;
+proto.asDays         = asDays;
+proto.asWeeks        = asWeeks;
+proto.asMonths       = asMonths;
+proto.asYears        = asYears;
+proto.valueOf        = valueOf;
+proto._bubble        = bubble;
+proto.get            = get;
+proto.milliseconds   = milliseconds;
+proto.seconds        = seconds;
+proto.minutes        = minutes;
+proto.hours          = hours;
+proto.days           = days;
+proto.weeks          = weeks;
+proto.months         = months;
+proto.years          = years;
+proto.humanize       = humanize;
+proto.toISOString    = toISOString;
+proto.toString       = toISOString;
+proto.toJSON         = toISOString;
+proto.locale         = locale;
+proto.localeData     = localeData;
+
+// Deprecations
+import { deprecate } from '../utils/deprecate';
+
+proto.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', toISOString);
+proto.lang = lang;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/format/format.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/format/format.js
new file mode 100644
index 0000000000000000000000000000000000000000..33486f1d566d6712869e84fc4bc7a3de16d97b1a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/format/format.js
@@ -0,0 +1,91 @@
+import zeroFill from '../utils/zero-fill';
+
+export var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g;
+
+var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g;
+
+var formatFunctions = {};
+
+export var formatTokenFunctions = {};
+
+// token:    'M'
+// padded:   ['MM', 2]
+// ordinal:  'Mo'
+// callback: function () { this.month() + 1 }
+export function addFormatToken (token, padded, ordinal, callback) {
+    var func = callback;
+    if (typeof callback === 'string') {
+        func = function () {
+            return this[callback]();
+        };
+    }
+    if (token) {
+        formatTokenFunctions[token] = func;
+    }
+    if (padded) {
+        formatTokenFunctions[padded[0]] = function () {
+            return zeroFill(func.apply(this, arguments), padded[1], padded[2]);
+        };
+    }
+    if (ordinal) {
+        formatTokenFunctions[ordinal] = function () {
+            return this.localeData().ordinal(func.apply(this, arguments), token);
+        };
+    }
+}
+
+function removeFormattingTokens(input) {
+    if (input.match(/\[[\s\S]/)) {
+        return input.replace(/^\[|\]$/g, '');
+    }
+    return input.replace(/\\/g, '');
+}
+
+function makeFormatFunction(format) {
+    var array = format.match(formattingTokens), i, length;
+
+    for (i = 0, length = array.length; i < length; i++) {
+        if (formatTokenFunctions[array[i]]) {
+            array[i] = formatTokenFunctions[array[i]];
+        } else {
+            array[i] = removeFormattingTokens(array[i]);
+        }
+    }
+
+    return function (mom) {
+        var output = '', i;
+        for (i = 0; i < length; i++) {
+            output += array[i] instanceof Function ? array[i].call(mom, format) : array[i];
+        }
+        return output;
+    };
+}
+
+// format date using native date object
+export function formatMoment(m, format) {
+    if (!m.isValid()) {
+        return m.localeData().invalidDate();
+    }
+
+    format = expandFormat(format, m.localeData());
+    formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format);
+
+    return formatFunctions[format](m);
+}
+
+export function expandFormat(format, locale) {
+    var i = 5;
+
+    function replaceLongDateFormatTokens(input) {
+        return locale.longDateFormat(input) || input;
+    }
+
+    localFormattingTokens.lastIndex = 0;
+    while (i >= 0 && localFormattingTokens.test(format)) {
+        format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
+        localFormattingTokens.lastIndex = 0;
+        i -= 1;
+    }
+
+    return format;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/base-config.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/base-config.js
new file mode 100644
index 0000000000000000000000000000000000000000..cbb0b36b49fa971a6827caf3523bd32ea128e562
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/base-config.js
@@ -0,0 +1,44 @@
+import { defaultCalendar } from './calendar';
+import { defaultLongDateFormat } from './formats';
+import { defaultInvalidDate } from './invalid';
+import { defaultOrdinal, defaultOrdinalParse } from './ordinal';
+import { defaultRelativeTime } from './relative';
+
+// months
+import {
+    defaultLocaleMonths,
+    defaultLocaleMonthsShort,
+} from '../units/month';
+
+// week
+import { defaultLocaleWeek } from '../units/week';
+
+// weekdays
+import {
+    defaultLocaleWeekdays,
+    defaultLocaleWeekdaysMin,
+    defaultLocaleWeekdaysShort,
+} from '../units/day-of-week';
+
+// meridiem
+import { defaultLocaleMeridiemParse } from '../units/hour';
+
+export var baseConfig = {
+    calendar: defaultCalendar,
+    longDateFormat: defaultLongDateFormat,
+    invalidDate: defaultInvalidDate,
+    ordinal: defaultOrdinal,
+    ordinalParse: defaultOrdinalParse,
+    relativeTime: defaultRelativeTime,
+
+    months: defaultLocaleMonths,
+    monthsShort: defaultLocaleMonthsShort,
+
+    week: defaultLocaleWeek,
+
+    weekdays: defaultLocaleWeekdays,
+    weekdaysMin: defaultLocaleWeekdaysMin,
+    weekdaysShort: defaultLocaleWeekdaysShort,
+
+    meridiemParse: defaultLocaleMeridiemParse
+};
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/calendar.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/calendar.js
new file mode 100644
index 0000000000000000000000000000000000000000..f12214b86da3ff3d2035d9b7cedce0d1bdd2a877
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/calendar.js
@@ -0,0 +1,15 @@
+export var defaultCalendar = {
+    sameDay : '[Today at] LT',
+    nextDay : '[Tomorrow at] LT',
+    nextWeek : 'dddd [at] LT',
+    lastDay : '[Yesterday at] LT',
+    lastWeek : '[Last] dddd [at] LT',
+    sameElse : 'L'
+};
+
+import isFunction from '../utils/is-function';
+
+export function calendar (key, mom, now) {
+    var output = this._calendar[key] || this._calendar['sameElse'];
+    return isFunction(output) ? output.call(mom, now) : output;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/constructor.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/constructor.js
new file mode 100644
index 0000000000000000000000000000000000000000..c32b73ee11c6d3e6759d91237c169ff343ba852d
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/constructor.js
@@ -0,0 +1,5 @@
+export function Locale(config) {
+    if (config != null) {
+        this.set(config);
+    }
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/en.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/en.js
new file mode 100644
index 0000000000000000000000000000000000000000..20964cd9c1c2ea926399b1185e9cd36dc2404856
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/en.js
@@ -0,0 +1,15 @@
+import './prototype';
+import { getSetGlobalLocale } from './locales';
+import toInt from '../utils/to-int';
+
+getSetGlobalLocale('en', {
+    ordinalParse: /\d{1,2}(th|st|nd|rd)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (toInt(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/formats.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/formats.js
new file mode 100644
index 0000000000000000000000000000000000000000..6d83b0394843d490250241143afd42937cce57f3
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/formats.js
@@ -0,0 +1,23 @@
+export var defaultLongDateFormat = {
+    LTS  : 'h:mm:ss A',
+    LT   : 'h:mm A',
+    L    : 'MM/DD/YYYY',
+    LL   : 'MMMM D, YYYY',
+    LLL  : 'MMMM D, YYYY h:mm A',
+    LLLL : 'dddd, MMMM D, YYYY h:mm A'
+};
+
+export function longDateFormat (key) {
+    var format = this._longDateFormat[key],
+        formatUpper = this._longDateFormat[key.toUpperCase()];
+
+    if (format || !formatUpper) {
+        return format;
+    }
+
+    this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) {
+        return val.slice(1);
+    });
+
+    return this._longDateFormat[key];
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/invalid.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/invalid.js
new file mode 100644
index 0000000000000000000000000000000000000000..e9096339baae8da1e3f27ad450f9754015ca3273
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/invalid.js
@@ -0,0 +1,5 @@
+export var defaultInvalidDate = 'Invalid date';
+
+export function invalidDate () {
+    return this._invalidDate;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/lists.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/lists.js
new file mode 100644
index 0000000000000000000000000000000000000000..42f7572e2a9253dd353633ee0e66c48d80055828
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/lists.js
@@ -0,0 +1,93 @@
+import isNumber from '../utils/is-number';
+import { getLocale } from './locales';
+import { createUTC } from '../create/utc';
+
+function get (format, index, field, setter) {
+    var locale = getLocale();
+    var utc = createUTC().set(setter, index);
+    return locale[field](utc, format);
+}
+
+function listMonthsImpl (format, index, field) {
+    if (isNumber(format)) {
+        index = format;
+        format = undefined;
+    }
+
+    format = format || '';
+
+    if (index != null) {
+        return get(format, index, field, 'month');
+    }
+
+    var i;
+    var out = [];
+    for (i = 0; i < 12; i++) {
+        out[i] = get(format, i, field, 'month');
+    }
+    return out;
+}
+
+// ()
+// (5)
+// (fmt, 5)
+// (fmt)
+// (true)
+// (true, 5)
+// (true, fmt, 5)
+// (true, fmt)
+function listWeekdaysImpl (localeSorted, format, index, field) {
+    if (typeof localeSorted === 'boolean') {
+        if (isNumber(format)) {
+            index = format;
+            format = undefined;
+        }
+
+        format = format || '';
+    } else {
+        format = localeSorted;
+        index = format;
+        localeSorted = false;
+
+        if (isNumber(format)) {
+            index = format;
+            format = undefined;
+        }
+
+        format = format || '';
+    }
+
+    var locale = getLocale(),
+        shift = localeSorted ? locale._week.dow : 0;
+
+    if (index != null) {
+        return get(format, (index + shift) % 7, field, 'day');
+    }
+
+    var i;
+    var out = [];
+    for (i = 0; i < 7; i++) {
+        out[i] = get(format, (i + shift) % 7, field, 'day');
+    }
+    return out;
+}
+
+export function listMonths (format, index) {
+    return listMonthsImpl(format, index, 'months');
+}
+
+export function listMonthsShort (format, index) {
+    return listMonthsImpl(format, index, 'monthsShort');
+}
+
+export function listWeekdays (localeSorted, format, index) {
+    return listWeekdaysImpl(localeSorted, format, index, 'weekdays');
+}
+
+export function listWeekdaysShort (localeSorted, format, index) {
+    return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort');
+}
+
+export function listWeekdaysMin (localeSorted, format, index) {
+    return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin');
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/locale.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/locale.js
new file mode 100644
index 0000000000000000000000000000000000000000..ac9cebfb824997a5384048ca913fca24b32ee493
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/locale.js
@@ -0,0 +1,39 @@
+// Side effect imports
+import './prototype';
+
+import {
+    getSetGlobalLocale,
+    defineLocale,
+    updateLocale,
+    getLocale,
+    listLocales
+} from './locales';
+
+import {
+    listMonths,
+    listMonthsShort,
+    listWeekdays,
+    listWeekdaysShort,
+    listWeekdaysMin
+} from './lists';
+
+export {
+    getSetGlobalLocale,
+    defineLocale,
+    updateLocale,
+    getLocale,
+    listLocales,
+    listMonths,
+    listMonthsShort,
+    listWeekdays,
+    listWeekdaysShort,
+    listWeekdaysMin
+};
+
+import { deprecate } from '../utils/deprecate';
+import { hooks } from '../utils/hooks';
+
+hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', getSetGlobalLocale);
+hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', getLocale);
+
+import './en';
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/locales.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/locales.js
new file mode 100644
index 0000000000000000000000000000000000000000..99ee11571849f4df7faabc10c9628b83501eb512
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/locales.js
@@ -0,0 +1,186 @@
+import isArray from '../utils/is-array';
+import hasOwnProp from '../utils/has-own-prop';
+import isUndefined from '../utils/is-undefined';
+import compareArrays from '../utils/compare-arrays';
+import { deprecateSimple } from '../utils/deprecate';
+import { mergeConfigs } from './set';
+import { Locale } from './constructor';
+import keys from '../utils/keys';
+
+import { baseConfig } from './base-config';
+
+// internal storage for locale config files
+var locales = {};
+var localeFamilies = {};
+var globalLocale;
+
+function normalizeLocale(key) {
+    return key ? key.toLowerCase().replace('_', '-') : key;
+}
+
+// pick the locale from the array
+// try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
+// substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
+function chooseLocale(names) {
+    var i = 0, j, next, locale, split;
+
+    while (i < names.length) {
+        split = normalizeLocale(names[i]).split('-');
+        j = split.length;
+        next = normalizeLocale(names[i + 1]);
+        next = next ? next.split('-') : null;
+        while (j > 0) {
+            locale = loadLocale(split.slice(0, j).join('-'));
+            if (locale) {
+                return locale;
+            }
+            if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
+                //the next array item is better than a shallower substring of this one
+                break;
+            }
+            j--;
+        }
+        i++;
+    }
+    return null;
+}
+
+function loadLocale(name) {
+    var oldLocale = null;
+    // TODO: Find a better way to register and load all the locales in Node
+    if (!locales[name] && (typeof module !== 'undefined') &&
+            module && module.exports) {
+        try {
+            oldLocale = globalLocale._abbr;
+            require('./locale/' + name);
+            // because defineLocale currently also sets the global locale, we
+            // want to undo that for lazy loaded locales
+            getSetGlobalLocale(oldLocale);
+        } catch (e) { }
+    }
+    return locales[name];
+}
+
+// This function will load locale and then set the global locale.  If
+// no arguments are passed in, it will simply return the current global
+// locale key.
+export function getSetGlobalLocale (key, values) {
+    var data;
+    if (key) {
+        if (isUndefined(values)) {
+            data = getLocale(key);
+        }
+        else {
+            data = defineLocale(key, values);
+        }
+
+        if (data) {
+            // moment.duration._locale = moment._locale = data;
+            globalLocale = data;
+        }
+    }
+
+    return globalLocale._abbr;
+}
+
+export function defineLocale (name, config) {
+    if (config !== null) {
+        var parentConfig = baseConfig;
+        config.abbr = name;
+        if (locales[name] != null) {
+            deprecateSimple('defineLocaleOverride',
+                    'use moment.updateLocale(localeName, config) to change ' +
+                    'an existing locale. moment.defineLocale(localeName, ' +
+                    'config) should only be used for creating a new locale ' +
+                    'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.');
+            parentConfig = locales[name]._config;
+        } else if (config.parentLocale != null) {
+            if (locales[config.parentLocale] != null) {
+                parentConfig = locales[config.parentLocale]._config;
+            } else {
+                if (!localeFamilies[config.parentLocale]) {
+                    localeFamilies[config.parentLocale] = [];
+                }
+                localeFamilies[config.parentLocale].push({
+                    name: name,
+                    config: config
+                });
+                return null;
+            }
+        }
+        locales[name] = new Locale(mergeConfigs(parentConfig, config));
+
+        if (localeFamilies[name]) {
+            localeFamilies[name].forEach(function (x) {
+                defineLocale(x.name, x.config);
+            });
+        }
+
+        // backwards compat for now: also set the locale
+        // make sure we set the locale AFTER all child locales have been
+        // created, so we won't end up with the child locale set.
+        getSetGlobalLocale(name);
+
+
+        return locales[name];
+    } else {
+        // useful for testing
+        delete locales[name];
+        return null;
+    }
+}
+
+export function updateLocale(name, config) {
+    if (config != null) {
+        var locale, parentConfig = baseConfig;
+        // MERGE
+        if (locales[name] != null) {
+            parentConfig = locales[name]._config;
+        }
+        config = mergeConfigs(parentConfig, config);
+        locale = new Locale(config);
+        locale.parentLocale = locales[name];
+        locales[name] = locale;
+
+        // backwards compat for now: also set the locale
+        getSetGlobalLocale(name);
+    } else {
+        // pass null for config to unupdate, useful for tests
+        if (locales[name] != null) {
+            if (locales[name].parentLocale != null) {
+                locales[name] = locales[name].parentLocale;
+            } else if (locales[name] != null) {
+                delete locales[name];
+            }
+        }
+    }
+    return locales[name];
+}
+
+// returns locale data
+export function getLocale (key) {
+    var locale;
+
+    if (key && key._locale && key._locale._abbr) {
+        key = key._locale._abbr;
+    }
+
+    if (!key) {
+        return globalLocale;
+    }
+
+    if (!isArray(key)) {
+        //short-circuit everything else
+        locale = loadLocale(key);
+        if (locale) {
+            return locale;
+        }
+        key = [key];
+    }
+
+    return chooseLocale(key);
+}
+
+export function listLocales() {
+    return keys(locales);
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/ordinal.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/ordinal.js
new file mode 100644
index 0000000000000000000000000000000000000000..0028aca024e7e1b75a0e466d8b50c2ec6020c3df
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/ordinal.js
@@ -0,0 +1,7 @@
+export var defaultOrdinal = '%d';
+export var defaultOrdinalParse = /\d{1,2}/;
+
+export function ordinal (number) {
+    return this._ordinal.replace('%d', number);
+}
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/pre-post-format.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/pre-post-format.js
new file mode 100644
index 0000000000000000000000000000000000000000..10ed20584294a94169d265a3db85af1dac525e03
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/pre-post-format.js
@@ -0,0 +1,3 @@
+export function preParsePostFormat (string) {
+    return string;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/prototype.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/prototype.js
new file mode 100644
index 0000000000000000000000000000000000000000..24eef89f14b917821a40c003e4f4aba5ddf13e7b
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/prototype.js
@@ -0,0 +1,69 @@
+import { Locale } from './constructor';
+
+var proto = Locale.prototype;
+
+import { calendar } from './calendar';
+import { longDateFormat } from './formats';
+import { invalidDate } from './invalid';
+import { ordinal } from './ordinal';
+import { preParsePostFormat } from './pre-post-format';
+import { relativeTime, pastFuture } from './relative';
+import { set } from './set';
+
+proto.calendar        = calendar;
+proto.longDateFormat  = longDateFormat;
+proto.invalidDate     = invalidDate;
+proto.ordinal         = ordinal;
+proto.preparse        = preParsePostFormat;
+proto.postformat      = preParsePostFormat;
+proto.relativeTime    = relativeTime;
+proto.pastFuture      = pastFuture;
+proto.set             = set;
+
+// Month
+import {
+    localeMonthsParse,
+    localeMonths,
+    localeMonthsShort,
+    monthsRegex,
+    monthsShortRegex
+} from '../units/month';
+
+proto.months            =        localeMonths;
+proto.monthsShort       =        localeMonthsShort;
+proto.monthsParse       =        localeMonthsParse;
+proto.monthsRegex       = monthsRegex;
+proto.monthsShortRegex  = monthsShortRegex;
+
+// Week
+import { localeWeek, localeFirstDayOfYear, localeFirstDayOfWeek } from '../units/week';
+proto.week = localeWeek;
+proto.firstDayOfYear = localeFirstDayOfYear;
+proto.firstDayOfWeek = localeFirstDayOfWeek;
+
+// Day of Week
+import {
+    localeWeekdaysParse,
+    localeWeekdays,
+    localeWeekdaysMin,
+    localeWeekdaysShort,
+
+    weekdaysRegex,
+    weekdaysShortRegex,
+    weekdaysMinRegex
+} from '../units/day-of-week';
+
+proto.weekdays       =        localeWeekdays;
+proto.weekdaysMin    =        localeWeekdaysMin;
+proto.weekdaysShort  =        localeWeekdaysShort;
+proto.weekdaysParse  =        localeWeekdaysParse;
+
+proto.weekdaysRegex       =        weekdaysRegex;
+proto.weekdaysShortRegex  =        weekdaysShortRegex;
+proto.weekdaysMinRegex    =        weekdaysMinRegex;
+
+// Hours
+import { localeIsPM, localeMeridiem } from '../units/hour';
+
+proto.isPM = localeIsPM;
+proto.meridiem = localeMeridiem;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/relative.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/relative.js
new file mode 100644
index 0000000000000000000000000000000000000000..4c485ea2224d50aa9f9287faf75ff415e8019913
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/relative.js
@@ -0,0 +1,29 @@
+export var defaultRelativeTime = {
+    future : 'in %s',
+    past   : '%s ago',
+    s  : 'a few seconds',
+    m  : 'a minute',
+    mm : '%d minutes',
+    h  : 'an hour',
+    hh : '%d hours',
+    d  : 'a day',
+    dd : '%d days',
+    M  : 'a month',
+    MM : '%d months',
+    y  : 'a year',
+    yy : '%d years'
+};
+
+import isFunction from '../utils/is-function';
+
+export function relativeTime (number, withoutSuffix, string, isFuture) {
+    var output = this._relativeTime[string];
+    return (isFunction(output)) ?
+        output(number, withoutSuffix, string, isFuture) :
+        output.replace(/%d/i, number);
+}
+
+export function pastFuture (diff, output) {
+    var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
+    return isFunction(format) ? format(output) : format.replace(/%s/i, output);
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/set.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/set.js
new file mode 100644
index 0000000000000000000000000000000000000000..45a2f46e12f5b29d644187d32a1d6291d5c5e4b7
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/locale/set.js
@@ -0,0 +1,46 @@
+import isFunction from '../utils/is-function';
+import extend from '../utils/extend';
+import isObject from '../utils/is-object';
+import hasOwnProp from '../utils/has-own-prop';
+
+export function set (config) {
+    var prop, i;
+    for (i in config) {
+        prop = config[i];
+        if (isFunction(prop)) {
+            this[i] = prop;
+        } else {
+            this['_' + i] = prop;
+        }
+    }
+    this._config = config;
+    // Lenient ordinal parsing accepts just a number in addition to
+    // number + (possibly) stuff coming from _ordinalParseLenient.
+    this._ordinalParseLenient = new RegExp(this._ordinalParse.source + '|' + (/\d{1,2}/).source);
+}
+
+export function mergeConfigs(parentConfig, childConfig) {
+    var res = extend({}, parentConfig), prop;
+    for (prop in childConfig) {
+        if (hasOwnProp(childConfig, prop)) {
+            if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) {
+                res[prop] = {};
+                extend(res[prop], parentConfig[prop]);
+                extend(res[prop], childConfig[prop]);
+            } else if (childConfig[prop] != null) {
+                res[prop] = childConfig[prop];
+            } else {
+                delete res[prop];
+            }
+        }
+    }
+    for (prop in parentConfig) {
+        if (hasOwnProp(parentConfig, prop) &&
+                !hasOwnProp(childConfig, prop) &&
+                isObject(parentConfig[prop])) {
+            // make sure changes to properties don't modify parent config
+            res[prop] = extend({}, res[prop]);
+        }
+    }
+    return res;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/add-subtract.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/add-subtract.js
new file mode 100644
index 0000000000000000000000000000000000000000..b9e86a69d2a86c3e4e041c1c98874e99e50d9108
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/add-subtract.js
@@ -0,0 +1,55 @@
+import { get, set } from './get-set';
+import { setMonth } from '../units/month';
+import { createDuration } from '../duration/create';
+import { deprecateSimple } from '../utils/deprecate';
+import { hooks } from '../utils/hooks';
+import absRound from '../utils/abs-round';
+
+
+// TODO: remove 'name' arg after deprecation is removed
+function createAdder(direction, name) {
+    return function (val, period) {
+        var dur, tmp;
+        //invert the arguments, but complain about it
+        if (period !== null && !isNaN(+period)) {
+            deprecateSimple(name, 'moment().' + name  + '(period, number) is deprecated. Please use moment().' + name + '(number, period). ' +
+            'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.');
+            tmp = val; val = period; period = tmp;
+        }
+
+        val = typeof val === 'string' ? +val : val;
+        dur = createDuration(val, period);
+        addSubtract(this, dur, direction);
+        return this;
+    };
+}
+
+export function addSubtract (mom, duration, isAdding, updateOffset) {
+    var milliseconds = duration._milliseconds,
+        days = absRound(duration._days),
+        months = absRound(duration._months);
+
+    if (!mom.isValid()) {
+        // No op
+        return;
+    }
+
+    updateOffset = updateOffset == null ? true : updateOffset;
+
+    if (milliseconds) {
+        mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding);
+    }
+    if (days) {
+        set(mom, 'Date', get(mom, 'Date') + days * isAdding);
+    }
+    if (months) {
+        setMonth(mom, get(mom, 'Month') + months * isAdding);
+    }
+    if (updateOffset) {
+        hooks.updateOffset(mom, days || months);
+    }
+}
+
+export var add      = createAdder(1, 'add');
+export var subtract = createAdder(-1, 'subtract');
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/calendar.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/calendar.js
new file mode 100644
index 0000000000000000000000000000000000000000..4b5725c58b0c17010d99f893995b4f067e80e467
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/calendar.js
@@ -0,0 +1,26 @@
+import { createLocal } from '../create/local';
+import { cloneWithOffset } from '../units/offset';
+import isFunction from '../utils/is-function';
+import { hooks } from '../utils/hooks';
+
+export function getCalendarFormat(myMoment, now) {
+    var diff = myMoment.diff(now, 'days', true);
+    return diff < -6 ? 'sameElse' :
+            diff < -1 ? 'lastWeek' :
+            diff < 0 ? 'lastDay' :
+            diff < 1 ? 'sameDay' :
+            diff < 2 ? 'nextDay' :
+            diff < 7 ? 'nextWeek' : 'sameElse';
+}
+
+export function calendar (time, formats) {
+    // We want to compare the start of today, vs this.
+    // Getting start-of-today depends on whether we're local/utc/offset or not.
+    var now = time || createLocal(),
+        sod = cloneWithOffset(now, this).startOf('day'),
+        format = hooks.calendarFormat(this, sod) || 'sameElse';
+
+    var output = formats && (isFunction(formats[format]) ? formats[format].call(this, now) : formats[format]);
+
+    return this.format(output || this.localeData().calendar(format, this, createLocal(now)));
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/clone.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/clone.js
new file mode 100644
index 0000000000000000000000000000000000000000..d96b328b2446c7684dc4eeea109ead71b2a722e0
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/clone.js
@@ -0,0 +1,5 @@
+import { Moment } from './constructor';
+
+export function clone () {
+    return new Moment(this);
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/compare.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/compare.js
new file mode 100644
index 0000000000000000000000000000000000000000..b26bac633c4c697aa9e556603fbdac4c00be6e36
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/compare.js
@@ -0,0 +1,59 @@
+import { isMoment } from './constructor';
+import { normalizeUnits } from '../units/aliases';
+import { createLocal } from '../create/local';
+import isUndefined from '../utils/is-undefined';
+
+export function isAfter (input, units) {
+    var localInput = isMoment(input) ? input : createLocal(input);
+    if (!(this.isValid() && localInput.isValid())) {
+        return false;
+    }
+    units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
+    if (units === 'millisecond') {
+        return this.valueOf() > localInput.valueOf();
+    } else {
+        return localInput.valueOf() < this.clone().startOf(units).valueOf();
+    }
+}
+
+export function isBefore (input, units) {
+    var localInput = isMoment(input) ? input : createLocal(input);
+    if (!(this.isValid() && localInput.isValid())) {
+        return false;
+    }
+    units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
+    if (units === 'millisecond') {
+        return this.valueOf() < localInput.valueOf();
+    } else {
+        return this.clone().endOf(units).valueOf() < localInput.valueOf();
+    }
+}
+
+export function isBetween (from, to, units, inclusivity) {
+    inclusivity = inclusivity || '()';
+    return (inclusivity[0] === '(' ? this.isAfter(from, units) : !this.isBefore(from, units)) &&
+        (inclusivity[1] === ')' ? this.isBefore(to, units) : !this.isAfter(to, units));
+}
+
+export function isSame (input, units) {
+    var localInput = isMoment(input) ? input : createLocal(input),
+        inputMs;
+    if (!(this.isValid() && localInput.isValid())) {
+        return false;
+    }
+    units = normalizeUnits(units || 'millisecond');
+    if (units === 'millisecond') {
+        return this.valueOf() === localInput.valueOf();
+    } else {
+        inputMs = localInput.valueOf();
+        return this.clone().startOf(units).valueOf() <= inputMs && inputMs <= this.clone().endOf(units).valueOf();
+    }
+}
+
+export function isSameOrAfter (input, units) {
+    return this.isSame(input, units) || this.isAfter(input,units);
+}
+
+export function isSameOrBefore (input, units) {
+    return this.isSame(input, units) || this.isBefore(input,units);
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/constructor.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/constructor.js
new file mode 100644
index 0000000000000000000000000000000000000000..964c0aef6a67d96a756cd7d24433ba331cc527ab
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/constructor.js
@@ -0,0 +1,74 @@
+import { hooks } from '../utils/hooks';
+import hasOwnProp from '../utils/has-own-prop';
+import isUndefined from '../utils/is-undefined';
+import getParsingFlags from '../create/parsing-flags';
+
+// Plugins that add properties should also add the key here (null value),
+// so we can properly clone ourselves.
+var momentProperties = hooks.momentProperties = [];
+
+export function copyConfig(to, from) {
+    var i, prop, val;
+
+    if (!isUndefined(from._isAMomentObject)) {
+        to._isAMomentObject = from._isAMomentObject;
+    }
+    if (!isUndefined(from._i)) {
+        to._i = from._i;
+    }
+    if (!isUndefined(from._f)) {
+        to._f = from._f;
+    }
+    if (!isUndefined(from._l)) {
+        to._l = from._l;
+    }
+    if (!isUndefined(from._strict)) {
+        to._strict = from._strict;
+    }
+    if (!isUndefined(from._tzm)) {
+        to._tzm = from._tzm;
+    }
+    if (!isUndefined(from._isUTC)) {
+        to._isUTC = from._isUTC;
+    }
+    if (!isUndefined(from._offset)) {
+        to._offset = from._offset;
+    }
+    if (!isUndefined(from._pf)) {
+        to._pf = getParsingFlags(from);
+    }
+    if (!isUndefined(from._locale)) {
+        to._locale = from._locale;
+    }
+
+    if (momentProperties.length > 0) {
+        for (i in momentProperties) {
+            prop = momentProperties[i];
+            val = from[prop];
+            if (!isUndefined(val)) {
+                to[prop] = val;
+            }
+        }
+    }
+
+    return to;
+}
+
+var updateInProgress = false;
+
+// Moment prototype object
+export function Moment(config) {
+    copyConfig(this, config);
+    this._d = new Date(config._d != null ? config._d.getTime() : NaN);
+    // Prevent infinite loop in case updateOffset creates new moment
+    // objects.
+    if (updateInProgress === false) {
+        updateInProgress = true;
+        hooks.updateOffset(this);
+        updateInProgress = false;
+    }
+}
+
+export function isMoment (obj) {
+    return obj instanceof Moment || (obj != null && obj._isAMomentObject != null);
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/creation-data.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/creation-data.js
new file mode 100644
index 0000000000000000000000000000000000000000..7e2d69aa1e34be8cc3ef2393077ffbda12dfbb01
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/creation-data.js
@@ -0,0 +1,9 @@
+export function creationData() {
+    return {
+        input: this._i,
+        format: this._f,
+        locale: this._locale,
+        isUTC: this._isUTC,
+        strict: this._strict
+    };
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/diff.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/diff.js
new file mode 100644
index 0000000000000000000000000000000000000000..9f4390818980b1d4fb00d67905fc02fe1f6df809
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/diff.js
@@ -0,0 +1,62 @@
+import absFloor from '../utils/abs-floor';
+import { cloneWithOffset } from '../units/offset';
+import { normalizeUnits } from '../units/aliases';
+
+export function diff (input, units, asFloat) {
+    var that,
+        zoneDelta,
+        delta, output;
+
+    if (!this.isValid()) {
+        return NaN;
+    }
+
+    that = cloneWithOffset(input, this);
+
+    if (!that.isValid()) {
+        return NaN;
+    }
+
+    zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4;
+
+    units = normalizeUnits(units);
+
+    if (units === 'year' || units === 'month' || units === 'quarter') {
+        output = monthDiff(this, that);
+        if (units === 'quarter') {
+            output = output / 3;
+        } else if (units === 'year') {
+            output = output / 12;
+        }
+    } else {
+        delta = this - that;
+        output = units === 'second' ? delta / 1e3 : // 1000
+            units === 'minute' ? delta / 6e4 : // 1000 * 60
+            units === 'hour' ? delta / 36e5 : // 1000 * 60 * 60
+            units === 'day' ? (delta - zoneDelta) / 864e5 : // 1000 * 60 * 60 * 24, negate dst
+            units === 'week' ? (delta - zoneDelta) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst
+            delta;
+    }
+    return asFloat ? output : absFloor(output);
+}
+
+function monthDiff (a, b) {
+    // difference in months
+    var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()),
+        // b is in (anchor - 1 month, anchor + 1 month)
+        anchor = a.clone().add(wholeMonthDiff, 'months'),
+        anchor2, adjust;
+
+    if (b - anchor < 0) {
+        anchor2 = a.clone().add(wholeMonthDiff - 1, 'months');
+        // linear across the month
+        adjust = (b - anchor) / (anchor - anchor2);
+    } else {
+        anchor2 = a.clone().add(wholeMonthDiff + 1, 'months');
+        // linear across the month
+        adjust = (b - anchor) / (anchor2 - anchor);
+    }
+
+    //check for negative zero, return zero if negative zero
+    return -(wholeMonthDiff + adjust) || 0;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/format.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/format.js
new file mode 100644
index 0000000000000000000000000000000000000000..539f6c8e1a0344330474d14f66862dced1e55759
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/format.js
@@ -0,0 +1,56 @@
+import { formatMoment } from '../format/format';
+import { hooks } from '../utils/hooks';
+import isFunction from '../utils/is-function';
+
+hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ';
+hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]';
+
+export function toString () {
+    return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
+}
+
+export function toISOString () {
+    var m = this.clone().utc();
+    if (0 < m.year() && m.year() <= 9999) {
+        if (isFunction(Date.prototype.toISOString)) {
+            // native implementation is ~50x faster, use it when we can
+            return this.toDate().toISOString();
+        } else {
+            return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
+        }
+    } else {
+        return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
+    }
+}
+
+/**
+ * Return a human readable representation of a moment that can
+ * also be evaluated to get a new moment which is the same
+ *
+ * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects
+ */
+export function inspect () {
+    if (!this.isValid()) {
+        return 'moment.invalid(/* ' + this._i + ' */)';
+    }
+    var func = 'moment';
+    var zone = '';
+    if (!this.isLocal()) {
+        func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone';
+        zone = 'Z';
+    }
+    var prefix = '[' + func + '("]';
+    var year = (0 < this.year() && this.year() <= 9999) ? 'YYYY' : 'YYYYYY';
+    var datetime = '-MM-DD[T]HH:mm:ss.SSS';
+    var suffix = zone + '[")]';
+
+    return this.format(prefix + year + datetime + suffix);
+}
+
+export function format (inputString) {
+    if (!inputString) {
+        inputString = this.isUtc() ? hooks.defaultFormatUtc : hooks.defaultFormat;
+    }
+    var output = formatMoment(this, inputString);
+    return this.localeData().postformat(output);
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/from.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/from.js
new file mode 100644
index 0000000000000000000000000000000000000000..4fbd03e438b7e2083379085d5ff25efcc8d41db2
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/from.js
@@ -0,0 +1,17 @@
+import { createDuration } from '../duration/create';
+import { createLocal } from '../create/local';
+import { isMoment } from '../moment/constructor';
+
+export function from (time, withoutSuffix) {
+    if (this.isValid() &&
+            ((isMoment(time) && time.isValid()) ||
+             createLocal(time).isValid())) {
+        return createDuration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix);
+    } else {
+        return this.localeData().invalidDate();
+    }
+}
+
+export function fromNow (withoutSuffix) {
+    return this.from(createLocal(), withoutSuffix);
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/get-set.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/get-set.js
new file mode 100644
index 0000000000000000000000000000000000000000..0d9fe5dfef06c63124251989a4acd721ddb05071
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/get-set.js
@@ -0,0 +1,55 @@
+import { normalizeUnits, normalizeObjectUnits } from '../units/aliases';
+import { getPrioritizedUnits } from '../units/priorities';
+import { hooks } from '../utils/hooks';
+import isFunction from '../utils/is-function';
+
+
+export function makeGetSet (unit, keepTime) {
+    return function (value) {
+        if (value != null) {
+            set(this, unit, value);
+            hooks.updateOffset(this, keepTime);
+            return this;
+        } else {
+            return get(this, unit);
+        }
+    };
+}
+
+export function get (mom, unit) {
+    return mom.isValid() ?
+        mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() : NaN;
+}
+
+export function set (mom, unit, value) {
+    if (mom.isValid()) {
+        mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
+    }
+}
+
+// MOMENTS
+
+export function stringGet (units) {
+    units = normalizeUnits(units);
+    if (isFunction(this[units])) {
+        return this[units]();
+    }
+    return this;
+}
+
+
+export function stringSet (units, value) {
+    if (typeof units === 'object') {
+        units = normalizeObjectUnits(units);
+        var prioritized = getPrioritizedUnits(units);
+        for (var i = 0; i < prioritized.length; i++) {
+            this[prioritized[i].unit](units[prioritized[i].unit]);
+        }
+    } else {
+        units = normalizeUnits(units);
+        if (isFunction(this[units])) {
+            return this[units](value);
+        }
+    }
+    return this;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/locale.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/locale.js
new file mode 100644
index 0000000000000000000000000000000000000000..fb46e6569e8c0d71fb3be0ec23cdf1901acaaf30
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/locale.js
@@ -0,0 +1,34 @@
+import { getLocale } from '../locale/locales';
+import { deprecate } from '../utils/deprecate';
+
+// If passed a locale key, it will set the locale for this
+// instance.  Otherwise, it will return the locale configuration
+// variables for this instance.
+export function locale (key) {
+    var newLocaleData;
+
+    if (key === undefined) {
+        return this._locale._abbr;
+    } else {
+        newLocaleData = getLocale(key);
+        if (newLocaleData != null) {
+            this._locale = newLocaleData;
+        }
+        return this;
+    }
+}
+
+export var lang = deprecate(
+    'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.',
+    function (key) {
+        if (key === undefined) {
+            return this.localeData();
+        } else {
+            return this.locale(key);
+        }
+    }
+);
+
+export function localeData () {
+    return this._locale;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/min-max.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/min-max.js
new file mode 100644
index 0000000000000000000000000000000000000000..d76920a7124127255f16e37f74bcacb1eb49d4cc
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/min-max.js
@@ -0,0 +1,63 @@
+import { deprecate } from '../utils/deprecate';
+import isArray from '../utils/is-array';
+import { createLocal } from '../create/local';
+import { createInvalid } from '../create/valid';
+
+export var prototypeMin = deprecate(
+    'moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/',
+    function () {
+        var other = createLocal.apply(null, arguments);
+        if (this.isValid() && other.isValid()) {
+            return other < this ? this : other;
+        } else {
+            return createInvalid();
+        }
+    }
+);
+
+export var prototypeMax = deprecate(
+    'moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/',
+    function () {
+        var other = createLocal.apply(null, arguments);
+        if (this.isValid() && other.isValid()) {
+            return other > this ? this : other;
+        } else {
+            return createInvalid();
+        }
+    }
+);
+
+// Pick a moment m from moments so that m[fn](other) is true for all
+// other. This relies on the function fn to be transitive.
+//
+// moments should either be an array of moment objects or an array, whose
+// first element is an array of moment objects.
+function pickBy(fn, moments) {
+    var res, i;
+    if (moments.length === 1 && isArray(moments[0])) {
+        moments = moments[0];
+    }
+    if (!moments.length) {
+        return createLocal();
+    }
+    res = moments[0];
+    for (i = 1; i < moments.length; ++i) {
+        if (!moments[i].isValid() || moments[i][fn](res)) {
+            res = moments[i];
+        }
+    }
+    return res;
+}
+
+// TODO: Use [].sort instead?
+export function min () {
+    var args = [].slice.call(arguments, 0);
+
+    return pickBy('isBefore', args);
+}
+
+export function max () {
+    var args = [].slice.call(arguments, 0);
+
+    return pickBy('isAfter', args);
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/moment.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/moment.js
new file mode 100644
index 0000000000000000000000000000000000000000..12eb5f15ab8b8f0047f1bbed599e1d11781ca3c0
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/moment.js
@@ -0,0 +1,28 @@
+import { createLocal } from '../create/local';
+import { createUTC } from '../create/utc';
+import { createInvalid } from '../create/valid';
+import { isMoment } from './constructor';
+import { min, max } from './min-max';
+import { now } from './now';
+import momentPrototype from './prototype';
+
+function createUnix (input) {
+    return createLocal(input * 1000);
+}
+
+function createInZone () {
+    return createLocal.apply(null, arguments).parseZone();
+}
+
+export {
+    now,
+    min,
+    max,
+    isMoment,
+    createUTC,
+    createUnix,
+    createLocal,
+    createInZone,
+    createInvalid,
+    momentPrototype
+};
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/now.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/now.js
new file mode 100644
index 0000000000000000000000000000000000000000..0f4d0aef0c6f20f9704b76f79649b00a753ad398
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/now.js
@@ -0,0 +1,3 @@
+export var now = function () {
+    return Date.now ? Date.now() : +(new Date());
+};
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/prototype.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/prototype.js
new file mode 100644
index 0000000000000000000000000000000000000000..bd8fff79c201e4e588c824e97296cffa14d79981
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/prototype.js
@@ -0,0 +1,150 @@
+import { Moment } from './constructor';
+
+var proto = Moment.prototype;
+
+import { add, subtract } from './add-subtract';
+import { calendar, getCalendarFormat } from './calendar';
+import { clone } from './clone';
+import { isBefore, isBetween, isSame, isAfter, isSameOrAfter, isSameOrBefore } from './compare';
+import { diff } from './diff';
+import { format, toString, toISOString, inspect } from './format';
+import { from, fromNow } from './from';
+import { to, toNow } from './to';
+import { stringGet, stringSet } from './get-set';
+import { locale, localeData, lang } from './locale';
+import { prototypeMin, prototypeMax } from './min-max';
+import { startOf, endOf } from './start-end-of';
+import { valueOf, toDate, toArray, toObject, toJSON, unix } from './to-type';
+import { isValid, parsingFlags, invalidAt } from './valid';
+import { creationData } from './creation-data';
+
+proto.add               = add;
+proto.calendar          = calendar;
+proto.clone             = clone;
+proto.diff              = diff;
+proto.endOf             = endOf;
+proto.format            = format;
+proto.from              = from;
+proto.fromNow           = fromNow;
+proto.to                = to;
+proto.toNow             = toNow;
+proto.get               = stringGet;
+proto.invalidAt         = invalidAt;
+proto.isAfter           = isAfter;
+proto.isBefore          = isBefore;
+proto.isBetween         = isBetween;
+proto.isSame            = isSame;
+proto.isSameOrAfter     = isSameOrAfter;
+proto.isSameOrBefore    = isSameOrBefore;
+proto.isValid           = isValid;
+proto.lang              = lang;
+proto.locale            = locale;
+proto.localeData        = localeData;
+proto.max               = prototypeMax;
+proto.min               = prototypeMin;
+proto.parsingFlags      = parsingFlags;
+proto.set               = stringSet;
+proto.startOf           = startOf;
+proto.subtract          = subtract;
+proto.toArray           = toArray;
+proto.toObject          = toObject;
+proto.toDate            = toDate;
+proto.toISOString       = toISOString;
+proto.inspect           = inspect;
+proto.toJSON            = toJSON;
+proto.toString          = toString;
+proto.unix              = unix;
+proto.valueOf           = valueOf;
+proto.creationData      = creationData;
+
+// Year
+import { getSetYear, getIsLeapYear } from '../units/year';
+proto.year       = getSetYear;
+proto.isLeapYear = getIsLeapYear;
+
+// Week Year
+import { getSetWeekYear, getSetISOWeekYear, getWeeksInYear, getISOWeeksInYear } from '../units/week-year';
+proto.weekYear    = getSetWeekYear;
+proto.isoWeekYear = getSetISOWeekYear;
+
+// Quarter
+import { getSetQuarter } from '../units/quarter';
+proto.quarter = proto.quarters = getSetQuarter;
+
+// Month
+import { getSetMonth, getDaysInMonth } from '../units/month';
+proto.month       = getSetMonth;
+proto.daysInMonth = getDaysInMonth;
+
+// Week
+import { getSetWeek, getSetISOWeek } from '../units/week';
+proto.week           = proto.weeks        = getSetWeek;
+proto.isoWeek        = proto.isoWeeks     = getSetISOWeek;
+proto.weeksInYear    = getWeeksInYear;
+proto.isoWeeksInYear = getISOWeeksInYear;
+
+// Day
+import { getSetDayOfMonth } from '../units/day-of-month';
+import { getSetDayOfWeek, getSetISODayOfWeek, getSetLocaleDayOfWeek } from '../units/day-of-week';
+import { getSetDayOfYear } from '../units/day-of-year';
+proto.date       = getSetDayOfMonth;
+proto.day        = proto.days             = getSetDayOfWeek;
+proto.weekday    = getSetLocaleDayOfWeek;
+proto.isoWeekday = getSetISODayOfWeek;
+proto.dayOfYear  = getSetDayOfYear;
+
+// Hour
+import { getSetHour } from '../units/hour';
+proto.hour = proto.hours = getSetHour;
+
+// Minute
+import { getSetMinute } from '../units/minute';
+proto.minute = proto.minutes = getSetMinute;
+
+// Second
+import { getSetSecond } from '../units/second';
+proto.second = proto.seconds = getSetSecond;
+
+// Millisecond
+import { getSetMillisecond } from '../units/millisecond';
+proto.millisecond = proto.milliseconds = getSetMillisecond;
+
+// Offset
+import {
+    getSetOffset,
+    setOffsetToUTC,
+    setOffsetToLocal,
+    setOffsetToParsedOffset,
+    hasAlignedHourOffset,
+    isDaylightSavingTime,
+    isDaylightSavingTimeShifted,
+    getSetZone,
+    isLocal,
+    isUtcOffset,
+    isUtc
+} from '../units/offset';
+proto.utcOffset            = getSetOffset;
+proto.utc                  = setOffsetToUTC;
+proto.local                = setOffsetToLocal;
+proto.parseZone            = setOffsetToParsedOffset;
+proto.hasAlignedHourOffset = hasAlignedHourOffset;
+proto.isDST                = isDaylightSavingTime;
+proto.isLocal              = isLocal;
+proto.isUtcOffset          = isUtcOffset;
+proto.isUtc                = isUtc;
+proto.isUTC                = isUtc;
+
+// Timezone
+import { getZoneAbbr, getZoneName } from '../units/timezone';
+proto.zoneAbbr = getZoneAbbr;
+proto.zoneName = getZoneName;
+
+// Deprecations
+import { deprecate } from '../utils/deprecate';
+proto.dates  = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth);
+proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth);
+proto.years  = deprecate('years accessor is deprecated. Use year instead', getSetYear);
+proto.zone   = deprecate('moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/', getSetZone);
+proto.isDSTShifted = deprecate('isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information', isDaylightSavingTimeShifted);
+
+export default proto;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/start-end-of.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/start-end-of.js
new file mode 100644
index 0000000000000000000000000000000000000000..02f982479ad8959af97b4ea99812c110c95e3d98
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/start-end-of.js
@@ -0,0 +1,59 @@
+import { normalizeUnits } from '../units/aliases';
+
+export function startOf (units) {
+    units = normalizeUnits(units);
+    // the following switch intentionally omits break keywords
+    // to utilize falling through the cases.
+    switch (units) {
+        case 'year':
+            this.month(0);
+            /* falls through */
+        case 'quarter':
+        case 'month':
+            this.date(1);
+            /* falls through */
+        case 'week':
+        case 'isoWeek':
+        case 'day':
+        case 'date':
+            this.hours(0);
+            /* falls through */
+        case 'hour':
+            this.minutes(0);
+            /* falls through */
+        case 'minute':
+            this.seconds(0);
+            /* falls through */
+        case 'second':
+            this.milliseconds(0);
+    }
+
+    // weeks are a special case
+    if (units === 'week') {
+        this.weekday(0);
+    }
+    if (units === 'isoWeek') {
+        this.isoWeekday(1);
+    }
+
+    // quarters are also special
+    if (units === 'quarter') {
+        this.month(Math.floor(this.month() / 3) * 3);
+    }
+
+    return this;
+}
+
+export function endOf (units) {
+    units = normalizeUnits(units);
+    if (units === undefined || units === 'millisecond') {
+        return this;
+    }
+
+    // 'date' is an alias for 'day', so it should be considered as such.
+    if (units === 'date') {
+        units = 'day';
+    }
+
+    return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms');
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/to-type.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/to-type.js
new file mode 100644
index 0000000000000000000000000000000000000000..a990dd200b3a09a395d8dd97492561a5d47560e1
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/to-type.js
@@ -0,0 +1,34 @@
+export function valueOf () {
+    return this._d.valueOf() - ((this._offset || 0) * 60000);
+}
+
+export function unix () {
+    return Math.floor(this.valueOf() / 1000);
+}
+
+export function toDate () {
+    return new Date(this.valueOf());
+}
+
+export function toArray () {
+    var m = this;
+    return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()];
+}
+
+export function toObject () {
+    var m = this;
+    return {
+        years: m.year(),
+        months: m.month(),
+        date: m.date(),
+        hours: m.hours(),
+        minutes: m.minutes(),
+        seconds: m.seconds(),
+        milliseconds: m.milliseconds()
+    };
+}
+
+export function toJSON () {
+    // new Date(NaN).toJSON() === null
+    return this.isValid() ? this.toISOString() : null;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/to.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/to.js
new file mode 100644
index 0000000000000000000000000000000000000000..7ad667e87f97726e81199b096731e6ff3fd4989f
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/to.js
@@ -0,0 +1,17 @@
+import { createDuration } from '../duration/create';
+import { createLocal } from '../create/local';
+import { isMoment } from '../moment/constructor';
+
+export function to (time, withoutSuffix) {
+    if (this.isValid() &&
+            ((isMoment(time) && time.isValid()) ||
+             createLocal(time).isValid())) {
+        return createDuration({from: this, to: time}).locale(this.locale()).humanize(!withoutSuffix);
+    } else {
+        return this.localeData().invalidDate();
+    }
+}
+
+export function toNow (withoutSuffix) {
+    return this.to(createLocal(), withoutSuffix);
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/valid.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/valid.js
new file mode 100644
index 0000000000000000000000000000000000000000..6c00742938851f5662f4fab5fec82d3daa71824c
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/moment/valid.js
@@ -0,0 +1,15 @@
+import { isValid as _isValid } from '../create/valid';
+import extend from '../utils/extend';
+import getParsingFlags from '../create/parsing-flags';
+
+export function isValid () {
+    return _isValid(this);
+}
+
+export function parsingFlags () {
+    return extend({}, getParsingFlags(this));
+}
+
+export function invalidAt () {
+    return getParsingFlags(this).overflow;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/parse/regex.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/parse/regex.js
new file mode 100644
index 0000000000000000000000000000000000000000..b1dc7529e5c7e2e182191f382217c62da6b16aa8
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/parse/regex.js
@@ -0,0 +1,54 @@
+export var match1         = /\d/;            //       0 - 9
+export var match2         = /\d\d/;          //      00 - 99
+export var match3         = /\d{3}/;         //     000 - 999
+export var match4         = /\d{4}/;         //    0000 - 9999
+export var match6         = /[+-]?\d{6}/;    // -999999 - 999999
+export var match1to2      = /\d\d?/;         //       0 - 99
+export var match3to4      = /\d\d\d\d?/;     //     999 - 9999
+export var match5to6      = /\d\d\d\d\d\d?/; //   99999 - 999999
+export var match1to3      = /\d{1,3}/;       //       0 - 999
+export var match1to4      = /\d{1,4}/;       //       0 - 9999
+export var match1to6      = /[+-]?\d{1,6}/;  // -999999 - 999999
+
+export var matchUnsigned  = /\d+/;           //       0 - inf
+export var matchSigned    = /[+-]?\d+/;      //    -inf - inf
+
+export var matchOffset    = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z
+export var matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi; // +00 -00 +00:00 -00:00 +0000 -0000 or Z
+
+export var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123
+
+// any word (or two) characters or numbers including two/three word month in arabic.
+// includes scottish gaelic two word and hyphenated months
+export var matchWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i;
+
+
+import hasOwnProp from '../utils/has-own-prop';
+import isFunction from '../utils/is-function';
+
+var regexes = {};
+
+export function addRegexToken (token, regex, strictRegex) {
+    regexes[token] = isFunction(regex) ? regex : function (isStrict, localeData) {
+        return (isStrict && strictRegex) ? strictRegex : regex;
+    };
+}
+
+export function getParseRegexForToken (token, config) {
+    if (!hasOwnProp(regexes, token)) {
+        return new RegExp(unescapeFormat(token));
+    }
+
+    return regexes[token](config._strict, config._locale);
+}
+
+// Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
+function unescapeFormat(s) {
+    return regexEscape(s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
+        return p1 || p2 || p3 || p4;
+    }));
+}
+
+export function regexEscape(s) {
+    return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/parse/token.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/parse/token.js
new file mode 100644
index 0000000000000000000000000000000000000000..24b4474f87e2416f5c1920e0f5263de0a14053b3
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/parse/token.js
@@ -0,0 +1,33 @@
+import hasOwnProp from '../utils/has-own-prop';
+import isNumber from '../utils/is-number';
+import toInt from '../utils/to-int';
+
+var tokens = {};
+
+export function addParseToken (token, callback) {
+    var i, func = callback;
+    if (typeof token === 'string') {
+        token = [token];
+    }
+    if (isNumber(callback)) {
+        func = function (input, array) {
+            array[callback] = toInt(input);
+        };
+    }
+    for (i = 0; i < token.length; i++) {
+        tokens[token[i]] = func;
+    }
+}
+
+export function addWeekParseToken (token, callback) {
+    addParseToken(token, function (input, array, config, token) {
+        config._w = config._w || {};
+        callback(input, config._w, config, token);
+    });
+}
+
+export function addTimeToArrayFromToken(token, input, config) {
+    if (input != null && hasOwnProp(tokens, token)) {
+        tokens[token](input, config._a, config, token);
+    }
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/aliases.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/aliases.js
new file mode 100644
index 0000000000000000000000000000000000000000..0d8b88a138b8c01d925d926ab8f6df5e0cc0b76e
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/aliases.js
@@ -0,0 +1,30 @@
+import hasOwnProp from '../utils/has-own-prop';
+
+var aliases = {};
+
+export function addUnitAlias (unit, shorthand) {
+    var lowerCase = unit.toLowerCase();
+    aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit;
+}
+
+export function normalizeUnits(units) {
+    return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined;
+}
+
+export function normalizeObjectUnits(inputObject) {
+    var normalizedInput = {},
+        normalizedProp,
+        prop;
+
+    for (prop in inputObject) {
+        if (hasOwnProp(inputObject, prop)) {
+            normalizedProp = normalizeUnits(prop);
+            if (normalizedProp) {
+                normalizedInput[normalizedProp] = inputObject[prop];
+            }
+        }
+    }
+
+    return normalizedInput;
+}
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/constants.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/constants.js
new file mode 100644
index 0000000000000000000000000000000000000000..70bf1b26ede2c1fcb9e0ce1a1f6a36142d32312a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/constants.js
@@ -0,0 +1,9 @@
+export var YEAR = 0;
+export var MONTH = 1;
+export var DATE = 2;
+export var HOUR = 3;
+export var MINUTE = 4;
+export var SECOND = 5;
+export var MILLISECOND = 6;
+export var WEEK = 7;
+export var WEEKDAY = 8;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/day-of-month.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/day-of-month.js
new file mode 100644
index 0000000000000000000000000000000000000000..e28ec9f4dd48dc2861de21e57736df0238a40193
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/day-of-month.js
@@ -0,0 +1,36 @@
+import { makeGetSet } from '../moment/get-set';
+import { addFormatToken } from '../format/format';
+import { addUnitAlias } from './aliases';
+import { addUnitPriority } from './priorities';
+import { addRegexToken, match1to2, match2 } from '../parse/regex';
+import { addParseToken } from '../parse/token';
+import { DATE } from './constants';
+import toInt from '../utils/to-int';
+
+// FORMATTING
+
+addFormatToken('D', ['DD', 2], 'Do', 'date');
+
+// ALIASES
+
+addUnitAlias('date', 'D');
+
+// PRIOROITY
+addUnitPriority('date', 9);
+
+// PARSING
+
+addRegexToken('D',  match1to2);
+addRegexToken('DD', match1to2, match2);
+addRegexToken('Do', function (isStrict, locale) {
+    return isStrict ? locale._ordinalParse : locale._ordinalParseLenient;
+});
+
+addParseToken(['D', 'DD'], DATE);
+addParseToken('Do', function (input, array) {
+    array[DATE] = toInt(input.match(match1to2)[0], 10);
+});
+
+// MOMENTS
+
+export var getSetDayOfMonth = makeGetSet('Date', true);
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/day-of-week.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/day-of-week.js
new file mode 100644
index 0000000000000000000000000000000000000000..603192e289826be321687db6fa6f119d0e6b625b
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/day-of-week.js
@@ -0,0 +1,363 @@
+import { addFormatToken } from '../format/format';
+import { addUnitAlias } from './aliases';
+import { addUnitPriority } from './priorities';
+import { addRegexToken, match1to2, matchWord, regexEscape } from '../parse/regex';
+import { addWeekParseToken } from '../parse/token';
+import toInt from '../utils/to-int';
+import isArray from '../utils/is-array';
+import indexOf from '../utils/index-of';
+import hasOwnProp from '../utils/has-own-prop';
+import { createUTC } from '../create/utc';
+import getParsingFlags from '../create/parsing-flags';
+
+// FORMATTING
+
+addFormatToken('d', 0, 'do', 'day');
+
+addFormatToken('dd', 0, 0, function (format) {
+    return this.localeData().weekdaysMin(this, format);
+});
+
+addFormatToken('ddd', 0, 0, function (format) {
+    return this.localeData().weekdaysShort(this, format);
+});
+
+addFormatToken('dddd', 0, 0, function (format) {
+    return this.localeData().weekdays(this, format);
+});
+
+addFormatToken('e', 0, 0, 'weekday');
+addFormatToken('E', 0, 0, 'isoWeekday');
+
+// ALIASES
+
+addUnitAlias('day', 'd');
+addUnitAlias('weekday', 'e');
+addUnitAlias('isoWeekday', 'E');
+
+// PRIORITY
+addUnitPriority('day', 11);
+addUnitPriority('weekday', 11);
+addUnitPriority('isoWeekday', 11);
+
+// PARSING
+
+addRegexToken('d',    match1to2);
+addRegexToken('e',    match1to2);
+addRegexToken('E',    match1to2);
+addRegexToken('dd',   function (isStrict, locale) {
+    return locale.weekdaysMinRegex(isStrict);
+});
+addRegexToken('ddd',   function (isStrict, locale) {
+    return locale.weekdaysShortRegex(isStrict);
+});
+addRegexToken('dddd',   function (isStrict, locale) {
+    return locale.weekdaysRegex(isStrict);
+});
+
+addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) {
+    var weekday = config._locale.weekdaysParse(input, token, config._strict);
+    // if we didn't get a weekday name, mark the date as invalid
+    if (weekday != null) {
+        week.d = weekday;
+    } else {
+        getParsingFlags(config).invalidWeekday = input;
+    }
+});
+
+addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) {
+    week[token] = toInt(input);
+});
+
+// HELPERS
+
+function parseWeekday(input, locale) {
+    if (typeof input !== 'string') {
+        return input;
+    }
+
+    if (!isNaN(input)) {
+        return parseInt(input, 10);
+    }
+
+    input = locale.weekdaysParse(input);
+    if (typeof input === 'number') {
+        return input;
+    }
+
+    return null;
+}
+
+function parseIsoWeekday(input, locale) {
+    if (typeof input === 'string') {
+        return locale.weekdaysParse(input) % 7 || 7;
+    }
+    return isNaN(input) ? null : input;
+}
+
+// LOCALES
+
+export var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_');
+export function localeWeekdays (m, format) {
+    if (!m) {
+        return this._weekdays;
+    }
+    return isArray(this._weekdays) ? this._weekdays[m.day()] :
+        this._weekdays[this._weekdays.isFormat.test(format) ? 'format' : 'standalone'][m.day()];
+}
+
+export var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_');
+export function localeWeekdaysShort (m) {
+    return (m) ? this._weekdaysShort[m.day()] : this._weekdaysShort;
+}
+
+export var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_');
+export function localeWeekdaysMin (m) {
+    return (m) ? this._weekdaysMin[m.day()] : this._weekdaysMin;
+}
+
+function handleStrictParse(weekdayName, format, strict) {
+    var i, ii, mom, llc = weekdayName.toLocaleLowerCase();
+    if (!this._weekdaysParse) {
+        this._weekdaysParse = [];
+        this._shortWeekdaysParse = [];
+        this._minWeekdaysParse = [];
+
+        for (i = 0; i < 7; ++i) {
+            mom = createUTC([2000, 1]).day(i);
+            this._minWeekdaysParse[i] = this.weekdaysMin(mom, '').toLocaleLowerCase();
+            this._shortWeekdaysParse[i] = this.weekdaysShort(mom, '').toLocaleLowerCase();
+            this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase();
+        }
+    }
+
+    if (strict) {
+        if (format === 'dddd') {
+            ii = indexOf.call(this._weekdaysParse, llc);
+            return ii !== -1 ? ii : null;
+        } else if (format === 'ddd') {
+            ii = indexOf.call(this._shortWeekdaysParse, llc);
+            return ii !== -1 ? ii : null;
+        } else {
+            ii = indexOf.call(this._minWeekdaysParse, llc);
+            return ii !== -1 ? ii : null;
+        }
+    } else {
+        if (format === 'dddd') {
+            ii = indexOf.call(this._weekdaysParse, llc);
+            if (ii !== -1) {
+                return ii;
+            }
+            ii = indexOf.call(this._shortWeekdaysParse, llc);
+            if (ii !== -1) {
+                return ii;
+            }
+            ii = indexOf.call(this._minWeekdaysParse, llc);
+            return ii !== -1 ? ii : null;
+        } else if (format === 'ddd') {
+            ii = indexOf.call(this._shortWeekdaysParse, llc);
+            if (ii !== -1) {
+                return ii;
+            }
+            ii = indexOf.call(this._weekdaysParse, llc);
+            if (ii !== -1) {
+                return ii;
+            }
+            ii = indexOf.call(this._minWeekdaysParse, llc);
+            return ii !== -1 ? ii : null;
+        } else {
+            ii = indexOf.call(this._minWeekdaysParse, llc);
+            if (ii !== -1) {
+                return ii;
+            }
+            ii = indexOf.call(this._weekdaysParse, llc);
+            if (ii !== -1) {
+                return ii;
+            }
+            ii = indexOf.call(this._shortWeekdaysParse, llc);
+            return ii !== -1 ? ii : null;
+        }
+    }
+}
+
+export function localeWeekdaysParse (weekdayName, format, strict) {
+    var i, mom, regex;
+
+    if (this._weekdaysParseExact) {
+        return handleStrictParse.call(this, weekdayName, format, strict);
+    }
+
+    if (!this._weekdaysParse) {
+        this._weekdaysParse = [];
+        this._minWeekdaysParse = [];
+        this._shortWeekdaysParse = [];
+        this._fullWeekdaysParse = [];
+    }
+
+    for (i = 0; i < 7; i++) {
+        // make the regex if we don't have it already
+
+        mom = createUTC([2000, 1]).day(i);
+        if (strict && !this._fullWeekdaysParse[i]) {
+            this._fullWeekdaysParse[i] = new RegExp('^' + this.weekdays(mom, '').replace('.', '\.?') + '$', 'i');
+            this._shortWeekdaysParse[i] = new RegExp('^' + this.weekdaysShort(mom, '').replace('.', '\.?') + '$', 'i');
+            this._minWeekdaysParse[i] = new RegExp('^' + this.weekdaysMin(mom, '').replace('.', '\.?') + '$', 'i');
+        }
+        if (!this._weekdaysParse[i]) {
+            regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
+            this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
+        }
+        // test the regex
+        if (strict && format === 'dddd' && this._fullWeekdaysParse[i].test(weekdayName)) {
+            return i;
+        } else if (strict && format === 'ddd' && this._shortWeekdaysParse[i].test(weekdayName)) {
+            return i;
+        } else if (strict && format === 'dd' && this._minWeekdaysParse[i].test(weekdayName)) {
+            return i;
+        } else if (!strict && this._weekdaysParse[i].test(weekdayName)) {
+            return i;
+        }
+    }
+}
+
+// MOMENTS
+
+export function getSetDayOfWeek (input) {
+    if (!this.isValid()) {
+        return input != null ? this : NaN;
+    }
+    var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
+    if (input != null) {
+        input = parseWeekday(input, this.localeData());
+        return this.add(input - day, 'd');
+    } else {
+        return day;
+    }
+}
+
+export function getSetLocaleDayOfWeek (input) {
+    if (!this.isValid()) {
+        return input != null ? this : NaN;
+    }
+    var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;
+    return input == null ? weekday : this.add(input - weekday, 'd');
+}
+
+export function getSetISODayOfWeek (input) {
+    if (!this.isValid()) {
+        return input != null ? this : NaN;
+    }
+
+    // behaves the same as moment#day except
+    // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
+    // as a setter, sunday should belong to the previous week.
+
+    if (input != null) {
+        var weekday = parseIsoWeekday(input, this.localeData());
+        return this.day(this.day() % 7 ? weekday : weekday - 7);
+    } else {
+        return this.day() || 7;
+    }
+}
+
+var defaultWeekdaysRegex = matchWord;
+export function weekdaysRegex (isStrict) {
+    if (this._weekdaysParseExact) {
+        if (!hasOwnProp(this, '_weekdaysRegex')) {
+            computeWeekdaysParse.call(this);
+        }
+        if (isStrict) {
+            return this._weekdaysStrictRegex;
+        } else {
+            return this._weekdaysRegex;
+        }
+    } else {
+        if (!hasOwnProp(this, '_weekdaysRegex')) {
+            this._weekdaysRegex = defaultWeekdaysRegex;
+        }
+        return this._weekdaysStrictRegex && isStrict ?
+            this._weekdaysStrictRegex : this._weekdaysRegex;
+    }
+}
+
+var defaultWeekdaysShortRegex = matchWord;
+export function weekdaysShortRegex (isStrict) {
+    if (this._weekdaysParseExact) {
+        if (!hasOwnProp(this, '_weekdaysRegex')) {
+            computeWeekdaysParse.call(this);
+        }
+        if (isStrict) {
+            return this._weekdaysShortStrictRegex;
+        } else {
+            return this._weekdaysShortRegex;
+        }
+    } else {
+        if (!hasOwnProp(this, '_weekdaysShortRegex')) {
+            this._weekdaysShortRegex = defaultWeekdaysShortRegex;
+        }
+        return this._weekdaysShortStrictRegex && isStrict ?
+            this._weekdaysShortStrictRegex : this._weekdaysShortRegex;
+    }
+}
+
+var defaultWeekdaysMinRegex = matchWord;
+export function weekdaysMinRegex (isStrict) {
+    if (this._weekdaysParseExact) {
+        if (!hasOwnProp(this, '_weekdaysRegex')) {
+            computeWeekdaysParse.call(this);
+        }
+        if (isStrict) {
+            return this._weekdaysMinStrictRegex;
+        } else {
+            return this._weekdaysMinRegex;
+        }
+    } else {
+        if (!hasOwnProp(this, '_weekdaysMinRegex')) {
+            this._weekdaysMinRegex = defaultWeekdaysMinRegex;
+        }
+        return this._weekdaysMinStrictRegex && isStrict ?
+            this._weekdaysMinStrictRegex : this._weekdaysMinRegex;
+    }
+}
+
+
+function computeWeekdaysParse () {
+    function cmpLenRev(a, b) {
+        return b.length - a.length;
+    }
+
+    var minPieces = [], shortPieces = [], longPieces = [], mixedPieces = [],
+        i, mom, minp, shortp, longp;
+    for (i = 0; i < 7; i++) {
+        // make the regex if we don't have it already
+        mom = createUTC([2000, 1]).day(i);
+        minp = this.weekdaysMin(mom, '');
+        shortp = this.weekdaysShort(mom, '');
+        longp = this.weekdays(mom, '');
+        minPieces.push(minp);
+        shortPieces.push(shortp);
+        longPieces.push(longp);
+        mixedPieces.push(minp);
+        mixedPieces.push(shortp);
+        mixedPieces.push(longp);
+    }
+    // Sorting makes sure if one weekday (or abbr) is a prefix of another it
+    // will match the longer piece.
+    minPieces.sort(cmpLenRev);
+    shortPieces.sort(cmpLenRev);
+    longPieces.sort(cmpLenRev);
+    mixedPieces.sort(cmpLenRev);
+    for (i = 0; i < 7; i++) {
+        shortPieces[i] = regexEscape(shortPieces[i]);
+        longPieces[i] = regexEscape(longPieces[i]);
+        mixedPieces[i] = regexEscape(mixedPieces[i]);
+    }
+
+    this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
+    this._weekdaysShortRegex = this._weekdaysRegex;
+    this._weekdaysMinRegex = this._weekdaysRegex;
+
+    this._weekdaysStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
+    this._weekdaysShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
+    this._weekdaysMinStrictRegex = new RegExp('^(' + minPieces.join('|') + ')', 'i');
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/day-of-year.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/day-of-year.js
new file mode 100644
index 0000000000000000000000000000000000000000..6fe931c1e46fbe36794d9b30d0f55c3ebac521bd
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/day-of-year.js
@@ -0,0 +1,36 @@
+import { addFormatToken } from '../format/format';
+import { addUnitAlias } from './aliases';
+import { addUnitPriority } from './priorities';
+import { addRegexToken, match3, match1to3 } from '../parse/regex';
+import { daysInYear } from './year';
+import { createUTCDate } from '../create/date-from-array';
+import { addParseToken } from '../parse/token';
+import toInt from '../utils/to-int';
+
+// FORMATTING
+
+addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear');
+
+// ALIASES
+
+addUnitAlias('dayOfYear', 'DDD');
+
+// PRIORITY
+addUnitPriority('dayOfYear', 4);
+
+// PARSING
+
+addRegexToken('DDD',  match1to3);
+addRegexToken('DDDD', match3);
+addParseToken(['DDD', 'DDDD'], function (input, array, config) {
+    config._dayOfYear = toInt(input);
+});
+
+// HELPERS
+
+// MOMENTS
+
+export function getSetDayOfYear (input) {
+    var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1;
+    return input == null ? dayOfYear : this.add((input - dayOfYear), 'd');
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/hour.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/hour.js
new file mode 100644
index 0000000000000000000000000000000000000000..d5733fbbcfa38d6fd48ddd8a2c455cf34baea9bb
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/hour.js
@@ -0,0 +1,138 @@
+import { makeGetSet } from '../moment/get-set';
+import { addFormatToken } from '../format/format';
+import { addUnitAlias } from './aliases';
+import { addUnitPriority } from './priorities';
+import { addRegexToken, match1to2, match2, match3to4, match5to6 } from '../parse/regex';
+import { addParseToken } from '../parse/token';
+import { HOUR, MINUTE, SECOND } from './constants';
+import toInt from '../utils/to-int';
+import zeroFill from '../utils/zero-fill';
+import getParsingFlags from '../create/parsing-flags';
+
+// FORMATTING
+
+function hFormat() {
+    return this.hours() % 12 || 12;
+}
+
+function kFormat() {
+    return this.hours() || 24;
+}
+
+addFormatToken('H', ['HH', 2], 0, 'hour');
+addFormatToken('h', ['hh', 2], 0, hFormat);
+addFormatToken('k', ['kk', 2], 0, kFormat);
+
+addFormatToken('hmm', 0, 0, function () {
+    return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2);
+});
+
+addFormatToken('hmmss', 0, 0, function () {
+    return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2) +
+        zeroFill(this.seconds(), 2);
+});
+
+addFormatToken('Hmm', 0, 0, function () {
+    return '' + this.hours() + zeroFill(this.minutes(), 2);
+});
+
+addFormatToken('Hmmss', 0, 0, function () {
+    return '' + this.hours() + zeroFill(this.minutes(), 2) +
+        zeroFill(this.seconds(), 2);
+});
+
+function meridiem (token, lowercase) {
+    addFormatToken(token, 0, 0, function () {
+        return this.localeData().meridiem(this.hours(), this.minutes(), lowercase);
+    });
+}
+
+meridiem('a', true);
+meridiem('A', false);
+
+// ALIASES
+
+addUnitAlias('hour', 'h');
+
+// PRIORITY
+addUnitPriority('hour', 13);
+
+// PARSING
+
+function matchMeridiem (isStrict, locale) {
+    return locale._meridiemParse;
+}
+
+addRegexToken('a',  matchMeridiem);
+addRegexToken('A',  matchMeridiem);
+addRegexToken('H',  match1to2);
+addRegexToken('h',  match1to2);
+addRegexToken('HH', match1to2, match2);
+addRegexToken('hh', match1to2, match2);
+
+addRegexToken('hmm', match3to4);
+addRegexToken('hmmss', match5to6);
+addRegexToken('Hmm', match3to4);
+addRegexToken('Hmmss', match5to6);
+
+addParseToken(['H', 'HH'], HOUR);
+addParseToken(['a', 'A'], function (input, array, config) {
+    config._isPm = config._locale.isPM(input);
+    config._meridiem = input;
+});
+addParseToken(['h', 'hh'], function (input, array, config) {
+    array[HOUR] = toInt(input);
+    getParsingFlags(config).bigHour = true;
+});
+addParseToken('hmm', function (input, array, config) {
+    var pos = input.length - 2;
+    array[HOUR] = toInt(input.substr(0, pos));
+    array[MINUTE] = toInt(input.substr(pos));
+    getParsingFlags(config).bigHour = true;
+});
+addParseToken('hmmss', function (input, array, config) {
+    var pos1 = input.length - 4;
+    var pos2 = input.length - 2;
+    array[HOUR] = toInt(input.substr(0, pos1));
+    array[MINUTE] = toInt(input.substr(pos1, 2));
+    array[SECOND] = toInt(input.substr(pos2));
+    getParsingFlags(config).bigHour = true;
+});
+addParseToken('Hmm', function (input, array, config) {
+    var pos = input.length - 2;
+    array[HOUR] = toInt(input.substr(0, pos));
+    array[MINUTE] = toInt(input.substr(pos));
+});
+addParseToken('Hmmss', function (input, array, config) {
+    var pos1 = input.length - 4;
+    var pos2 = input.length - 2;
+    array[HOUR] = toInt(input.substr(0, pos1));
+    array[MINUTE] = toInt(input.substr(pos1, 2));
+    array[SECOND] = toInt(input.substr(pos2));
+});
+
+// LOCALES
+
+export function localeIsPM (input) {
+    // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
+    // Using charAt should be more compatible.
+    return ((input + '').toLowerCase().charAt(0) === 'p');
+}
+
+export var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i;
+export function localeMeridiem (hours, minutes, isLower) {
+    if (hours > 11) {
+        return isLower ? 'pm' : 'PM';
+    } else {
+        return isLower ? 'am' : 'AM';
+    }
+}
+
+
+// MOMENTS
+
+// Setting the hour should keep the time, because the user explicitly
+// specified which hour he wants. So trying to maintain the same hour (in
+// a new timezone) makes sense. Adding/subtracting hours does not follow
+// this rule.
+export var getSetHour = makeGetSet('Hours', true);
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/millisecond.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/millisecond.js
new file mode 100644
index 0000000000000000000000000000000000000000..27c951269360e0498145fbf04d6c6de4e7950144
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/millisecond.js
@@ -0,0 +1,69 @@
+import { makeGetSet } from '../moment/get-set';
+import { addFormatToken } from '../format/format';
+import { addUnitAlias } from './aliases';
+import { addUnitPriority } from './priorities';
+import { addRegexToken, match1, match2, match3, match1to3, matchUnsigned } from '../parse/regex';
+import { addParseToken } from '../parse/token';
+import { MILLISECOND } from './constants';
+import toInt from '../utils/to-int';
+
+// FORMATTING
+
+addFormatToken('S', 0, 0, function () {
+    return ~~(this.millisecond() / 100);
+});
+
+addFormatToken(0, ['SS', 2], 0, function () {
+    return ~~(this.millisecond() / 10);
+});
+
+addFormatToken(0, ['SSS', 3], 0, 'millisecond');
+addFormatToken(0, ['SSSS', 4], 0, function () {
+    return this.millisecond() * 10;
+});
+addFormatToken(0, ['SSSSS', 5], 0, function () {
+    return this.millisecond() * 100;
+});
+addFormatToken(0, ['SSSSSS', 6], 0, function () {
+    return this.millisecond() * 1000;
+});
+addFormatToken(0, ['SSSSSSS', 7], 0, function () {
+    return this.millisecond() * 10000;
+});
+addFormatToken(0, ['SSSSSSSS', 8], 0, function () {
+    return this.millisecond() * 100000;
+});
+addFormatToken(0, ['SSSSSSSSS', 9], 0, function () {
+    return this.millisecond() * 1000000;
+});
+
+
+// ALIASES
+
+addUnitAlias('millisecond', 'ms');
+
+// PRIORITY
+
+addUnitPriority('millisecond', 16);
+
+// PARSING
+
+addRegexToken('S',    match1to3, match1);
+addRegexToken('SS',   match1to3, match2);
+addRegexToken('SSS',  match1to3, match3);
+
+var token;
+for (token = 'SSSS'; token.length <= 9; token += 'S') {
+    addRegexToken(token, matchUnsigned);
+}
+
+function parseMs(input, array) {
+    array[MILLISECOND] = toInt(('0.' + input) * 1000);
+}
+
+for (token = 'S'; token.length <= 9; token += 'S') {
+    addParseToken(token, parseMs);
+}
+// MOMENTS
+
+export var getSetMillisecond = makeGetSet('Milliseconds', false);
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/minute.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/minute.js
new file mode 100644
index 0000000000000000000000000000000000000000..9f760322e1340536235dc71fd9d71cd968effde2
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/minute.js
@@ -0,0 +1,29 @@
+import { makeGetSet } from '../moment/get-set';
+import { addFormatToken } from '../format/format';
+import { addUnitAlias } from './aliases';
+import { addUnitPriority } from './priorities';
+import { addRegexToken, match1to2, match2 } from '../parse/regex';
+import { addParseToken } from '../parse/token';
+import { MINUTE } from './constants';
+
+// FORMATTING
+
+addFormatToken('m', ['mm', 2], 0, 'minute');
+
+// ALIASES
+
+addUnitAlias('minute', 'm');
+
+// PRIORITY
+
+addUnitPriority('minute', 14);
+
+// PARSING
+
+addRegexToken('m',  match1to2);
+addRegexToken('mm', match1to2, match2);
+addParseToken(['m', 'mm'], MINUTE);
+
+// MOMENTS
+
+export var getSetMinute = makeGetSet('Minutes', false);
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/month.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/month.js
new file mode 100644
index 0000000000000000000000000000000000000000..e454d678a1377969f8a967dd92a0ea6c7b1728e9
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/month.js
@@ -0,0 +1,281 @@
+import { get } from '../moment/get-set';
+import hasOwnProp from '../utils/has-own-prop';
+import { addFormatToken } from '../format/format';
+import { addUnitAlias } from './aliases';
+import { addUnitPriority } from './priorities';
+import { addRegexToken, match1to2, match2, matchWord, regexEscape } from '../parse/regex';
+import { addParseToken } from '../parse/token';
+import { hooks } from '../utils/hooks';
+import { MONTH } from './constants';
+import toInt from '../utils/to-int';
+import isArray from '../utils/is-array';
+import isNumber from '../utils/is-number';
+import indexOf from '../utils/index-of';
+import { createUTC } from '../create/utc';
+import getParsingFlags from '../create/parsing-flags';
+
+export function daysInMonth(year, month) {
+    return new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
+}
+
+// FORMATTING
+
+addFormatToken('M', ['MM', 2], 'Mo', function () {
+    return this.month() + 1;
+});
+
+addFormatToken('MMM', 0, 0, function (format) {
+    return this.localeData().monthsShort(this, format);
+});
+
+addFormatToken('MMMM', 0, 0, function (format) {
+    return this.localeData().months(this, format);
+});
+
+// ALIASES
+
+addUnitAlias('month', 'M');
+
+// PRIORITY
+
+addUnitPriority('month', 8);
+
+// PARSING
+
+addRegexToken('M',    match1to2);
+addRegexToken('MM',   match1to2, match2);
+addRegexToken('MMM',  function (isStrict, locale) {
+    return locale.monthsShortRegex(isStrict);
+});
+addRegexToken('MMMM', function (isStrict, locale) {
+    return locale.monthsRegex(isStrict);
+});
+
+addParseToken(['M', 'MM'], function (input, array) {
+    array[MONTH] = toInt(input) - 1;
+});
+
+addParseToken(['MMM', 'MMMM'], function (input, array, config, token) {
+    var month = config._locale.monthsParse(input, token, config._strict);
+    // if we didn't find a month name, mark the date as invalid.
+    if (month != null) {
+        array[MONTH] = month;
+    } else {
+        getParsingFlags(config).invalidMonth = input;
+    }
+});
+
+// LOCALES
+
+var MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/;
+export var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_');
+export function localeMonths (m, format) {
+    if (!m) {
+        return this._months;
+    }
+    return isArray(this._months) ? this._months[m.month()] :
+        this._months[(this._months.isFormat || MONTHS_IN_FORMAT).test(format) ? 'format' : 'standalone'][m.month()];
+}
+
+export var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_');
+export function localeMonthsShort (m, format) {
+    if (!m) {
+        return this._monthsShort;
+    }
+    return isArray(this._monthsShort) ? this._monthsShort[m.month()] :
+        this._monthsShort[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()];
+}
+
+function handleStrictParse(monthName, format, strict) {
+    var i, ii, mom, llc = monthName.toLocaleLowerCase();
+    if (!this._monthsParse) {
+        // this is not used
+        this._monthsParse = [];
+        this._longMonthsParse = [];
+        this._shortMonthsParse = [];
+        for (i = 0; i < 12; ++i) {
+            mom = createUTC([2000, i]);
+            this._shortMonthsParse[i] = this.monthsShort(mom, '').toLocaleLowerCase();
+            this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase();
+        }
+    }
+
+    if (strict) {
+        if (format === 'MMM') {
+            ii = indexOf.call(this._shortMonthsParse, llc);
+            return ii !== -1 ? ii : null;
+        } else {
+            ii = indexOf.call(this._longMonthsParse, llc);
+            return ii !== -1 ? ii : null;
+        }
+    } else {
+        if (format === 'MMM') {
+            ii = indexOf.call(this._shortMonthsParse, llc);
+            if (ii !== -1) {
+                return ii;
+            }
+            ii = indexOf.call(this._longMonthsParse, llc);
+            return ii !== -1 ? ii : null;
+        } else {
+            ii = indexOf.call(this._longMonthsParse, llc);
+            if (ii !== -1) {
+                return ii;
+            }
+            ii = indexOf.call(this._shortMonthsParse, llc);
+            return ii !== -1 ? ii : null;
+        }
+    }
+}
+
+export function localeMonthsParse (monthName, format, strict) {
+    var i, mom, regex;
+
+    if (this._monthsParseExact) {
+        return handleStrictParse.call(this, monthName, format, strict);
+    }
+
+    if (!this._monthsParse) {
+        this._monthsParse = [];
+        this._longMonthsParse = [];
+        this._shortMonthsParse = [];
+    }
+
+    // TODO: add sorting
+    // Sorting makes sure if one month (or abbr) is a prefix of another
+    // see sorting in computeMonthsParse
+    for (i = 0; i < 12; i++) {
+        // make the regex if we don't have it already
+        mom = createUTC([2000, i]);
+        if (strict && !this._longMonthsParse[i]) {
+            this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');
+            this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');
+        }
+        if (!strict && !this._monthsParse[i]) {
+            regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
+            this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
+        }
+        // test the regex
+        if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {
+            return i;
+        } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {
+            return i;
+        } else if (!strict && this._monthsParse[i].test(monthName)) {
+            return i;
+        }
+    }
+}
+
+// MOMENTS
+
+export function setMonth (mom, value) {
+    var dayOfMonth;
+
+    if (!mom.isValid()) {
+        // No op
+        return mom;
+    }
+
+    if (typeof value === 'string') {
+        if (/^\d+$/.test(value)) {
+            value = toInt(value);
+        } else {
+            value = mom.localeData().monthsParse(value);
+            // TODO: Another silent failure?
+            if (!isNumber(value)) {
+                return mom;
+            }
+        }
+    }
+
+    dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));
+    mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
+    return mom;
+}
+
+export function getSetMonth (value) {
+    if (value != null) {
+        setMonth(this, value);
+        hooks.updateOffset(this, true);
+        return this;
+    } else {
+        return get(this, 'Month');
+    }
+}
+
+export function getDaysInMonth () {
+    return daysInMonth(this.year(), this.month());
+}
+
+var defaultMonthsShortRegex = matchWord;
+export function monthsShortRegex (isStrict) {
+    if (this._monthsParseExact) {
+        if (!hasOwnProp(this, '_monthsRegex')) {
+            computeMonthsParse.call(this);
+        }
+        if (isStrict) {
+            return this._monthsShortStrictRegex;
+        } else {
+            return this._monthsShortRegex;
+        }
+    } else {
+        if (!hasOwnProp(this, '_monthsShortRegex')) {
+            this._monthsShortRegex = defaultMonthsShortRegex;
+        }
+        return this._monthsShortStrictRegex && isStrict ?
+            this._monthsShortStrictRegex : this._monthsShortRegex;
+    }
+}
+
+var defaultMonthsRegex = matchWord;
+export function monthsRegex (isStrict) {
+    if (this._monthsParseExact) {
+        if (!hasOwnProp(this, '_monthsRegex')) {
+            computeMonthsParse.call(this);
+        }
+        if (isStrict) {
+            return this._monthsStrictRegex;
+        } else {
+            return this._monthsRegex;
+        }
+    } else {
+        if (!hasOwnProp(this, '_monthsRegex')) {
+            this._monthsRegex = defaultMonthsRegex;
+        }
+        return this._monthsStrictRegex && isStrict ?
+            this._monthsStrictRegex : this._monthsRegex;
+    }
+}
+
+function computeMonthsParse () {
+    function cmpLenRev(a, b) {
+        return b.length - a.length;
+    }
+
+    var shortPieces = [], longPieces = [], mixedPieces = [],
+        i, mom;
+    for (i = 0; i < 12; i++) {
+        // make the regex if we don't have it already
+        mom = createUTC([2000, i]);
+        shortPieces.push(this.monthsShort(mom, ''));
+        longPieces.push(this.months(mom, ''));
+        mixedPieces.push(this.months(mom, ''));
+        mixedPieces.push(this.monthsShort(mom, ''));
+    }
+    // Sorting makes sure if one month (or abbr) is a prefix of another it
+    // will match the longer piece.
+    shortPieces.sort(cmpLenRev);
+    longPieces.sort(cmpLenRev);
+    mixedPieces.sort(cmpLenRev);
+    for (i = 0; i < 12; i++) {
+        shortPieces[i] = regexEscape(shortPieces[i]);
+        longPieces[i] = regexEscape(longPieces[i]);
+    }
+    for (i = 0; i < 24; i++) {
+        mixedPieces[i] = regexEscape(mixedPieces[i]);
+    }
+
+    this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
+    this._monthsShortRegex = this._monthsRegex;
+    this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
+    this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/offset.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/offset.js
new file mode 100644
index 0000000000000000000000000000000000000000..168aeadd808610444d6d4aa1437fd40aa9252ec0
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/offset.js
@@ -0,0 +1,235 @@
+import zeroFill from '../utils/zero-fill';
+import { createDuration } from '../duration/create';
+import { addSubtract } from '../moment/add-subtract';
+import { isMoment, copyConfig } from '../moment/constructor';
+import { addFormatToken } from '../format/format';
+import { addRegexToken, matchOffset, matchShortOffset } from '../parse/regex';
+import { addParseToken } from '../parse/token';
+import { createLocal } from '../create/local';
+import { prepareConfig } from '../create/from-anything';
+import { createUTC } from '../create/utc';
+import isDate from '../utils/is-date';
+import toInt from '../utils/to-int';
+import isUndefined from '../utils/is-undefined';
+import compareArrays from '../utils/compare-arrays';
+import { hooks } from '../utils/hooks';
+
+// FORMATTING
+
+function offset (token, separator) {
+    addFormatToken(token, 0, 0, function () {
+        var offset = this.utcOffset();
+        var sign = '+';
+        if (offset < 0) {
+            offset = -offset;
+            sign = '-';
+        }
+        return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~(offset) % 60, 2);
+    });
+}
+
+offset('Z', ':');
+offset('ZZ', '');
+
+// PARSING
+
+addRegexToken('Z',  matchShortOffset);
+addRegexToken('ZZ', matchShortOffset);
+addParseToken(['Z', 'ZZ'], function (input, array, config) {
+    config._useUTC = true;
+    config._tzm = offsetFromString(matchShortOffset, input);
+});
+
+// HELPERS
+
+// timezone chunker
+// '+10:00' > ['10',  '00']
+// '-1530'  > ['-15', '30']
+var chunkOffset = /([\+\-]|\d\d)/gi;
+
+function offsetFromString(matcher, string) {
+    var matches = (string || '').match(matcher);
+
+    if (matches === null) {
+        return null;
+    }
+
+    var chunk   = matches[matches.length - 1] || [];
+    var parts   = (chunk + '').match(chunkOffset) || ['-', 0, 0];
+    var minutes = +(parts[1] * 60) + toInt(parts[2]);
+
+    return minutes === 0 ?
+      0 :
+      parts[0] === '+' ? minutes : -minutes;
+}
+
+// Return a moment from input, that is local/utc/zone equivalent to model.
+export function cloneWithOffset(input, model) {
+    var res, diff;
+    if (model._isUTC) {
+        res = model.clone();
+        diff = (isMoment(input) || isDate(input) ? input.valueOf() : createLocal(input).valueOf()) - res.valueOf();
+        // Use low-level api, because this fn is low-level api.
+        res._d.setTime(res._d.valueOf() + diff);
+        hooks.updateOffset(res, false);
+        return res;
+    } else {
+        return createLocal(input).local();
+    }
+}
+
+function getDateOffset (m) {
+    // On Firefox.24 Date#getTimezoneOffset returns a floating point.
+    // https://github.com/moment/moment/pull/1871
+    return -Math.round(m._d.getTimezoneOffset() / 15) * 15;
+}
+
+// HOOKS
+
+// This function will be called whenever a moment is mutated.
+// It is intended to keep the offset in sync with the timezone.
+hooks.updateOffset = function () {};
+
+// MOMENTS
+
+// keepLocalTime = true means only change the timezone, without
+// affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
+// 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
+// +0200, so we adjust the time as needed, to be valid.
+//
+// Keeping the time actually adds/subtracts (one hour)
+// from the actual represented time. That is why we call updateOffset
+// a second time. In case it wants us to change the offset again
+// _changeInProgress == true case, then we have to adjust, because
+// there is no such time in the given timezone.
+export function getSetOffset (input, keepLocalTime) {
+    var offset = this._offset || 0,
+        localAdjust;
+    if (!this.isValid()) {
+        return input != null ? this : NaN;
+    }
+    if (input != null) {
+        if (typeof input === 'string') {
+            input = offsetFromString(matchShortOffset, input);
+            if (input === null) {
+                return this;
+            }
+        } else if (Math.abs(input) < 16) {
+            input = input * 60;
+        }
+        if (!this._isUTC && keepLocalTime) {
+            localAdjust = getDateOffset(this);
+        }
+        this._offset = input;
+        this._isUTC = true;
+        if (localAdjust != null) {
+            this.add(localAdjust, 'm');
+        }
+        if (offset !== input) {
+            if (!keepLocalTime || this._changeInProgress) {
+                addSubtract(this, createDuration(input - offset, 'm'), 1, false);
+            } else if (!this._changeInProgress) {
+                this._changeInProgress = true;
+                hooks.updateOffset(this, true);
+                this._changeInProgress = null;
+            }
+        }
+        return this;
+    } else {
+        return this._isUTC ? offset : getDateOffset(this);
+    }
+}
+
+export function getSetZone (input, keepLocalTime) {
+    if (input != null) {
+        if (typeof input !== 'string') {
+            input = -input;
+        }
+
+        this.utcOffset(input, keepLocalTime);
+
+        return this;
+    } else {
+        return -this.utcOffset();
+    }
+}
+
+export function setOffsetToUTC (keepLocalTime) {
+    return this.utcOffset(0, keepLocalTime);
+}
+
+export function setOffsetToLocal (keepLocalTime) {
+    if (this._isUTC) {
+        this.utcOffset(0, keepLocalTime);
+        this._isUTC = false;
+
+        if (keepLocalTime) {
+            this.subtract(getDateOffset(this), 'm');
+        }
+    }
+    return this;
+}
+
+export function setOffsetToParsedOffset () {
+    if (this._tzm != null) {
+        this.utcOffset(this._tzm);
+    } else if (typeof this._i === 'string') {
+        var tZone = offsetFromString(matchOffset, this._i);
+        if (tZone != null) {
+            this.utcOffset(tZone);
+        }
+        else {
+            this.utcOffset(0, true);
+        }
+    }
+    return this;
+}
+
+export function hasAlignedHourOffset (input) {
+    if (!this.isValid()) {
+        return false;
+    }
+    input = input ? createLocal(input).utcOffset() : 0;
+
+    return (this.utcOffset() - input) % 60 === 0;
+}
+
+export function isDaylightSavingTime () {
+    return (
+        this.utcOffset() > this.clone().month(0).utcOffset() ||
+        this.utcOffset() > this.clone().month(5).utcOffset()
+    );
+}
+
+export function isDaylightSavingTimeShifted () {
+    if (!isUndefined(this._isDSTShifted)) {
+        return this._isDSTShifted;
+    }
+
+    var c = {};
+
+    copyConfig(c, this);
+    c = prepareConfig(c);
+
+    if (c._a) {
+        var other = c._isUTC ? createUTC(c._a) : createLocal(c._a);
+        this._isDSTShifted = this.isValid() &&
+            compareArrays(c._a, other.toArray()) > 0;
+    } else {
+        this._isDSTShifted = false;
+    }
+
+    return this._isDSTShifted;
+}
+
+export function isLocal () {
+    return this.isValid() ? !this._isUTC : false;
+}
+
+export function isUtcOffset () {
+    return this.isValid() ? this._isUTC : false;
+}
+
+export function isUtc () {
+    return this.isValid() ? this._isUTC && this._offset === 0 : false;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/priorities.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/priorities.js
new file mode 100644
index 0000000000000000000000000000000000000000..699017cb80f22b5df9f98ed2f0a16609888e0a6a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/priorities.js
@@ -0,0 +1,16 @@
+var priorities = {};
+
+export function addUnitPriority(unit, priority) {
+    priorities[unit] = priority;
+}
+
+export function getPrioritizedUnits(unitsObj) {
+    var units = [];
+    for (var u in unitsObj) {
+        units.push({unit: u, priority: priorities[u]});
+    }
+    units.sort(function (a, b) {
+        return a.priority - b.priority;
+    });
+    return units;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/quarter.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/quarter.js
new file mode 100644
index 0000000000000000000000000000000000000000..a6d409a862c8108e29d47effa0dc9b1070a94ff0
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/quarter.js
@@ -0,0 +1,32 @@
+import { addFormatToken } from '../format/format';
+import { addUnitAlias } from './aliases';
+import { addUnitPriority } from './priorities';
+import { addRegexToken, match1 } from '../parse/regex';
+import { addParseToken } from '../parse/token';
+import { MONTH } from './constants';
+import toInt from '../utils/to-int';
+
+// FORMATTING
+
+addFormatToken('Q', 0, 'Qo', 'quarter');
+
+// ALIASES
+
+addUnitAlias('quarter', 'Q');
+
+// PRIORITY
+
+addUnitPriority('quarter', 7);
+
+// PARSING
+
+addRegexToken('Q', match1);
+addParseToken('Q', function (input, array) {
+    array[MONTH] = (toInt(input) - 1) * 3;
+});
+
+// MOMENTS
+
+export function getSetQuarter (input) {
+    return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/second.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/second.js
new file mode 100644
index 0000000000000000000000000000000000000000..179371186e98f1749443a37951d4fc58612ce99f
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/second.js
@@ -0,0 +1,29 @@
+import { makeGetSet } from '../moment/get-set';
+import { addFormatToken } from '../format/format';
+import { addUnitAlias } from './aliases';
+import { addUnitPriority } from './priorities';
+import { addRegexToken, match1to2, match2 } from '../parse/regex';
+import { addParseToken } from '../parse/token';
+import { SECOND } from './constants';
+
+// FORMATTING
+
+addFormatToken('s', ['ss', 2], 0, 'second');
+
+// ALIASES
+
+addUnitAlias('second', 's');
+
+// PRIORITY
+
+addUnitPriority('second', 15);
+
+// PARSING
+
+addRegexToken('s',  match1to2);
+addRegexToken('ss', match1to2, match2);
+addParseToken(['s', 'ss'], SECOND);
+
+// MOMENTS
+
+export var getSetSecond = makeGetSet('Seconds', false);
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/timestamp.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/timestamp.js
new file mode 100644
index 0000000000000000000000000000000000000000..a49e1e4b852e1c01a04c8655534e9e74947e7cc1
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/timestamp.js
@@ -0,0 +1,20 @@
+import { addFormatToken } from '../format/format';
+import { addRegexToken, matchTimestamp, matchSigned } from '../parse/regex';
+import { addParseToken } from '../parse/token';
+import toInt from '../utils/to-int';
+
+// FORMATTING
+
+addFormatToken('X', 0, 0, 'unix');
+addFormatToken('x', 0, 0, 'valueOf');
+
+// PARSING
+
+addRegexToken('x', matchSigned);
+addRegexToken('X', matchTimestamp);
+addParseToken('X', function (input, array, config) {
+    config._d = new Date(parseFloat(input, 10) * 1000);
+});
+addParseToken('x', function (input, array, config) {
+    config._d = new Date(toInt(input));
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/timezone.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/timezone.js
new file mode 100644
index 0000000000000000000000000000000000000000..20c81cd2c623b3ca3226919e94c8625c92832d58
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/timezone.js
@@ -0,0 +1,16 @@
+import { addFormatToken } from '../format/format';
+
+// FORMATTING
+
+addFormatToken('z',  0, 0, 'zoneAbbr');
+addFormatToken('zz', 0, 0, 'zoneName');
+
+// MOMENTS
+
+export function getZoneAbbr () {
+    return this._isUTC ? 'UTC' : '';
+}
+
+export function getZoneName () {
+    return this._isUTC ? 'Coordinated Universal Time' : '';
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/units.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/units.js
new file mode 100644
index 0000000000000000000000000000000000000000..6f45f1c040b25f47e1fc59f7603a7ff879528927
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/units.js
@@ -0,0 +1,20 @@
+// Side effect imports
+import './day-of-month';
+import './day-of-week';
+import './day-of-year';
+import './hour';
+import './millisecond';
+import './minute';
+import './month';
+import './offset';
+import './quarter';
+import './second';
+import './timestamp';
+import './timezone';
+import './week-year';
+import './week';
+import './year';
+
+import { normalizeUnits } from './aliases';
+
+export { normalizeUnits };
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/week-calendar-utils.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/week-calendar-utils.js
new file mode 100644
index 0000000000000000000000000000000000000000..b89810c75ac934a24cb81ce4a4adaffef0cf6a18
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/week-calendar-utils.js
@@ -0,0 +1,65 @@
+import { daysInYear } from './year';
+import { createLocal } from '../create/local';
+import { createUTCDate } from '../create/date-from-array';
+
+// start-of-first-week - start-of-year
+function firstWeekOffset(year, dow, doy) {
+    var // first-week day -- which january is always in the first week (4 for iso, 1 for other)
+        fwd = 7 + dow - doy,
+        // first-week day local weekday -- which local weekday is fwd
+        fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7;
+
+    return -fwdlw + fwd - 1;
+}
+
+//http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
+export function dayOfYearFromWeeks(year, week, weekday, dow, doy) {
+    var localWeekday = (7 + weekday - dow) % 7,
+        weekOffset = firstWeekOffset(year, dow, doy),
+        dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset,
+        resYear, resDayOfYear;
+
+    if (dayOfYear <= 0) {
+        resYear = year - 1;
+        resDayOfYear = daysInYear(resYear) + dayOfYear;
+    } else if (dayOfYear > daysInYear(year)) {
+        resYear = year + 1;
+        resDayOfYear = dayOfYear - daysInYear(year);
+    } else {
+        resYear = year;
+        resDayOfYear = dayOfYear;
+    }
+
+    return {
+        year: resYear,
+        dayOfYear: resDayOfYear
+    };
+}
+
+export function weekOfYear(mom, dow, doy) {
+    var weekOffset = firstWeekOffset(mom.year(), dow, doy),
+        week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1,
+        resWeek, resYear;
+
+    if (week < 1) {
+        resYear = mom.year() - 1;
+        resWeek = week + weeksInYear(resYear, dow, doy);
+    } else if (week > weeksInYear(mom.year(), dow, doy)) {
+        resWeek = week - weeksInYear(mom.year(), dow, doy);
+        resYear = mom.year() + 1;
+    } else {
+        resYear = mom.year();
+        resWeek = week;
+    }
+
+    return {
+        week: resWeek,
+        year: resYear
+    };
+}
+
+export function weeksInYear(year, dow, doy) {
+    var weekOffset = firstWeekOffset(year, dow, doy),
+        weekOffsetNext = firstWeekOffset(year + 1, dow, doy);
+    return (daysInYear(year) - weekOffset + weekOffsetNext) / 7;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/week-year.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/week-year.js
new file mode 100644
index 0000000000000000000000000000000000000000..7fa5425bccbf4d0a62e28801c2e9a4ef6da492b8
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/week-year.js
@@ -0,0 +1,107 @@
+import { addFormatToken } from '../format/format';
+import { addUnitAlias } from './aliases';
+import { addUnitPriority } from './priorities';
+import { addRegexToken, match1to2, match1to4, match1to6, match2, match4, match6, matchSigned } from '../parse/regex';
+import { addWeekParseToken } from '../parse/token';
+import { weekOfYear, weeksInYear, dayOfYearFromWeeks } from './week-calendar-utils';
+import toInt from '../utils/to-int';
+import { hooks } from '../utils/hooks';
+import { createLocal } from '../create/local';
+import { createUTCDate } from '../create/date-from-array';
+
+// FORMATTING
+
+addFormatToken(0, ['gg', 2], 0, function () {
+    return this.weekYear() % 100;
+});
+
+addFormatToken(0, ['GG', 2], 0, function () {
+    return this.isoWeekYear() % 100;
+});
+
+function addWeekYearFormatToken (token, getter) {
+    addFormatToken(0, [token, token.length], 0, getter);
+}
+
+addWeekYearFormatToken('gggg',     'weekYear');
+addWeekYearFormatToken('ggggg',    'weekYear');
+addWeekYearFormatToken('GGGG',  'isoWeekYear');
+addWeekYearFormatToken('GGGGG', 'isoWeekYear');
+
+// ALIASES
+
+addUnitAlias('weekYear', 'gg');
+addUnitAlias('isoWeekYear', 'GG');
+
+// PRIORITY
+
+addUnitPriority('weekYear', 1);
+addUnitPriority('isoWeekYear', 1);
+
+
+// PARSING
+
+addRegexToken('G',      matchSigned);
+addRegexToken('g',      matchSigned);
+addRegexToken('GG',     match1to2, match2);
+addRegexToken('gg',     match1to2, match2);
+addRegexToken('GGGG',   match1to4, match4);
+addRegexToken('gggg',   match1to4, match4);
+addRegexToken('GGGGG',  match1to6, match6);
+addRegexToken('ggggg',  match1to6, match6);
+
+addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (input, week, config, token) {
+    week[token.substr(0, 2)] = toInt(input);
+});
+
+addWeekParseToken(['gg', 'GG'], function (input, week, config, token) {
+    week[token] = hooks.parseTwoDigitYear(input);
+});
+
+// MOMENTS
+
+export function getSetWeekYear (input) {
+    return getSetWeekYearHelper.call(this,
+            input,
+            this.week(),
+            this.weekday(),
+            this.localeData()._week.dow,
+            this.localeData()._week.doy);
+}
+
+export function getSetISOWeekYear (input) {
+    return getSetWeekYearHelper.call(this,
+            input, this.isoWeek(), this.isoWeekday(), 1, 4);
+}
+
+export function getISOWeeksInYear () {
+    return weeksInYear(this.year(), 1, 4);
+}
+
+export function getWeeksInYear () {
+    var weekInfo = this.localeData()._week;
+    return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
+}
+
+function getSetWeekYearHelper(input, week, weekday, dow, doy) {
+    var weeksTarget;
+    if (input == null) {
+        return weekOfYear(this, dow, doy).year;
+    } else {
+        weeksTarget = weeksInYear(input, dow, doy);
+        if (week > weeksTarget) {
+            week = weeksTarget;
+        }
+        return setWeekAll.call(this, input, week, weekday, dow, doy);
+    }
+}
+
+function setWeekAll(weekYear, week, weekday, dow, doy) {
+    var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy),
+        date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear);
+
+    this.year(date.getUTCFullYear());
+    this.month(date.getUTCMonth());
+    this.date(date.getUTCDate());
+    return this;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/week.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/week.js
new file mode 100644
index 0000000000000000000000000000000000000000..da64ffef328a68491c6211b2fbc350ed4d96100c
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/week.js
@@ -0,0 +1,67 @@
+import { addFormatToken } from '../format/format';
+import { addUnitAlias } from './aliases';
+import { addUnitPriority } from './priorities';
+import { addRegexToken, match1to2, match2 } from '../parse/regex';
+import { addWeekParseToken } from '../parse/token';
+import toInt from '../utils/to-int';
+import { createLocal } from '../create/local';
+import { weekOfYear } from './week-calendar-utils';
+
+// FORMATTING
+
+addFormatToken('w', ['ww', 2], 'wo', 'week');
+addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek');
+
+// ALIASES
+
+addUnitAlias('week', 'w');
+addUnitAlias('isoWeek', 'W');
+
+// PRIORITIES
+
+addUnitPriority('week', 5);
+addUnitPriority('isoWeek', 5);
+
+// PARSING
+
+addRegexToken('w',  match1to2);
+addRegexToken('ww', match1to2, match2);
+addRegexToken('W',  match1to2);
+addRegexToken('WW', match1to2, match2);
+
+addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) {
+    week[token.substr(0, 1)] = toInt(input);
+});
+
+// HELPERS
+
+// LOCALES
+
+export function localeWeek (mom) {
+    return weekOfYear(mom, this._week.dow, this._week.doy).week;
+}
+
+export var defaultLocaleWeek = {
+    dow : 0, // Sunday is the first day of the week.
+    doy : 6  // The week that contains Jan 1st is the first week of the year.
+};
+
+export function localeFirstDayOfWeek () {
+    return this._week.dow;
+}
+
+export function localeFirstDayOfYear () {
+    return this._week.doy;
+}
+
+// MOMENTS
+
+export function getSetWeek (input) {
+    var week = this.localeData().week(this);
+    return input == null ? week : this.add((input - week) * 7, 'd');
+}
+
+export function getSetISOWeek (input) {
+    var week = weekOfYear(this, 1, 4).week;
+    return input == null ? week : this.add((input - week) * 7, 'd');
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/year.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/year.js
new file mode 100644
index 0000000000000000000000000000000000000000..a10e5b4beb3588238208508569b7c4f953aede7e
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/units/year.js
@@ -0,0 +1,75 @@
+import { makeGetSet } from '../moment/get-set';
+import { addFormatToken } from '../format/format';
+import { addUnitAlias } from './aliases';
+import { addUnitPriority } from './priorities';
+import { addRegexToken, match1to2, match1to4, match1to6, match2, match4, match6, matchSigned } from '../parse/regex';
+import { addParseToken } from '../parse/token';
+import { hooks } from '../utils/hooks';
+import { YEAR } from './constants';
+import toInt from '../utils/to-int';
+
+// FORMATTING
+
+addFormatToken('Y', 0, 0, function () {
+    var y = this.year();
+    return y <= 9999 ? '' + y : '+' + y;
+});
+
+addFormatToken(0, ['YY', 2], 0, function () {
+    return this.year() % 100;
+});
+
+addFormatToken(0, ['YYYY',   4],       0, 'year');
+addFormatToken(0, ['YYYYY',  5],       0, 'year');
+addFormatToken(0, ['YYYYYY', 6, true], 0, 'year');
+
+// ALIASES
+
+addUnitAlias('year', 'y');
+
+// PRIORITIES
+
+addUnitPriority('year', 1);
+
+// PARSING
+
+addRegexToken('Y',      matchSigned);
+addRegexToken('YY',     match1to2, match2);
+addRegexToken('YYYY',   match1to4, match4);
+addRegexToken('YYYYY',  match1to6, match6);
+addRegexToken('YYYYYY', match1to6, match6);
+
+addParseToken(['YYYYY', 'YYYYYY'], YEAR);
+addParseToken('YYYY', function (input, array) {
+    array[YEAR] = input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input);
+});
+addParseToken('YY', function (input, array) {
+    array[YEAR] = hooks.parseTwoDigitYear(input);
+});
+addParseToken('Y', function (input, array) {
+    array[YEAR] = parseInt(input, 10);
+});
+
+// HELPERS
+
+export function daysInYear(year) {
+    return isLeapYear(year) ? 366 : 365;
+}
+
+function isLeapYear(year) {
+    return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
+}
+
+// HOOKS
+
+hooks.parseTwoDigitYear = function (input) {
+    return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
+};
+
+// MOMENTS
+
+export var getSetYear = makeGetSet('FullYear', true);
+
+export function getIsLeapYear () {
+    return isLeapYear(this.year());
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/abs-ceil.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/abs-ceil.js
new file mode 100644
index 0000000000000000000000000000000000000000..7cf93290c5163e04ebaf381a03785a0d91b59587
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/abs-ceil.js
@@ -0,0 +1,7 @@
+export default function absCeil (number) {
+    if (number < 0) {
+        return Math.floor(number);
+    } else {
+        return Math.ceil(number);
+    }
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/abs-floor.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/abs-floor.js
new file mode 100644
index 0000000000000000000000000000000000000000..401c7f041f82ab9b73505e5908e68da7b81da685
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/abs-floor.js
@@ -0,0 +1,8 @@
+export default function absFloor (number) {
+    if (number < 0) {
+        // -0 -> 0
+        return Math.ceil(number) || 0;
+    } else {
+        return Math.floor(number);
+    }
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/abs-round.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/abs-round.js
new file mode 100644
index 0000000000000000000000000000000000000000..98f54bc68fd47569bf365cf6cb340b65a78c084a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/abs-round.js
@@ -0,0 +1,7 @@
+export default function absRound (number) {
+    if (number < 0) {
+        return Math.round(-1 * number) * -1;
+    } else {
+        return Math.round(number);
+    }
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/compare-arrays.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/compare-arrays.js
new file mode 100644
index 0000000000000000000000000000000000000000..2eb274befee7b82ba54a7f7a9396360d963788f7
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/compare-arrays.js
@@ -0,0 +1,16 @@
+import toInt from './to-int';
+
+// compare two arrays, return the number of differences
+export default function compareArrays(array1, array2, dontConvert) {
+    var len = Math.min(array1.length, array2.length),
+        lengthDiff = Math.abs(array1.length - array2.length),
+        diffs = 0,
+        i;
+    for (i = 0; i < len; i++) {
+        if ((dontConvert && array1[i] !== array2[i]) ||
+            (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) {
+            diffs++;
+        }
+    }
+    return diffs + lengthDiff;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/defaults.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/defaults.js
new file mode 100644
index 0000000000000000000000000000000000000000..45c5e8794247286e8ee4399d47e75dadd4ea2aad
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/defaults.js
@@ -0,0 +1,10 @@
+// Pick the first defined of two or three arguments.
+export default function defaults(a, b, c) {
+    if (a != null) {
+        return a;
+    }
+    if (b != null) {
+        return b;
+    }
+    return c;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/deprecate.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/deprecate.js
new file mode 100644
index 0000000000000000000000000000000000000000..8b4c87a280551ce91636911a3fdf81b9bea8b0ae
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/deprecate.js
@@ -0,0 +1,55 @@
+import extend from './extend';
+import { hooks } from './hooks';
+import isUndefined from './is-undefined';
+
+function warn(msg) {
+    if (hooks.suppressDeprecationWarnings === false &&
+            (typeof console !==  'undefined') && console.warn) {
+        console.warn('Deprecation warning: ' + msg);
+    }
+}
+
+export function deprecate(msg, fn) {
+    var firstTime = true;
+
+    return extend(function () {
+        if (hooks.deprecationHandler != null) {
+            hooks.deprecationHandler(null, msg);
+        }
+        if (firstTime) {
+            var args = [];
+            var arg;
+            for (var i = 0; i < arguments.length; i++) {
+                arg = '';
+                if (typeof arguments[i] === 'object') {
+                    arg += '\n[' + i + '] ';
+                    for (var key in arguments[0]) {
+                        arg += key + ': ' + arguments[0][key] + ', ';
+                    }
+                    arg = arg.slice(0, -2); // Remove trailing comma and space
+                } else {
+                    arg = arguments[i];
+                }
+                args.push(arg);
+            }
+            warn(msg + '\nArguments: ' + Array.prototype.slice.call(args).join('') + '\n' + (new Error()).stack);
+            firstTime = false;
+        }
+        return fn.apply(this, arguments);
+    }, fn);
+}
+
+var deprecations = {};
+
+export function deprecateSimple(name, msg) {
+    if (hooks.deprecationHandler != null) {
+        hooks.deprecationHandler(name, msg);
+    }
+    if (!deprecations[name]) {
+        warn(msg);
+        deprecations[name] = true;
+    }
+}
+
+hooks.suppressDeprecationWarnings = false;
+hooks.deprecationHandler = null;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/extend.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/extend.js
new file mode 100644
index 0000000000000000000000000000000000000000..ba74a0bf19cfe5da28300d13fb42f74a59b18862
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/extend.js
@@ -0,0 +1,19 @@
+import hasOwnProp from './has-own-prop';
+
+export default function extend(a, b) {
+    for (var i in b) {
+        if (hasOwnProp(b, i)) {
+            a[i] = b[i];
+        }
+    }
+
+    if (hasOwnProp(b, 'toString')) {
+        a.toString = b.toString;
+    }
+
+    if (hasOwnProp(b, 'valueOf')) {
+        a.valueOf = b.valueOf;
+    }
+
+    return a;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/has-own-prop.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/has-own-prop.js
new file mode 100644
index 0000000000000000000000000000000000000000..4d2403ccb40af36d3f3f873616f16164adc3e242
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/has-own-prop.js
@@ -0,0 +1,3 @@
+export default function hasOwnProp(a, b) {
+    return Object.prototype.hasOwnProperty.call(a, b);
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/hooks.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/hooks.js
new file mode 100644
index 0000000000000000000000000000000000000000..02a5bd3dac2ffcaced113bb9b2c593d1047a13e8
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/hooks.js
@@ -0,0 +1,13 @@
+export { hooks, setHookCallback };
+
+var hookCallback;
+
+function hooks () {
+    return hookCallback.apply(null, arguments);
+}
+
+// This is done to register the method called with moment()
+// without creating circular dependencies.
+function setHookCallback (callback) {
+    hookCallback = callback;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/index-of.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/index-of.js
new file mode 100644
index 0000000000000000000000000000000000000000..92298cff31a55a0b4dfe8a6b52294fff13ba13d0
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/index-of.js
@@ -0,0 +1,18 @@
+var indexOf;
+
+if (Array.prototype.indexOf) {
+    indexOf = Array.prototype.indexOf;
+} else {
+    indexOf = function (o) {
+        // I know
+        var i;
+        for (i = 0; i < this.length; ++i) {
+            if (this[i] === o) {
+                return i;
+            }
+        }
+        return -1;
+    };
+}
+
+export { indexOf as default };
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/is-array.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/is-array.js
new file mode 100644
index 0000000000000000000000000000000000000000..2d0e0f3da3d70f6e0110bad036462bdb1098e1c2
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/is-array.js
@@ -0,0 +1,3 @@
+export default function isArray(input) {
+    return input instanceof Array || Object.prototype.toString.call(input) === '[object Array]';
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/is-date.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/is-date.js
new file mode 100644
index 0000000000000000000000000000000000000000..69c4d0e9c6a29cba71fb6eab6c48919a30bd6dba
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/is-date.js
@@ -0,0 +1,3 @@
+export default function isDate(input) {
+    return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/is-function.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/is-function.js
new file mode 100644
index 0000000000000000000000000000000000000000..12304b1bd63b0e585a68cce90438f9c39d769c2b
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/is-function.js
@@ -0,0 +1,3 @@
+export default function isFunction(input) {
+    return input instanceof Function || Object.prototype.toString.call(input) === '[object Function]';
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/is-number.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/is-number.js
new file mode 100644
index 0000000000000000000000000000000000000000..e34c783b05a836794f6cd4eaa654ff00bfb5614c
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/is-number.js
@@ -0,0 +1,3 @@
+export default function isNumber(input) {
+    return typeof value === 'number' || Object.prototype.toString.call(input) === '[object Number]';
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/is-object-empty.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/is-object-empty.js
new file mode 100644
index 0000000000000000000000000000000000000000..1f2d939a579fc0af068d3db06b763f90eb792724
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/is-object-empty.js
@@ -0,0 +1,8 @@
+export default function isObjectEmpty(obj) {
+    var k;
+    for (k in obj) {
+        // even if its not own property I'd still call it non-empty
+        return false;
+    }
+    return true;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/is-object.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/is-object.js
new file mode 100644
index 0000000000000000000000000000000000000000..111353899ac92a7010237cb84e8bdae2b3e72b60
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/is-object.js
@@ -0,0 +1,5 @@
+export default function isObject(input) {
+    // IE8 will treat undefined and null as object if it wasn't for
+    // input != null
+    return input != null && Object.prototype.toString.call(input) === '[object Object]';
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/is-undefined.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/is-undefined.js
new file mode 100644
index 0000000000000000000000000000000000000000..de57a8b28491528fa953f2387c2e5596b6c76cc0
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/is-undefined.js
@@ -0,0 +1,3 @@
+export default function isUndefined(input) {
+    return input === void 0;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/keys.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/keys.js
new file mode 100644
index 0000000000000000000000000000000000000000..2da4e322882ffca15ad2c95447a362b69820a4fb
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/keys.js
@@ -0,0 +1,19 @@
+import hasOwnProp from './has-own-prop';
+
+var keys;
+
+if (Object.keys) {
+    keys = Object.keys;
+} else {
+    keys = function (obj) {
+        var i, res = [];
+        for (i in obj) {
+            if (hasOwnProp(obj, i)) {
+                res.push(i);
+            }
+        }
+        return res;
+    };
+}
+
+export { keys as default };
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/map.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/map.js
new file mode 100644
index 0000000000000000000000000000000000000000..1cbc5639f0afe042f7d49370464a6154d1200306
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/map.js
@@ -0,0 +1,7 @@
+export default function map(arr, fn) {
+    var res = [], i;
+    for (i = 0; i < arr.length; ++i) {
+        res.push(fn(arr[i], i));
+    }
+    return res;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/some.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/some.js
new file mode 100644
index 0000000000000000000000000000000000000000..1bd318675f0665b929c1b05d7ba2099a5f1f41bf
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/some.js
@@ -0,0 +1,19 @@
+var some;
+if (Array.prototype.some) {
+    some = Array.prototype.some;
+} else {
+    some = function (fun) {
+        var t = Object(this);
+        var len = t.length >>> 0;
+
+        for (var i = 0; i < len; i++) {
+            if (i in t && fun.call(this, t[i], i, t)) {
+                return true;
+            }
+        }
+
+        return false;
+    };
+}
+
+export { some as default };
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/to-int.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/to-int.js
new file mode 100644
index 0000000000000000000000000000000000000000..fb489416f160e9bb118e134c8c835fafeedde143
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/to-int.js
@@ -0,0 +1,12 @@
+import absFloor from './abs-floor';
+
+export default function toInt(argumentForCoercion) {
+    var coercedNumber = +argumentForCoercion,
+        value = 0;
+
+    if (coercedNumber !== 0 && isFinite(coercedNumber)) {
+        value = absFloor(coercedNumber);
+    }
+
+    return value;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/zero-fill.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/zero-fill.js
new file mode 100644
index 0000000000000000000000000000000000000000..7009ec903d336d5ec9489d5dd81b8afae028a86b
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/lib/utils/zero-fill.js
@@ -0,0 +1,7 @@
+export default function zeroFill(number, targetLength, forceSign) {
+    var absNumber = '' + Math.abs(number),
+        zerosToFill = targetLength - absNumber.length,
+        sign = number >= 0;
+    return (sign ? (forceSign ? '+' : '') : '-') +
+        Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber;
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/af.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/af.js
new file mode 100644
index 0000000000000000000000000000000000000000..addd827382832d8879fa8253f348c23ee0cb55b2
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/af.js
@@ -0,0 +1,63 @@
+//! moment.js locale configuration
+//! locale : Afrikaans [af]
+//! author : Werner Mollentze : https://github.com/wernerm
+
+import moment from '../moment';
+
+export default moment.defineLocale('af', {
+    months : 'Januarie_Februarie_Maart_April_Mei_Junie_Julie_Augustus_September_Oktober_November_Desember'.split('_'),
+    monthsShort : 'Jan_Feb_Mrt_Apr_Mei_Jun_Jul_Aug_Sep_Okt_Nov_Des'.split('_'),
+    weekdays : 'Sondag_Maandag_Dinsdag_Woensdag_Donderdag_Vrydag_Saterdag'.split('_'),
+    weekdaysShort : 'Son_Maa_Din_Woe_Don_Vry_Sat'.split('_'),
+    weekdaysMin : 'So_Ma_Di_Wo_Do_Vr_Sa'.split('_'),
+    meridiemParse: /vm|nm/i,
+    isPM : function (input) {
+        return /^nm$/i.test(input);
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 12) {
+            return isLower ? 'vm' : 'VM';
+        } else {
+            return isLower ? 'nm' : 'NM';
+        }
+    },
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[Vandag om] LT',
+        nextDay : '[Môre om] LT',
+        nextWeek : 'dddd [om] LT',
+        lastDay : '[Gister om] LT',
+        lastWeek : '[Laas] dddd [om] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'oor %s',
+        past : '%s gelede',
+        s : '\'n paar sekondes',
+        m : '\'n minuut',
+        mm : '%d minute',
+        h : '\'n uur',
+        hh : '%d ure',
+        d : '\'n dag',
+        dd : '%d dae',
+        M : '\'n maand',
+        MM : '%d maande',
+        y : '\'n jaar',
+        yy : '%d jaar'
+    },
+    ordinalParse: /\d{1,2}(ste|de)/,
+    ordinal : function (number) {
+        return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de'); // Thanks to Joris Röling : https://github.com/jjupiter
+    },
+    week : {
+        dow : 1, // Maandag is die eerste dag van die week.
+        doy : 4  // Die week wat die 4de Januarie bevat is die eerste week van die jaar.
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ar-dz.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ar-dz.js
new file mode 100644
index 0000000000000000000000000000000000000000..d14e0ff830b71271bb2452cb96c2a2ae93332ff6
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ar-dz.js
@@ -0,0 +1,50 @@
+//! moment.js locale configuration
+//! locale : Arabic (Algeria) [ar-dz]
+//! author : Noureddine LOUAHEDJ : https://github.com/noureddineme
+
+import moment from '../moment';
+
+export default moment.defineLocale('ar-dz', {
+    months : 'جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
+    monthsShort : 'جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
+    weekdays : 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
+    weekdaysShort : 'احد_اثنين_ثلاثاء_اربعاء_خميس_جمعة_سبت'.split('_'),
+    weekdaysMin : 'أح_إث_ثلا_أر_خم_جم_سب'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[اليوم على الساعة] LT',
+        nextDay: '[غدا على الساعة] LT',
+        nextWeek: 'dddd [على الساعة] LT',
+        lastDay: '[أمس على الساعة] LT',
+        lastWeek: 'dddd [على الساعة] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'في %s',
+        past : 'منذ %s',
+        s : 'ثوان',
+        m : 'دقيقة',
+        mm : '%d دقائق',
+        h : 'ساعة',
+        hh : '%d ساعات',
+        d : 'يوم',
+        dd : '%d أيام',
+        M : 'شهر',
+        MM : '%d أشهر',
+        y : 'سنة',
+        yy : '%d سنوات'
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 4  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ar-ly.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ar-ly.js
new file mode 100644
index 0000000000000000000000000000000000000000..2dcba3f684af2a1d61a165b2710f43675423c2eb
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ar-ly.js
@@ -0,0 +1,112 @@
+//! moment.js locale configuration
+//! locale : Arabic (Lybia) [ar-ly]
+//! author : Ali Hmer: https://github.com/kikoanis
+
+import moment from '../moment';
+
+var symbolMap = {
+    '1': '1',
+    '2': '2',
+    '3': '3',
+    '4': '4',
+    '5': '5',
+    '6': '6',
+    '7': '7',
+    '8': '8',
+    '9': '9',
+    '0': '0'
+}, pluralForm = function (n) {
+    return n === 0 ? 0 : n === 1 ? 1 : n === 2 ? 2 : n % 100 >= 3 && n % 100 <= 10 ? 3 : n % 100 >= 11 ? 4 : 5;
+}, plurals = {
+    s : ['أقل من ثانية', 'ثانية واحدة', ['ثانيتان', 'ثانيتين'], '%d ثوان', '%d ثانية', '%d ثانية'],
+    m : ['أقل من دقيقة', 'دقيقة واحدة', ['دقيقتان', 'دقيقتين'], '%d دقائق', '%d دقيقة', '%d دقيقة'],
+    h : ['أقل من ساعة', 'ساعة واحدة', ['ساعتان', 'ساعتين'], '%d ساعات', '%d ساعة', '%d ساعة'],
+    d : ['أقل من يوم', 'يوم واحد', ['يومان', 'يومين'], '%d أيام', '%d يومًا', '%d يوم'],
+    M : ['أقل من شهر', 'شهر واحد', ['شهران', 'شهرين'], '%d أشهر', '%d شهرا', '%d شهر'],
+    y : ['أقل من عام', 'عام واحد', ['عامان', 'عامين'], '%d أعوام', '%d عامًا', '%d عام']
+}, pluralize = function (u) {
+    return function (number, withoutSuffix, string, isFuture) {
+        var f = pluralForm(number),
+            str = plurals[u][pluralForm(number)];
+        if (f === 2) {
+            str = str[withoutSuffix ? 0 : 1];
+        }
+        return str.replace(/%d/i, number);
+    };
+}, months = [
+    'يناير',
+    'فبراير',
+    'مارس',
+    'أبريل',
+    'مايو',
+    'يونيو',
+    'يوليو',
+    'أغسطس',
+    'سبتمبر',
+    'أكتوبر',
+    'نوفمبر',
+    'ديسمبر'
+];
+
+export default moment.defineLocale('ar-ly', {
+    months : months,
+    monthsShort : months,
+    weekdays : 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
+    weekdaysShort : 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'),
+    weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'D/\u200FM/\u200FYYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    meridiemParse: /ص|م/,
+    isPM : function (input) {
+        return 'Ù…' === input;
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return 'ص';
+        } else {
+            return 'Ù…';
+        }
+    },
+    calendar : {
+        sameDay: '[اليوم عند الساعة] LT',
+        nextDay: '[غدًا عند الساعة] LT',
+        nextWeek: 'dddd [عند الساعة] LT',
+        lastDay: '[أمس عند الساعة] LT',
+        lastWeek: 'dddd [عند الساعة] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'بعد %s',
+        past : 'منذ %s',
+        s : pluralize('s'),
+        m : pluralize('m'),
+        mm : pluralize('m'),
+        h : pluralize('h'),
+        hh : pluralize('h'),
+        d : pluralize('d'),
+        dd : pluralize('d'),
+        M : pluralize('M'),
+        MM : pluralize('M'),
+        y : pluralize('y'),
+        yy : pluralize('y')
+    },
+    preparse: function (string) {
+        return string.replace(/\u200f/g, '').replace(/،/g, ',');
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap[match];
+        }).replace(/,/g, '،');
+    },
+    week : {
+        dow : 6, // Saturday is the first day of the week.
+        doy : 12  // The week that contains Jan 1st is the first week of the year.
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ar-ma.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ar-ma.js
new file mode 100644
index 0000000000000000000000000000000000000000..03973d229815a4b0bb16e0b2a3894e4cc6387ccd
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ar-ma.js
@@ -0,0 +1,51 @@
+//! moment.js locale configuration
+//! locale : Arabic (Morocco) [ar-ma]
+//! author : ElFadili Yassine : https://github.com/ElFadiliY
+//! author : Abdel Said : https://github.com/abdelsaid
+
+import moment from '../moment';
+
+export default moment.defineLocale('ar-ma', {
+    months : 'يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر'.split('_'),
+    monthsShort : 'يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر'.split('_'),
+    weekdays : 'الأحد_الإتنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
+    weekdaysShort : 'احد_اتنين_ثلاثاء_اربعاء_خميس_جمعة_سبت'.split('_'),
+    weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[اليوم على الساعة] LT',
+        nextDay: '[غدا على الساعة] LT',
+        nextWeek: 'dddd [على الساعة] LT',
+        lastDay: '[أمس على الساعة] LT',
+        lastWeek: 'dddd [على الساعة] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'في %s',
+        past : 'منذ %s',
+        s : 'ثوان',
+        m : 'دقيقة',
+        mm : '%d دقائق',
+        h : 'ساعة',
+        hh : '%d ساعات',
+        d : 'يوم',
+        dd : '%d أيام',
+        M : 'شهر',
+        MM : '%d أشهر',
+        y : 'سنة',
+        yy : '%d سنوات'
+    },
+    week : {
+        dow : 6, // Saturday is the first day of the week.
+        doy : 12  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ar-sa.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ar-sa.js
new file mode 100644
index 0000000000000000000000000000000000000000..30a9968d6e320421600bf538d9b5b8b6827945e7
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ar-sa.js
@@ -0,0 +1,95 @@
+//! moment.js locale configuration
+//! locale : Arabic (Saudi Arabia) [ar-sa]
+//! author : Suhail Alkowaileet : https://github.com/xsoh
+
+import moment from '../moment';
+
+var symbolMap = {
+    '1': 'Ù¡',
+    '2': 'Ù¢',
+    '3': 'Ù£',
+    '4': 'Ù¤',
+    '5': 'Ù¥',
+    '6': 'Ù¦',
+    '7': 'Ù§',
+    '8': 'Ù¨',
+    '9': 'Ù©',
+    '0': 'Ù '
+}, numberMap = {
+    'Ù¡': '1',
+    'Ù¢': '2',
+    'Ù£': '3',
+    'Ù¤': '4',
+    'Ù¥': '5',
+    'Ù¦': '6',
+    'Ù§': '7',
+    'Ù¨': '8',
+    'Ù©': '9',
+    'Ù ': '0'
+};
+
+export default moment.defineLocale('ar-sa', {
+    months : 'يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
+    monthsShort : 'يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
+    weekdays : 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
+    weekdaysShort : 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'),
+    weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    meridiemParse: /ص|م/,
+    isPM : function (input) {
+        return 'Ù…' === input;
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return 'ص';
+        } else {
+            return 'Ù…';
+        }
+    },
+    calendar : {
+        sameDay: '[اليوم على الساعة] LT',
+        nextDay: '[غدا على الساعة] LT',
+        nextWeek: 'dddd [على الساعة] LT',
+        lastDay: '[أمس على الساعة] LT',
+        lastWeek: 'dddd [على الساعة] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'في %s',
+        past : 'منذ %s',
+        s : 'ثوان',
+        m : 'دقيقة',
+        mm : '%d دقائق',
+        h : 'ساعة',
+        hh : '%d ساعات',
+        d : 'يوم',
+        dd : '%d أيام',
+        M : 'شهر',
+        MM : '%d أشهر',
+        y : 'سنة',
+        yy : '%d سنوات'
+    },
+    preparse: function (string) {
+        return string.replace(/[١٢٣٤٥٦٧٨٩٠]/g, function (match) {
+            return numberMap[match];
+        }).replace(/،/g, ',');
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap[match];
+        }).replace(/,/g, '،');
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ar-tn.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ar-tn.js
new file mode 100644
index 0000000000000000000000000000000000000000..8ab8945bddfd61b65b5ca003eea6300b2c8220bc
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ar-tn.js
@@ -0,0 +1,50 @@
+//! moment.js locale configuration
+//! locale  :  Arabic (Tunisia) [ar-tn]
+//! author : Nader Toukabri : https://github.com/naderio
+
+import moment from '../moment';
+
+export default moment.defineLocale('ar-tn', {
+    months: 'جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
+    monthsShort: 'جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),
+    weekdays: 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
+    weekdaysShort: 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'),
+    weekdaysMin: 'ح_ن_ث_ر_خ_ج_س'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat: {
+        LT: 'HH:mm',
+        LTS: 'HH:mm:ss',
+        L: 'DD/MM/YYYY',
+        LL: 'D MMMM YYYY',
+        LLL: 'D MMMM YYYY HH:mm',
+        LLLL: 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar: {
+        sameDay: '[اليوم على الساعة] LT',
+        nextDay: '[غدا على الساعة] LT',
+        nextWeek: 'dddd [على الساعة] LT',
+        lastDay: '[أمس على الساعة] LT',
+        lastWeek: 'dddd [على الساعة] LT',
+        sameElse: 'L'
+    },
+    relativeTime: {
+        future: 'في %s',
+        past: 'منذ %s',
+        s: 'ثوان',
+        m: 'دقيقة',
+        mm: '%d دقائق',
+        h: 'ساعة',
+        hh: '%d ساعات',
+        d: 'يوم',
+        dd: '%d أيام',
+        M: 'شهر',
+        MM: '%d أشهر',
+        y: 'سنة',
+        yy: '%d سنوات'
+    },
+    week: {
+        dow: 1, // Monday is the first day of the week.
+        doy: 4 // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ar.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ar.js
new file mode 100644
index 0000000000000000000000000000000000000000..619843ae560d0f6bd54bef9087b00cbd23f25cab
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ar.js
@@ -0,0 +1,128 @@
+//! moment.js locale configuration
+//! locale : Arabic [ar]
+//! author : Abdel Said: https://github.com/abdelsaid
+//! author : Ahmed Elkhatib
+//! author : forabi https://github.com/forabi
+
+import moment from '../moment';
+
+var symbolMap = {
+    '1': 'Ù¡',
+    '2': 'Ù¢',
+    '3': 'Ù£',
+    '4': 'Ù¤',
+    '5': 'Ù¥',
+    '6': 'Ù¦',
+    '7': 'Ù§',
+    '8': 'Ù¨',
+    '9': 'Ù©',
+    '0': 'Ù '
+}, numberMap = {
+    'Ù¡': '1',
+    'Ù¢': '2',
+    'Ù£': '3',
+    'Ù¤': '4',
+    'Ù¥': '5',
+    'Ù¦': '6',
+    'Ù§': '7',
+    'Ù¨': '8',
+    'Ù©': '9',
+    'Ù ': '0'
+}, pluralForm = function (n) {
+    return n === 0 ? 0 : n === 1 ? 1 : n === 2 ? 2 : n % 100 >= 3 && n % 100 <= 10 ? 3 : n % 100 >= 11 ? 4 : 5;
+}, plurals = {
+    s : ['أقل من ثانية', 'ثانية واحدة', ['ثانيتان', 'ثانيتين'], '%d ثوان', '%d ثانية', '%d ثانية'],
+    m : ['أقل من دقيقة', 'دقيقة واحدة', ['دقيقتان', 'دقيقتين'], '%d دقائق', '%d دقيقة', '%d دقيقة'],
+    h : ['أقل من ساعة', 'ساعة واحدة', ['ساعتان', 'ساعتين'], '%d ساعات', '%d ساعة', '%d ساعة'],
+    d : ['أقل من يوم', 'يوم واحد', ['يومان', 'يومين'], '%d أيام', '%d يومًا', '%d يوم'],
+    M : ['أقل من شهر', 'شهر واحد', ['شهران', 'شهرين'], '%d أشهر', '%d شهرا', '%d شهر'],
+    y : ['أقل من عام', 'عام واحد', ['عامان', 'عامين'], '%d أعوام', '%d عامًا', '%d عام']
+}, pluralize = function (u) {
+    return function (number, withoutSuffix, string, isFuture) {
+        var f = pluralForm(number),
+            str = plurals[u][pluralForm(number)];
+        if (f === 2) {
+            str = str[withoutSuffix ? 0 : 1];
+        }
+        return str.replace(/%d/i, number);
+    };
+}, months = [
+    'كانون الثاني يناير',
+    'شباط فبراير',
+    'آذار مارس',
+    'نيسان أبريل',
+    'أيار مايو',
+    'حزيران يونيو',
+    'تموز يوليو',
+    'آب أغسطس',
+    'أيلول سبتمبر',
+    'تشرين الأول أكتوبر',
+    'تشرين الثاني نوفمبر',
+    'كانون الأول ديسمبر'
+];
+
+export default moment.defineLocale('ar', {
+    months : months,
+    monthsShort : months,
+    weekdays : 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
+    weekdaysShort : 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'),
+    weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'D/\u200FM/\u200FYYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    meridiemParse: /ص|م/,
+    isPM : function (input) {
+        return 'Ù…' === input;
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return 'ص';
+        } else {
+            return 'Ù…';
+        }
+    },
+    calendar : {
+        sameDay: '[اليوم عند الساعة] LT',
+        nextDay: '[غدًا عند الساعة] LT',
+        nextWeek: 'dddd [عند الساعة] LT',
+        lastDay: '[أمس عند الساعة] LT',
+        lastWeek: 'dddd [عند الساعة] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'بعد %s',
+        past : 'منذ %s',
+        s : pluralize('s'),
+        m : pluralize('m'),
+        mm : pluralize('m'),
+        h : pluralize('h'),
+        hh : pluralize('h'),
+        d : pluralize('d'),
+        dd : pluralize('d'),
+        M : pluralize('M'),
+        MM : pluralize('M'),
+        y : pluralize('y'),
+        yy : pluralize('y')
+    },
+    preparse: function (string) {
+        return string.replace(/\u200f/g, '').replace(/[١٢٣٤٥٦٧٨٩٠]/g, function (match) {
+            return numberMap[match];
+        }).replace(/،/g, ',');
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap[match];
+        }).replace(/,/g, '،');
+    },
+    week : {
+        dow : 6, // Saturday is the first day of the week.
+        doy : 12  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/az.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/az.js
new file mode 100644
index 0000000000000000000000000000000000000000..f9b368b816bfc3c0183b62e0159767bf949a6a6c
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/az.js
@@ -0,0 +1,96 @@
+//! moment.js locale configuration
+//! locale : Azerbaijani [az]
+//! author : topchiyev : https://github.com/topchiyev
+
+import moment from '../moment';
+
+var suffixes = {
+    1: '-inci',
+    5: '-inci',
+    8: '-inci',
+    70: '-inci',
+    80: '-inci',
+    2: '-nci',
+    7: '-nci',
+    20: '-nci',
+    50: '-nci',
+    3: '-üncü',
+    4: '-üncü',
+    100: '-üncü',
+    6: '-ncı',
+    9: '-uncu',
+    10: '-uncu',
+    30: '-uncu',
+    60: '-ıncı',
+    90: '-ıncı'
+};
+
+export default moment.defineLocale('az', {
+    months : 'yanvar_fevral_mart_aprel_may_iyun_iyul_avqust_sentyabr_oktyabr_noyabr_dekabr'.split('_'),
+    monthsShort : 'yan_fev_mar_apr_may_iyn_iyl_avq_sen_okt_noy_dek'.split('_'),
+    weekdays : 'Bazar_Bazar ertəsi_Çərşənbə axşamı_Çərşənbə_Cümə axşamı_Cümə_Şənbə'.split('_'),
+    weekdaysShort : 'Baz_BzE_ÇAx_Çər_CAx_Cüm_Şən'.split('_'),
+    weekdaysMin : 'Bz_BE_ÇA_Çə_CA_Cü_Şə'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[bugün saat] LT',
+        nextDay : '[sabah saat] LT',
+        nextWeek : '[gələn həftə] dddd [saat] LT',
+        lastDay : '[dünən] LT',
+        lastWeek : '[keçən həftə] dddd [saat] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s sonra',
+        past : '%s əvvəl',
+        s : 'birneçə saniyyə',
+        m : 'bir dəqiqə',
+        mm : '%d dəqiqə',
+        h : 'bir saat',
+        hh : '%d saat',
+        d : 'bir gün',
+        dd : '%d gün',
+        M : 'bir ay',
+        MM : '%d ay',
+        y : 'bir il',
+        yy : '%d il'
+    },
+    meridiemParse: /gecə|səhər|gündüz|axşam/,
+    isPM : function (input) {
+        return /^(gündüz|axşam)$/.test(input);
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'gecÉ™';
+        } else if (hour < 12) {
+            return 'səhər';
+        } else if (hour < 17) {
+            return 'gündüz';
+        } else {
+            return 'axÅŸam';
+        }
+    },
+    ordinalParse: /\d{1,2}-(ıncı|inci|nci|üncü|ncı|uncu)/,
+    ordinal : function (number) {
+        if (number === 0) {  // special case for zero
+            return number + '-ıncı';
+        }
+        var a = number % 10,
+            b = number % 100 - a,
+            c = number >= 100 ? 100 : null;
+        return number + (suffixes[a] || suffixes[b] || suffixes[c]);
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/be.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/be.js
new file mode 100644
index 0000000000000000000000000000000000000000..c22c6e1e69c8a05c6bbf93e7ee6b030590607f83
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/be.js
@@ -0,0 +1,125 @@
+//! moment.js locale configuration
+//! locale : Belarusian [be]
+//! author : Dmitry Demidov : https://github.com/demidov91
+//! author: Praleska: http://praleska.pro/
+//! Author : Menelion Elensúle : https://github.com/Oire
+
+import moment from '../moment';
+
+function plural(word, num) {
+    var forms = word.split('_');
+    return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]);
+}
+function relativeTimeWithPlural(number, withoutSuffix, key) {
+    var format = {
+        'mm': withoutSuffix ? 'хвіліна_хвіліны_хвілін' : 'хвіліну_хвіліны_хвілін',
+        'hh': withoutSuffix ? 'гадзіна_гадзіны_гадзін' : 'гадзіну_гадзіны_гадзін',
+        'dd': 'дзень_дні_дзён',
+        'MM': 'месяц_месяцы_месяцаў',
+        'yy': 'год_гады_гадоў'
+    };
+    if (key === 'm') {
+        return withoutSuffix ? 'хвіліна' : 'хвіліну';
+    }
+    else if (key === 'h') {
+        return withoutSuffix ? 'гадзіна' : 'гадзіну';
+    }
+    else {
+        return number + ' ' + plural(format[key], +number);
+    }
+}
+
+export default moment.defineLocale('be', {
+    months : {
+        format: 'студзеня_лютага_сакавіка_красавіка_траўня_чэрвеня_ліпеня_жніўня_верасня_кастрычніка_лістапада_снежня'.split('_'),
+        standalone: 'студзень_люты_сакавік_красавік_травень_чэрвень_ліпень_жнівень_верасень_кастрычнік_лістапад_снежань'.split('_')
+    },
+    monthsShort : 'студ_лют_сак_крас_трав_чэрв_ліп_жнів_вер_каст_ліст_снеж'.split('_'),
+    weekdays : {
+        format: 'нядзелю_панядзелак_аўторак_сераду_чацвер_пятніцу_суботу'.split('_'),
+        standalone: 'нядзеля_панядзелак_аўторак_серада_чацвер_пятніца_субота'.split('_'),
+        isFormat: /\[ ?[Вв] ?(?:мінулую|наступную)? ?\] ?dddd/
+    },
+    weekdaysShort : 'нд_пн_ат_ср_чц_пт_сб'.split('_'),
+    weekdaysMin : 'нд_пн_ат_ср_чц_пт_сб'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY г.',
+        LLL : 'D MMMM YYYY г., HH:mm',
+        LLLL : 'dddd, D MMMM YYYY г., HH:mm'
+    },
+    calendar : {
+        sameDay: '[Сёння ў] LT',
+        nextDay: '[Заўтра ў] LT',
+        lastDay: '[Учора ў] LT',
+        nextWeek: function () {
+            return '[У] dddd [ў] LT';
+        },
+        lastWeek: function () {
+            switch (this.day()) {
+                case 0:
+                case 3:
+                case 5:
+                case 6:
+                    return '[У мінулую] dddd [ў] LT';
+                case 1:
+                case 2:
+                case 4:
+                    return '[У мінулы] dddd [ў] LT';
+            }
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'праз %s',
+        past : '%s таму',
+        s : 'некалькі секунд',
+        m : relativeTimeWithPlural,
+        mm : relativeTimeWithPlural,
+        h : relativeTimeWithPlural,
+        hh : relativeTimeWithPlural,
+        d : 'дзень',
+        dd : relativeTimeWithPlural,
+        M : 'месяц',
+        MM : relativeTimeWithPlural,
+        y : 'год',
+        yy : relativeTimeWithPlural
+    },
+    meridiemParse: /ночы|раніцы|дня|вечара/,
+    isPM : function (input) {
+        return /^(дня|вечара)$/.test(input);
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'ночы';
+        } else if (hour < 12) {
+            return 'раніцы';
+        } else if (hour < 17) {
+            return 'дня';
+        } else {
+            return 'вечара';
+        }
+    },
+    ordinalParse: /\d{1,2}-(і|ы|га)/,
+    ordinal: function (number, period) {
+        switch (period) {
+            case 'M':
+            case 'd':
+            case 'DDD':
+            case 'w':
+            case 'W':
+                return (number % 10 === 2 || number % 10 === 3) && (number % 100 !== 12 && number % 100 !== 13) ? number + '-Ñ–' : number + '-Ñ‹';
+            case 'D':
+                return number + '-га';
+            default:
+                return number;
+        }
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/bg-x.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/bg-x.js
new file mode 100644
index 0000000000000000000000000000000000000000..0fb9de0fbd8b3ddd33478c809fac082c90a84949
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/bg-x.js
@@ -0,0 +1,5 @@
+import moment from '../moment';
+
+export default moment.defineLocale('bg-x', {
+    parentLocale: 'bg'
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/bg.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/bg.js
new file mode 100644
index 0000000000000000000000000000000000000000..0c4597ed5a91fe75250ed0519100d65e21d5ebe5
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/bg.js
@@ -0,0 +1,81 @@
+//! moment.js locale configuration
+//! locale : Bulgarian [bg]
+//! author : Krasen Borisov : https://github.com/kraz
+
+import moment from '../moment';
+
+export default moment.defineLocale('bg', {
+    months : 'януари_февруари_март_април_май_юни_юли_август_септември_октомври_ноември_декември'.split('_'),
+    monthsShort : 'янр_фев_мар_апр_май_юни_юли_авг_сеп_окт_ное_дек'.split('_'),
+    weekdays : 'неделя_понеделник_вторник_сряда_четвъртък_петък_събота'.split('_'),
+    weekdaysShort : 'нед_пон_вто_сря_чет_пет_съб'.split('_'),
+    weekdaysMin : 'нд_пн_вт_ср_чт_пт_сб'.split('_'),
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'D.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY H:mm',
+        LLLL : 'dddd, D MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay : '[Днес в] LT',
+        nextDay : '[Утре в] LT',
+        nextWeek : 'dddd [в] LT',
+        lastDay : '[Вчера в] LT',
+        lastWeek : function () {
+            switch (this.day()) {
+                case 0:
+                case 3:
+                case 6:
+                    return '[В изминалата] dddd [в] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[В изминалия] dddd [в] LT';
+            }
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'след %s',
+        past : 'преди %s',
+        s : 'няколко секунди',
+        m : 'минута',
+        mm : '%d минути',
+        h : 'час',
+        hh : '%d часа',
+        d : 'ден',
+        dd : '%d дни',
+        M : 'месец',
+        MM : '%d месеца',
+        y : 'година',
+        yy : '%d години'
+    },
+    ordinalParse: /\d{1,2}-(ев|ен|ти|ви|ри|ми)/,
+    ordinal : function (number) {
+        var lastDigit = number % 10,
+            last2Digits = number % 100;
+        if (number === 0) {
+            return number + '-ев';
+        } else if (last2Digits === 0) {
+            return number + '-ен';
+        } else if (last2Digits > 10 && last2Digits < 20) {
+            return number + '-ти';
+        } else if (lastDigit === 1) {
+            return number + '-ви';
+        } else if (lastDigit === 2) {
+            return number + '-ри';
+        } else if (lastDigit === 7 || lastDigit === 8) {
+            return number + '-ми';
+        } else {
+            return number + '-ти';
+        }
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/bn.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/bn.js
new file mode 100644
index 0000000000000000000000000000000000000000..359a376dc7a1b66aa4441629cdfabb0cc2d9da83
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/bn.js
@@ -0,0 +1,109 @@
+//! moment.js locale configuration
+//! locale : Bengali [bn]
+//! author : Kaushik Gandhi : https://github.com/kaushikgandhi
+
+import moment from '../moment';
+
+var symbolMap = {
+    '1': 'à§§',
+    '2': '২',
+    '3': 'à§©',
+    '4': '৪',
+    '5': 'à§«',
+    '6': '৬',
+    '7': 'à§­',
+    '8': 'à§®',
+    '9': '৯',
+    '0': '০'
+},
+numberMap = {
+    'à§§': '1',
+    '২': '2',
+    'à§©': '3',
+    '৪': '4',
+    'à§«': '5',
+    '৬': '6',
+    'à§­': '7',
+    'à§®': '8',
+    '৯': '9',
+    '০': '0'
+};
+
+export default moment.defineLocale('bn', {
+    months : 'জানুয়ারী_ফেব্রুয়ারি_মার্চ_এপ্রিল_মে_জুন_জুলাই_আগস্ট_সেপ্টেম্বর_অক্টোবর_নভেম্বর_ডিসেম্বর'.split('_'),
+    monthsShort : 'জানু_ফেব_মার্চ_এপ্র_মে_জুন_জুল_আগ_সেপ্ট_অক্টো_নভে_ডিসে'.split('_'),
+    weekdays : 'রবিবার_সোমবার_মঙ্গলবার_বুধবার_বৃহস্পতিবার_শুক্রবার_শনিবার'.split('_'),
+    weekdaysShort : 'রবি_সোম_মঙ্গল_বুধ_বৃহস্পতি_শুক্র_শনি'.split('_'),
+    weekdaysMin : 'রবি_সোম_মঙ্গ_বুধ_বৃহঃ_শুক্র_শনি'.split('_'),
+    longDateFormat : {
+        LT : 'A h:mm সময়',
+        LTS : 'A h:mm:ss সময়',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, A h:mm সময়',
+        LLLL : 'dddd, D MMMM YYYY, A h:mm সময়'
+    },
+    calendar : {
+        sameDay : '[আজ] LT',
+        nextDay : '[আগামীকাল] LT',
+        nextWeek : 'dddd, LT',
+        lastDay : '[গতকাল] LT',
+        lastWeek : '[গত] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s পরে',
+        past : '%s আগে',
+        s : 'কয়েক সেকেন্ড',
+        m : 'এক মিনিট',
+        mm : '%d মিনিট',
+        h : 'এক ঘন্টা',
+        hh : '%d ঘন্টা',
+        d : 'এক দিন',
+        dd : '%d দিন',
+        M : 'এক মাস',
+        MM : '%d মাস',
+        y : 'এক বছর',
+        yy : '%d বছর'
+    },
+    preparse: function (string) {
+        return string.replace(/[১২৩৪৫৬৭৮৯০]/g, function (match) {
+            return numberMap[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap[match];
+        });
+    },
+    meridiemParse: /রাত|সকাল|দুপুর|বিকাল|রাত/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if ((meridiem === 'রাত' && hour >= 4) ||
+                (meridiem === 'দুপুর' && hour < 5) ||
+                meridiem === 'বিকাল') {
+            return hour + 12;
+        } else {
+            return hour;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'রাত';
+        } else if (hour < 10) {
+            return 'সকাল';
+        } else if (hour < 17) {
+            return 'দুপুর';
+        } else if (hour < 20) {
+            return 'বিকাল';
+        } else {
+            return 'রাত';
+        }
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/bo.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/bo.js
new file mode 100644
index 0000000000000000000000000000000000000000..5d15d84480d8f79381fc1b3eb7c36d3991c4569c
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/bo.js
@@ -0,0 +1,110 @@
+//! moment.js locale configuration
+//! locale : Tibetan [bo]
+//! author : Thupten N. Chakrishar : https://github.com/vajradog
+
+import moment from '../moment';
+
+var symbolMap = {
+    '1': '༡',
+    '2': '༢',
+    '3': '༣',
+    '4': '༤',
+    '5': '༥',
+    '6': '༦',
+    '7': '༧',
+    '8': '༨',
+    '9': '༩',
+    '0': '༠'
+},
+numberMap = {
+    '༡': '1',
+    '༢': '2',
+    '༣': '3',
+    '༤': '4',
+    '༥': '5',
+    '༦': '6',
+    '༧': '7',
+    '༨': '8',
+    '༩': '9',
+    '༠': '0'
+};
+
+export default moment.defineLocale('bo', {
+    months : 'ཟླ་བ་དང་པོ_ཟླ་བ་གཉིས་པ_ཟླ་བ་གསུམ་པ_ཟླ་བ་བཞི་པ_ཟླ་བ་ལྔ་པ_ཟླ་བ་དྲུག་པ_ཟླ་བ་བདུན་པ_ཟླ་བ་བརྒྱད་པ_ཟླ་བ་དགུ་པ_ཟླ་བ་བཅུ་པ_ཟླ་བ་བཅུ་གཅིག་པ_ཟླ་བ་བཅུ་གཉིས་པ'.split('_'),
+    monthsShort : 'ཟླ་བ་དང་པོ_ཟླ་བ་གཉིས་པ_ཟླ་བ་གསུམ་པ_ཟླ་བ་བཞི་པ_ཟླ་བ་ལྔ་པ_ཟླ་བ་དྲུག་པ_ཟླ་བ་བདུན་པ_ཟླ་བ་བརྒྱད་པ_ཟླ་བ་དགུ་པ_ཟླ་བ་བཅུ་པ_ཟླ་བ་བཅུ་གཅིག་པ_ཟླ་བ་བཅུ་གཉིས་པ'.split('_'),
+    weekdays : 'གཟའ་ཉི་མ་_གཟའ་ཟླ་བ་_གཟའ་མིག་དམར་_གཟའ་ལྷག་པ་_གཟའ་ཕུར་བུ_གཟའ་པ་སངས་_གཟའ་སྤེན་པ་'.split('_'),
+    weekdaysShort : 'ཉི་མ་_ཟླ་བ་_མིག་དམར་_ལྷག་པ་_ཕུར་བུ_པ་སངས་_སྤེན་པ་'.split('_'),
+    weekdaysMin : 'ཉི་མ་_ཟླ་བ་_མིག་དམར་_ལྷག་པ་_ཕུར་བུ_པ་སངས་_སྤེན་པ་'.split('_'),
+    longDateFormat : {
+        LT : 'A h:mm',
+        LTS : 'A h:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, A h:mm',
+        LLLL : 'dddd, D MMMM YYYY, A h:mm'
+    },
+    calendar : {
+        sameDay : '[དི་རིང] LT',
+        nextDay : '[སང་ཉིན] LT',
+        nextWeek : '[བདུན་ཕྲག་རྗེས་མ], LT',
+        lastDay : '[ཁ་སང] LT',
+        lastWeek : '[བདུན་ཕྲག་མཐའ་མ] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s ལ་',
+        past : '%s སྔན་ལ',
+        s : 'ལམ་སང',
+        m : 'སྐར་མ་གཅིག',
+        mm : '%d སྐར་མ',
+        h : 'ཆུ་ཚོད་གཅིག',
+        hh : '%d ཆུ་ཚོད',
+        d : 'ཉིན་གཅིག',
+        dd : '%d ཉིན་',
+        M : 'ཟླ་བ་གཅིག',
+        MM : '%d ཟླ་བ',
+        y : 'ལོ་གཅིག',
+        yy : '%d ལོ'
+    },
+    preparse: function (string) {
+        return string.replace(/[༡༢༣༤༥༦༧༨༩༠]/g, function (match) {
+            return numberMap[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap[match];
+        });
+    },
+    meridiemParse: /མཚན་མོ|ཞོགས་ཀས|ཉིན་གུང|དགོང་དག|མཚན་མོ/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if ((meridiem === 'མཚན་མོ' && hour >= 4) ||
+                (meridiem === 'ཉིན་གུང' && hour < 5) ||
+                meridiem === 'དགོང་དག') {
+            return hour + 12;
+        } else {
+            return hour;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'མཚན་མོ';
+        } else if (hour < 10) {
+            return 'ཞོགས་ཀས';
+        } else if (hour < 17) {
+            return 'ཉིན་གུང';
+        } else if (hour < 20) {
+            return 'དགོང་དག';
+        } else {
+            return 'མཚན་མོ';
+        }
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/br.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/br.js
new file mode 100644
index 0000000000000000000000000000000000000000..86c580d47489887222473259f1fc1e7b0aeb2434
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/br.js
@@ -0,0 +1,99 @@
+//! moment.js locale configuration
+//! locale : Breton [br]
+//! author : Jean-Baptiste Le Duigou : https://github.com/jbleduigou
+
+import moment from '../moment';
+
+function relativeTimeWithMutation(number, withoutSuffix, key) {
+    var format = {
+        'mm': 'munutenn',
+        'MM': 'miz',
+        'dd': 'devezh'
+    };
+    return number + ' ' + mutation(format[key], number);
+}
+function specialMutationForYears(number) {
+    switch (lastNumber(number)) {
+        case 1:
+        case 3:
+        case 4:
+        case 5:
+        case 9:
+            return number + ' bloaz';
+        default:
+            return number + ' vloaz';
+    }
+}
+function lastNumber(number) {
+    if (number > 9) {
+        return lastNumber(number % 10);
+    }
+    return number;
+}
+function mutation(text, number) {
+    if (number === 2) {
+        return softMutation(text);
+    }
+    return text;
+}
+function softMutation(text) {
+    var mutationTable = {
+        'm': 'v',
+        'b': 'v',
+        'd': 'z'
+    };
+    if (mutationTable[text.charAt(0)] === undefined) {
+        return text;
+    }
+    return mutationTable[text.charAt(0)] + text.substring(1);
+}
+
+export default moment.defineLocale('br', {
+    months : 'Genver_C\'hwevrer_Meurzh_Ebrel_Mae_Mezheven_Gouere_Eost_Gwengolo_Here_Du_Kerzu'.split('_'),
+    monthsShort : 'Gen_C\'hwe_Meu_Ebr_Mae_Eve_Gou_Eos_Gwe_Her_Du_Ker'.split('_'),
+    weekdays : 'Sul_Lun_Meurzh_Merc\'her_Yaou_Gwener_Sadorn'.split('_'),
+    weekdaysShort : 'Sul_Lun_Meu_Mer_Yao_Gwe_Sad'.split('_'),
+    weekdaysMin : 'Su_Lu_Me_Mer_Ya_Gw_Sa'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'h[e]mm A',
+        LTS : 'h[e]mm:ss A',
+        L : 'DD/MM/YYYY',
+        LL : 'D [a viz] MMMM YYYY',
+        LLL : 'D [a viz] MMMM YYYY h[e]mm A',
+        LLLL : 'dddd, D [a viz] MMMM YYYY h[e]mm A'
+    },
+    calendar : {
+        sameDay : '[Hiziv da] LT',
+        nextDay : '[Warc\'hoazh da] LT',
+        nextWeek : 'dddd [da] LT',
+        lastDay : '[Dec\'h da] LT',
+        lastWeek : 'dddd [paset da] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'a-benn %s',
+        past : '%s \'zo',
+        s : 'un nebeud segondennoù',
+        m : 'ur vunutenn',
+        mm : relativeTimeWithMutation,
+        h : 'un eur',
+        hh : '%d eur',
+        d : 'un devezh',
+        dd : relativeTimeWithMutation,
+        M : 'ur miz',
+        MM : relativeTimeWithMutation,
+        y : 'ur bloaz',
+        yy : specialMutationForYears
+    },
+    ordinalParse: /\d{1,2}(añ|vet)/,
+    ordinal : function (number) {
+        var output = (number === 1) ? 'añ' : 'vet';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/bs.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/bs.js
new file mode 100644
index 0000000000000000000000000000000000000000..90cb0b96c60afd8c5331e6afc5aa702d6f289f6f
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/bs.js
@@ -0,0 +1,133 @@
+//! moment.js locale configuration
+//! locale : Bosnian [bs]
+//! author : Nedim Cholich : https://github.com/frontyard
+//! based on (hr) translation by Bojan Marković
+
+import moment from '../moment';
+
+function translate(number, withoutSuffix, key) {
+    var result = number + ' ';
+    switch (key) {
+        case 'm':
+            return withoutSuffix ? 'jedna minuta' : 'jedne minute';
+        case 'mm':
+            if (number === 1) {
+                result += 'minuta';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'minute';
+            } else {
+                result += 'minuta';
+            }
+            return result;
+        case 'h':
+            return withoutSuffix ? 'jedan sat' : 'jednog sata';
+        case 'hh':
+            if (number === 1) {
+                result += 'sat';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'sata';
+            } else {
+                result += 'sati';
+            }
+            return result;
+        case 'dd':
+            if (number === 1) {
+                result += 'dan';
+            } else {
+                result += 'dana';
+            }
+            return result;
+        case 'MM':
+            if (number === 1) {
+                result += 'mjesec';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'mjeseca';
+            } else {
+                result += 'mjeseci';
+            }
+            return result;
+        case 'yy':
+            if (number === 1) {
+                result += 'godina';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'godine';
+            } else {
+                result += 'godina';
+            }
+            return result;
+    }
+}
+
+export default moment.defineLocale('bs', {
+    months : 'januar_februar_mart_april_maj_juni_juli_august_septembar_oktobar_novembar_decembar'.split('_'),
+    monthsShort : 'jan._feb._mar._apr._maj._jun._jul._aug._sep._okt._nov._dec.'.split('_'),
+    monthsParseExact: true,
+    weekdays : 'nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota'.split('_'),
+    weekdaysShort : 'ned._pon._uto._sri._čet._pet._sub.'.split('_'),
+    weekdaysMin : 'ne_po_ut_sr_če_pe_su'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY H:mm',
+        LLLL : 'dddd, D. MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay  : '[danas u] LT',
+        nextDay  : '[sutra u] LT',
+        nextWeek : function () {
+            switch (this.day()) {
+                case 0:
+                    return '[u] [nedjelju] [u] LT';
+                case 3:
+                    return '[u] [srijedu] [u] LT';
+                case 6:
+                    return '[u] [subotu] [u] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[u] dddd [u] LT';
+            }
+        },
+        lastDay  : '[jučer u] LT',
+        lastWeek : function () {
+            switch (this.day()) {
+                case 0:
+                case 3:
+                    return '[prošlu] dddd [u] LT';
+                case 6:
+                    return '[prošle] [subote] [u] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[prošli] dddd [u] LT';
+            }
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'za %s',
+        past   : 'prije %s',
+        s      : 'par sekundi',
+        m      : translate,
+        mm     : translate,
+        h      : translate,
+        hh     : translate,
+        d      : 'dan',
+        dd     : translate,
+        M      : 'mjesec',
+        MM     : translate,
+        y      : 'godinu',
+        yy     : translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ca.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ca.js
new file mode 100644
index 0000000000000000000000000000000000000000..7e9c570893f7ba350ba70516f47780946a031b42
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ca.js
@@ -0,0 +1,72 @@
+//! moment.js locale configuration
+//! locale : Catalan [ca]
+//! author : Juan G. Hurtado : https://github.com/juanghurtado
+
+import moment from '../moment';
+
+export default moment.defineLocale('ca', {
+    months : 'gener_febrer_març_abril_maig_juny_juliol_agost_setembre_octubre_novembre_desembre'.split('_'),
+    monthsShort : 'gen._febr._mar._abr._mai._jun._jul._ag._set._oct._nov._des.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'diumenge_dilluns_dimarts_dimecres_dijous_divendres_dissabte'.split('_'),
+    weekdaysShort : 'dg._dl._dt._dc._dj._dv._ds.'.split('_'),
+    weekdaysMin : 'Dg_Dl_Dt_Dc_Dj_Dv_Ds'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY H:mm',
+        LLLL : 'dddd D MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay : function () {
+            return '[avui a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
+        },
+        nextDay : function () {
+            return '[demà a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
+        },
+        nextWeek : function () {
+            return 'dddd [a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
+        },
+        lastDay : function () {
+            return '[ahir a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
+        },
+        lastWeek : function () {
+            return '[el] dddd [passat a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'en %s',
+        past : 'fa %s',
+        s : 'uns segons',
+        m : 'un minut',
+        mm : '%d minuts',
+        h : 'una hora',
+        hh : '%d hores',
+        d : 'un dia',
+        dd : '%d dies',
+        M : 'un mes',
+        MM : '%d mesos',
+        y : 'un any',
+        yy : '%d anys'
+    },
+    ordinalParse: /\d{1,2}(r|n|t|è|a)/,
+    ordinal : function (number, period) {
+        var output = (number === 1) ? 'r' :
+            (number === 2) ? 'n' :
+            (number === 3) ? 'r' :
+            (number === 4) ? 't' : 'è';
+        if (period === 'w' || period === 'W') {
+            output = 'a';
+        }
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/cs.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/cs.js
new file mode 100644
index 0000000000000000000000000000000000000000..621b8031c3dd1702476394feb3cc36b0a42df3f0
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/cs.js
@@ -0,0 +1,163 @@
+//! moment.js locale configuration
+//! locale : Czech [cs]
+//! author : petrbela : https://github.com/petrbela
+
+import moment from '../moment';
+
+var months = 'leden_únor_březen_duben_květen_červen_červenec_srpen_září_říjen_listopad_prosinec'.split('_'),
+    monthsShort = 'led_úno_bře_dub_kvě_čvn_čvc_srp_zář_říj_lis_pro'.split('_');
+function plural(n) {
+    return (n > 1) && (n < 5) && (~~(n / 10) !== 1);
+}
+function translate(number, withoutSuffix, key, isFuture) {
+    var result = number + ' ';
+    switch (key) {
+        case 's':  // a few seconds / in a few seconds / a few seconds ago
+            return (withoutSuffix || isFuture) ? 'pár sekund' : 'pár sekundami';
+        case 'm':  // a minute / in a minute / a minute ago
+            return withoutSuffix ? 'minuta' : (isFuture ? 'minutu' : 'minutou');
+        case 'mm': // 9 minutes / in 9 minutes / 9 minutes ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural(number) ? 'minuty' : 'minut');
+            } else {
+                return result + 'minutami';
+            }
+            break;
+        case 'h':  // an hour / in an hour / an hour ago
+            return withoutSuffix ? 'hodina' : (isFuture ? 'hodinu' : 'hodinou');
+        case 'hh': // 9 hours / in 9 hours / 9 hours ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural(number) ? 'hodiny' : 'hodin');
+            } else {
+                return result + 'hodinami';
+            }
+            break;
+        case 'd':  // a day / in a day / a day ago
+            return (withoutSuffix || isFuture) ? 'den' : 'dnem';
+        case 'dd': // 9 days / in 9 days / 9 days ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural(number) ? 'dny' : 'dní');
+            } else {
+                return result + 'dny';
+            }
+            break;
+        case 'M':  // a month / in a month / a month ago
+            return (withoutSuffix || isFuture) ? 'měsíc' : 'měsícem';
+        case 'MM': // 9 months / in 9 months / 9 months ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural(number) ? 'měsíce' : 'měsíců');
+            } else {
+                return result + 'měsíci';
+            }
+            break;
+        case 'y':  // a year / in a year / a year ago
+            return (withoutSuffix || isFuture) ? 'rok' : 'rokem';
+        case 'yy': // 9 years / in 9 years / 9 years ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural(number) ? 'roky' : 'let');
+            } else {
+                return result + 'lety';
+            }
+            break;
+    }
+}
+
+export default moment.defineLocale('cs', {
+    months : months,
+    monthsShort : monthsShort,
+    monthsParse : (function (months, monthsShort) {
+        var i, _monthsParse = [];
+        for (i = 0; i < 12; i++) {
+            // use custom parser to solve problem with July (červenec)
+            _monthsParse[i] = new RegExp('^' + months[i] + '$|^' + monthsShort[i] + '$', 'i');
+        }
+        return _monthsParse;
+    }(months, monthsShort)),
+    shortMonthsParse : (function (monthsShort) {
+        var i, _shortMonthsParse = [];
+        for (i = 0; i < 12; i++) {
+            _shortMonthsParse[i] = new RegExp('^' + monthsShort[i] + '$', 'i');
+        }
+        return _shortMonthsParse;
+    }(monthsShort)),
+    longMonthsParse : (function (months) {
+        var i, _longMonthsParse = [];
+        for (i = 0; i < 12; i++) {
+            _longMonthsParse[i] = new RegExp('^' + months[i] + '$', 'i');
+        }
+        return _longMonthsParse;
+    }(months)),
+    weekdays : 'neděle_pondělí_úterý_středa_čtvrtek_pátek_sobota'.split('_'),
+    weekdaysShort : 'ne_po_út_st_čt_pá_so'.split('_'),
+    weekdaysMin : 'ne_po_út_st_čt_pá_so'.split('_'),
+    longDateFormat : {
+        LT: 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY H:mm',
+        LLLL : 'dddd D. MMMM YYYY H:mm',
+        l : 'D. M. YYYY'
+    },
+    calendar : {
+        sameDay: '[dnes v] LT',
+        nextDay: '[zítra v] LT',
+        nextWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[v neděli v] LT';
+                case 1:
+                case 2:
+                    return '[v] dddd [v] LT';
+                case 3:
+                    return '[ve středu v] LT';
+                case 4:
+                    return '[ve čtvrtek v] LT';
+                case 5:
+                    return '[v pátek v] LT';
+                case 6:
+                    return '[v sobotu v] LT';
+            }
+        },
+        lastDay: '[včera v] LT',
+        lastWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[minulou neděli v] LT';
+                case 1:
+                case 2:
+                    return '[minulé] dddd [v] LT';
+                case 3:
+                    return '[minulou středu v] LT';
+                case 4:
+                case 5:
+                    return '[minulý] dddd [v] LT';
+                case 6:
+                    return '[minulou sobotu v] LT';
+            }
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'za %s',
+        past : 'před %s',
+        s : translate,
+        m : translate,
+        mm : translate,
+        h : translate,
+        hh : translate,
+        d : translate,
+        dd : translate,
+        M : translate,
+        MM : translate,
+        y : translate,
+        yy : translate
+    },
+    ordinalParse : /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/cv.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/cv.js
new file mode 100644
index 0000000000000000000000000000000000000000..1884d2dbf2ab899f1d7c7eee01c52e7268b8e5af
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/cv.js
@@ -0,0 +1,53 @@
+//! moment.js locale configuration
+//! locale : Chuvash [cv]
+//! author : Anatoly Mironov : https://github.com/mirontoli
+
+import moment from '../moment';
+
+export default moment.defineLocale('cv', {
+    months : 'кӑрлач_нарӑс_пуш_ака_май_ҫӗртме_утӑ_ҫурла_авӑн_юпа_чӳк_раштав'.split('_'),
+    monthsShort : 'кӑр_нар_пуш_ака_май_ҫӗр_утӑ_ҫур_авн_юпа_чӳк_раш'.split('_'),
+    weekdays : 'вырсарникун_тунтикун_ытларикун_юнкун_кӗҫнерникун_эрнекун_шӑматкун'.split('_'),
+    weekdaysShort : 'выр_тун_ытл_юн_кӗҫ_эрн_шӑм'.split('_'),
+    weekdaysMin : 'вр_тн_ыт_юн_кҫ_эр_шм'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD-MM-YYYY',
+        LL : 'YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ]',
+        LLL : 'YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm',
+        LLLL : 'dddd, YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm'
+    },
+    calendar : {
+        sameDay: '[Паян] LT [сехетре]',
+        nextDay: '[Ыран] LT [сехетре]',
+        lastDay: '[Ӗнер] LT [сехетре]',
+        nextWeek: '[Ҫитес] dddd LT [сехетре]',
+        lastWeek: '[Иртнӗ] dddd LT [сехетре]',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : function (output) {
+            var affix = /сехет$/i.exec(output) ? 'рен' : /ҫул$/i.exec(output) ? 'тан' : 'ран';
+            return output + affix;
+        },
+        past : '%s каялла',
+        s : 'пӗр-ик ҫеккунт',
+        m : 'пӗр минут',
+        mm : '%d минут',
+        h : 'пӗр сехет',
+        hh : '%d сехет',
+        d : 'пӗр кун',
+        dd : '%d кун',
+        M : 'пӗр уйӑх',
+        MM : '%d уйӑх',
+        y : 'пӗр ҫул',
+        yy : '%d ҫул'
+    },
+    ordinalParse: /\d{1,2}-мӗш/,
+    ordinal : '%d-мӗш',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/cy.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/cy.js
new file mode 100644
index 0000000000000000000000000000000000000000..972b7009925cafc58cdfd0ca8841751a79bab658
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/cy.js
@@ -0,0 +1,72 @@
+//! moment.js locale configuration
+//! locale : Welsh [cy]
+//! author : Robert Allen : https://github.com/robgallen
+//! author : https://github.com/ryangreaves
+
+import moment from '../moment';
+
+export default moment.defineLocale('cy', {
+    months: 'Ionawr_Chwefror_Mawrth_Ebrill_Mai_Mehefin_Gorffennaf_Awst_Medi_Hydref_Tachwedd_Rhagfyr'.split('_'),
+    monthsShort: 'Ion_Chwe_Maw_Ebr_Mai_Meh_Gor_Aws_Med_Hyd_Tach_Rhag'.split('_'),
+    weekdays: 'Dydd Sul_Dydd Llun_Dydd Mawrth_Dydd Mercher_Dydd Iau_Dydd Gwener_Dydd Sadwrn'.split('_'),
+    weekdaysShort: 'Sul_Llun_Maw_Mer_Iau_Gwe_Sad'.split('_'),
+    weekdaysMin: 'Su_Ll_Ma_Me_Ia_Gw_Sa'.split('_'),
+    weekdaysParseExact : true,
+    // time formats are the same as en-gb
+    longDateFormat: {
+        LT: 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L: 'DD/MM/YYYY',
+        LL: 'D MMMM YYYY',
+        LLL: 'D MMMM YYYY HH:mm',
+        LLLL: 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar: {
+        sameDay: '[Heddiw am] LT',
+        nextDay: '[Yfory am] LT',
+        nextWeek: 'dddd [am] LT',
+        lastDay: '[Ddoe am] LT',
+        lastWeek: 'dddd [diwethaf am] LT',
+        sameElse: 'L'
+    },
+    relativeTime: {
+        future: 'mewn %s',
+        past: '%s yn ôl',
+        s: 'ychydig eiliadau',
+        m: 'munud',
+        mm: '%d munud',
+        h: 'awr',
+        hh: '%d awr',
+        d: 'diwrnod',
+        dd: '%d diwrnod',
+        M: 'mis',
+        MM: '%d mis',
+        y: 'blwyddyn',
+        yy: '%d flynedd'
+    },
+    ordinalParse: /\d{1,2}(fed|ain|af|il|ydd|ed|eg)/,
+    // traditional ordinal numbers above 31 are not commonly used in colloquial Welsh
+    ordinal: function (number) {
+        var b = number,
+            output = '',
+            lookup = [
+                '', 'af', 'il', 'ydd', 'ydd', 'ed', 'ed', 'ed', 'fed', 'fed', 'fed', // 1af to 10fed
+                'eg', 'fed', 'eg', 'eg', 'fed', 'eg', 'eg', 'fed', 'eg', 'fed' // 11eg to 20fed
+            ];
+        if (b > 20) {
+            if (b === 40 || b === 50 || b === 60 || b === 80 || b === 100) {
+                output = 'fed'; // not 30ain, 70ain or 90ain
+            } else {
+                output = 'ain';
+            }
+        } else if (b > 0) {
+            output = lookup[b];
+        }
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/da.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/da.js
new file mode 100644
index 0000000000000000000000000000000000000000..da2316cadca4982b019a7415954c916a94af409e
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/da.js
@@ -0,0 +1,51 @@
+//! moment.js locale configuration
+//! locale : Danish [da]
+//! author : Ulrik Nielsen : https://github.com/mrbase
+
+import moment from '../moment';
+
+export default moment.defineLocale('da', {
+    months : 'januar_februar_marts_april_maj_juni_juli_august_september_oktober_november_december'.split('_'),
+    monthsShort : 'jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec'.split('_'),
+    weekdays : 'søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag'.split('_'),
+    weekdaysShort : 'søn_man_tir_ons_tor_fre_lør'.split('_'),
+    weekdaysMin : 'sø_ma_ti_on_to_fr_lø'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY HH:mm',
+        LLLL : 'dddd [d.] D. MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[I dag kl.] LT',
+        nextDay : '[I morgen kl.] LT',
+        nextWeek : 'dddd [kl.] LT',
+        lastDay : '[I går kl.] LT',
+        lastWeek : '[sidste] dddd [kl] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'om %s',
+        past : '%s siden',
+        s : 'få sekunder',
+        m : 'et minut',
+        mm : '%d minutter',
+        h : 'en time',
+        hh : '%d timer',
+        d : 'en dag',
+        dd : '%d dage',
+        M : 'en måned',
+        MM : '%d måneder',
+        y : 'et år',
+        yy : '%d år'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/de-at.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/de-at.js
new file mode 100644
index 0000000000000000000000000000000000000000..4e59f687258f21ae780c8322a9ab9b5eb2a100e7
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/de-at.js
@@ -0,0 +1,69 @@
+//! moment.js locale configuration
+//! locale : German (Austria) [de-at]
+//! author : lluchs : https://github.com/lluchs
+//! author: Menelion Elensúle: https://github.com/Oire
+//! author : Martin Groller : https://github.com/MadMG
+//! author : Mikolaj Dadela : https://github.com/mik01aj
+
+import moment from '../moment';
+
+function processRelativeTime(number, withoutSuffix, key, isFuture) {
+    var format = {
+        'm': ['eine Minute', 'einer Minute'],
+        'h': ['eine Stunde', 'einer Stunde'],
+        'd': ['ein Tag', 'einem Tag'],
+        'dd': [number + ' Tage', number + ' Tagen'],
+        'M': ['ein Monat', 'einem Monat'],
+        'MM': [number + ' Monate', number + ' Monaten'],
+        'y': ['ein Jahr', 'einem Jahr'],
+        'yy': [number + ' Jahre', number + ' Jahren']
+    };
+    return withoutSuffix ? format[key][0] : format[key][1];
+}
+
+export default moment.defineLocale('de-at', {
+    months : 'Jänner_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember'.split('_'),
+    monthsShort : 'Jän._Febr._Mrz._Apr._Mai_Jun._Jul._Aug._Sept._Okt._Nov._Dez.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag'.split('_'),
+    weekdaysShort : 'So._Mo._Di._Mi._Do._Fr._Sa.'.split('_'),
+    weekdaysMin : 'So_Mo_Di_Mi_Do_Fr_Sa'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT: 'HH:mm',
+        LTS: 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY HH:mm',
+        LLLL : 'dddd, D. MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[heute um] LT [Uhr]',
+        sameElse: 'L',
+        nextDay: '[morgen um] LT [Uhr]',
+        nextWeek: 'dddd [um] LT [Uhr]',
+        lastDay: '[gestern um] LT [Uhr]',
+        lastWeek: '[letzten] dddd [um] LT [Uhr]'
+    },
+    relativeTime : {
+        future : 'in %s',
+        past : 'vor %s',
+        s : 'ein paar Sekunden',
+        m : processRelativeTime,
+        mm : '%d Minuten',
+        h : processRelativeTime,
+        hh : '%d Stunden',
+        d : processRelativeTime,
+        dd : processRelativeTime,
+        M : processRelativeTime,
+        MM : processRelativeTime,
+        y : processRelativeTime,
+        yy : processRelativeTime
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/de.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/de.js
new file mode 100644
index 0000000000000000000000000000000000000000..1839b5955c3d8f83bdb536a8e23a8912860b8dee
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/de.js
@@ -0,0 +1,68 @@
+//! moment.js locale configuration
+//! locale : German [de]
+//! author : lluchs : https://github.com/lluchs
+//! author: Menelion Elensúle: https://github.com/Oire
+//! author : Mikolaj Dadela : https://github.com/mik01aj
+
+import moment from '../moment';
+
+function processRelativeTime(number, withoutSuffix, key, isFuture) {
+    var format = {
+        'm': ['eine Minute', 'einer Minute'],
+        'h': ['eine Stunde', 'einer Stunde'],
+        'd': ['ein Tag', 'einem Tag'],
+        'dd': [number + ' Tage', number + ' Tagen'],
+        'M': ['ein Monat', 'einem Monat'],
+        'MM': [number + ' Monate', number + ' Monaten'],
+        'y': ['ein Jahr', 'einem Jahr'],
+        'yy': [number + ' Jahre', number + ' Jahren']
+    };
+    return withoutSuffix ? format[key][0] : format[key][1];
+}
+
+export default moment.defineLocale('de', {
+    months : 'Januar_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember'.split('_'),
+    monthsShort : 'Jan._Febr._Mrz._Apr._Mai_Jun._Jul._Aug._Sept._Okt._Nov._Dez.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag'.split('_'),
+    weekdaysShort : 'So._Mo._Di._Mi._Do._Fr._Sa.'.split('_'),
+    weekdaysMin : 'So_Mo_Di_Mi_Do_Fr_Sa'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT: 'HH:mm',
+        LTS: 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY HH:mm',
+        LLLL : 'dddd, D. MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[heute um] LT [Uhr]',
+        sameElse: 'L',
+        nextDay: '[morgen um] LT [Uhr]',
+        nextWeek: 'dddd [um] LT [Uhr]',
+        lastDay: '[gestern um] LT [Uhr]',
+        lastWeek: '[letzten] dddd [um] LT [Uhr]'
+    },
+    relativeTime : {
+        future : 'in %s',
+        past : 'vor %s',
+        s : 'ein paar Sekunden',
+        m : processRelativeTime,
+        mm : '%d Minuten',
+        h : processRelativeTime,
+        hh : '%d Stunden',
+        d : processRelativeTime,
+        dd : processRelativeTime,
+        M : processRelativeTime,
+        MM : processRelativeTime,
+        y : processRelativeTime,
+        yy : processRelativeTime
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/dv.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/dv.js
new file mode 100644
index 0000000000000000000000000000000000000000..9490e3feae78c1e94960bd38c3c6243e2752dafd
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/dv.js
@@ -0,0 +1,89 @@
+//! moment.js locale configuration
+//! locale : Maldivian [dv]
+//! author : Jawish Hameed : https://github.com/jawish
+
+import moment from '../moment';
+
+var months = [
+    'Þ–Þ¬Þ‚ÞªÞ‡Þ¦ÞƒÞ©',
+    'ÞŠÞ¬Þ„Þ°ÞƒÞªÞ‡Þ¦ÞƒÞ©',
+    'Þ‰Þ§ÞƒÞ¨Þ—Þª',
+    'އޭޕްރީލު',
+    'Þ‰Þ­',
+    'Þ–Þ«Þ‚Þ°',
+    'ޖުލައި',
+    'އޯގަސްޓު',
+    'ސެޕްޓެމްބަރު',
+    'Þ‡Þ®Þ†Þ°Þ“Þ¯Þ„Þ¦ÞƒÞª',
+    'Þ‚Þ®ÞˆÞ¬Þ‰Þ°Þ„Þ¦ÞƒÞª',
+    'ޑިސެމްބަރު'
+], weekdays = [
+    'އާދިއްތަ',
+    'Þ€Þ¯Þ‰Þ¦',
+    'Þ‡Þ¦Þ‚Þ°ÞŽÞ§ÞƒÞ¦',
+    'Þ„ÞªÞ‹Þ¦',
+    'ބުރާސްފަތި',
+    'Þ€ÞªÞ†ÞªÞƒÞª',
+    'Þ€Þ®Þ‚Þ¨Þ€Þ¨ÞƒÞª'
+];
+
+export default moment.defineLocale('dv', {
+    months : months,
+    monthsShort : months,
+    weekdays : weekdays,
+    weekdaysShort : weekdays,
+    weekdaysMin : 'Þ‡Þ§Þ‹Þ¨_Þ€Þ¯Þ‰Þ¦_Þ‡Þ¦Þ‚Þ°_Þ„ÞªÞ‹Þ¦_Þ„ÞªÞƒÞ§_Þ€ÞªÞ†Þª_Þ€Þ®Þ‚Þ¨'.split('_'),
+    longDateFormat : {
+
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'D/M/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    meridiemParse: /Þ‰Þ†|Þ‰ÞŠ/,
+    isPM : function (input) {
+        return 'Þ‰ÞŠ' === input;
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return 'Þ‰Þ†';
+        } else {
+            return 'Þ‰ÞŠ';
+        }
+    },
+    calendar : {
+        sameDay : '[Þ‰Þ¨Þ‡Þ¦Þ‹Þª] LT',
+        nextDay : '[Þ‰Þ§Þ‹Þ¦Þ‰Þ§] LT',
+        nextWeek : 'dddd LT',
+        lastDay : '[Þ‡Þ¨Þ‡Þ°Þ”Þ¬] LT',
+        lastWeek : '[ފާއިތުވި] dddd LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'ތެރޭގައި %s',
+        past : 'Þ†ÞªÞƒÞ¨Þ‚Þ° %s',
+        s : 'ސިކުންތުކޮޅެއް',
+        m : 'Þ‰Þ¨Þ‚Þ¨Þ“Þ¬Þ‡Þ°',
+        mm : 'Þ‰Þ¨Þ‚Þ¨Þ“Þª %d',
+        h : 'ÞŽÞ¦Þ‘Þ¨Þ‡Þ¨ÞƒÞ¬Þ‡Þ°',
+        hh : 'ÞŽÞ¦Þ‘Þ¨Þ‡Þ¨ÞƒÞª %d',
+        d : 'Þ‹ÞªÞˆÞ¦Þ€Þ¬Þ‡Þ°',
+        dd : 'ދުވަސް %d',
+        M : 'Þ‰Þ¦Þ€Þ¬Þ‡Þ°',
+        MM : 'މަސް %d',
+        y : 'Þ‡Þ¦Þ€Þ¦ÞƒÞ¬Þ‡Þ°',
+        yy : 'Þ‡Þ¦Þ€Þ¦ÞƒÞª %d'
+    },
+    preparse: function (string) {
+        return string.replace(/،/g, ',');
+    },
+    postformat: function (string) {
+        return string.replace(/,/g, '،');
+    },
+    week : {
+        dow : 7,  // Sunday is the first day of the week.
+        doy : 12  // The week that contains Jan 1st is the first week of the year.
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/el.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/el.js
new file mode 100644
index 0000000000000000000000000000000000000000..e157a6352dbc06f8153b5eb37bfe4cf3e73e968f
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/el.js
@@ -0,0 +1,86 @@
+//! moment.js locale configuration
+//! locale : Greek [el]
+//! author : Aggelos Karalias : https://github.com/mehiel
+
+import moment from '../moment';
+import isFunction from '../lib/utils/is-function';
+
+export default moment.defineLocale('el', {
+    monthsNominativeEl : 'Ιανουάριος_Φεβρουάριος_Μάρτιος_Απρίλιος_Μάιος_Ιούνιος_Ιούλιος_Αύγουστος_Σεπτέμβριος_Οκτώβριος_Νοέμβριος_Δεκέμβριος'.split('_'),
+    monthsGenitiveEl : 'Ιανουαρίου_Φεβρουαρίου_Μαρτίου_Απριλίου_Μαΐου_Ιουνίου_Ιουλίου_Αυγούστου_Σεπτεμβρίου_Οκτωβρίου_Νοεμβρίου_Δεκεμβρίου'.split('_'),
+    months : function (momentToFormat, format) {
+        if (/D/.test(format.substring(0, format.indexOf('MMMM')))) { // if there is a day number before 'MMMM'
+            return this._monthsGenitiveEl[momentToFormat.month()];
+        } else {
+            return this._monthsNominativeEl[momentToFormat.month()];
+        }
+    },
+    monthsShort : 'Ιαν_Φεβ_Μαρ_Απρ_Μαϊ_Ιουν_Ιουλ_Αυγ_Σεπ_Οκτ_Νοε_Δεκ'.split('_'),
+    weekdays : 'Κυριακή_Δευτέρα_Τρίτη_Τετάρτη_Πέμπτη_Παρασκευή_Σάββατο'.split('_'),
+    weekdaysShort : 'Κυρ_Δευ_Τρι_Τετ_Πεμ_Παρ_Σαβ'.split('_'),
+    weekdaysMin : 'Κυ_Δε_Τρ_Τε_Πε_Πα_Σα'.split('_'),
+    meridiem : function (hours, minutes, isLower) {
+        if (hours > 11) {
+            return isLower ? 'μμ' : 'ΜΜ';
+        } else {
+            return isLower ? 'πμ' : 'ΠΜ';
+        }
+    },
+    isPM : function (input) {
+        return ((input + '').toLowerCase()[0] === 'μ');
+    },
+    meridiemParse : /[ΠΜ]\.?Μ?\.?/i,
+    longDateFormat : {
+        LT : 'h:mm A',
+        LTS : 'h:mm:ss A',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY h:mm A',
+        LLLL : 'dddd, D MMMM YYYY h:mm A'
+    },
+    calendarEl : {
+        sameDay : '[Σήμερα {}] LT',
+        nextDay : '[Αύριο {}] LT',
+        nextWeek : 'dddd [{}] LT',
+        lastDay : '[Χθες {}] LT',
+        lastWeek : function () {
+            switch (this.day()) {
+                case 6:
+                    return '[το προηγούμενο] dddd [{}] LT';
+                default:
+                    return '[την προηγούμενη] dddd [{}] LT';
+            }
+        },
+        sameElse : 'L'
+    },
+    calendar : function (key, mom) {
+        var output = this._calendarEl[key],
+            hours = mom && mom.hours();
+        if (isFunction(output)) {
+            output = output.apply(mom);
+        }
+        return output.replace('{}', (hours % 12 === 1 ? 'στη' : 'στις'));
+    },
+    relativeTime : {
+        future : 'σε %s',
+        past : '%s πριν',
+        s : 'λίγα δευτερόλεπτα',
+        m : 'ένα λεπτό',
+        mm : '%d λεπτά',
+        h : 'μία ώρα',
+        hh : '%d ώρες',
+        d : 'μία μέρα',
+        dd : '%d μέρες',
+        M : 'ένας μήνας',
+        MM : '%d μήνες',
+        y : 'ένας χρόνος',
+        yy : '%d χρόνια'
+    },
+    ordinalParse: /\d{1,2}η/,
+    ordinal: '%dη',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4st is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/en-au.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/en-au.js
new file mode 100644
index 0000000000000000000000000000000000000000..5f714095280416e1902283640362505e59ce14ce
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/en-au.js
@@ -0,0 +1,58 @@
+//! moment.js locale configuration
+//! locale : English (Australia) [en-au]
+//! author : Jared Morse : https://github.com/jarcoal
+
+import moment from '../moment';
+
+export default moment.defineLocale('en-au', {
+    months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),
+    monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),
+    weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
+    weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
+    weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'h:mm A',
+        LTS : 'h:mm:ss A',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY h:mm A',
+        LLLL : 'dddd, D MMMM YYYY h:mm A'
+    },
+    calendar : {
+        sameDay : '[Today at] LT',
+        nextDay : '[Tomorrow at] LT',
+        nextWeek : 'dddd [at] LT',
+        lastDay : '[Yesterday at] LT',
+        lastWeek : '[Last] dddd [at] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'in %s',
+        past : '%s ago',
+        s : 'a few seconds',
+        m : 'a minute',
+        mm : '%d minutes',
+        h : 'an hour',
+        hh : '%d hours',
+        d : 'a day',
+        dd : '%d days',
+        M : 'a month',
+        MM : '%d months',
+        y : 'a year',
+        yy : '%d years'
+    },
+    ordinalParse: /\d{1,2}(st|nd|rd|th)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/en-ca.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/en-ca.js
new file mode 100644
index 0000000000000000000000000000000000000000..a678eab57d8d530bf2878486b415fc1318a48071
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/en-ca.js
@@ -0,0 +1,53 @@
+//! moment.js locale configuration
+//! locale : English (Canada) [en-ca]
+//! author : Jonathan Abourbih : https://github.com/jonbca
+
+import moment from '../moment';
+
+export default moment.defineLocale('en-ca', {
+    months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),
+    monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),
+    weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
+    weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
+    weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'h:mm A',
+        LTS : 'h:mm:ss A',
+        L : 'YYYY-MM-DD',
+        LL : 'MMMM D, YYYY',
+        LLL : 'MMMM D, YYYY h:mm A',
+        LLLL : 'dddd, MMMM D, YYYY h:mm A'
+    },
+    calendar : {
+        sameDay : '[Today at] LT',
+        nextDay : '[Tomorrow at] LT',
+        nextWeek : 'dddd [at] LT',
+        lastDay : '[Yesterday at] LT',
+        lastWeek : '[Last] dddd [at] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'in %s',
+        past : '%s ago',
+        s : 'a few seconds',
+        m : 'a minute',
+        mm : '%d minutes',
+        h : 'an hour',
+        hh : '%d hours',
+        d : 'a day',
+        dd : '%d days',
+        M : 'a month',
+        MM : '%d months',
+        y : 'a year',
+        yy : '%d years'
+    },
+    ordinalParse: /\d{1,2}(st|nd|rd|th)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/en-gb.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/en-gb.js
new file mode 100644
index 0000000000000000000000000000000000000000..f551112d7fbd5302e82b840a6bf4497a83564c8c
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/en-gb.js
@@ -0,0 +1,58 @@
+//! moment.js locale configuration
+//! locale : English (United Kingdom) [en-gb]
+//! author : Chris Gedrim : https://github.com/chrisgedrim
+
+import moment from '../moment';
+
+export default moment.defineLocale('en-gb', {
+    months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),
+    monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),
+    weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
+    weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
+    weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[Today at] LT',
+        nextDay : '[Tomorrow at] LT',
+        nextWeek : 'dddd [at] LT',
+        lastDay : '[Yesterday at] LT',
+        lastWeek : '[Last] dddd [at] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'in %s',
+        past : '%s ago',
+        s : 'a few seconds',
+        m : 'a minute',
+        mm : '%d minutes',
+        h : 'an hour',
+        hh : '%d hours',
+        d : 'a day',
+        dd : '%d days',
+        M : 'a month',
+        MM : '%d months',
+        y : 'a year',
+        yy : '%d years'
+    },
+    ordinalParse: /\d{1,2}(st|nd|rd|th)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/en-ie.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/en-ie.js
new file mode 100644
index 0000000000000000000000000000000000000000..3447973e3ad386a2856098d1ebce15f2fa908fe5
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/en-ie.js
@@ -0,0 +1,58 @@
+//! moment.js locale configuration
+//! locale : English (Ireland) [en-ie]
+//! author : Chris Cartlidge : https://github.com/chriscartlidge
+
+import moment from '../moment';
+
+export default moment.defineLocale('en-ie', {
+    months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),
+    monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),
+    weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
+    weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
+    weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD-MM-YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[Today at] LT',
+        nextDay : '[Tomorrow at] LT',
+        nextWeek : 'dddd [at] LT',
+        lastDay : '[Yesterday at] LT',
+        lastWeek : '[Last] dddd [at] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'in %s',
+        past : '%s ago',
+        s : 'a few seconds',
+        m : 'a minute',
+        mm : '%d minutes',
+        h : 'an hour',
+        hh : '%d hours',
+        d : 'a day',
+        dd : '%d days',
+        M : 'a month',
+        MM : '%d months',
+        y : 'a year',
+        yy : '%d years'
+    },
+    ordinalParse: /\d{1,2}(st|nd|rd|th)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/en-nz.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/en-nz.js
new file mode 100644
index 0000000000000000000000000000000000000000..8413be1c25c71626e0c8564b7223eb53284d4d1f
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/en-nz.js
@@ -0,0 +1,57 @@
+//! moment.js locale configuration
+//! locale : English (New Zealand) [en-nz]
+//! author : Luke McGregor : https://github.com/lukemcgregor
+
+import moment from '../moment';
+
+export default moment.defineLocale('en-nz', {
+    months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),
+    monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),
+    weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
+    weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
+    weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'h:mm A',
+        LTS : 'h:mm:ss A',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY h:mm A',
+        LLLL : 'dddd, D MMMM YYYY h:mm A'
+    },
+    calendar : {
+        sameDay : '[Today at] LT',
+        nextDay : '[Tomorrow at] LT',
+        nextWeek : 'dddd [at] LT',
+        lastDay : '[Yesterday at] LT',
+        lastWeek : '[Last] dddd [at] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'in %s',
+        past : '%s ago',
+        s : 'a few seconds',
+        m : 'a minute',
+        mm : '%d minutes',
+        h : 'an hour',
+        hh : '%d hours',
+        d : 'a day',
+        dd : '%d days',
+        M : 'a month',
+        MM : '%d months',
+        y : 'a year',
+        yy : '%d years'
+    },
+    ordinalParse: /\d{1,2}(st|nd|rd|th)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/eo.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/eo.js
new file mode 100644
index 0000000000000000000000000000000000000000..e8df29f863a23e713029bdd3bd6888cb5acc3d31
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/eo.js
@@ -0,0 +1,64 @@
+//! moment.js locale configuration
+//! locale : Esperanto [eo]
+//! author : Colin Dean : https://github.com/colindean
+//! komento: Mi estas malcerta se mi korekte traktis akuzativojn en tiu traduko.
+//!          Se ne, bonvolu korekti kaj avizi min por ke mi povas lerni!
+
+import moment from '../moment';
+
+export default moment.defineLocale('eo', {
+    months : 'januaro_februaro_marto_aprilo_majo_junio_julio_aÅ­gusto_septembro_oktobro_novembro_decembro'.split('_'),
+    monthsShort : 'jan_feb_mar_apr_maj_jun_jul_aÅ­g_sep_okt_nov_dec'.split('_'),
+    weekdays : 'Dimanĉo_Lundo_Mardo_Merkredo_Ĵaŭdo_Vendredo_Sabato'.split('_'),
+    weekdaysShort : 'Dim_Lun_Mard_Merk_Ä´aÅ­_Ven_Sab'.split('_'),
+    weekdaysMin : 'Di_Lu_Ma_Me_Ä´a_Ve_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'YYYY-MM-DD',
+        LL : 'D[-an de] MMMM, YYYY',
+        LLL : 'D[-an de] MMMM, YYYY HH:mm',
+        LLLL : 'dddd, [la] D[-an de] MMMM, YYYY HH:mm'
+    },
+    meridiemParse: /[ap]\.t\.m/i,
+    isPM: function (input) {
+        return input.charAt(0).toLowerCase() === 'p';
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours > 11) {
+            return isLower ? 'p.t.m.' : 'P.T.M.';
+        } else {
+            return isLower ? 'a.t.m.' : 'A.T.M.';
+        }
+    },
+    calendar : {
+        sameDay : '[HodiaÅ­ je] LT',
+        nextDay : '[MorgaÅ­ je] LT',
+        nextWeek : 'dddd [je] LT',
+        lastDay : '[HieraÅ­ je] LT',
+        lastWeek : '[pasinta] dddd [je] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'je %s',
+        past : 'antaÅ­ %s',
+        s : 'sekundoj',
+        m : 'minuto',
+        mm : '%d minutoj',
+        h : 'horo',
+        hh : '%d horoj',
+        d : 'tago',//ne 'diurno', ĉar estas uzita por proksimumo
+        dd : '%d tagoj',
+        M : 'monato',
+        MM : '%d monatoj',
+        y : 'jaro',
+        yy : '%d jaroj'
+    },
+    ordinalParse: /\d{1,2}a/,
+    ordinal : '%da',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/es-do.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/es-do.js
new file mode 100644
index 0000000000000000000000000000000000000000..21a44ab89a1c45080fce3bdcf593b6be6918b6f7
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/es-do.js
@@ -0,0 +1,71 @@
+//! moment.js locale configuration
+//! locale : Spanish (Dominican Republic) [es-do]
+
+import moment from '../moment';
+
+var monthsShortDot = 'ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.'.split('_'),
+    monthsShort = 'ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic'.split('_');
+
+export default moment.defineLocale('es-do', {
+    months : 'enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre'.split('_'),
+    monthsShort : function (m, format) {
+        if (/-MMM-/.test(format)) {
+            return monthsShort[m.month()];
+        } else {
+            return monthsShortDot[m.month()];
+        }
+    },
+    monthsParseExact : true,
+    weekdays : 'domingo_lunes_martes_miércoles_jueves_viernes_sábado'.split('_'),
+    weekdaysShort : 'dom._lun._mar._mié._jue._vie._sáb.'.split('_'),
+    weekdaysMin : 'do_lu_ma_mi_ju_vi_sá'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'h:mm A',
+        LTS : 'h:mm:ss A',
+        L : 'DD/MM/YYYY',
+        LL : 'D [de] MMMM [de] YYYY',
+        LLL : 'D [de] MMMM [de] YYYY h:mm A',
+        LLLL : 'dddd, D [de] MMMM [de] YYYY h:mm A'
+    },
+    calendar : {
+        sameDay : function () {
+            return '[hoy a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        nextDay : function () {
+            return '[mañana a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        nextWeek : function () {
+            return 'dddd [a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        lastDay : function () {
+            return '[ayer a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        lastWeek : function () {
+            return '[el] dddd [pasado a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'en %s',
+        past : 'hace %s',
+        s : 'unos segundos',
+        m : 'un minuto',
+        mm : '%d minutos',
+        h : 'una hora',
+        hh : '%d horas',
+        d : 'un día',
+        dd : '%d días',
+        M : 'un mes',
+        MM : '%d meses',
+        y : 'un año',
+        yy : '%d años'
+    },
+    ordinalParse : /\d{1,2}º/,
+    ordinal : '%dº',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/es.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/es.js
new file mode 100644
index 0000000000000000000000000000000000000000..cc971615a96ca1179552a36e51a5c16382d49497
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/es.js
@@ -0,0 +1,72 @@
+//! moment.js locale configuration
+//! locale : Spanish [es]
+//! author : Julio Napurí : https://github.com/julionc
+
+import moment from '../moment';
+
+var monthsShortDot = 'ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.'.split('_'),
+    monthsShort = 'ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic'.split('_');
+
+export default moment.defineLocale('es', {
+    months : 'enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre'.split('_'),
+    monthsShort : function (m, format) {
+        if (/-MMM-/.test(format)) {
+            return monthsShort[m.month()];
+        } else {
+            return monthsShortDot[m.month()];
+        }
+    },
+    monthsParseExact : true,
+    weekdays : 'domingo_lunes_martes_miércoles_jueves_viernes_sábado'.split('_'),
+    weekdaysShort : 'dom._lun._mar._mié._jue._vie._sáb.'.split('_'),
+    weekdaysMin : 'do_lu_ma_mi_ju_vi_sá'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D [de] MMMM [de] YYYY',
+        LLL : 'D [de] MMMM [de] YYYY H:mm',
+        LLLL : 'dddd, D [de] MMMM [de] YYYY H:mm'
+    },
+    calendar : {
+        sameDay : function () {
+            return '[hoy a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        nextDay : function () {
+            return '[mañana a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        nextWeek : function () {
+            return 'dddd [a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        lastDay : function () {
+            return '[ayer a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        lastWeek : function () {
+            return '[el] dddd [pasado a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'en %s',
+        past : 'hace %s',
+        s : 'unos segundos',
+        m : 'un minuto',
+        mm : '%d minutos',
+        h : 'una hora',
+        hh : '%d horas',
+        d : 'un día',
+        dd : '%d días',
+        M : 'un mes',
+        MM : '%d meses',
+        y : 'un año',
+        yy : '%d años'
+    },
+    ordinalParse : /\d{1,2}º/,
+    ordinal : '%dº',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/et.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/et.js
new file mode 100644
index 0000000000000000000000000000000000000000..f8a718ba66196e8a9185c5d8461e3ef5cf5aa86d
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/et.js
@@ -0,0 +1,71 @@
+//! moment.js locale configuration
+//! locale : Estonian [et]
+//! author : Henry Kehlmann : https://github.com/madhenry
+//! improvements : Illimar Tambek : https://github.com/ragulka
+
+import moment from '../moment';
+
+function processRelativeTime(number, withoutSuffix, key, isFuture) {
+    var format = {
+        's' : ['mõne sekundi', 'mõni sekund', 'paar sekundit'],
+        'm' : ['ühe minuti', 'üks minut'],
+        'mm': [number + ' minuti', number + ' minutit'],
+        'h' : ['ühe tunni', 'tund aega', 'üks tund'],
+        'hh': [number + ' tunni', number + ' tundi'],
+        'd' : ['ühe päeva', 'üks päev'],
+        'M' : ['kuu aja', 'kuu aega', 'üks kuu'],
+        'MM': [number + ' kuu', number + ' kuud'],
+        'y' : ['ühe aasta', 'aasta', 'üks aasta'],
+        'yy': [number + ' aasta', number + ' aastat']
+    };
+    if (withoutSuffix) {
+        return format[key][2] ? format[key][2] : format[key][1];
+    }
+    return isFuture ? format[key][0] : format[key][1];
+}
+
+export default moment.defineLocale('et', {
+    months        : 'jaanuar_veebruar_märts_aprill_mai_juuni_juuli_august_september_oktoober_november_detsember'.split('_'),
+    monthsShort   : 'jaan_veebr_märts_apr_mai_juuni_juuli_aug_sept_okt_nov_dets'.split('_'),
+    weekdays      : 'pühapäev_esmaspäev_teisipäev_kolmapäev_neljapäev_reede_laupäev'.split('_'),
+    weekdaysShort : 'P_E_T_K_N_R_L'.split('_'),
+    weekdaysMin   : 'P_E_T_K_N_R_L'.split('_'),
+    longDateFormat : {
+        LT   : 'H:mm',
+        LTS : 'H:mm:ss',
+        L    : 'DD.MM.YYYY',
+        LL   : 'D. MMMM YYYY',
+        LLL  : 'D. MMMM YYYY H:mm',
+        LLLL : 'dddd, D. MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay  : '[Täna,] LT',
+        nextDay  : '[Homme,] LT',
+        nextWeek : '[Järgmine] dddd LT',
+        lastDay  : '[Eile,] LT',
+        lastWeek : '[Eelmine] dddd LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s pärast',
+        past   : '%s tagasi',
+        s      : processRelativeTime,
+        m      : processRelativeTime,
+        mm     : processRelativeTime,
+        h      : processRelativeTime,
+        hh     : processRelativeTime,
+        d      : processRelativeTime,
+        dd     : '%d päeva',
+        M      : processRelativeTime,
+        MM     : processRelativeTime,
+        y      : processRelativeTime,
+        yy     : processRelativeTime
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/eu.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/eu.js
new file mode 100644
index 0000000000000000000000000000000000000000..390819b65b929ddab408fcc7f2786894f8863c97
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/eu.js
@@ -0,0 +1,57 @@
+//! moment.js locale configuration
+//! locale : Basque [eu]
+//! author : Eneko Illarramendi : https://github.com/eillarra
+
+import moment from '../moment';
+
+export default moment.defineLocale('eu', {
+    months : 'urtarrila_otsaila_martxoa_apirila_maiatza_ekaina_uztaila_abuztua_iraila_urria_azaroa_abendua'.split('_'),
+    monthsShort : 'urt._ots._mar._api._mai._eka._uzt._abu._ira._urr._aza._abe.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'igandea_astelehena_asteartea_asteazkena_osteguna_ostirala_larunbata'.split('_'),
+    weekdaysShort : 'ig._al._ar._az._og._ol._lr.'.split('_'),
+    weekdaysMin : 'ig_al_ar_az_og_ol_lr'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'YYYY-MM-DD',
+        LL : 'YYYY[ko] MMMM[ren] D[a]',
+        LLL : 'YYYY[ko] MMMM[ren] D[a] HH:mm',
+        LLLL : 'dddd, YYYY[ko] MMMM[ren] D[a] HH:mm',
+        l : 'YYYY-M-D',
+        ll : 'YYYY[ko] MMM D[a]',
+        lll : 'YYYY[ko] MMM D[a] HH:mm',
+        llll : 'ddd, YYYY[ko] MMM D[a] HH:mm'
+    },
+    calendar : {
+        sameDay : '[gaur] LT[etan]',
+        nextDay : '[bihar] LT[etan]',
+        nextWeek : 'dddd LT[etan]',
+        lastDay : '[atzo] LT[etan]',
+        lastWeek : '[aurreko] dddd LT[etan]',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s barru',
+        past : 'duela %s',
+        s : 'segundo batzuk',
+        m : 'minutu bat',
+        mm : '%d minutu',
+        h : 'ordu bat',
+        hh : '%d ordu',
+        d : 'egun bat',
+        dd : '%d egun',
+        M : 'hilabete bat',
+        MM : '%d hilabete',
+        y : 'urte bat',
+        yy : '%d urte'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/fa.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/fa.js
new file mode 100644
index 0000000000000000000000000000000000000000..634c2c19dbbfb143d00292d62e97d394d2feb7dd
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/fa.js
@@ -0,0 +1,97 @@
+//! moment.js locale configuration
+//! locale : Persian [fa]
+//! author : Ebrahim Byagowi : https://github.com/ebraminio
+
+import moment from '../moment';
+
+var symbolMap = {
+    '1': 'Û±',
+    '2': 'Û²',
+    '3': 'Û³',
+    '4': 'Û´',
+    '5': 'Ûµ',
+    '6': 'Û¶',
+    '7': 'Û·',
+    '8': 'Û¸',
+    '9': 'Û¹',
+    '0': 'Û°'
+}, numberMap = {
+    'Û±': '1',
+    'Û²': '2',
+    'Û³': '3',
+    'Û´': '4',
+    'Ûµ': '5',
+    'Û¶': '6',
+    'Û·': '7',
+    'Û¸': '8',
+    'Û¹': '9',
+    'Û°': '0'
+};
+
+export default moment.defineLocale('fa', {
+    months : 'ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر'.split('_'),
+    monthsShort : 'ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر'.split('_'),
+    weekdays : 'یک\u200cشنبه_دوشنبه_سه\u200cشنبه_چهارشنبه_پنج\u200cشنبه_جمعه_شنبه'.split('_'),
+    weekdaysShort : 'یک\u200cشنبه_دوشنبه_سه\u200cشنبه_چهارشنبه_پنج\u200cشنبه_جمعه_شنبه'.split('_'),
+    weekdaysMin : 'ی_د_س_چ_پ_ج_ش'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    meridiemParse: /قبل از ظهر|بعد از ظهر/,
+    isPM: function (input) {
+        return /بعد از ظهر/.test(input);
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return 'قبل از ظهر';
+        } else {
+            return 'بعد از ظهر';
+        }
+    },
+    calendar : {
+        sameDay : '[امروز ساعت] LT',
+        nextDay : '[فردا ساعت] LT',
+        nextWeek : 'dddd [ساعت] LT',
+        lastDay : '[دیروز ساعت] LT',
+        lastWeek : 'dddd [پیش] [ساعت] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'در %s',
+        past : '%s پیش',
+        s : 'چندین ثانیه',
+        m : 'یک دقیقه',
+        mm : '%d دقیقه',
+        h : 'یک ساعت',
+        hh : '%d ساعت',
+        d : 'یک روز',
+        dd : '%d روز',
+        M : 'یک ماه',
+        MM : '%d ماه',
+        y : 'یک سال',
+        yy : '%d سال'
+    },
+    preparse: function (string) {
+        return string.replace(/[Û°-Û¹]/g, function (match) {
+            return numberMap[match];
+        }).replace(/،/g, ',');
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap[match];
+        }).replace(/,/g, '،');
+    },
+    ordinalParse: /\d{1,2}Ù…/,
+    ordinal : '%dÙ…',
+    week : {
+        dow : 6, // Saturday is the first day of the week.
+        doy : 12 // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/fi.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/fi.js
new file mode 100644
index 0000000000000000000000000000000000000000..f91e1280b955dd29b3092b841a9aa45231fa63a0
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/fi.js
@@ -0,0 +1,98 @@
+//! moment.js locale configuration
+//! locale : Finnish [fi]
+//! author : Tarmo Aidantausta : https://github.com/bleadof
+
+import moment from '../moment';
+
+var numbersPast = 'nolla yksi kaksi kolme neljä viisi kuusi seitsemän kahdeksan yhdeksän'.split(' '),
+    numbersFuture = [
+        'nolla', 'yhden', 'kahden', 'kolmen', 'neljän', 'viiden', 'kuuden',
+        numbersPast[7], numbersPast[8], numbersPast[9]
+    ];
+function translate(number, withoutSuffix, key, isFuture) {
+    var result = '';
+    switch (key) {
+        case 's':
+            return isFuture ? 'muutaman sekunnin' : 'muutama sekunti';
+        case 'm':
+            return isFuture ? 'minuutin' : 'minuutti';
+        case 'mm':
+            result = isFuture ? 'minuutin' : 'minuuttia';
+            break;
+        case 'h':
+            return isFuture ? 'tunnin' : 'tunti';
+        case 'hh':
+            result = isFuture ? 'tunnin' : 'tuntia';
+            break;
+        case 'd':
+            return isFuture ? 'päivän' : 'päivä';
+        case 'dd':
+            result = isFuture ? 'päivän' : 'päivää';
+            break;
+        case 'M':
+            return isFuture ? 'kuukauden' : 'kuukausi';
+        case 'MM':
+            result = isFuture ? 'kuukauden' : 'kuukautta';
+            break;
+        case 'y':
+            return isFuture ? 'vuoden' : 'vuosi';
+        case 'yy':
+            result = isFuture ? 'vuoden' : 'vuotta';
+            break;
+    }
+    result = verbalNumber(number, isFuture) + ' ' + result;
+    return result;
+}
+function verbalNumber(number, isFuture) {
+    return number < 10 ? (isFuture ? numbersFuture[number] : numbersPast[number]) : number;
+}
+
+export default moment.defineLocale('fi', {
+    months : 'tammikuu_helmikuu_maaliskuu_huhtikuu_toukokuu_kesäkuu_heinäkuu_elokuu_syyskuu_lokakuu_marraskuu_joulukuu'.split('_'),
+    monthsShort : 'tammi_helmi_maalis_huhti_touko_kesä_heinä_elo_syys_loka_marras_joulu'.split('_'),
+    weekdays : 'sunnuntai_maanantai_tiistai_keskiviikko_torstai_perjantai_lauantai'.split('_'),
+    weekdaysShort : 'su_ma_ti_ke_to_pe_la'.split('_'),
+    weekdaysMin : 'su_ma_ti_ke_to_pe_la'.split('_'),
+    longDateFormat : {
+        LT : 'HH.mm',
+        LTS : 'HH.mm.ss',
+        L : 'DD.MM.YYYY',
+        LL : 'Do MMMM[ta] YYYY',
+        LLL : 'Do MMMM[ta] YYYY, [klo] HH.mm',
+        LLLL : 'dddd, Do MMMM[ta] YYYY, [klo] HH.mm',
+        l : 'D.M.YYYY',
+        ll : 'Do MMM YYYY',
+        lll : 'Do MMM YYYY, [klo] HH.mm',
+        llll : 'ddd, Do MMM YYYY, [klo] HH.mm'
+    },
+    calendar : {
+        sameDay : '[tänään] [klo] LT',
+        nextDay : '[huomenna] [klo] LT',
+        nextWeek : 'dddd [klo] LT',
+        lastDay : '[eilen] [klo] LT',
+        lastWeek : '[viime] dddd[na] [klo] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s päästä',
+        past : '%s sitten',
+        s : translate,
+        m : translate,
+        mm : translate,
+        h : translate,
+        hh : translate,
+        d : translate,
+        dd : translate,
+        M : translate,
+        MM : translate,
+        y : translate,
+        yy : translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/fo.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/fo.js
new file mode 100644
index 0000000000000000000000000000000000000000..e3b169d74c4907c4c6fd4285c48c16b89f71f7d8
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/fo.js
@@ -0,0 +1,51 @@
+//! moment.js locale configuration
+//! locale : Faroese [fo]
+//! author : Ragnar Johannesen : https://github.com/ragnar123
+
+import moment from '../moment';
+
+export default moment.defineLocale('fo', {
+    months : 'januar_februar_mars_apríl_mai_juni_juli_august_september_oktober_november_desember'.split('_'),
+    monthsShort : 'jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_'),
+    weekdays : 'sunnudagur_mánadagur_týsdagur_mikudagur_hósdagur_fríggjadagur_leygardagur'.split('_'),
+    weekdaysShort : 'sun_mán_týs_mik_hós_frí_ley'.split('_'),
+    weekdaysMin : 'su_má_tý_mi_hó_fr_le'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D. MMMM, YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[Í dag kl.] LT',
+        nextDay : '[Í morgin kl.] LT',
+        nextWeek : 'dddd [kl.] LT',
+        lastDay : '[Í gjár kl.] LT',
+        lastWeek : '[síðstu] dddd [kl] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'um %s',
+        past : '%s síðani',
+        s : 'fá sekund',
+        m : 'ein minutt',
+        mm : '%d minuttir',
+        h : 'ein tími',
+        hh : '%d tímar',
+        d : 'ein dagur',
+        dd : '%d dagar',
+        M : 'ein mánaði',
+        MM : '%d mánaðir',
+        y : 'eitt ár',
+        yy : '%d ár'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/fr-ca.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/fr-ca.js
new file mode 100644
index 0000000000000000000000000000000000000000..07b3de18d481796f31fc88234c347632b05cf43a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/fr-ca.js
@@ -0,0 +1,51 @@
+//! moment.js locale configuration
+//! locale : French (Canada) [fr-ca]
+//! author : Jonathan Abourbih : https://github.com/jonbca
+
+import moment from '../moment';
+
+export default moment.defineLocale('fr-ca', {
+    months : 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split('_'),
+    monthsShort : 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'),
+    weekdaysShort : 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'),
+    weekdaysMin : 'Di_Lu_Ma_Me_Je_Ve_Sa'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'YYYY-MM-DD',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Aujourd\'hui à] LT',
+        nextDay: '[Demain à] LT',
+        nextWeek: 'dddd [à] LT',
+        lastDay: '[Hier à] LT',
+        lastWeek: 'dddd [dernier à] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'dans %s',
+        past : 'il y a %s',
+        s : 'quelques secondes',
+        m : 'une minute',
+        mm : '%d minutes',
+        h : 'une heure',
+        hh : '%d heures',
+        d : 'un jour',
+        dd : '%d jours',
+        M : 'un mois',
+        MM : '%d mois',
+        y : 'un an',
+        yy : '%d ans'
+    },
+    ordinalParse: /\d{1,2}(er|e)/,
+    ordinal : function (number) {
+        return number + (number === 1 ? 'er' : 'e');
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/fr-ch.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/fr-ch.js
new file mode 100644
index 0000000000000000000000000000000000000000..ea0d291a4e59dbe2f34bbc3b2827239c8fbe6680
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/fr-ch.js
@@ -0,0 +1,55 @@
+//! moment.js locale configuration
+//! locale : French (Switzerland) [fr-ch]
+//! author : Gaspard Bucher : https://github.com/gaspard
+
+import moment from '../moment';
+
+export default moment.defineLocale('fr-ch', {
+    months : 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split('_'),
+    monthsShort : 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'),
+    weekdaysShort : 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'),
+    weekdaysMin : 'Di_Lu_Ma_Me_Je_Ve_Sa'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Aujourd\'hui à] LT',
+        nextDay: '[Demain à] LT',
+        nextWeek: 'dddd [à] LT',
+        lastDay: '[Hier à] LT',
+        lastWeek: 'dddd [dernier à] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'dans %s',
+        past : 'il y a %s',
+        s : 'quelques secondes',
+        m : 'une minute',
+        mm : '%d minutes',
+        h : 'une heure',
+        hh : '%d heures',
+        d : 'un jour',
+        dd : '%d jours',
+        M : 'un mois',
+        MM : '%d mois',
+        y : 'un an',
+        yy : '%d ans'
+    },
+    ordinalParse: /\d{1,2}(er|e)/,
+    ordinal : function (number) {
+        return number + (number === 1 ? 'er' : 'e');
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/fr.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/fr.js
new file mode 100644
index 0000000000000000000000000000000000000000..6e704d1d0f4d9baae6a2a029365ff5f3181476ea
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/fr.js
@@ -0,0 +1,55 @@
+//! moment.js locale configuration
+//! locale : French [fr]
+//! author : John Fischer : https://github.com/jfroffice
+
+import moment from '../moment';
+
+export default moment.defineLocale('fr', {
+    months : 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split('_'),
+    monthsShort : 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'),
+    weekdaysShort : 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'),
+    weekdaysMin : 'Di_Lu_Ma_Me_Je_Ve_Sa'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Aujourd\'hui à] LT',
+        nextDay: '[Demain à] LT',
+        nextWeek: 'dddd [à] LT',
+        lastDay: '[Hier à] LT',
+        lastWeek: 'dddd [dernier à] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'dans %s',
+        past : 'il y a %s',
+        s : 'quelques secondes',
+        m : 'une minute',
+        mm : '%d minutes',
+        h : 'une heure',
+        hh : '%d heures',
+        d : 'un jour',
+        dd : '%d jours',
+        M : 'un mois',
+        MM : '%d mois',
+        y : 'un an',
+        yy : '%d ans'
+    },
+    ordinalParse: /\d{1,2}(er|)/,
+    ordinal : function (number) {
+        return number + (number === 1 ? 'er' : '');
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/fy.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/fy.js
new file mode 100644
index 0000000000000000000000000000000000000000..5861a772657ba995cea0ea1164127c6bb3960540
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/fy.js
@@ -0,0 +1,64 @@
+//! moment.js locale configuration
+//! locale : Frisian [fy]
+//! author : Robin van der Vliet : https://github.com/robin0van0der0v
+
+import moment from '../moment';
+
+var monthsShortWithDots = 'jan._feb._mrt._apr._mai_jun._jul._aug._sep._okt._nov._des.'.split('_'),
+    monthsShortWithoutDots = 'jan_feb_mrt_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_');
+
+export default moment.defineLocale('fy', {
+    months : 'jannewaris_febrewaris_maart_april_maaie_juny_july_augustus_septimber_oktober_novimber_desimber'.split('_'),
+    monthsShort : function (m, format) {
+        if (/-MMM-/.test(format)) {
+            return monthsShortWithoutDots[m.month()];
+        } else {
+            return monthsShortWithDots[m.month()];
+        }
+    },
+    monthsParseExact : true,
+    weekdays : 'snein_moandei_tiisdei_woansdei_tongersdei_freed_sneon'.split('_'),
+    weekdaysShort : 'si._mo._ti._wo._to._fr._so.'.split('_'),
+    weekdaysMin : 'Si_Mo_Ti_Wo_To_Fr_So'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD-MM-YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[hjoed om] LT',
+        nextDay: '[moarn om] LT',
+        nextWeek: 'dddd [om] LT',
+        lastDay: '[juster om] LT',
+        lastWeek: '[ôfrûne] dddd [om] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'oer %s',
+        past : '%s lyn',
+        s : 'in pear sekonden',
+        m : 'ien minút',
+        mm : '%d minuten',
+        h : 'ien oere',
+        hh : '%d oeren',
+        d : 'ien dei',
+        dd : '%d dagen',
+        M : 'ien moanne',
+        MM : '%d moannen',
+        y : 'ien jier',
+        yy : '%d jierren'
+    },
+    ordinalParse: /\d{1,2}(ste|de)/,
+    ordinal : function (number) {
+        return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de');
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/gd.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/gd.js
new file mode 100644
index 0000000000000000000000000000000000000000..3ec664e476cd9dec7dfd2b03a38f524e40542e89
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/gd.js
@@ -0,0 +1,67 @@
+//! moment.js locale configuration
+//! locale : Scottish Gaelic [gd]
+//! author : Jon Ashdown : https://github.com/jonashdown
+
+import moment from '../moment';
+
+var months = [
+    'Am Faoilleach', 'An Gearran', 'Am Màrt', 'An Giblean', 'An Cèitean', 'An t-Ògmhios', 'An t-Iuchar', 'An Lùnastal', 'An t-Sultain', 'An Dàmhair', 'An t-Samhain', 'An Dùbhlachd'
+];
+
+var monthsShort = ['Faoi', 'Gear', 'Màrt', 'Gibl', 'Cèit', 'Ògmh', 'Iuch', 'Lùn', 'Sult', 'Dàmh', 'Samh', 'Dùbh'];
+
+var weekdays = ['Didòmhnaich', 'Diluain', 'Dimàirt', 'Diciadain', 'Diardaoin', 'Dihaoine', 'Disathairne'];
+
+var weekdaysShort = ['Did', 'Dil', 'Dim', 'Dic', 'Dia', 'Dih', 'Dis'];
+
+var weekdaysMin = ['Dò', 'Lu', 'Mà', 'Ci', 'Ar', 'Ha', 'Sa'];
+
+export default moment.defineLocale('gd', {
+    months : months,
+    monthsShort : monthsShort,
+    monthsParseExact : true,
+    weekdays : weekdays,
+    weekdaysShort : weekdaysShort,
+    weekdaysMin : weekdaysMin,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[An-diugh aig] LT',
+        nextDay : '[A-màireach aig] LT',
+        nextWeek : 'dddd [aig] LT',
+        lastDay : '[An-dè aig] LT',
+        lastWeek : 'dddd [seo chaidh] [aig] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'ann an %s',
+        past : 'bho chionn %s',
+        s : 'beagan diogan',
+        m : 'mionaid',
+        mm : '%d mionaidean',
+        h : 'uair',
+        hh : '%d uairean',
+        d : 'latha',
+        dd : '%d latha',
+        M : 'mìos',
+        MM : '%d mìosan',
+        y : 'bliadhna',
+        yy : '%d bliadhna'
+    },
+    ordinalParse : /\d{1,2}(d|na|mh)/,
+    ordinal : function (number) {
+        var output = number === 1 ? 'd' : number % 10 === 2 ? 'na' : 'mh';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/gl.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/gl.js
new file mode 100644
index 0000000000000000000000000000000000000000..d0ea61d49b8f35079aeb8aab4d7bf4b3389a4c3d
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/gl.js
@@ -0,0 +1,68 @@
+//! moment.js locale configuration
+//! locale : Galician [gl]
+//! author : Juan G. Hurtado : https://github.com/juanghurtado
+
+import moment from '../moment';
+
+export default moment.defineLocale('gl', {
+    months : 'xaneiro_febreiro_marzo_abril_maio_xuño_xullo_agosto_setembro_outubro_novembro_decembro'.split('_'),
+    monthsShort : 'xan._feb._mar._abr._mai._xuñ._xul._ago._set._out._nov._dec.'.split('_'),
+    monthsParseExact: true,
+    weekdays : 'domingo_luns_martes_mércores_xoves_venres_sábado'.split('_'),
+    weekdaysShort : 'dom._lun._mar._mér._xov._ven._sáb.'.split('_'),
+    weekdaysMin : 'do_lu_ma_mé_xo_ve_sá'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D [de] MMMM [de] YYYY',
+        LLL : 'D [de] MMMM [de] YYYY H:mm',
+        LLLL : 'dddd, D [de] MMMM [de] YYYY H:mm'
+    },
+    calendar : {
+        sameDay : function () {
+            return '[hoxe ' + ((this.hours() !== 1) ? 'ás' : 'á') + '] LT';
+        },
+        nextDay : function () {
+            return '[mañá ' + ((this.hours() !== 1) ? 'ás' : 'á') + '] LT';
+        },
+        nextWeek : function () {
+            return 'dddd [' + ((this.hours() !== 1) ? 'ás' : 'a') + '] LT';
+        },
+        lastDay : function () {
+            return '[onte ' + ((this.hours() !== 1) ? 'á' : 'a') + '] LT';
+        },
+        lastWeek : function () {
+            return '[o] dddd [pasado ' + ((this.hours() !== 1) ? 'ás' : 'a') + '] LT';
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : function (str) {
+            if (str.indexOf('un') === 0) {
+                return 'n' + str;
+            }
+            return 'en ' + str;
+        },
+        past : 'hai %s',
+        s : 'uns segundos',
+        m : 'un minuto',
+        mm : '%d minutos',
+        h : 'unha hora',
+        hh : '%d horas',
+        d : 'un día',
+        dd : '%d días',
+        M : 'un mes',
+        MM : '%d meses',
+        y : 'un ano',
+        yy : '%d anos'
+    },
+    ordinalParse : /\d{1,2}º/,
+    ordinal : '%dº',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/he.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/he.js
new file mode 100644
index 0000000000000000000000000000000000000000..b6a1944b57fcf963a2c4d469547473a272d20396
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/he.js
@@ -0,0 +1,90 @@
+//! moment.js locale configuration
+//! locale : Hebrew [he]
+//! author : Tomer Cohen : https://github.com/tomer
+//! author : Moshe Simantov : https://github.com/DevelopmentIL
+//! author : Tal Ater : https://github.com/TalAter
+
+import moment from '../moment';
+
+export default moment.defineLocale('he', {
+    months : 'ינואר_פברואר_מרץ_אפריל_מאי_יוני_יולי_אוגוסט_ספטמבר_אוקטובר_נובמבר_דצמבר'.split('_'),
+    monthsShort : 'ינו׳_פבר׳_מרץ_אפר׳_מאי_יוני_יולי_אוג׳_ספט׳_אוק׳_נוב׳_דצמ׳'.split('_'),
+    weekdays : 'ראשון_שני_שלישי_רביעי_חמישי_שישי_שבת'.split('_'),
+    weekdaysShort : 'א׳_ב׳_ג׳_ד׳_ה׳_ו׳_ש׳'.split('_'),
+    weekdaysMin : 'א_ב_ג_ד_ה_ו_ש'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D [ב]MMMM YYYY',
+        LLL : 'D [ב]MMMM YYYY HH:mm',
+        LLLL : 'dddd, D [ב]MMMM YYYY HH:mm',
+        l : 'D/M/YYYY',
+        ll : 'D MMM YYYY',
+        lll : 'D MMM YYYY HH:mm',
+        llll : 'ddd, D MMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[היום ב־]LT',
+        nextDay : '[מחר ב־]LT',
+        nextWeek : 'dddd [בשעה] LT',
+        lastDay : '[אתמול ב־]LT',
+        lastWeek : '[ביום] dddd [האחרון בשעה] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'בעוד %s',
+        past : 'לפני %s',
+        s : 'מספר שניות',
+        m : 'דקה',
+        mm : '%d דקות',
+        h : 'שעה',
+        hh : function (number) {
+            if (number === 2) {
+                return 'שעתיים';
+            }
+            return number + ' שעות';
+        },
+        d : 'יום',
+        dd : function (number) {
+            if (number === 2) {
+                return 'יומיים';
+            }
+            return number + ' ימים';
+        },
+        M : 'חודש',
+        MM : function (number) {
+            if (number === 2) {
+                return 'חודשיים';
+            }
+            return number + ' חודשים';
+        },
+        y : 'שנה',
+        yy : function (number) {
+            if (number === 2) {
+                return 'שנתיים';
+            } else if (number % 10 === 0 && number !== 10) {
+                return number + ' שנה';
+            }
+            return number + ' שנים';
+        }
+    },
+    meridiemParse: /אחה"צ|לפנה"צ|אחרי הצהריים|לפני הצהריים|לפנות בוקר|בבוקר|בערב/i,
+    isPM : function (input) {
+        return /^(אחה"צ|אחרי הצהריים|בערב)$/.test(input);
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 5) {
+            return 'לפנות בוקר';
+        } else if (hour < 10) {
+            return 'בבוקר';
+        } else if (hour < 12) {
+            return isLower ? 'לפנה"צ' : 'לפני הצהריים';
+        } else if (hour < 18) {
+            return isLower ? 'אחה"צ' : 'אחרי הצהריים';
+        } else {
+            return 'בערב';
+        }
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/hi.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/hi.js
new file mode 100644
index 0000000000000000000000000000000000000000..30a50e4ebe194078daa60f9e73975a786c664982
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/hi.js
@@ -0,0 +1,115 @@
+//! moment.js locale configuration
+//! locale : Hindi [hi]
+//! author : Mayank Singhal : https://github.com/mayanksinghal
+
+import moment from '../moment';
+
+var symbolMap = {
+    '1': '१',
+    '2': '२',
+    '3': '३',
+    '4': '४',
+    '5': '५',
+    '6': '६',
+    '7': '७',
+    '8': '८',
+    '9': '९',
+    '0': '०'
+},
+numberMap = {
+    '१': '1',
+    '२': '2',
+    '३': '3',
+    '४': '4',
+    '५': '5',
+    '६': '6',
+    '७': '7',
+    '८': '8',
+    '९': '9',
+    '०': '0'
+};
+
+export default moment.defineLocale('hi', {
+    months : 'जनवरी_फ़रवरी_मार्च_अप्रैल_मई_जून_जुलाई_अगस्त_सितम्बर_अक्टूबर_नवम्बर_दिसम्बर'.split('_'),
+    monthsShort : 'जन._फ़र._मार्च_अप्रै._मई_जून_जुल._अग._सित._अक्टू._नव._दिस.'.split('_'),
+    monthsParseExact: true,
+    weekdays : 'रविवार_सोमवार_मंगलवार_बुधवार_गुरूवार_शुक्रवार_शनिवार'.split('_'),
+    weekdaysShort : 'रवि_सोम_मंगल_बुध_गुरू_शुक्र_शनि'.split('_'),
+    weekdaysMin : 'र_सो_मं_बु_गु_शु_श'.split('_'),
+    longDateFormat : {
+        LT : 'A h:mm बजे',
+        LTS : 'A h:mm:ss बजे',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, A h:mm बजे',
+        LLLL : 'dddd, D MMMM YYYY, A h:mm बजे'
+    },
+    calendar : {
+        sameDay : '[आज] LT',
+        nextDay : '[कल] LT',
+        nextWeek : 'dddd, LT',
+        lastDay : '[कल] LT',
+        lastWeek : '[पिछले] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s में',
+        past : '%s पहले',
+        s : 'कुछ ही क्षण',
+        m : 'एक मिनट',
+        mm : '%d मिनट',
+        h : 'एक घंटा',
+        hh : '%d घंटे',
+        d : 'एक दिन',
+        dd : '%d दिन',
+        M : 'एक महीने',
+        MM : '%d महीने',
+        y : 'एक वर्ष',
+        yy : '%d वर्ष'
+    },
+    preparse: function (string) {
+        return string.replace(/[१२३४५६७८९०]/g, function (match) {
+            return numberMap[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap[match];
+        });
+    },
+    // Hindi notation for meridiems are quite fuzzy in practice. While there exists
+    // a rigid notion of a 'Pahar' it is not used as rigidly in modern Hindi.
+    meridiemParse: /रात|सुबह|दोपहर|शाम/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'रात') {
+            return hour < 4 ? hour : hour + 12;
+        } else if (meridiem === 'सुबह') {
+            return hour;
+        } else if (meridiem === 'दोपहर') {
+            return hour >= 10 ? hour : hour + 12;
+        } else if (meridiem === 'शाम') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'रात';
+        } else if (hour < 10) {
+            return 'सुबह';
+        } else if (hour < 17) {
+            return 'दोपहर';
+        } else if (hour < 20) {
+            return 'शाम';
+        } else {
+            return 'रात';
+        }
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/hr.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/hr.js
new file mode 100644
index 0000000000000000000000000000000000000000..84878ad094a63e118f17b13fc0684b829757268a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/hr.js
@@ -0,0 +1,135 @@
+//! moment.js locale configuration
+//! locale : Croatian [hr]
+//! author : Bojan Marković : https://github.com/bmarkovic
+
+import moment from '../moment';
+
+function translate(number, withoutSuffix, key) {
+    var result = number + ' ';
+    switch (key) {
+        case 'm':
+            return withoutSuffix ? 'jedna minuta' : 'jedne minute';
+        case 'mm':
+            if (number === 1) {
+                result += 'minuta';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'minute';
+            } else {
+                result += 'minuta';
+            }
+            return result;
+        case 'h':
+            return withoutSuffix ? 'jedan sat' : 'jednog sata';
+        case 'hh':
+            if (number === 1) {
+                result += 'sat';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'sata';
+            } else {
+                result += 'sati';
+            }
+            return result;
+        case 'dd':
+            if (number === 1) {
+                result += 'dan';
+            } else {
+                result += 'dana';
+            }
+            return result;
+        case 'MM':
+            if (number === 1) {
+                result += 'mjesec';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'mjeseca';
+            } else {
+                result += 'mjeseci';
+            }
+            return result;
+        case 'yy':
+            if (number === 1) {
+                result += 'godina';
+            } else if (number === 2 || number === 3 || number === 4) {
+                result += 'godine';
+            } else {
+                result += 'godina';
+            }
+            return result;
+    }
+}
+
+export default moment.defineLocale('hr', {
+    months : {
+        format: 'siječnja_veljače_ožujka_travnja_svibnja_lipnja_srpnja_kolovoza_rujna_listopada_studenoga_prosinca'.split('_'),
+        standalone: 'siječanj_veljača_ožujak_travanj_svibanj_lipanj_srpanj_kolovoz_rujan_listopad_studeni_prosinac'.split('_')
+    },
+    monthsShort : 'sij._velj._ožu._tra._svi._lip._srp._kol._ruj._lis._stu._pro.'.split('_'),
+    monthsParseExact: true,
+    weekdays : 'nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota'.split('_'),
+    weekdaysShort : 'ned._pon._uto._sri._čet._pet._sub.'.split('_'),
+    weekdaysMin : 'ne_po_ut_sr_če_pe_su'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY H:mm',
+        LLLL : 'dddd, D. MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay  : '[danas u] LT',
+        nextDay  : '[sutra u] LT',
+        nextWeek : function () {
+            switch (this.day()) {
+                case 0:
+                    return '[u] [nedjelju] [u] LT';
+                case 3:
+                    return '[u] [srijedu] [u] LT';
+                case 6:
+                    return '[u] [subotu] [u] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[u] dddd [u] LT';
+            }
+        },
+        lastDay  : '[jučer u] LT',
+        lastWeek : function () {
+            switch (this.day()) {
+                case 0:
+                case 3:
+                    return '[prošlu] dddd [u] LT';
+                case 6:
+                    return '[prošle] [subote] [u] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[prošli] dddd [u] LT';
+            }
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'za %s',
+        past   : 'prije %s',
+        s      : 'par sekundi',
+        m      : translate,
+        mm     : translate,
+        h      : translate,
+        hh     : translate,
+        d      : 'dan',
+        dd     : translate,
+        M      : 'mjesec',
+        MM     : translate,
+        y      : 'godinu',
+        yy     : translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/hu.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/hu.js
new file mode 100644
index 0000000000000000000000000000000000000000..0cffecf836d107b16ca8c01577b15102da7e2abf
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/hu.js
@@ -0,0 +1,100 @@
+//! moment.js locale configuration
+//! locale : Hungarian [hu]
+//! author : Adam Brunner : https://github.com/adambrunner
+
+import moment from '../moment';
+
+var weekEndings = 'vasárnap hétfőn kedden szerdán csütörtökön pénteken szombaton'.split(' ');
+function translate(number, withoutSuffix, key, isFuture) {
+    var num = number,
+        suffix;
+    switch (key) {
+        case 's':
+            return (isFuture || withoutSuffix) ? 'néhány másodperc' : 'néhány másodperce';
+        case 'm':
+            return 'egy' + (isFuture || withoutSuffix ? ' perc' : ' perce');
+        case 'mm':
+            return num + (isFuture || withoutSuffix ? ' perc' : ' perce');
+        case 'h':
+            return 'egy' + (isFuture || withoutSuffix ? ' óra' : ' órája');
+        case 'hh':
+            return num + (isFuture || withoutSuffix ? ' óra' : ' órája');
+        case 'd':
+            return 'egy' + (isFuture || withoutSuffix ? ' nap' : ' napja');
+        case 'dd':
+            return num + (isFuture || withoutSuffix ? ' nap' : ' napja');
+        case 'M':
+            return 'egy' + (isFuture || withoutSuffix ? ' hónap' : ' hónapja');
+        case 'MM':
+            return num + (isFuture || withoutSuffix ? ' hónap' : ' hónapja');
+        case 'y':
+            return 'egy' + (isFuture || withoutSuffix ? ' év' : ' éve');
+        case 'yy':
+            return num + (isFuture || withoutSuffix ? ' év' : ' éve');
+    }
+    return '';
+}
+function week(isFuture) {
+    return (isFuture ? '' : '[múlt] ') + '[' + weekEndings[this.day()] + '] LT[-kor]';
+}
+
+export default moment.defineLocale('hu', {
+    months : 'január_február_március_április_május_június_július_augusztus_szeptember_október_november_december'.split('_'),
+    monthsShort : 'jan_feb_márc_ápr_máj_jún_júl_aug_szept_okt_nov_dec'.split('_'),
+    weekdays : 'vasárnap_hétfő_kedd_szerda_csütörtök_péntek_szombat'.split('_'),
+    weekdaysShort : 'vas_hét_kedd_sze_csüt_pén_szo'.split('_'),
+    weekdaysMin : 'v_h_k_sze_cs_p_szo'.split('_'),
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'YYYY.MM.DD.',
+        LL : 'YYYY. MMMM D.',
+        LLL : 'YYYY. MMMM D. H:mm',
+        LLLL : 'YYYY. MMMM D., dddd H:mm'
+    },
+    meridiemParse: /de|du/i,
+    isPM: function (input) {
+        return input.charAt(1).toLowerCase() === 'u';
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 12) {
+            return isLower === true ? 'de' : 'DE';
+        } else {
+            return isLower === true ? 'du' : 'DU';
+        }
+    },
+    calendar : {
+        sameDay : '[ma] LT[-kor]',
+        nextDay : '[holnap] LT[-kor]',
+        nextWeek : function () {
+            return week.call(this, true);
+        },
+        lastDay : '[tegnap] LT[-kor]',
+        lastWeek : function () {
+            return week.call(this, false);
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s múlva',
+        past : '%s',
+        s : translate,
+        m : translate,
+        mm : translate,
+        h : translate,
+        hh : translate,
+        d : translate,
+        dd : translate,
+        M : translate,
+        MM : translate,
+        y : translate,
+        yy : translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/hy-am.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/hy-am.js
new file mode 100644
index 0000000000000000000000000000000000000000..bc50205e03a5b177802a1111bfb1ae9bff437653
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/hy-am.js
@@ -0,0 +1,86 @@
+//! moment.js locale configuration
+//! locale : Armenian [hy-am]
+//! author : Armendarabyan : https://github.com/armendarabyan
+
+import moment from '../moment';
+
+export default moment.defineLocale('hy-am', {
+    months : {
+        format: 'Õ°Õ¸Ö‚Õ¶Õ¾Õ¡Ö€Õ«_ÖƒÕ¥Õ¿Ö€Õ¾Õ¡Ö€Õ«_Õ´Õ¡Ö€Õ¿Õ«_Õ¡ÕºÖ€Õ«Õ¬Õ«_Õ´Õ¡ÕµÕ«Õ½Õ«_Õ°Õ¸Ö‚Õ¶Õ«Õ½Õ«_Õ°Õ¸Ö‚Õ¬Õ«Õ½Õ«_Ö…Õ£Õ¸Õ½Õ¿Õ¸Õ½Õ«_Õ½Õ¥ÕºÕ¿Õ¥Õ´Õ¢Õ¥Ö€Õ«_Õ°Õ¸Õ¯Õ¿Õ¥Õ´Õ¢Õ¥Ö€Õ«_Õ¶Õ¸ÕµÕ¥Õ´Õ¢Õ¥Ö€Õ«_Õ¤Õ¥Õ¯Õ¿Õ¥Õ´Õ¢Õ¥Ö€Õ«'.split('_'),
+        standalone: 'Õ°Õ¸Ö‚Õ¶Õ¾Õ¡Ö€_ÖƒÕ¥Õ¿Ö€Õ¾Õ¡Ö€_Õ´Õ¡Ö€Õ¿_Õ¡ÕºÖ€Õ«Õ¬_Õ´Õ¡ÕµÕ«Õ½_Õ°Õ¸Ö‚Õ¶Õ«Õ½_Õ°Õ¸Ö‚Õ¬Õ«Õ½_Ö…Õ£Õ¸Õ½Õ¿Õ¸Õ½_Õ½Õ¥ÕºÕ¿Õ¥Õ´Õ¢Õ¥Ö€_Õ°Õ¸Õ¯Õ¿Õ¥Õ´Õ¢Õ¥Ö€_Õ¶Õ¸ÕµÕ¥Õ´Õ¢Õ¥Ö€_Õ¤Õ¥Õ¯Õ¿Õ¥Õ´Õ¢Õ¥Ö€'.split('_')
+    },
+    monthsShort : 'Õ°Õ¶Õ¾_ÖƒÕ¿Ö€_Õ´Ö€Õ¿_Õ¡ÕºÖ€_Õ´ÕµÕ½_Õ°Õ¶Õ½_Õ°Õ¬Õ½_Ö…Õ£Õ½_Õ½ÕºÕ¿_Õ°Õ¯Õ¿_Õ¶Õ´Õ¢_Õ¤Õ¯Õ¿'.split('_'),
+    weekdays : 'Õ¯Õ«Ö€Õ¡Õ¯Õ«_Õ¥Ö€Õ¯Õ¸Ö‚Õ·Õ¡Õ¢Õ©Õ«_Õ¥Ö€Õ¥Ö„Õ·Õ¡Õ¢Õ©Õ«_Õ¹Õ¸Ö€Õ¥Ö„Õ·Õ¡Õ¢Õ©Õ«_Õ°Õ«Õ¶Õ£Õ·Õ¡Õ¢Õ©Õ«_Õ¸Ö‚Ö€Õ¢Õ¡Õ©_Õ·Õ¡Õ¢Õ¡Õ©'.split('_'),
+    weekdaysShort : 'Õ¯Ö€Õ¯_Õ¥Ö€Õ¯_Õ¥Ö€Ö„_Õ¹Ö€Ö„_Õ°Õ¶Õ£_Õ¸Ö‚Ö€Õ¢_Õ·Õ¢Õ©'.split('_'),
+    weekdaysMin : 'Õ¯Ö€Õ¯_Õ¥Ö€Õ¯_Õ¥Ö€Ö„_Õ¹Ö€Ö„_Õ°Õ¶Õ£_Õ¸Ö‚Ö€Õ¢_Õ·Õ¢Õ©'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY Õ©.',
+        LLL : 'D MMMM YYYY Õ©., HH:mm',
+        LLLL : 'dddd, D MMMM YYYY Õ©., HH:mm'
+    },
+    calendar : {
+        sameDay: '[Õ¡ÕµÕ½Ö…Ö€] LT',
+        nextDay: '[Õ¾Õ¡Õ²Õ¨] LT',
+        lastDay: '[Õ¥Ö€Õ¥Õ¯] LT',
+        nextWeek: function () {
+            return 'dddd [Ö…Ö€Õ¨ ÕªÕ¡Õ´Õ¨] LT';
+        },
+        lastWeek: function () {
+            return '[անցած] dddd [օրը ժամը] LT';
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : '%s Õ°Õ¥Õ¿Õ¸',
+        past : '%s Õ¡Õ¼Õ¡Õ»',
+        s : 'Õ´Õ« Ö„Õ¡Õ¶Õ« Õ¾Õ¡ÕµÖ€Õ¯ÕµÕ¡Õ¶',
+        m : 'Ö€Õ¸ÕºÕ¥',
+        mm : '%d Ö€Õ¸ÕºÕ¥',
+        h : 'ÕªÕ¡Õ´',
+        hh : '%d ÕªÕ¡Õ´',
+        d : 'Ö…Ö€',
+        dd : '%d Ö…Ö€',
+        M : 'Õ¡Õ´Õ«Õ½',
+        MM : '%d Õ¡Õ´Õ«Õ½',
+        y : 'Õ¿Õ¡Ö€Õ«',
+        yy : '%d Õ¿Õ¡Ö€Õ«'
+    },
+    meridiemParse: /գիշերվա|առավոտվա|ցերեկվա|երեկոյան/,
+    isPM: function (input) {
+        return /^(ցերեկվա|երեկոյան)$/.test(input);
+    },
+    meridiem : function (hour) {
+        if (hour < 4) {
+            return 'Õ£Õ«Õ·Õ¥Ö€Õ¾Õ¡';
+        } else if (hour < 12) {
+            return 'Õ¡Õ¼Õ¡Õ¾Õ¸Õ¿Õ¾Õ¡';
+        } else if (hour < 17) {
+            return 'ցերեկվա';
+        } else {
+            return 'Õ¥Ö€Õ¥Õ¯Õ¸ÕµÕ¡Õ¶';
+        }
+    },
+    ordinalParse: /\d{1,2}|\d{1,2}-(Õ«Õ¶|Ö€Õ¤)/,
+    ordinal: function (number, period) {
+        switch (period) {
+            case 'DDD':
+            case 'w':
+            case 'W':
+            case 'DDDo':
+                if (number === 1) {
+                    return number + '-Õ«Õ¶';
+                }
+                return number + '-Ö€Õ¤';
+            default:
+                return number;
+        }
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/id.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/id.js
new file mode 100644
index 0000000000000000000000000000000000000000..ab4204e5873b8c2bb6570acbc386b7e240bd48b1
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/id.js
@@ -0,0 +1,74 @@
+//! moment.js locale configuration
+//! locale : Indonesian [id]
+//! author : Mohammad Satrio Utomo : https://github.com/tyok
+//! reference: http://id.wikisource.org/wiki/Pedoman_Umum_Ejaan_Bahasa_Indonesia_yang_Disempurnakan
+
+import moment from '../moment';
+
+export default moment.defineLocale('id', {
+    months : 'Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_November_Desember'.split('_'),
+    monthsShort : 'Jan_Feb_Mar_Apr_Mei_Jun_Jul_Ags_Sep_Okt_Nov_Des'.split('_'),
+    weekdays : 'Minggu_Senin_Selasa_Rabu_Kamis_Jumat_Sabtu'.split('_'),
+    weekdaysShort : 'Min_Sen_Sel_Rab_Kam_Jum_Sab'.split('_'),
+    weekdaysMin : 'Mg_Sn_Sl_Rb_Km_Jm_Sb'.split('_'),
+    longDateFormat : {
+        LT : 'HH.mm',
+        LTS : 'HH.mm.ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY [pukul] HH.mm',
+        LLLL : 'dddd, D MMMM YYYY [pukul] HH.mm'
+    },
+    meridiemParse: /pagi|siang|sore|malam/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'pagi') {
+            return hour;
+        } else if (meridiem === 'siang') {
+            return hour >= 11 ? hour : hour + 12;
+        } else if (meridiem === 'sore' || meridiem === 'malam') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 11) {
+            return 'pagi';
+        } else if (hours < 15) {
+            return 'siang';
+        } else if (hours < 19) {
+            return 'sore';
+        } else {
+            return 'malam';
+        }
+    },
+    calendar : {
+        sameDay : '[Hari ini pukul] LT',
+        nextDay : '[Besok pukul] LT',
+        nextWeek : 'dddd [pukul] LT',
+        lastDay : '[Kemarin pukul] LT',
+        lastWeek : 'dddd [lalu pukul] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'dalam %s',
+        past : '%s yang lalu',
+        s : 'beberapa detik',
+        m : 'semenit',
+        mm : '%d menit',
+        h : 'sejam',
+        hh : '%d jam',
+        d : 'sehari',
+        dd : '%d hari',
+        M : 'sebulan',
+        MM : '%d bulan',
+        y : 'setahun',
+        yy : '%d tahun'
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/is.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/is.js
new file mode 100644
index 0000000000000000000000000000000000000000..22f873d0b20bf9b2a4c81c6931418324f5201331
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/is.js
@@ -0,0 +1,118 @@
+//! moment.js locale configuration
+//! locale : Icelandic [is]
+//! author : Hinrik Örn Sigurðsson : https://github.com/hinrik
+
+import moment from '../moment';
+
+function plural(n) {
+    if (n % 100 === 11) {
+        return true;
+    } else if (n % 10 === 1) {
+        return false;
+    }
+    return true;
+}
+function translate(number, withoutSuffix, key, isFuture) {
+    var result = number + ' ';
+    switch (key) {
+        case 's':
+            return withoutSuffix || isFuture ? 'nokkrar sekúndur' : 'nokkrum sekúndum';
+        case 'm':
+            return withoutSuffix ? 'mínúta' : 'mínútu';
+        case 'mm':
+            if (plural(number)) {
+                return result + (withoutSuffix || isFuture ? 'mínútur' : 'mínútum');
+            } else if (withoutSuffix) {
+                return result + 'mínúta';
+            }
+            return result + 'mínútu';
+        case 'hh':
+            if (plural(number)) {
+                return result + (withoutSuffix || isFuture ? 'klukkustundir' : 'klukkustundum');
+            }
+            return result + 'klukkustund';
+        case 'd':
+            if (withoutSuffix) {
+                return 'dagur';
+            }
+            return isFuture ? 'dag' : 'degi';
+        case 'dd':
+            if (plural(number)) {
+                if (withoutSuffix) {
+                    return result + 'dagar';
+                }
+                return result + (isFuture ? 'daga' : 'dögum');
+            } else if (withoutSuffix) {
+                return result + 'dagur';
+            }
+            return result + (isFuture ? 'dag' : 'degi');
+        case 'M':
+            if (withoutSuffix) {
+                return 'mánuður';
+            }
+            return isFuture ? 'mánuð' : 'mánuði';
+        case 'MM':
+            if (plural(number)) {
+                if (withoutSuffix) {
+                    return result + 'mánuðir';
+                }
+                return result + (isFuture ? 'mánuði' : 'mánuðum');
+            } else if (withoutSuffix) {
+                return result + 'mánuður';
+            }
+            return result + (isFuture ? 'mánuð' : 'mánuði');
+        case 'y':
+            return withoutSuffix || isFuture ? 'ár' : 'ári';
+        case 'yy':
+            if (plural(number)) {
+                return result + (withoutSuffix || isFuture ? 'ár' : 'árum');
+            }
+            return result + (withoutSuffix || isFuture ? 'ár' : 'ári');
+    }
+}
+
+export default moment.defineLocale('is', {
+    months : 'janúar_febrúar_mars_apríl_maí_júní_júlí_ágúst_september_október_nóvember_desember'.split('_'),
+    monthsShort : 'jan_feb_mar_apr_maí_jún_júl_ágú_sep_okt_nóv_des'.split('_'),
+    weekdays : 'sunnudagur_mánudagur_þriðjudagur_miðvikudagur_fimmtudagur_föstudagur_laugardagur'.split('_'),
+    weekdaysShort : 'sun_mán_þri_mið_fim_fös_lau'.split('_'),
+    weekdaysMin : 'Su_Má_Þr_Mi_Fi_Fö_La'.split('_'),
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY [kl.] H:mm',
+        LLLL : 'dddd, D. MMMM YYYY [kl.] H:mm'
+    },
+    calendar : {
+        sameDay : '[í dag kl.] LT',
+        nextDay : '[á morgun kl.] LT',
+        nextWeek : 'dddd [kl.] LT',
+        lastDay : '[í gær kl.] LT',
+        lastWeek : '[síðasta] dddd [kl.] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'eftir %s',
+        past : 'fyrir %s síðan',
+        s : translate,
+        m : translate,
+        mm : translate,
+        h : 'klukkustund',
+        hh : translate,
+        d : translate,
+        dd : translate,
+        M : translate,
+        MM : translate,
+        y : translate,
+        yy : translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/it.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/it.js
new file mode 100644
index 0000000000000000000000000000000000000000..0b47212e2262161980de7ad1de5c996c05a80703
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/it.js
@@ -0,0 +1,61 @@
+//! moment.js locale configuration
+//! locale : Italian [it]
+//! author : Lorenzo : https://github.com/aliem
+//! author: Mattia Larentis: https://github.com/nostalgiaz
+
+import moment from '../moment';
+
+export default moment.defineLocale('it', {
+    months : 'gennaio_febbraio_marzo_aprile_maggio_giugno_luglio_agosto_settembre_ottobre_novembre_dicembre'.split('_'),
+    monthsShort : 'gen_feb_mar_apr_mag_giu_lug_ago_set_ott_nov_dic'.split('_'),
+    weekdays : 'Domenica_Lunedì_Martedì_Mercoledì_Giovedì_Venerdì_Sabato'.split('_'),
+    weekdaysShort : 'Dom_Lun_Mar_Mer_Gio_Ven_Sab'.split('_'),
+    weekdaysMin : 'Do_Lu_Ma_Me_Gi_Ve_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Oggi alle] LT',
+        nextDay: '[Domani alle] LT',
+        nextWeek: 'dddd [alle] LT',
+        lastDay: '[Ieri alle] LT',
+        lastWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[la scorsa] dddd [alle] LT';
+                default:
+                    return '[lo scorso] dddd [alle] LT';
+            }
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : function (s) {
+            return ((/^[0-9].+$/).test(s) ? 'tra' : 'in') + ' ' + s;
+        },
+        past : '%s fa',
+        s : 'alcuni secondi',
+        m : 'un minuto',
+        mm : '%d minuti',
+        h : 'un\'ora',
+        hh : '%d ore',
+        d : 'un giorno',
+        dd : '%d giorni',
+        M : 'un mese',
+        MM : '%d mesi',
+        y : 'un anno',
+        yy : '%d anni'
+    },
+    ordinalParse : /\d{1,2}º/,
+    ordinal: '%dº',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ja.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ja.js
new file mode 100644
index 0000000000000000000000000000000000000000..38a262ed3dc297769ac03381c40d2f0704b38ada
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ja.js
@@ -0,0 +1,67 @@
+//! moment.js locale configuration
+//! locale : Japanese [ja]
+//! author : LI Long : https://github.com/baryon
+
+import moment from '../moment';
+
+export default moment.defineLocale('ja', {
+    months : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
+    monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
+    weekdays : '日曜日_月曜日_火曜日_水曜日_木曜日_金曜日_土曜日'.split('_'),
+    weekdaysShort : '日_月_火_水_木_金_土'.split('_'),
+    weekdaysMin : '日_月_火_水_木_金_土'.split('_'),
+    longDateFormat : {
+        LT : 'Ah時m分',
+        LTS : 'Ah時m分s秒',
+        L : 'YYYY/MM/DD',
+        LL : 'YYYY年M月D日',
+        LLL : 'YYYY年M月D日Ah時m分',
+        LLLL : 'YYYY年M月D日Ah時m分 dddd'
+    },
+    meridiemParse: /午前|午後/i,
+    isPM : function (input) {
+        return input === '午後';
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return '午前';
+        } else {
+            return '午後';
+        }
+    },
+    calendar : {
+        sameDay : '[今日] LT',
+        nextDay : '[明日] LT',
+        nextWeek : '[来週]dddd LT',
+        lastDay : '[昨日] LT',
+        lastWeek : '[前週]dddd LT',
+        sameElse : 'L'
+    },
+    ordinalParse : /\d{1,2}æ—¥/,
+    ordinal : function (number, period) {
+        switch (period) {
+            case 'd':
+            case 'D':
+            case 'DDD':
+                return number + 'æ—¥';
+            default:
+                return number;
+        }
+    },
+    relativeTime : {
+        future : '%s後',
+        past : '%s前',
+        s : 'æ•°ç§’',
+        m : '1分',
+        mm : '%d分',
+        h : '1時間',
+        hh : '%d時間',
+        d : '1æ—¥',
+        dd : '%dæ—¥',
+        M : '1ヶ月',
+        MM : '%dヶ月',
+        y : '1å¹´',
+        yy : '%då¹´'
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/jv.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/jv.js
new file mode 100644
index 0000000000000000000000000000000000000000..e5e25f9db16805e993c0ad93843bd351fc89be7a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/jv.js
@@ -0,0 +1,73 @@
+//! moment.js locale configuration
+//! locale : Javanese [jv]
+//! author : Rony Lantip : https://github.com/lantip
+//! reference: http://jv.wikipedia.org/wiki/Basa_Jawa
+
+import moment from '../moment';
+
+export default moment.defineLocale('jv', {
+    months : 'Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_Nopember_Desember'.split('_'),
+    monthsShort : 'Jan_Feb_Mar_Apr_Mei_Jun_Jul_Ags_Sep_Okt_Nop_Des'.split('_'),
+    weekdays : 'Minggu_Senen_Seloso_Rebu_Kemis_Jemuwah_Septu'.split('_'),
+    weekdaysShort : 'Min_Sen_Sel_Reb_Kem_Jem_Sep'.split('_'),
+    weekdaysMin : 'Mg_Sn_Sl_Rb_Km_Jm_Sp'.split('_'),
+    longDateFormat : {
+        LT : 'HH.mm',
+        LTS : 'HH.mm.ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY [pukul] HH.mm',
+        LLLL : 'dddd, D MMMM YYYY [pukul] HH.mm'
+    },
+    meridiemParse: /enjing|siyang|sonten|ndalu/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'enjing') {
+            return hour;
+        } else if (meridiem === 'siyang') {
+            return hour >= 11 ? hour : hour + 12;
+        } else if (meridiem === 'sonten' || meridiem === 'ndalu') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 11) {
+            return 'enjing';
+        } else if (hours < 15) {
+            return 'siyang';
+        } else if (hours < 19) {
+            return 'sonten';
+        } else {
+            return 'ndalu';
+        }
+    },
+    calendar : {
+        sameDay : '[Dinten puniko pukul] LT',
+        nextDay : '[Mbenjang pukul] LT',
+        nextWeek : 'dddd [pukul] LT',
+        lastDay : '[Kala wingi pukul] LT',
+        lastWeek : 'dddd [kepengker pukul] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'wonten ing %s',
+        past : '%s ingkang kepengker',
+        s : 'sawetawis detik',
+        m : 'setunggal menit',
+        mm : '%d menit',
+        h : 'setunggal jam',
+        hh : '%d jam',
+        d : 'sedinten',
+        dd : '%d dinten',
+        M : 'sewulan',
+        MM : '%d wulan',
+        y : 'setaun',
+        yy : '%d taun'
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ka.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ka.js
new file mode 100644
index 0000000000000000000000000000000000000000..b03175d629de11a07bc6e3983eff37a9e1e9f31b
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ka.js
@@ -0,0 +1,80 @@
+//! moment.js locale configuration
+//! locale : Georgian [ka]
+//! author : Irakli Janiashvili : https://github.com/irakli-janiashvili
+
+import moment from '../moment';
+
+export default moment.defineLocale('ka', {
+    months : {
+        standalone: 'იანვარი_თებერვალი_მარტი_აპრილი_მაისი_ივნისი_ივლისი_აგვისტო_სექტემბერი_ოქტომბერი_ნოემბერი_დეკემბერი'.split('_'),
+        format: 'იანვარს_თებერვალს_მარტს_აპრილის_მაისს_ივნისს_ივლისს_აგვისტს_სექტემბერს_ოქტომბერს_ნოემბერს_დეკემბერს'.split('_')
+    },
+    monthsShort : 'იან_თებ_მარ_აპრ_მაი_ივნ_ივლ_აგვ_სექ_ოქტ_ნოე_დეკ'.split('_'),
+    weekdays : {
+        standalone: 'კვირა_ორშაბათი_სამშაბათი_ოთხშაბათი_ხუთშაბათი_პარასკევი_შაბათი'.split('_'),
+        format: 'კვირას_ორშაბათს_სამშაბათს_ოთხშაბათს_ხუთშაბათს_პარასკევს_შაბათს'.split('_'),
+        isFormat: /(წინა|შემდეგ)/
+    },
+    weekdaysShort : 'კვი_ორშ_სამ_ოთხ_ხუთ_პარ_შაბ'.split('_'),
+    weekdaysMin : 'კვ_ორ_სა_ოთ_ხუ_პა_შა'.split('_'),
+    longDateFormat : {
+        LT : 'h:mm A',
+        LTS : 'h:mm:ss A',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY h:mm A',
+        LLLL : 'dddd, D MMMM YYYY h:mm A'
+    },
+    calendar : {
+        sameDay : '[დღეს] LT[-ზე]',
+        nextDay : '[ხვალ] LT[-ზე]',
+        lastDay : '[გუშინ] LT[-ზე]',
+        nextWeek : '[შემდეგ] dddd LT[-ზე]',
+        lastWeek : '[წინა] dddd LT-ზე',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : function (s) {
+            return (/(წამი|წუთი|საათი|წელი)/).test(s) ?
+                s.replace(/ი$/, 'ში') :
+                s + 'ში';
+        },
+        past : function (s) {
+            if ((/(წამი|წუთი|საათი|დღე|თვე)/).test(s)) {
+                return s.replace(/(ი|ე)$/, 'ის წინ');
+            }
+            if ((/წელი/).test(s)) {
+                return s.replace(/წელი$/, 'წლის წინ');
+            }
+        },
+        s : 'რამდენიმე წამი',
+        m : 'წუთი',
+        mm : '%d წუთი',
+        h : 'საათი',
+        hh : '%d საათი',
+        d : 'დღე',
+        dd : '%d დღე',
+        M : 'თვე',
+        MM : '%d თვე',
+        y : 'წელი',
+        yy : '%d წელი'
+    },
+    ordinalParse: /0|1-ლი|მე-\d{1,2}|\d{1,2}-ე/,
+    ordinal : function (number) {
+        if (number === 0) {
+            return number;
+        }
+        if (number === 1) {
+            return number + '-ლი';
+        }
+        if ((number < 20) || (number <= 100 && (number % 20 === 0)) || (number % 100 === 0)) {
+            return 'მე-' + number;
+        }
+        return number + '-ე';
+    },
+    week : {
+        dow : 1,
+        doy : 7
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/kk.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/kk.js
new file mode 100644
index 0000000000000000000000000000000000000000..073405439cc9518235abcf05b14ea75d148f6c26
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/kk.js
@@ -0,0 +1,77 @@
+//! moment.js locale configuration
+//! locale : Kazakh [kk]
+//! authors : Nurlan Rakhimzhanov : https://github.com/nurlan
+
+import moment from '../moment';
+
+var suffixes = {
+    0: '-ші',
+    1: '-ші',
+    2: '-ші',
+    3: '-ші',
+    4: '-ші',
+    5: '-ші',
+    6: '-шы',
+    7: '-ші',
+    8: '-ші',
+    9: '-шы',
+    10: '-шы',
+    20: '-шы',
+    30: '-шы',
+    40: '-шы',
+    50: '-ші',
+    60: '-шы',
+    70: '-ші',
+    80: '-ші',
+    90: '-шы',
+    100: '-ші'
+};
+
+export default moment.defineLocale('kk', {
+    months : 'қаңтар_ақпан_наурыз_сәуір_мамыр_маусым_шілде_тамыз_қыркүйек_қазан_қараша_желтоқсан'.split('_'),
+    monthsShort : 'қаң_ақп_нау_сәу_мам_мау_шіл_там_қыр_қаз_қар_жел'.split('_'),
+    weekdays : 'жексенбі_дүйсенбі_сейсенбі_сәрсенбі_бейсенбі_жұма_сенбі'.split('_'),
+    weekdaysShort : 'жек_дүй_сей_сәр_бей_жұм_сен'.split('_'),
+    weekdaysMin : 'жк_дй_сй_ср_бй_жм_сн'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[Бүгін сағат] LT',
+        nextDay : '[Ертең сағат] LT',
+        nextWeek : 'dddd [сағат] LT',
+        lastDay : '[Кеше сағат] LT',
+        lastWeek : '[Өткен аптаның] dddd [сағат] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s ішінде',
+        past : '%s бұрын',
+        s : 'бірнеше секунд',
+        m : 'бір минут',
+        mm : '%d минут',
+        h : 'бір сағат',
+        hh : '%d сағат',
+        d : 'бір күн',
+        dd : '%d күн',
+        M : 'бір ай',
+        MM : '%d ай',
+        y : 'бір жыл',
+        yy : '%d жыл'
+    },
+    ordinalParse: /\d{1,2}-(ші|шы)/,
+    ordinal : function (number) {
+        var a = number % 10,
+            b = number >= 100 ? 100 : null;
+        return number + (suffixes[number] || suffixes[a] || suffixes[b]);
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/km.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/km.js
new file mode 100644
index 0000000000000000000000000000000000000000..8ae00be765405e35c14065f3e8ab934cd1a339a7
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/km.js
@@ -0,0 +1,49 @@
+//! moment.js locale configuration
+//! locale : Cambodian [km]
+//! author : Kruy Vanna : https://github.com/kruyvanna
+
+import moment from '../moment';
+
+export default moment.defineLocale('km', {
+    months: 'មករា_កុម្ភៈ_មីនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ'.split('_'),
+    monthsShort: 'មករា_កុម្ភៈ_មីនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ'.split('_'),
+    weekdays: 'អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍'.split('_'),
+    weekdaysShort: 'អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍'.split('_'),
+    weekdaysMin: 'អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍'.split('_'),
+    longDateFormat: {
+        LT: 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L: 'DD/MM/YYYY',
+        LL: 'D MMMM YYYY',
+        LLL: 'D MMMM YYYY HH:mm',
+        LLLL: 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar: {
+        sameDay: '[ថ្ងៃនេះ ម៉ោង] LT',
+        nextDay: '[ស្អែក ម៉ោង] LT',
+        nextWeek: 'dddd [ម៉ោង] LT',
+        lastDay: '[ម្សិលមិញ ម៉ោង] LT',
+        lastWeek: 'dddd [សប្តាហ៍មុន] [ម៉ោង] LT',
+        sameElse: 'L'
+    },
+    relativeTime: {
+        future: '%sទៀត',
+        past: '%sមុន',
+        s: 'ប៉ុន្មានវិនាទី',
+        m: 'មួយនាទី',
+        mm: '%d នាទី',
+        h: 'មួយម៉ោង',
+        hh: '%d ម៉ោង',
+        d: 'មួយថ្ងៃ',
+        dd: '%d ថ្ងៃ',
+        M: 'មួយខែ',
+        MM: '%d ខែ',
+        y: 'មួយឆ្នាំ',
+        yy: '%d ឆ្នាំ'
+    },
+    week: {
+        dow: 1, // Monday is the first day of the week.
+        doy: 4 // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ko.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ko.js
new file mode 100644
index 0000000000000000000000000000000000000000..6941fa5261c90c5781001a6e0e7d2577631e329b
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ko.js
@@ -0,0 +1,56 @@
+//! moment.js locale configuration
+//! locale : Korean [ko]
+//! author : Kyungwook, Park : https://github.com/kyungw00k
+//! author : Jeeeyul Lee <jeeeyul@gmail.com>
+
+import moment from '../moment';
+
+export default moment.defineLocale('ko', {
+    months : '1ì›”_2ì›”_3ì›”_4ì›”_5ì›”_6ì›”_7ì›”_8ì›”_9ì›”_10ì›”_11ì›”_12ì›”'.split('_'),
+    monthsShort : '1ì›”_2ì›”_3ì›”_4ì›”_5ì›”_6ì›”_7ì›”_8ì›”_9ì›”_10ì›”_11ì›”_12ì›”'.split('_'),
+    weekdays : '일요일_월요일_화요일_수요일_목요일_금요일_토요일'.split('_'),
+    weekdaysShort : '일_월_화_수_목_금_토'.split('_'),
+    weekdaysMin : '일_월_화_수_목_금_토'.split('_'),
+    longDateFormat : {
+        LT : 'A h시 m분',
+        LTS : 'A h시 m분 s초',
+        L : 'YYYY.MM.DD',
+        LL : 'YYYY년 MMMM D일',
+        LLL : 'YYYY년 MMMM D일 A h시 m분',
+        LLLL : 'YYYY년 MMMM D일 dddd A h시 m분'
+    },
+    calendar : {
+        sameDay : '오늘 LT',
+        nextDay : '내일 LT',
+        nextWeek : 'dddd LT',
+        lastDay : '어제 LT',
+        lastWeek : '지난주 dddd LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s 후',
+        past : '%s ì „',
+        s : '몇 초',
+        ss : '%dì´ˆ',
+        m : '일분',
+        mm : '%dë¶„',
+        h : '한 시간',
+        hh : '%d시간',
+        d : '하루',
+        dd : '%d일',
+        M : '한 달',
+        MM : '%d달',
+        y : '일 년',
+        yy : '%dë…„'
+    },
+    ordinalParse : /\d{1,2}일/,
+    ordinal : '%d일',
+    meridiemParse : /오전|오후/,
+    isPM : function (token) {
+        return token === '오후';
+    },
+    meridiem : function (hour, minute, isUpper) {
+        return hour < 12 ? '오전' : '오후';
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ky.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ky.js
new file mode 100644
index 0000000000000000000000000000000000000000..566677c810900dc0f40816f11403ce935b1cd013
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ky.js
@@ -0,0 +1,78 @@
+//! moment.js locale configuration
+//! locale : Kyrgyz [ky]
+//! author : Chyngyz Arystan uulu : https://github.com/chyngyz
+
+
+import moment from '../moment';
+
+var suffixes = {
+    0: '-чү',
+    1: '-чи',
+    2: '-чи',
+    3: '-чү',
+    4: '-чү',
+    5: '-чи',
+    6: '-чы',
+    7: '-чи',
+    8: '-чи',
+    9: '-чу',
+    10: '-чу',
+    20: '-чы',
+    30: '-чу',
+    40: '-чы',
+    50: '-чү',
+    60: '-чы',
+    70: '-чи',
+    80: '-чи',
+    90: '-чу',
+    100: '-чү'
+};
+
+export default moment.defineLocale('ky', {
+    months : 'январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь'.split('_'),
+    monthsShort : 'янв_фев_март_апр_май_июнь_июль_авг_сен_окт_ноя_дек'.split('_'),
+    weekdays : 'Жекшемби_Дүйшөмбү_Шейшемби_Шаршемби_Бейшемби_Жума_Ишемби'.split('_'),
+    weekdaysShort : 'Жек_Дүй_Шей_Шар_Бей_Жум_Ише'.split('_'),
+    weekdaysMin : 'Жк_Дй_Шй_Шр_Бй_Жм_Иш'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[Бүгүн саат] LT',
+        nextDay : '[Эртең саат] LT',
+        nextWeek : 'dddd [саат] LT',
+        lastDay : '[Кече саат] LT',
+        lastWeek : '[Өткен аптанын] dddd [күнү] [саат] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s ичинде',
+        past : '%s мурун',
+        s : 'бирнече секунд',
+        m : 'бир мүнөт',
+        mm : '%d мүнөт',
+        h : 'бир саат',
+        hh : '%d саат',
+        d : 'бир күн',
+        dd : '%d күн',
+        M : 'бир ай',
+        MM : '%d ай',
+        y : 'бир жыл',
+        yy : '%d жыл'
+    },
+    ordinalParse: /\d{1,2}-(чи|чы|чү|чу)/,
+    ordinal : function (number) {
+        var a = number % 10,
+            b = number >= 100 ? 100 : null;
+        return number + (suffixes[number] || suffixes[a] || suffixes[b]);
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/lb.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/lb.js
new file mode 100644
index 0000000000000000000000000000000000000000..843b7adf25341b1191de3eae605f7438fc434eef
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/lb.js
@@ -0,0 +1,128 @@
+//! moment.js locale configuration
+//! locale : Luxembourgish [lb]
+//! author : mweimerskirch : https://github.com/mweimerskirch
+//! author : David Raison : https://github.com/kwisatz
+
+import moment from '../moment';
+
+function processRelativeTime(number, withoutSuffix, key, isFuture) {
+    var format = {
+        'm': ['eng Minutt', 'enger Minutt'],
+        'h': ['eng Stonn', 'enger Stonn'],
+        'd': ['een Dag', 'engem Dag'],
+        'M': ['ee Mount', 'engem Mount'],
+        'y': ['ee Joer', 'engem Joer']
+    };
+    return withoutSuffix ? format[key][0] : format[key][1];
+}
+function processFutureTime(string) {
+    var number = string.substr(0, string.indexOf(' '));
+    if (eifelerRegelAppliesToNumber(number)) {
+        return 'a ' + string;
+    }
+    return 'an ' + string;
+}
+function processPastTime(string) {
+    var number = string.substr(0, string.indexOf(' '));
+    if (eifelerRegelAppliesToNumber(number)) {
+        return 'viru ' + string;
+    }
+    return 'virun ' + string;
+}
+/**
+ * Returns true if the word before the given number loses the '-n' ending.
+ * e.g. 'an 10 Deeg' but 'a 5 Deeg'
+ *
+ * @param number {integer}
+ * @returns {boolean}
+ */
+function eifelerRegelAppliesToNumber(number) {
+    number = parseInt(number, 10);
+    if (isNaN(number)) {
+        return false;
+    }
+    if (number < 0) {
+        // Negative Number --> always true
+        return true;
+    } else if (number < 10) {
+        // Only 1 digit
+        if (4 <= number && number <= 7) {
+            return true;
+        }
+        return false;
+    } else if (number < 100) {
+        // 2 digits
+        var lastDigit = number % 10, firstDigit = number / 10;
+        if (lastDigit === 0) {
+            return eifelerRegelAppliesToNumber(firstDigit);
+        }
+        return eifelerRegelAppliesToNumber(lastDigit);
+    } else if (number < 10000) {
+        // 3 or 4 digits --> recursively check first digit
+        while (number >= 10) {
+            number = number / 10;
+        }
+        return eifelerRegelAppliesToNumber(number);
+    } else {
+        // Anything larger than 4 digits: recursively check first n-3 digits
+        number = number / 1000;
+        return eifelerRegelAppliesToNumber(number);
+    }
+}
+
+export default moment.defineLocale('lb', {
+    months: 'Januar_Februar_Mäerz_Abrëll_Mee_Juni_Juli_August_September_Oktober_November_Dezember'.split('_'),
+    monthsShort: 'Jan._Febr._Mrz._Abr._Mee_Jun._Jul._Aug._Sept._Okt._Nov._Dez.'.split('_'),
+    monthsParseExact : true,
+    weekdays: 'Sonndeg_Méindeg_Dënschdeg_Mëttwoch_Donneschdeg_Freideg_Samschdeg'.split('_'),
+    weekdaysShort: 'So._Mé._Dë._Më._Do._Fr._Sa.'.split('_'),
+    weekdaysMin: 'So_Mé_Dë_Më_Do_Fr_Sa'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat: {
+        LT: 'H:mm [Auer]',
+        LTS: 'H:mm:ss [Auer]',
+        L: 'DD.MM.YYYY',
+        LL: 'D. MMMM YYYY',
+        LLL: 'D. MMMM YYYY H:mm [Auer]',
+        LLLL: 'dddd, D. MMMM YYYY H:mm [Auer]'
+    },
+    calendar: {
+        sameDay: '[Haut um] LT',
+        sameElse: 'L',
+        nextDay: '[Muer um] LT',
+        nextWeek: 'dddd [um] LT',
+        lastDay: '[Gëschter um] LT',
+        lastWeek: function () {
+            // Different date string for 'Dënschdeg' (Tuesday) and 'Donneschdeg' (Thursday) due to phonological rule
+            switch (this.day()) {
+                case 2:
+                case 4:
+                    return '[Leschten] dddd [um] LT';
+                default:
+                    return '[Leschte] dddd [um] LT';
+            }
+        }
+    },
+    relativeTime : {
+        future : processFutureTime,
+        past : processPastTime,
+        s : 'e puer Sekonnen',
+        m : processRelativeTime,
+        mm : '%d Minutten',
+        h : processRelativeTime,
+        hh : '%d Stonnen',
+        d : processRelativeTime,
+        dd : '%d Deeg',
+        M : processRelativeTime,
+        MM : '%d Méint',
+        y : processRelativeTime,
+        yy : '%d Joer'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal: '%d.',
+    week: {
+        dow: 1, // Monday is the first day of the week.
+        doy: 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/lo.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/lo.js
new file mode 100644
index 0000000000000000000000000000000000000000..5f6ad7d5ca55263d4e1cd73127d0ee8c1932ae36
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/lo.js
@@ -0,0 +1,61 @@
+//! moment.js locale configuration
+//! locale : Lao [lo]
+//! author : Ryan Hart : https://github.com/ryanhart2
+
+import moment from '../moment';
+
+export default moment.defineLocale('lo', {
+    months : 'ມັງກອນ_ກຸມພາ_ມີນາ_ເມສາ_ພຶດສະພາ_ມິຖຸນາ_ກໍລະກົດ_ສິງຫາ_ກັນຍາ_ຕຸລາ_ພະຈິກ_ທັນວາ'.split('_'),
+    monthsShort : 'ມັງກອນ_ກຸມພາ_ມີນາ_ເມສາ_ພຶດສະພາ_ມິຖຸນາ_ກໍລະກົດ_ສິງຫາ_ກັນຍາ_ຕຸລາ_ພະຈິກ_ທັນວາ'.split('_'),
+    weekdays : 'ອາທິດ_ຈັນ_ອັງຄານ_ພຸດ_ພະຫັດ_ສຸກ_ເສົາ'.split('_'),
+    weekdaysShort : 'ທິດ_ຈັນ_ອັງຄານ_ພຸດ_ພະຫັດ_ສຸກ_ເສົາ'.split('_'),
+    weekdaysMin : 'ທ_ຈ_ອຄ_ພ_ພຫ_ສກ_ສ'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'ວັນdddd D MMMM YYYY HH:mm'
+    },
+    meridiemParse: /ຕອນເຊົ້າ|ຕອນແລງ/,
+    isPM: function (input) {
+        return input === 'ຕອນແລງ';
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return 'ຕອນເຊົ້າ';
+        } else {
+            return 'ຕອນແລງ';
+        }
+    },
+    calendar : {
+        sameDay : '[ມື້ນີ້ເວລາ] LT',
+        nextDay : '[ມື້ອື່ນເວລາ] LT',
+        nextWeek : '[ວັນ]dddd[ໜ້າເວລາ] LT',
+        lastDay : '[ມື້ວານນີ້ເວລາ] LT',
+        lastWeek : '[ວັນ]dddd[ແລ້ວນີ້ເວລາ] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'ອີກ %s',
+        past : '%sຜ່ານມາ',
+        s : 'ບໍ່ເທົ່າໃດວິນາທີ',
+        m : '1 ນາທີ',
+        mm : '%d ນາທີ',
+        h : '1 ຊົ່ວໂມງ',
+        hh : '%d ຊົ່ວໂມງ',
+        d : '1 ມື້',
+        dd : '%d ມື້',
+        M : '1 ເດືອນ',
+        MM : '%d ເດືອນ',
+        y : '1 ປີ',
+        yy : '%d ປີ'
+    },
+    ordinalParse: /(ທີ່)\d{1,2}/,
+    ordinal : function (number) {
+        return 'ທີ່' + number;
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/lt.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/lt.js
new file mode 100644
index 0000000000000000000000000000000000000000..363f193609d92626aadeaf875eae26f01b629801
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/lt.js
@@ -0,0 +1,108 @@
+//! moment.js locale configuration
+//! locale : Lithuanian [lt]
+//! author : Mindaugas Mozūras : https://github.com/mmozuras
+
+import moment from '../moment';
+
+var units = {
+    'm' : 'minutÄ—_minutÄ—s_minutÄ™',
+    'mm': 'minutės_minučių_minutes',
+    'h' : 'valanda_valandos_valandÄ…',
+    'hh': 'valandos_valandų_valandas',
+    'd' : 'diena_dienos_dienÄ…',
+    'dd': 'dienos_dienų_dienas',
+    'M' : 'mėnuo_mėnesio_mėnesį',
+    'MM': 'mėnesiai_mėnesių_mėnesius',
+    'y' : 'metai_metų_metus',
+    'yy': 'metai_metų_metus'
+};
+function translateSeconds(number, withoutSuffix, key, isFuture) {
+    if (withoutSuffix) {
+        return 'kelios sekundÄ—s';
+    } else {
+        return isFuture ? 'kelių sekundžių' : 'kelias sekundes';
+    }
+}
+function translateSingular(number, withoutSuffix, key, isFuture) {
+    return withoutSuffix ? forms(key)[0] : (isFuture ? forms(key)[1] : forms(key)[2]);
+}
+function special(number) {
+    return number % 10 === 0 || (number > 10 && number < 20);
+}
+function forms(key) {
+    return units[key].split('_');
+}
+function translate(number, withoutSuffix, key, isFuture) {
+    var result = number + ' ';
+    if (number === 1) {
+        return result + translateSingular(number, withoutSuffix, key[0], isFuture);
+    } else if (withoutSuffix) {
+        return result + (special(number) ? forms(key)[1] : forms(key)[0]);
+    } else {
+        if (isFuture) {
+            return result + forms(key)[1];
+        } else {
+            return result + (special(number) ? forms(key)[1] : forms(key)[2]);
+        }
+    }
+}
+export default moment.defineLocale('lt', {
+    months : {
+        format: 'sausio_vasario_kovo_balandžio_gegužės_birželio_liepos_rugpjūčio_rugsėjo_spalio_lapkričio_gruodžio'.split('_'),
+        standalone: 'sausis_vasaris_kovas_balandis_gegužė_birželis_liepa_rugpjūtis_rugsėjis_spalis_lapkritis_gruodis'.split('_'),
+        isFormat: /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?|MMMM?(\[[^\[\]]*\]|\s)+D[oD]?/
+    },
+    monthsShort : 'sau_vas_kov_bal_geg_bir_lie_rgp_rgs_spa_lap_grd'.split('_'),
+    weekdays : {
+        format: 'sekmadienį_pirmadienį_antradienį_trečiadienį_ketvirtadienį_penktadienį_šeštadienį'.split('_'),
+        standalone: 'sekmadienis_pirmadienis_antradienis_trečiadienis_ketvirtadienis_penktadienis_šeštadienis'.split('_'),
+        isFormat: /dddd HH:mm/
+    },
+    weekdaysShort : 'Sek_Pir_Ant_Tre_Ket_Pen_Šeš'.split('_'),
+    weekdaysMin : 'S_P_A_T_K_Pn_Å '.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'YYYY-MM-DD',
+        LL : 'YYYY [m.] MMMM D [d.]',
+        LLL : 'YYYY [m.] MMMM D [d.], HH:mm [val.]',
+        LLLL : 'YYYY [m.] MMMM D [d.], dddd, HH:mm [val.]',
+        l : 'YYYY-MM-DD',
+        ll : 'YYYY [m.] MMMM D [d.]',
+        lll : 'YYYY [m.] MMMM D [d.], HH:mm [val.]',
+        llll : 'YYYY [m.] MMMM D [d.], ddd, HH:mm [val.]'
+    },
+    calendar : {
+        sameDay : '[Å iandien] LT',
+        nextDay : '[Rytoj] LT',
+        nextWeek : 'dddd LT',
+        lastDay : '[Vakar] LT',
+        lastWeek : '[Praėjusį] dddd LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'po %s',
+        past : 'prieš %s',
+        s : translateSeconds,
+        m : translateSingular,
+        mm : translate,
+        h : translateSingular,
+        hh : translate,
+        d : translateSingular,
+        dd : translate,
+        M : translateSingular,
+        MM : translate,
+        y : translateSingular,
+        yy : translate
+    },
+    ordinalParse: /\d{1,2}-oji/,
+    ordinal : function (number) {
+        return number + '-oji';
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/lv.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/lv.js
new file mode 100644
index 0000000000000000000000000000000000000000..5afe0b7af52a9701ae32a2b8a495b3dc05976654
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/lv.js
@@ -0,0 +1,88 @@
+//! moment.js locale configuration
+//! locale : Latvian [lv]
+//! author : Kristaps Karlsons : https://github.com/skakri
+//! author : Jānis Elmeris : https://github.com/JanisE
+
+import moment from '../moment';
+
+var units = {
+    'm': 'minūtes_minūtēm_minūte_minūtes'.split('_'),
+    'mm': 'minūtes_minūtēm_minūte_minūtes'.split('_'),
+    'h': 'stundas_stundām_stunda_stundas'.split('_'),
+    'hh': 'stundas_stundām_stunda_stundas'.split('_'),
+    'd': 'dienas_dienām_diena_dienas'.split('_'),
+    'dd': 'dienas_dienām_diena_dienas'.split('_'),
+    'M': 'mēneša_mēnešiem_mēnesis_mēneši'.split('_'),
+    'MM': 'mēneša_mēnešiem_mēnesis_mēneši'.split('_'),
+    'y': 'gada_gadiem_gads_gadi'.split('_'),
+    'yy': 'gada_gadiem_gads_gadi'.split('_')
+};
+/**
+ * @param withoutSuffix boolean true = a length of time; false = before/after a period of time.
+ */
+function format(forms, number, withoutSuffix) {
+    if (withoutSuffix) {
+        // E.g. "21 minūte", "3 minūtes".
+        return number % 10 === 1 && number % 100 !== 11 ? forms[2] : forms[3];
+    } else {
+        // E.g. "21 minūtes" as in "pēc 21 minūtes".
+        // E.g. "3 minūtēm" as in "pēc 3 minūtēm".
+        return number % 10 === 1 && number % 100 !== 11 ? forms[0] : forms[1];
+    }
+}
+function relativeTimeWithPlural(number, withoutSuffix, key) {
+    return number + ' ' + format(units[key], number, withoutSuffix);
+}
+function relativeTimeWithSingular(number, withoutSuffix, key) {
+    return format(units[key], number, withoutSuffix);
+}
+function relativeSeconds(number, withoutSuffix) {
+    return withoutSuffix ? 'dažas sekundes' : 'dažām sekundēm';
+}
+
+export default moment.defineLocale('lv', {
+    months : 'janvāris_februāris_marts_aprīlis_maijs_jūnijs_jūlijs_augusts_septembris_oktobris_novembris_decembris'.split('_'),
+    monthsShort : 'jan_feb_mar_apr_mai_jūn_jūl_aug_sep_okt_nov_dec'.split('_'),
+    weekdays : 'svētdiena_pirmdiena_otrdiena_trešdiena_ceturtdiena_piektdiena_sestdiena'.split('_'),
+    weekdaysShort : 'Sv_P_O_T_C_Pk_S'.split('_'),
+    weekdaysMin : 'Sv_P_O_T_C_Pk_S'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY.',
+        LL : 'YYYY. [gada] D. MMMM',
+        LLL : 'YYYY. [gada] D. MMMM, HH:mm',
+        LLLL : 'YYYY. [gada] D. MMMM, dddd, HH:mm'
+    },
+    calendar : {
+        sameDay : '[Å odien pulksten] LT',
+        nextDay : '[Rīt pulksten] LT',
+        nextWeek : 'dddd [pulksten] LT',
+        lastDay : '[Vakar pulksten] LT',
+        lastWeek : '[Pagājušā] dddd [pulksten] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'pēc %s',
+        past : 'pirms %s',
+        s : relativeSeconds,
+        m : relativeTimeWithSingular,
+        mm : relativeTimeWithPlural,
+        h : relativeTimeWithSingular,
+        hh : relativeTimeWithPlural,
+        d : relativeTimeWithSingular,
+        dd : relativeTimeWithPlural,
+        M : relativeTimeWithSingular,
+        MM : relativeTimeWithPlural,
+        y : relativeTimeWithSingular,
+        yy : relativeTimeWithPlural
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/me.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/me.js
new file mode 100644
index 0000000000000000000000000000000000000000..1635cb500f9faf130f2f6450c364a105b07f8c27
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/me.js
@@ -0,0 +1,101 @@
+//! moment.js locale configuration
+//! locale : Montenegrin [me]
+//! author : Miodrag Nikač <miodrag@restartit.me> : https://github.com/miodragnikac
+
+import moment from '../moment';
+
+var translator = {
+    words: { //Different grammatical cases
+        m: ['jedan minut', 'jednog minuta'],
+        mm: ['minut', 'minuta', 'minuta'],
+        h: ['jedan sat', 'jednog sata'],
+        hh: ['sat', 'sata', 'sati'],
+        dd: ['dan', 'dana', 'dana'],
+        MM: ['mjesec', 'mjeseca', 'mjeseci'],
+        yy: ['godina', 'godine', 'godina']
+    },
+    correctGrammaticalCase: function (number, wordKey) {
+        return number === 1 ? wordKey[0] : (number >= 2 && number <= 4 ? wordKey[1] : wordKey[2]);
+    },
+    translate: function (number, withoutSuffix, key) {
+        var wordKey = translator.words[key];
+        if (key.length === 1) {
+            return withoutSuffix ? wordKey[0] : wordKey[1];
+        } else {
+            return number + ' ' + translator.correctGrammaticalCase(number, wordKey);
+        }
+    }
+};
+
+export default moment.defineLocale('me', {
+    months: 'januar_februar_mart_april_maj_jun_jul_avgust_septembar_oktobar_novembar_decembar'.split('_'),
+    monthsShort: 'jan._feb._mar._apr._maj_jun_jul_avg._sep._okt._nov._dec.'.split('_'),
+    monthsParseExact : true,
+    weekdays: 'nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota'.split('_'),
+    weekdaysShort: 'ned._pon._uto._sri._čet._pet._sub.'.split('_'),
+    weekdaysMin: 'ne_po_ut_sr_če_pe_su'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat: {
+        LT: 'H:mm',
+        LTS : 'H:mm:ss',
+        L: 'DD.MM.YYYY',
+        LL: 'D. MMMM YYYY',
+        LLL: 'D. MMMM YYYY H:mm',
+        LLLL: 'dddd, D. MMMM YYYY H:mm'
+    },
+    calendar: {
+        sameDay: '[danas u] LT',
+        nextDay: '[sjutra u] LT',
+
+        nextWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[u] [nedjelju] [u] LT';
+                case 3:
+                    return '[u] [srijedu] [u] LT';
+                case 6:
+                    return '[u] [subotu] [u] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[u] dddd [u] LT';
+            }
+        },
+        lastDay  : '[juče u] LT',
+        lastWeek : function () {
+            var lastWeekDays = [
+                '[prošle] [nedjelje] [u] LT',
+                '[prošlog] [ponedjeljka] [u] LT',
+                '[prošlog] [utorka] [u] LT',
+                '[prošle] [srijede] [u] LT',
+                '[prošlog] [četvrtka] [u] LT',
+                '[prošlog] [petka] [u] LT',
+                '[prošle] [subote] [u] LT'
+            ];
+            return lastWeekDays[this.day()];
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'za %s',
+        past   : 'prije %s',
+        s      : 'nekoliko sekundi',
+        m      : translator.translate,
+        mm     : translator.translate,
+        h      : translator.translate,
+        hh     : translator.translate,
+        d      : 'dan',
+        dd     : translator.translate,
+        M      : 'mjesec',
+        MM     : translator.translate,
+        y      : 'godinu',
+        yy     : translator.translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/mi.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/mi.js
new file mode 100644
index 0000000000000000000000000000000000000000..6c894bbe0018ffa3228378f5339b25b8af62fcd8
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/mi.js
@@ -0,0 +1,54 @@
+//! moment.js locale configuration
+//! locale : Maori [mi]
+//! author : John Corrigan <robbiecloset@gmail.com> : https://github.com/johnideal
+
+import moment from '../moment';
+
+export default moment.defineLocale('mi', {
+    months: 'Kohi-tāte_Hui-tanguru_Poutū-te-rangi_Paenga-whāwhā_Haratua_Pipiri_Hōngoingoi_Here-turi-kōkā_Mahuru_Whiringa-ā-nuku_Whiringa-ā-rangi_Hakihea'.split('_'),
+    monthsShort: 'Kohi_Hui_Pou_Pae_Hara_Pipi_Hōngoi_Here_Mahu_Whi-nu_Whi-ra_Haki'.split('_'),
+    monthsRegex: /(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,
+    monthsStrictRegex: /(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,
+    monthsShortRegex: /(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,
+    monthsShortStrictRegex: /(?:['a-z\u0101\u014D\u016B]+\-?){1,2}/i,
+    weekdays: 'Rātapu_Mane_Tūrei_Wenerei_Tāite_Paraire_Hātarei'.split('_'),
+    weekdaysShort: 'Ta_Ma_Tū_We_Tāi_Pa_Hā'.split('_'),
+    weekdaysMin: 'Ta_Ma_Tū_We_Tāi_Pa_Hā'.split('_'),
+    longDateFormat: {
+        LT: 'HH:mm',
+        LTS: 'HH:mm:ss',
+        L: 'DD/MM/YYYY',
+        LL: 'D MMMM YYYY',
+        LLL: 'D MMMM YYYY [i] HH:mm',
+        LLLL: 'dddd, D MMMM YYYY [i] HH:mm'
+    },
+    calendar: {
+        sameDay: '[i teie mahana, i] LT',
+        nextDay: '[apopo i] LT',
+        nextWeek: 'dddd [i] LT',
+        lastDay: '[inanahi i] LT',
+        lastWeek: 'dddd [whakamutunga i] LT',
+        sameElse: 'L'
+    },
+    relativeTime: {
+        future: 'i roto i %s',
+        past: '%s i mua',
+        s: 'te hēkona ruarua',
+        m: 'he meneti',
+        mm: '%d meneti',
+        h: 'te haora',
+        hh: '%d haora',
+        d: 'he ra',
+        dd: '%d ra',
+        M: 'he marama',
+        MM: '%d marama',
+        y: 'he tau',
+        yy: '%d tau'
+    },
+    ordinalParse: /\d{1,2}º/,
+    ordinal: '%dº',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/mk.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/mk.js
new file mode 100644
index 0000000000000000000000000000000000000000..ccd7a161878555b1f0a76f55ea3a553e0a1bdf96
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/mk.js
@@ -0,0 +1,81 @@
+//! moment.js locale configuration
+//! locale : Macedonian [mk]
+//! author : Borislav Mickov : https://github.com/B0k0
+
+import moment from '../moment';
+
+export default moment.defineLocale('mk', {
+    months : 'јануари_февруари_март_април_мај_јуни_јули_август_септември_октомври_ноември_декември'.split('_'),
+    monthsShort : 'јан_фев_мар_апр_мај_јун_јул_авг_сеп_окт_ное_дек'.split('_'),
+    weekdays : 'недела_понеделник_вторник_среда_четврток_петок_сабота'.split('_'),
+    weekdaysShort : 'нед_пон_вто_сре_чет_пет_саб'.split('_'),
+    weekdaysMin : 'нe_пo_вт_ср_че_пе_сa'.split('_'),
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'D.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY H:mm',
+        LLLL : 'dddd, D MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay : '[Денес во] LT',
+        nextDay : '[Утре во] LT',
+        nextWeek : '[Во] dddd [во] LT',
+        lastDay : '[Вчера во] LT',
+        lastWeek : function () {
+            switch (this.day()) {
+                case 0:
+                case 3:
+                case 6:
+                    return '[Изминатата] dddd [во] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[Изминатиот] dddd [во] LT';
+            }
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'после %s',
+        past : 'пред %s',
+        s : 'неколку секунди',
+        m : 'минута',
+        mm : '%d минути',
+        h : 'час',
+        hh : '%d часа',
+        d : 'ден',
+        dd : '%d дена',
+        M : 'месец',
+        MM : '%d месеци',
+        y : 'година',
+        yy : '%d години'
+    },
+    ordinalParse: /\d{1,2}-(ев|ен|ти|ви|ри|ми)/,
+    ordinal : function (number) {
+        var lastDigit = number % 10,
+            last2Digits = number % 100;
+        if (number === 0) {
+            return number + '-ев';
+        } else if (last2Digits === 0) {
+            return number + '-ен';
+        } else if (last2Digits > 10 && last2Digits < 20) {
+            return number + '-ти';
+        } else if (lastDigit === 1) {
+            return number + '-ви';
+        } else if (lastDigit === 2) {
+            return number + '-ри';
+        } else if (lastDigit === 7 || lastDigit === 8) {
+            return number + '-ми';
+        } else {
+            return number + '-ти';
+        }
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ml.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ml.js
new file mode 100644
index 0000000000000000000000000000000000000000..c3df98818e4b0b0401f97ddf27f69c85bcb8a8ba
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ml.js
@@ -0,0 +1,72 @@
+//! moment.js locale configuration
+//! locale : Malayalam [ml]
+//! author : Floyd Pink : https://github.com/floydpink
+
+import moment from '../moment';
+
+export default moment.defineLocale('ml', {
+    months : 'ജനുവരി_ഫെബ്രുവരി_മാർച്ച്_ഏപ്രിൽ_മേയ്_ജൂൺ_ജൂലൈ_ഓഗസ്റ്റ്_സെപ്റ്റംബർ_ഒക്ടോബർ_നവംബർ_ഡിസംബർ'.split('_'),
+    monthsShort : 'ജനു._ഫെബ്രു._മാർ._ഏപ്രി._മേയ്_ജൂൺ_ജൂലൈ._ഓഗ._സെപ്റ്റ._ഒക്ടോ._നവം._ഡിസം.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'ഞായറാഴ്ച_തിങ്കളാഴ്ച_ചൊവ്വാഴ്ച_ബുധനാഴ്ച_വ്യാഴാഴ്ച_വെള്ളിയാഴ്ച_ശനിയാഴ്ച'.split('_'),
+    weekdaysShort : 'ഞായർ_തിങ്കൾ_ചൊവ്വ_ബുധൻ_വ്യാഴം_വെള്ളി_ശനി'.split('_'),
+    weekdaysMin : 'ഞാ_തി_ചൊ_ബു_വ്യാ_വെ_ശ'.split('_'),
+    longDateFormat : {
+        LT : 'A h:mm -നു',
+        LTS : 'A h:mm:ss -നു',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, A h:mm -നു',
+        LLLL : 'dddd, D MMMM YYYY, A h:mm -നു'
+    },
+    calendar : {
+        sameDay : '[ഇന്ന്] LT',
+        nextDay : '[നാളെ] LT',
+        nextWeek : 'dddd, LT',
+        lastDay : '[ഇന്നലെ] LT',
+        lastWeek : '[കഴിഞ്ഞ] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s കഴിഞ്ഞ്',
+        past : '%s മുൻപ്',
+        s : 'അൽപ നിമിഷങ്ങൾ',
+        m : 'ഒരു മിനിറ്റ്',
+        mm : '%d മിനിറ്റ്',
+        h : 'ഒരു മണിക്കൂർ',
+        hh : '%d മണിക്കൂർ',
+        d : 'ഒരു ദിവസം',
+        dd : '%d ദിവസം',
+        M : 'ഒരു മാസം',
+        MM : '%d മാസം',
+        y : 'ഒരു വർഷം',
+        yy : '%d വർഷം'
+    },
+    meridiemParse: /രാത്രി|രാവിലെ|ഉച്ച കഴിഞ്ഞ്|വൈകുന്നേരം|രാത്രി/i,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if ((meridiem === 'രാത്രി' && hour >= 4) ||
+                meridiem === 'ഉച്ച കഴിഞ്ഞ്' ||
+                meridiem === 'വൈകുന്നേരം') {
+            return hour + 12;
+        } else {
+            return hour;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'രാത്രി';
+        } else if (hour < 12) {
+            return 'രാവിലെ';
+        } else if (hour < 17) {
+            return 'ഉച്ച കഴിഞ്ഞ്';
+        } else if (hour < 20) {
+            return 'വൈകുന്നേരം';
+        } else {
+            return 'രാത്രി';
+        }
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/mr.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/mr.js
new file mode 100644
index 0000000000000000000000000000000000000000..08cc3e02bee6e715024a2fbf45b3b2bde1da6032
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/mr.js
@@ -0,0 +1,150 @@
+//! moment.js locale configuration
+//! locale : Marathi [mr]
+//! author : Harshad Kale : https://github.com/kalehv
+//! author : Vivek Athalye : https://github.com/vnathalye
+
+import moment from '../moment';
+
+var symbolMap = {
+    '1': '१',
+    '2': '२',
+    '3': '३',
+    '4': '४',
+    '5': '५',
+    '6': '६',
+    '7': '७',
+    '8': '८',
+    '9': '९',
+    '0': '०'
+},
+numberMap = {
+    '१': '1',
+    '२': '2',
+    '३': '3',
+    '४': '4',
+    '५': '5',
+    '६': '6',
+    '७': '7',
+    '८': '8',
+    '९': '9',
+    '०': '0'
+};
+
+function relativeTimeMr(number, withoutSuffix, string, isFuture)
+{
+    var output = '';
+    if (withoutSuffix) {
+        switch (string) {
+            case 's': output = 'काही सेकंद'; break;
+            case 'm': output = 'एक मिनिट'; break;
+            case 'mm': output = '%d मिनिटे'; break;
+            case 'h': output = 'एक तास'; break;
+            case 'hh': output = '%d तास'; break;
+            case 'd': output = 'एक दिवस'; break;
+            case 'dd': output = '%d दिवस'; break;
+            case 'M': output = 'एक महिना'; break;
+            case 'MM': output = '%d महिने'; break;
+            case 'y': output = 'एक वर्ष'; break;
+            case 'yy': output = '%d वर्षे'; break;
+        }
+    }
+    else {
+        switch (string) {
+            case 's': output = 'काही सेकंदां'; break;
+            case 'm': output = 'एका मिनिटा'; break;
+            case 'mm': output = '%d मिनिटां'; break;
+            case 'h': output = 'एका तासा'; break;
+            case 'hh': output = '%d तासां'; break;
+            case 'd': output = 'एका दिवसा'; break;
+            case 'dd': output = '%d दिवसां'; break;
+            case 'M': output = 'एका महिन्या'; break;
+            case 'MM': output = '%d महिन्यां'; break;
+            case 'y': output = 'एका वर्षा'; break;
+            case 'yy': output = '%d वर्षां'; break;
+        }
+    }
+    return output.replace(/%d/i, number);
+}
+
+export default moment.defineLocale('mr', {
+    months : 'जानेवारी_फेब्रुवारी_मार्च_एप्रिल_मे_जून_जुलै_ऑगस्ट_सप्टेंबर_ऑक्टोबर_नोव्हेंबर_डिसेंबर'.split('_'),
+    monthsShort: 'जाने._फेब्रु._मार्च._एप्रि._मे._जून._जुलै._ऑग._सप्टें._ऑक्टो._नोव्हें._डिसें.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'रविवार_सोमवार_मंगळवार_बुधवार_गुरूवार_शुक्रवार_शनिवार'.split('_'),
+    weekdaysShort : 'रवि_सोम_मंगळ_बुध_गुरू_शुक्र_शनि'.split('_'),
+    weekdaysMin : 'र_सो_मं_बु_गु_शु_श'.split('_'),
+    longDateFormat : {
+        LT : 'A h:mm वाजता',
+        LTS : 'A h:mm:ss वाजता',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, A h:mm वाजता',
+        LLLL : 'dddd, D MMMM YYYY, A h:mm वाजता'
+    },
+    calendar : {
+        sameDay : '[आज] LT',
+        nextDay : '[उद्या] LT',
+        nextWeek : 'dddd, LT',
+        lastDay : '[काल] LT',
+        lastWeek: '[मागील] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future: '%sमध्ये',
+        past: '%sपूर्वी',
+        s: relativeTimeMr,
+        m: relativeTimeMr,
+        mm: relativeTimeMr,
+        h: relativeTimeMr,
+        hh: relativeTimeMr,
+        d: relativeTimeMr,
+        dd: relativeTimeMr,
+        M: relativeTimeMr,
+        MM: relativeTimeMr,
+        y: relativeTimeMr,
+        yy: relativeTimeMr
+    },
+    preparse: function (string) {
+        return string.replace(/[१२३४५६७८९०]/g, function (match) {
+            return numberMap[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap[match];
+        });
+    },
+    meridiemParse: /रात्री|सकाळी|दुपारी|सायंकाळी/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'रात्री') {
+            return hour < 4 ? hour : hour + 12;
+        } else if (meridiem === 'सकाळी') {
+            return hour;
+        } else if (meridiem === 'दुपारी') {
+            return hour >= 10 ? hour : hour + 12;
+        } else if (meridiem === 'सायंकाळी') {
+            return hour + 12;
+        }
+    },
+    meridiem: function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'रात्री';
+        } else if (hour < 10) {
+            return 'सकाळी';
+        } else if (hour < 17) {
+            return 'दुपारी';
+        } else if (hour < 20) {
+            return 'सायंकाळी';
+        } else {
+            return 'रात्री';
+        }
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ms-my.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ms-my.js
new file mode 100644
index 0000000000000000000000000000000000000000..f5ea96f467cb66fc6c4b89c17b872b42232daa3a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ms-my.js
@@ -0,0 +1,74 @@
+//! moment.js locale configuration
+//! locale : Malay [ms-my]
+//! note : DEPRECATED, the correct one is [ms]
+//! author : Weldan Jamili : https://github.com/weldan
+
+import moment from '../moment';
+
+export default moment.defineLocale('ms-my', {
+    months : 'Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember'.split('_'),
+    monthsShort : 'Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis'.split('_'),
+    weekdays : 'Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu'.split('_'),
+    weekdaysShort : 'Ahd_Isn_Sel_Rab_Kha_Jum_Sab'.split('_'),
+    weekdaysMin : 'Ah_Is_Sl_Rb_Km_Jm_Sb'.split('_'),
+    longDateFormat : {
+        LT : 'HH.mm',
+        LTS : 'HH.mm.ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY [pukul] HH.mm',
+        LLLL : 'dddd, D MMMM YYYY [pukul] HH.mm'
+    },
+    meridiemParse: /pagi|tengahari|petang|malam/,
+    meridiemHour: function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'pagi') {
+            return hour;
+        } else if (meridiem === 'tengahari') {
+            return hour >= 11 ? hour : hour + 12;
+        } else if (meridiem === 'petang' || meridiem === 'malam') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 11) {
+            return 'pagi';
+        } else if (hours < 15) {
+            return 'tengahari';
+        } else if (hours < 19) {
+            return 'petang';
+        } else {
+            return 'malam';
+        }
+    },
+    calendar : {
+        sameDay : '[Hari ini pukul] LT',
+        nextDay : '[Esok pukul] LT',
+        nextWeek : 'dddd [pukul] LT',
+        lastDay : '[Kelmarin pukul] LT',
+        lastWeek : 'dddd [lepas pukul] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'dalam %s',
+        past : '%s yang lepas',
+        s : 'beberapa saat',
+        m : 'seminit',
+        mm : '%d minit',
+        h : 'sejam',
+        hh : '%d jam',
+        d : 'sehari',
+        dd : '%d hari',
+        M : 'sebulan',
+        MM : '%d bulan',
+        y : 'setahun',
+        yy : '%d tahun'
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ms.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ms.js
new file mode 100644
index 0000000000000000000000000000000000000000..44c3e373010e85543c728180f4208dbf9df2343a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ms.js
@@ -0,0 +1,73 @@
+//! moment.js locale configuration
+//! locale : Malay [ms]
+//! author : Weldan Jamili : https://github.com/weldan
+
+import moment from '../moment';
+
+export default moment.defineLocale('ms', {
+    months : 'Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember'.split('_'),
+    monthsShort : 'Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis'.split('_'),
+    weekdays : 'Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu'.split('_'),
+    weekdaysShort : 'Ahd_Isn_Sel_Rab_Kha_Jum_Sab'.split('_'),
+    weekdaysMin : 'Ah_Is_Sl_Rb_Km_Jm_Sb'.split('_'),
+    longDateFormat : {
+        LT : 'HH.mm',
+        LTS : 'HH.mm.ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY [pukul] HH.mm',
+        LLLL : 'dddd, D MMMM YYYY [pukul] HH.mm'
+    },
+    meridiemParse: /pagi|tengahari|petang|malam/,
+    meridiemHour: function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'pagi') {
+            return hour;
+        } else if (meridiem === 'tengahari') {
+            return hour >= 11 ? hour : hour + 12;
+        } else if (meridiem === 'petang' || meridiem === 'malam') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 11) {
+            return 'pagi';
+        } else if (hours < 15) {
+            return 'tengahari';
+        } else if (hours < 19) {
+            return 'petang';
+        } else {
+            return 'malam';
+        }
+    },
+    calendar : {
+        sameDay : '[Hari ini pukul] LT',
+        nextDay : '[Esok pukul] LT',
+        nextWeek : 'dddd [pukul] LT',
+        lastDay : '[Kelmarin pukul] LT',
+        lastWeek : 'dddd [lepas pukul] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'dalam %s',
+        past : '%s yang lepas',
+        s : 'beberapa saat',
+        m : 'seminit',
+        mm : '%d minit',
+        h : 'sejam',
+        hh : '%d jam',
+        d : 'sehari',
+        dd : '%d hari',
+        M : 'sebulan',
+        MM : '%d bulan',
+        y : 'setahun',
+        yy : '%d tahun'
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/my.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/my.js
new file mode 100644
index 0000000000000000000000000000000000000000..401d06e911e80c14126248e3d658d4a3af3ca4b7
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/my.js
@@ -0,0 +1,86 @@
+//! moment.js locale configuration
+//! locale : Burmese [my]
+//! author : Squar team, mysquar.com
+//! author : David Rossellat : https://github.com/gholadr
+//! author : Tin Aung Lin : https://github.com/thanyawzinmin
+
+import moment from '../moment';
+
+var symbolMap = {
+    '1': '၁',
+    '2': '၂',
+    '3': '၃',
+    '4': '၄',
+    '5': '၅',
+    '6': '၆',
+    '7': '၇',
+    '8': '၈',
+    '9': '၉',
+    '0': '၀'
+}, numberMap = {
+    '၁': '1',
+    '၂': '2',
+    '၃': '3',
+    '၄': '4',
+    '၅': '5',
+    '၆': '6',
+    '၇': '7',
+    '၈': '8',
+    '၉': '9',
+    '၀': '0'
+};
+
+export default moment.defineLocale('my', {
+    months: 'ဇန်နဝါရီ_ဖေဖော်ဝါရီ_မတ်_ဧပြီ_မေ_ဇွန်_ဇူလိုင်_သြဂုတ်_စက်တင်ဘာ_အောက်တိုဘာ_နိုဝင်ဘာ_ဒီဇင်ဘာ'.split('_'),
+    monthsShort: 'ဇန်_ဖေ_မတ်_ပြီ_မေ_ဇွန်_လိုင်_သြ_စက်_အောက်_နို_ဒီ'.split('_'),
+    weekdays: 'တနင်္ဂနွေ_တနင်္လာ_အင်္ဂါ_ဗုဒ္ဓဟူး_ကြာသပတေး_သောကြာ_စနေ'.split('_'),
+    weekdaysShort: 'နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ'.split('_'),
+    weekdaysMin: 'နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ'.split('_'),
+
+    longDateFormat: {
+        LT: 'HH:mm',
+        LTS: 'HH:mm:ss',
+        L: 'DD/MM/YYYY',
+        LL: 'D MMMM YYYY',
+        LLL: 'D MMMM YYYY HH:mm',
+        LLLL: 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar: {
+        sameDay: '[ယနေ.] LT [မှာ]',
+        nextDay: '[မနက်ဖြန်] LT [မှာ]',
+        nextWeek: 'dddd LT [မှာ]',
+        lastDay: '[မနေ.က] LT [မှာ]',
+        lastWeek: '[ပြီးခဲ့သော] dddd LT [မှာ]',
+        sameElse: 'L'
+    },
+    relativeTime: {
+        future: 'လာမည့် %s မှာ',
+        past: 'လွန်ခဲ့သော %s က',
+        s: 'စက္ကန်.အနည်းငယ်',
+        m: 'တစ်မိနစ်',
+        mm: '%d မိနစ်',
+        h: 'တစ်နာရီ',
+        hh: '%d နာရီ',
+        d: 'တစ်ရက်',
+        dd: '%d ရက်',
+        M: 'တစ်လ',
+        MM: '%d လ',
+        y: 'တစ်နှစ်',
+        yy: '%d နှစ်'
+    },
+    preparse: function (string) {
+        return string.replace(/[၁၂၃၄၅၆၇၈၉၀]/g, function (match) {
+            return numberMap[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap[match];
+        });
+    },
+    week: {
+        dow: 1, // Monday is the first day of the week.
+        doy: 4 // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/nb.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/nb.js
new file mode 100644
index 0000000000000000000000000000000000000000..00744383c5b37bdc2ebfa405d61fc7b1b3583efe
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/nb.js
@@ -0,0 +1,54 @@
+//! moment.js locale configuration
+//! locale : Norwegian Bokmål [nb]
+//! authors : Espen Hovlandsdal : https://github.com/rexxars
+//!           Sigurd Gartmann : https://github.com/sigurdga
+
+import moment from '../moment';
+
+export default moment.defineLocale('nb', {
+    months : 'januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember'.split('_'),
+    monthsShort : 'jan._feb._mars_april_mai_juni_juli_aug._sep._okt._nov._des.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag'.split('_'),
+    weekdaysShort : 'sø._ma._ti._on._to._fr._lø.'.split('_'),
+    weekdaysMin : 'sø_ma_ti_on_to_fr_lø'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY [kl.] HH:mm',
+        LLLL : 'dddd D. MMMM YYYY [kl.] HH:mm'
+    },
+    calendar : {
+        sameDay: '[i dag kl.] LT',
+        nextDay: '[i morgen kl.] LT',
+        nextWeek: 'dddd [kl.] LT',
+        lastDay: '[i går kl.] LT',
+        lastWeek: '[forrige] dddd [kl.] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'om %s',
+        past : '%s siden',
+        s : 'noen sekunder',
+        m : 'ett minutt',
+        mm : '%d minutter',
+        h : 'en time',
+        hh : '%d timer',
+        d : 'en dag',
+        dd : '%d dager',
+        M : 'en måned',
+        MM : '%d måneder',
+        y : 'ett år',
+        yy : '%d år'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ne.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ne.js
new file mode 100644
index 0000000000000000000000000000000000000000..a82cb95b39e9f8b0a0067312b7591faa01d51825
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ne.js
@@ -0,0 +1,114 @@
+//! moment.js locale configuration
+//! locale : Nepalese [ne]
+//! author : suvash : https://github.com/suvash
+
+import moment from '../moment';
+
+var symbolMap = {
+    '1': '१',
+    '2': '२',
+    '3': '३',
+    '4': '४',
+    '5': '५',
+    '6': '६',
+    '7': '७',
+    '8': '८',
+    '9': '९',
+    '0': '०'
+},
+numberMap = {
+    '१': '1',
+    '२': '2',
+    '३': '3',
+    '४': '4',
+    '५': '5',
+    '६': '6',
+    '७': '7',
+    '८': '8',
+    '९': '9',
+    '०': '0'
+};
+
+export default moment.defineLocale('ne', {
+    months : 'जनवरी_फेब्रुवरी_मार्च_अप्रिल_मई_जुन_जुलाई_अगष्ट_सेप्टेम्बर_अक्टोबर_नोभेम्बर_डिसेम्बर'.split('_'),
+    monthsShort : 'जन._फेब्रु._मार्च_अप्रि._मई_जुन_जुलाई._अग._सेप्ट._अक्टो._नोभे._डिसे.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'आइतबार_सोमबार_मङ्गलबार_बुधबार_बिहिबार_शुक्रबार_शनिबार'.split('_'),
+    weekdaysShort : 'आइत._सोम._मङ्गल._बुध._बिहि._शुक्र._शनि.'.split('_'),
+    weekdaysMin : 'आ._सो._मं._बु._बि._शु._श.'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'Aको h:mm बजे',
+        LTS : 'Aको h:mm:ss बजे',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, Aको h:mm बजे',
+        LLLL : 'dddd, D MMMM YYYY, Aको h:mm बजे'
+    },
+    preparse: function (string) {
+        return string.replace(/[१२३४५६७८९०]/g, function (match) {
+            return numberMap[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap[match];
+        });
+    },
+    meridiemParse: /राति|बिहान|दिउँसो|साँझ/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'राति') {
+            return hour < 4 ? hour : hour + 12;
+        } else if (meridiem === 'बिहान') {
+            return hour;
+        } else if (meridiem === 'दिउँसो') {
+            return hour >= 10 ? hour : hour + 12;
+        } else if (meridiem === 'साँझ') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 3) {
+            return 'राति';
+        } else if (hour < 12) {
+            return 'बिहान';
+        } else if (hour < 16) {
+            return 'दिउँसो';
+        } else if (hour < 20) {
+            return 'साँझ';
+        } else {
+            return 'राति';
+        }
+    },
+    calendar : {
+        sameDay : '[आज] LT',
+        nextDay : '[भोलि] LT',
+        nextWeek : '[आउँदो] dddd[,] LT',
+        lastDay : '[हिजो] LT',
+        lastWeek : '[गएको] dddd[,] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%sमा',
+        past : '%s अगाडि',
+        s : 'केही क्षण',
+        m : 'एक मिनेट',
+        mm : '%d मिनेट',
+        h : 'एक घण्टा',
+        hh : '%d घण्टा',
+        d : 'एक दिन',
+        dd : '%d दिन',
+        M : 'एक महिना',
+        MM : '%d महिना',
+        y : 'एक बर्ष',
+        yy : '%d बर्ष'
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/nl-be.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/nl-be.js
new file mode 100644
index 0000000000000000000000000000000000000000..159eee3871fa77196d799c418e68b4ee8387d081
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/nl-be.js
@@ -0,0 +1,77 @@
+//! moment.js locale configuration
+//! locale : Dutch (Belgium) [nl-be]
+//! author : Joris Röling : https://github.com/jorisroling
+//! author : Jacob Middag : https://github.com/middagj
+
+import moment from '../moment';
+
+var monthsShortWithDots = 'jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.'.split('_'),
+    monthsShortWithoutDots = 'jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec'.split('_');
+
+var monthsParse = [/^jan/i, /^feb/i, /^maart|mrt.?$/i, /^apr/i, /^mei$/i, /^jun[i.]?$/i, /^jul[i.]?$/i, /^aug/i, /^sep/i, /^okt/i, /^nov/i, /^dec/i];
+var monthsRegex = /^(januari|februari|maart|april|mei|april|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i;
+
+export default moment.defineLocale('nl-be', {
+    months : 'januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december'.split('_'),
+    monthsShort : function (m, format) {
+        if (/-MMM-/.test(format)) {
+            return monthsShortWithoutDots[m.month()];
+        } else {
+            return monthsShortWithDots[m.month()];
+        }
+    },
+
+    monthsRegex: monthsRegex,
+    monthsShortRegex: monthsRegex,
+    monthsStrictRegex: /^(januari|februari|maart|mei|ju[nl]i|april|augustus|september|oktober|november|december)/i,
+    monthsShortStrictRegex: /^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i,
+
+    monthsParse : monthsParse,
+    longMonthsParse : monthsParse,
+    shortMonthsParse : monthsParse,
+
+    weekdays : 'zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag'.split('_'),
+    weekdaysShort : 'zo._ma._di._wo._do._vr._za.'.split('_'),
+    weekdaysMin : 'Zo_Ma_Di_Wo_Do_Vr_Za'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[vandaag om] LT',
+        nextDay: '[morgen om] LT',
+        nextWeek: 'dddd [om] LT',
+        lastDay: '[gisteren om] LT',
+        lastWeek: '[afgelopen] dddd [om] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'over %s',
+        past : '%s geleden',
+        s : 'een paar seconden',
+        m : 'één minuut',
+        mm : '%d minuten',
+        h : 'één uur',
+        hh : '%d uur',
+        d : 'één dag',
+        dd : '%d dagen',
+        M : 'één maand',
+        MM : '%d maanden',
+        y : 'één jaar',
+        yy : '%d jaar'
+    },
+    ordinalParse: /\d{1,2}(ste|de)/,
+    ordinal : function (number) {
+        return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de');
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/nl.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/nl.js
new file mode 100644
index 0000000000000000000000000000000000000000..0988cfe6a9ec9d749fe270376f0ee27b6e6bed8e
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/nl.js
@@ -0,0 +1,77 @@
+//! moment.js locale configuration
+//! locale : Dutch [nl]
+//! author : Joris Röling : https://github.com/jorisroling
+//! author : Jacob Middag : https://github.com/middagj
+
+import moment from '../moment';
+
+var monthsShortWithDots = 'jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.'.split('_'),
+    monthsShortWithoutDots = 'jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec'.split('_');
+
+var monthsParse = [/^jan/i, /^feb/i, /^maart|mrt.?$/i, /^apr/i, /^mei$/i, /^jun[i.]?$/i, /^jul[i.]?$/i, /^aug/i, /^sep/i, /^okt/i, /^nov/i, /^dec/i];
+var monthsRegex = /^(januari|februari|maart|april|mei|april|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i;
+
+export default moment.defineLocale('nl', {
+    months : 'januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december'.split('_'),
+    monthsShort : function (m, format) {
+        if (/-MMM-/.test(format)) {
+            return monthsShortWithoutDots[m.month()];
+        } else {
+            return monthsShortWithDots[m.month()];
+        }
+    },
+
+    monthsRegex: monthsRegex,
+    monthsShortRegex: monthsRegex,
+    monthsStrictRegex: /^(januari|februari|maart|mei|ju[nl]i|april|augustus|september|oktober|november|december)/i,
+    monthsShortStrictRegex: /^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i,
+
+    monthsParse : monthsParse,
+    longMonthsParse : monthsParse,
+    shortMonthsParse : monthsParse,
+
+    weekdays : 'zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag'.split('_'),
+    weekdaysShort : 'zo._ma._di._wo._do._vr._za.'.split('_'),
+    weekdaysMin : 'Zo_Ma_Di_Wo_Do_Vr_Za'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD-MM-YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[vandaag om] LT',
+        nextDay: '[morgen om] LT',
+        nextWeek: 'dddd [om] LT',
+        lastDay: '[gisteren om] LT',
+        lastWeek: '[afgelopen] dddd [om] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'over %s',
+        past : '%s geleden',
+        s : 'een paar seconden',
+        m : 'één minuut',
+        mm : '%d minuten',
+        h : 'één uur',
+        hh : '%d uur',
+        d : 'één dag',
+        dd : '%d dagen',
+        M : 'één maand',
+        MM : '%d maanden',
+        y : 'één jaar',
+        yy : '%d jaar'
+    },
+    ordinalParse: /\d{1,2}(ste|de)/,
+    ordinal : function (number) {
+        return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de');
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/nn.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/nn.js
new file mode 100644
index 0000000000000000000000000000000000000000..13ecbca43aa6b118b1a093f79e1a58dda7fa65e4
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/nn.js
@@ -0,0 +1,51 @@
+//! moment.js locale configuration
+//! locale : Nynorsk [nn]
+//! author : https://github.com/mechuwind
+
+import moment from '../moment';
+
+export default moment.defineLocale('nn', {
+    months : 'januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember'.split('_'),
+    monthsShort : 'jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_'),
+    weekdays : 'sundag_måndag_tysdag_onsdag_torsdag_fredag_laurdag'.split('_'),
+    weekdaysShort : 'sun_mån_tys_ons_tor_fre_lau'.split('_'),
+    weekdaysMin : 'su_må_ty_on_to_fr_lø'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY [kl.] H:mm',
+        LLLL : 'dddd D. MMMM YYYY [kl.] HH:mm'
+    },
+    calendar : {
+        sameDay: '[I dag klokka] LT',
+        nextDay: '[I morgon klokka] LT',
+        nextWeek: 'dddd [klokka] LT',
+        lastDay: '[I går klokka] LT',
+        lastWeek: '[Føregåande] dddd [klokka] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'om %s',
+        past : '%s sidan',
+        s : 'nokre sekund',
+        m : 'eit minutt',
+        mm : '%d minutt',
+        h : 'ein time',
+        hh : '%d timar',
+        d : 'ein dag',
+        dd : '%d dagar',
+        M : 'ein månad',
+        MM : '%d månader',
+        y : 'eit år',
+        yy : '%d år'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/pa-in.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/pa-in.js
new file mode 100644
index 0000000000000000000000000000000000000000..78da521659b1f1655aae70e1bdd5d700011a8b7c
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/pa-in.js
@@ -0,0 +1,115 @@
+//! moment.js locale configuration
+//! locale : Punjabi (India) [pa-in]
+//! author : Harpreet Singh : https://github.com/harpreetkhalsagtbit
+
+import moment from '../moment';
+
+var symbolMap = {
+    '1': 'à©§',
+    '2': '੨',
+    '3': 'à©©',
+    '4': '੪',
+    '5': 'à©«',
+    '6': '੬',
+    '7': 'à©­',
+    '8': 'à©®',
+    '9': '੯',
+    '0': '੦'
+},
+numberMap = {
+    'à©§': '1',
+    '੨': '2',
+    'à©©': '3',
+    '੪': '4',
+    'à©«': '5',
+    '੬': '6',
+    'à©­': '7',
+    'à©®': '8',
+    '੯': '9',
+    '੦': '0'
+};
+
+export default moment.defineLocale('pa-in', {
+    // There are months name as per Nanakshahi Calender but they are not used as rigidly in modern Punjabi.
+    months : 'ਜਨਵਰੀ_ਫ਼ਰਵਰੀ_ਮਾਰਚ_ਅਪ੍ਰੈਲ_ਮਈ_ਜੂਨ_ਜੁਲਾਈ_ਅਗਸਤ_ਸਤੰਬਰ_ਅਕਤੂਬਰ_ਨਵੰਬਰ_ਦਸੰਬਰ'.split('_'),
+    monthsShort : 'ਜਨਵਰੀ_ਫ਼ਰਵਰੀ_ਮਾਰਚ_ਅਪ੍ਰੈਲ_ਮਈ_ਜੂਨ_ਜੁਲਾਈ_ਅਗਸਤ_ਸਤੰਬਰ_ਅਕਤੂਬਰ_ਨਵੰਬਰ_ਦਸੰਬਰ'.split('_'),
+    weekdays : 'ਐਤਵਾਰ_ਸੋਮਵਾਰ_ਮੰਗਲਵਾਰ_ਬੁਧਵਾਰ_ਵੀਰਵਾਰ_ਸ਼ੁੱਕਰਵਾਰ_ਸ਼ਨੀਚਰਵਾਰ'.split('_'),
+    weekdaysShort : 'ਐਤ_ਸੋਮ_ਮੰਗਲ_ਬੁਧ_ਵੀਰ_ਸ਼ੁਕਰ_ਸ਼ਨੀ'.split('_'),
+    weekdaysMin : 'ਐਤ_ਸੋਮ_ਮੰਗਲ_ਬੁਧ_ਵੀਰ_ਸ਼ੁਕਰ_ਸ਼ਨੀ'.split('_'),
+    longDateFormat : {
+        LT : 'A h:mm ਵਜੇ',
+        LTS : 'A h:mm:ss ਵਜੇ',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, A h:mm ਵਜੇ',
+        LLLL : 'dddd, D MMMM YYYY, A h:mm ਵਜੇ'
+    },
+    calendar : {
+        sameDay : '[ਅਜ] LT',
+        nextDay : '[ਕਲ] LT',
+        nextWeek : 'dddd, LT',
+        lastDay : '[ਕਲ] LT',
+        lastWeek : '[ਪਿਛਲੇ] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s ਵਿੱਚ',
+        past : '%s ਪਿਛਲੇ',
+        s : 'ਕੁਝ ਸਕਿੰਟ',
+        m : 'ਇਕ ਮਿੰਟ',
+        mm : '%d ਮਿੰਟ',
+        h : 'ਇੱਕ ਘੰਟਾ',
+        hh : '%d ਘੰਟੇ',
+        d : 'ਇੱਕ ਦਿਨ',
+        dd : '%d ਦਿਨ',
+        M : 'ਇੱਕ ਮਹੀਨਾ',
+        MM : '%d ਮਹੀਨੇ',
+        y : 'ਇੱਕ ਸਾਲ',
+        yy : '%d ਸਾਲ'
+    },
+    preparse: function (string) {
+        return string.replace(/[੧੨੩੪੫੬੭੮੯੦]/g, function (match) {
+            return numberMap[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap[match];
+        });
+    },
+    // Punjabi notation for meridiems are quite fuzzy in practice. While there exists
+    // a rigid notion of a 'Pahar' it is not used as rigidly in modern Punjabi.
+    meridiemParse: /ਰਾਤ|ਸਵੇਰ|ਦੁਪਹਿਰ|ਸ਼ਾਮ/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'ਰਾਤ') {
+            return hour < 4 ? hour : hour + 12;
+        } else if (meridiem === 'ਸਵੇਰ') {
+            return hour;
+        } else if (meridiem === 'ਦੁਪਹਿਰ') {
+            return hour >= 10 ? hour : hour + 12;
+        } else if (meridiem === 'ਸ਼ਾਮ') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'ਰਾਤ';
+        } else if (hour < 10) {
+            return 'ਸਵੇਰ';
+        } else if (hour < 17) {
+            return 'ਦੁਪਹਿਰ';
+        } else if (hour < 20) {
+            return 'ਸ਼ਾਮ';
+        } else {
+            return 'ਰਾਤ';
+        }
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/pl.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/pl.js
new file mode 100644
index 0000000000000000000000000000000000000000..9934a5e6873eb6ba29e2b5baba28d3ce24ebc4a8
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/pl.js
@@ -0,0 +1,95 @@
+//! moment.js locale configuration
+//! locale : Polish [pl]
+//! author : Rafal Hirsz : https://github.com/evoL
+
+import moment from '../moment';
+
+var monthsNominative = 'styczeń_luty_marzec_kwiecień_maj_czerwiec_lipiec_sierpień_wrzesień_październik_listopad_grudzień'.split('_'),
+    monthsSubjective = 'stycznia_lutego_marca_kwietnia_maja_czerwca_lipca_sierpnia_września_października_listopada_grudnia'.split('_');
+function plural(n) {
+    return (n % 10 < 5) && (n % 10 > 1) && ((~~(n / 10) % 10) !== 1);
+}
+function translate(number, withoutSuffix, key) {
+    var result = number + ' ';
+    switch (key) {
+        case 'm':
+            return withoutSuffix ? 'minuta' : 'minutÄ™';
+        case 'mm':
+            return result + (plural(number) ? 'minuty' : 'minut');
+        case 'h':
+            return withoutSuffix  ? 'godzina'  : 'godzinÄ™';
+        case 'hh':
+            return result + (plural(number) ? 'godziny' : 'godzin');
+        case 'MM':
+            return result + (plural(number) ? 'miesiące' : 'miesięcy');
+        case 'yy':
+            return result + (plural(number) ? 'lata' : 'lat');
+    }
+}
+
+export default moment.defineLocale('pl', {
+    months : function (momentToFormat, format) {
+        if (format === '') {
+            // Hack: if format empty we know this is used to generate
+            // RegExp by moment. Give then back both valid forms of months
+            // in RegExp ready format.
+            return '(' + monthsSubjective[momentToFormat.month()] + '|' + monthsNominative[momentToFormat.month()] + ')';
+        } else if (/D MMMM/.test(format)) {
+            return monthsSubjective[momentToFormat.month()];
+        } else {
+            return monthsNominative[momentToFormat.month()];
+        }
+    },
+    monthsShort : 'sty_lut_mar_kwi_maj_cze_lip_sie_wrz_paź_lis_gru'.split('_'),
+    weekdays : 'niedziela_poniedziałek_wtorek_środa_czwartek_piątek_sobota'.split('_'),
+    weekdaysShort : 'ndz_pon_wt_śr_czw_pt_sob'.split('_'),
+    weekdaysMin : 'Nd_Pn_Wt_Åšr_Cz_Pt_So'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[DziÅ› o] LT',
+        nextDay: '[Jutro o] LT',
+        nextWeek: '[W] dddd [o] LT',
+        lastDay: '[Wczoraj o] LT',
+        lastWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[W zeszłą niedzielę o] LT';
+                case 3:
+                    return '[W zeszłą środę o] LT';
+                case 6:
+                    return '[W zeszłą sobotę o] LT';
+                default:
+                    return '[W zeszły] dddd [o] LT';
+            }
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'za %s',
+        past : '%s temu',
+        s : 'kilka sekund',
+        m : translate,
+        mm : translate,
+        h : translate,
+        hh : translate,
+        d : '1 dzień',
+        dd : '%d dni',
+        M : 'miesiÄ…c',
+        MM : translate,
+        y : 'rok',
+        yy : translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/pt-br.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/pt-br.js
new file mode 100644
index 0000000000000000000000000000000000000000..6e42d1ef1235dbc13c5601e98fd6a9ba2d601b85
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/pt-br.js
@@ -0,0 +1,52 @@
+//! moment.js locale configuration
+//! locale : Portuguese (Brazil) [pt-br]
+//! author : Caio Ribeiro Pereira : https://github.com/caio-ribeiro-pereira
+
+import moment from '../moment';
+
+export default moment.defineLocale('pt-br', {
+    months : 'Janeiro_Fevereiro_Março_Abril_Maio_Junho_Julho_Agosto_Setembro_Outubro_Novembro_Dezembro'.split('_'),
+    monthsShort : 'Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez'.split('_'),
+    weekdays : 'Domingo_Segunda-feira_Terça-feira_Quarta-feira_Quinta-feira_Sexta-feira_Sábado'.split('_'),
+    weekdaysShort : 'Dom_Seg_Ter_Qua_Qui_Sex_Sáb'.split('_'),
+    weekdaysMin : 'Dom_2ª_3ª_4ª_5ª_6ª_Sáb'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D [de] MMMM [de] YYYY',
+        LLL : 'D [de] MMMM [de] YYYY [às] HH:mm',
+        LLLL : 'dddd, D [de] MMMM [de] YYYY [às] HH:mm'
+    },
+    calendar : {
+        sameDay: '[Hoje às] LT',
+        nextDay: '[Amanhã às] LT',
+        nextWeek: 'dddd [às] LT',
+        lastDay: '[Ontem às] LT',
+        lastWeek: function () {
+            return (this.day() === 0 || this.day() === 6) ?
+                '[Último] dddd [às] LT' : // Saturday + Sunday
+                '[Última] dddd [às] LT'; // Monday - Friday
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'em %s',
+        past : '%s atrás',
+        s : 'poucos segundos',
+        m : 'um minuto',
+        mm : '%d minutos',
+        h : 'uma hora',
+        hh : '%d horas',
+        d : 'um dia',
+        dd : '%d dias',
+        M : 'um mês',
+        MM : '%d meses',
+        y : 'um ano',
+        yy : '%d anos'
+    },
+    ordinalParse: /\d{1,2}º/,
+    ordinal : '%dº'
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/pt.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/pt.js
new file mode 100644
index 0000000000000000000000000000000000000000..b6ab969c86fe50c6340fcc6a2db1ae5a2f472816
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/pt.js
@@ -0,0 +1,56 @@
+//! moment.js locale configuration
+//! locale : Portuguese [pt]
+//! author : Jefferson : https://github.com/jalex79
+
+import moment from '../moment';
+
+export default moment.defineLocale('pt', {
+    months : 'Janeiro_Fevereiro_Março_Abril_Maio_Junho_Julho_Agosto_Setembro_Outubro_Novembro_Dezembro'.split('_'),
+    monthsShort : 'Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez'.split('_'),
+    weekdays : 'Domingo_Segunda-Feira_Terça-Feira_Quarta-Feira_Quinta-Feira_Sexta-Feira_Sábado'.split('_'),
+    weekdaysShort : 'Dom_Seg_Ter_Qua_Qui_Sex_Sáb'.split('_'),
+    weekdaysMin : 'Dom_2ª_3ª_4ª_5ª_6ª_Sáb'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D [de] MMMM [de] YYYY',
+        LLL : 'D [de] MMMM [de] YYYY HH:mm',
+        LLLL : 'dddd, D [de] MMMM [de] YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Hoje às] LT',
+        nextDay: '[Amanhã às] LT',
+        nextWeek: 'dddd [às] LT',
+        lastDay: '[Ontem às] LT',
+        lastWeek: function () {
+            return (this.day() === 0 || this.day() === 6) ?
+                '[Último] dddd [às] LT' : // Saturday + Sunday
+                '[Última] dddd [às] LT'; // Monday - Friday
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'em %s',
+        past : 'há %s',
+        s : 'segundos',
+        m : 'um minuto',
+        mm : '%d minutos',
+        h : 'uma hora',
+        hh : '%d horas',
+        d : 'um dia',
+        dd : '%d dias',
+        M : 'um mês',
+        MM : '%d meses',
+        y : 'um ano',
+        yy : '%d anos'
+    },
+    ordinalParse: /\d{1,2}º/,
+    ordinal : '%dº',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ro.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ro.js
new file mode 100644
index 0000000000000000000000000000000000000000..444eebad7b0a778a9630310384bf95386218a39a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ro.js
@@ -0,0 +1,66 @@
+//! moment.js locale configuration
+//! locale : Romanian [ro]
+//! author : Vlad Gurdiga : https://github.com/gurdiga
+//! author : Valentin Agachi : https://github.com/avaly
+
+import moment from '../moment';
+
+function relativeTimeWithPlural(number, withoutSuffix, key) {
+    var format = {
+            'mm': 'minute',
+            'hh': 'ore',
+            'dd': 'zile',
+            'MM': 'luni',
+            'yy': 'ani'
+        },
+        separator = ' ';
+    if (number % 100 >= 20 || (number >= 100 && number % 100 === 0)) {
+        separator = ' de ';
+    }
+    return number + separator + format[key];
+}
+
+export default moment.defineLocale('ro', {
+    months : 'ianuarie_februarie_martie_aprilie_mai_iunie_iulie_august_septembrie_octombrie_noiembrie_decembrie'.split('_'),
+    monthsShort : 'ian._febr._mart._apr._mai_iun._iul._aug._sept._oct._nov._dec.'.split('_'),
+    monthsParseExact: true,
+    weekdays : 'duminică_luni_marți_miercuri_joi_vineri_sâmbătă'.split('_'),
+    weekdaysShort : 'Dum_Lun_Mar_Mie_Joi_Vin_Sâm'.split('_'),
+    weekdaysMin : 'Du_Lu_Ma_Mi_Jo_Vi_Sâ'.split('_'),
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY H:mm',
+        LLLL : 'dddd, D MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay: '[azi la] LT',
+        nextDay: '[mâine la] LT',
+        nextWeek: 'dddd [la] LT',
+        lastDay: '[ieri la] LT',
+        lastWeek: '[fosta] dddd [la] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'peste %s',
+        past : '%s în urmă',
+        s : 'câteva secunde',
+        m : 'un minut',
+        mm : relativeTimeWithPlural,
+        h : 'o oră',
+        hh : relativeTimeWithPlural,
+        d : 'o zi',
+        dd : relativeTimeWithPlural,
+        M : 'o lună',
+        MM : relativeTimeWithPlural,
+        y : 'un an',
+        yy : relativeTimeWithPlural
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ru.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ru.js
new file mode 100644
index 0000000000000000000000000000000000000000..2f10d6749c1b6bc0d90a16e3ba44ee88d31277ba
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ru.js
@@ -0,0 +1,173 @@
+//! moment.js locale configuration
+//! locale : Russian [ru]
+//! author : Viktorminator : https://github.com/Viktorminator
+//! Author : Menelion Elensúle : https://github.com/Oire
+//! author : Коренберг Марк : https://github.com/socketpair
+
+import moment from '../moment';
+
+function plural(word, num) {
+    var forms = word.split('_');
+    return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]);
+}
+function relativeTimeWithPlural(number, withoutSuffix, key) {
+    var format = {
+        'mm': withoutSuffix ? 'минута_минуты_минут' : 'минуту_минуты_минут',
+        'hh': 'час_часа_часов',
+        'dd': 'день_дня_дней',
+        'MM': 'месяц_месяца_месяцев',
+        'yy': 'год_года_лет'
+    };
+    if (key === 'm') {
+        return withoutSuffix ? 'минута' : 'минуту';
+    }
+    else {
+        return number + ' ' + plural(format[key], +number);
+    }
+}
+var monthsParse = [/^янв/i, /^фев/i, /^мар/i, /^апр/i, /^ма[йя]/i, /^июн/i, /^июл/i, /^авг/i, /^сен/i, /^окт/i, /^ноя/i, /^дек/i];
+
+// http://new.gramota.ru/spravka/rules/139-prop : § 103
+// Сокращения месяцев: http://new.gramota.ru/spravka/buro/search-answer?s=242637
+// CLDR data:          http://www.unicode.org/cldr/charts/28/summary/ru.html#1753
+export default moment.defineLocale('ru', {
+    months : {
+        format: 'января_февраля_марта_апреля_мая_июня_июля_августа_сентября_октября_ноября_декабря'.split('_'),
+        standalone: 'январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь'.split('_')
+    },
+    monthsShort : {
+        // по CLDR именно "июл." и "июн.", но какой смысл менять букву на точку ?
+        format: 'янв._февр._мар._апр._мая_июня_июля_авг._сент._окт._нояб._дек.'.split('_'),
+        standalone: 'янв._февр._март_апр._май_июнь_июль_авг._сент._окт._нояб._дек.'.split('_')
+    },
+    weekdays : {
+        standalone: 'воскресенье_понедельник_вторник_среда_четверг_пятница_суббота'.split('_'),
+        format: 'воскресенье_понедельник_вторник_среду_четверг_пятницу_субботу'.split('_'),
+        isFormat: /\[ ?[Вв] ?(?:прошлую|следующую|эту)? ?\] ?dddd/
+    },
+    weekdaysShort : 'вс_пн_вт_ср_чт_пт_сб'.split('_'),
+    weekdaysMin : 'вс_пн_вт_ср_чт_пт_сб'.split('_'),
+    monthsParse : monthsParse,
+    longMonthsParse : monthsParse,
+    shortMonthsParse : monthsParse,
+
+    // полные названия с падежами, по три буквы, для некоторых, по 4 буквы, сокращения с точкой и без точки
+    monthsRegex: /^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i,
+
+    // копия предыдущего
+    monthsShortRegex: /^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i,
+
+    // полные названия с падежами
+    monthsStrictRegex: /^(январ[яь]|феврал[яь]|марта?|апрел[яь]|ма[яй]|июн[яь]|июл[яь]|августа?|сентябр[яь]|октябр[яь]|ноябр[яь]|декабр[яь])/i,
+
+    // Выражение, которое соотвествует только сокращённым формам
+    monthsShortStrictRegex: /^(янв\.|февр?\.|мар[т.]|апр\.|ма[яй]|июн[ья.]|июл[ья.]|авг\.|сент?\.|окт\.|нояб?\.|дек\.)/i,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY г.',
+        LLL : 'D MMMM YYYY г., HH:mm',
+        LLLL : 'dddd, D MMMM YYYY г., HH:mm'
+    },
+    calendar : {
+        sameDay: '[Сегодня в] LT',
+        nextDay: '[Завтра в] LT',
+        lastDay: '[Вчера в] LT',
+        nextWeek: function (now) {
+            if (now.week() !== this.week()) {
+                switch (this.day()) {
+                    case 0:
+                        return '[В следующее] dddd [в] LT';
+                    case 1:
+                    case 2:
+                    case 4:
+                        return '[В следующий] dddd [в] LT';
+                    case 3:
+                    case 5:
+                    case 6:
+                        return '[В следующую] dddd [в] LT';
+                }
+            } else {
+                if (this.day() === 2) {
+                    return '[Во] dddd [в] LT';
+                } else {
+                    return '[В] dddd [в] LT';
+                }
+            }
+        },
+        lastWeek: function (now) {
+            if (now.week() !== this.week()) {
+                switch (this.day()) {
+                    case 0:
+                        return '[В прошлое] dddd [в] LT';
+                    case 1:
+                    case 2:
+                    case 4:
+                        return '[В прошлый] dddd [в] LT';
+                    case 3:
+                    case 5:
+                    case 6:
+                        return '[В прошлую] dddd [в] LT';
+                }
+            } else {
+                if (this.day() === 2) {
+                    return '[Во] dddd [в] LT';
+                } else {
+                    return '[В] dddd [в] LT';
+                }
+            }
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'через %s',
+        past : '%s назад',
+        s : 'несколько секунд',
+        m : relativeTimeWithPlural,
+        mm : relativeTimeWithPlural,
+        h : 'час',
+        hh : relativeTimeWithPlural,
+        d : 'день',
+        dd : relativeTimeWithPlural,
+        M : 'месяц',
+        MM : relativeTimeWithPlural,
+        y : 'год',
+        yy : relativeTimeWithPlural
+    },
+    meridiemParse: /ночи|утра|дня|вечера/i,
+    isPM : function (input) {
+        return /^(дня|вечера)$/.test(input);
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'ночи';
+        } else if (hour < 12) {
+            return 'утра';
+        } else if (hour < 17) {
+            return 'дня';
+        } else {
+            return 'вечера';
+        }
+    },
+    ordinalParse: /\d{1,2}-(й|го|я)/,
+    ordinal: function (number, period) {
+        switch (period) {
+            case 'M':
+            case 'd':
+            case 'DDD':
+                return number + '-й';
+            case 'D':
+                return number + '-го';
+            case 'w':
+            case 'W':
+                return number + '-я';
+            default:
+                return number;
+        }
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/se.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/se.js
new file mode 100644
index 0000000000000000000000000000000000000000..af6a01c31d663e7fdf2ab027e3098be1972204e9
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/se.js
@@ -0,0 +1,51 @@
+//! moment.js locale configuration
+//! locale : Northern Sami [se]
+//! authors : BÃ¥rd Rolstad Henriksen : https://github.com/karamell
+
+
+import moment from '../moment';
+
+export default moment.defineLocale('se', {
+    months : 'ođđajagemánnu_guovvamánnu_njukčamánnu_cuoŋománnu_miessemánnu_geassemánnu_suoidnemánnu_borgemánnu_čakčamánnu_golggotmánnu_skábmamánnu_juovlamánnu'.split('_'),
+    monthsShort : 'ođđj_guov_njuk_cuo_mies_geas_suoi_borg_čakč_golg_skáb_juov'.split('_'),
+    weekdays : 'sotnabeaivi_vuossárga_maŋŋebárga_gaskavahkku_duorastat_bearjadat_lávvardat'.split('_'),
+    weekdaysShort : 'sotn_vuos_maŋ_gask_duor_bear_láv'.split('_'),
+    weekdaysMin : 's_v_m_g_d_b_L'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'MMMM D. [b.] YYYY',
+        LLL : 'MMMM D. [b.] YYYY [ti.] HH:mm',
+        LLLL : 'dddd, MMMM D. [b.] YYYY [ti.] HH:mm'
+    },
+    calendar : {
+        sameDay: '[otne ti] LT',
+        nextDay: '[ihttin ti] LT',
+        nextWeek: 'dddd [ti] LT',
+        lastDay: '[ikte ti] LT',
+        lastWeek: '[ovddit] dddd [ti] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : '%s geažes',
+        past : 'maŋit %s',
+        s : 'moadde sekunddat',
+        m : 'okta minuhta',
+        mm : '%d minuhtat',
+        h : 'okta diimmu',
+        hh : '%d diimmut',
+        d : 'okta beaivi',
+        dd : '%d beaivvit',
+        M : 'okta mánnu',
+        MM : '%d mánut',
+        y : 'okta jahki',
+        yy : '%d jagit'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/si.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/si.js
new file mode 100644
index 0000000000000000000000000000000000000000..0cc2b78e5e22b5dfb492d26c3f15f50262da3b6c
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/si.js
@@ -0,0 +1,61 @@
+//! moment.js locale configuration
+//! locale : Sinhalese [si]
+//! author : Sampath Sitinamaluwa : https://github.com/sampathsris
+
+import moment from '../moment';
+
+/*jshint -W100*/
+export default moment.defineLocale('si', {
+    months : 'ජනවාරි_පෙබරවාරි_මාර්තු_අප්‍රේල්_මැයි_ජූනි_ජූලි_අගෝස්තු_සැප්තැම්බර්_ඔක්තෝබර්_නොවැම්බර්_දෙසැම්බර්'.split('_'),
+    monthsShort : 'ජන_පෙබ_මාර්_අප්_මැයි_ජූනි_ජූලි_අගෝ_සැප්_ඔක්_නොවැ_දෙසැ'.split('_'),
+    weekdays : 'ඉරිදා_සඳුදා_අඟහරුවාදා_බදාදා_බ්‍රහස්පතින්දා_සිකුරාදා_සෙනසුරාදා'.split('_'),
+    weekdaysShort : 'ඉරි_සඳු_අඟ_බදා_බ්‍රහ_සිකු_සෙන'.split('_'),
+    weekdaysMin : 'ඉ_ස_අ_බ_බ්‍ර_සි_සෙ'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'a h:mm',
+        LTS : 'a h:mm:ss',
+        L : 'YYYY/MM/DD',
+        LL : 'YYYY MMMM D',
+        LLL : 'YYYY MMMM D, a h:mm',
+        LLLL : 'YYYY MMMM D [වැනි] dddd, a h:mm:ss'
+    },
+    calendar : {
+        sameDay : '[අද] LT[ට]',
+        nextDay : '[හෙට] LT[ට]',
+        nextWeek : 'dddd LT[à¶§]',
+        lastDay : '[ඊයේ] LT[ට]',
+        lastWeek : '[පසුගිය] dddd LT[ට]',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%sකින්',
+        past : '%sකට පෙර',
+        s : 'තත්පර කිහිපය',
+        m : 'මිනිත්තුව',
+        mm : 'මිනිත්තු %d',
+        h : 'පැය',
+        hh : 'පැය %d',
+        d : 'දිනය',
+        dd : 'දින %d',
+        M : 'මාසය',
+        MM : 'මාස %d',
+        y : 'වසර',
+        yy : 'වසර %d'
+    },
+    ordinalParse: /\d{1,2} වැනි/,
+    ordinal : function (number) {
+        return number + ' වැනි';
+    },
+    meridiemParse : /පෙර වරු|පස් වරු|පෙ.ව|ප.ව./,
+    isPM : function (input) {
+        return input === 'ප.ව.' || input === 'පස් වරු';
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours > 11) {
+            return isLower ? 'ප.ව.' : 'පස් වරු';
+        } else {
+            return isLower ? 'පෙ.ව.' : 'පෙර වරු';
+        }
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/sk.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/sk.js
new file mode 100644
index 0000000000000000000000000000000000000000..0d5f0e04a5ff3a2fe666ffb7da7ce51ad4e8ece1
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/sk.js
@@ -0,0 +1,141 @@
+//! moment.js locale configuration
+//! locale : Slovak [sk]
+//! author : Martin Minka : https://github.com/k2s
+//! based on work of petrbela : https://github.com/petrbela
+
+import moment from '../moment';
+
+var months = 'január_február_marec_apríl_máj_jún_júl_august_september_október_november_december'.split('_'),
+    monthsShort = 'jan_feb_mar_apr_máj_jún_júl_aug_sep_okt_nov_dec'.split('_');
+function plural(n) {
+    return (n > 1) && (n < 5);
+}
+function translate(number, withoutSuffix, key, isFuture) {
+    var result = number + ' ';
+    switch (key) {
+        case 's':  // a few seconds / in a few seconds / a few seconds ago
+            return (withoutSuffix || isFuture) ? 'pár sekúnd' : 'pár sekundami';
+        case 'm':  // a minute / in a minute / a minute ago
+            return withoutSuffix ? 'minúta' : (isFuture ? 'minútu' : 'minútou');
+        case 'mm': // 9 minutes / in 9 minutes / 9 minutes ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural(number) ? 'minúty' : 'minút');
+            } else {
+                return result + 'minútami';
+            }
+            break;
+        case 'h':  // an hour / in an hour / an hour ago
+            return withoutSuffix ? 'hodina' : (isFuture ? 'hodinu' : 'hodinou');
+        case 'hh': // 9 hours / in 9 hours / 9 hours ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural(number) ? 'hodiny' : 'hodín');
+            } else {
+                return result + 'hodinami';
+            }
+            break;
+        case 'd':  // a day / in a day / a day ago
+            return (withoutSuffix || isFuture) ? 'deň' : 'dňom';
+        case 'dd': // 9 days / in 9 days / 9 days ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural(number) ? 'dni' : 'dní');
+            } else {
+                return result + 'dňami';
+            }
+            break;
+        case 'M':  // a month / in a month / a month ago
+            return (withoutSuffix || isFuture) ? 'mesiac' : 'mesiacom';
+        case 'MM': // 9 months / in 9 months / 9 months ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural(number) ? 'mesiace' : 'mesiacov');
+            } else {
+                return result + 'mesiacmi';
+            }
+            break;
+        case 'y':  // a year / in a year / a year ago
+            return (withoutSuffix || isFuture) ? 'rok' : 'rokom';
+        case 'yy': // 9 years / in 9 years / 9 years ago
+            if (withoutSuffix || isFuture) {
+                return result + (plural(number) ? 'roky' : 'rokov');
+            } else {
+                return result + 'rokmi';
+            }
+            break;
+    }
+}
+
+export default moment.defineLocale('sk', {
+    months : months,
+    monthsShort : monthsShort,
+    weekdays : 'nedeľa_pondelok_utorok_streda_štvrtok_piatok_sobota'.split('_'),
+    weekdaysShort : 'ne_po_ut_st_št_pi_so'.split('_'),
+    weekdaysMin : 'ne_po_ut_st_št_pi_so'.split('_'),
+    longDateFormat : {
+        LT: 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY H:mm',
+        LLLL : 'dddd D. MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay: '[dnes o] LT',
+        nextDay: '[zajtra o] LT',
+        nextWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[v nedeľu o] LT';
+                case 1:
+                case 2:
+                    return '[v] dddd [o] LT';
+                case 3:
+                    return '[v stredu o] LT';
+                case 4:
+                    return '[vo štvrtok o] LT';
+                case 5:
+                    return '[v piatok o] LT';
+                case 6:
+                    return '[v sobotu o] LT';
+            }
+        },
+        lastDay: '[včera o] LT',
+        lastWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[minulú nedeľu o] LT';
+                case 1:
+                case 2:
+                    return '[minulý] dddd [o] LT';
+                case 3:
+                    return '[minulú stredu o] LT';
+                case 4:
+                case 5:
+                    return '[minulý] dddd [o] LT';
+                case 6:
+                    return '[minulú sobotu o] LT';
+            }
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'za %s',
+        past : 'pred %s',
+        s : translate,
+        m : translate,
+        mm : translate,
+        h : translate,
+        hh : translate,
+        d : translate,
+        dd : translate,
+        M : translate,
+        MM : translate,
+        y : translate,
+        yy : translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/sl.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/sl.js
new file mode 100644
index 0000000000000000000000000000000000000000..2f36d5bf375d4ba7d1e1925cfe706651dd9a2578
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/sl.js
@@ -0,0 +1,152 @@
+//! moment.js locale configuration
+//! locale : Slovenian [sl]
+//! author : Robert Sedovšek : https://github.com/sedovsek
+
+import moment from '../moment';
+
+function processRelativeTime(number, withoutSuffix, key, isFuture) {
+    var result = number + ' ';
+    switch (key) {
+        case 's':
+            return withoutSuffix || isFuture ? 'nekaj sekund' : 'nekaj sekundami';
+        case 'm':
+            return withoutSuffix ? 'ena minuta' : 'eno minuto';
+        case 'mm':
+            if (number === 1) {
+                result += withoutSuffix ? 'minuta' : 'minuto';
+            } else if (number === 2) {
+                result += withoutSuffix || isFuture ? 'minuti' : 'minutama';
+            } else if (number < 5) {
+                result += withoutSuffix || isFuture ? 'minute' : 'minutami';
+            } else {
+                result += withoutSuffix || isFuture ? 'minut' : 'minutami';
+            }
+            return result;
+        case 'h':
+            return withoutSuffix ? 'ena ura' : 'eno uro';
+        case 'hh':
+            if (number === 1) {
+                result += withoutSuffix ? 'ura' : 'uro';
+            } else if (number === 2) {
+                result += withoutSuffix || isFuture ? 'uri' : 'urama';
+            } else if (number < 5) {
+                result += withoutSuffix || isFuture ? 'ure' : 'urami';
+            } else {
+                result += withoutSuffix || isFuture ? 'ur' : 'urami';
+            }
+            return result;
+        case 'd':
+            return withoutSuffix || isFuture ? 'en dan' : 'enim dnem';
+        case 'dd':
+            if (number === 1) {
+                result += withoutSuffix || isFuture ? 'dan' : 'dnem';
+            } else if (number === 2) {
+                result += withoutSuffix || isFuture ? 'dni' : 'dnevoma';
+            } else {
+                result += withoutSuffix || isFuture ? 'dni' : 'dnevi';
+            }
+            return result;
+        case 'M':
+            return withoutSuffix || isFuture ? 'en mesec' : 'enim mesecem';
+        case 'MM':
+            if (number === 1) {
+                result += withoutSuffix || isFuture ? 'mesec' : 'mesecem';
+            } else if (number === 2) {
+                result += withoutSuffix || isFuture ? 'meseca' : 'mesecema';
+            } else if (number < 5) {
+                result += withoutSuffix || isFuture ? 'mesece' : 'meseci';
+            } else {
+                result += withoutSuffix || isFuture ? 'mesecev' : 'meseci';
+            }
+            return result;
+        case 'y':
+            return withoutSuffix || isFuture ? 'eno leto' : 'enim letom';
+        case 'yy':
+            if (number === 1) {
+                result += withoutSuffix || isFuture ? 'leto' : 'letom';
+            } else if (number === 2) {
+                result += withoutSuffix || isFuture ? 'leti' : 'letoma';
+            } else if (number < 5) {
+                result += withoutSuffix || isFuture ? 'leta' : 'leti';
+            } else {
+                result += withoutSuffix || isFuture ? 'let' : 'leti';
+            }
+            return result;
+    }
+}
+
+export default moment.defineLocale('sl', {
+    months : 'januar_februar_marec_april_maj_junij_julij_avgust_september_oktober_november_december'.split('_'),
+    monthsShort : 'jan._feb._mar._apr._maj._jun._jul._avg._sep._okt._nov._dec.'.split('_'),
+    monthsParseExact: true,
+    weekdays : 'nedelja_ponedeljek_torek_sreda_četrtek_petek_sobota'.split('_'),
+    weekdaysShort : 'ned._pon._tor._sre._čet._pet._sob.'.split('_'),
+    weekdaysMin : 'ne_po_to_sr_če_pe_so'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM YYYY',
+        LLL : 'D. MMMM YYYY H:mm',
+        LLLL : 'dddd, D. MMMM YYYY H:mm'
+    },
+    calendar : {
+        sameDay  : '[danes ob] LT',
+        nextDay  : '[jutri ob] LT',
+
+        nextWeek : function () {
+            switch (this.day()) {
+                case 0:
+                    return '[v] [nedeljo] [ob] LT';
+                case 3:
+                    return '[v] [sredo] [ob] LT';
+                case 6:
+                    return '[v] [soboto] [ob] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[v] dddd [ob] LT';
+            }
+        },
+        lastDay  : '[včeraj ob] LT',
+        lastWeek : function () {
+            switch (this.day()) {
+                case 0:
+                    return '[prejšnjo] [nedeljo] [ob] LT';
+                case 3:
+                    return '[prejšnjo] [sredo] [ob] LT';
+                case 6:
+                    return '[prejšnjo] [soboto] [ob] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[prejšnji] dddd [ob] LT';
+            }
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'čez %s',
+        past   : 'pred %s',
+        s      : processRelativeTime,
+        m      : processRelativeTime,
+        mm     : processRelativeTime,
+        h      : processRelativeTime,
+        hh     : processRelativeTime,
+        d      : processRelativeTime,
+        dd     : processRelativeTime,
+        M      : processRelativeTime,
+        MM     : processRelativeTime,
+        y      : processRelativeTime,
+        yy     : processRelativeTime
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/sq.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/sq.js
new file mode 100644
index 0000000000000000000000000000000000000000..b0011c7f0bcdaecf472ba7b6bad6233fcda3d550
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/sq.js
@@ -0,0 +1,61 @@
+//! moment.js locale configuration
+//! locale : Albanian [sq]
+//! author : Flakërim Ismani : https://github.com/flakerimi
+//! author : Menelion Elensúle : https://github.com/Oire
+//! author : Oerd Cukalla : https://github.com/oerd
+
+import moment from '../moment';
+
+export default moment.defineLocale('sq', {
+    months : 'Janar_Shkurt_Mars_Prill_Maj_Qershor_Korrik_Gusht_Shtator_Tetor_Nëntor_Dhjetor'.split('_'),
+    monthsShort : 'Jan_Shk_Mar_Pri_Maj_Qer_Kor_Gus_Sht_Tet_Nën_Dhj'.split('_'),
+    weekdays : 'E Diel_E Hënë_E Martë_E Mërkurë_E Enjte_E Premte_E Shtunë'.split('_'),
+    weekdaysShort : 'Die_Hën_Mar_Mër_Enj_Pre_Sht'.split('_'),
+    weekdaysMin : 'D_H_Ma_Më_E_P_Sh'.split('_'),
+    weekdaysParseExact : true,
+    meridiemParse: /PD|MD/,
+    isPM: function (input) {
+        return input.charAt(0) === 'M';
+    },
+    meridiem : function (hours, minutes, isLower) {
+        return hours < 12 ? 'PD' : 'MD';
+    },
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[Sot në] LT',
+        nextDay : '[Nesër në] LT',
+        nextWeek : 'dddd [në] LT',
+        lastDay : '[Dje në] LT',
+        lastWeek : 'dddd [e kaluar në] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'në %s',
+        past : '%s më parë',
+        s : 'disa sekonda',
+        m : 'një minutë',
+        mm : '%d minuta',
+        h : 'një orë',
+        hh : '%d orë',
+        d : 'një ditë',
+        dd : '%d ditë',
+        M : 'një muaj',
+        MM : '%d muaj',
+        y : 'një vit',
+        yy : '%d vite'
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/sr-cyrl.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/sr-cyrl.js
new file mode 100644
index 0000000000000000000000000000000000000000..90449c1aeb2acc0afd1844bb1dd3bba3e69869f0
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/sr-cyrl.js
@@ -0,0 +1,100 @@
+//! moment.js locale configuration
+//! locale : Serbian Cyrillic [sr-cyrl]
+//! author : Milan Janačković<milanjanackovic@gmail.com> : https://github.com/milan-j
+
+import moment from '../moment';
+
+var translator = {
+    words: { //Different grammatical cases
+        m: ['један минут', 'једне минуте'],
+        mm: ['минут', 'минуте', 'минута'],
+        h: ['један сат', 'једног сата'],
+        hh: ['сат', 'сата', 'сати'],
+        dd: ['дан', 'дана', 'дана'],
+        MM: ['месец', 'месеца', 'месеци'],
+        yy: ['година', 'године', 'година']
+    },
+    correctGrammaticalCase: function (number, wordKey) {
+        return number === 1 ? wordKey[0] : (number >= 2 && number <= 4 ? wordKey[1] : wordKey[2]);
+    },
+    translate: function (number, withoutSuffix, key) {
+        var wordKey = translator.words[key];
+        if (key.length === 1) {
+            return withoutSuffix ? wordKey[0] : wordKey[1];
+        } else {
+            return number + ' ' + translator.correctGrammaticalCase(number, wordKey);
+        }
+    }
+};
+
+export default moment.defineLocale('sr-cyrl', {
+    months: 'јануар_фебруар_март_април_мај_јун_јул_август_септембар_октобар_новембар_децембар'.split('_'),
+    monthsShort: 'јан._феб._мар._апр._мај_јун_јул_авг._сеп._окт._нов._дец.'.split('_'),
+    monthsParseExact: true,
+    weekdays: 'недеља_понедељак_уторак_среда_четвртак_петак_субота'.split('_'),
+    weekdaysShort: 'нед._пон._уто._сре._чет._пет._суб.'.split('_'),
+    weekdaysMin: 'не_по_ут_ср_че_пе_су'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat: {
+        LT: 'H:mm',
+        LTS : 'H:mm:ss',
+        L: 'DD.MM.YYYY',
+        LL: 'D. MMMM YYYY',
+        LLL: 'D. MMMM YYYY H:mm',
+        LLLL: 'dddd, D. MMMM YYYY H:mm'
+    },
+    calendar: {
+        sameDay: '[данас у] LT',
+        nextDay: '[сутра у] LT',
+        nextWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[у] [недељу] [у] LT';
+                case 3:
+                    return '[у] [среду] [у] LT';
+                case 6:
+                    return '[у] [суботу] [у] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[у] dddd [у] LT';
+            }
+        },
+        lastDay  : '[јуче у] LT',
+        lastWeek : function () {
+            var lastWeekDays = [
+                '[прошле] [недеље] [у] LT',
+                '[прошлог] [понедељка] [у] LT',
+                '[прошлог] [уторка] [у] LT',
+                '[прошле] [среде] [у] LT',
+                '[прошлог] [четвртка] [у] LT',
+                '[прошлог] [петка] [у] LT',
+                '[прошле] [суботе] [у] LT'
+            ];
+            return lastWeekDays[this.day()];
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'за %s',
+        past   : 'пре %s',
+        s      : 'неколико секунди',
+        m      : translator.translate,
+        mm     : translator.translate,
+        h      : translator.translate,
+        hh     : translator.translate,
+        d      : 'дан',
+        dd     : translator.translate,
+        M      : 'месец',
+        MM     : translator.translate,
+        y      : 'годину',
+        yy     : translator.translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/sr.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/sr.js
new file mode 100644
index 0000000000000000000000000000000000000000..6716b42726aae522b59c9159511f50888584c746
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/sr.js
@@ -0,0 +1,100 @@
+//! moment.js locale configuration
+//! locale : Serbian [sr]
+//! author : Milan Janačković<milanjanackovic@gmail.com> : https://github.com/milan-j
+
+import moment from '../moment';
+
+var translator = {
+    words: { //Different grammatical cases
+        m: ['jedan minut', 'jedne minute'],
+        mm: ['minut', 'minute', 'minuta'],
+        h: ['jedan sat', 'jednog sata'],
+        hh: ['sat', 'sata', 'sati'],
+        dd: ['dan', 'dana', 'dana'],
+        MM: ['mesec', 'meseca', 'meseci'],
+        yy: ['godina', 'godine', 'godina']
+    },
+    correctGrammaticalCase: function (number, wordKey) {
+        return number === 1 ? wordKey[0] : (number >= 2 && number <= 4 ? wordKey[1] : wordKey[2]);
+    },
+    translate: function (number, withoutSuffix, key) {
+        var wordKey = translator.words[key];
+        if (key.length === 1) {
+            return withoutSuffix ? wordKey[0] : wordKey[1];
+        } else {
+            return number + ' ' + translator.correctGrammaticalCase(number, wordKey);
+        }
+    }
+};
+
+export default moment.defineLocale('sr', {
+    months: 'januar_februar_mart_april_maj_jun_jul_avgust_septembar_oktobar_novembar_decembar'.split('_'),
+    monthsShort: 'jan._feb._mar._apr._maj_jun_jul_avg._sep._okt._nov._dec.'.split('_'),
+    monthsParseExact: true,
+    weekdays: 'nedelja_ponedeljak_utorak_sreda_četvrtak_petak_subota'.split('_'),
+    weekdaysShort: 'ned._pon._uto._sre._čet._pet._sub.'.split('_'),
+    weekdaysMin: 'ne_po_ut_sr_če_pe_su'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat: {
+        LT: 'H:mm',
+        LTS : 'H:mm:ss',
+        L: 'DD.MM.YYYY',
+        LL: 'D. MMMM YYYY',
+        LLL: 'D. MMMM YYYY H:mm',
+        LLLL: 'dddd, D. MMMM YYYY H:mm'
+    },
+    calendar: {
+        sameDay: '[danas u] LT',
+        nextDay: '[sutra u] LT',
+        nextWeek: function () {
+            switch (this.day()) {
+                case 0:
+                    return '[u] [nedelju] [u] LT';
+                case 3:
+                    return '[u] [sredu] [u] LT';
+                case 6:
+                    return '[u] [subotu] [u] LT';
+                case 1:
+                case 2:
+                case 4:
+                case 5:
+                    return '[u] dddd [u] LT';
+            }
+        },
+        lastDay  : '[juče u] LT',
+        lastWeek : function () {
+            var lastWeekDays = [
+                '[prošle] [nedelje] [u] LT',
+                '[prošlog] [ponedeljka] [u] LT',
+                '[prošlog] [utorka] [u] LT',
+                '[prošle] [srede] [u] LT',
+                '[prošlog] [četvrtka] [u] LT',
+                '[prošlog] [petka] [u] LT',
+                '[prošle] [subote] [u] LT'
+            ];
+            return lastWeekDays[this.day()];
+        },
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'za %s',
+        past   : 'pre %s',
+        s      : 'nekoliko sekundi',
+        m      : translator.translate,
+        mm     : translator.translate,
+        h      : translator.translate,
+        hh     : translator.translate,
+        d      : 'dan',
+        dd     : translator.translate,
+        M      : 'mesec',
+        MM     : translator.translate,
+        y      : 'godinu',
+        yy     : translator.translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ss.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ss.js
new file mode 100644
index 0000000000000000000000000000000000000000..f6a7d0a8c5a06867a0d868dfa1eb928d094b63a5
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ss.js
@@ -0,0 +1,80 @@
+//! moment.js locale configuration
+//! locale : siSwati [ss]
+//! author : Nicolai Davies<mail@nicolai.io> : https://github.com/nicolaidavies
+
+
+import moment from '../moment';
+
+export default moment.defineLocale('ss', {
+    months : "Bhimbidvwane_Indlovana_Indlov'lenkhulu_Mabasa_Inkhwekhweti_Inhlaba_Kholwane_Ingci_Inyoni_Imphala_Lweti_Ingongoni".split('_'),
+    monthsShort : 'Bhi_Ina_Inu_Mab_Ink_Inh_Kho_Igc_Iny_Imp_Lwe_Igo'.split('_'),
+    weekdays : 'Lisontfo_Umsombuluko_Lesibili_Lesitsatfu_Lesine_Lesihlanu_Umgcibelo'.split('_'),
+    weekdaysShort : 'Lis_Umb_Lsb_Les_Lsi_Lsh_Umg'.split('_'),
+    weekdaysMin : 'Li_Us_Lb_Lt_Ls_Lh_Ug'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'h:mm A',
+        LTS : 'h:mm:ss A',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY h:mm A',
+        LLLL : 'dddd, D MMMM YYYY h:mm A'
+    },
+    calendar : {
+        sameDay : '[Namuhla nga] LT',
+        nextDay : '[Kusasa nga] LT',
+        nextWeek : 'dddd [nga] LT',
+        lastDay : '[Itolo nga] LT',
+        lastWeek : 'dddd [leliphelile] [nga] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'nga %s',
+        past : 'wenteka nga %s',
+        s : 'emizuzwana lomcane',
+        m : 'umzuzu',
+        mm : '%d emizuzu',
+        h : 'lihora',
+        hh : '%d emahora',
+        d : 'lilanga',
+        dd : '%d emalanga',
+        M : 'inyanga',
+        MM : '%d tinyanga',
+        y : 'umnyaka',
+        yy : '%d iminyaka'
+    },
+    meridiemParse: /ekuseni|emini|entsambama|ebusuku/,
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 11) {
+            return 'ekuseni';
+        } else if (hours < 15) {
+            return 'emini';
+        } else if (hours < 19) {
+            return 'entsambama';
+        } else {
+            return 'ebusuku';
+        }
+    },
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'ekuseni') {
+            return hour;
+        } else if (meridiem === 'emini') {
+            return hour >= 11 ? hour : hour + 12;
+        } else if (meridiem === 'entsambama' || meridiem === 'ebusuku') {
+            if (hour === 0) {
+                return 0;
+            }
+            return hour + 12;
+        }
+    },
+    ordinalParse: /\d{1,2}/,
+    ordinal : '%d',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/sv.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/sv.js
new file mode 100644
index 0000000000000000000000000000000000000000..15d1c9d99c1d9a80f5c10f35bac500b647d04130
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/sv.js
@@ -0,0 +1,60 @@
+//! moment.js locale configuration
+//! locale : Swedish [sv]
+//! author : Jens Alm : https://github.com/ulmus
+
+import moment from '../moment';
+
+export default moment.defineLocale('sv', {
+    months : 'januari_februari_mars_april_maj_juni_juli_augusti_september_oktober_november_december'.split('_'),
+    monthsShort : 'jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec'.split('_'),
+    weekdays : 'söndag_måndag_tisdag_onsdag_torsdag_fredag_lördag'.split('_'),
+    weekdaysShort : 'sön_mån_tis_ons_tor_fre_lör'.split('_'),
+    weekdaysMin : 'sö_må_ti_on_to_fr_lö'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'YYYY-MM-DD',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY [kl.] HH:mm',
+        LLLL : 'dddd D MMMM YYYY [kl.] HH:mm',
+        lll : 'D MMM YYYY HH:mm',
+        llll : 'ddd D MMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Idag] LT',
+        nextDay: '[Imorgon] LT',
+        lastDay: '[Igår] LT',
+        nextWeek: '[PÃ¥] dddd LT',
+        lastWeek: '[I] dddd[s] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'om %s',
+        past : 'för %s sedan',
+        s : 'några sekunder',
+        m : 'en minut',
+        mm : '%d minuter',
+        h : 'en timme',
+        hh : '%d timmar',
+        d : 'en dag',
+        dd : '%d dagar',
+        M : 'en månad',
+        MM : '%d månader',
+        y : 'ett år',
+        yy : '%d år'
+    },
+    ordinalParse: /\d{1,2}(e|a)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'e' :
+            (b === 1) ? 'a' :
+            (b === 2) ? 'a' :
+            (b === 3) ? 'e' : 'e';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/sw.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/sw.js
new file mode 100644
index 0000000000000000000000000000000000000000..a36d9dd2a96a2d308ada4ff521e0b0c6a30cb036
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/sw.js
@@ -0,0 +1,50 @@
+//! moment.js locale configuration
+//! locale : Swahili [sw]
+//! author : Fahad Kassim : https://github.com/fadsel
+
+import moment from '../moment';
+
+export default moment.defineLocale('sw', {
+    months : 'Januari_Februari_Machi_Aprili_Mei_Juni_Julai_Agosti_Septemba_Oktoba_Novemba_Desemba'.split('_'),
+    monthsShort : 'Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ago_Sep_Okt_Nov_Des'.split('_'),
+    weekdays : 'Jumapili_Jumatatu_Jumanne_Jumatano_Alhamisi_Ijumaa_Jumamosi'.split('_'),
+    weekdaysShort : 'Jpl_Jtat_Jnne_Jtan_Alh_Ijm_Jmos'.split('_'),
+    weekdaysMin : 'J2_J3_J4_J5_Al_Ij_J1'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[leo saa] LT',
+        nextDay : '[kesho saa] LT',
+        nextWeek : '[wiki ijayo] dddd [saat] LT',
+        lastDay : '[jana] LT',
+        lastWeek : '[wiki iliyopita] dddd [saat] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s baadaye',
+        past : 'tokea %s',
+        s : 'hivi punde',
+        m : 'dakika moja',
+        mm : 'dakika %d',
+        h : 'saa limoja',
+        hh : 'masaa %d',
+        d : 'siku moja',
+        dd : 'masiku %d',
+        M : 'mwezi mmoja',
+        MM : 'miezi %d',
+        y : 'mwaka mmoja',
+        yy : 'miaka %d'
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ta.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ta.js
new file mode 100644
index 0000000000000000000000000000000000000000..6be3e2e0bc6f334048d83ee3c93efe6b19c8afc4
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/ta.js
@@ -0,0 +1,120 @@
+//! moment.js locale configuration
+//! locale : Tamil [ta]
+//! author : Arjunkumar Krishnamoorthy : https://github.com/tk120404
+
+import moment from '../moment';
+
+var symbolMap = {
+    '1': '௧',
+    '2': '௨',
+    '3': '௩',
+    '4': '௪',
+    '5': '௫',
+    '6': '௬',
+    '7': '௭',
+    '8': '௮',
+    '9': '௯',
+    '0': '௦'
+}, numberMap = {
+    '௧': '1',
+    '௨': '2',
+    '௩': '3',
+    '௪': '4',
+    '௫': '5',
+    '௬': '6',
+    '௭': '7',
+    '௮': '8',
+    '௯': '9',
+    '௦': '0'
+};
+
+export default moment.defineLocale('ta', {
+    months : 'ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்'.split('_'),
+    monthsShort : 'ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்'.split('_'),
+    weekdays : 'ஞாயிற்றுக்கிழமை_திங்கட்கிழமை_செவ்வாய்கிழமை_புதன்கிழமை_வியாழக்கிழமை_வெள்ளிக்கிழமை_சனிக்கிழமை'.split('_'),
+    weekdaysShort : 'ஞாயிறு_திங்கள்_செவ்வாய்_புதன்_வியாழன்_வெள்ளி_சனி'.split('_'),
+    weekdaysMin : 'ஞா_தி_செ_பு_வி_வெ_ச'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, HH:mm',
+        LLLL : 'dddd, D MMMM YYYY, HH:mm'
+    },
+    calendar : {
+        sameDay : '[இன்று] LT',
+        nextDay : '[நாளை] LT',
+        nextWeek : 'dddd, LT',
+        lastDay : '[நேற்று] LT',
+        lastWeek : '[கடந்த வாரம்] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s இல்',
+        past : '%s முன்',
+        s : 'ஒரு சில விநாடிகள்',
+        m : 'ஒரு நிமிடம்',
+        mm : '%d நிமிடங்கள்',
+        h : 'ஒரு மணி நேரம்',
+        hh : '%d மணி நேரம்',
+        d : 'ஒரு நாள்',
+        dd : '%d நாட்கள்',
+        M : 'ஒரு மாதம்',
+        MM : '%d மாதங்கள்',
+        y : 'ஒரு வருடம்',
+        yy : '%d ஆண்டுகள்'
+    },
+    ordinalParse: /\d{1,2}வது/,
+    ordinal : function (number) {
+        return number + 'வது';
+    },
+    preparse: function (string) {
+        return string.replace(/[௧௨௩௪௫௬௭௮௯௦]/g, function (match) {
+            return numberMap[match];
+        });
+    },
+    postformat: function (string) {
+        return string.replace(/\d/g, function (match) {
+            return symbolMap[match];
+        });
+    },
+    // refer http://ta.wikipedia.org/s/1er1
+    meridiemParse: /யாமம்|வைகறை|காலை|நண்பகல்|எற்பாடு|மாலை/,
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 2) {
+            return ' யாமம்';
+        } else if (hour < 6) {
+            return ' வைகறை';  // வைகறை
+        } else if (hour < 10) {
+            return ' காலை'; // காலை
+        } else if (hour < 14) {
+            return ' நண்பகல்'; // நண்பகல்
+        } else if (hour < 18) {
+            return ' எற்பாடு'; // எற்பாடு
+        } else if (hour < 22) {
+            return ' மாலை'; // மாலை
+        } else {
+            return ' யாமம்';
+        }
+    },
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'யாமம்') {
+            return hour < 2 ? hour : hour + 12;
+        } else if (meridiem === 'வைகறை' || meridiem === 'காலை') {
+            return hour;
+        } else if (meridiem === 'நண்பகல்') {
+            return hour >= 10 ? hour : hour + 12;
+        } else {
+            return hour + 12;
+        }
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/te.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/te.js
new file mode 100644
index 0000000000000000000000000000000000000000..d9edc388d43091dd55a24c5badd23cdb1e9b3617
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/te.js
@@ -0,0 +1,79 @@
+//! moment.js locale configuration
+//! locale : Telugu [te]
+//! author : Krishna Chaitanya Thota : https://github.com/kcthota
+
+import moment from '../moment';
+
+export default moment.defineLocale('te', {
+    months : 'జనవరి_ఫిబ్రవరి_మార్చి_ఏప్రిల్_మే_జూన్_జూలై_ఆగస్టు_సెప్టెంబర్_అక్టోబర్_నవంబర్_డిసెంబర్'.split('_'),
+    monthsShort : 'జన._ఫిబ్ర._మార్చి_ఏప్రి._మే_జూన్_జూలై_ఆగ._సెప్._అక్టో._నవ._డిసె.'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'ఆదివారం_సోమవారం_మంగళవారం_బుధవారం_గురువారం_శుక్రవారం_శనివారం'.split('_'),
+    weekdaysShort : 'ఆది_సోమ_మంగళ_బుధ_గురు_శుక్ర_శని'.split('_'),
+    weekdaysMin : 'ఆ_సో_మం_బు_గు_శు_శ'.split('_'),
+    longDateFormat : {
+        LT : 'A h:mm',
+        LTS : 'A h:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY, A h:mm',
+        LLLL : 'dddd, D MMMM YYYY, A h:mm'
+    },
+    calendar : {
+        sameDay : '[నేడు] LT',
+        nextDay : '[రేపు] LT',
+        nextWeek : 'dddd, LT',
+        lastDay : '[నిన్న] LT',
+        lastWeek : '[à°—à°¤] dddd, LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s లో',
+        past : '%s క్రితం',
+        s : 'కొన్ని క్షణాలు',
+        m : 'ఒక నిమిషం',
+        mm : '%d నిమిషాలు',
+        h : 'à°’à°• à°—à°‚à°Ÿ',
+        hh : '%d గంటలు',
+        d : 'ఒక రోజు',
+        dd : '%d రోజులు',
+        M : 'ఒక నెల',
+        MM : '%d నెలలు',
+        y : 'ఒక సంవత్సరం',
+        yy : '%d సంవత్సరాలు'
+    },
+    ordinalParse : /\d{1,2}à°µ/,
+    ordinal : '%dà°µ',
+    meridiemParse: /రాత్రి|ఉదయం|మధ్యాహ్నం|సాయంత్రం/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === 'రాత్రి') {
+            return hour < 4 ? hour : hour + 12;
+        } else if (meridiem === 'ఉదయం') {
+            return hour;
+        } else if (meridiem === 'మధ్యాహ్నం') {
+            return hour >= 10 ? hour : hour + 12;
+        } else if (meridiem === 'సాయంత్రం') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'రాత్రి';
+        } else if (hour < 10) {
+            return 'ఉదయం';
+        } else if (hour < 17) {
+            return 'మధ్యాహ్నం';
+        } else if (hour < 20) {
+            return 'సాయంత్రం';
+        } else {
+            return 'రాత్రి';
+        }
+    },
+    week : {
+        dow : 0, // Sunday is the first day of the week.
+        doy : 6  // The week that contains Jan 1st is the first week of the year.
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/tet.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/tet.js
new file mode 100644
index 0000000000000000000000000000000000000000..e048e243b832925f5e0c027ed4482f10277932b5
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/tet.js
@@ -0,0 +1,58 @@
+//! moment.js locale configuration
+//! locale : Tetun Dili (East Timor) [tet]
+//! author : Joshua Brooks : https://github.com/joshbrooks
+//! author : Onorio De J. Afonso : https://github.com/marobo
+
+import moment from '../moment';
+
+export default moment.defineLocale('tet', {
+    months : 'Janeiru_Fevereiru_Marsu_Abril_Maiu_Juniu_Juliu_Augustu_Setembru_Outubru_Novembru_Dezembru'.split('_'),
+    monthsShort : 'Jan_Fev_Mar_Abr_Mai_Jun_Jul_Aug_Set_Out_Nov_Dez'.split('_'),
+    weekdays : 'Domingu_Segunda_Tersa_Kuarta_Kinta_Sexta_Sabadu'.split('_'),
+    weekdaysShort : 'Dom_Seg_Ters_Kua_Kint_Sext_Sab'.split('_'),
+    weekdaysMin : 'Do_Seg_Te_Ku_Ki_Sex_Sa'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Ohin iha] LT',
+        nextDay: '[Aban iha] LT',
+        nextWeek: 'dddd [iha] LT',
+        lastDay: '[Horiseik iha] LT',
+        lastWeek: 'dddd [semana kotuk] [iha] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'iha %s',
+        past : '%s liuba',
+        s : 'minutu balun',
+        m : 'minutu ida',
+        mm : 'minutus %d',
+        h : 'horas ida',
+        hh : 'horas %d',
+        d : 'loron ida',
+        dd : 'loron %d',
+        M : 'fulan ida',
+        MM : 'fulan %d',
+        y : 'tinan ida',
+        yy : 'tinan %d'
+    },
+    ordinalParse: /\d{1,2}(st|nd|rd|th)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/th.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/th.js
new file mode 100644
index 0000000000000000000000000000000000000000..423f827b34161b230d875c76e3625b229f9db034
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/th.js
@@ -0,0 +1,57 @@
+//! moment.js locale configuration
+//! locale : Thai [th]
+//! author : Kridsada Thanabulpong : https://github.com/sirn
+
+import moment from '../moment';
+
+export default moment.defineLocale('th', {
+    months : 'มกราคม_กุมภาพันธ์_มีนาคม_เมษายน_พฤษภาคม_มิถุนายน_กรกฎาคม_สิงหาคม_กันยายน_ตุลาคม_พฤศจิกายน_ธันวาคม'.split('_'),
+    monthsShort : 'ม.ค._ก.พ._มี.ค._เม.ย._พ.ค._มิ.ย._ก.ค._ส.ค._ก.ย._ต.ค._พ.ย._ธ.ค.'.split('_'),
+    monthsParseExact: true,
+    weekdays : 'อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัสบดี_ศุกร์_เสาร์'.split('_'),
+    weekdaysShort : 'อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัส_ศุกร์_เสาร์'.split('_'), // yes, three characters difference
+    weekdaysMin : 'อา._จ._อ._พ._พฤ._ศ._ส.'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'H:mm',
+        LTS : 'H:mm:ss',
+        L : 'YYYY/MM/DD',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY เวลา H:mm',
+        LLLL : 'วันddddที่ D MMMM YYYY เวลา H:mm'
+    },
+    meridiemParse: /ก่อนเที่ยง|หลังเที่ยง/,
+    isPM: function (input) {
+        return input === 'หลังเที่ยง';
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 12) {
+            return 'ก่อนเที่ยง';
+        } else {
+            return 'หลังเที่ยง';
+        }
+    },
+    calendar : {
+        sameDay : '[วันนี้ เวลา] LT',
+        nextDay : '[พรุ่งนี้ เวลา] LT',
+        nextWeek : 'dddd[หน้า เวลา] LT',
+        lastDay : '[เมื่อวานนี้ เวลา] LT',
+        lastWeek : '[วัน]dddd[ที่แล้ว เวลา] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'อีก %s',
+        past : '%sที่แล้ว',
+        s : 'ไม่กี่วินาที',
+        m : '1 นาที',
+        mm : '%d นาที',
+        h : '1 ชั่วโมง',
+        hh : '%d ชั่วโมง',
+        d : '1 วัน',
+        dd : '%d วัน',
+        M : '1 เดือน',
+        MM : '%d เดือน',
+        y : '1 ปี',
+        yy : '%d ปี'
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/tl-ph.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/tl-ph.js
new file mode 100644
index 0000000000000000000000000000000000000000..d93f6389b721f9f13a23ae52ed936e0302347668
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/tl-ph.js
@@ -0,0 +1,53 @@
+//! moment.js locale configuration
+//! locale : Tagalog (Philippines) [tl-ph]
+//! author : Dan Hagman : https://github.com/hagmandan
+
+import moment from '../moment';
+
+export default moment.defineLocale('tl-ph', {
+    months : 'Enero_Pebrero_Marso_Abril_Mayo_Hunyo_Hulyo_Agosto_Setyembre_Oktubre_Nobyembre_Disyembre'.split('_'),
+    monthsShort : 'Ene_Peb_Mar_Abr_May_Hun_Hul_Ago_Set_Okt_Nob_Dis'.split('_'),
+    weekdays : 'Linggo_Lunes_Martes_Miyerkules_Huwebes_Biyernes_Sabado'.split('_'),
+    weekdaysShort : 'Lin_Lun_Mar_Miy_Huw_Biy_Sab'.split('_'),
+    weekdaysMin : 'Li_Lu_Ma_Mi_Hu_Bi_Sab'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'MM/D/YYYY',
+        LL : 'MMMM D, YYYY',
+        LLL : 'MMMM D, YYYY HH:mm',
+        LLLL : 'dddd, MMMM DD, YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: 'LT [ngayong araw]',
+        nextDay: '[Bukas ng] LT',
+        nextWeek: 'LT [sa susunod na] dddd',
+        lastDay: 'LT [kahapon]',
+        lastWeek: 'LT [noong nakaraang] dddd',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'sa loob ng %s',
+        past : '%s ang nakalipas',
+        s : 'ilang segundo',
+        m : 'isang minuto',
+        mm : '%d minuto',
+        h : 'isang oras',
+        hh : '%d oras',
+        d : 'isang araw',
+        dd : '%d araw',
+        M : 'isang buwan',
+        MM : '%d buwan',
+        y : 'isang taon',
+        yy : '%d taon'
+    },
+    ordinalParse: /\d{1,2}/,
+    ordinal : function (number) {
+        return number;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/tlh.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/tlh.js
new file mode 100644
index 0000000000000000000000000000000000000000..af1b08d4ba74f8ba532738474e1671cb03e03048
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/tlh.js
@@ -0,0 +1,110 @@
+//! moment.js locale configuration
+//! locale : Klingon [tlh]
+//! author : Dominika Kruk : https://github.com/amaranthrose
+
+import moment from '../moment';
+
+var numbersNouns = 'pagh_wa’_cha’_wej_loS_vagh_jav_Soch_chorgh_Hut'.split('_');
+
+function translateFuture(output) {
+    var time = output;
+    time = (output.indexOf('jaj') !== -1) ?
+    time.slice(0, -3) + 'leS' :
+    (output.indexOf('jar') !== -1) ?
+    time.slice(0, -3) + 'waQ' :
+    (output.indexOf('DIS') !== -1) ?
+    time.slice(0, -3) + 'nem' :
+    time + ' pIq';
+    return time;
+}
+
+function translatePast(output) {
+    var time = output;
+    time = (output.indexOf('jaj') !== -1) ?
+    time.slice(0, -3) + 'Hu’' :
+    (output.indexOf('jar') !== -1) ?
+    time.slice(0, -3) + 'wen' :
+    (output.indexOf('DIS') !== -1) ?
+    time.slice(0, -3) + 'ben' :
+    time + ' ret';
+    return time;
+}
+
+function translate(number, withoutSuffix, string, isFuture) {
+    var numberNoun = numberAsNoun(number);
+    switch (string) {
+        case 'mm':
+            return numberNoun + ' tup';
+        case 'hh':
+            return numberNoun + ' rep';
+        case 'dd':
+            return numberNoun + ' jaj';
+        case 'MM':
+            return numberNoun + ' jar';
+        case 'yy':
+            return numberNoun + ' DIS';
+    }
+}
+
+function numberAsNoun(number) {
+    var hundred = Math.floor((number % 1000) / 100),
+    ten = Math.floor((number % 100) / 10),
+    one = number % 10,
+    word = '';
+    if (hundred > 0) {
+        word += numbersNouns[hundred] + 'vatlh';
+    }
+    if (ten > 0) {
+        word += ((word !== '') ? ' ' : '') + numbersNouns[ten] + 'maH';
+    }
+    if (one > 0) {
+        word += ((word !== '') ? ' ' : '') + numbersNouns[one];
+    }
+    return (word === '') ? 'pagh' : word;
+}
+
+export default moment.defineLocale('tlh', {
+    months : 'tera’ jar wa’_tera’ jar cha’_tera’ jar wej_tera’ jar loS_tera’ jar vagh_tera’ jar jav_tera’ jar Soch_tera’ jar chorgh_tera’ jar Hut_tera’ jar wa’maH_tera’ jar wa’maH wa’_tera’ jar wa’maH cha’'.split('_'),
+    monthsShort : 'jar wa’_jar cha’_jar wej_jar loS_jar vagh_jar jav_jar Soch_jar chorgh_jar Hut_jar wa’maH_jar wa’maH wa’_jar wa’maH cha’'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj'.split('_'),
+    weekdaysShort : 'lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj'.split('_'),
+    weekdaysMin : 'lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[DaHjaj] LT',
+        nextDay: '[wa’leS] LT',
+        nextWeek: 'LLL',
+        lastDay: '[wa’Hu’] LT',
+        lastWeek: 'LLL',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : translateFuture,
+        past : translatePast,
+        s : 'puS lup',
+        m : 'wa’ tup',
+        mm : translate,
+        h : 'wa’ rep',
+        hh : translate,
+        d : 'wa’ jaj',
+        dd : translate,
+        M : 'wa’ jar',
+        MM : translate,
+        y : 'wa’ DIS',
+        yy : translate
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/tr.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/tr.js
new file mode 100644
index 0000000000000000000000000000000000000000..0ae427acbe3e1b684f718f12647d8fa210024c07
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/tr.js
@@ -0,0 +1,81 @@
+//! moment.js locale configuration
+//! locale : Turkish [tr]
+//! authors : Erhan Gundogan : https://github.com/erhangundogan,
+//!           Burak YiÄŸit Kaya: https://github.com/BYK
+
+import moment from '../moment';
+
+var suffixes = {
+    1: '\'inci',
+    5: '\'inci',
+    8: '\'inci',
+    70: '\'inci',
+    80: '\'inci',
+    2: '\'nci',
+    7: '\'nci',
+    20: '\'nci',
+    50: '\'nci',
+    3: '\'üncü',
+    4: '\'üncü',
+    100: '\'üncü',
+    6: '\'ncı',
+    9: '\'uncu',
+    10: '\'uncu',
+    30: '\'uncu',
+    60: '\'ıncı',
+    90: '\'ıncı'
+};
+
+export default moment.defineLocale('tr', {
+    months : 'Ocak_Şubat_Mart_Nisan_Mayıs_Haziran_Temmuz_Ağustos_Eylül_Ekim_Kasım_Aralık'.split('_'),
+    monthsShort : 'Oca_Åžub_Mar_Nis_May_Haz_Tem_AÄŸu_Eyl_Eki_Kas_Ara'.split('_'),
+    weekdays : 'Pazar_Pazartesi_Salı_Çarşamba_Perşembe_Cuma_Cumartesi'.split('_'),
+    weekdaysShort : 'Paz_Pts_Sal_Çar_Per_Cum_Cts'.split('_'),
+    weekdaysMin : 'Pz_Pt_Sa_Ça_Pe_Cu_Ct'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[bugün saat] LT',
+        nextDay : '[yarın saat] LT',
+        nextWeek : '[haftaya] dddd [saat] LT',
+        lastDay : '[dün] LT',
+        lastWeek : '[geçen hafta] dddd [saat] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : '%s sonra',
+        past : '%s önce',
+        s : 'birkaç saniye',
+        m : 'bir dakika',
+        mm : '%d dakika',
+        h : 'bir saat',
+        hh : '%d saat',
+        d : 'bir gün',
+        dd : '%d gün',
+        M : 'bir ay',
+        MM : '%d ay',
+        y : 'bir yıl',
+        yy : '%d yıl'
+    },
+    ordinalParse: /\d{1,2}'(inci|nci|üncü|ncı|uncu|ıncı)/,
+    ordinal : function (number) {
+        if (number === 0) {  // special case for zero
+            return number + '\'ıncı';
+        }
+        var a = number % 10,
+            b = number % 100 - a,
+            c = number >= 100 ? 100 : null;
+        return number + (suffixes[a] || suffixes[b] || suffixes[c]);
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/tzl.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/tzl.js
new file mode 100644
index 0000000000000000000000000000000000000000..d4fcdbfde2d475515c71ed0b81b9f432e9642e56
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/tzl.js
@@ -0,0 +1,82 @@
+//! moment.js locale configuration
+//! locale : Talossan [tzl]
+//! author : Robin van der Vliet : https://github.com/robin0van0der0v
+//! author : Iustì Canun
+
+import moment from '../moment';
+
+// After the year there should be a slash and the amount of years since December 26, 1979 in Roman numerals.
+// This is currently too difficult (maybe even impossible) to add.
+export default moment.defineLocale('tzl', {
+    months : 'Januar_Fevraglh_Març_Avrïu_Mai_Gün_Julia_Guscht_Setemvar_Listopäts_Noemvar_Zecemvar'.split('_'),
+    monthsShort : 'Jan_Fev_Mar_Avr_Mai_Gün_Jul_Gus_Set_Lis_Noe_Zec'.split('_'),
+    weekdays : 'Súladi_Lúneçi_Maitzi_Márcuri_Xhúadi_Viénerçi_Sáturi'.split('_'),
+    weekdaysShort : 'Súl_Lún_Mai_Már_Xhú_Vié_Sát'.split('_'),
+    weekdaysMin : 'Sú_Lú_Ma_Má_Xh_Vi_Sá'.split('_'),
+    longDateFormat : {
+        LT : 'HH.mm',
+        LTS : 'HH.mm.ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D. MMMM [dallas] YYYY',
+        LLL : 'D. MMMM [dallas] YYYY HH.mm',
+        LLLL : 'dddd, [li] D. MMMM [dallas] YYYY HH.mm'
+    },
+    meridiemParse: /d\'o|d\'a/i,
+    isPM : function (input) {
+        return 'd\'o' === input.toLowerCase();
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours > 11) {
+            return isLower ? 'd\'o' : 'D\'O';
+        } else {
+            return isLower ? 'd\'a' : 'D\'A';
+        }
+    },
+    calendar : {
+        sameDay : '[oxhi à] LT',
+        nextDay : '[demà à] LT',
+        nextWeek : 'dddd [à] LT',
+        lastDay : '[ieiri à] LT',
+        lastWeek : '[sür el] dddd [lasteu à] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'osprei %s',
+        past : 'ja%s',
+        s : processRelativeTime,
+        m : processRelativeTime,
+        mm : processRelativeTime,
+        h : processRelativeTime,
+        hh : processRelativeTime,
+        d : processRelativeTime,
+        dd : processRelativeTime,
+        M : processRelativeTime,
+        MM : processRelativeTime,
+        y : processRelativeTime,
+        yy : processRelativeTime
+    },
+    ordinalParse: /\d{1,2}\./,
+    ordinal : '%d.',
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
+function processRelativeTime(number, withoutSuffix, key, isFuture) {
+    var format = {
+        's': ['viensas secunds', '\'iensas secunds'],
+        'm': ['\'n míut', '\'iens míut'],
+        'mm': [number + ' míuts', '' + number + ' míuts'],
+        'h': ['\'n þora', '\'iensa þora'],
+        'hh': [number + ' þoras', '' + number + ' þoras'],
+        'd': ['\'n ziua', '\'iensa ziua'],
+        'dd': [number + ' ziuas', '' + number + ' ziuas'],
+        'M': ['\'n mes', '\'iens mes'],
+        'MM': [number + ' mesen', '' + number + ' mesen'],
+        'y': ['\'n ar', '\'iens ar'],
+        'yy': [number + ' ars', '' + number + ' ars']
+    };
+    return isFuture ? format[key][0] : (withoutSuffix ? format[key][0] : format[key][1]);
+}
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/tzm-latn.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/tzm-latn.js
new file mode 100644
index 0000000000000000000000000000000000000000..aaf62d70c05af368fd596aea0329a19d33e6a38d
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/tzm-latn.js
@@ -0,0 +1,49 @@
+//! moment.js locale configuration
+//! locale : Central Atlas Tamazight Latin [tzm-latn]
+//! author : Abdel Said : https://github.com/abdelsaid
+
+import moment from '../moment';
+
+export default moment.defineLocale('tzm-latn', {
+    months : 'innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir'.split('_'),
+    monthsShort : 'innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir'.split('_'),
+    weekdays : 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'),
+    weekdaysShort : 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'),
+    weekdaysMin : 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[asdkh g] LT',
+        nextDay: '[aska g] LT',
+        nextWeek: 'dddd [g] LT',
+        lastDay: '[assant g] LT',
+        lastWeek: 'dddd [g] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'dadkh s yan %s',
+        past : 'yan %s',
+        s : 'imik',
+        m : 'minuḍ',
+        mm : '%d minuḍ',
+        h : 'saɛa',
+        hh : '%d tassaɛin',
+        d : 'ass',
+        dd : '%d ossan',
+        M : 'ayowr',
+        MM : '%d iyyirn',
+        y : 'asgas',
+        yy : '%d isgasn'
+    },
+    week : {
+        dow : 6, // Saturday is the first day of the week.
+        doy : 12  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/tzm.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/tzm.js
new file mode 100644
index 0000000000000000000000000000000000000000..663f85f4cb98deb68826755b0f55e43c1c0718b3
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/tzm.js
@@ -0,0 +1,49 @@
+//! moment.js locale configuration
+//! locale : Central Atlas Tamazight [tzm]
+//! author : Abdel Said : https://github.com/abdelsaid
+
+import moment from '../moment';
+
+export default moment.defineLocale('tzm', {
+    months : 'ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ'.split('_'),
+    monthsShort : 'ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ'.split('_'),
+    weekdays : 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'),
+    weekdaysShort : 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'),
+    weekdaysMin : 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS: 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[ⴰⵙⴷⵅ ⴴ] LT',
+        nextDay: '[ⴰⵙⴽⴰ ⴴ] LT',
+        nextWeek: 'dddd [â´´] LT',
+        lastDay: '[ⴰⵚⴰⵏⵜ ⴴ] LT',
+        lastWeek: 'dddd [â´´] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'ⴷⴰⴷⵅ ⵙ ⵢⴰⵏ %s',
+        past : 'ⵢⴰⵏ %s',
+        s : 'ⵉⵎⵉⴽ',
+        m : 'ⵎⵉⵏⵓⴺ',
+        mm : '%d ⵎⵉⵏⵓⴺ',
+        h : 'ⵙⴰⵄⴰ',
+        hh : '%d ⵜⴰⵙⵙⴰⵄⵉⵏ',
+        d : 'ⴰⵙⵙ',
+        dd : '%d oⵙⵙⴰⵏ',
+        M : 'ⴰⵢoⵓⵔ',
+        MM : '%d ⵉⵢⵢⵉⵔⵏ',
+        y : 'ⴰⵙⴳⴰⵙ',
+        yy : '%d ⵉⵙⴳⴰⵙⵏ'
+    },
+    week : {
+        dow : 6, // Saturday is the first day of the week.
+        doy : 12  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/uk.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/uk.js
new file mode 100644
index 0000000000000000000000000000000000000000..f5f793cfb4f2dc55423c9116994d698547784521
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/uk.js
@@ -0,0 +1,137 @@
+//! moment.js locale configuration
+//! locale : Ukrainian [uk]
+//! author : zemlanin : https://github.com/zemlanin
+//! Author : Menelion Elensúle : https://github.com/Oire
+
+import moment from '../moment';
+
+function plural(word, num) {
+    var forms = word.split('_');
+    return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]);
+}
+function relativeTimeWithPlural(number, withoutSuffix, key) {
+    var format = {
+        'mm': withoutSuffix ? 'хвилина_хвилини_хвилин' : 'хвилину_хвилини_хвилин',
+        'hh': withoutSuffix ? 'година_години_годин' : 'годину_години_годин',
+        'dd': 'день_дні_днів',
+        'MM': 'місяць_місяці_місяців',
+        'yy': 'рік_роки_років'
+    };
+    if (key === 'm') {
+        return withoutSuffix ? 'хвилина' : 'хвилину';
+    }
+    else if (key === 'h') {
+        return withoutSuffix ? 'година' : 'годину';
+    }
+    else {
+        return number + ' ' + plural(format[key], +number);
+    }
+}
+function weekdaysCaseReplace(m, format) {
+    var weekdays = {
+        'nominative': 'неділя_понеділок_вівторок_середа_четвер_п’ятниця_субота'.split('_'),
+        'accusative': 'неділю_понеділок_вівторок_середу_четвер_п’ятницю_суботу'.split('_'),
+        'genitive': 'неділі_понеділка_вівторка_середи_четверга_п’ятниці_суботи'.split('_')
+    },
+    nounCase = (/(\[[ВвУу]\]) ?dddd/).test(format) ?
+        'accusative' :
+        ((/\[?(?:минулої|наступної)? ?\] ?dddd/).test(format) ?
+            'genitive' :
+            'nominative');
+    return weekdays[nounCase][m.day()];
+}
+function processHoursFunction(str) {
+    return function () {
+        return str + 'о' + (this.hours() === 11 ? 'б' : '') + '] LT';
+    };
+}
+
+export default moment.defineLocale('uk', {
+    months : {
+        'format': 'січня_лютого_березня_квітня_травня_червня_липня_серпня_вересня_жовтня_листопада_грудня'.split('_'),
+        'standalone': 'січень_лютий_березень_квітень_травень_червень_липень_серпень_вересень_жовтень_листопад_грудень'.split('_')
+    },
+    monthsShort : 'січ_лют_бер_квіт_трав_черв_лип_серп_вер_жовт_лист_груд'.split('_'),
+    weekdays : weekdaysCaseReplace,
+    weekdaysShort : 'нд_пн_вт_ср_чт_пт_сб'.split('_'),
+    weekdaysMin : 'нд_пн_вт_ср_чт_пт_сб'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD.MM.YYYY',
+        LL : 'D MMMM YYYY р.',
+        LLL : 'D MMMM YYYY р., HH:mm',
+        LLLL : 'dddd, D MMMM YYYY р., HH:mm'
+    },
+    calendar : {
+        sameDay: processHoursFunction('[Сьогодні '),
+        nextDay: processHoursFunction('[Завтра '),
+        lastDay: processHoursFunction('[Вчора '),
+        nextWeek: processHoursFunction('[У] dddd ['),
+        lastWeek: function () {
+            switch (this.day()) {
+                case 0:
+                case 3:
+                case 5:
+                case 6:
+                    return processHoursFunction('[Минулої] dddd [').call(this);
+                case 1:
+                case 2:
+                case 4:
+                    return processHoursFunction('[Минулого] dddd [').call(this);
+            }
+        },
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : 'за %s',
+        past : '%s тому',
+        s : 'декілька секунд',
+        m : relativeTimeWithPlural,
+        mm : relativeTimeWithPlural,
+        h : 'годину',
+        hh : relativeTimeWithPlural,
+        d : 'день',
+        dd : relativeTimeWithPlural,
+        M : 'місяць',
+        MM : relativeTimeWithPlural,
+        y : 'рік',
+        yy : relativeTimeWithPlural
+    },
+    // M. E.: those two are virtually unused but a user might want to implement them for his/her website for some reason
+    meridiemParse: /ночі|ранку|дня|вечора/,
+    isPM: function (input) {
+        return /^(дня|вечора)$/.test(input);
+    },
+    meridiem : function (hour, minute, isLower) {
+        if (hour < 4) {
+            return 'ночі';
+        } else if (hour < 12) {
+            return 'ранку';
+        } else if (hour < 17) {
+            return 'дня';
+        } else {
+            return 'вечора';
+        }
+    },
+    ordinalParse: /\d{1,2}-(й|го)/,
+    ordinal: function (number, period) {
+        switch (period) {
+            case 'M':
+            case 'd':
+            case 'DDD':
+            case 'w':
+            case 'W':
+                return number + '-й';
+            case 'D':
+                return number + '-го';
+            default:
+                return number;
+        }
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 1st is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/uz.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/uz.js
new file mode 100644
index 0000000000000000000000000000000000000000..24a80e19031dcbfe6f663ddd9e47e1724bd7ccf4
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/uz.js
@@ -0,0 +1,49 @@
+//! moment.js locale configuration
+//! locale : Uzbek [uz]
+//! author : Sardor Muminov : https://github.com/muminoff
+
+import moment from '../moment';
+
+export default moment.defineLocale('uz', {
+    months : 'январ_феврал_март_апрел_май_июн_июл_август_сентябр_октябр_ноябр_декабр'.split('_'),
+    monthsShort : 'янв_фев_мар_апр_май_июн_июл_авг_сен_окт_ноя_дек'.split('_'),
+    weekdays : 'Якшанба_Душанба_Сешанба_Чоршанба_Пайшанба_Жума_Шанба'.split('_'),
+    weekdaysShort : 'Якш_Душ_Сеш_Чор_Пай_Жум_Шан'.split('_'),
+    weekdaysMin : 'Як_Ду_Се_Чо_Па_Жу_Ша'.split('_'),
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'D MMMM YYYY, dddd HH:mm'
+    },
+    calendar : {
+        sameDay : '[Бугун соат] LT [да]',
+        nextDay : '[Эртага] LT [да]',
+        nextWeek : 'dddd [куни соат] LT [да]',
+        lastDay : '[Кеча соат] LT [да]',
+        lastWeek : '[Утган] dddd [куни соат] LT [да]',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'Якин %s ичида',
+        past : 'Бир неча %s олдин',
+        s : 'фурсат',
+        m : 'бир дакика',
+        mm : '%d дакика',
+        h : 'бир соат',
+        hh : '%d соат',
+        d : 'бир кун',
+        dd : '%d кун',
+        M : 'бир ой',
+        MM : '%d ой',
+        y : 'бир йил',
+        yy : '%d йил'
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 7  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/vi.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/vi.js
new file mode 100644
index 0000000000000000000000000000000000000000..bbd81cada9ee31abd6338927dc670548ce1ab263
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/vi.js
@@ -0,0 +1,70 @@
+//! moment.js locale configuration
+//! locale : Vietnamese [vi]
+//! author : Bang Nguyen : https://github.com/bangnk
+
+import moment from '../moment';
+
+export default moment.defineLocale('vi', {
+    months : 'tháng 1_tháng 2_tháng 3_tháng 4_tháng 5_tháng 6_tháng 7_tháng 8_tháng 9_tháng 10_tháng 11_tháng 12'.split('_'),
+    monthsShort : 'Th01_Th02_Th03_Th04_Th05_Th06_Th07_Th08_Th09_Th10_Th11_Th12'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'chủ nhật_thứ hai_thứ ba_thứ tư_thứ năm_thứ sáu_thứ bảy'.split('_'),
+    weekdaysShort : 'CN_T2_T3_T4_T5_T6_T7'.split('_'),
+    weekdaysMin : 'CN_T2_T3_T4_T5_T6_T7'.split('_'),
+    weekdaysParseExact : true,
+    meridiemParse: /sa|ch/i,
+    isPM : function (input) {
+        return /^ch$/i.test(input);
+    },
+    meridiem : function (hours, minutes, isLower) {
+        if (hours < 12) {
+            return isLower ? 'sa' : 'SA';
+        } else {
+            return isLower ? 'ch' : 'CH';
+        }
+    },
+    longDateFormat : {
+        LT : 'HH:mm',
+        LTS : 'HH:mm:ss',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM [năm] YYYY',
+        LLL : 'D MMMM [năm] YYYY HH:mm',
+        LLLL : 'dddd, D MMMM [năm] YYYY HH:mm',
+        l : 'DD/M/YYYY',
+        ll : 'D MMM YYYY',
+        lll : 'D MMM YYYY HH:mm',
+        llll : 'ddd, D MMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay: '[Hôm nay lúc] LT',
+        nextDay: '[Ngày mai lúc] LT',
+        nextWeek: 'dddd [tuần tới lúc] LT',
+        lastDay: '[Hôm qua lúc] LT',
+        lastWeek: 'dddd [tuần rồi lúc] LT',
+        sameElse: 'L'
+    },
+    relativeTime : {
+        future : '%s tá»›i',
+        past : '%s trước',
+        s : 'vài giây',
+        m : 'một phút',
+        mm : '%d phút',
+        h : 'một giờ',
+        hh : '%d giờ',
+        d : 'một ngày',
+        dd : '%d ngày',
+        M : 'một tháng',
+        MM : '%d tháng',
+        y : 'một năm',
+        yy : '%d năm'
+    },
+    ordinalParse: /\d{1,2}/,
+    ordinal : function (number) {
+        return number;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/x-pseudo.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/x-pseudo.js
new file mode 100644
index 0000000000000000000000000000000000000000..008359eb51c346a9ac3665e2bc557332108f5517
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/x-pseudo.js
@@ -0,0 +1,58 @@
+//! moment.js locale configuration
+//! locale : Pseudo [x-pseudo]
+//! author : Andrew Hood : https://github.com/andrewhood125
+
+import moment from '../moment';
+
+export default moment.defineLocale('x-pseudo', {
+    months : 'J~áñúá~rý_F~ébrú~árý_~Márc~h_Áp~ríl_~Máý_~Júñé~_Júl~ý_Áú~gúst~_Sép~témb~ér_Ó~ctób~ér_Ñ~óvém~bér_~Décé~mbér'.split('_'),
+    monthsShort : 'J~áñ_~Féb_~Már_~Ápr_~Máý_~Júñ_~Júl_~Áúg_~Sép_~Óct_~Ñóv_~Déc'.split('_'),
+    monthsParseExact : true,
+    weekdays : 'S~úñdá~ý_Mó~ñdáý~_Túé~sdáý~_Wéd~ñésd~áý_T~húrs~dáý_~Fríd~áý_S~átúr~dáý'.split('_'),
+    weekdaysShort : 'S~úñ_~Móñ_~Túé_~Wéd_~Thú_~Frí_~Sát'.split('_'),
+    weekdaysMin : 'S~ú_Mó~_Tú_~Wé_T~h_Fr~_Sá'.split('_'),
+    weekdaysParseExact : true,
+    longDateFormat : {
+        LT : 'HH:mm',
+        L : 'DD/MM/YYYY',
+        LL : 'D MMMM YYYY',
+        LLL : 'D MMMM YYYY HH:mm',
+        LLLL : 'dddd, D MMMM YYYY HH:mm'
+    },
+    calendar : {
+        sameDay : '[T~ódá~ý át] LT',
+        nextDay : '[T~ómó~rró~w át] LT',
+        nextWeek : 'dddd [át] LT',
+        lastDay : '[Ý~ést~érdá~ý át] LT',
+        lastWeek : '[L~ást] dddd [át] LT',
+        sameElse : 'L'
+    },
+    relativeTime : {
+        future : 'í~ñ %s',
+        past : '%s á~gó',
+        s : 'á ~féw ~sécó~ñds',
+        m : 'á ~míñ~úté',
+        mm : '%d m~íñú~tés',
+        h : 'á~ñ hó~úr',
+        hh : '%d h~óúrs',
+        d : 'á ~dáý',
+        dd : '%d d~áýs',
+        M : 'á ~móñ~th',
+        MM : '%d m~óñt~hs',
+        y : 'á ~ýéár',
+        yy : '%d ý~éárs'
+    },
+    ordinalParse: /\d{1,2}(th|st|nd|rd)/,
+    ordinal : function (number) {
+        var b = number % 10,
+            output = (~~(number % 100 / 10) === 1) ? 'th' :
+            (b === 1) ? 'st' :
+            (b === 2) ? 'nd' :
+            (b === 3) ? 'rd' : 'th';
+        return number + output;
+    },
+    week : {
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/zh-cn.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/zh-cn.js
new file mode 100644
index 0000000000000000000000000000000000000000..031c50e664685cf5f7dc1d765ac0ed2245d7d72a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/zh-cn.js
@@ -0,0 +1,118 @@
+//! moment.js locale configuration
+//! locale : Chinese (China) [zh-cn]
+//! author : suupic : https://github.com/suupic
+//! author : Zeno Zeng : https://github.com/zenozeng
+
+import moment from '../moment';
+
+export default moment.defineLocale('zh-cn', {
+    months : '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'),
+    monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
+    weekdays : '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'),
+    weekdaysShort : '周日_周一_周二_周三_周四_周五_周六'.split('_'),
+    weekdaysMin : '日_一_二_三_四_五_六'.split('_'),
+    longDateFormat : {
+        LT : 'Ah点mm分',
+        LTS : 'Ah点m分s秒',
+        L : 'YYYY-MM-DD',
+        LL : 'YYYYå¹´MMMDæ—¥',
+        LLL : 'YYYY年MMMD日Ah点mm分',
+        LLLL : 'YYYY年MMMD日ddddAh点mm分',
+        l : 'YYYY-MM-DD',
+        ll : 'YYYYå¹´MMMDæ—¥',
+        lll : 'YYYY年MMMD日Ah点mm分',
+        llll : 'YYYY年MMMD日ddddAh点mm分'
+    },
+    meridiemParse: /凌晨|早上|上午|中午|下午|晚上/,
+    meridiemHour: function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === '凌晨' || meridiem === '早上' ||
+                meridiem === '上午') {
+            return hour;
+        } else if (meridiem === '下午' || meridiem === '晚上') {
+            return hour + 12;
+        } else {
+            // '中午'
+            return hour >= 11 ? hour : hour + 12;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        var hm = hour * 100 + minute;
+        if (hm < 600) {
+            return '凌晨';
+        } else if (hm < 900) {
+            return '早上';
+        } else if (hm < 1130) {
+            return '上午';
+        } else if (hm < 1230) {
+            return '中午';
+        } else if (hm < 1800) {
+            return '下午';
+        } else {
+            return '晚上';
+        }
+    },
+    calendar : {
+        sameDay : function () {
+            return this.minutes() === 0 ? '[今天]Ah[点整]' : '[今天]LT';
+        },
+        nextDay : function () {
+            return this.minutes() === 0 ? '[明天]Ah[点整]' : '[明天]LT';
+        },
+        lastDay : function () {
+            return this.minutes() === 0 ? '[昨天]Ah[点整]' : '[昨天]LT';
+        },
+        nextWeek : function () {
+            var startOfWeek, prefix;
+            startOfWeek = moment().startOf('week');
+            prefix = this.diff(startOfWeek, 'days') >= 7 ? '[下]' : '[本]';
+            return this.minutes() === 0 ? prefix + 'dddAh点整' : prefix + 'dddAh点mm';
+        },
+        lastWeek : function () {
+            var startOfWeek, prefix;
+            startOfWeek = moment().startOf('week');
+            prefix = this.unix() < startOfWeek.unix()  ? '[上]' : '[本]';
+            return this.minutes() === 0 ? prefix + 'dddAh点整' : prefix + 'dddAh点mm';
+        },
+        sameElse : 'LL'
+    },
+    ordinalParse: /\d{1,2}(日|月|周)/,
+    ordinal : function (number, period) {
+        switch (period) {
+            case 'd':
+            case 'D':
+            case 'DDD':
+                return number + 'æ—¥';
+            case 'M':
+                return number + '月';
+            case 'w':
+            case 'W':
+                return number + '周';
+            default:
+                return number;
+        }
+    },
+    relativeTime : {
+        future : '%s内',
+        past : '%s前',
+        s : '几秒',
+        m : '1 分钟',
+        mm : '%d 分钟',
+        h : '1 小时',
+        hh : '%d 小时',
+        d : '1 天',
+        dd : '%d 天',
+        M : '1 个月',
+        MM : '%d 个月',
+        y : '1 å¹´',
+        yy : '%d å¹´'
+    },
+    week : {
+        // GB/T 7408-1994《数据元和交换格式·信息交换·日期和时间表示法》与ISO 8601:1988等效
+        dow : 1, // Monday is the first day of the week.
+        doy : 4  // The week that contains Jan 4th is the first week of the year.
+    }
+});
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/zh-hk.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/zh-hk.js
new file mode 100644
index 0000000000000000000000000000000000000000..51d385d89afc1d53ba5b38c472deb90320bf14cc
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/zh-hk.js
@@ -0,0 +1,95 @@
+//! moment.js locale configuration
+//! locale : Chinese (Hong Kong) [zh-hk]
+//! author : Ben : https://github.com/ben-lin
+//! author : Chris Lam : https://github.com/hehachris
+//! author : Konstantin : https://github.com/skfd
+
+import moment from '../moment';
+
+export default moment.defineLocale('zh-hk', {
+    months : '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'),
+    monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
+    weekdays : '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'),
+    weekdaysShort : '週日_週一_週二_週三_週四_週五_週六'.split('_'),
+    weekdaysMin : '日_一_二_三_四_五_六'.split('_'),
+    longDateFormat : {
+        LT : 'Ah點mm分',
+        LTS : 'Ah點m分s秒',
+        L : 'YYYYå¹´MMMDæ—¥',
+        LL : 'YYYYå¹´MMMDæ—¥',
+        LLL : 'YYYY年MMMD日Ah點mm分',
+        LLLL : 'YYYY年MMMD日ddddAh點mm分',
+        l : 'YYYYå¹´MMMDæ—¥',
+        ll : 'YYYYå¹´MMMDæ—¥',
+        lll : 'YYYY年MMMD日Ah點mm分',
+        llll : 'YYYY年MMMD日ddddAh點mm分'
+    },
+    meridiemParse: /凌晨|早上|上午|中午|下午|晚上/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === '凌晨' || meridiem === '早上' || meridiem === '上午') {
+            return hour;
+        } else if (meridiem === '中午') {
+            return hour >= 11 ? hour : hour + 12;
+        } else if (meridiem === '下午' || meridiem === '晚上') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        var hm = hour * 100 + minute;
+        if (hm < 600) {
+            return '凌晨';
+        } else if (hm < 900) {
+            return '早上';
+        } else if (hm < 1130) {
+            return '上午';
+        } else if (hm < 1230) {
+            return '中午';
+        } else if (hm < 1800) {
+            return '下午';
+        } else {
+            return '晚上';
+        }
+    },
+    calendar : {
+        sameDay : '[今天]LT',
+        nextDay : '[明天]LT',
+        nextWeek : '[下]ddddLT',
+        lastDay : '[昨天]LT',
+        lastWeek : '[上]ddddLT',
+        sameElse : 'L'
+    },
+    ordinalParse: /\d{1,2}(日|月|週)/,
+    ordinal : function (number, period) {
+        switch (period) {
+            case 'd' :
+            case 'D' :
+            case 'DDD' :
+                return number + 'æ—¥';
+            case 'M' :
+                return number + '月';
+            case 'w' :
+            case 'W' :
+                return number + '週';
+            default :
+                return number;
+        }
+    },
+    relativeTime : {
+        future : '%så…§',
+        past : '%s前',
+        s : '幾秒',
+        m : '1 分鐘',
+        mm : '%d 分鐘',
+        h : '1 小時',
+        hh : '%d 小時',
+        d : '1 天',
+        dd : '%d 天',
+        M : '1 個月',
+        MM : '%d 個月',
+        y : '1 å¹´',
+        yy : '%d å¹´'
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/zh-tw.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/zh-tw.js
new file mode 100644
index 0000000000000000000000000000000000000000..577d61eb59f6765c493da43086417327ccc43127
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/locale/zh-tw.js
@@ -0,0 +1,94 @@
+//! moment.js locale configuration
+//! locale : Chinese (Taiwan) [zh-tw]
+//! author : Ben : https://github.com/ben-lin
+//! author : Chris Lam : https://github.com/hehachris
+
+import moment from '../moment';
+
+export default moment.defineLocale('zh-tw', {
+    months : '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'),
+    monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
+    weekdays : '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'),
+    weekdaysShort : '週日_週一_週二_週三_週四_週五_週六'.split('_'),
+    weekdaysMin : '日_一_二_三_四_五_六'.split('_'),
+    longDateFormat : {
+        LT : 'Ah點mm分',
+        LTS : 'Ah點m分s秒',
+        L : 'YYYYå¹´MMMDæ—¥',
+        LL : 'YYYYå¹´MMMDæ—¥',
+        LLL : 'YYYY年MMMD日Ah點mm分',
+        LLLL : 'YYYY年MMMD日ddddAh點mm分',
+        l : 'YYYYå¹´MMMDæ—¥',
+        ll : 'YYYYå¹´MMMDæ—¥',
+        lll : 'YYYY年MMMD日Ah點mm分',
+        llll : 'YYYY年MMMD日ddddAh點mm分'
+    },
+    meridiemParse: /凌晨|早上|上午|中午|下午|晚上/,
+    meridiemHour : function (hour, meridiem) {
+        if (hour === 12) {
+            hour = 0;
+        }
+        if (meridiem === '凌晨' || meridiem === '早上' || meridiem === '上午') {
+            return hour;
+        } else if (meridiem === '中午') {
+            return hour >= 11 ? hour : hour + 12;
+        } else if (meridiem === '下午' || meridiem === '晚上') {
+            return hour + 12;
+        }
+    },
+    meridiem : function (hour, minute, isLower) {
+        var hm = hour * 100 + minute;
+        if (hm < 600) {
+            return '凌晨';
+        } else if (hm < 900) {
+            return '早上';
+        } else if (hm < 1130) {
+            return '上午';
+        } else if (hm < 1230) {
+            return '中午';
+        } else if (hm < 1800) {
+            return '下午';
+        } else {
+            return '晚上';
+        }
+    },
+    calendar : {
+        sameDay : '[今天]LT',
+        nextDay : '[明天]LT',
+        nextWeek : '[下]ddddLT',
+        lastDay : '[昨天]LT',
+        lastWeek : '[上]ddddLT',
+        sameElse : 'L'
+    },
+    ordinalParse: /\d{1,2}(日|月|週)/,
+    ordinal : function (number, period) {
+        switch (period) {
+            case 'd' :
+            case 'D' :
+            case 'DDD' :
+                return number + 'æ—¥';
+            case 'M' :
+                return number + '月';
+            case 'w' :
+            case 'W' :
+                return number + '週';
+            default :
+                return number;
+        }
+    },
+    relativeTime : {
+        future : '%så…§',
+        past : '%s前',
+        s : '幾秒',
+        m : '1 分鐘',
+        mm : '%d 分鐘',
+        h : '1 小時',
+        hh : '%d 小時',
+        d : '1 天',
+        dd : '%d 天',
+        M : '1 個月',
+        MM : '%d 個月',
+        y : '1 å¹´',
+        yy : '%d å¹´'
+    }
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/moment.js b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/moment.js
new file mode 100644
index 0000000000000000000000000000000000000000..f87e507c8b0e424cbe425a055f8ae84291da601f
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/moment/src/moment.js
@@ -0,0 +1,82 @@
+//! moment.js
+//! version : 2.16.0
+//! authors : Tim Wood, Iskren Chernev, Moment.js contributors
+//! license : MIT
+//! momentjs.com
+
+import { hooks as moment, setHookCallback } from './lib/utils/hooks';
+
+moment.version = '2.16.0';
+
+import {
+    min,
+    max,
+    now,
+    isMoment,
+    momentPrototype as fn,
+    createUTC       as utc,
+    createUnix      as unix,
+    createLocal     as local,
+    createInvalid   as invalid,
+    createInZone    as parseZone
+} from './lib/moment/moment';
+
+import {
+    getCalendarFormat
+} from './lib/moment/calendar';
+
+import {
+    defineLocale,
+    updateLocale,
+    getSetGlobalLocale as locale,
+    getLocale          as localeData,
+    listLocales        as locales,
+    listMonths         as months,
+    listMonthsShort    as monthsShort,
+    listWeekdays       as weekdays,
+    listWeekdaysMin    as weekdaysMin,
+    listWeekdaysShort  as weekdaysShort
+} from './lib/locale/locale';
+
+import {
+    isDuration,
+    createDuration as duration,
+    getSetRelativeTimeRounding as relativeTimeRounding,
+    getSetRelativeTimeThreshold as relativeTimeThreshold
+} from './lib/duration/duration';
+
+import { normalizeUnits } from './lib/units/units';
+
+import isDate from './lib/utils/is-date';
+
+setHookCallback(local);
+
+moment.fn                    = fn;
+moment.min                   = min;
+moment.max                   = max;
+moment.now                   = now;
+moment.utc                   = utc;
+moment.unix                  = unix;
+moment.months                = months;
+moment.isDate                = isDate;
+moment.locale                = locale;
+moment.invalid               = invalid;
+moment.duration              = duration;
+moment.isMoment              = isMoment;
+moment.weekdays              = weekdays;
+moment.parseZone             = parseZone;
+moment.localeData            = localeData;
+moment.isDuration            = isDuration;
+moment.monthsShort           = monthsShort;
+moment.weekdaysMin           = weekdaysMin;
+moment.defineLocale          = defineLocale;
+moment.updateLocale          = updateLocale;
+moment.locales               = locales;
+moment.weekdaysShort         = weekdaysShort;
+moment.normalizeUnits        = normalizeUnits;
+moment.relativeTimeRounding = relativeTimeRounding;
+moment.relativeTimeThreshold = relativeTimeThreshold;
+moment.calendarFormat        = getCalendarFormat;
+moment.prototype             = fn;
+
+export default moment;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/ms/LICENSE.md b/KEMMessaging/node_modules/firebase-admin/node_modules/ms/LICENSE.md
new file mode 100644
index 0000000000000000000000000000000000000000..69b61253a38926757b7de1d4df4880fc2105c2c9
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/ms/LICENSE.md
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Zeit, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/ms/README.md b/KEMMessaging/node_modules/firebase-admin/node_modules/ms/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..5b475707d8aaf089849bc11aaa11d9baf9976fc1
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/ms/README.md
@@ -0,0 +1,52 @@
+# ms
+
+[![Build Status](https://travis-ci.org/zeit/ms.svg?branch=master)](https://travis-ci.org/zeit/ms)
+[![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/sindresorhus/xo)
+[![Slack Channel](https://zeit-slackin.now.sh/badge.svg)](https://zeit.chat/)
+
+Use this package to easily convert various time formats to milliseconds.
+
+## Examples
+
+```js
+ms('2 days')  // 172800000
+ms('1d')      // 86400000
+ms('10h')     // 36000000
+ms('2.5 hrs') // 9000000
+ms('2h')      // 7200000
+ms('1m')      // 60000
+ms('5s')      // 5000
+ms('1y')      // 31557600000
+ms('100')     // 100
+```
+
+### Convert from milliseconds
+
+```js
+ms(60000)             // "1m"
+ms(2 * 60000)         // "2m"
+ms(ms('10 hours'))    // "10h"
+```
+
+### Time format written-out
+
+```js
+ms(60000, { long: true })             // "1 minute"
+ms(2 * 60000, { long: true })         // "2 minutes"
+ms(ms('10 hours'), { long: true })    // "10 hours"
+```
+
+## Features
+
+- Works both in [node](https://nodejs.org) and in the browser.
+- If a number is supplied to `ms`, a string with a unit is returned.
+- If a string that contains the number is supplied, it returns it as a number (e.g.: it returns `100` for `'100'`).
+- If you pass a string with a number and a valid unit, the number of equivalent ms is returned.
+
+## Caught a bug?
+
+1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your own GitHub account and then [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device
+2. Link the package to the global module directory: `npm link`
+3. Within the module you want to test your local development instance of ms, just link it to the dependencies: `npm link ms`. Instead of the default one from npm, node will now use your clone of ms!
+
+As always, you can run the tests using: `npm test`
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/ms/index.js b/KEMMessaging/node_modules/firebase-admin/node_modules/ms/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..824b37ebac2ebd756ff8a431757e25cfbc8a3072
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/ms/index.js
@@ -0,0 +1,149 @@
+/**
+ * Helpers.
+ */
+
+var s = 1000
+var m = s * 60
+var h = m * 60
+var d = h * 24
+var y = d * 365.25
+
+/**
+ * Parse or format the given `val`.
+ *
+ * Options:
+ *
+ *  - `long` verbose formatting [false]
+ *
+ * @param {String|Number} val
+ * @param {Object} options
+ * @throws {Error} throw an error if val is not a non-empty string or a number
+ * @return {String|Number}
+ * @api public
+ */
+
+module.exports = function (val, options) {
+  options = options || {}
+  var type = typeof val
+  if (type === 'string' && val.length > 0) {
+    return parse(val)
+  } else if (type === 'number' && isNaN(val) === false) {
+    return options.long ?
+			fmtLong(val) :
+			fmtShort(val)
+  }
+  throw new Error('val is not a non-empty string or a valid number. val=' + JSON.stringify(val))
+}
+
+/**
+ * Parse the given `str` and return milliseconds.
+ *
+ * @param {String} str
+ * @return {Number}
+ * @api private
+ */
+
+function parse(str) {
+  str = String(str)
+  if (str.length > 10000) {
+    return
+  }
+  var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(str)
+  if (!match) {
+    return
+  }
+  var n = parseFloat(match[1])
+  var type = (match[2] || 'ms').toLowerCase()
+  switch (type) {
+    case 'years':
+    case 'year':
+    case 'yrs':
+    case 'yr':
+    case 'y':
+      return n * y
+    case 'days':
+    case 'day':
+    case 'd':
+      return n * d
+    case 'hours':
+    case 'hour':
+    case 'hrs':
+    case 'hr':
+    case 'h':
+      return n * h
+    case 'minutes':
+    case 'minute':
+    case 'mins':
+    case 'min':
+    case 'm':
+      return n * m
+    case 'seconds':
+    case 'second':
+    case 'secs':
+    case 'sec':
+    case 's':
+      return n * s
+    case 'milliseconds':
+    case 'millisecond':
+    case 'msecs':
+    case 'msec':
+    case 'ms':
+      return n
+    default:
+      return undefined
+  }
+}
+
+/**
+ * Short format for `ms`.
+ *
+ * @param {Number} ms
+ * @return {String}
+ * @api private
+ */
+
+function fmtShort(ms) {
+  if (ms >= d) {
+    return Math.round(ms / d) + 'd'
+  }
+  if (ms >= h) {
+    return Math.round(ms / h) + 'h'
+  }
+  if (ms >= m) {
+    return Math.round(ms / m) + 'm'
+  }
+  if (ms >= s) {
+    return Math.round(ms / s) + 's'
+  }
+  return ms + 'ms'
+}
+
+/**
+ * Long format for `ms`.
+ *
+ * @param {Number} ms
+ * @return {String}
+ * @api private
+ */
+
+function fmtLong(ms) {
+  return plural(ms, d, 'day') ||
+    plural(ms, h, 'hour') ||
+    plural(ms, m, 'minute') ||
+    plural(ms, s, 'second') ||
+    ms + ' ms'
+}
+
+/**
+ * Pluralization helper.
+ */
+
+function plural(ms, n, name) {
+  if (ms < n) {
+    return
+  }
+  if (ms < n * 1.5) {
+    return Math.floor(ms / n) + ' ' + name
+  }
+  return Math.ceil(ms / n) + ' ' + name + 's'
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/ms/package.json b/KEMMessaging/node_modules/firebase-admin/node_modules/ms/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..81023f68e899a3a1d28b9027000a13fa19c9b489
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/ms/package.json
@@ -0,0 +1,84 @@
+{
+  "_args": [
+    [
+      {
+        "raw": "ms@https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
+        "scope": null,
+        "escapedName": "ms",
+        "name": "ms",
+        "rawSpec": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
+        "spec": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
+        "type": "remote"
+      },
+      "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin"
+    ]
+  ],
+  "_from": "ms@>=0.7.1 <0.8.0",
+  "_id": "ms@0.7.2",
+  "_inCache": true,
+  "_location": "/firebase-admin/ms",
+  "_phantomChildren": {},
+  "_requested": {
+    "raw": "ms@https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
+    "scope": null,
+    "escapedName": "ms",
+    "name": "ms",
+    "rawSpec": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
+    "spec": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
+    "type": "remote"
+  },
+  "_requiredBy": [
+    "/firebase-admin",
+    "/firebase-admin/jsonwebtoken"
+  ],
+  "_resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
+  "_shasum": "ae25cf2512b3885a1d95d7f037868d8431124765",
+  "_shrinkwrap": null,
+  "_spec": "ms@https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
+  "_where": "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin",
+  "bugs": {
+    "url": "https://github.com/zeit/ms/issues"
+  },
+  "component": {
+    "scripts": {
+      "ms/index.js": "index.js"
+    }
+  },
+  "dependencies": {},
+  "description": "Tiny milisecond conversion utility",
+  "devDependencies": {
+    "expect.js": "^0.3.1",
+    "mocha": "^3.0.2",
+    "serve": "^1.4.0",
+    "xo": "^0.17.0"
+  },
+  "files": [
+    "index.js"
+  ],
+  "homepage": "https://github.com/zeit/ms#readme",
+  "license": "MIT",
+  "main": "./index",
+  "name": "ms",
+  "optionalDependencies": {},
+  "readme": "# ms\n\n[![Build Status](https://travis-ci.org/zeit/ms.svg?branch=master)](https://travis-ci.org/zeit/ms)\n[![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/sindresorhus/xo)\n[![Slack Channel](https://zeit-slackin.now.sh/badge.svg)](https://zeit.chat/)\n\nUse this package to easily convert various time formats to milliseconds.\n\n## Examples\n\n```js\nms('2 days')  // 172800000\nms('1d')      // 86400000\nms('10h')     // 36000000\nms('2.5 hrs') // 9000000\nms('2h')      // 7200000\nms('1m')      // 60000\nms('5s')      // 5000\nms('1y')      // 31557600000\nms('100')     // 100\n```\n\n### Convert from milliseconds\n\n```js\nms(60000)             // \"1m\"\nms(2 * 60000)         // \"2m\"\nms(ms('10 hours'))    // \"10h\"\n```\n\n### Time format written-out\n\n```js\nms(60000, { long: true })             // \"1 minute\"\nms(2 * 60000, { long: true })         // \"2 minutes\"\nms(ms('10 hours'), { long: true })    // \"10 hours\"\n```\n\n## Features\n\n- Works both in [node](https://nodejs.org) and in the browser.\n- If a number is supplied to `ms`, a string with a unit is returned.\n- If a string that contains the number is supplied, it returns it as a number (e.g.: it returns `100` for `'100'`).\n- If you pass a string with a number and a valid unit, the number of equivalent ms is returned.\n\n## Caught a bug?\n\n1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your own GitHub account and then [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device\n2. Link the package to the global module directory: `npm link`\n3. Within the module you want to test your local development instance of ms, just link it to the dependencies: `npm link ms`. Instead of the default one from npm, node will now use your clone of ms!\n\nAs always, you can run the tests using: `npm test`\n",
+  "readmeFilename": "README.md",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/zeit/ms.git"
+  },
+  "scripts": {
+    "test": "xo && mocha test/index.js",
+    "test-browser": "serve ./test"
+  },
+  "version": "0.7.2",
+  "xo": {
+    "space": true,
+    "semicolon": false,
+    "envs": [
+      "mocha"
+    ],
+    "rules": {
+      "complexity": 0
+    }
+  }
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/safe-buffer/.travis.yml b/KEMMessaging/node_modules/firebase-admin/node_modules/safe-buffer/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..7b20f28cb01a0ce5445a401c3ec1bc92f96fe10d
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/safe-buffer/.travis.yml
@@ -0,0 +1,7 @@
+language: node_js
+node_js:
+  - 'node'
+  - '5'
+  - '4'
+  - '0.12'
+  - '0.10'
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/safe-buffer/LICENSE b/KEMMessaging/node_modules/firebase-admin/node_modules/safe-buffer/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..0c068ceecbd48fc4e8279e6451793fec2bf12178
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/safe-buffer/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) Feross Aboukhadijeh
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/safe-buffer/README.md b/KEMMessaging/node_modules/firebase-admin/node_modules/safe-buffer/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..96eb387aa0858665c6745a92703623eb7f15a8bc
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/safe-buffer/README.md
@@ -0,0 +1,581 @@
+# safe-buffer [![travis][travis-image]][travis-url] [![npm][npm-image]][npm-url] [![downloads][downloads-image]][npm-url]
+
+#### Safer Node.js Buffer API
+
+**Use the new Node.js v6 Buffer APIs (`Buffer.from`, `Buffer.alloc`,
+`Buffer.allocUnsafe`, `Buffer.allocUnsafeSlow`) in Node.js v0.10, v0.12, v4.x, and v5.x.**
+
+**Uses the built-in implementations when available.**
+
+[travis-image]: https://img.shields.io/travis/feross/safe-buffer.svg
+[travis-url]: https://travis-ci.org/feross/safe-buffer
+[npm-image]: https://img.shields.io/npm/v/safe-buffer.svg
+[npm-url]: https://npmjs.org/package/safe-buffer
+[downloads-image]: https://img.shields.io/npm/dm/safe-buffer.svg
+
+## install
+
+```
+npm install safe-buffer
+```
+
+## usage
+
+The goal of this package is to provide a safe replacement for the node.js `Buffer`.
+
+It's a drop-in replacement for `Buffer`. You can use it by adding one `require` line to
+the top of your node.js modules:
+
+```js
+var Buffer = require('safe-buffer').Buffer
+
+// Existing buffer code will continue to work without issues:
+
+new Buffer('hey', 'utf8')
+new Buffer([1, 2, 3], 'utf8')
+new Buffer(obj)
+new Buffer(16) // create an uninitialized buffer (potentially unsafe)
+
+// But you can use these new explicit APIs to make clear what you want:
+
+Buffer.from('hey', 'utf8') // convert from many types to a Buffer
+Buffer.alloc(16) // create a zero-filled buffer (safe)
+Buffer.allocUnsafe(16) // create an uninitialized buffer (potentially unsafe)
+```
+
+## api
+
+### Class Method: Buffer.from(array)
+<!-- YAML
+added: v3.0.0
+-->
+
+* `array` {Array}
+
+Allocates a new `Buffer` using an `array` of octets.
+
+```js
+const buf = Buffer.from([0x62,0x75,0x66,0x66,0x65,0x72]);
+  // creates a new Buffer containing ASCII bytes
+  // ['b','u','f','f','e','r']
+```
+
+A `TypeError` will be thrown if `array` is not an `Array`.
+
+### Class Method: Buffer.from(arrayBuffer[, byteOffset[, length]])
+<!-- YAML
+added: v5.10.0
+-->
+
+* `arrayBuffer` {ArrayBuffer} The `.buffer` property of a `TypedArray` or
+  a `new ArrayBuffer()`
+* `byteOffset` {Number} Default: `0`
+* `length` {Number} Default: `arrayBuffer.length - byteOffset`
+
+When passed a reference to the `.buffer` property of a `TypedArray` instance,
+the newly created `Buffer` will share the same allocated memory as the
+TypedArray.
+
+```js
+const arr = new Uint16Array(2);
+arr[0] = 5000;
+arr[1] = 4000;
+
+const buf = Buffer.from(arr.buffer); // shares the memory with arr;
+
+console.log(buf);
+  // Prints: <Buffer 88 13 a0 0f>
+
+// changing the TypedArray changes the Buffer also
+arr[1] = 6000;
+
+console.log(buf);
+  // Prints: <Buffer 88 13 70 17>
+```
+
+The optional `byteOffset` and `length` arguments specify a memory range within
+the `arrayBuffer` that will be shared by the `Buffer`.
+
+```js
+const ab = new ArrayBuffer(10);
+const buf = Buffer.from(ab, 0, 2);
+console.log(buf.length);
+  // Prints: 2
+```
+
+A `TypeError` will be thrown if `arrayBuffer` is not an `ArrayBuffer`.
+
+### Class Method: Buffer.from(buffer)
+<!-- YAML
+added: v3.0.0
+-->
+
+* `buffer` {Buffer}
+
+Copies the passed `buffer` data onto a new `Buffer` instance.
+
+```js
+const buf1 = Buffer.from('buffer');
+const buf2 = Buffer.from(buf1);
+
+buf1[0] = 0x61;
+console.log(buf1.toString());
+  // 'auffer'
+console.log(buf2.toString());
+  // 'buffer' (copy is not changed)
+```
+
+A `TypeError` will be thrown if `buffer` is not a `Buffer`.
+
+### Class Method: Buffer.from(str[, encoding])
+<!-- YAML
+added: v5.10.0
+-->
+
+* `str` {String} String to encode.
+* `encoding` {String} Encoding to use, Default: `'utf8'`
+
+Creates a new `Buffer` containing the given JavaScript string `str`. If
+provided, the `encoding` parameter identifies the character encoding.
+If not provided, `encoding` defaults to `'utf8'`.
+
+```js
+const buf1 = Buffer.from('this is a tést');
+console.log(buf1.toString());
+  // prints: this is a tést
+console.log(buf1.toString('ascii'));
+  // prints: this is a tC)st
+
+const buf2 = Buffer.from('7468697320697320612074c3a97374', 'hex');
+console.log(buf2.toString());
+  // prints: this is a tést
+```
+
+A `TypeError` will be thrown if `str` is not a string.
+
+### Class Method: Buffer.alloc(size[, fill[, encoding]])
+<!-- YAML
+added: v5.10.0
+-->
+
+* `size` {Number}
+* `fill` {Value} Default: `undefined`
+* `encoding` {String} Default: `utf8`
+
+Allocates a new `Buffer` of `size` bytes. If `fill` is `undefined`, the
+`Buffer` will be *zero-filled*.
+
+```js
+const buf = Buffer.alloc(5);
+console.log(buf);
+  // <Buffer 00 00 00 00 00>
+```
+
+The `size` must be less than or equal to the value of
+`require('buffer').kMaxLength` (on 64-bit architectures, `kMaxLength` is
+`(2^31)-1`). Otherwise, a [`RangeError`][] is thrown. A zero-length Buffer will
+be created if a `size` less than or equal to 0 is specified.
+
+If `fill` is specified, the allocated `Buffer` will be initialized by calling
+`buf.fill(fill)`. See [`buf.fill()`][] for more information.
+
+```js
+const buf = Buffer.alloc(5, 'a');
+console.log(buf);
+  // <Buffer 61 61 61 61 61>
+```
+
+If both `fill` and `encoding` are specified, the allocated `Buffer` will be
+initialized by calling `buf.fill(fill, encoding)`. For example:
+
+```js
+const buf = Buffer.alloc(11, 'aGVsbG8gd29ybGQ=', 'base64');
+console.log(buf);
+  // <Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64>
+```
+
+Calling `Buffer.alloc(size)` can be significantly slower than the alternative
+`Buffer.allocUnsafe(size)` but ensures that the newly created `Buffer` instance
+contents will *never contain sensitive data*.
+
+A `TypeError` will be thrown if `size` is not a number.
+
+### Class Method: Buffer.allocUnsafe(size)
+<!-- YAML
+added: v5.10.0
+-->
+
+* `size` {Number}
+
+Allocates a new *non-zero-filled* `Buffer` of `size` bytes.  The `size` must
+be less than or equal to the value of `require('buffer').kMaxLength` (on 64-bit
+architectures, `kMaxLength` is `(2^31)-1`). Otherwise, a [`RangeError`][] is
+thrown. A zero-length Buffer will be created if a `size` less than or equal to
+0 is specified.
+
+The underlying memory for `Buffer` instances created in this way is *not
+initialized*. The contents of the newly created `Buffer` are unknown and
+*may contain sensitive data*. Use [`buf.fill(0)`][] to initialize such
+`Buffer` instances to zeroes.
+
+```js
+const buf = Buffer.allocUnsafe(5);
+console.log(buf);
+  // <Buffer 78 e0 82 02 01>
+  // (octets will be different, every time)
+buf.fill(0);
+console.log(buf);
+  // <Buffer 00 00 00 00 00>
+```
+
+A `TypeError` will be thrown if `size` is not a number.
+
+Note that the `Buffer` module pre-allocates an internal `Buffer` instance of
+size `Buffer.poolSize` that is used as a pool for the fast allocation of new
+`Buffer` instances created using `Buffer.allocUnsafe(size)` (and the deprecated
+`new Buffer(size)` constructor) only when `size` is less than or equal to
+`Buffer.poolSize >> 1` (floor of `Buffer.poolSize` divided by two). The default
+value of `Buffer.poolSize` is `8192` but can be modified.
+
+Use of this pre-allocated internal memory pool is a key difference between
+calling `Buffer.alloc(size, fill)` vs. `Buffer.allocUnsafe(size).fill(fill)`.
+Specifically, `Buffer.alloc(size, fill)` will *never* use the internal Buffer
+pool, while `Buffer.allocUnsafe(size).fill(fill)` *will* use the internal
+Buffer pool if `size` is less than or equal to half `Buffer.poolSize`. The
+difference is subtle but can be important when an application requires the
+additional performance that `Buffer.allocUnsafe(size)` provides.
+
+### Class Method: Buffer.allocUnsafeSlow(size)
+<!-- YAML
+added: v5.10.0
+-->
+
+* `size` {Number}
+
+Allocates a new *non-zero-filled* and non-pooled `Buffer` of `size` bytes.  The
+`size` must be less than or equal to the value of
+`require('buffer').kMaxLength` (on 64-bit architectures, `kMaxLength` is
+`(2^31)-1`). Otherwise, a [`RangeError`][] is thrown. A zero-length Buffer will
+be created if a `size` less than or equal to 0 is specified.
+
+The underlying memory for `Buffer` instances created in this way is *not
+initialized*. The contents of the newly created `Buffer` are unknown and
+*may contain sensitive data*. Use [`buf.fill(0)`][] to initialize such
+`Buffer` instances to zeroes.
+
+When using `Buffer.allocUnsafe()` to allocate new `Buffer` instances,
+allocations under 4KB are, by default, sliced from a single pre-allocated
+`Buffer`. This allows applications to avoid the garbage collection overhead of
+creating many individually allocated Buffers. This approach improves both
+performance and memory usage by eliminating the need to track and cleanup as
+many `Persistent` objects.
+
+However, in the case where a developer may need to retain a small chunk of
+memory from a pool for an indeterminate amount of time, it may be appropriate
+to create an un-pooled Buffer instance using `Buffer.allocUnsafeSlow()` then
+copy out the relevant bits.
+
+```js
+// need to keep around a few small chunks of memory
+const store = [];
+
+socket.on('readable', () => {
+  const data = socket.read();
+  // allocate for retained data
+  const sb = Buffer.allocUnsafeSlow(10);
+  // copy the data into the new allocation
+  data.copy(sb, 0, 0, 10);
+  store.push(sb);
+});
+```
+
+Use of `Buffer.allocUnsafeSlow()` should be used only as a last resort *after*
+a developer has observed undue memory retention in their applications.
+
+A `TypeError` will be thrown if `size` is not a number.
+
+### All the Rest
+
+The rest of the `Buffer` API is exactly the same as in node.js.
+[See the docs](https://nodejs.org/api/buffer.html).
+
+
+## Related links
+
+- [Node.js issue: Buffer(number) is unsafe](https://github.com/nodejs/node/issues/4660)
+- [Node.js Enhancement Proposal: Buffer.from/Buffer.alloc/Buffer.zalloc/Buffer() soft-deprecate](https://github.com/nodejs/node-eps/pull/4)
+
+## Why is `Buffer` unsafe?
+
+Today, the node.js `Buffer` constructor is overloaded to handle many different argument
+types like `String`, `Array`, `Object`, `TypedArrayView` (`Uint8Array`, etc.),
+`ArrayBuffer`, and also `Number`.
+
+The API is optimized for convenience: you can throw any type at it, and it will try to do
+what you want.
+
+Because the Buffer constructor is so powerful, you often see code like this:
+
+```js
+// Convert UTF-8 strings to hex
+function toHex (str) {
+  return new Buffer(str).toString('hex')
+}
+```
+
+***But what happens if `toHex` is called with a `Number` argument?***
+
+### Remote Memory Disclosure
+
+If an attacker can make your program call the `Buffer` constructor with a `Number`
+argument, then they can make it allocate uninitialized memory from the node.js process.
+This could potentially disclose TLS private keys, user data, or database passwords.
+
+When the `Buffer` constructor is passed a `Number` argument, it returns an
+**UNINITIALIZED** block of memory of the specified `size`. When you create a `Buffer` like
+this, you **MUST** overwrite the contents before returning it to the user.
+
+From the [node.js docs](https://nodejs.org/api/buffer.html#buffer_new_buffer_size):
+
+> `new Buffer(size)`
+>
+> - `size` Number
+>
+> The underlying memory for `Buffer` instances created in this way is not initialized.
+> **The contents of a newly created `Buffer` are unknown and could contain sensitive
+> data.** Use `buf.fill(0)` to initialize a Buffer to zeroes.
+
+(Emphasis our own.)
+
+Whenever the programmer intended to create an uninitialized `Buffer` you often see code
+like this:
+
+```js
+var buf = new Buffer(16)
+
+// Immediately overwrite the uninitialized buffer with data from another buffer
+for (var i = 0; i < buf.length; i++) {
+  buf[i] = otherBuf[i]
+}
+```
+
+
+### Would this ever be a problem in real code?
+
+Yes. It's surprisingly common to forget to check the type of your variables in a
+dynamically-typed language like JavaScript.
+
+Usually the consequences of assuming the wrong type is that your program crashes with an
+uncaught exception. But the failure mode for forgetting to check the type of arguments to
+the `Buffer` constructor is more catastrophic.
+
+Here's an example of a vulnerable service that takes a JSON payload and converts it to
+hex:
+
+```js
+// Take a JSON payload {str: "some string"} and convert it to hex
+var server = http.createServer(function (req, res) {
+  var data = ''
+  req.setEncoding('utf8')
+  req.on('data', function (chunk) {
+    data += chunk
+  })
+  req.on('end', function () {
+    var body = JSON.parse(data)
+    res.end(new Buffer(body.str).toString('hex'))
+  })
+})
+
+server.listen(8080)
+```
+
+In this example, an http client just has to send:
+
+```json
+{
+  "str": 1000
+}
+```
+
+and it will get back 1,000 bytes of uninitialized memory from the server.
+
+This is a very serious bug. It's similar in severity to the
+[the Heartbleed bug](http://heartbleed.com/) that allowed disclosure of OpenSSL process
+memory by remote attackers.
+
+
+### Which real-world packages were vulnerable?
+
+#### [`bittorrent-dht`](https://www.npmjs.com/package/bittorrent-dht)
+
+[Mathias Buus](https://github.com/mafintosh) and I
+([Feross Aboukhadijeh](http://feross.org/)) found this issue in one of our own packages,
+[`bittorrent-dht`](https://www.npmjs.com/package/bittorrent-dht). The bug would allow
+anyone on the internet to send a series of messages to a user of `bittorrent-dht` and get
+them to reveal 20 bytes at a time of uninitialized memory from the node.js process.
+
+Here's
+[the commit](https://github.com/feross/bittorrent-dht/commit/6c7da04025d5633699800a99ec3fbadf70ad35b8)
+that fixed it. We released a new fixed version, created a
+[Node Security Project disclosure](https://nodesecurity.io/advisories/68), and deprecated all
+vulnerable versions on npm so users will get a warning to upgrade to a newer version.
+
+#### [`ws`](https://www.npmjs.com/package/ws)
+
+That got us wondering if there were other vulnerable packages. Sure enough, within a short
+period of time, we found the same issue in [`ws`](https://www.npmjs.com/package/ws), the
+most popular WebSocket implementation in node.js.
+
+If certain APIs were called with `Number` parameters instead of `String` or `Buffer` as
+expected, then uninitialized server memory would be disclosed to the remote peer.
+
+These were the vulnerable methods:
+
+```js
+socket.send(number)
+socket.ping(number)
+socket.pong(number)
+```
+
+Here's a vulnerable socket server with some echo functionality:
+
+```js
+server.on('connection', function (socket) {
+  socket.on('message', function (message) {
+    message = JSON.parse(message)
+    if (message.type === 'echo') {
+      socket.send(message.data) // send back the user's message
+    }
+  })
+})
+```
+
+`socket.send(number)` called on the server, will disclose server memory.
+
+Here's [the release](https://github.com/websockets/ws/releases/tag/1.0.1) where the issue
+was fixed, with a more detailed explanation. Props to
+[Arnout Kazemier](https://github.com/3rd-Eden) for the quick fix. Here's the
+[Node Security Project disclosure](https://nodesecurity.io/advisories/67).
+
+
+### What's the solution?
+
+It's important that node.js offers a fast way to get memory otherwise performance-critical
+applications would needlessly get a lot slower.
+
+But we need a better way to *signal our intent* as programmers. **When we want
+uninitialized memory, we should request it explicitly.**
+
+Sensitive functionality should not be packed into a developer-friendly API that loosely
+accepts many different types. This type of API encourages the lazy practice of passing
+variables in without checking the type very carefully.
+
+#### A new API: `Buffer.allocUnsafe(number)`
+
+The functionality of creating buffers with uninitialized memory should be part of another
+API. We propose `Buffer.allocUnsafe(number)`. This way, it's not part of an API that
+frequently gets user input of all sorts of different types passed into it.
+
+```js
+var buf = Buffer.allocUnsafe(16) // careful, uninitialized memory!
+
+// Immediately overwrite the uninitialized buffer with data from another buffer
+for (var i = 0; i < buf.length; i++) {
+  buf[i] = otherBuf[i]
+}
+```
+
+
+### How do we fix node.js core?
+
+We sent [a PR to node.js core](https://github.com/nodejs/node/pull/4514) (merged as
+`semver-major`) which defends against one case:
+
+```js
+var str = 16
+new Buffer(str, 'utf8')
+```
+
+In this situation, it's implied that the programmer intended the first argument to be a
+string, since they passed an encoding as a second argument. Today, node.js will allocate
+uninitialized memory in the case of `new Buffer(number, encoding)`, which is probably not
+what the programmer intended.
+
+But this is only a partial solution, since if the programmer does `new Buffer(variable)`
+(without an `encoding` parameter) there's no way to know what they intended. If `variable`
+is sometimes a number, then uninitialized memory will sometimes be returned.
+
+### What's the real long-term fix?
+
+We could deprecate and remove `new Buffer(number)` and use `Buffer.allocUnsafe(number)` when
+we need uninitialized memory. But that would break 1000s of packages.
+
+~~We believe the best solution is to:~~
+
+~~1. Change `new Buffer(number)` to return safe, zeroed-out memory~~
+
+~~2. Create a new API for creating uninitialized Buffers. We propose: `Buffer.allocUnsafe(number)`~~
+
+#### Update
+
+We now support adding three new APIs:
+
+- `Buffer.from(value)` - convert from any type to a buffer
+- `Buffer.alloc(size)` - create a zero-filled buffer
+- `Buffer.allocUnsafe(size)` - create an uninitialized buffer with given size
+
+This solves the core problem that affected `ws` and `bittorrent-dht` which is
+`Buffer(variable)` getting tricked into taking a number argument.
+
+This way, existing code continues working and the impact on the npm ecosystem will be
+minimal. Over time, npm maintainers can migrate performance-critical code to use
+`Buffer.allocUnsafe(number)` instead of `new Buffer(number)`.
+
+
+### Conclusion
+
+We think there's a serious design issue with the `Buffer` API as it exists today. It
+promotes insecure software by putting high-risk functionality into a convenient API
+with friendly "developer ergonomics".
+
+This wasn't merely a theoretical exercise because we found the issue in some of the
+most popular npm packages.
+
+Fortunately, there's an easy fix that can be applied today. Use `safe-buffer` in place of
+`buffer`.
+
+```js
+var Buffer = require('safe-buffer').Buffer
+```
+
+Eventually, we hope that node.js core can switch to this new, safer behavior. We believe
+the impact on the ecosystem would be minimal since it's not a breaking change.
+Well-maintained, popular packages would be updated to use `Buffer.alloc` quickly, while
+older, insecure packages would magically become safe from this attack vector.
+
+
+## links
+
+- [Node.js PR: buffer: throw if both length and enc are passed](https://github.com/nodejs/node/pull/4514)
+- [Node Security Project disclosure for `ws`](https://nodesecurity.io/advisories/67)
+- [Node Security Project disclosure for`bittorrent-dht`](https://nodesecurity.io/advisories/68)
+
+
+## credit
+
+The original issues in `bittorrent-dht`
+([disclosure](https://nodesecurity.io/advisories/68)) and
+`ws` ([disclosure](https://nodesecurity.io/advisories/67)) were discovered by
+[Mathias Buus](https://github.com/mafintosh) and
+[Feross Aboukhadijeh](http://feross.org/).
+
+Thanks to [Adam Baldwin](https://github.com/evilpacket) for helping disclose these issues
+and for his work running the [Node Security Project](https://nodesecurity.io/).
+
+Thanks to [John Hiesey](https://github.com/jhiesey) for proofreading this README and
+auditing the code.
+
+
+## license
+
+MIT. Copyright (C) [Feross Aboukhadijeh](http://feross.org)
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/safe-buffer/browser.js b/KEMMessaging/node_modules/firebase-admin/node_modules/safe-buffer/browser.js
new file mode 100644
index 0000000000000000000000000000000000000000..0bd12027d30ff7bddbd4d78db61b27d344511cae
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/safe-buffer/browser.js
@@ -0,0 +1 @@
+module.exports = require('buffer')
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/safe-buffer/index.js b/KEMMessaging/node_modules/firebase-admin/node_modules/safe-buffer/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..74a7358ee82ac58bda839be95ced8e5333d2eead
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/safe-buffer/index.js
@@ -0,0 +1,58 @@
+var buffer = require('buffer')
+
+if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) {
+  module.exports = buffer
+} else {
+  // Copy properties from require('buffer')
+  Object.keys(buffer).forEach(function (prop) {
+    exports[prop] = buffer[prop]
+  })
+  exports.Buffer = SafeBuffer
+}
+
+function SafeBuffer (arg, encodingOrOffset, length) {
+  return Buffer(arg, encodingOrOffset, length)
+}
+
+// Copy static methods from Buffer
+Object.keys(Buffer).forEach(function (prop) {
+  SafeBuffer[prop] = Buffer[prop]
+})
+
+SafeBuffer.from = function (arg, encodingOrOffset, length) {
+  if (typeof arg === 'number') {
+    throw new TypeError('Argument must not be a number')
+  }
+  return Buffer(arg, encodingOrOffset, length)
+}
+
+SafeBuffer.alloc = function (size, fill, encoding) {
+  if (typeof size !== 'number') {
+    throw new TypeError('Argument must be a number')
+  }
+  var buf = Buffer(size)
+  if (fill !== undefined) {
+    if (typeof encoding === 'string') {
+      buf.fill(fill, encoding)
+    } else {
+      buf.fill(fill)
+    }
+  } else {
+    buf.fill(0)
+  }
+  return buf
+}
+
+SafeBuffer.allocUnsafe = function (size) {
+  if (typeof size !== 'number') {
+    throw new TypeError('Argument must be a number')
+  }
+  return Buffer(size)
+}
+
+SafeBuffer.allocUnsafeSlow = function (size) {
+  if (typeof size !== 'number') {
+    throw new TypeError('Argument must be a number')
+  }
+  return buffer.SlowBuffer(size)
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/safe-buffer/package.json b/KEMMessaging/node_modules/firebase-admin/node_modules/safe-buffer/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..b37be8a7bb2ab550ff41e04d132b316b6d79b8b6
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/safe-buffer/package.json
@@ -0,0 +1,80 @@
+{
+  "_args": [
+    [
+      {
+        "raw": "safe-buffer@https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz",
+        "scope": null,
+        "escapedName": "safe-buffer",
+        "name": "safe-buffer",
+        "rawSpec": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz",
+        "spec": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz",
+        "type": "remote"
+      },
+      "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin"
+    ]
+  ],
+  "_from": "safe-buffer@>=5.0.1 <6.0.0",
+  "_id": "safe-buffer@5.0.1",
+  "_inCache": true,
+  "_location": "/firebase-admin/safe-buffer",
+  "_phantomChildren": {},
+  "_requested": {
+    "raw": "safe-buffer@https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz",
+    "scope": null,
+    "escapedName": "safe-buffer",
+    "name": "safe-buffer",
+    "rawSpec": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz",
+    "spec": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz",
+    "type": "remote"
+  },
+  "_requiredBy": [
+    "/firebase-admin",
+    "/firebase-admin/jwa",
+    "/firebase-admin/jws"
+  ],
+  "_resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz",
+  "_shasum": "d263ca54696cd8a306b5ca6551e92de57918fbe7",
+  "_shrinkwrap": null,
+  "_spec": "safe-buffer@https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz",
+  "_where": "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin",
+  "author": {
+    "name": "Feross Aboukhadijeh",
+    "email": "feross@feross.org",
+    "url": "http://feross.org"
+  },
+  "browser": "./browser.js",
+  "bugs": {
+    "url": "https://github.com/feross/safe-buffer/issues"
+  },
+  "dependencies": {},
+  "description": "Safer Node.js Buffer API",
+  "devDependencies": {
+    "standard": "^7.0.0",
+    "tape": "^4.0.0",
+    "zuul": "^3.0.0"
+  },
+  "homepage": "https://github.com/feross/safe-buffer",
+  "keywords": [
+    "buffer",
+    "buffer allocate",
+    "node security",
+    "safe",
+    "safe-buffer",
+    "security",
+    "uninitialized"
+  ],
+  "license": "MIT",
+  "main": "index.js",
+  "name": "safe-buffer",
+  "optionalDependencies": {},
+  "readme": "# safe-buffer [![travis][travis-image]][travis-url] [![npm][npm-image]][npm-url] [![downloads][downloads-image]][npm-url]\n\n#### Safer Node.js Buffer API\n\n**Use the new Node.js v6 Buffer APIs (`Buffer.from`, `Buffer.alloc`,\n`Buffer.allocUnsafe`, `Buffer.allocUnsafeSlow`) in Node.js v0.10, v0.12, v4.x, and v5.x.**\n\n**Uses the built-in implementations when available.**\n\n[travis-image]: https://img.shields.io/travis/feross/safe-buffer.svg\n[travis-url]: https://travis-ci.org/feross/safe-buffer\n[npm-image]: https://img.shields.io/npm/v/safe-buffer.svg\n[npm-url]: https://npmjs.org/package/safe-buffer\n[downloads-image]: https://img.shields.io/npm/dm/safe-buffer.svg\n\n## install\n\n```\nnpm install safe-buffer\n```\n\n## usage\n\nThe goal of this package is to provide a safe replacement for the node.js `Buffer`.\n\nIt's a drop-in replacement for `Buffer`. You can use it by adding one `require` line to\nthe top of your node.js modules:\n\n```js\nvar Buffer = require('safe-buffer').Buffer\n\n// Existing buffer code will continue to work without issues:\n\nnew Buffer('hey', 'utf8')\nnew Buffer([1, 2, 3], 'utf8')\nnew Buffer(obj)\nnew Buffer(16) // create an uninitialized buffer (potentially unsafe)\n\n// But you can use these new explicit APIs to make clear what you want:\n\nBuffer.from('hey', 'utf8') // convert from many types to a Buffer\nBuffer.alloc(16) // create a zero-filled buffer (safe)\nBuffer.allocUnsafe(16) // create an uninitialized buffer (potentially unsafe)\n```\n\n## api\n\n### Class Method: Buffer.from(array)\n<!-- YAML\nadded: v3.0.0\n-->\n\n* `array` {Array}\n\nAllocates a new `Buffer` using an `array` of octets.\n\n```js\nconst buf = Buffer.from([0x62,0x75,0x66,0x66,0x65,0x72]);\n  // creates a new Buffer containing ASCII bytes\n  // ['b','u','f','f','e','r']\n```\n\nA `TypeError` will be thrown if `array` is not an `Array`.\n\n### Class Method: Buffer.from(arrayBuffer[, byteOffset[, length]])\n<!-- YAML\nadded: v5.10.0\n-->\n\n* `arrayBuffer` {ArrayBuffer} The `.buffer` property of a `TypedArray` or\n  a `new ArrayBuffer()`\n* `byteOffset` {Number} Default: `0`\n* `length` {Number} Default: `arrayBuffer.length - byteOffset`\n\nWhen passed a reference to the `.buffer` property of a `TypedArray` instance,\nthe newly created `Buffer` will share the same allocated memory as the\nTypedArray.\n\n```js\nconst arr = new Uint16Array(2);\narr[0] = 5000;\narr[1] = 4000;\n\nconst buf = Buffer.from(arr.buffer); // shares the memory with arr;\n\nconsole.log(buf);\n  // Prints: <Buffer 88 13 a0 0f>\n\n// changing the TypedArray changes the Buffer also\narr[1] = 6000;\n\nconsole.log(buf);\n  // Prints: <Buffer 88 13 70 17>\n```\n\nThe optional `byteOffset` and `length` arguments specify a memory range within\nthe `arrayBuffer` that will be shared by the `Buffer`.\n\n```js\nconst ab = new ArrayBuffer(10);\nconst buf = Buffer.from(ab, 0, 2);\nconsole.log(buf.length);\n  // Prints: 2\n```\n\nA `TypeError` will be thrown if `arrayBuffer` is not an `ArrayBuffer`.\n\n### Class Method: Buffer.from(buffer)\n<!-- YAML\nadded: v3.0.0\n-->\n\n* `buffer` {Buffer}\n\nCopies the passed `buffer` data onto a new `Buffer` instance.\n\n```js\nconst buf1 = Buffer.from('buffer');\nconst buf2 = Buffer.from(buf1);\n\nbuf1[0] = 0x61;\nconsole.log(buf1.toString());\n  // 'auffer'\nconsole.log(buf2.toString());\n  // 'buffer' (copy is not changed)\n```\n\nA `TypeError` will be thrown if `buffer` is not a `Buffer`.\n\n### Class Method: Buffer.from(str[, encoding])\n<!-- YAML\nadded: v5.10.0\n-->\n\n* `str` {String} String to encode.\n* `encoding` {String} Encoding to use, Default: `'utf8'`\n\nCreates a new `Buffer` containing the given JavaScript string `str`. If\nprovided, the `encoding` parameter identifies the character encoding.\nIf not provided, `encoding` defaults to `'utf8'`.\n\n```js\nconst buf1 = Buffer.from('this is a tést');\nconsole.log(buf1.toString());\n  // prints: this is a tést\nconsole.log(buf1.toString('ascii'));\n  // prints: this is a tC)st\n\nconst buf2 = Buffer.from('7468697320697320612074c3a97374', 'hex');\nconsole.log(buf2.toString());\n  // prints: this is a tést\n```\n\nA `TypeError` will be thrown if `str` is not a string.\n\n### Class Method: Buffer.alloc(size[, fill[, encoding]])\n<!-- YAML\nadded: v5.10.0\n-->\n\n* `size` {Number}\n* `fill` {Value} Default: `undefined`\n* `encoding` {String} Default: `utf8`\n\nAllocates a new `Buffer` of `size` bytes. If `fill` is `undefined`, the\n`Buffer` will be *zero-filled*.\n\n```js\nconst buf = Buffer.alloc(5);\nconsole.log(buf);\n  // <Buffer 00 00 00 00 00>\n```\n\nThe `size` must be less than or equal to the value of\n`require('buffer').kMaxLength` (on 64-bit architectures, `kMaxLength` is\n`(2^31)-1`). Otherwise, a [`RangeError`][] is thrown. A zero-length Buffer will\nbe created if a `size` less than or equal to 0 is specified.\n\nIf `fill` is specified, the allocated `Buffer` will be initialized by calling\n`buf.fill(fill)`. See [`buf.fill()`][] for more information.\n\n```js\nconst buf = Buffer.alloc(5, 'a');\nconsole.log(buf);\n  // <Buffer 61 61 61 61 61>\n```\n\nIf both `fill` and `encoding` are specified, the allocated `Buffer` will be\ninitialized by calling `buf.fill(fill, encoding)`. For example:\n\n```js\nconst buf = Buffer.alloc(11, 'aGVsbG8gd29ybGQ=', 'base64');\nconsole.log(buf);\n  // <Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64>\n```\n\nCalling `Buffer.alloc(size)` can be significantly slower than the alternative\n`Buffer.allocUnsafe(size)` but ensures that the newly created `Buffer` instance\ncontents will *never contain sensitive data*.\n\nA `TypeError` will be thrown if `size` is not a number.\n\n### Class Method: Buffer.allocUnsafe(size)\n<!-- YAML\nadded: v5.10.0\n-->\n\n* `size` {Number}\n\nAllocates a new *non-zero-filled* `Buffer` of `size` bytes.  The `size` must\nbe less than or equal to the value of `require('buffer').kMaxLength` (on 64-bit\narchitectures, `kMaxLength` is `(2^31)-1`). Otherwise, a [`RangeError`][] is\nthrown. A zero-length Buffer will be created if a `size` less than or equal to\n0 is specified.\n\nThe underlying memory for `Buffer` instances created in this way is *not\ninitialized*. The contents of the newly created `Buffer` are unknown and\n*may contain sensitive data*. Use [`buf.fill(0)`][] to initialize such\n`Buffer` instances to zeroes.\n\n```js\nconst buf = Buffer.allocUnsafe(5);\nconsole.log(buf);\n  // <Buffer 78 e0 82 02 01>\n  // (octets will be different, every time)\nbuf.fill(0);\nconsole.log(buf);\n  // <Buffer 00 00 00 00 00>\n```\n\nA `TypeError` will be thrown if `size` is not a number.\n\nNote that the `Buffer` module pre-allocates an internal `Buffer` instance of\nsize `Buffer.poolSize` that is used as a pool for the fast allocation of new\n`Buffer` instances created using `Buffer.allocUnsafe(size)` (and the deprecated\n`new Buffer(size)` constructor) only when `size` is less than or equal to\n`Buffer.poolSize >> 1` (floor of `Buffer.poolSize` divided by two). The default\nvalue of `Buffer.poolSize` is `8192` but can be modified.\n\nUse of this pre-allocated internal memory pool is a key difference between\ncalling `Buffer.alloc(size, fill)` vs. `Buffer.allocUnsafe(size).fill(fill)`.\nSpecifically, `Buffer.alloc(size, fill)` will *never* use the internal Buffer\npool, while `Buffer.allocUnsafe(size).fill(fill)` *will* use the internal\nBuffer pool if `size` is less than or equal to half `Buffer.poolSize`. The\ndifference is subtle but can be important when an application requires the\nadditional performance that `Buffer.allocUnsafe(size)` provides.\n\n### Class Method: Buffer.allocUnsafeSlow(size)\n<!-- YAML\nadded: v5.10.0\n-->\n\n* `size` {Number}\n\nAllocates a new *non-zero-filled* and non-pooled `Buffer` of `size` bytes.  The\n`size` must be less than or equal to the value of\n`require('buffer').kMaxLength` (on 64-bit architectures, `kMaxLength` is\n`(2^31)-1`). Otherwise, a [`RangeError`][] is thrown. A zero-length Buffer will\nbe created if a `size` less than or equal to 0 is specified.\n\nThe underlying memory for `Buffer` instances created in this way is *not\ninitialized*. The contents of the newly created `Buffer` are unknown and\n*may contain sensitive data*. Use [`buf.fill(0)`][] to initialize such\n`Buffer` instances to zeroes.\n\nWhen using `Buffer.allocUnsafe()` to allocate new `Buffer` instances,\nallocations under 4KB are, by default, sliced from a single pre-allocated\n`Buffer`. This allows applications to avoid the garbage collection overhead of\ncreating many individually allocated Buffers. This approach improves both\nperformance and memory usage by eliminating the need to track and cleanup as\nmany `Persistent` objects.\n\nHowever, in the case where a developer may need to retain a small chunk of\nmemory from a pool for an indeterminate amount of time, it may be appropriate\nto create an un-pooled Buffer instance using `Buffer.allocUnsafeSlow()` then\ncopy out the relevant bits.\n\n```js\n// need to keep around a few small chunks of memory\nconst store = [];\n\nsocket.on('readable', () => {\n  const data = socket.read();\n  // allocate for retained data\n  const sb = Buffer.allocUnsafeSlow(10);\n  // copy the data into the new allocation\n  data.copy(sb, 0, 0, 10);\n  store.push(sb);\n});\n```\n\nUse of `Buffer.allocUnsafeSlow()` should be used only as a last resort *after*\na developer has observed undue memory retention in their applications.\n\nA `TypeError` will be thrown if `size` is not a number.\n\n### All the Rest\n\nThe rest of the `Buffer` API is exactly the same as in node.js.\n[See the docs](https://nodejs.org/api/buffer.html).\n\n\n## Related links\n\n- [Node.js issue: Buffer(number) is unsafe](https://github.com/nodejs/node/issues/4660)\n- [Node.js Enhancement Proposal: Buffer.from/Buffer.alloc/Buffer.zalloc/Buffer() soft-deprecate](https://github.com/nodejs/node-eps/pull/4)\n\n## Why is `Buffer` unsafe?\n\nToday, the node.js `Buffer` constructor is overloaded to handle many different argument\ntypes like `String`, `Array`, `Object`, `TypedArrayView` (`Uint8Array`, etc.),\n`ArrayBuffer`, and also `Number`.\n\nThe API is optimized for convenience: you can throw any type at it, and it will try to do\nwhat you want.\n\nBecause the Buffer constructor is so powerful, you often see code like this:\n\n```js\n// Convert UTF-8 strings to hex\nfunction toHex (str) {\n  return new Buffer(str).toString('hex')\n}\n```\n\n***But what happens if `toHex` is called with a `Number` argument?***\n\n### Remote Memory Disclosure\n\nIf an attacker can make your program call the `Buffer` constructor with a `Number`\nargument, then they can make it allocate uninitialized memory from the node.js process.\nThis could potentially disclose TLS private keys, user data, or database passwords.\n\nWhen the `Buffer` constructor is passed a `Number` argument, it returns an\n**UNINITIALIZED** block of memory of the specified `size`. When you create a `Buffer` like\nthis, you **MUST** overwrite the contents before returning it to the user.\n\nFrom the [node.js docs](https://nodejs.org/api/buffer.html#buffer_new_buffer_size):\n\n> `new Buffer(size)`\n>\n> - `size` Number\n>\n> The underlying memory for `Buffer` instances created in this way is not initialized.\n> **The contents of a newly created `Buffer` are unknown and could contain sensitive\n> data.** Use `buf.fill(0)` to initialize a Buffer to zeroes.\n\n(Emphasis our own.)\n\nWhenever the programmer intended to create an uninitialized `Buffer` you often see code\nlike this:\n\n```js\nvar buf = new Buffer(16)\n\n// Immediately overwrite the uninitialized buffer with data from another buffer\nfor (var i = 0; i < buf.length; i++) {\n  buf[i] = otherBuf[i]\n}\n```\n\n\n### Would this ever be a problem in real code?\n\nYes. It's surprisingly common to forget to check the type of your variables in a\ndynamically-typed language like JavaScript.\n\nUsually the consequences of assuming the wrong type is that your program crashes with an\nuncaught exception. But the failure mode for forgetting to check the type of arguments to\nthe `Buffer` constructor is more catastrophic.\n\nHere's an example of a vulnerable service that takes a JSON payload and converts it to\nhex:\n\n```js\n// Take a JSON payload {str: \"some string\"} and convert it to hex\nvar server = http.createServer(function (req, res) {\n  var data = ''\n  req.setEncoding('utf8')\n  req.on('data', function (chunk) {\n    data += chunk\n  })\n  req.on('end', function () {\n    var body = JSON.parse(data)\n    res.end(new Buffer(body.str).toString('hex'))\n  })\n})\n\nserver.listen(8080)\n```\n\nIn this example, an http client just has to send:\n\n```json\n{\n  \"str\": 1000\n}\n```\n\nand it will get back 1,000 bytes of uninitialized memory from the server.\n\nThis is a very serious bug. It's similar in severity to the\n[the Heartbleed bug](http://heartbleed.com/) that allowed disclosure of OpenSSL process\nmemory by remote attackers.\n\n\n### Which real-world packages were vulnerable?\n\n#### [`bittorrent-dht`](https://www.npmjs.com/package/bittorrent-dht)\n\n[Mathias Buus](https://github.com/mafintosh) and I\n([Feross Aboukhadijeh](http://feross.org/)) found this issue in one of our own packages,\n[`bittorrent-dht`](https://www.npmjs.com/package/bittorrent-dht). The bug would allow\nanyone on the internet to send a series of messages to a user of `bittorrent-dht` and get\nthem to reveal 20 bytes at a time of uninitialized memory from the node.js process.\n\nHere's\n[the commit](https://github.com/feross/bittorrent-dht/commit/6c7da04025d5633699800a99ec3fbadf70ad35b8)\nthat fixed it. We released a new fixed version, created a\n[Node Security Project disclosure](https://nodesecurity.io/advisories/68), and deprecated all\nvulnerable versions on npm so users will get a warning to upgrade to a newer version.\n\n#### [`ws`](https://www.npmjs.com/package/ws)\n\nThat got us wondering if there were other vulnerable packages. Sure enough, within a short\nperiod of time, we found the same issue in [`ws`](https://www.npmjs.com/package/ws), the\nmost popular WebSocket implementation in node.js.\n\nIf certain APIs were called with `Number` parameters instead of `String` or `Buffer` as\nexpected, then uninitialized server memory would be disclosed to the remote peer.\n\nThese were the vulnerable methods:\n\n```js\nsocket.send(number)\nsocket.ping(number)\nsocket.pong(number)\n```\n\nHere's a vulnerable socket server with some echo functionality:\n\n```js\nserver.on('connection', function (socket) {\n  socket.on('message', function (message) {\n    message = JSON.parse(message)\n    if (message.type === 'echo') {\n      socket.send(message.data) // send back the user's message\n    }\n  })\n})\n```\n\n`socket.send(number)` called on the server, will disclose server memory.\n\nHere's [the release](https://github.com/websockets/ws/releases/tag/1.0.1) where the issue\nwas fixed, with a more detailed explanation. Props to\n[Arnout Kazemier](https://github.com/3rd-Eden) for the quick fix. Here's the\n[Node Security Project disclosure](https://nodesecurity.io/advisories/67).\n\n\n### What's the solution?\n\nIt's important that node.js offers a fast way to get memory otherwise performance-critical\napplications would needlessly get a lot slower.\n\nBut we need a better way to *signal our intent* as programmers. **When we want\nuninitialized memory, we should request it explicitly.**\n\nSensitive functionality should not be packed into a developer-friendly API that loosely\naccepts many different types. This type of API encourages the lazy practice of passing\nvariables in without checking the type very carefully.\n\n#### A new API: `Buffer.allocUnsafe(number)`\n\nThe functionality of creating buffers with uninitialized memory should be part of another\nAPI. We propose `Buffer.allocUnsafe(number)`. This way, it's not part of an API that\nfrequently gets user input of all sorts of different types passed into it.\n\n```js\nvar buf = Buffer.allocUnsafe(16) // careful, uninitialized memory!\n\n// Immediately overwrite the uninitialized buffer with data from another buffer\nfor (var i = 0; i < buf.length; i++) {\n  buf[i] = otherBuf[i]\n}\n```\n\n\n### How do we fix node.js core?\n\nWe sent [a PR to node.js core](https://github.com/nodejs/node/pull/4514) (merged as\n`semver-major`) which defends against one case:\n\n```js\nvar str = 16\nnew Buffer(str, 'utf8')\n```\n\nIn this situation, it's implied that the programmer intended the first argument to be a\nstring, since they passed an encoding as a second argument. Today, node.js will allocate\nuninitialized memory in the case of `new Buffer(number, encoding)`, which is probably not\nwhat the programmer intended.\n\nBut this is only a partial solution, since if the programmer does `new Buffer(variable)`\n(without an `encoding` parameter) there's no way to know what they intended. If `variable`\nis sometimes a number, then uninitialized memory will sometimes be returned.\n\n### What's the real long-term fix?\n\nWe could deprecate and remove `new Buffer(number)` and use `Buffer.allocUnsafe(number)` when\nwe need uninitialized memory. But that would break 1000s of packages.\n\n~~We believe the best solution is to:~~\n\n~~1. Change `new Buffer(number)` to return safe, zeroed-out memory~~\n\n~~2. Create a new API for creating uninitialized Buffers. We propose: `Buffer.allocUnsafe(number)`~~\n\n#### Update\n\nWe now support adding three new APIs:\n\n- `Buffer.from(value)` - convert from any type to a buffer\n- `Buffer.alloc(size)` - create a zero-filled buffer\n- `Buffer.allocUnsafe(size)` - create an uninitialized buffer with given size\n\nThis solves the core problem that affected `ws` and `bittorrent-dht` which is\n`Buffer(variable)` getting tricked into taking a number argument.\n\nThis way, existing code continues working and the impact on the npm ecosystem will be\nminimal. Over time, npm maintainers can migrate performance-critical code to use\n`Buffer.allocUnsafe(number)` instead of `new Buffer(number)`.\n\n\n### Conclusion\n\nWe think there's a serious design issue with the `Buffer` API as it exists today. It\npromotes insecure software by putting high-risk functionality into a convenient API\nwith friendly \"developer ergonomics\".\n\nThis wasn't merely a theoretical exercise because we found the issue in some of the\nmost popular npm packages.\n\nFortunately, there's an easy fix that can be applied today. Use `safe-buffer` in place of\n`buffer`.\n\n```js\nvar Buffer = require('safe-buffer').Buffer\n```\n\nEventually, we hope that node.js core can switch to this new, safer behavior. We believe\nthe impact on the ecosystem would be minimal since it's not a breaking change.\nWell-maintained, popular packages would be updated to use `Buffer.alloc` quickly, while\nolder, insecure packages would magically become safe from this attack vector.\n\n\n## links\n\n- [Node.js PR: buffer: throw if both length and enc are passed](https://github.com/nodejs/node/pull/4514)\n- [Node Security Project disclosure for `ws`](https://nodesecurity.io/advisories/67)\n- [Node Security Project disclosure for`bittorrent-dht`](https://nodesecurity.io/advisories/68)\n\n\n## credit\n\nThe original issues in `bittorrent-dht`\n([disclosure](https://nodesecurity.io/advisories/68)) and\n`ws` ([disclosure](https://nodesecurity.io/advisories/67)) were discovered by\n[Mathias Buus](https://github.com/mafintosh) and\n[Feross Aboukhadijeh](http://feross.org/).\n\nThanks to [Adam Baldwin](https://github.com/evilpacket) for helping disclose these issues\nand for his work running the [Node Security Project](https://nodesecurity.io/).\n\nThanks to [John Hiesey](https://github.com/jhiesey) for proofreading this README and\nauditing the code.\n\n\n## license\n\nMIT. Copyright (C) [Feross Aboukhadijeh](http://feross.org)\n",
+  "readmeFilename": "README.md",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/feross/safe-buffer.git"
+  },
+  "scripts": {
+    "test": "standard && tape test.js"
+  },
+  "version": "5.0.1"
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/safe-buffer/test.js b/KEMMessaging/node_modules/firebase-admin/node_modules/safe-buffer/test.js
new file mode 100644
index 0000000000000000000000000000000000000000..7da8ad761ee720bab57c1315453378fc5c524e0d
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/safe-buffer/test.js
@@ -0,0 +1,99 @@
+var test = require('tape')
+var SafeBuffer = require('./').Buffer
+
+test('new SafeBuffer(value) works just like Buffer', function (t) {
+  t.deepEqual(new SafeBuffer('hey'), new Buffer('hey'))
+  t.deepEqual(new SafeBuffer('hey', 'utf8'), new Buffer('hey', 'utf8'))
+  t.deepEqual(new SafeBuffer('686579', 'hex'), new Buffer('686579', 'hex'))
+  t.deepEqual(new SafeBuffer([1, 2, 3]), new Buffer([1, 2, 3]))
+  t.deepEqual(new SafeBuffer(new Uint8Array([1, 2, 3])), new Buffer(new Uint8Array([1, 2, 3])))
+
+  t.equal(typeof SafeBuffer.isBuffer, 'function')
+  t.equal(SafeBuffer.isBuffer(new SafeBuffer('hey')), true)
+  t.equal(Buffer.isBuffer(new SafeBuffer('hey')), true)
+  t.notOk(SafeBuffer.isBuffer({}))
+
+  t.end()
+})
+
+test('SafeBuffer.from(value) converts to a Buffer', function (t) {
+  t.deepEqual(SafeBuffer.from('hey'), new Buffer('hey'))
+  t.deepEqual(SafeBuffer.from('hey', 'utf8'), new Buffer('hey', 'utf8'))
+  t.deepEqual(SafeBuffer.from('686579', 'hex'), new Buffer('686579', 'hex'))
+  t.deepEqual(SafeBuffer.from([1, 2, 3]), new Buffer([1, 2, 3]))
+  t.deepEqual(SafeBuffer.from(new Uint8Array([1, 2, 3])), new Buffer(new Uint8Array([1, 2, 3])))
+
+  t.end()
+})
+
+test('SafeBuffer.alloc(number) returns zeroed-out memory', function (t) {
+  for (var i = 0; i < 10; i++) {
+    var expected1 = new Buffer(1000)
+    expected1.fill(0)
+    t.deepEqual(SafeBuffer.alloc(1000), expected1)
+
+    var expected2 = new Buffer(1000 * 1000)
+    expected2.fill(0)
+    t.deepEqual(SafeBuffer.alloc(1000 * 1000), expected2)
+  }
+  t.end()
+})
+
+test('SafeBuffer.allocUnsafe(number)', function (t) {
+  var buf = SafeBuffer.allocUnsafe(100) // unitialized memory
+  t.equal(buf.length, 100)
+  t.equal(SafeBuffer.isBuffer(buf), true)
+  t.equal(Buffer.isBuffer(buf), true)
+  t.end()
+})
+
+test('SafeBuffer.from() throws with number types', function (t) {
+  t.plan(5)
+  t.throws(function () {
+    SafeBuffer.from(0)
+  })
+  t.throws(function () {
+    SafeBuffer.from(-1)
+  })
+  t.throws(function () {
+    SafeBuffer.from(NaN)
+  })
+  t.throws(function () {
+    SafeBuffer.from(Infinity)
+  })
+  t.throws(function () {
+    SafeBuffer.from(99)
+  })
+})
+
+test('SafeBuffer.allocUnsafe() throws with non-number types', function (t) {
+  t.plan(4)
+  t.throws(function () {
+    SafeBuffer.allocUnsafe('hey')
+  })
+  t.throws(function () {
+    SafeBuffer.allocUnsafe('hey', 'utf8')
+  })
+  t.throws(function () {
+    SafeBuffer.allocUnsafe([1, 2, 3])
+  })
+  t.throws(function () {
+    SafeBuffer.allocUnsafe({})
+  })
+})
+
+test('SafeBuffer.alloc() throws with non-number types', function (t) {
+  t.plan(4)
+  t.throws(function () {
+    SafeBuffer.alloc('hey')
+  })
+  t.throws(function () {
+    SafeBuffer.alloc('hey', 'utf8')
+  })
+  t.throws(function () {
+    SafeBuffer.alloc([1, 2, 3])
+  })
+  t.throws(function () {
+    SafeBuffer.alloc({})
+  })
+})
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/topo/.npmignore b/KEMMessaging/node_modules/firebase-admin/node_modules/topo/.npmignore
new file mode 100644
index 0000000000000000000000000000000000000000..7e1574dc5c3c81d41c152e95b3c538613e69f19f
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/topo/.npmignore
@@ -0,0 +1,18 @@
+.idea
+*.iml
+npm-debug.log
+dump.rdb
+node_modules
+results.tap
+results.xml
+npm-shrinkwrap.json
+config.json
+.DS_Store
+*/.DS_Store
+*/*/.DS_Store
+._*
+*/._*
+*/*/._*
+coverage.*
+lib-cov
+complexity.md
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/topo/.travis.yml b/KEMMessaging/node_modules/firebase-admin/node_modules/topo/.travis.yml
new file mode 100755
index 0000000000000000000000000000000000000000..ca495f9e36266a68eb8dbe86f059697cfa06d57e
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/topo/.travis.yml
@@ -0,0 +1,9 @@
+language: node_js
+
+node_js:
+  - 0.10
+  - 4.0
+  - 4
+
+sudo: false
+
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/topo/API.md b/KEMMessaging/node_modules/firebase-admin/node_modules/topo/API.md
new file mode 100755
index 0000000000000000000000000000000000000000..2b9c3547026e3c5f0019ac2429440ba7606a2b28
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/topo/API.md
@@ -0,0 +1,32 @@
+# API Reference
+
+## `Topo`
+The `Topo` object is the container for topologically sorting a list of nodes with non-circular interdependencies.
+
+### `new Topo()`
+Creates a new `Topo` object.
+
+### `topo.add(nodes, [options])`
+Specifies an additional node or list of nodes to be topologically sorted where:
+  - `nodes` - a mixed value or array of mixed values to be added as nodes to the topologically sorted list.
+  - `options` - optional sorting information about the `nodes`:
+    - `group` - a string naming the group to which `nodes` should be assigned.  The group name `'?'` is reserved.
+    - `before` - a string or array of strings specifying the groups that `nodes` must precede in the topological sort.
+    - `after` - a string or array of strings specifying the groups that `nodes` must succeed in the topological sort.
+    - `sort` - a numerical value used to sort items when performing a `topo.merge()`.
+
+Returns an array of the topologically sorted nodes.
+
+### `topo.nodes`
+An array of the topologically sorted nodes.  This list is renewed upon each call to [`topo.add()`](#topoaddnodes-options).
+
+### `topo.merge(others)`
+Merges another `Topo` object into the current object where:
+- `others` - the other object or array of objects to be merged into the current one. `null`
+  values are ignored.
+
+Returns an array of the topologically sorted nodes. Will throw if a dependency error is found as a result of the
+combined items.
+
+If the order in which items have been added to each list matters, use the `sort` option in `topo.add()` with an incrementing
+value providing an absolute sort order among all items added to either object.
\ No newline at end of file
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/topo/CONTRIBUTING.md b/KEMMessaging/node_modules/firebase-admin/node_modules/topo/CONTRIBUTING.md
new file mode 100755
index 0000000000000000000000000000000000000000..058cc93695a6047e91f646e5dcae468212a1164e
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/topo/CONTRIBUTING.md
@@ -0,0 +1,16 @@
+# How to contribute
+We welcome contributions from the community and are pleased to have them.  Please follow this guide when logging issues or making code changes.
+
+## Logging Issues
+All issues should be created using the [new issue form](https://github.com/hapijs/topo/issues/new). Clearly describe the issue including steps
+to reproduce if there are any. Also, make sure to indicate the earliest version that has the issue being reported.
+
+## Patching Code
+
+Code changes are welcome and should follow the guidelines below.
+
+* Fork the repository on GitHub.
+* Fix the issue ensuring that your code follows the [style guide](https://github.com/hapijs/contrib/blob/master/Style.md).
+* Add tests for your new code ensuring that you have 100% code coverage (we can help you reach 100% but will not merge without it).
+    * Run `npm test` to generate a report of test coverage
+* [Pull requests](http://help.github.com/send-pull-requests/) should be made to the [master branch](https://github.com/hapijs/topo/tree/master).
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/topo/LICENSE b/KEMMessaging/node_modules/firebase-admin/node_modules/topo/LICENSE
new file mode 100755
index 0000000000000000000000000000000000000000..27d182218bc78b555ac810979e9fd23362dc6816
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/topo/LICENSE
@@ -0,0 +1,28 @@
+Copyright (c) 2012-2014, Walmart and other contributors.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * The names of any contributors may not be used to endorse or promote
+      products derived from this software without specific prior written
+      permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+                                  *   *   *
+
+The complete list of contributors can be found at: https://github.com/hapijs/topo/graphs/contributors
\ No newline at end of file
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/topo/README.md b/KEMMessaging/node_modules/firebase-admin/node_modules/topo/README.md
new file mode 100755
index 0000000000000000000000000000000000000000..bcc33f34679d35d8030f47cd335e3c4276ac73dd
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/topo/README.md
@@ -0,0 +1,29 @@
+# topo
+
+Topological sorting with grouping support.
+
+[![Build Status](https://secure.travis-ci.org/hapijs/topo.png)](http://travis-ci.org/hapijs/topo)
+
+Lead Maintainer: [Devin Ivy](https://github.com/devinivy)
+
+## Usage
+
+See the [API Reference](API.md)
+
+**Example**
+```node
+var Topo = require('topo');
+
+var morning = new Topo();
+
+morning.add('Nap', { after: ['breakfast', 'prep'] });
+
+morning.add([
+    'Make toast',
+    'Pour juice'
+], { before: 'breakfast', group: 'prep' });
+
+morning.add('Eat breakfast', { group: 'breakfast' });
+
+morning.nodes;        // ['Make toast', 'Pour juice', 'Eat breakfast', 'Nap']
+```
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/topo/lib/index.js b/KEMMessaging/node_modules/firebase-admin/node_modules/topo/lib/index.js
new file mode 100755
index 0000000000000000000000000000000000000000..434c32f994a7b4df7e4d369892e51510626c71cb
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/topo/lib/index.js
@@ -0,0 +1,231 @@
+// Load modules
+
+var Hoek = require('hoek');
+
+
+// Declare internals
+
+var internals = {};
+
+
+exports = module.exports = internals.Topo = function () {
+
+    this._items = [];
+    this.nodes = [];
+};
+
+
+internals.Topo.prototype.add = function (nodes, options) {
+
+    var self = this;
+
+    options = options || {};
+
+    // Validate rules
+
+    var before = [].concat(options.before || []);
+    var after = [].concat(options.after || []);
+    var group = options.group || '?';
+    var sort = options.sort || 0;                   // Used for merging only
+
+    Hoek.assert(before.indexOf(group) === -1, 'Item cannot come before itself:', group);
+    Hoek.assert(before.indexOf('?') === -1, 'Item cannot come before unassociated items');
+    Hoek.assert(after.indexOf(group) === -1, 'Item cannot come after itself:', group);
+    Hoek.assert(after.indexOf('?') === -1, 'Item cannot come after unassociated items');
+
+    ([].concat(nodes)).forEach(function (node, i) {
+
+        var item = {
+            seq: self._items.length,
+            sort: sort,
+            before: before,
+            after: after,
+            group: group,
+            node: node
+        };
+
+        self._items.push(item);
+    });
+
+    // Insert event
+
+    var error = this._sort();
+    Hoek.assert(!error, 'item', (group !== '?' ? 'added into group ' + group : ''), 'created a dependencies error');
+
+    return this.nodes;
+};
+
+
+internals.Topo.prototype.merge = function (others) {
+
+    others = [].concat(others);
+    for (var o = 0, ol = others.length; o < ol; ++o) {
+        var other = others[o];
+        if (other) {
+            for (var i = 0, il = other._items.length; i < il; ++i) {
+                var item = Hoek.shallow(other._items[i]);
+                this._items.push(item);
+            }
+        }
+    }
+
+    // Sort items
+
+    this._items.sort(internals.mergeSort);
+    for (i = 0, il = this._items.length; i < il; ++i) {
+        this._items[i].seq = i;
+    }
+
+    var error = this._sort();
+    Hoek.assert(!error, 'merge created a dependencies error');
+
+    return this.nodes;
+};
+
+
+internals.mergeSort = function (a, b) {
+
+    return a.sort === b.sort ? 0 : (a.sort < b.sort ? -1 : 1);
+};
+
+
+internals.Topo.prototype._sort = function () {
+
+    // Construct graph
+
+    var groups = {};
+    var graph = {};
+    var graphAfters = {};
+
+    for (var i = 0, il = this._items.length; i < il; ++i) {
+        var item = this._items[i];
+        var seq = item.seq;                         // Unique across all items
+        var group = item.group;
+
+        // Determine Groups
+
+        groups[group] = groups[group] || [];
+        groups[group].push(seq);
+
+        // Build intermediary graph using 'before'
+
+        graph[seq] = item.before;
+
+        // Build second intermediary graph with 'after'
+
+        var after = item.after;
+        for (var j = 0, jl = after.length; j < jl; ++j) {
+            graphAfters[after[j]] = (graphAfters[after[j]] || []).concat(seq);
+        }
+    }
+
+    // Expand intermediary graph
+
+    var graphNodes = Object.keys(graph);
+    for (i = 0, il = graphNodes.length; i < il; ++i) {
+        var node = graphNodes[i];
+        var expandedGroups = [];
+
+        var graphNodeItems = Object.keys(graph[node]);
+        for (j = 0, jl = graphNodeItems.length; j < jl; ++j) {
+            group = graph[node][graphNodeItems[j]];
+            groups[group] = groups[group] || [];
+
+            for (var k = 0, kl = groups[group].length; k < kl; ++k) {
+
+                expandedGroups.push(groups[group][k]);
+            }
+        }
+        graph[node] = expandedGroups;
+    }
+
+    // Merge intermediary graph using graphAfters into final graph
+
+    var afterNodes = Object.keys(graphAfters);
+    for (i = 0, il = afterNodes.length; i < il; ++i) {
+        group = afterNodes[i];
+
+        if (groups[group]) {
+            for (j = 0, jl = groups[group].length; j < jl; ++j) {
+                node = groups[group][j];
+                graph[node] = graph[node].concat(graphAfters[group]);
+            }
+        }
+    }
+
+    // Compile ancestors
+
+    var children;
+    var ancestors = {};
+    graphNodes = Object.keys(graph);
+    for (i = 0, il = graphNodes.length; i < il; ++i) {
+        node = graphNodes[i];
+        children = graph[node];
+
+        for (j = 0, jl = children.length; j < jl; ++j) {
+            ancestors[children[j]] = (ancestors[children[j]] || []).concat(node);
+        }
+    }
+
+    // Topo sort
+
+    var visited = {};
+    var sorted = [];
+
+    for (i = 0, il = this._items.length; i < il; ++i) {
+        var next = i;
+
+        if (ancestors[i]) {
+            next = null;
+            for (j = 0, jl = this._items.length; j < jl; ++j) {
+                if (visited[j] === true) {
+                    continue;
+                }
+
+                if (!ancestors[j]) {
+                    ancestors[j] = [];
+                }
+
+                var shouldSeeCount = ancestors[j].length;
+                var seenCount = 0;
+                for (var l = 0, ll = shouldSeeCount; l < ll; ++l) {
+                    if (sorted.indexOf(ancestors[j][l]) >= 0) {
+                        ++seenCount;
+                    }
+                }
+
+                if (seenCount === shouldSeeCount) {
+                    next = j;
+                    break;
+                }
+            }
+        }
+
+        if (next !== null) {
+            next = next.toString();         // Normalize to string TODO: replace with seq
+            visited[next] = true;
+            sorted.push(next);
+        }
+    }
+
+    if (sorted.length !== this._items.length) {
+        return new Error('Invalid dependencies');
+    }
+
+    var seqIndex = {};
+    for (i = 0, il = this._items.length; i < il; ++i) {
+
+        item = this._items[i];
+        seqIndex[item.seq] = item;
+    }
+
+    var sortedNodes = [];
+    this._items = sorted.map(function (value) {
+
+        var sortedItem = seqIndex[value];
+        sortedNodes.push(sortedItem.node);
+        return sortedItem;
+    });
+
+    this.nodes = sortedNodes;
+};
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/topo/package.json b/KEMMessaging/node_modules/firebase-admin/node_modules/topo/package.json
new file mode 100755
index 0000000000000000000000000000000000000000..3fcdc5b3fc2c502c767dbcdf6c6d9f161d050dea
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/topo/package.json
@@ -0,0 +1,75 @@
+{
+  "_args": [
+    [
+      {
+        "raw": "topo@https://registry.npmjs.org/topo/-/topo-1.1.0.tgz",
+        "scope": null,
+        "escapedName": "topo",
+        "name": "topo",
+        "rawSpec": "https://registry.npmjs.org/topo/-/topo-1.1.0.tgz",
+        "spec": "https://registry.npmjs.org/topo/-/topo-1.1.0.tgz",
+        "type": "remote"
+      },
+      "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin"
+    ]
+  ],
+  "_from": "topo@>=1.0.0 <2.0.0",
+  "_id": "topo@1.1.0",
+  "_inCache": true,
+  "_location": "/firebase-admin/topo",
+  "_phantomChildren": {},
+  "_requested": {
+    "raw": "topo@https://registry.npmjs.org/topo/-/topo-1.1.0.tgz",
+    "scope": null,
+    "escapedName": "topo",
+    "name": "topo",
+    "rawSpec": "https://registry.npmjs.org/topo/-/topo-1.1.0.tgz",
+    "spec": "https://registry.npmjs.org/topo/-/topo-1.1.0.tgz",
+    "type": "remote"
+  },
+  "_requiredBy": [
+    "/firebase-admin",
+    "/firebase-admin/joi"
+  ],
+  "_resolved": "https://registry.npmjs.org/topo/-/topo-1.1.0.tgz",
+  "_shasum": "e9d751615d1bb87dc865db182fa1ca0a5ef536d5",
+  "_shrinkwrap": null,
+  "_spec": "topo@https://registry.npmjs.org/topo/-/topo-1.1.0.tgz",
+  "_where": "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin",
+  "bugs": {
+    "url": "https://github.com/hapijs/topo/issues"
+  },
+  "dependencies": {
+    "hoek": "2.x.x"
+  },
+  "description": "Topological sorting with grouping support",
+  "devDependencies": {
+    "code": "1.x.x",
+    "lab": "6.x.x"
+  },
+  "engines": {
+    "node": ">=0.10.40"
+  },
+  "homepage": "https://github.com/hapijs/topo#readme",
+  "keywords": [
+    "topological",
+    "sort",
+    "toposort",
+    "topsort"
+  ],
+  "license": "BSD-3-Clause",
+  "main": "lib/index.js",
+  "name": "topo",
+  "optionalDependencies": {},
+  "readme": "# topo\n\nTopological sorting with grouping support.\n\n[![Build Status](https://secure.travis-ci.org/hapijs/topo.png)](http://travis-ci.org/hapijs/topo)\n\nLead Maintainer: [Devin Ivy](https://github.com/devinivy)\n\n## Usage\n\nSee the [API Reference](API.md)\n\n**Example**\n```node\nvar Topo = require('topo');\n\nvar morning = new Topo();\n\nmorning.add('Nap', { after: ['breakfast', 'prep'] });\n\nmorning.add([\n    'Make toast',\n    'Pour juice'\n], { before: 'breakfast', group: 'prep' });\n\nmorning.add('Eat breakfast', { group: 'breakfast' });\n\nmorning.nodes;        // ['Make toast', 'Pour juice', 'Eat breakfast', 'Nap']\n```\n",
+  "readmeFilename": "README.md",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/hapijs/topo.git"
+  },
+  "scripts": {
+    "test": "lab -a code -t 100 -L",
+    "test-cov-html": "lab -a code -t 100 -L -r html -o coverage.html"
+  },
+  "version": "1.1.0"
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/topo/test/index.js b/KEMMessaging/node_modules/firebase-admin/node_modules/topo/test/index.js
new file mode 100755
index 0000000000000000000000000000000000000000..afec18d0d2495e0406475124b61a8f07bda7bd17
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/topo/test/index.js
@@ -0,0 +1,266 @@
+// Load modules
+
+var Code = require('code');
+var Lab = require('lab');
+var Hoek = require('hoek');
+var Topo = require('..');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var lab = exports.lab = Lab.script();
+var describe = lab.describe;
+var it = lab.it;
+var expect = Code.expect;
+
+
+describe('Topo', function () {
+
+    var testDeps = function (scenario) {
+
+        var topo = new Topo();
+        scenario.forEach(function (record, i) {
+
+            var options = record.before || record.after || record.group ? { before: record.before, after: record.after, group: record.group } : null;
+            topo.add(record.id, options);
+        });
+
+        return topo.nodes.join('');
+    };
+
+    it('sorts dependencies', function (done) {
+
+        var scenario = [
+            { id: '0', before: 'a' },
+            { id: '1', after: 'f', group: 'a' },
+            { id: '2', before: 'a' },
+            { id: '3', before: ['b', 'c'], group: 'a' },
+            { id: '4', after: 'c', group: 'b' },
+            { id: '5', group: 'c' },
+            { id: '6', group: 'd' },
+            { id: '7', group: 'e' },
+            { id: '8', before: 'd' },
+            { id: '9', after: 'c', group: 'a' }
+        ];
+
+        expect(testDeps(scenario)).to.equal('0213547869');
+        done();
+    });
+
+    it('sorts dependencies (before as array)', function (done) {
+
+        var scenario = [
+            { id: '0', group: 'a' },
+            { id: '1', group: 'b' },
+            { id: '2', before: ['a', 'b'] }
+        ];
+
+        expect(testDeps(scenario)).to.equal('201');
+        done();
+    });
+
+    it('sorts dependencies (after as array)', function (done) {
+
+        var scenario = [
+            { id: '0', after: ['a', 'b'] },
+            { id: '1', group: 'a' },
+            { id: '2', group: 'b' }
+        ];
+
+        expect(testDeps(scenario)).to.equal('120');
+        done();
+    });
+
+
+    it('sorts dependencies (seq)', function (done) {
+
+        var scenario = [
+            { id: '0' },
+            { id: '1' },
+            { id: '2' },
+            { id: '3' }
+        ];
+
+        expect(testDeps(scenario)).to.equal('0123');
+        done();
+    });
+
+    it('sorts dependencies (explicitly using after or before)', function (done) {
+
+        var set = '0123456789abcdefghijklmnopqrstuvwxyz';
+        var groups = set.split('');
+
+        // Use Fisher-Yates for shuffling
+
+        var fisherYates = function (array) {
+
+            var i = array.length;
+            while (--i) {
+                var j = Math.floor(Math.random() * (i + 1));
+                var tempi = array[i];
+                var tempj = array[j];
+                array[i] = tempj;
+                array[j] = tempi;
+            }
+        };
+
+        var scenarioAfter = [];
+        var scenarioBefore = [];
+        for (var i = 0, il = groups.length; i < il; ++i) {
+            var item = {
+                id: groups[i],
+                group: groups[i]
+            };
+            var afterMod = {
+                after: i ? groups.slice(0, i) : []
+            };
+            var beforeMod = {
+                before: groups.slice(i + 1)
+            };
+
+            scenarioAfter.push(Hoek.applyToDefaults(item, afterMod));
+            scenarioBefore.push(Hoek.applyToDefaults(item, beforeMod));
+        }
+
+        fisherYates(scenarioAfter);
+        expect(testDeps(scenarioAfter)).to.equal(set);
+
+        fisherYates(scenarioBefore);
+        expect(testDeps(scenarioBefore)).to.equal(set);
+        done();
+    });
+
+    it('throws on circular dependency', function (done) {
+
+        var scenario = [
+            { id: '0', before: 'a', group: 'b' },
+            { id: '1', before: 'c', group: 'a' },
+            { id: '2', before: 'b', group: 'c' }
+        ];
+
+        expect(function () {
+
+            testDeps(scenario);
+        }).to.throw('item added into group c created a dependencies error');
+
+        done();
+    });
+
+    describe('merge()', function () {
+
+        it('merges objects', function (done) {
+
+            var topo = new Topo();
+            topo.add('0', { before: 'a' });
+            topo.add('2', { before: 'a' });
+            topo.add('4', { after: 'c', group: 'b' });
+            topo.add('6', { group: 'd' });
+            topo.add('8', { before: 'd' });
+            expect(topo.nodes.join('')).to.equal('02486');
+
+            var other = new Topo();
+            other.add('1', { after: 'f', group: 'a' });
+            other.add('3', { before: ['b', 'c'], group: 'a' });
+            other.add('5', { group: 'c' });
+            other.add('7', { group: 'e' });
+            other.add('9', { after: 'c', group: 'a' });
+            expect(other.nodes.join('')).to.equal('13579');
+
+            topo.merge(other);
+            expect(topo.nodes.join('')).to.equal('0286135479');
+            done();
+        });
+
+        it('merges objects (explicit sort)', function (done) {
+
+            var topo = new Topo();
+            topo.add('0', { before: 'a', sort: 1 });
+            topo.add('2', { before: 'a', sort: 2 });
+            topo.add('4', { after: 'c', group: 'b', sort: 3 });
+            topo.add('6', { group: 'd', sort: 4 });
+            topo.add('8', { before: 'd', sort: 5 });
+            expect(topo.nodes.join('')).to.equal('02486');
+
+            var other = new Topo();
+            other.add('1', { after: 'f', group: 'a', sort: 6 });
+            other.add('3', { before: ['b', 'c'], group: 'a', sort: 7 });
+            other.add('5', { group: 'c', sort: 8 });
+            other.add('7', { group: 'e', sort: 9 });
+            other.add('9', { after: 'c', group: 'a', sort: 10 });
+            expect(other.nodes.join('')).to.equal('13579');
+
+            topo.merge(other);
+            expect(topo.nodes.join('')).to.equal('0286135479');
+            done();
+        });
+
+        it('merges objects (mixed sort)', function (done) {
+
+            var topo = new Topo();
+            topo.add('0', { before: 'a', sort: 1 });
+            topo.add('2', { before: 'a', sort: 3 });
+            topo.add('4', { after: 'c', group: 'b', sort: 5 });
+            topo.add('6', { group: 'd', sort: 7 });
+            topo.add('8', { before: 'd', sort: 9 });
+            expect(topo.nodes.join('')).to.equal('02486');
+
+            var other = new Topo();
+            other.add('1', { after: 'f', group: 'a', sort: 2 });
+            other.add('3', { before: ['b', 'c'], group: 'a', sort: 4 });
+            other.add('5', { group: 'c', sort: 6 });
+            other.add('7', { group: 'e', sort: 8 });
+            other.add('9', { after: 'c', group: 'a', sort: 10 });
+            expect(other.nodes.join('')).to.equal('13579');
+
+            topo.merge(other);
+            expect(topo.nodes.join('')).to.equal('0213547869');
+            done();
+        });
+
+        it('merges objects (multiple)', function (done) {
+
+            var topo1 = new Topo();
+            topo1.add('0', { before: 'a', sort: 1 });
+            topo1.add('2', { before: 'a', sort: 3 });
+            topo1.add('4', { after: 'c', group: 'b', sort: 5 });
+
+            var topo2 = new Topo();
+            topo2.add('6', { group: 'd', sort: 7 });
+            topo2.add('8', { before: 'd', sort: 9 });
+
+            var other = new Topo();
+            other.add('1', { after: 'f', group: 'a', sort: 2 });
+            other.add('3', { before: ['b', 'c'], group: 'a', sort: 4 });
+            other.add('5', { group: 'c', sort: 6 });
+            other.add('7', { group: 'e', sort: 8 });
+            other.add('9', { after: 'c', group: 'a', sort: 10 });
+            expect(other.nodes.join('')).to.equal('13579');
+
+            topo1.merge([topo2, null, other]);
+            expect(topo1.nodes.join('')).to.equal('0213547869');
+            done();
+        });
+
+        it('throws on circular dependency', function (done) {
+
+            var topo = new Topo();
+            topo.add('0', { before: 'a', group: 'b' });
+            topo.add('1', { before: 'c', group: 'a' });
+
+            var other = new Topo();
+            other.add('2', { before: 'b', group: 'c' });
+
+            expect(function () {
+
+                topo.merge(other);
+            }).to.throw('merge created a dependencies error');
+
+            done();
+        });
+    });
+});
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/CHANGELOG.md b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..f9835a8d7bce9ee0ecaec0e324cb7c582c60164a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/CHANGELOG.md
@@ -0,0 +1,110 @@
+### 0.6.5 / 2016-05-20
+
+* Don't mutate buffers passed in by the application when masking
+
+### 0.6.4 / 2016-01-07
+
+* If a number is given as input for a frame payload, send it as a string
+
+### 0.6.3 / 2015-11-06
+
+* Reject draft-76 handshakes if their Sec-WebSocket-Key headers are invalid
+* Throw a more helpful error if a client is created with an invalid URL
+
+### 0.6.2 / 2015-07-18
+
+* When the peer sends a close frame with no error code, emit 1000
+
+### 0.6.1 / 2015-07-13
+
+* Use the `buffer.{read,write}UInt{16,32}BE` methods for reading/writing numbers
+  to buffers rather than including duplicate logic for this
+
+### 0.6.0 / 2015-07-08
+
+* Allow the parser to recover cleanly if event listeners raise an error
+* Add a `pong` method for sending unsolicited pong frames
+
+### 0.5.4 / 2015-03-29
+
+* Don't emit extra close frames if we receive a close frame after we already
+  sent one
+* Fail the connection when the driver receives an invalid
+  `Sec-WebSocket-Extensions` header
+
+### 0.5.3 / 2015-02-22
+
+* Don't treat incoming data as WebSocket frames if a client driver is closed
+  before receiving the server handshake
+
+### 0.5.2 / 2015-02-19
+
+* Fix compatibility with the HTTP parser on io.js
+* Use `websocket-extensions` to make sure messages and close frames are kept in
+  order
+* Don't emit multiple `error` events
+
+### 0.5.1 / 2014-12-18
+
+* Don't allow drivers to be created with unrecognized options
+
+### 0.5.0 / 2014-12-13
+
+* Support protocol extensions via the websocket-extensions module
+
+### 0.4.0 / 2014-11-08
+
+* Support connection via HTTP proxies using `CONNECT`
+
+### 0.3.6 / 2014-10-04
+
+* It is now possible to call `close()` before `start()` and close the driver
+
+### 0.3.5 / 2014-07-06
+
+* Don't hold references to frame buffers after a message has been emitted
+* Make sure that `protocol` and `version` are exposed properly by the TCP driver
+
+### 0.3.4 / 2014-05-08
+
+* Don't hold memory-leaking references to I/O buffers after they have been
+  parsed
+
+### 0.3.3 / 2014-04-24
+
+* Correct the draft-76 status line reason phrase
+
+### 0.3.2 / 2013-12-29
+
+* Expand `maxLength` to cover sequences of continuation frames and
+  `draft-{75,76}`
+* Decrease default maximum frame buffer size to 64MB
+* Stop parsing when the protocol enters a failure mode, to save CPU cycles
+
+### 0.3.1 / 2013-12-03
+
+* Add a `maxLength` option to limit allowed frame size
+* Don't pre-allocate a message buffer until the whole frame has arrived
+* Fix compatibility with Node v0.11 `HTTPParser`
+
+### 0.3.0 / 2013-09-09
+
+* Support client URLs with Basic Auth credentials
+
+### 0.2.2 / 2013-07-05
+
+* No functional changes, just updates to package.json
+
+### 0.2.1 / 2013-05-17
+
+* Export the isSecureRequest() method since faye-websocket relies on it
+* Queue sent messages in the client's initial state
+
+### 0.2.0 / 2013-05-12
+
+* Add API for setting and reading headers
+* Add Driver.server() method for getting a driver for TCP servers
+
+### 0.1.0 / 2013-05-04
+
+* First stable release
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/CODE_OF_CONDUCT.md b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000000000000000000000000000000000000..4547adff7217faedd773c3f752bc050a6773bdc0
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/CODE_OF_CONDUCT.md
@@ -0,0 +1,4 @@
+# Code of Conduct
+
+All projects under the [Faye](https://github.com/faye) umbrella are covered by
+the [Code of Conduct](https://github.com/faye/code-of-conduct).
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/README.md b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..f103abef8ed68cd07e13ac32772b5c2ae3643a62
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/README.md
@@ -0,0 +1,383 @@
+# websocket-driver [![Build Status](https://travis-ci.org/faye/websocket-driver-node.svg)](https://travis-ci.org/faye/websocket-driver-node)
+
+This module provides a complete implementation of the WebSocket protocols that
+can be hooked up to any I/O stream. It aims to simplify things by decoupling the
+protocol details from the I/O layer, such that users only need to implement code
+to stream data in and out of it without needing to know anything about how the
+protocol actually works. Think of it as a complete WebSocket system with
+pluggable I/O.
+
+Due to this design, you get a lot of things for free. In particular, if you hook
+this module up to some I/O object, it will do all of this for you:
+
+* Select the correct server-side driver to talk to the client
+* Generate and send both server- and client-side handshakes
+* Recognize when the handshake phase completes and the WS protocol begins
+* Negotiate subprotocol selection based on `Sec-WebSocket-Protocol`
+* Negotiate and use extensions via the
+  [websocket-extensions](https://github.com/faye/websocket-extensions-node)
+  module
+* Buffer sent messages until the handshake process is finished
+* Deal with proxies that defer delivery of the draft-76 handshake body
+* Notify you when the socket is open and closed and when messages arrive
+* Recombine fragmented messages
+* Dispatch text, binary, ping, pong and close frames
+* Manage the socket-closing handshake process
+* Automatically reply to ping frames with a matching pong
+* Apply masking to messages sent by the client
+
+This library was originally extracted from the [Faye](http://faye.jcoglan.com)
+project but now aims to provide simple WebSocket support for any Node-based
+project.
+
+
+## Installation
+
+```
+$ npm install websocket-driver
+```
+
+
+## Usage
+
+This module provides protocol drivers that have the same interface on the server
+and on the client. A WebSocket driver is an object with two duplex streams
+attached; one for incoming/outgoing messages and one for managing the wire
+protocol over an I/O stream. The full API is described below.
+
+
+### Server-side with HTTP
+
+A Node webserver emits a special event for 'upgrade' requests, and this is where
+you should handle WebSockets. You first check whether the request is a
+WebSocket, and if so you can create a driver and attach the request's I/O stream
+to it.
+
+```js
+var http = require('http'),
+    websocket = require('websocket-driver');
+
+var server = http.createServer();
+
+server.on('upgrade', function(request, socket, body) {
+  if (!websocket.isWebSocket(request)) return;
+
+  var driver = websocket.http(request);
+
+  driver.io.write(body);
+  socket.pipe(driver.io).pipe(socket);
+
+  driver.messages.on('data', function(message) {
+    console.log('Got a message', message);
+  });
+
+  driver.start();
+});
+```
+
+Note the line `driver.io.write(body)` - you must pass the `body` buffer to the
+socket driver in order to make certain versions of the protocol work.
+
+
+### Server-side with TCP
+
+You can also handle WebSocket connections in a bare TCP server, if you're not
+using an HTTP server and don't want to implement HTTP parsing yourself.
+
+The driver will emit a `connect` event when a request is received, and at this
+point you can detect whether it's a WebSocket and handle it as such. Here's an
+example using the Node `net` module:
+
+```js
+var net = require('net'),
+    websocket = require('websocket-driver');
+
+var server = net.createServer(function(connection) {
+  var driver = websocket.server();
+
+  driver.on('connect', function() {
+    if (websocket.isWebSocket(driver)) {
+      driver.start();
+    } else {
+      // handle other HTTP requests
+    }
+  });
+
+  driver.on('close', function() { connection.end() });
+  connection.on('error', function() {});
+
+  connection.pipe(driver.io).pipe(connection);
+
+  driver.messages.pipe(driver.messages);
+});
+
+server.listen(4180);
+```
+
+In the `connect` event, the driver gains several properties to describe the
+request, similar to a Node request object, such as `method`, `url` and
+`headers`. However you should remember it's not a real request object; you
+cannot write data to it, it only tells you what request data we parsed from the
+input.
+
+If the request has a body, it will be in the `driver.body` buffer, but only as
+much of the body as has been piped into the driver when the `connect` event
+fires.
+
+
+### Client-side
+
+Similarly, to implement a WebSocket client you just need to make a driver by
+passing in a URL. After this you use the driver API as described below to
+process incoming data and send outgoing data.
+
+
+```js
+var net = require('net'),
+    websocket = require('websocket-driver');
+
+var driver = websocket.client('ws://www.example.com/socket'),
+    tcp = net.connect(80, 'www.example.com');
+
+tcp.pipe(driver.io).pipe(tcp);
+
+tcp.on('connect', function() {
+  driver.start();
+});
+
+driver.messages.on('data', function(message) {
+  console.log('Got a message', message);
+});
+```
+
+Client drivers have two additional properties for reading the HTTP data that was
+sent back by the server:
+
+* `driver.statusCode` - the integer value of the HTTP status code
+* `driver.headers` - an object containing the response headers
+
+
+### HTTP Proxies
+
+The client driver supports connections via HTTP proxies using the `CONNECT`
+method. Instead of sending the WebSocket handshake immediately, it will send a
+`CONNECT` request, wait for a `200` response, and then proceed as normal.
+
+To use this feature, call `driver.proxy(url)` where `url` is the origin of the
+proxy, including a username and password if required. This produces a duplex
+stream that you should pipe in and out of your TCP connection to the proxy
+server. When the proxy emits `connect`, you can then pipe `driver.io` to your
+TCP stream and call `driver.start()`.
+
+```js
+var net = require('net'),
+    websocket = require('websocket-driver');
+
+var driver = websocket.client('ws://www.example.com/socket'),
+    proxy  = driver.proxy('http://username:password@proxy.example.com'),
+    tcp    = net.connect(80, 'proxy.example.com');
+
+tcp.pipe(proxy).pipe(tcp, {end: false});
+
+tcp.on('connect', function() {
+  proxy.start();
+});
+
+proxy.on('connect', function() {
+  driver.io.pipe(tcp).pipe(driver.io);
+  driver.start();
+});
+
+driver.messages.on('data', function(message) {
+  console.log('Got a message', message);
+});
+```
+
+The proxy's `connect` event is also where you should perform a TLS handshake on
+your TCP stream, if you are connecting to a `wss:` endpoint.
+
+In the event that proxy connection fails, `proxy` will emit an `error`. You can
+inspect the proxy's response via `proxy.statusCode` and `proxy.headers`.
+
+```js
+proxy.on('error', function(error) {
+  console.error(error.message);
+  console.log(proxy.statusCode);
+  console.log(proxy.headers);
+});
+```
+
+Before calling `proxy.start()` you can set custom headers using
+`proxy.setHeader()`:
+
+```js
+proxy.setHeader('User-Agent', 'node');
+proxy.start();
+```
+
+
+### Driver API
+
+Drivers are created using one of the following methods:
+
+```js
+driver = websocket.http(request, options)
+driver = websocket.server(options)
+driver = websocket.client(url, options)
+```
+
+The `http` method returns a driver chosen using the headers from a Node HTTP
+request object. The `server` method returns a driver that will parse an HTTP
+request and then decide which driver to use for it using the `http` method. The
+`client` method always returns a driver for the RFC version of the protocol with
+masking enabled on outgoing frames.
+
+The `options` argument is optional, and is an object. It may contain the
+following fields:
+
+* `maxLength` - the maximum allowed size of incoming message frames, in bytes.
+  The default value is `2^26 - 1`, or 1 byte short of 64 MiB.
+* `protocols` - an array of strings representing acceptable subprotocols for use
+  over the socket. The driver will negotiate one of these to use via the
+  `Sec-WebSocket-Protocol` header if supported by the other peer.
+
+A driver has two duplex streams attached to it:
+
+* <b>`driver.io`</b> - this stream should be attached to an I/O socket like a
+  TCP stream. Pipe incoming TCP chunks to this stream for them to be parsed, and
+  pipe this stream back into TCP to send outgoing frames.
+* <b>`driver.messages`</b> - this stream emits messages received over the
+  WebSocket.  Writing to it sends messages to the other peer by emitting frames
+  via the `driver.io` stream.
+
+All drivers respond to the following API methods, but some of them are no-ops
+depending on whether the client supports the behaviour.
+
+Note that most of these methods are commands: if they produce data that should
+be sent over the socket, they will give this to you by emitting `data` events on
+the `driver.io` stream.
+
+#### `driver.on('open', function(event) {})`
+
+Adds a callback to execute when the socket becomes open.
+
+#### `driver.on('message', function(event) {})`
+
+Adds a callback to execute when a message is received. `event` will have a
+`data` attribute containing either a string in the case of a text message or a
+`Buffer` in the case of a binary message.
+
+You can also listen for messages using the `driver.messages.on('data')` event,
+which emits strings for text messages and buffers for binary messages.
+
+#### `driver.on('error', function(event) {})`
+
+Adds a callback to execute when a protocol error occurs due to the other peer
+sending an invalid byte sequence. `event` will have a `message` attribute
+describing the error.
+
+#### `driver.on('close', function(event) {})`
+
+Adds a callback to execute when the socket becomes closed. The `event` object
+has `code` and `reason` attributes.
+
+#### `driver.addExtension(extension)`
+
+Registers a protocol extension whose operation will be negotiated via the
+`Sec-WebSocket-Extensions` header. `extension` is any extension compatible with
+the [websocket-extensions](https://github.com/faye/websocket-extensions-node)
+framework.
+
+#### `driver.setHeader(name, value)`
+
+Sets a custom header to be sent as part of the handshake response, either from
+the server or from the client. Must be called before `start()`, since this is
+when the headers are serialized and sent.
+
+#### `driver.start()`
+
+Initiates the protocol by sending the handshake - either the response for a
+server-side driver or the request for a client-side one. This should be the
+first method you invoke.  Returns `true` if and only if a handshake was sent.
+
+#### `driver.parse(string)`
+
+Takes a string and parses it, potentially resulting in message events being
+emitted (see `on('message')` above) or in data being sent to `driver.io`.  You
+should send all data you receive via I/O to this method by piping a stream into
+`driver.io`.
+
+#### `driver.text(string)`
+
+Sends a text message over the socket. If the socket handshake is not yet
+complete, the message will be queued until it is. Returns `true` if the message
+was sent or queued, and `false` if the socket can no longer send messages.
+
+This method is equivalent to `driver.messages.write(string)`.
+
+#### `driver.binary(buffer)`
+
+Takes a `Buffer` and sends it as a binary message. Will queue and return `true`
+or `false` the same way as the `text` method. It will also return `false` if the
+driver does not support binary messages.
+
+This method is equivalent to `driver.messages.write(buffer)`.
+
+#### `driver.ping(string = '', function() {})`
+
+Sends a ping frame over the socket, queueing it if necessary. `string` and the
+callback are both optional. If a callback is given, it will be invoked when the
+socket receives a pong frame whose content matches `string`. Returns `false` if
+frames can no longer be sent, or if the driver does not support ping/pong.
+
+#### `driver.pong(string = '')`
+
+Sends a pong frame over the socket, queueing it if necessary. `string` is
+optional. Returns `false` if frames can no longer be sent, or if the driver does
+not support ping/pong.
+
+You don't need to call this when a ping frame is received; pings are replied to
+automatically by the driver. This method is for sending unsolicited pongs.
+
+#### `driver.close()`
+
+Initiates the closing handshake if the socket is still open. For drivers with no
+closing handshake, this will result in the immediate execution of the
+`on('close')` driver. For drivers with a closing handshake, this sends a closing
+frame and `emit('close')` will execute when a response is received or a protocol
+error occurs.
+
+#### `driver.version`
+
+Returns the WebSocket version in use as a string. Will either be `hixie-75`,
+`hixie-76` or `hybi-$version`.
+
+#### `driver.protocol`
+
+Returns a string containing the selected subprotocol, if any was agreed upon
+using the `Sec-WebSocket-Protocol` mechanism. This value becomes available after
+`emit('open')` has fired.
+
+
+## License
+
+(The MIT License)
+
+Copyright (c) 2010-2016 James Coglan
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the 'Software'), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/examples/tcp_server.js b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/examples/tcp_server.js
new file mode 100644
index 0000000000000000000000000000000000000000..2537c33514e11992851ebbdca93917923cf55317
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/examples/tcp_server.js
@@ -0,0 +1,22 @@
+var net       = require('net'),
+    websocket = require('..'),
+    deflate   = require('permessage-deflate');
+
+var server = net.createServer(function(connection) {
+  var driver = websocket.server();
+  driver.addExtension(deflate);
+
+  driver.on('connect', function() {
+    if (websocket.isWebSocket(driver)) driver.start();
+  });
+
+  driver.on('close', function() { connection.end() });
+  connection.on('error', function() {});
+
+  connection.pipe(driver.io);
+  driver.io.pipe(connection);
+
+  driver.messages.pipe(driver.messages);
+});
+
+server.listen(process.argv[2]);
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver.js b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver.js
new file mode 100644
index 0000000000000000000000000000000000000000..221ab2771f1ec8499ecc4976ebe05f9683b228b3
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver.js
@@ -0,0 +1,50 @@
+'use strict';
+
+// Protocol references:
+// 
+// * http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75
+// * http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76
+// * http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17
+
+var Base   = require('./driver/base'),
+    Client = require('./driver/client'),
+    Server = require('./driver/server');
+
+var Driver = {
+  client: function(url, options) {
+    options = options || {};
+    if (options.masking === undefined) options.masking = true;
+    return new Client(url, options);
+  },
+
+  server: function(options) {
+    options = options || {};
+    if (options.requireMasking === undefined) options.requireMasking = true;
+    return new Server(options);
+  },
+
+  http: function() {
+    return Server.http.apply(Server, arguments);
+  },
+
+  isSecureRequest: function(request) {
+    return Server.isSecureRequest(request);
+  },
+
+  isWebSocket: function(request) {
+    if (request.method !== 'GET') return false;
+
+    var connection = request.headers.connection || '',
+        upgrade    = request.headers.upgrade || '';
+
+    return request.method === 'GET' &&
+           connection.toLowerCase().split(/ *, */).indexOf('upgrade') >= 0 &&
+           upgrade.toLowerCase() === 'websocket';
+  },
+
+  validateOptions: function(options, validKeys) {
+    Base.validateOptions(options, validKeys);
+  }
+};
+
+module.exports = Driver;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/base.js b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/base.js
new file mode 100644
index 0000000000000000000000000000000000000000..7e9df0187232807d64439b52306d8c966a832d39
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/base.js
@@ -0,0 +1,147 @@
+'use strict';
+
+var Emitter = require('events').EventEmitter,
+    util    = require('util'),
+    streams = require('../streams'),
+    Headers = require('./headers'),
+    Reader  = require('./stream_reader');
+
+var Base = function(request, url, options) {
+  Emitter.call(this);
+  Base.validateOptions(options || {}, ['maxLength', 'masking', 'requireMasking', 'protocols']);
+
+  this._request   = request;
+  this._reader    = new Reader();
+  this._options   = options || {};
+  this._maxLength = this._options.maxLength || this.MAX_LENGTH;
+  this._headers   = new Headers();
+  this.__queue    = [];
+  this.readyState = 0;
+  this.url        = url;
+
+  this.io = new streams.IO(this);
+  this.messages = new streams.Messages(this);
+  this._bindEventListeners();
+};
+util.inherits(Base, Emitter);
+
+Base.validateOptions = function(options, validKeys) {
+  for (var key in options) {
+    if (validKeys.indexOf(key) < 0)
+      throw new Error('Unrecognized option: ' + key);
+  }
+};
+
+var instance = {
+  // This is 64MB, small enough for an average VPS to handle without
+  // crashing from process out of memory
+  MAX_LENGTH: 0x3ffffff,
+
+  STATES: ['connecting', 'open', 'closing', 'closed'],
+
+  _bindEventListeners: function() {
+    var self = this;
+
+    // Protocol errors are informational and do not have to be handled
+    this.messages.on('error', function() {});
+
+    this.on('message', function(event) {
+      var messages = self.messages;
+      if (messages.readable) messages.emit('data', event.data);
+    });
+
+    this.on('error', function(error) {
+      var messages = self.messages;
+      if (messages.readable) messages.emit('error', error);
+    });
+
+    this.on('close', function() {
+      var messages = self.messages;
+      if (!messages.readable) return;
+      messages.readable = messages.writable = false;
+      messages.emit('end');
+    });
+  },
+
+  getState: function() {
+    return this.STATES[this.readyState] || null;
+  },
+
+  addExtension: function(extension) {
+    return false;
+  },
+
+  setHeader: function(name, value) {
+    if (this.readyState > 0) return false;
+    this._headers.set(name, value);
+    return true;
+  },
+
+  start: function() {
+    if (this.readyState !== 0) return false;
+    var response = this._handshakeResponse();
+    if (!response) return false;
+    this._write(response);
+    if (this._stage !== -1) this._open();
+    return true;
+  },
+
+  text: function(message) {
+    return this.frame(message);
+  },
+
+  binary: function(message) {
+    return false;
+  },
+
+  ping: function() {
+    return false;
+  },
+
+  pong: function() {
+      return false;
+  },
+
+  close: function(reason, code) {
+    if (this.readyState !== 1) return false;
+    this.readyState = 3;
+    this.emit('close', new Base.CloseEvent(null, null));
+    return true;
+  },
+
+  _open: function() {
+    this.readyState = 1;
+    this.__queue.forEach(function(args) { this.frame.apply(this, args) }, this);
+    this.__queue = [];
+    this.emit('open', new Base.OpenEvent());
+  },
+
+  _queue: function(message) {
+    this.__queue.push(message);
+    return true;
+  },
+
+  _write: function(chunk) {
+    var io = this.io;
+    if (io.readable) io.emit('data', chunk);
+  }
+};
+
+for (var key in instance)
+  Base.prototype[key] = instance[key];
+
+
+Base.ConnectEvent = function() {};
+
+Base.OpenEvent = function() {};
+
+Base.CloseEvent = function(code, reason) {
+  this.code   = code;
+  this.reason = reason;
+};
+
+Base.MessageEvent = function(data) {
+  this.data = data;
+};
+
+module.exports = Base;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/client.js b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/client.js
new file mode 100644
index 0000000000000000000000000000000000000000..59cc959e1aca62950ff7011fa78003d0ac590474
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/client.js
@@ -0,0 +1,138 @@
+'use strict';
+
+var crypto     = require('crypto'),
+    url        = require('url'),
+    util       = require('util'),
+    HttpParser = require('../http_parser'),
+    Base       = require('./base'),
+    Hybi       = require('./hybi'),
+    Proxy      = require('./proxy');
+
+var Client = function(_url, options) {
+  this.version = 'hybi-13';
+  Hybi.call(this, null, _url, options);
+
+  this.readyState = -1;
+  this._key       = Client.generateKey();
+  this._accept    = Hybi.generateAccept(this._key);
+  this._http      = new HttpParser('response');
+
+  var uri  = url.parse(this.url),
+      auth = uri.auth && new Buffer(uri.auth, 'utf8').toString('base64');
+
+  if (this.VALID_PROTOCOLS.indexOf(uri.protocol) < 0)
+    throw new Error(this.url + ' is not a valid WebSocket URL');
+
+  this._pathname = (uri.pathname || '/') + (uri.search || '');
+
+  this._headers.set('Host', uri.host);
+  this._headers.set('Upgrade', 'websocket');
+  this._headers.set('Connection', 'Upgrade');
+  this._headers.set('Sec-WebSocket-Key', this._key);
+  this._headers.set('Sec-WebSocket-Version', '13');
+
+  if (this._protocols.length > 0)
+    this._headers.set('Sec-WebSocket-Protocol', this._protocols.join(', '));
+
+  if (auth)
+    this._headers.set('Authorization', 'Basic ' + auth);
+};
+util.inherits(Client, Hybi);
+
+Client.generateKey = function() {
+  return crypto.randomBytes(16).toString('base64');
+};
+
+var instance = {
+  VALID_PROTOCOLS: ['ws:', 'wss:'],
+
+  proxy: function(origin, options) {
+    return new Proxy(this, origin, options);
+  },
+
+  start: function() {
+    if (this.readyState !== -1) return false;
+    this._write(this._handshakeRequest());
+    this.readyState = 0;
+    return true;
+  },
+
+  parse: function(chunk) {
+    if (this.readyState === 3) return;
+    if (this.readyState > 0) return Hybi.prototype.parse.call(this, chunk);
+
+    this._http.parse(chunk);
+    if (!this._http.isComplete()) return;
+
+    this._validateHandshake();
+    if (this.readyState === 3) return;
+
+    this._open();
+    this.parse(this._http.body);
+  },
+
+  _handshakeRequest: function() {
+    var extensions = this._extensions.generateOffer();
+    if (extensions)
+      this._headers.set('Sec-WebSocket-Extensions', extensions);
+
+    var start   = 'GET ' + this._pathname + ' HTTP/1.1',
+        headers = [start, this._headers.toString(), ''];
+
+    return new Buffer(headers.join('\r\n'), 'utf8');
+  },
+
+  _failHandshake: function(message) {
+    message = 'Error during WebSocket handshake: ' + message;
+    this.readyState = 3;
+    this.emit('error', new Error(message));
+    this.emit('close', new Base.CloseEvent(this.ERRORS.protocol_error, message));
+  },
+
+  _validateHandshake: function() {
+    this.statusCode = this._http.statusCode;
+    this.headers    = this._http.headers;
+
+    if (this._http.statusCode !== 101)
+      return this._failHandshake('Unexpected response code: ' + this._http.statusCode);
+
+    var headers    = this._http.headers,
+        upgrade    = headers['upgrade'] || '',
+        connection = headers['connection'] || '',
+        accept     = headers['sec-websocket-accept'] || '',
+        protocol   = headers['sec-websocket-protocol'] || '';
+
+    if (upgrade === '')
+      return this._failHandshake("'Upgrade' header is missing");
+    if (upgrade.toLowerCase() !== 'websocket')
+      return this._failHandshake("'Upgrade' header value is not 'WebSocket'");
+
+    if (connection === '')
+      return this._failHandshake("'Connection' header is missing");
+    if (connection.toLowerCase() !== 'upgrade')
+      return this._failHandshake("'Connection' header value is not 'Upgrade'");
+
+    if (accept !== this._accept)
+      return this._failHandshake('Sec-WebSocket-Accept mismatch');
+
+    this.protocol = null;
+
+    if (protocol !== '') {
+      if (this._protocols.indexOf(protocol) < 0)
+        return this._failHandshake('Sec-WebSocket-Protocol mismatch');
+      else
+        this.protocol = protocol;
+    }
+
+    try {
+      this._extensions.activate(this.headers['sec-websocket-extensions']);
+    } catch (e) {
+      return this._failHandshake(e.message);
+    }
+  }
+};
+
+for (var key in instance)
+  Client.prototype[key] = instance[key];
+
+module.exports = Client;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/draft75.js b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/draft75.js
new file mode 100644
index 0000000000000000000000000000000000000000..6663e55560b114ea808311eaf0422941468ce8ce
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/draft75.js
@@ -0,0 +1,122 @@
+'use strict';
+
+var Base = require('./base'),
+    util = require('util');
+
+var Draft75 = function(request, url, options) {
+  Base.apply(this, arguments);
+  this._stage  = 0;
+  this.version = 'hixie-75';
+
+  this._headers.set('Upgrade', 'WebSocket');
+  this._headers.set('Connection', 'Upgrade');
+  this._headers.set('WebSocket-Origin', this._request.headers.origin);
+  this._headers.set('WebSocket-Location', this.url);
+};
+util.inherits(Draft75, Base);
+
+var instance = {
+  close: function() {
+    if (this.readyState === 3) return false;
+    this.readyState = 3;
+    this.emit('close', new Base.CloseEvent(null, null));
+    return true;
+  },
+
+  parse: function(chunk) {
+    if (this.readyState > 1) return;
+
+    this._reader.put(chunk);
+
+    this._reader.eachByte(function(octet) {
+      var message;
+
+      switch (this._stage) {
+        case -1:
+          this._body.push(octet);
+          this._sendHandshakeBody();
+          break;
+
+        case 0:
+          this._parseLeadingByte(octet);
+          break;
+
+        case 1:
+          this._length = (octet & 0x7F) + 128 * this._length;
+
+          if (this._closing && this._length === 0) {
+            return this.close();
+          }
+          else if ((octet & 0x80) !== 0x80) {
+            if (this._length === 0) {
+              this._stage = 0;
+            }
+            else {
+              this._skipped = 0;
+              this._stage   = 2;
+            }
+          }
+          break;
+
+        case 2:
+          if (octet === 0xFF) {
+            this._stage = 0;
+            message = new Buffer(this._buffer).toString('utf8', 0, this._buffer.length);
+            this.emit('message', new Base.MessageEvent(message));
+          }
+          else {
+            if (this._length) {
+              this._skipped += 1;
+              if (this._skipped === this._length)
+                this._stage = 0;
+            } else {
+              this._buffer.push(octet);
+              if (this._buffer.length > this._maxLength) return this.close();
+            }
+          }
+          break;
+      }
+    }, this);
+  },
+
+  frame: function(buffer) {
+    if (this.readyState === 0) return this._queue([buffer]);
+    if (this.readyState > 1) return false;
+
+    if (typeof buffer !== 'string') buffer = buffer.toString();
+
+    var payload = new Buffer(buffer, 'utf8'),
+        frame   = new Buffer(payload.length + 2);
+
+    frame[0] = 0x00;
+    frame[payload.length + 1] = 0xFF;
+    payload.copy(frame, 1);
+
+    this._write(frame);
+    return true;
+  },
+
+  _handshakeResponse: function() {
+    var start   = 'HTTP/1.1 101 Web Socket Protocol Handshake',
+        headers = [start, this._headers.toString(), ''];
+
+    return new Buffer(headers.join('\r\n'), 'utf8');
+  },
+
+  _parseLeadingByte: function(octet) {
+    if ((octet & 0x80) === 0x80) {
+      this._length = 0;
+      this._stage  = 1;
+    } else {
+      delete this._length;
+      delete this._skipped;
+      this._buffer = [];
+      this._stage  = 2;
+    }
+  }
+};
+
+for (var key in instance)
+  Draft75.prototype[key] = instance[key];
+
+module.exports = Draft75;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/draft76.js b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/draft76.js
new file mode 100644
index 0000000000000000000000000000000000000000..01646851dae3a57f0ad3ba9c2bead1bb99ddf9b9
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/draft76.js
@@ -0,0 +1,116 @@
+'use strict';
+
+var Base    = require('./base'),
+    Draft75 = require('./draft75'),
+    crypto  = require('crypto'),
+    util    = require('util');
+
+
+var numberFromKey = function(key) {
+  return parseInt(key.match(/[0-9]/g).join(''), 10);
+};
+
+var spacesInKey = function(key) {
+  return key.match(/ /g).length;
+};
+
+
+var Draft76 = function(request, url, options) {
+  Draft75.apply(this, arguments);
+  this._stage  = -1;
+  this._body   = [];
+  this.version = 'hixie-76';
+
+  this._headers.clear();
+
+  this._headers.set('Upgrade', 'WebSocket');
+  this._headers.set('Connection', 'Upgrade');
+  this._headers.set('Sec-WebSocket-Origin', this._request.headers.origin);
+  this._headers.set('Sec-WebSocket-Location', this.url);
+};
+util.inherits(Draft76, Draft75);
+
+var instance = {
+  BODY_SIZE: 8,
+
+  start: function() {
+    if (!Draft75.prototype.start.call(this)) return false;
+    this._started = true;
+    this._sendHandshakeBody();
+    return true;
+  },
+
+  close: function() {
+    if (this.readyState === 3) return false;
+    this._write(new Buffer([0xFF, 0x00]));
+    this.readyState = 3;
+    this.emit('close', new Base.CloseEvent(null, null));
+    return true;
+  },
+
+  _handshakeResponse: function() {
+    var headers = this._request.headers,
+
+        key1    = headers['sec-websocket-key1'],
+        number1 = numberFromKey(key1),
+        spaces1 = spacesInKey(key1),
+
+        key2    = headers['sec-websocket-key2'],
+        number2 = numberFromKey(key2),
+        spaces2 = spacesInKey(key2);
+
+    if (number1 % spaces1 !== 0 || number2 % spaces2 !== 0) {
+      this.emit('error', new Error('Client sent invalid Sec-WebSocket-Key headers'));
+      this.close();
+      return null;
+    }
+
+    this._keyValues = [number1 / spaces1, number2 / spaces2];
+
+    var start   = 'HTTP/1.1 101 WebSocket Protocol Handshake',
+        headers = [start, this._headers.toString(), ''];
+
+    return new Buffer(headers.join('\r\n'), 'binary');
+  },
+
+  _handshakeSignature: function() {
+    if (this._body.length < this.BODY_SIZE) return null;
+
+    var md5    = crypto.createHash('md5'),
+        buffer = new Buffer(8 + this.BODY_SIZE);
+
+    buffer.writeUInt32BE(this._keyValues[0], 0);
+    buffer.writeUInt32BE(this._keyValues[1], 4);
+    new Buffer(this._body).copy(buffer, 8, 0, this.BODY_SIZE);
+
+    md5.update(buffer);
+    return new Buffer(md5.digest('binary'), 'binary');
+  },
+
+  _sendHandshakeBody: function() {
+    if (!this._started) return;
+    var signature = this._handshakeSignature();
+    if (!signature) return;
+
+    this._write(signature);
+    this._stage = 0;
+    this._open();
+
+    if (this._body.length > this.BODY_SIZE)
+      this.parse(this._body.slice(this.BODY_SIZE));
+  },
+
+  _parseLeadingByte: function(octet) {
+    if (octet !== 0xFF)
+      return Draft75.prototype._parseLeadingByte.call(this, octet);
+
+    this._closing = true;
+    this._length  = 0;
+    this._stage   = 1;
+  }
+};
+
+for (var key in instance)
+  Draft76.prototype[key] = instance[key];
+
+module.exports = Draft76;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/headers.js b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/headers.js
new file mode 100644
index 0000000000000000000000000000000000000000..bc96b7dc6c8f0a376c87fa21e4e6dd157bcf5ff3
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/headers.js
@@ -0,0 +1,35 @@
+'use strict';
+
+var Headers = function() {
+  this.clear();
+};
+
+Headers.prototype.ALLOWED_DUPLICATES = ['set-cookie', 'set-cookie2', 'warning', 'www-authenticate'];
+
+Headers.prototype.clear = function() {
+  this._sent  = {};
+  this._lines = [];
+};
+
+Headers.prototype.set = function(name, value) {
+  if (value === undefined) return;
+
+  name = this._strip(name);
+  value = this._strip(value);
+
+  var key = name.toLowerCase();
+  if (!this._sent.hasOwnProperty(key) || this.ALLOWED_DUPLICATES.indexOf(key) >= 0) {
+    this._sent[key] = true;
+    this._lines.push(name + ': ' + value + '\r\n');
+  }
+};
+
+Headers.prototype.toString = function() {
+  return this._lines.join('');
+};
+
+Headers.prototype._strip = function(string) {
+  return string.toString().replace(/^ */, '').replace(/ *$/, '');
+};
+
+module.exports = Headers;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/hybi.js b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/hybi.js
new file mode 100644
index 0000000000000000000000000000000000000000..0f7596cb8120411bff96112295131a9c3644a733
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/hybi.js
@@ -0,0 +1,474 @@
+'use strict';
+
+var crypto     = require('crypto'),
+    util       = require('util'),
+    Extensions = require('websocket-extensions'),
+    Base       = require('./base'),
+    Frame      = require('./hybi/frame'),
+    Message    = require('./hybi/message');
+
+var Hybi = function(request, url, options) {
+  Base.apply(this, arguments);
+
+  this._extensions     = new Extensions();
+  this._stage          = 0;
+  this._masking        = this._options.masking;
+  this._protocols      = this._options.protocols || [];
+  this._requireMasking = this._options.requireMasking;
+  this._pingCallbacks  = {};
+
+  if (typeof this._protocols === 'string')
+    this._protocols = this._protocols.split(/ *, */);
+
+  if (!this._request) return;
+
+  var secKey    = this._request.headers['sec-websocket-key'],
+      protos    = this._request.headers['sec-websocket-protocol'],
+      version   = this._request.headers['sec-websocket-version'],
+      supported = this._protocols;
+
+  this._headers.set('Upgrade', 'websocket');
+  this._headers.set('Connection', 'Upgrade');
+  this._headers.set('Sec-WebSocket-Accept', Hybi.generateAccept(secKey));
+
+  if (protos !== undefined) {
+    if (typeof protos === 'string') protos = protos.split(/ *, */);
+    this.protocol = protos.filter(function(p) { return supported.indexOf(p) >= 0 })[0];
+    if (this.protocol) this._headers.set('Sec-WebSocket-Protocol', this.protocol);
+  }
+
+  this.version = 'hybi-' + version;
+};
+util.inherits(Hybi, Base);
+
+Hybi.mask = function(payload, mask, offset) {
+  if (!mask || mask.length === 0) return payload;
+  offset = offset || 0;
+
+  for (var i = 0, n = payload.length - offset; i < n; i++) {
+    payload[offset + i] = payload[offset + i] ^ mask[i % 4];
+  }
+  return payload;
+};
+
+Hybi.generateAccept = function(key) {
+  var sha1 = crypto.createHash('sha1');
+  sha1.update(key + Hybi.GUID);
+  return sha1.digest('base64');
+};
+
+Hybi.GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
+
+var instance = {
+  FIN:    0x80,
+  MASK:   0x80,
+  RSV1:   0x40,
+  RSV2:   0x20,
+  RSV3:   0x10,
+  OPCODE: 0x0F,
+  LENGTH: 0x7F,
+
+  OPCODES: {
+    continuation: 0,
+    text:         1,
+    binary:       2,
+    close:        8,
+    ping:         9,
+    pong:         10
+  },
+
+  OPCODE_CODES:    [0, 1, 2, 8, 9, 10],
+  MESSAGE_OPCODES: [0, 1, 2],
+  OPENING_OPCODES: [1, 2],
+
+  ERRORS: {
+    normal_closure:       1000,
+    going_away:           1001,
+    protocol_error:       1002,
+    unacceptable:         1003,
+    encoding_error:       1007,
+    policy_violation:     1008,
+    too_large:            1009,
+    extension_error:      1010,
+    unexpected_condition: 1011
+  },
+
+  ERROR_CODES:        [1000, 1001, 1002, 1003, 1007, 1008, 1009, 1010, 1011],
+  DEFAULT_ERROR_CODE: 1000,
+  MIN_RESERVED_ERROR: 3000,
+  MAX_RESERVED_ERROR: 4999,
+
+  // http://www.w3.org/International/questions/qa-forms-utf-8.en.php
+  UTF8_MATCH: /^([\x00-\x7F]|[\xC2-\xDF][\x80-\xBF]|\xE0[\xA0-\xBF][\x80-\xBF]|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}|\xED[\x80-\x9F][\x80-\xBF]|\xF0[\x90-\xBF][\x80-\xBF]{2}|[\xF1-\xF3][\x80-\xBF]{3}|\xF4[\x80-\x8F][\x80-\xBF]{2})*$/,
+
+  addExtension: function(extension) {
+    this._extensions.add(extension);
+    return true;
+  },
+
+  parse: function(chunk) {
+    this._reader.put(chunk);
+    var buffer = true;
+    while (buffer) {
+      switch (this._stage) {
+        case 0:
+          buffer = this._reader.read(1);
+          if (buffer) this._parseOpcode(buffer[0]);
+          break;
+
+        case 1:
+          buffer = this._reader.read(1);
+          if (buffer) this._parseLength(buffer[0]);
+          break;
+
+        case 2:
+          buffer = this._reader.read(this._frame.lengthBytes);
+          if (buffer) this._parseExtendedLength(buffer);
+          break;
+
+        case 3:
+          buffer = this._reader.read(4);
+          if (buffer) {
+            this._stage = 4;
+            this._frame.maskingKey = buffer;
+          }
+          break;
+
+        case 4:
+          buffer = this._reader.read(this._frame.length);
+          if (buffer) {
+            this._stage = 0;
+            this._emitFrame(buffer);
+          }
+          break;
+
+        default:
+          buffer = null;
+      }
+    }
+  },
+
+  text: function(message) {
+    if (this.readyState > 1) return false;
+    return this.frame(message, 'text');
+  },
+
+  binary: function(message) {
+    if (this.readyState > 1) return false;
+    return this.frame(message, 'binary');
+  },
+
+  ping: function(message, callback) {
+    if (this.readyState > 1) return false;
+    message = message || '';
+    if (callback) this._pingCallbacks[message] = callback;
+    return this.frame(message, 'ping');
+  },
+
+  pong: function(message) {
+      if (this.readyState > 1) return false;
+      message = message ||'';
+      return this.frame(message, 'pong');
+  },
+
+  close: function(reason, code) {
+    reason = reason || '';
+    code   = code   || this.ERRORS.normal_closure;
+
+    if (this.readyState <= 0) {
+      this.readyState = 3;
+      this.emit('close', new Base.CloseEvent(code, reason));
+      return true;
+    } else if (this.readyState === 1) {
+      this.readyState = 2;
+      this._extensions.close(function() { this.frame(reason, 'close', code) }, this);
+      return true;
+    } else {
+      return false;
+    }
+  },
+
+  frame: function(buffer, type, code) {
+    if (this.readyState <= 0) return this._queue([buffer, type, code]);
+    if (this.readyState > 2) return false;
+
+    if (buffer instanceof Array)    buffer = new Buffer(buffer);
+    if (typeof buffer === 'number') buffer = buffer.toString();
+
+    var message = new Message(),
+        isText  = (typeof buffer === 'string'),
+        payload, copy;
+
+    message.rsv1   = message.rsv2 = message.rsv3 = false;
+    message.opcode = this.OPCODES[type || (isText ? 'text' : 'binary')];
+
+    payload = isText ? new Buffer(buffer, 'utf8') : buffer;
+
+    if (code) {
+      copy = payload;
+      payload = new Buffer(2 + copy.length);
+      payload.writeUInt16BE(code, 0);
+      copy.copy(payload, 2);
+    }
+    message.data = payload;
+
+    var onMessageReady = function(message) {
+      var frame = new Frame();
+
+      frame.final   = true;
+      frame.rsv1    = message.rsv1;
+      frame.rsv2    = message.rsv2;
+      frame.rsv3    = message.rsv3;
+      frame.opcode  = message.opcode;
+      frame.masked  = !!this._masking;
+      frame.length  = message.data.length;
+      frame.payload = message.data;
+
+      if (frame.masked) frame.maskingKey = crypto.randomBytes(4);
+
+      this._sendFrame(frame);
+    };
+
+    if (this.MESSAGE_OPCODES.indexOf(message.opcode) >= 0)
+      this._extensions.processOutgoingMessage(message, function(error, message) {
+        if (error) return this._fail('extension_error', error.message);
+        onMessageReady.call(this, message);
+      }, this);
+    else
+      onMessageReady.call(this, message);
+
+    return true;
+  },
+
+  _sendFrame: function(frame) {
+    var length = frame.length,
+        header = (length <= 125) ? 2 : (length <= 65535 ? 4 : 10),
+        offset = header + (frame.masked ? 4 : 0),
+        buffer = new Buffer(offset + length),
+        masked = frame.masked ? this.MASK : 0;
+
+    buffer[0] = (frame.final ? this.FIN : 0) |
+                (frame.rsv1 ? this.RSV1 : 0) |
+                (frame.rsv2 ? this.RSV2 : 0) |
+                (frame.rsv3 ? this.RSV3 : 0) |
+                frame.opcode;
+
+    if (length <= 125) {
+      buffer[1] = masked | length;
+    } else if (length <= 65535) {
+      buffer[1] = masked | 126;
+      buffer.writeUInt16BE(length, 2);
+    } else {
+      buffer[1] = masked | 127;
+      buffer.writeUInt32BE(Math.floor(length / 0x100000000), 2);
+      buffer.writeUInt32BE(length % 0x100000000, 6);
+    }
+
+    frame.payload.copy(buffer, offset);
+
+    if (frame.masked) {
+      frame.maskingKey.copy(buffer, header);
+      Hybi.mask(buffer, frame.maskingKey, offset);
+    }
+
+    this._write(buffer);
+  },
+
+  _handshakeResponse: function() {
+    try {
+      var extensions = this._extensions.generateResponse(this._request.headers['sec-websocket-extensions']);
+    } catch (e) {
+      return this._fail('protocol_error', e.message);
+    }
+
+    if (extensions) this._headers.set('Sec-WebSocket-Extensions', extensions);
+
+    var start   = 'HTTP/1.1 101 Switching Protocols',
+        headers = [start, this._headers.toString(), ''];
+
+    return new Buffer(headers.join('\r\n'), 'utf8');
+  },
+
+  _shutdown: function(code, reason, error) {
+    delete this._frame;
+    delete this._message;
+    this._stage = 5;
+
+    var sendCloseFrame = (this.readyState === 1);
+    this.readyState = 2;
+
+    this._extensions.close(function() {
+      if (sendCloseFrame) this.frame(reason, 'close', code);
+      this.readyState = 3;
+      if (error) this.emit('error', new Error(reason));
+      this.emit('close', new Base.CloseEvent(code, reason));
+    }, this);
+  },
+
+  _fail: function(type, message) {
+    if (this.readyState > 1) return;
+    this._shutdown(this.ERRORS[type], message, true);
+  },
+
+  _parseOpcode: function(octet) {
+    var rsvs = [this.RSV1, this.RSV2, this.RSV3].map(function(rsv) {
+      return (octet & rsv) === rsv;
+    });
+
+    var frame = this._frame = new Frame();
+
+    frame.final  = (octet & this.FIN) === this.FIN;
+    frame.rsv1   = rsvs[0];
+    frame.rsv2   = rsvs[1];
+    frame.rsv3   = rsvs[2];
+    frame.opcode = (octet & this.OPCODE);
+
+    this._stage = 1;
+
+    if (!this._extensions.validFrameRsv(frame))
+      return this._fail('protocol_error',
+          'One or more reserved bits are on: reserved1 = ' + (frame.rsv1 ? 1 : 0) +
+          ', reserved2 = ' + (frame.rsv2 ? 1 : 0) +
+          ', reserved3 = ' + (frame.rsv3 ? 1 : 0));
+
+    if (this.OPCODE_CODES.indexOf(frame.opcode) < 0)
+      return this._fail('protocol_error', 'Unrecognized frame opcode: ' + frame.opcode);
+
+    if (this.MESSAGE_OPCODES.indexOf(frame.opcode) < 0 && !frame.final)
+      return this._fail('protocol_error', 'Received fragmented control frame: opcode = ' + frame.opcode);
+
+    if (this._message && this.OPENING_OPCODES.indexOf(frame.opcode) >= 0)
+      return this._fail('protocol_error', 'Received new data frame but previous continuous frame is unfinished');
+  },
+
+  _parseLength: function(octet) {
+    var frame = this._frame;
+    frame.masked = (octet & this.MASK) === this.MASK;
+    frame.length = (octet & this.LENGTH);
+
+    if (frame.length >= 0 && frame.length <= 125) {
+      this._stage = frame.masked ? 3 : 4;
+      if (!this._checkFrameLength()) return;
+    } else {
+      this._stage = 2;
+      frame.lengthBytes = (frame.length === 126 ? 2 : 8);
+    }
+
+    if (this._requireMasking && !frame.masked)
+      return this._fail('unacceptable', 'Received unmasked frame but masking is required');
+  },
+
+  _parseExtendedLength: function(buffer) {
+    var frame = this._frame;
+    frame.length = this._readUInt(buffer);
+
+    this._stage = frame.masked ? 3 : 4;
+
+    if (this.MESSAGE_OPCODES.indexOf(frame.opcode) < 0 && frame.length > 125)
+      return this._fail('protocol_error', 'Received control frame having too long payload: ' + frame.length);
+
+    if (!this._checkFrameLength()) return;
+  },
+
+  _checkFrameLength: function() {
+    var length = this._message ? this._message.length : 0;
+
+    if (length + this._frame.length > this._maxLength) {
+      this._fail('too_large', 'WebSocket frame length too large');
+      return false;
+    } else {
+      return true;
+    }
+  },
+
+  _emitFrame: function(buffer) {
+    var frame   = this._frame,
+        payload = frame.payload = Hybi.mask(buffer, frame.maskingKey),
+        opcode  = frame.opcode,
+        message,
+        code, reason,
+        callbacks, callback;
+
+    delete this._frame;
+
+    if (opcode === this.OPCODES.continuation) {
+      if (!this._message) return this._fail('protocol_error', 'Received unexpected continuation frame');
+      this._message.pushFrame(frame);
+    }
+
+    if (opcode === this.OPCODES.text || opcode === this.OPCODES.binary) {
+      this._message = new Message();
+      this._message.pushFrame(frame);
+    }
+
+    if (frame.final && this.MESSAGE_OPCODES.indexOf(opcode) >= 0)
+      return this._emitMessage(this._message);
+
+    if (opcode === this.OPCODES.close) {
+      code   = (payload.length >= 2) ? payload.readUInt16BE(0) : null;
+      reason = (payload.length > 2) ? this._encode(payload.slice(2)) : null;
+
+      if (!(payload.length === 0) &&
+          !(code !== null && code >= this.MIN_RESERVED_ERROR && code <= this.MAX_RESERVED_ERROR) &&
+          this.ERROR_CODES.indexOf(code) < 0)
+        code = this.ERRORS.protocol_error;
+
+      if (payload.length > 125 || (payload.length > 2 && !reason))
+        code = this.ERRORS.protocol_error;
+
+      this._shutdown(code || this.DEFAULT_ERROR_CODE, reason || '');
+    }
+
+    if (opcode === this.OPCODES.ping) {
+      this.frame(payload, 'pong');
+    }
+
+    if (opcode === this.OPCODES.pong) {
+      callbacks = this._pingCallbacks;
+      message   = this._encode(payload);
+      callback  = callbacks[message];
+
+      delete callbacks[message];
+      if (callback) callback()
+    }
+  },
+
+  _emitMessage: function(message) {
+    var message = this._message;
+    message.read();
+
+    delete this._message;
+
+    this._extensions.processIncomingMessage(message, function(error, message) {
+      if (error) return this._fail('extension_error', error.message);
+
+      var payload = message.data;
+      if (message.opcode === this.OPCODES.text) payload = this._encode(payload);
+
+      if (payload === null)
+        return this._fail('encoding_error', 'Could not decode a text frame as UTF-8');
+      else
+        this.emit('message', new Base.MessageEvent(payload));
+    }, this);
+  },
+
+  _encode: function(buffer) {
+    try {
+      var string = buffer.toString('binary', 0, buffer.length);
+      if (!this.UTF8_MATCH.test(string)) return null;
+    } catch (e) {}
+    return buffer.toString('utf8', 0, buffer.length);
+  },
+
+  _readUInt: function(buffer) {
+    if (buffer.length === 2) return buffer.readUInt16BE(0);
+
+    return buffer.readUInt32BE(0) * 0x100000000 +
+           buffer.readUInt32BE(4);
+  }
+};
+
+for (var key in instance)
+  Hybi.prototype[key] = instance[key];
+
+module.exports = Hybi;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/hybi/frame.js b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/hybi/frame.js
new file mode 100644
index 0000000000000000000000000000000000000000..0fb003f821500254d81a42181d88b17e731b9a89
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/hybi/frame.js
@@ -0,0 +1,21 @@
+'use strict';
+
+var Frame = function() {};
+
+var instance = {
+  final:        false,
+  rsv1:         false,
+  rsv2:         false,
+  rsv3:         false,
+  opcode:       null,
+  masked:       false,
+  maskingKey:   null,
+  lengthBytes:  1,
+  length:       0,
+  payload:      null
+};
+
+for (var key in instance)
+  Frame.prototype[key] = instance[key];
+
+module.exports = Frame;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/hybi/message.js b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/hybi/message.js
new file mode 100644
index 0000000000000000000000000000000000000000..3db1a3ccb4401b4b2e00f8fb39c08f98f474f51c
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/hybi/message.js
@@ -0,0 +1,41 @@
+'use strict';
+
+var Message = function() {
+  this.rsv1    = false;
+  this.rsv2    = false;
+  this.rsv3    = false;
+  this.opcode  = null
+  this.length  = 0;
+  this._chunks = [];
+};
+
+var instance = {
+  read: function() {
+    if (this.data) return this.data;
+
+    this.data  = new Buffer(this.length);
+    var offset = 0;
+
+    for (var i = 0, n = this._chunks.length; i < n; i++) {
+      this._chunks[i].copy(this.data, offset);
+      offset += this._chunks[i].length;
+    }
+    return this.data;
+  },
+
+  pushFrame: function(frame) {
+    this.rsv1 = this.rsv1 || frame.rsv1;
+    this.rsv2 = this.rsv2 || frame.rsv2;
+    this.rsv3 = this.rsv3 || frame.rsv3;
+
+    if (this.opcode === null) this.opcode = frame.opcode;
+
+    this._chunks.push(frame.payload);
+    this.length += frame.length;
+  }
+};
+
+for (var key in instance)
+  Message.prototype[key] = instance[key];
+
+module.exports = Message;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/proxy.js b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/proxy.js
new file mode 100644
index 0000000000000000000000000000000000000000..e7362eaebbf1978b5d2543490c21d4b6a385914b
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/proxy.js
@@ -0,0 +1,98 @@
+'use strict';
+
+var Stream     = require('stream').Stream,
+    url        = require('url'),
+    util       = require('util'),
+    Base       = require('./base'),
+    Headers    = require('./headers'),
+    HttpParser = require('../http_parser');
+
+var PORTS = {'ws:': 80, 'wss:': 443};
+
+var Proxy = function(client, origin, options) {
+  this._client  = client;
+  this._http    = new HttpParser('response');
+  this._origin  = (typeof client.url === 'object') ? client.url : url.parse(client.url);
+  this._url     = (typeof origin === 'object') ? origin : url.parse(origin);
+  this._options = options || {};
+  this._state   = 0;
+
+  this.readable = this.writable = true;
+  this._paused  = false;
+
+  this._headers = new Headers();
+  this._headers.set('Host', this._origin.host);
+  this._headers.set('Connection', 'keep-alive');
+  this._headers.set('Proxy-Connection', 'keep-alive');
+
+  var auth = this._url.auth && new Buffer(this._url.auth, 'utf8').toString('base64');
+  if (auth) this._headers.set('Proxy-Authorization', 'Basic ' + auth);
+};
+util.inherits(Proxy, Stream);
+
+var instance = {
+  setHeader: function(name, value) {
+    if (this._state !== 0) return false;
+    this._headers.set(name, value);
+    return true;
+  },
+
+  start: function() {
+    if (this._state !== 0) return false;
+    this._state = 1;
+
+    var origin = this._origin,
+        port   = origin.port || PORTS[origin.protocol],
+        start  = 'CONNECT ' + origin.hostname + ':' + port + ' HTTP/1.1';
+
+    var headers = [start, this._headers.toString(), ''];
+
+    this.emit('data', new Buffer(headers.join('\r\n'), 'utf8'));
+    return true;
+  },
+
+  pause: function() {
+    this._paused = true;
+  },
+
+  resume: function() {
+    this._paused = false;
+    this.emit('drain');
+  },
+
+  write: function(chunk) {
+    if (!this.writable) return false;
+
+    this._http.parse(chunk);
+    if (!this._http.isComplete()) return !this._paused;
+
+    this.statusCode = this._http.statusCode;
+    this.headers    = this._http.headers;
+
+    if (this.statusCode === 200) {
+      this.emit('connect', new Base.ConnectEvent());
+    } else {
+      var message = "Can't establish a connection to the server at " + this._origin.href;
+      this.emit('error', new Error(message));
+    }
+    this.end();
+    return !this._paused;
+  },
+
+  end: function(chunk) {
+    if (!this.writable) return;
+    if (chunk !== undefined) this.write(chunk);
+    this.readable = this.writable = false;
+    this.emit('close');
+    this.emit('end');
+  },
+
+  destroy: function() {
+    this.end();
+  }
+};
+
+for (var key in instance)
+  Proxy.prototype[key] = instance[key];
+
+module.exports = Proxy;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/server.js b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/server.js
new file mode 100644
index 0000000000000000000000000000000000000000..964ed28669d84d785689275a9018e13d00970ffb
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/server.js
@@ -0,0 +1,108 @@
+'use strict';
+
+var util       = require('util'),
+    HttpParser = require('../http_parser'),
+    Base       = require('./base'),
+    Draft75    = require('./draft75'),
+    Draft76    = require('./draft76'),
+    Hybi       = require('./hybi');
+
+var Server = function(options) {
+  Base.call(this, null, null, options);
+  this._http = new HttpParser('request');
+};
+util.inherits(Server, Base);
+
+var instance = {
+  EVENTS: ['open', 'message', 'error', 'close'],
+
+  _bindEventListeners: function() {
+    this.messages.on('error', function() {});
+    this.on('error', function() {});
+  },
+
+  parse: function(chunk) {
+    if (this._delegate) return this._delegate.parse(chunk);
+
+    this._http.parse(chunk);
+    if (!this._http.isComplete()) return;
+
+    this.method  = this._http.method;
+    this.url     = this._http.url;
+    this.headers = this._http.headers;
+    this.body    = this._http.body;
+
+    var self = this;
+    this._delegate = Server.http(this, this._options);
+    this._delegate.messages = this.messages;
+    this._delegate.io = this.io;
+    this._open();
+
+    this.EVENTS.forEach(function(event) {
+      this._delegate.on(event, function(e) { self.emit(event, e) });
+    }, this);
+
+    this.protocol = this._delegate.protocol;
+    this.version  = this._delegate.version;
+
+    this.parse(this._http.body);
+    this.emit('connect', new Base.ConnectEvent());
+  },
+
+  _open: function() {
+    this.__queue.forEach(function(msg) {
+      this._delegate[msg[0]].apply(this._delegate, msg[1]);
+    }, this);
+    this.__queue = [];
+  }
+};
+
+['addExtension', 'setHeader', 'start', 'frame', 'text', 'binary', 'ping', 'close'].forEach(function(method) {
+  instance[method] = function() {
+    if (this._delegate) {
+      return this._delegate[method].apply(this._delegate, arguments);
+    } else {
+      this.__queue.push([method, arguments]);
+      return true;
+    }
+  };
+});
+
+for (var key in instance)
+  Server.prototype[key] = instance[key];
+
+Server.isSecureRequest = function(request) {
+  if (request.connection && request.connection.authorized !== undefined) return true;
+  if (request.socket && request.socket.secure) return true;
+
+  var headers = request.headers;
+  if (!headers) return false;
+  if (headers['https'] === 'on') return true;
+  if (headers['x-forwarded-ssl'] === 'on') return true;
+  if (headers['x-forwarded-scheme'] === 'https') return true;
+  if (headers['x-forwarded-proto'] === 'https') return true;
+
+  return false;
+};
+
+Server.determineUrl = function(request) {
+  var scheme = this.isSecureRequest(request) ? 'wss:' : 'ws:';
+  return scheme + '//' + request.headers.host + request.url;
+};
+
+Server.http = function(request, options) {
+  options = options || {};
+  if (options.requireMasking === undefined) options.requireMasking = true;
+
+  var headers = request.headers,
+      url     = this.determineUrl(request);
+
+  if (headers['sec-websocket-version'])
+    return new Hybi(request, url, options);
+  else if (headers['sec-websocket-key1'])
+    return new Draft76(request, url, options);
+  else
+    return new Draft75(request, url, options);
+};
+
+module.exports = Server;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/stream_reader.js b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/stream_reader.js
new file mode 100644
index 0000000000000000000000000000000000000000..04a15db1bac92ab5ef2e798d527239390a73fa90
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/driver/stream_reader.js
@@ -0,0 +1,80 @@
+'use strict';
+
+var StreamReader = function() {
+  this._queue     = [];
+  this._queueSize = 0;
+  this._offset    = 0;
+};
+
+StreamReader.prototype.put = function(buffer) {
+  if (!buffer || buffer.length === 0) return;
+  if (!buffer.copy) buffer = new Buffer(buffer);
+  this._queue.push(buffer);
+  this._queueSize += buffer.length;
+};
+
+StreamReader.prototype.read = function(length) {
+  if (length > this._queueSize) return null;
+  if (length === 0) return new Buffer(0);
+
+  this._queueSize -= length;
+
+  var queue  = this._queue,
+      remain = length,
+      first  = queue[0],
+      buffers, buffer;
+
+  if (first.length >= length) {
+    if (first.length === length) {
+      return queue.shift();
+    } else {
+      buffer = first.slice(0, length);
+      queue[0] = first.slice(length);
+      return buffer;
+    }
+  }
+
+  for (var i = 0, n = queue.length; i < n; i++) {
+    if (remain < queue[i].length) break;
+    remain -= queue[i].length;
+  }
+  buffers = queue.splice(0, i);
+
+  if (remain > 0 && queue.length > 0) {
+    buffers.push(queue[0].slice(0, remain));
+    queue[0] = queue[0].slice(remain);
+  }
+  return this._concat(buffers, length);
+};
+
+StreamReader.prototype.eachByte = function(callback, context) {
+  var buffer, n, index;
+
+  while (this._queue.length > 0) {
+    buffer = this._queue[0];
+    n = buffer.length;
+
+    while (this._offset < n) {
+      index = this._offset;
+      this._offset += 1;
+      callback.call(context, buffer[index]);
+    }
+    this._offset = 0;
+    this._queue.shift();
+  }
+};
+
+StreamReader.prototype._concat = function(buffers, length) {
+  if (Buffer.concat) return Buffer.concat(buffers, length);
+
+  var buffer = new Buffer(length),
+      offset = 0;
+
+  for (var i = 0, n = buffers.length; i < n; i++) {
+    buffers[i].copy(buffer, offset);
+    offset += buffers[i].length;
+  }
+  return buffer;
+};
+
+module.exports = StreamReader;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/http_parser.js b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/http_parser.js
new file mode 100644
index 0000000000000000000000000000000000000000..7ef4d95d2bc142f6c1271bd06df3992cf4b284f7
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/http_parser.js
@@ -0,0 +1,100 @@
+'use strict';
+
+var NodeHTTPParser = process.binding('http_parser').HTTPParser,
+    version        = NodeHTTPParser.RESPONSE ? 6 : 4;
+
+var HttpParser = function(type) {
+  if (type === 'request')
+    this._parser = new NodeHTTPParser(NodeHTTPParser.REQUEST || 'request');
+  else
+    this._parser = new NodeHTTPParser(NodeHTTPParser.RESPONSE || 'response');
+
+  this._type     = type;
+  this._complete = false;
+  this.headers   = {};
+
+  var current = null,
+      self    = this;
+
+  this._parser.onHeaderField = function(b, start, length) {
+    current = b.toString('utf8', start, start + length).toLowerCase();
+  };
+
+  this._parser.onHeaderValue = function(b, start, length) {
+    var value = b.toString('utf8', start, start + length);
+
+    if (self.headers.hasOwnProperty(current))
+      self.headers[current] += ', ' + value;
+    else
+      self.headers[current] = value;
+  };
+
+  this._parser.onHeadersComplete = this._parser[NodeHTTPParser.kOnHeadersComplete] =
+  function(majorVersion, minorVersion, headers, method, pathname, statusCode) {
+    var info = arguments[0];
+
+    if (typeof info === 'object') {
+      method     = info.method;
+      pathname   = info.url;
+      statusCode = info.statusCode;
+      headers    = info.headers;
+    }
+
+    self.method     = (typeof method === 'number') ? HttpParser.METHODS[method] : method;
+    self.statusCode = statusCode;
+    self.url        = pathname;
+
+    if (!headers) return;
+
+    for (var i = 0, n = headers.length, key, value; i < n; i += 2) {
+      key   = headers[i].toLowerCase();
+      value = headers[i+1];
+      if (self.headers.hasOwnProperty(key))
+        self.headers[key] += ', ' + value;
+      else
+        self.headers[key] = value;
+    }
+
+    self._complete = true;
+  };
+};
+
+HttpParser.METHODS = {
+  0:  'DELETE',
+  1:  'GET',
+  2:  'HEAD',
+  3:  'POST',
+  4:  'PUT',
+  5:  'CONNECT',
+  6:  'OPTIONS',
+  7:  'TRACE',
+  8:  'COPY',
+  9:  'LOCK',
+  10: 'MKCOL',
+  11: 'MOVE',
+  12: 'PROPFIND',
+  13: 'PROPPATCH',
+  14: 'SEARCH',
+  15: 'UNLOCK',
+  16: 'REPORT',
+  17: 'MKACTIVITY',
+  18: 'CHECKOUT',
+  19: 'MERGE',
+  24: 'PATCH'
+};
+
+HttpParser.prototype.isComplete = function() {
+  return this._complete;
+};
+
+HttpParser.prototype.parse = function(chunk) {
+  var offset   = (version < 6) ? 1 : 0,
+      consumed = this._parser.execute(chunk, 0, chunk.length) + offset;
+
+  if (this._complete)
+    this.body = (consumed < chunk.length)
+              ? chunk.slice(consumed)
+              : new Buffer(0);
+};
+
+module.exports = HttpParser;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/streams.js b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/streams.js
new file mode 100644
index 0000000000000000000000000000000000000000..96ab31fa39016d8da715505f5e7016c95deac299
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/lib/websocket/streams.js
@@ -0,0 +1,146 @@
+'use strict';
+
+/**
+
+Streams in a WebSocket connection
+---------------------------------
+
+We model a WebSocket as two duplex streams: one stream is for the wire protocol
+over an I/O socket, and the other is for incoming/outgoing messages.
+
+
+                        +----------+      +---------+      +----------+
+    [1] write(chunk) -->| ~~~~~~~~ +----->| parse() +----->| ~~~~~~~~ +--> emit('data') [2]
+                        |          |      +----+----+      |          |
+                        |          |           |           |          |
+                        |    IO    |           | [5]       | Messages |
+                        |          |           V           |          |
+                        |          |      +---------+      |          |
+    [4] emit('data') <--+ ~~~~~~~~ |<-----+ frame() |<-----+ ~~~~~~~~ |<-- write(chunk) [3]
+                        +----------+      +---------+      +----------+
+
+
+Message transfer in each direction is simple: IO receives a byte stream [1] and
+sends this stream for parsing. The parser will periodically emit a complete
+message text on the Messages stream [2]. Similarly, when messages are written
+to the Messages stream [3], they are framed using the WebSocket wire format and
+emitted via IO [4].
+
+There is a feedback loop via [5] since some input from [1] will be things like
+ping, pong and close frames. In these cases the protocol responds by emitting
+responses directly back to [4] rather than emitting messages via [2].
+
+For the purposes of flow control, we consider the sources of each Readable
+stream to be as follows:
+
+* [2] receives input from [1]
+* [4] receives input from [1] and [3]
+
+The classes below express the relationships described above without prescribing
+anything about how parse() and frame() work, other than assuming they emit
+'data' events to the IO and Messages streams. They will work with any protocol
+driver having these two methods.
+**/
+
+
+var Stream = require('stream').Stream,
+    util   = require('util');
+
+
+var IO = function(driver) {
+  this.readable = this.writable = true;
+  this._paused  = false;
+  this._driver  = driver;
+};
+util.inherits(IO, Stream);
+
+// The IO pause() and resume() methods will be called when the socket we are
+// piping to gets backed up and drains. Since IO output [4] comes from IO input
+// [1] and Messages input [3], we need to tell both of those to return false
+// from write() when this stream is paused.
+
+IO.prototype.pause = function() {
+  this._paused = true;
+  this._driver.messages._paused = true;
+};
+
+IO.prototype.resume = function() {
+  this._paused = false;
+  this.emit('drain');
+
+  var messages = this._driver.messages;
+  messages._paused = false;
+  messages.emit('drain');
+};
+
+// When we receive input from a socket, send it to the parser and tell the
+// source whether to back off.
+IO.prototype.write = function(chunk) {
+  if (!this.writable) return false;
+  this._driver.parse(chunk);
+  return !this._paused;
+};
+
+// The IO end() method will be called when the socket piping into it emits
+// 'close' or 'end', i.e. the socket is closed. In this situation the Messages
+// stream will not emit any more data so we emit 'end'.
+IO.prototype.end = function(chunk) {
+  if (!this.writable) return;
+  if (chunk !== undefined) this.write(chunk);
+  this.writable = false;
+
+  var messages = this._driver.messages;
+  if (messages.readable) {
+    messages.readable = messages.writable = false;
+    messages.emit('end');
+  }
+};
+
+IO.prototype.destroy = function() {
+  this.end();
+};
+
+
+var Messages = function(driver) {
+  this.readable = this.writable = true;
+  this._paused  = false;
+  this._driver  = driver;
+};
+util.inherits(Messages, Stream);
+
+// The Messages pause() and resume() methods will be called when the app that's
+// processing the messages gets backed up and drains. If we're emitting
+// messages too fast we should tell the source to slow down. Message output [2]
+// comes from IO input [1].
+
+Messages.prototype.pause = function() {
+  this._driver.io._paused = true;
+};
+
+Messages.prototype.resume = function() {
+  this._driver.io._paused = false;
+  this._driver.io.emit('drain');
+};
+
+// When we receive messages from the user, send them to the formatter and tell
+// the source whether to back off.
+Messages.prototype.write = function(message) {
+  if (!this.writable) return false;
+  if (typeof message === 'string') this._driver.text(message);
+  else this._driver.binary(message);
+  return !this._paused;
+};
+
+// The Messages end() method will be called when a stream piping into it emits
+// 'end'. Many streams may be piped into the WebSocket and one of them ending
+// does not mean the whole socket is done, so just process the input and move
+// on leaving the socket open.
+Messages.prototype.end = function(message) {
+  if (message !== undefined) this.write(message);
+};
+
+Messages.prototype.destroy = function() {};
+
+
+exports.IO = IO;
+exports.Messages = Messages;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/package.json b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..3abb9f73aa95832e7467f7bad8ae6f50da63f62c
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-driver/package.json
@@ -0,0 +1,76 @@
+{
+  "_args": [
+    [
+      {
+        "raw": "websocket-driver@https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz",
+        "scope": null,
+        "escapedName": "websocket-driver",
+        "name": "websocket-driver",
+        "rawSpec": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz",
+        "spec": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz",
+        "type": "remote"
+      },
+      "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin"
+    ]
+  ],
+  "_from": "websocket-driver@>=0.5.1",
+  "_id": "websocket-driver@0.6.5",
+  "_inCache": true,
+  "_location": "/firebase-admin/websocket-driver",
+  "_phantomChildren": {},
+  "_requested": {
+    "raw": "websocket-driver@https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz",
+    "scope": null,
+    "escapedName": "websocket-driver",
+    "name": "websocket-driver",
+    "rawSpec": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz",
+    "spec": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz",
+    "type": "remote"
+  },
+  "_requiredBy": [
+    "/firebase-admin",
+    "/firebase-admin/faye-websocket"
+  ],
+  "_resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz",
+  "_shasum": "5cb2556ceb85f4373c6d8238aa691c8454e13a36",
+  "_shrinkwrap": null,
+  "_spec": "websocket-driver@https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz",
+  "_where": "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin",
+  "author": {
+    "name": "James Coglan",
+    "email": "jcoglan@gmail.com",
+    "url": "http://jcoglan.com/"
+  },
+  "bugs": {
+    "url": "https://github.com/faye/websocket-driver-node/issues"
+  },
+  "dependencies": {
+    "websocket-extensions": ">=0.1.1"
+  },
+  "description": "WebSocket protocol handler with pluggable I/O",
+  "devDependencies": {
+    "jstest": "",
+    "permessage-deflate": ""
+  },
+  "engines": {
+    "node": ">=0.6.0"
+  },
+  "homepage": "https://github.com/faye/websocket-driver-node",
+  "keywords": [
+    "websocket"
+  ],
+  "license": "MIT",
+  "main": "./lib/websocket/driver",
+  "name": "websocket-driver",
+  "optionalDependencies": {},
+  "readme": "# websocket-driver [![Build Status](https://travis-ci.org/faye/websocket-driver-node.svg)](https://travis-ci.org/faye/websocket-driver-node)\n\nThis module provides a complete implementation of the WebSocket protocols that\ncan be hooked up to any I/O stream. It aims to simplify things by decoupling the\nprotocol details from the I/O layer, such that users only need to implement code\nto stream data in and out of it without needing to know anything about how the\nprotocol actually works. Think of it as a complete WebSocket system with\npluggable I/O.\n\nDue to this design, you get a lot of things for free. In particular, if you hook\nthis module up to some I/O object, it will do all of this for you:\n\n* Select the correct server-side driver to talk to the client\n* Generate and send both server- and client-side handshakes\n* Recognize when the handshake phase completes and the WS protocol begins\n* Negotiate subprotocol selection based on `Sec-WebSocket-Protocol`\n* Negotiate and use extensions via the\n  [websocket-extensions](https://github.com/faye/websocket-extensions-node)\n  module\n* Buffer sent messages until the handshake process is finished\n* Deal with proxies that defer delivery of the draft-76 handshake body\n* Notify you when the socket is open and closed and when messages arrive\n* Recombine fragmented messages\n* Dispatch text, binary, ping, pong and close frames\n* Manage the socket-closing handshake process\n* Automatically reply to ping frames with a matching pong\n* Apply masking to messages sent by the client\n\nThis library was originally extracted from the [Faye](http://faye.jcoglan.com)\nproject but now aims to provide simple WebSocket support for any Node-based\nproject.\n\n\n## Installation\n\n```\n$ npm install websocket-driver\n```\n\n\n## Usage\n\nThis module provides protocol drivers that have the same interface on the server\nand on the client. A WebSocket driver is an object with two duplex streams\nattached; one for incoming/outgoing messages and one for managing the wire\nprotocol over an I/O stream. The full API is described below.\n\n\n### Server-side with HTTP\n\nA Node webserver emits a special event for 'upgrade' requests, and this is where\nyou should handle WebSockets. You first check whether the request is a\nWebSocket, and if so you can create a driver and attach the request's I/O stream\nto it.\n\n```js\nvar http = require('http'),\n    websocket = require('websocket-driver');\n\nvar server = http.createServer();\n\nserver.on('upgrade', function(request, socket, body) {\n  if (!websocket.isWebSocket(request)) return;\n\n  var driver = websocket.http(request);\n\n  driver.io.write(body);\n  socket.pipe(driver.io).pipe(socket);\n\n  driver.messages.on('data', function(message) {\n    console.log('Got a message', message);\n  });\n\n  driver.start();\n});\n```\n\nNote the line `driver.io.write(body)` - you must pass the `body` buffer to the\nsocket driver in order to make certain versions of the protocol work.\n\n\n### Server-side with TCP\n\nYou can also handle WebSocket connections in a bare TCP server, if you're not\nusing an HTTP server and don't want to implement HTTP parsing yourself.\n\nThe driver will emit a `connect` event when a request is received, and at this\npoint you can detect whether it's a WebSocket and handle it as such. Here's an\nexample using the Node `net` module:\n\n```js\nvar net = require('net'),\n    websocket = require('websocket-driver');\n\nvar server = net.createServer(function(connection) {\n  var driver = websocket.server();\n\n  driver.on('connect', function() {\n    if (websocket.isWebSocket(driver)) {\n      driver.start();\n    } else {\n      // handle other HTTP requests\n    }\n  });\n\n  driver.on('close', function() { connection.end() });\n  connection.on('error', function() {});\n\n  connection.pipe(driver.io).pipe(connection);\n\n  driver.messages.pipe(driver.messages);\n});\n\nserver.listen(4180);\n```\n\nIn the `connect` event, the driver gains several properties to describe the\nrequest, similar to a Node request object, such as `method`, `url` and\n`headers`. However you should remember it's not a real request object; you\ncannot write data to it, it only tells you what request data we parsed from the\ninput.\n\nIf the request has a body, it will be in the `driver.body` buffer, but only as\nmuch of the body as has been piped into the driver when the `connect` event\nfires.\n\n\n### Client-side\n\nSimilarly, to implement a WebSocket client you just need to make a driver by\npassing in a URL. After this you use the driver API as described below to\nprocess incoming data and send outgoing data.\n\n\n```js\nvar net = require('net'),\n    websocket = require('websocket-driver');\n\nvar driver = websocket.client('ws://www.example.com/socket'),\n    tcp = net.connect(80, 'www.example.com');\n\ntcp.pipe(driver.io).pipe(tcp);\n\ntcp.on('connect', function() {\n  driver.start();\n});\n\ndriver.messages.on('data', function(message) {\n  console.log('Got a message', message);\n});\n```\n\nClient drivers have two additional properties for reading the HTTP data that was\nsent back by the server:\n\n* `driver.statusCode` - the integer value of the HTTP status code\n* `driver.headers` - an object containing the response headers\n\n\n### HTTP Proxies\n\nThe client driver supports connections via HTTP proxies using the `CONNECT`\nmethod. Instead of sending the WebSocket handshake immediately, it will send a\n`CONNECT` request, wait for a `200` response, and then proceed as normal.\n\nTo use this feature, call `driver.proxy(url)` where `url` is the origin of the\nproxy, including a username and password if required. This produces a duplex\nstream that you should pipe in and out of your TCP connection to the proxy\nserver. When the proxy emits `connect`, you can then pipe `driver.io` to your\nTCP stream and call `driver.start()`.\n\n```js\nvar net = require('net'),\n    websocket = require('websocket-driver');\n\nvar driver = websocket.client('ws://www.example.com/socket'),\n    proxy  = driver.proxy('http://username:password@proxy.example.com'),\n    tcp    = net.connect(80, 'proxy.example.com');\n\ntcp.pipe(proxy).pipe(tcp, {end: false});\n\ntcp.on('connect', function() {\n  proxy.start();\n});\n\nproxy.on('connect', function() {\n  driver.io.pipe(tcp).pipe(driver.io);\n  driver.start();\n});\n\ndriver.messages.on('data', function(message) {\n  console.log('Got a message', message);\n});\n```\n\nThe proxy's `connect` event is also where you should perform a TLS handshake on\nyour TCP stream, if you are connecting to a `wss:` endpoint.\n\nIn the event that proxy connection fails, `proxy` will emit an `error`. You can\ninspect the proxy's response via `proxy.statusCode` and `proxy.headers`.\n\n```js\nproxy.on('error', function(error) {\n  console.error(error.message);\n  console.log(proxy.statusCode);\n  console.log(proxy.headers);\n});\n```\n\nBefore calling `proxy.start()` you can set custom headers using\n`proxy.setHeader()`:\n\n```js\nproxy.setHeader('User-Agent', 'node');\nproxy.start();\n```\n\n\n### Driver API\n\nDrivers are created using one of the following methods:\n\n```js\ndriver = websocket.http(request, options)\ndriver = websocket.server(options)\ndriver = websocket.client(url, options)\n```\n\nThe `http` method returns a driver chosen using the headers from a Node HTTP\nrequest object. The `server` method returns a driver that will parse an HTTP\nrequest and then decide which driver to use for it using the `http` method. The\n`client` method always returns a driver for the RFC version of the protocol with\nmasking enabled on outgoing frames.\n\nThe `options` argument is optional, and is an object. It may contain the\nfollowing fields:\n\n* `maxLength` - the maximum allowed size of incoming message frames, in bytes.\n  The default value is `2^26 - 1`, or 1 byte short of 64 MiB.\n* `protocols` - an array of strings representing acceptable subprotocols for use\n  over the socket. The driver will negotiate one of these to use via the\n  `Sec-WebSocket-Protocol` header if supported by the other peer.\n\nA driver has two duplex streams attached to it:\n\n* <b>`driver.io`</b> - this stream should be attached to an I/O socket like a\n  TCP stream. Pipe incoming TCP chunks to this stream for them to be parsed, and\n  pipe this stream back into TCP to send outgoing frames.\n* <b>`driver.messages`</b> - this stream emits messages received over the\n  WebSocket.  Writing to it sends messages to the other peer by emitting frames\n  via the `driver.io` stream.\n\nAll drivers respond to the following API methods, but some of them are no-ops\ndepending on whether the client supports the behaviour.\n\nNote that most of these methods are commands: if they produce data that should\nbe sent over the socket, they will give this to you by emitting `data` events on\nthe `driver.io` stream.\n\n#### `driver.on('open', function(event) {})`\n\nAdds a callback to execute when the socket becomes open.\n\n#### `driver.on('message', function(event) {})`\n\nAdds a callback to execute when a message is received. `event` will have a\n`data` attribute containing either a string in the case of a text message or a\n`Buffer` in the case of a binary message.\n\nYou can also listen for messages using the `driver.messages.on('data')` event,\nwhich emits strings for text messages and buffers for binary messages.\n\n#### `driver.on('error', function(event) {})`\n\nAdds a callback to execute when a protocol error occurs due to the other peer\nsending an invalid byte sequence. `event` will have a `message` attribute\ndescribing the error.\n\n#### `driver.on('close', function(event) {})`\n\nAdds a callback to execute when the socket becomes closed. The `event` object\nhas `code` and `reason` attributes.\n\n#### `driver.addExtension(extension)`\n\nRegisters a protocol extension whose operation will be negotiated via the\n`Sec-WebSocket-Extensions` header. `extension` is any extension compatible with\nthe [websocket-extensions](https://github.com/faye/websocket-extensions-node)\nframework.\n\n#### `driver.setHeader(name, value)`\n\nSets a custom header to be sent as part of the handshake response, either from\nthe server or from the client. Must be called before `start()`, since this is\nwhen the headers are serialized and sent.\n\n#### `driver.start()`\n\nInitiates the protocol by sending the handshake - either the response for a\nserver-side driver or the request for a client-side one. This should be the\nfirst method you invoke.  Returns `true` if and only if a handshake was sent.\n\n#### `driver.parse(string)`\n\nTakes a string and parses it, potentially resulting in message events being\nemitted (see `on('message')` above) or in data being sent to `driver.io`.  You\nshould send all data you receive via I/O to this method by piping a stream into\n`driver.io`.\n\n#### `driver.text(string)`\n\nSends a text message over the socket. If the socket handshake is not yet\ncomplete, the message will be queued until it is. Returns `true` if the message\nwas sent or queued, and `false` if the socket can no longer send messages.\n\nThis method is equivalent to `driver.messages.write(string)`.\n\n#### `driver.binary(buffer)`\n\nTakes a `Buffer` and sends it as a binary message. Will queue and return `true`\nor `false` the same way as the `text` method. It will also return `false` if the\ndriver does not support binary messages.\n\nThis method is equivalent to `driver.messages.write(buffer)`.\n\n#### `driver.ping(string = '', function() {})`\n\nSends a ping frame over the socket, queueing it if necessary. `string` and the\ncallback are both optional. If a callback is given, it will be invoked when the\nsocket receives a pong frame whose content matches `string`. Returns `false` if\nframes can no longer be sent, or if the driver does not support ping/pong.\n\n#### `driver.pong(string = '')`\n\nSends a pong frame over the socket, queueing it if necessary. `string` is\noptional. Returns `false` if frames can no longer be sent, or if the driver does\nnot support ping/pong.\n\nYou don't need to call this when a ping frame is received; pings are replied to\nautomatically by the driver. This method is for sending unsolicited pongs.\n\n#### `driver.close()`\n\nInitiates the closing handshake if the socket is still open. For drivers with no\nclosing handshake, this will result in the immediate execution of the\n`on('close')` driver. For drivers with a closing handshake, this sends a closing\nframe and `emit('close')` will execute when a response is received or a protocol\nerror occurs.\n\n#### `driver.version`\n\nReturns the WebSocket version in use as a string. Will either be `hixie-75`,\n`hixie-76` or `hybi-$version`.\n\n#### `driver.protocol`\n\nReturns a string containing the selected subprotocol, if any was agreed upon\nusing the `Sec-WebSocket-Protocol` mechanism. This value becomes available after\n`emit('open')` has fired.\n\n\n## License\n\n(The MIT License)\n\nCopyright (c) 2010-2016 James Coglan\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the 'Software'), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n",
+  "readmeFilename": "README.md",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/faye/websocket-driver-node.git"
+  },
+  "scripts": {
+    "test": "jstest spec/runner.js"
+  },
+  "version": "0.6.5"
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/CHANGELOG.md b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..065eed767e1302228736fad12609701abc9fccdd
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/CHANGELOG.md
@@ -0,0 +1,8 @@
+### 0.1.1 / 2015-02-19
+
+* Prevent sessions being closed before they have finished processing messages
+* Add a callback to `Extensions.close()` so the caller can tell when it's safe to close the socket
+
+### 0.1.0 / 2014-12-12
+
+* Initial release
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/README.md b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..bae7024f3bae04209952687062574d79a2de1b3e
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/README.md
@@ -0,0 +1,354 @@
+# websocket-extensions [![Build status](https://secure.travis-ci.org/faye/websocket-extensions-node.svg)](http://travis-ci.org/faye/websocket-extensions-node)
+
+A minimal framework that supports the implementation of WebSocket extensions in
+a way that's decoupled from the main protocol. This library aims to allow a
+WebSocket extension to be written and used with any protocol library, by
+defining abstract representations of frames and messages that allow modules to
+co-operate.
+
+`websocket-extensions` provides a container for registering extension plugins,
+and provides all the functions required to negotiate which extensions to use
+during a session via the `Sec-WebSocket-Extensions` header. By implementing the
+APIs defined in this document, an extension may be used by any WebSocket library
+based on this framework.
+
+## Installation
+
+```
+$ npm install websocket-extensions
+```
+
+## Usage
+
+There are two main audiences for this library: authors implementing the
+WebSocket protocol, and authors implementing extensions. End users of a
+WebSocket library or an extension should be able to use any extension by passing
+it as an argument to their chosen protocol library, without needing to know how
+either of them work, or how the `websocket-extensions` framework operates.
+
+The library is designed with the aim that any protocol implementation and any
+extension can be used together, so long as they support the same abstract
+representation of frames and messages.
+
+### Data types
+
+The APIs provided by the framework rely on two data types; extensions will
+expect to be given data and to be able to return data in these formats:
+
+#### *Frame*
+
+*Frame* is a structure representing a single WebSocket frame of any type. Frames
+are simple objects that must have at least the following properties, which
+represent the data encoded in the frame:
+
+| property     | description                                                        |
+| ------------ | ------------------------------------------------------------------ |
+| `final`      | `true` if the `FIN` bit is set, `false` otherwise                  |
+| `rsv1`       | `true` if the `RSV1` bit is set, `false` otherwise                 |
+| `rsv2`       | `true` if the `RSV2` bit is set, `false` otherwise                 |
+| `rsv3`       | `true` if the `RSV3` bit is set, `false` otherwise                 |
+| `opcode`     | the numeric opcode (`0`, `1`, `2`, `8`, `9`, or `10`) of the frame |
+| `masked`     | `true` if the `MASK` bit is set, `false` otherwise                 |
+| `maskingKey` | a 4-byte `Buffer` if `masked` is `true`, otherwise `null`          |
+| `payload`    | a `Buffer` containing the (unmasked) application data              |
+
+#### *Message*
+
+A *Message* represents a complete application message, which can be formed from
+text, binary and continuation frames. It has the following properties:
+
+| property | description                                                       |
+| -------- | ----------------------------------------------------------------- |
+| `rsv1`   | `true` if the first frame of the message has the `RSV1` bit set   |
+| `rsv2`   | `true` if the first frame of the message has the `RSV2` bit set   |
+| `rsv3`   | `true` if the first frame of the message has the `RSV3` bit set   |
+| `opcode` | the numeric opcode (`1` or `2`) of the first frame of the message |
+| `data`   | the concatenation of all the frame payloads in the message        |
+
+### For driver authors
+
+A driver author is someone implementing the WebSocket protocol proper, and who
+wishes end users to be able to use WebSocket extensions with their library.
+
+At the start of a WebSocket session, on both the client and the server side,
+they should begin by creating an extension container and adding whichever
+extensions they want to use.
+
+```js
+var Extensions = require('websocket-extensions'),
+    deflate    = require('permessage-deflate');
+
+var exts = new Extensions();
+exts.add(deflate);
+```
+
+In the following examples, `exts` refers to this `Extensions` instance.
+
+#### Client sessions
+
+Clients will use the methods `generateOffer()` and `activate(header)`.
+
+As part of the handshake process, the client must send a
+`Sec-WebSocket-Extensions` header to advertise that it supports the registered
+extensions. This header should be generated using:
+
+```js
+request.headers['sec-websocket-extensions'] = exts.generateOffer();
+```
+
+This returns a string, for example `"permessage-deflate;
+client_max_window_bits"`, that represents all the extensions the client is
+offering to use, and their parameters. This string may contain multiple offers
+for the same extension.
+
+When the client receives the handshake response from the server, it should pass
+the incoming `Sec-WebSocket-Extensions` header in to `exts` to activate the
+extensions the server has accepted:
+
+```js
+exts.activate(response.headers['sec-websocket-extensions']);
+```
+
+If the server has sent any extension responses that the client does not
+recognize, or are in conflict with one another for use of RSV bits, or that use
+invalid parameters for the named extensions, then `exts.activate()` will
+`throw`. In this event, the client driver should fail the connection with
+closing code `1010`.
+
+#### Server sessions
+
+Servers will use the method `generateResponse(header)`.
+
+A server session needs to generate a `Sec-WebSocket-Extensions` header to send
+in its handshake response:
+
+```js
+var clientOffer = request.headers['sec-websocket-extensions'],
+    extResponse = exts.generateResponse(clientOffer);
+
+response.headers['sec-websocket-extensions'] = extResponse;
+```
+
+Calling `exts.generateResponse(header)` activates those extensions the client
+has asked to use, if they are registered, asks each extension for a set of
+response parameters, and returns a string containing the response parameters for
+all accepted extensions.
+
+#### In both directions
+
+Both clients and servers will use the methods `validFrameRsv(frame)`,
+`processIncomingMessage(message)` and `processOutgoingMessage(message)`.
+
+The WebSocket protocol requires that frames do not have any of the `RSV` bits
+set unless there is an extension in use that allows otherwise. When processing
+an incoming frame, sessions should pass a *Frame* object to:
+
+```js
+exts.validFrameRsv(frame)
+```
+
+If this method returns `false`, the session should fail the WebSocket connection
+with closing code `1002`.
+
+To pass incoming messages through the extension stack, a session should
+construct a *Message* object according to the above datatype definitions, and
+call:
+
+```js
+exts.processIncomingMessage(message, function(error, msg) {
+  // hand the message off to the application
+});
+```
+
+If any extensions fail to process the message, then the callback will yield an
+error and the session should fail the WebSocket connection with closing code
+`1010`. If `error` is `null`, then `msg` should be passed on to the application.
+
+To pass outgoing messages through the extension stack, a session should
+construct a *Message* as before, and call:
+
+```js
+exts.processOutgoingMessage(message, function(error, msg) {
+  // write message to the transport
+});
+```
+
+If any extensions fail to process the message, then the callback will yield an
+error and the session should fail the WebSocket connection with closing code
+`1010`. If `error` is `null`, then `message` should be converted into frames
+(with the message's `rsv1`, `rsv2`, `rsv3` and `opcode` set on the first frame)
+and written to the transport.
+
+At the end of the WebSocket session (either when the protocol is explicitly
+ended or the transport connection disconnects), the driver should call:
+
+```js
+exts.close(function() {})
+```
+
+The callback is invoked when all extensions have finished processing any
+messages in the pipeline and it's safe to close the socket.
+
+### For extension authors
+
+An extension author is someone implementing an extension that transforms
+WebSocket messages passing between the client and server. They would like to
+implement their extension once and have it work with any protocol library.
+
+Extension authors will not install `websocket-extensions` or call it directly.
+Instead, they should implement the following API to allow their extension to
+plug into the `websocket-extensions` framework.
+
+An `Extension` is any object that has the following properties:
+
+| property | description                                                                  |
+| -------- | ---------------------------------------------------------------------------- |
+| `name`   | a string containing the name of the extension as used in negotiation headers |
+| `type`   | a string, must be `"permessage"`                                             |
+| `rsv1`   | either `true` if the extension uses the RSV1 bit, `false` otherwise          |
+| `rsv2`   | either `true` if the extension uses the RSV2 bit, `false` otherwise          |
+| `rsv3`   | either `true` if the extension uses the RSV3 bit, `false` otherwise          |
+
+It must also implement the following methods:
+
+```js
+ext.createClientSession()
+```
+
+This returns a *ClientSession*, whose interface is defined below.
+
+```js
+ext.createServerSession(offers)
+```
+
+This takes an array of offer params and returns a *ServerSession*, whose
+interface is defined below. For example, if the client handshake contains the
+offer header:
+
+```
+Sec-WebSocket-Extensions: permessage-deflate; server_no_context_takeover; server_max_window_bits=8, \
+                          permessage-deflate; server_max_window_bits=15
+```
+
+then the `permessage-deflate` extension will receive the call:
+
+```js
+ext.createServerSession([
+  {server_no_context_takeover: true, server_max_window_bits: 8},
+  {server_max_window_bits: 15}
+]);
+```
+
+The extension must decide which set of parameters it wants to accept, if any,
+and return a *ServerSession* if it wants to accept the parameters and `null`
+otherwise.
+
+#### *ClientSession*
+
+A *ClientSession* is the type returned by `ext.createClientSession()`. It must
+implement the following methods, as well as the *Session* API listed below.
+
+```js
+clientSession.generateOffer()
+// e.g.  -> [
+//            {server_no_context_takeover: true, server_max_window_bits: 8},
+//            {server_max_window_bits: 15}
+//          ]
+```
+
+This must return a set of parameters to include in the client's
+`Sec-WebSocket-Extensions` offer header. If the session wants to offer multiple
+configurations, it can return an array of sets of parameters as shown above.
+
+```js
+clientSession.activate(params) // -> true
+```
+
+This must take a single set of parameters from the server's handshake response
+and use them to configure the client session. If the client accepts the given
+parameters, then this method must return `true`. If it returns any other value,
+the framework will interpret this as the client rejecting the response, and will
+`throw`.
+
+#### *ServerSession*
+
+A *ServerSession* is the type returned by `ext.createServerSession(offers)`. It
+must implement the following methods, as well as the *Session* API listed below.
+
+```js
+serverSession.generateResponse()
+// e.g.  -> {server_max_window_bits: 8}
+```
+
+This returns the set of parameters the server session wants to send in its
+`Sec-WebSocket-Extensions` response header. Only one set of parameters is
+returned to the client per extension. Server sessions that would confict on
+their use of RSV bits are not activated.
+
+#### *Session*
+
+The *Session* API must be implemented by both client and server sessions. It
+contains two methods, `processIncomingMessage(message)` and
+`processOutgoingMessage(message)`.
+
+```js
+session.processIncomingMessage(message, function(error, msg) { ... })
+```
+
+The session must implement this method to take an incoming *Message* as defined
+above, transform it in any way it needs, then return it via the callback. If
+there is an error processing the message, this method should yield an error as
+the first argument.
+
+```js
+session.processOutgoingMessage(message, function(error, msg) { ... })
+```
+
+The session must implement this method to take an outgoing *Message* as defined
+above, transform it in any way it needs, then return it via the callback. If
+there is an error processing the message, this method should yield an error as
+the first argument.
+
+Note that both `processIncomingMessage()` and `processOutgoingMessage()` can
+perform their logic asynchronously, are allowed to process multiple messages
+concurrently, and are not required to complete working on messages in the same
+order the messages arrive. `websocket-extensions` will reorder messages as your
+extension emits them and will make sure every extension is given messages in the
+order they arrive from the driver. This allows extensions to maintain state that
+depends on the messages' wire order, for example keeping a DEFLATE compression
+context between messages.
+
+```js
+session.close()
+```
+
+The framework will call this method when the WebSocket session ends, allowing
+the session to release any resources it's using.
+
+## Examples
+
+* Consumer: [websocket-driver](https://github.com/faye/websocket-driver-node)
+* Provider: [permessage-deflate](https://github.com/faye/permessage-deflate-node)
+
+## License
+
+(The MIT License)
+
+Copyright (c) 2014-2015 James Coglan
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the 'Software'), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/lib/parser.js b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/lib/parser.js
new file mode 100644
index 0000000000000000000000000000000000000000..6c78be6b5a2177d058674b7c049a18a3c648e5e8
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/lib/parser.js
@@ -0,0 +1,99 @@
+'use strict';
+
+var TOKEN    = /([!#\$%&'\*\+\-\.\^_`\|~0-9a-z]+)/,
+    NOTOKEN  = /([^!#\$%&'\*\+\-\.\^_`\|~0-9a-z])/g,
+    QUOTED   = /"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)"/,
+    PARAM    = new RegExp(TOKEN.source + '(?:=(?:' + TOKEN.source + '|' + QUOTED.source + '))?'),
+    EXT      = new RegExp(TOKEN.source + '(?: *; *' + PARAM.source + ')*', 'g'),
+    EXT_LIST = new RegExp('^' + EXT.source + '(?: *, *' + EXT.source + ')*$'),
+    NUMBER   = /^-?(0|[1-9][0-9]*)(\.[0-9]+)?$/;
+
+var Parser = {
+  parseHeader: function(header) {
+    var offers = new Offers();
+    if (header === '' || header === undefined) return offers;
+
+    if (!EXT_LIST.test(header))
+      throw new SyntaxError('Invalid Sec-WebSocket-Extensions header: ' + header);
+
+    var values = header.match(EXT);
+
+    values.forEach(function(value) {
+      var params = value.match(new RegExp(PARAM.source, 'g')),
+          name   = params.shift(),
+          offer  = {};
+
+      params.forEach(function(param) {
+        var args = param.match(PARAM), key = args[1], data;
+
+        if (args[2] !== undefined) {
+          data = args[2];
+        } else if (args[3] !== undefined) {
+          data = args[3].replace(/\\/g, '');
+        } else {
+          data = true;
+        }
+        if (NUMBER.test(data)) data = parseFloat(data);
+
+        if (offer.hasOwnProperty(key)) {
+          offer[key] = [].concat(offer[key]);
+          offer[key].push(data);
+        } else {
+          offer[key] = data;
+        }
+      }, this);
+      offers.push(name, offer);
+    }, this);
+
+    return offers;
+  },
+
+  serializeParams: function(name, params) {
+    var values = [];
+
+    var print = function(key, value) {
+      if (value instanceof Array) {
+        value.forEach(function(v) { print(key, v) });
+      } else if (value === true) {
+        values.push(key);
+      } else if (typeof value === 'number') {
+        values.push(key + '=' + value);
+      } else if (NOTOKEN.test(value)) {
+        values.push(key + '="' + value.replace(/"/g, '\\"') + '"');
+      } else {
+        values.push(key + '=' + value);
+      }
+    };
+
+    for (var key in params) print(key, params[key]);
+
+    return [name].concat(values).join('; ');
+  }
+};
+
+var Offers = function() {
+  this._byName  = {};
+  this._inOrder = [];
+};
+
+Offers.prototype.push = function(name, params) {
+  this._byName[name] = this._byName[name] || [];
+  this._byName[name].push(params);
+  this._inOrder.push({name: name, params: params});
+};
+
+Offers.prototype.eachOffer = function(callback, context) {
+  var list = this._inOrder;
+  for (var i = 0, n = list.length; i < n; i++)
+    callback.call(context, list[i].name, list[i].params);
+};
+
+Offers.prototype.byName = function(name) {
+  return this._byName[name] || [];
+};
+
+Offers.prototype.toArray = function() {
+  return this._inOrder.slice();
+};
+
+module.exports = Parser;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/lib/pipeline/README.md b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/lib/pipeline/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..c373a3689c17cad9663ad4215ccb08c79e68b8df
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/lib/pipeline/README.md
@@ -0,0 +1,607 @@
+# Extension pipelining
+
+`websocket-extensions` models the extension negotiation and processing pipeline
+of the WebSocket protocol. Between the driver parsing messages from the TCP
+stream and handing those messages off to the application, there may exist a
+stack of extensions that transform the message somehow.
+
+In the parlance of this framework, a *session* refers to a single instance of an
+extension, acting on a particular socket on either the server or the client
+side. A session may transform messages both incoming to the application and
+outgoing from the application, for example the `permessage-deflate` extension
+compresses outgoing messages and decompresses incoming messages. Message streams
+in either direction are independent; that is, incoming and outgoing messages
+cannot be assumed to 'pair up' as in a request-response protocol.
+
+Asynchronous processing of messages poses a number of problems that this
+pipeline construction is intended to solve.
+
+
+## Overview
+
+Logically, we have the following:
+
+
+    +-------------+  out  +---+     +---+     +---+       +--------+
+    |             |------>|   |---->|   |---->|   |------>|        |
+    | Application |       | A |     | B |     | C |       | Driver |
+    |             |<------|   |<----|   |<----|   |<------|        |
+    +-------------+  in   +---+     +---+     +---+       +--------+
+
+                          \                       /
+                           +----------o----------+
+                                      |
+                                   sessions
+
+
+For outgoing messages, the driver receives the result of
+
+        C.outgoing(B.outgoing(A.outgoing(message)))
+
+    or, [A, B, C].reduce(((m, ext) => ext.outgoing(m)), message)
+
+For incoming messages, the application receives the result of
+
+        A.incoming(B.incoming(C.incoming(message)))
+
+    or, [C, B, A].reduce(((m, ext) => ext.incoming(m)), message)
+
+A session is of the following type, to borrow notation from pseudo-Haskell:
+
+    type Session = {
+      incoming :: Message -> Message
+      outgoing :: Message -> Message
+      close    :: () -> ()
+    }
+
+(That `() -> ()` syntax is intended to mean that `close()` is a nullary void
+method; I apologise to any Haskell readers for not using the right monad.)
+
+The `incoming()` and `outgoing()` methods perform message transformation in the
+respective directions; `close()` is called when a socket closes so the session
+can release any resources it's holding, for example a DEFLATE de/compression
+context.
+
+However because this is JavaScript, the `incoming()` and `outgoing()` methods
+may be asynchronous (indeed, `permessage-deflate` is based on `zlib`, whose API
+is stream-based). So their interface is strictly:
+
+    type Session = {
+      incoming :: Message -> Callback -> ()
+      outgoing :: Message -> Callback -> ()
+      close    :: () -> ()
+    }
+
+    type Callback = Either Error Message -> ()
+
+This means a message *m2* can be pushed into a session while it's still
+processing the preceding message *m1*. The messages can be processed
+concurrently but they *must* be given to the next session in line (or to the
+application) in the same order they came in. Applications will expect to receive
+messages in the order they arrived over the wire, and sessions require this too.
+So ordering of messages must be preserved throughout the pipeline.
+
+Consider the following highly simplified extension that deflates messages on the
+wire. `message` is a value conforming the type:
+
+    type Message = {
+      rsv1   :: Boolean
+      rsv2   :: Boolean
+      rsv3   :: Boolean
+      opcode :: Number
+      data   :: Buffer
+    }
+
+Here's the extension:
+
+```js
+var zlib = require('zlib');
+
+var deflate = {
+  outgoing: function(message, callback) {
+    zlib.deflateRaw(message.data, function(error, result) {
+      message.rsv1 = true;
+      message.data = result;
+      callback(error, message);
+    });
+  },
+
+  incoming: function(message, callback) {
+    // decompress inbound messages (elided)
+  },
+
+  close: function() {
+    // no state to clean up
+  }
+};
+```
+
+We can call it with a large message followed by a small one, and the small one
+will be returned first:
+
+```js
+var crypto = require('crypto'),
+    large  = crypto.randomBytes(1 << 14),
+    small  = new Buffer('hi');
+
+deflate.outgoing({data: large}, function() {
+  console.log(1, 'large');
+});
+
+deflate.outgoing({data: small}, function() {
+  console.log(2, 'small');
+});
+
+/* prints:  2 'small'
+            1 'large' */
+```
+
+So a session that processes messages asynchronously may fail to preserve message
+ordering.
+
+Now, this extension is stateless, so it can process messages in any order and
+still produce the same output. But some extensions are stateful and require
+message order to be preserved.
+
+For example, when using `permessage-deflate` without `no_context_takeover` set,
+the session retains a DEFLATE de/compression context between messages, which
+accumulates state as it consumes data (later messages can refer to sections of
+previous ones to improve compression). Reordering parts of the DEFLATE stream
+will result in a failed decompression. Messages must be decompressed in the same
+order they were compressed by the peer in order for the DEFLATE protocol to
+work.
+
+Finally, there is the problem of closing a socket. When a WebSocket is closed by
+the application, or receives a closing request from the other peer, there may be
+messages outgoing from the application and incoming from the peer in the
+pipeline. If we close the socket and pipeline immediately, two problems arise:
+
+* We may send our own closing frame to the peer before all prior messages we
+  sent have been written to the socket, and before we have finished processing
+  all prior messages from the peer
+* The session may be instructed to close its resources (e.g. its de/compression
+  context) while it's in the middle of processing a message, or before it has
+  received messages that are upstream of it in the pipeline
+
+Essentially, we must defer closing the sessions and sending a closing frame
+until after all prior messages have exited the pipeline.
+
+
+## Design goals
+
+* Message order must be preserved between the protocol driver, the extension
+  sessions, and the application
+* Messages should be handed off to sessions and endpoints as soon as possible,
+  to maximise throughput of stateless sessions
+* The closing procedure should block any further messages from entering the
+  pipeline, and should allow all existing messages to drain
+* Sessions should be closed as soon as possible to prevent them holding memory
+  and other resources when they have no more messages to handle
+* The closing API should allow the caller to detect when the pipeline is empty
+  and it is safe to continue the WebSocket closing procedure
+* Individual extensions should remain as simple as possible to facilitate
+  modularity and independent authorship
+
+The final point about modularity is an important one: this framework is designed
+to facilitate extensions existing as plugins, by decoupling the protocol driver,
+extensions, and application. In an ideal world, plugins should only need to
+contain code for their specific functionality, and not solve these problems that
+apply to all sessions. Also, solving some of these problems requires
+consideration of all active sessions collectively, which an individual session
+is incapable of doing.
+
+For example, it is entirely possible to take the simple `deflate` extension
+above and wrap its `incoming()` and `outgoing()` methods in two `Transform`
+streams, producing this type:
+
+    type Session = {
+      incoming :: TransformStream
+      outtoing :: TransformStream
+      close    :: () -> ()
+    }
+
+The `Transform` class makes it easy to wrap an async function such that message
+order is preserved:
+
+```js
+var stream  = require('stream'),
+    session = new stream.Transform({objectMode: true});
+
+session._transform = function(message, _, callback) {
+  var self = this;
+  deflate.outgoing(message, function(error, result) {
+    self.push(result);
+    callback();
+  });
+};
+```
+
+However, this has a negative impact on throughput: it works by deferring
+`callback()` until the async function has 'returned', which blocks `Transform`
+from passing further input into the `_transform()` method until the current
+message is dealt with completely. This would prevent sessions from processing
+messages concurrently, and would unnecessarily reduce the throughput of
+stateless extensions.
+
+So, input should be handed off to sessions as soon as possible, and all we need
+is a mechanism to reorder the output so that message order is preserved for the
+next session in line.
+
+
+## Solution
+
+We now describe the model implemented here and how it meets the above design
+goals. The above diagram where a stack of extensions sit between the driver and
+application describes the data flow, but not the object graph. That looks like
+this:
+
+
+            +--------+
+            | Driver |
+            +---o----+
+                |
+                V
+          +------------+      +----------+
+          | Extensions o----->| Pipeline |
+          +------------+      +-----o----+
+                                    |
+                    +---------------+---------------+
+                    |               |               |
+              +-----o----+    +-----o----+    +-----o----+
+              | Cell [A] |    | Cell [B] |    | Cell [C] |
+              +----------+    +----------+    +----------+
+
+
+A driver using this framework holds an instance of the `Extensions` class, which
+it uses to register extension plugins, negotiate headers and transform messages.
+The `Extensions` instance itself holds a `Pipeline`, which contains an array of
+`Cell` objects, each of which wraps one of the sessions.
+
+
+### Message processing
+
+Both the `Pipeline` and `Cell` classes have `incoming()` and `outgoing()`
+methods; the `Pipeline` interface pushes messages into the pipe, delegates the
+message to each `Cell` in turn, then returns it back to the driver. Outgoing
+messages pass through `A` then `B` then `C`, and incoming messages in the
+reverse order.
+
+Internally, a `Cell` contains two `Functor` objects. A `Functor` wraps an async
+function and makes sure its output messages maintain the order of its input
+messages. This name is due to [@fronx](https://github.com/fronx), on the basis
+that, by preserving message order, the abstraction preserves the *mapping*
+between input and output messages. To use our simple `deflate` extension from
+above:
+
+```js
+var functor = new Functor(deflate, 'outgoing');
+
+functor.call({data: large}, function() {
+  console.log(1, 'large');
+});
+
+functor.call({data: small}, function() {
+  console.log(2, 'small');
+});
+
+/*  ->  1 'large'
+        2 'small' */
+```
+
+A `Cell` contains two of these, one for each direction:
+
+
+                            +-----------------------+
+                      +---->| Functor [A, incoming] |
+    +----------+      |     +-----------------------+
+    | Cell [A] o------+
+    +----------+      |     +-----------------------+
+                      +---->| Functor [A, outgoing] |
+                            +-----------------------+
+
+
+This satisfies the message transformation requirements: the `Pipeline` simply
+loops over the cells in the appropriate direction to transform each message.
+Because each `Cell` will preserve message order, we can pass a message to the
+next `Cell` in line as soon as the current `Cell` returns it. This gives each
+`Cell` all the messages in order while maximising throughput.
+
+
+### Session closing
+
+We want to close each session as soon as possible, after all existing messages
+have drained. To do this, each `Cell` begins with a pending message counter in
+each direction, labelled `in` and `out` below.
+
+
+                              +----------+
+                              | Pipeline |
+                              +-----o----+
+                                    |
+                    +---------------+---------------+
+                    |               |               |
+              +-----o----+    +-----o----+    +-----o----+
+              | Cell [A] |    | Cell [B] |    | Cell [C] |
+              +----------+    +----------+    +----------+
+                 in: 0           in: 0           in: 0
+                out: 0          out: 0          out: 0
+
+
+When a message *m1* enters the pipeline, say in the `outgoing` direction, we
+increment the `pending.out` counter on all cells immediately.
+
+
+                              +----------+
+                        m1 => | Pipeline |
+                              +-----o----+
+                                    |
+                    +---------------+---------------+
+                    |               |               |
+              +-----o----+    +-----o----+    +-----o----+
+              | Cell [A] |    | Cell [B] |    | Cell [C] |
+              +----------+    +----------+    +----------+
+                 in: 0           in: 0           in: 0
+                out: 1          out: 1          out: 1
+
+
+*m1* is handed off to `A`, meanwhile a second message `m2` arrives in the same
+direction. All `pending.out` counters are again incremented.
+
+
+                              +----------+
+                        m2 => | Pipeline |
+                              +-----o----+
+                                    |
+                    +---------------+---------------+
+                m1  |               |               |
+              +-----o----+    +-----o----+    +-----o----+
+              | Cell [A] |    | Cell [B] |    | Cell [C] |
+              +----------+    +----------+    +----------+
+                 in: 0           in: 0           in: 0
+                out: 2          out: 2          out: 2
+
+
+When the first cell's `A.outgoing` functor finishes processing *m1*, the first
+`pending.out` counter is decremented and *m1* is handed off to cell `B`.
+
+
+                              +----------+
+                              | Pipeline |
+                              +-----o----+
+                                    |
+                    +---------------+---------------+
+                m2  |           m1  |               |
+              +-----o----+    +-----o----+    +-----o----+
+              | Cell [A] |    | Cell [B] |    | Cell [C] |
+              +----------+    +----------+    +----------+
+                 in: 0           in: 0           in: 0
+                out: 1          out: 2          out: 2
+
+
+
+As `B` finishes with *m1*, and as `A` finishes with *m2*, the `pending.out`
+counters continue to decrement.
+
+
+                              +----------+
+                              | Pipeline |
+                              +-----o----+
+                                    |
+                    +---------------+---------------+
+                    |           m2  |           m1  |
+              +-----o----+    +-----o----+    +-----o----+
+              | Cell [A] |    | Cell [B] |    | Cell [C] |
+              +----------+    +----------+    +----------+
+                 in: 0           in: 0           in: 0
+                out: 0          out: 1          out: 2
+
+
+
+Say `C` is a little slow, and begins processing *m2* while still processing
+*m1*. That's fine, the `Functor` mechanism will keep *m1* ahead of *m2* in the
+output.
+
+
+                              +----------+
+                              | Pipeline |
+                              +-----o----+
+                                    |
+                    +---------------+---------------+
+                    |               |           m2  | m1
+              +-----o----+    +-----o----+    +-----o----+
+              | Cell [A] |    | Cell [B] |    | Cell [C] |
+              +----------+    +----------+    +----------+
+                 in: 0           in: 0           in: 0
+                out: 0          out: 0          out: 2
+
+
+Once all messages are dealt with, the counters return to `0`.
+
+
+                              +----------+
+                              | Pipeline |
+                              +-----o----+
+                                    |
+                    +---------------+---------------+
+                    |               |               |
+              +-----o----+    +-----o----+    +-----o----+
+              | Cell [A] |    | Cell [B] |    | Cell [C] |
+              +----------+    +----------+    +----------+
+                 in: 0           in: 0           in: 0
+                out: 0          out: 0          out: 0
+
+
+The same process applies in the `incoming` direction, the only difference being
+that messages are passed to `C` first.
+
+This makes closing the sessions quite simple. When the driver wants to close the
+socket, it calls `Pipeline.close()`. This *immediately* calls `close()` on all
+the cells. If a cell has `in == out == 0`, then it immediately calls
+`session.close()`. Otherwise, it stores the closing call and defers it until
+`in` and `out` have both ticked down to zero. The pipeline will not accept new
+messages after `close()` has been called, so we know the pending counts will not
+increase after this point.
+
+This means each session is closed as soon as possible: `A` can close while the
+slow `C` session is still working, because it knows there are no more messages
+on the way. Similarly, `C` will defer closing if `close()` is called while *m1*
+is still in `B`, and *m2* in `A`, because its pending count means it knows it
+has work yet to do, even if it's not received those messages yet. This concern
+cannot be addressed by extensions acting only on their own local state, unless
+we pollute individual extensions by making them all implement this same
+mechanism.
+
+The actual closing API at each level is slightly different:
+
+    type Session = {
+      close :: () -> ()
+    }
+
+    type Cell = {
+      close :: () -> Promise ()
+    }
+
+    type Pipeline = {
+      close :: Callback -> ()
+    }
+
+This might appear inconsistent so it's worth explaining. Remember that a
+`Pipeline` holds a list of `Cell` objects, each wrapping a `Session`. The driver
+talks (via the `Extensions` API) to the `Pipeline` interface, and it wants
+`Pipeline.close()` to do two things: close all the sessions, and tell me when
+it's safe to start the closing procedure (i.e. when all messages have drained
+from the pipe and been handed off to the application or socket). A callback API
+works well for that.
+
+At the other end of the stack, `Session.close()` is a nullary void method with
+no callback or promise API because we don't care what it does, and whatever it
+does do will not block the WebSocket protocol; we're not going to hold off
+processing messages while a session closes its de/compression context. We just
+tell it to close itself, and don't want to wait while it does that.
+
+In the middle, `Cell.close()` returns a promise rather than using a callback.
+This is for two reasons. First, `Cell.close()` might not do anything
+immediately, it might have to defer its effect while messages drain. So, if
+given a callback, it would have to store it in a queue for later execution.
+Callbacks work fine if your method does something and can then invoke the
+callback itself, but if you need to store callbacks somewhere so another method
+can execute them, a promise is a better fit. Second, it better serves the
+purposes of `Pipeline.close()`: it wants to call `close()` on each of a list of
+cells, and wait for all of them to finish. This is simple and idiomatic using
+promises:
+
+```js
+var closed = cells.map((cell) => cell.close());
+Promise.all(closed).then(callback);
+```
+
+(We don't actually use a full *Promises/A+* compatible promise here, we use a
+much simplified construction that acts as a callback aggregater and resolves
+synchronously and does not support chaining, but the principle is the same.)
+
+
+### Error handling
+
+We've not mentioned error handling so far but it bears some explanation. The
+above counter system still applies, but behaves slightly differently in the
+presence of errors.
+
+Say we push three messages into the pipe in the outgoing direction:
+
+
+                              +----------+
+                m3, m2, m1 => | Pipeline |
+                              +-----o----+
+                                    |
+                    +---------------+---------------+
+                    |               |               |
+              +-----o----+    +-----o----+    +-----o----+
+              | Cell [A] |    | Cell [B] |    | Cell [C] |
+              +----------+    +----------+    +----------+
+                 in: 0           in: 0           in: 0
+                out: 3          out: 3          out: 3
+
+
+They pass through the cells successfully up to this point:
+
+
+                              +----------+
+                              | Pipeline |
+                              +-----o----+
+                                    |
+                    +---------------+---------------+
+                m3  |           m2  |           m1  |
+              +-----o----+    +-----o----+    +-----o----+
+              | Cell [A] |    | Cell [B] |    | Cell [C] |
+              +----------+    +----------+    +----------+
+                 in: 0           in: 0           in: 0
+                out: 1          out: 2          out: 3
+
+
+At this point, session `B` produces an error while processing *m2*, that is *m2*
+becomes *e2*. *m1* is still in the pipeline, and *m3* is queued behind *m2*.
+What ought to happen is that *m1* is handed off to the socket, then *m2* is
+released to the driver, which will detect the error and begin closing the
+socket. No further processing should be done on *m3* and it should not be
+released to the driver after the error is emitted.
+
+To handle this, we allow errors to pass down the pipeline just like messages do,
+to maintain ordering. But, once a cell sees its session produce an error, or it
+receives an error from upstream, it should refuse to accept any further
+messages. Session `B` might have begun processing *m3* by the time it produces
+the error *e2*, but `C` will have been given *e2* before it receives *m3*, and
+can simply drop *m3*.
+
+Now, say *e2* reaches the slow session `C` while *m1* is still present,
+meanwhile *m3* has been dropped. `C` will never receive *m3* since it will have
+been dropped upstream. Under the present model, its `out` counter will be `3`
+but it is only going to emit two more values: *m1* and *e2*. In order for
+closing to work, we need to decrement `out` to reflect this. The situation
+should look like this:
+
+
+                              +----------+
+                              | Pipeline |
+                              +-----o----+
+                                    |
+                    +---------------+---------------+
+                    |               |           e2  | m1
+              +-----o----+    +-----o----+    +-----o----+
+              | Cell [A] |    | Cell [B] |    | Cell [C] |
+              +----------+    +----------+    +----------+
+                 in: 0           in: 0           in: 0
+                out: 0          out: 0          out: 2
+
+
+When a cell sees its session emit an error, or when it receives an error from
+upstream, it sets its pending count in the appropriate direction to equal the
+number of messages it is *currently* processing. It will not accept any messages
+after it sees the error, so this will allow the counter to reach zero.
+
+Note that while *e2* is in the pipeline, `Pipeline` should drop any further
+messages in the outgoing direction, but should continue to accept incoming
+messages. Until *e2* makes it out of the pipe to the driver, behind previous
+successful messages, the driver does not know an error has happened, and a
+message may arrive over the socket and make it all the way through the incoming
+pipe in the meantime. We only halt processing in the affected direction to avoid
+doing unnecessary work since messages arriving after an error should not be
+processed.
+
+Some unnecessary work may happen, for example any messages already in the
+pipeline following *m2* will be processed by `A`, since it's upstream of the
+error. Those messages will be dropped by `B`.
+
+
+## Alternative ideas
+
+I am considering implementing `Functor` as an object-mode transform stream
+rather than what is essentially an async function. Being object-mode, a stream
+would preserve message boundaries and would also possibly help address
+back-pressure. I'm not sure whether this would require external API changes so
+that such streams could be connected to the downstream driver's streams.
+
+
+## Acknowledgements
+
+Credit is due to [@mnowster](https://github.com/mnowster) for helping with the
+design and to [@fronx](https://github.com/fronx) for helping name things.
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/lib/pipeline/cell.js b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/lib/pipeline/cell.js
new file mode 100644
index 0000000000000000000000000000000000000000..fdd40eba89a40aa2ea9e83bc036c000d24ed9fa8
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/lib/pipeline/cell.js
@@ -0,0 +1,52 @@
+'use strict';
+
+var Functor = require('./functor'),
+    Pledge  = require('./pledge');
+
+var Cell = function(tuple) {
+  this._ext     = tuple[0];
+  this._session = tuple[1];
+
+  this._functors = {
+    incoming: new Functor(this._session, 'processIncomingMessage'),
+    outgoing: new Functor(this._session, 'processOutgoingMessage')
+  };
+};
+
+Cell.prototype.pending = function(direction) {
+  this._functors[direction].pending += 1;
+};
+
+Cell.prototype.incoming = function(error, message, callback, context) {
+  this._exec('incoming', error, message, callback, context);
+};
+
+Cell.prototype.outgoing = function(error, message, callback, context) {
+  this._exec('outgoing', error, message, callback, context);
+};
+
+Cell.prototype.close = function() {
+  this._closed = this._closed || new Pledge();
+  this._doClose();
+  return this._closed;
+};
+
+Cell.prototype._exec = function(direction, error, message, callback, context) {
+  this._functors[direction].call(error, message, function(err, msg) {
+    if (err) err.message = this._ext.name + ': ' + err.message;
+    callback.call(context, err, msg);
+    this._doClose();
+  }, this);
+};
+
+Cell.prototype._doClose = function() {
+  var fin  = this._functors.incoming,
+      fout = this._functors.outgoing;
+
+  if (!this._closed || fin.pending + fout.pending !== 0) return;
+  if (this._session) this._session.close();
+  this._session = null;
+  this._closed.done();
+};
+
+module.exports = Cell;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/lib/pipeline/functor.js b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/lib/pipeline/functor.js
new file mode 100644
index 0000000000000000000000000000000000000000..105ace3dc86134034d330c9184e554148b9e2d4d
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/lib/pipeline/functor.js
@@ -0,0 +1,61 @@
+'use strict';
+
+var RingBuffer = require('./ring_buffer');
+
+var Functor = function(session, method) {
+  this._session = session;
+  this._method  = method;
+  this._queue   = new RingBuffer(Functor.QUEUE_SIZE);
+  this._stopped = false;
+  this.pending  = 0;
+};
+
+Functor.QUEUE_SIZE = 8;
+
+Functor.prototype.call = function(error, message, callback, context) {
+  if (this._stopped) return;
+
+  var record = {error: error, message: message, callback: callback, context: context, done: false},
+      called = false,
+      self   = this;
+
+  this._queue.push(record);
+
+  if (record.error) {
+    record.done = true;
+    this._stop();
+    return this._flushQueue();
+  }
+
+  this._session[this._method](message, function(err, msg) {
+    if (!(called ^ (called = true))) return;
+
+    if (err) {
+      self._stop();
+      record.error   = err;
+      record.message = null;
+    } else {
+      record.message = msg;
+    }
+
+    record.done = true;
+    self._flushQueue();
+  });
+};
+
+Functor.prototype._stop = function() {
+  this.pending  = this._queue.length;
+  this._stopped = true;
+};
+
+Functor.prototype._flushQueue = function() {
+  var queue = this._queue, record;
+
+  while (queue.length > 0 && queue.peek().done) {
+    this.pending -= 1;
+    record = queue.shift();
+    record.callback.call(record.context, record.error, record.message);
+  }
+};
+
+module.exports = Functor;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/lib/pipeline/index.js b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/lib/pipeline/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..169303c633ba5e467d4846ede2b965de6c7111be
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/lib/pipeline/index.js
@@ -0,0 +1,47 @@
+'use strict';
+
+var Cell   = require('./cell'),
+    Pledge = require('./pledge');
+
+var Pipeline = function(sessions) {
+  this._cells   = sessions.map(function(session) { return new Cell(session) });
+  this._stopped = {incoming: false, outgoing: false};
+};
+
+Pipeline.prototype.processIncomingMessage = function(message, callback, context) {
+  if (this._stopped.incoming) return;
+  this._loop('incoming', this._cells.length - 1, -1, -1, message, callback, context);
+};
+
+Pipeline.prototype.processOutgoingMessage = function(message, callback, context) {
+  if (this._stopped.outgoing) return;
+  this._loop('outgoing', 0, this._cells.length, 1, message, callback, context);
+};
+
+Pipeline.prototype.close = function(callback, context) {
+  this._stopped = {incoming: true, outgoing: true};
+
+  var closed = this._cells.map(function(a) { return a.close() });
+  if (callback)
+    Pledge.all(closed).then(function() { callback.call(context) });
+};
+
+Pipeline.prototype._loop = function(direction, start, end, step, message, callback, context) {
+  var cells = this._cells,
+      n     = cells.length,
+      self  = this;
+
+  while (n--) cells[n].pending(direction);
+
+  var pipe = function(index, error, msg) {
+    if (index === end) return callback.call(context, error, msg);
+
+    cells[index][direction](error, msg, function(err, m) {
+      if (err) self._stopped[direction] = true;
+      pipe(index + step, err, m);
+    });
+  };
+  pipe(start, null, message);
+};
+
+module.exports = Pipeline;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/lib/pipeline/pledge.js b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/lib/pipeline/pledge.js
new file mode 100644
index 0000000000000000000000000000000000000000..8a1f45df8c2fc0ec0b09f28a315d7000d9538e8c
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/lib/pipeline/pledge.js
@@ -0,0 +1,37 @@
+'use strict';
+
+var RingBuffer = require('./ring_buffer');
+
+var Pledge = function() {
+  this._complete  = false;
+  this._callbacks = new RingBuffer(Pledge.QUEUE_SIZE);
+};
+
+Pledge.QUEUE_SIZE = 4;
+
+Pledge.all = function(list) {
+  var pledge  = new Pledge(),
+      pending = list.length,
+      n       = pending;
+
+  if (pending === 0) pledge.done();
+
+  while (n--) list[n].then(function() {
+    pending -= 1;
+    if (pending === 0) pledge.done();
+  });
+  return pledge;
+};
+
+Pledge.prototype.then = function(callback) {
+  if (this._complete) callback();
+  else this._callbacks.push(callback);
+};
+
+Pledge.prototype.done = function() {
+  this._complete = true;
+  var callbacks = this._callbacks, callback;
+  while (callback = callbacks.shift()) callback();
+};
+
+module.exports = Pledge;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/lib/pipeline/ring_buffer.js b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/lib/pipeline/ring_buffer.js
new file mode 100644
index 0000000000000000000000000000000000000000..2787f27323f31576fadca9a73d690651edfbc76a
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/lib/pipeline/ring_buffer.js
@@ -0,0 +1,62 @@
+'use strict';
+
+var RingBuffer = function(bufferSize) {
+  this._buffer     = new Array(bufferSize);
+  this._bufferSize = bufferSize;
+  this._ringOffset = 0;
+  this._ringSize   = bufferSize;
+  this._head       = 0;
+  this._tail       = 0;
+  this.length      = 0;
+};
+
+RingBuffer.prototype.push = function(value) {
+  var expandBuffer = false,
+      expandRing   = false;
+
+  if (this._ringSize < this._bufferSize) {
+    expandBuffer = (this._tail === 0);
+  } else if (this._ringOffset === this._ringSize) {
+    expandBuffer = true;
+    expandRing   = (this._tail === 0);
+  }
+
+  if (expandBuffer) {
+    this._tail       = this._bufferSize;
+    this._buffer     = this._buffer.concat(new Array(this._bufferSize));
+    this._bufferSize = this._buffer.length;
+
+    if (expandRing)
+      this._ringSize = this._bufferSize;
+  }
+
+  this._buffer[this._tail] = value;
+  this.length += 1;
+  if (this._tail < this._ringSize) this._ringOffset += 1;
+  this._tail = (this._tail + 1) % this._bufferSize;
+};
+
+RingBuffer.prototype.peek = function() {
+  if (this.length === 0) return void 0;
+  return this._buffer[this._head];
+};
+
+RingBuffer.prototype.shift = function() {
+  if (this.length === 0) return void 0;
+
+  var value = this._buffer[this._head];
+  this._buffer[this._head] = void 0;
+  this.length -= 1;
+  this._ringOffset -= 1;
+
+  if (this._ringOffset === 0 && this.length > 0) {
+    this._head       = this._ringSize;
+    this._ringOffset = this.length;
+    this._ringSize   = this._bufferSize;
+  } else {
+    this._head = (this._head + 1) % this._ringSize;
+  }
+  return value;
+};
+
+module.exports = RingBuffer;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/lib/websocket_extensions.js b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/lib/websocket_extensions.js
new file mode 100644
index 0000000000000000000000000000000000000000..80e5e10b39ffb8c9864cfa5cd11ff04be327d22d
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/lib/websocket_extensions.js
@@ -0,0 +1,162 @@
+'use strict';
+
+var Parser   = require('./parser'),
+    Pipeline = require('./pipeline');
+
+var Extensions = function() {
+  this._rsv1 = this._rsv2 = this._rsv3 = null;
+
+  this._byName   = {};
+  this._inOrder  = [];
+  this._sessions = [];
+  this._index    = {}
+};
+
+Extensions.MESSAGE_OPCODES = [1, 2];
+
+var instance = {
+  add: function(ext) {
+    if (typeof ext.name !== 'string') throw new TypeError('extension.name must be a string');
+    if (ext.type !== 'permessage') throw new TypeError('extension.type must be "permessage"');
+
+    if (typeof ext.rsv1 !== 'boolean') throw new TypeError('extension.rsv1 must be true or false');
+    if (typeof ext.rsv2 !== 'boolean') throw new TypeError('extension.rsv2 must be true or false');
+    if (typeof ext.rsv3 !== 'boolean') throw new TypeError('extension.rsv3 must be true or false');
+
+    if (this._byName.hasOwnProperty(ext.name))
+      throw new TypeError('An extension with name "' + ext.name + '" is already registered');
+
+    this._byName[ext.name] = ext;
+    this._inOrder.push(ext);
+  },
+
+  generateOffer: function() {
+    var sessions = [],
+        offer    = [],
+        index    = {};
+
+    this._inOrder.forEach(function(ext) {
+      var session = ext.createClientSession();
+      if (!session) return;
+
+      var record = [ext, session];
+      sessions.push(record);
+      index[ext.name] = record;
+
+      var offers = session.generateOffer();
+      offers = offers ? [].concat(offers) : [];
+
+      offers.forEach(function(off) {
+        offer.push(Parser.serializeParams(ext.name, off));
+      }, this);
+    }, this);
+
+    this._sessions = sessions;
+    this._index    = index;
+
+    return offer.length > 0 ? offer.join(', ') : null;
+  },
+
+  activate: function(header) {
+    var responses = Parser.parseHeader(header),
+        sessions  = [];
+
+    responses.eachOffer(function(name, params) {
+      var record = this._index[name];
+
+      if (!record)
+        throw new Error('Server sent an extension response for unknown extension "' + name + '"');
+
+      var ext      = record[0],
+          session  = record[1],
+          reserved = this._reserved(ext);
+
+      if (reserved)
+        throw new Error('Server sent two extension responses that use the RSV' +
+                        reserved[0] + ' bit: "' +
+                        reserved[1] + '" and "' + ext.name + '"');
+
+      if (session.activate(params) !== true)
+        throw new Error('Server sent unacceptable extension parameters: ' +
+                        Parser.serializeParams(name, params));
+
+      this._reserve(ext);
+      sessions.push(record);
+    }, this);
+
+    this._sessions = sessions;
+    this._pipeline = new Pipeline(sessions);
+  },
+
+  generateResponse: function(header) {
+    var offers   = Parser.parseHeader(header),
+        sessions = [],
+        response = [];
+
+    this._inOrder.forEach(function(ext) {
+      var offer = offers.byName(ext.name);
+      if (offer.length === 0 || this._reserved(ext)) return;
+
+      var session = ext.createServerSession(offer);
+      if (!session) return;
+
+      this._reserve(ext);
+      sessions.push([ext, session]);
+      response.push(Parser.serializeParams(ext.name, session.generateResponse()));
+    }, this);
+
+    this._sessions = sessions;
+    this._pipeline = new Pipeline(sessions);
+
+    return response.length > 0 ? response.join(', ') : null;
+  },
+
+  validFrameRsv: function(frame) {
+    var allowed = {rsv1: false, rsv2: false, rsv3: false},
+        ext;
+
+    if (Extensions.MESSAGE_OPCODES.indexOf(frame.opcode) >= 0) {
+      for (var i = 0, n = this._sessions.length; i < n; i++) {
+        ext = this._sessions[i][0];
+        allowed.rsv1 = allowed.rsv1 || ext.rsv1;
+        allowed.rsv2 = allowed.rsv2 || ext.rsv2;
+        allowed.rsv3 = allowed.rsv3 || ext.rsv3;
+      }
+    }
+
+    return (allowed.rsv1 || !frame.rsv1) &&
+           (allowed.rsv2 || !frame.rsv2) &&
+           (allowed.rsv3 || !frame.rsv3);
+  },
+
+  processIncomingMessage: function(message, callback, context) {
+    this._pipeline.processIncomingMessage(message, callback, context);
+  },
+
+  processOutgoingMessage: function(message, callback, context) {
+    this._pipeline.processOutgoingMessage(message, callback, context);
+  },
+
+  close: function(callback, context) {
+    if (!this._pipeline) return callback.call(context);
+    this._pipeline.close(callback, context);
+  },
+
+  _reserve: function(ext) {
+    this._rsv1 = this._rsv1 || (ext.rsv1 && ext.name);
+    this._rsv2 = this._rsv2 || (ext.rsv2 && ext.name);
+    this._rsv3 = this._rsv3 || (ext.rsv3 && ext.name);
+  },
+
+  _reserved: function(ext) {
+    if (this._rsv1 && ext.rsv1) return [1, this._rsv1];
+    if (this._rsv2 && ext.rsv2) return [2, this._rsv2];
+    if (this._rsv3 && ext.rsv3) return [3, this._rsv3];
+    return false;
+  }
+};
+
+for (var key in instance)
+  Extensions.prototype[key] = instance[key];
+
+module.exports = Extensions;
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/package.json b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..59f8e0abd64fe319c6d5826c924833fabb4ccacb
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/websocket-extensions/package.json
@@ -0,0 +1,73 @@
+{
+  "_args": [
+    [
+      {
+        "raw": "websocket-extensions@https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz",
+        "scope": null,
+        "escapedName": "websocket-extensions",
+        "name": "websocket-extensions",
+        "rawSpec": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz",
+        "spec": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz",
+        "type": "remote"
+      },
+      "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin"
+    ]
+  ],
+  "_from": "websocket-extensions@>=0.1.1",
+  "_id": "websocket-extensions@0.1.1",
+  "_inCache": true,
+  "_location": "/firebase-admin/websocket-extensions",
+  "_phantomChildren": {},
+  "_requested": {
+    "raw": "websocket-extensions@https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz",
+    "scope": null,
+    "escapedName": "websocket-extensions",
+    "name": "websocket-extensions",
+    "rawSpec": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz",
+    "spec": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz",
+    "type": "remote"
+  },
+  "_requiredBy": [
+    "/firebase-admin",
+    "/firebase-admin/websocket-driver"
+  ],
+  "_resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz",
+  "_shasum": "76899499c184b6ef754377c2dbb0cd6cb55d29e7",
+  "_shrinkwrap": null,
+  "_spec": "websocket-extensions@https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz",
+  "_where": "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin",
+  "author": {
+    "name": "James Coglan",
+    "email": "jcoglan@gmail.com",
+    "url": "http://jcoglan.com/"
+  },
+  "bugs": {
+    "url": "http://github.com/faye/websocket-extensions-node/issues"
+  },
+  "dependencies": {},
+  "description": "Generic extension manager for WebSocket connections",
+  "devDependencies": {
+    "jstest": ""
+  },
+  "engines": {
+    "node": ">=0.6.0"
+  },
+  "homepage": "http://github.com/faye/websocket-extensions-node",
+  "keywords": [
+    "websocket"
+  ],
+  "license": "MIT",
+  "main": "./lib/websocket_extensions",
+  "name": "websocket-extensions",
+  "optionalDependencies": {},
+  "readme": "# websocket-extensions [![Build status](https://secure.travis-ci.org/faye/websocket-extensions-node.svg)](http://travis-ci.org/faye/websocket-extensions-node)\n\nA minimal framework that supports the implementation of WebSocket extensions in\na way that's decoupled from the main protocol. This library aims to allow a\nWebSocket extension to be written and used with any protocol library, by\ndefining abstract representations of frames and messages that allow modules to\nco-operate.\n\n`websocket-extensions` provides a container for registering extension plugins,\nand provides all the functions required to negotiate which extensions to use\nduring a session via the `Sec-WebSocket-Extensions` header. By implementing the\nAPIs defined in this document, an extension may be used by any WebSocket library\nbased on this framework.\n\n## Installation\n\n```\n$ npm install websocket-extensions\n```\n\n## Usage\n\nThere are two main audiences for this library: authors implementing the\nWebSocket protocol, and authors implementing extensions. End users of a\nWebSocket library or an extension should be able to use any extension by passing\nit as an argument to their chosen protocol library, without needing to know how\neither of them work, or how the `websocket-extensions` framework operates.\n\nThe library is designed with the aim that any protocol implementation and any\nextension can be used together, so long as they support the same abstract\nrepresentation of frames and messages.\n\n### Data types\n\nThe APIs provided by the framework rely on two data types; extensions will\nexpect to be given data and to be able to return data in these formats:\n\n#### *Frame*\n\n*Frame* is a structure representing a single WebSocket frame of any type. Frames\nare simple objects that must have at least the following properties, which\nrepresent the data encoded in the frame:\n\n| property     | description                                                        |\n| ------------ | ------------------------------------------------------------------ |\n| `final`      | `true` if the `FIN` bit is set, `false` otherwise                  |\n| `rsv1`       | `true` if the `RSV1` bit is set, `false` otherwise                 |\n| `rsv2`       | `true` if the `RSV2` bit is set, `false` otherwise                 |\n| `rsv3`       | `true` if the `RSV3` bit is set, `false` otherwise                 |\n| `opcode`     | the numeric opcode (`0`, `1`, `2`, `8`, `9`, or `10`) of the frame |\n| `masked`     | `true` if the `MASK` bit is set, `false` otherwise                 |\n| `maskingKey` | a 4-byte `Buffer` if `masked` is `true`, otherwise `null`          |\n| `payload`    | a `Buffer` containing the (unmasked) application data              |\n\n#### *Message*\n\nA *Message* represents a complete application message, which can be formed from\ntext, binary and continuation frames. It has the following properties:\n\n| property | description                                                       |\n| -------- | ----------------------------------------------------------------- |\n| `rsv1`   | `true` if the first frame of the message has the `RSV1` bit set   |\n| `rsv2`   | `true` if the first frame of the message has the `RSV2` bit set   |\n| `rsv3`   | `true` if the first frame of the message has the `RSV3` bit set   |\n| `opcode` | the numeric opcode (`1` or `2`) of the first frame of the message |\n| `data`   | the concatenation of all the frame payloads in the message        |\n\n### For driver authors\n\nA driver author is someone implementing the WebSocket protocol proper, and who\nwishes end users to be able to use WebSocket extensions with their library.\n\nAt the start of a WebSocket session, on both the client and the server side,\nthey should begin by creating an extension container and adding whichever\nextensions they want to use.\n\n```js\nvar Extensions = require('websocket-extensions'),\n    deflate    = require('permessage-deflate');\n\nvar exts = new Extensions();\nexts.add(deflate);\n```\n\nIn the following examples, `exts` refers to this `Extensions` instance.\n\n#### Client sessions\n\nClients will use the methods `generateOffer()` and `activate(header)`.\n\nAs part of the handshake process, the client must send a\n`Sec-WebSocket-Extensions` header to advertise that it supports the registered\nextensions. This header should be generated using:\n\n```js\nrequest.headers['sec-websocket-extensions'] = exts.generateOffer();\n```\n\nThis returns a string, for example `\"permessage-deflate;\nclient_max_window_bits\"`, that represents all the extensions the client is\noffering to use, and their parameters. This string may contain multiple offers\nfor the same extension.\n\nWhen the client receives the handshake response from the server, it should pass\nthe incoming `Sec-WebSocket-Extensions` header in to `exts` to activate the\nextensions the server has accepted:\n\n```js\nexts.activate(response.headers['sec-websocket-extensions']);\n```\n\nIf the server has sent any extension responses that the client does not\nrecognize, or are in conflict with one another for use of RSV bits, or that use\ninvalid parameters for the named extensions, then `exts.activate()` will\n`throw`. In this event, the client driver should fail the connection with\nclosing code `1010`.\n\n#### Server sessions\n\nServers will use the method `generateResponse(header)`.\n\nA server session needs to generate a `Sec-WebSocket-Extensions` header to send\nin its handshake response:\n\n```js\nvar clientOffer = request.headers['sec-websocket-extensions'],\n    extResponse = exts.generateResponse(clientOffer);\n\nresponse.headers['sec-websocket-extensions'] = extResponse;\n```\n\nCalling `exts.generateResponse(header)` activates those extensions the client\nhas asked to use, if they are registered, asks each extension for a set of\nresponse parameters, and returns a string containing the response parameters for\nall accepted extensions.\n\n#### In both directions\n\nBoth clients and servers will use the methods `validFrameRsv(frame)`,\n`processIncomingMessage(message)` and `processOutgoingMessage(message)`.\n\nThe WebSocket protocol requires that frames do not have any of the `RSV` bits\nset unless there is an extension in use that allows otherwise. When processing\nan incoming frame, sessions should pass a *Frame* object to:\n\n```js\nexts.validFrameRsv(frame)\n```\n\nIf this method returns `false`, the session should fail the WebSocket connection\nwith closing code `1002`.\n\nTo pass incoming messages through the extension stack, a session should\nconstruct a *Message* object according to the above datatype definitions, and\ncall:\n\n```js\nexts.processIncomingMessage(message, function(error, msg) {\n  // hand the message off to the application\n});\n```\n\nIf any extensions fail to process the message, then the callback will yield an\nerror and the session should fail the WebSocket connection with closing code\n`1010`. If `error` is `null`, then `msg` should be passed on to the application.\n\nTo pass outgoing messages through the extension stack, a session should\nconstruct a *Message* as before, and call:\n\n```js\nexts.processOutgoingMessage(message, function(error, msg) {\n  // write message to the transport\n});\n```\n\nIf any extensions fail to process the message, then the callback will yield an\nerror and the session should fail the WebSocket connection with closing code\n`1010`. If `error` is `null`, then `message` should be converted into frames\n(with the message's `rsv1`, `rsv2`, `rsv3` and `opcode` set on the first frame)\nand written to the transport.\n\nAt the end of the WebSocket session (either when the protocol is explicitly\nended or the transport connection disconnects), the driver should call:\n\n```js\nexts.close(function() {})\n```\n\nThe callback is invoked when all extensions have finished processing any\nmessages in the pipeline and it's safe to close the socket.\n\n### For extension authors\n\nAn extension author is someone implementing an extension that transforms\nWebSocket messages passing between the client and server. They would like to\nimplement their extension once and have it work with any protocol library.\n\nExtension authors will not install `websocket-extensions` or call it directly.\nInstead, they should implement the following API to allow their extension to\nplug into the `websocket-extensions` framework.\n\nAn `Extension` is any object that has the following properties:\n\n| property | description                                                                  |\n| -------- | ---------------------------------------------------------------------------- |\n| `name`   | a string containing the name of the extension as used in negotiation headers |\n| `type`   | a string, must be `\"permessage\"`                                             |\n| `rsv1`   | either `true` if the extension uses the RSV1 bit, `false` otherwise          |\n| `rsv2`   | either `true` if the extension uses the RSV2 bit, `false` otherwise          |\n| `rsv3`   | either `true` if the extension uses the RSV3 bit, `false` otherwise          |\n\nIt must also implement the following methods:\n\n```js\next.createClientSession()\n```\n\nThis returns a *ClientSession*, whose interface is defined below.\n\n```js\next.createServerSession(offers)\n```\n\nThis takes an array of offer params and returns a *ServerSession*, whose\ninterface is defined below. For example, if the client handshake contains the\noffer header:\n\n```\nSec-WebSocket-Extensions: permessage-deflate; server_no_context_takeover; server_max_window_bits=8, \\\n                          permessage-deflate; server_max_window_bits=15\n```\n\nthen the `permessage-deflate` extension will receive the call:\n\n```js\next.createServerSession([\n  {server_no_context_takeover: true, server_max_window_bits: 8},\n  {server_max_window_bits: 15}\n]);\n```\n\nThe extension must decide which set of parameters it wants to accept, if any,\nand return a *ServerSession* if it wants to accept the parameters and `null`\notherwise.\n\n#### *ClientSession*\n\nA *ClientSession* is the type returned by `ext.createClientSession()`. It must\nimplement the following methods, as well as the *Session* API listed below.\n\n```js\nclientSession.generateOffer()\n// e.g.  -> [\n//            {server_no_context_takeover: true, server_max_window_bits: 8},\n//            {server_max_window_bits: 15}\n//          ]\n```\n\nThis must return a set of parameters to include in the client's\n`Sec-WebSocket-Extensions` offer header. If the session wants to offer multiple\nconfigurations, it can return an array of sets of parameters as shown above.\n\n```js\nclientSession.activate(params) // -> true\n```\n\nThis must take a single set of parameters from the server's handshake response\nand use them to configure the client session. If the client accepts the given\nparameters, then this method must return `true`. If it returns any other value,\nthe framework will interpret this as the client rejecting the response, and will\n`throw`.\n\n#### *ServerSession*\n\nA *ServerSession* is the type returned by `ext.createServerSession(offers)`. It\nmust implement the following methods, as well as the *Session* API listed below.\n\n```js\nserverSession.generateResponse()\n// e.g.  -> {server_max_window_bits: 8}\n```\n\nThis returns the set of parameters the server session wants to send in its\n`Sec-WebSocket-Extensions` response header. Only one set of parameters is\nreturned to the client per extension. Server sessions that would confict on\ntheir use of RSV bits are not activated.\n\n#### *Session*\n\nThe *Session* API must be implemented by both client and server sessions. It\ncontains two methods, `processIncomingMessage(message)` and\n`processOutgoingMessage(message)`.\n\n```js\nsession.processIncomingMessage(message, function(error, msg) { ... })\n```\n\nThe session must implement this method to take an incoming *Message* as defined\nabove, transform it in any way it needs, then return it via the callback. If\nthere is an error processing the message, this method should yield an error as\nthe first argument.\n\n```js\nsession.processOutgoingMessage(message, function(error, msg) { ... })\n```\n\nThe session must implement this method to take an outgoing *Message* as defined\nabove, transform it in any way it needs, then return it via the callback. If\nthere is an error processing the message, this method should yield an error as\nthe first argument.\n\nNote that both `processIncomingMessage()` and `processOutgoingMessage()` can\nperform their logic asynchronously, are allowed to process multiple messages\nconcurrently, and are not required to complete working on messages in the same\norder the messages arrive. `websocket-extensions` will reorder messages as your\nextension emits them and will make sure every extension is given messages in the\norder they arrive from the driver. This allows extensions to maintain state that\ndepends on the messages' wire order, for example keeping a DEFLATE compression\ncontext between messages.\n\n```js\nsession.close()\n```\n\nThe framework will call this method when the WebSocket session ends, allowing\nthe session to release any resources it's using.\n\n## Examples\n\n* Consumer: [websocket-driver](https://github.com/faye/websocket-driver-node)\n* Provider: [permessage-deflate](https://github.com/faye/permessage-deflate-node)\n\n## License\n\n(The MIT License)\n\nCopyright (c) 2014-2015 James Coglan\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the 'Software'), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n",
+  "readmeFilename": "README.md",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/faye/websocket-extensions-node.git"
+  },
+  "scripts": {
+    "test": "jstest spec/runner.js"
+  },
+  "version": "0.1.1"
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/xtend/.jshintrc b/KEMMessaging/node_modules/firebase-admin/node_modules/xtend/.jshintrc
new file mode 100644
index 0000000000000000000000000000000000000000..77887b5f0f2efc24bd55430cb6f95f8a0cad89d8
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/xtend/.jshintrc
@@ -0,0 +1,30 @@
+{
+    "maxdepth": 4,
+    "maxstatements": 200,
+    "maxcomplexity": 12,
+    "maxlen": 80,
+    "maxparams": 5,
+
+    "curly": true,
+    "eqeqeq": true,
+    "immed": true,
+    "latedef": false,
+    "noarg": true,
+    "noempty": true,
+    "nonew": true,
+    "undef": true,
+    "unused": "vars",
+    "trailing": true,
+
+    "quotmark": true,
+    "expr": true,
+    "asi": true,
+
+    "browser": false,
+    "esnext": true,
+    "devel": false,
+    "node": false,
+    "nonstandard": false,
+
+    "predef": ["require", "module", "__dirname", "__filename"]
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/xtend/.npmignore b/KEMMessaging/node_modules/firebase-admin/node_modules/xtend/.npmignore
new file mode 100644
index 0000000000000000000000000000000000000000..3c3629e647f5ddf82548912e337bea9826b434af
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/xtend/.npmignore
@@ -0,0 +1 @@
+node_modules
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/xtend/LICENCE b/KEMMessaging/node_modules/firebase-admin/node_modules/xtend/LICENCE
new file mode 100644
index 0000000000000000000000000000000000000000..1a14b437e87a8f3b7cd67b0c164b84b5575b554c
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/xtend/LICENCE
@@ -0,0 +1,19 @@
+Copyright (c) 2012-2014 Raynos.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/xtend/Makefile b/KEMMessaging/node_modules/firebase-admin/node_modules/xtend/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..d583fcf49dc1a343087a932f9912fab74e2b2f6b
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/xtend/Makefile
@@ -0,0 +1,4 @@
+browser:
+	node ./support/compile
+
+.PHONY: browser
\ No newline at end of file
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/xtend/README.md b/KEMMessaging/node_modules/firebase-admin/node_modules/xtend/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..093cb2978e4af078e3e8f40dd505afd96999569e
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/xtend/README.md
@@ -0,0 +1,32 @@
+# xtend
+
+[![browser support][3]][4]
+
+[![locked](http://badges.github.io/stability-badges/dist/locked.svg)](http://github.com/badges/stability-badges)
+
+Extend like a boss
+
+xtend is a basic utility library which allows you to extend an object by appending all of the properties from each object in a list. When there are identical properties, the right-most property takes precedence.
+
+## Examples
+
+```js
+var extend = require("xtend")
+
+// extend returns a new object. Does not mutate arguments
+var combination = extend({
+    a: "a",
+    b: 'c'
+}, {
+    b: "b"
+})
+// { a: "a", b: "b" }
+```
+
+## Stability status: Locked
+
+## MIT Licenced
+
+
+  [3]: http://ci.testling.com/Raynos/xtend.png
+  [4]: http://ci.testling.com/Raynos/xtend
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/xtend/immutable.js b/KEMMessaging/node_modules/firebase-admin/node_modules/xtend/immutable.js
new file mode 100644
index 0000000000000000000000000000000000000000..94889c9de11a181cec153de1713c8ae14ae4cb43
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/xtend/immutable.js
@@ -0,0 +1,19 @@
+module.exports = extend
+
+var hasOwnProperty = Object.prototype.hasOwnProperty;
+
+function extend() {
+    var target = {}
+
+    for (var i = 0; i < arguments.length; i++) {
+        var source = arguments[i]
+
+        for (var key in source) {
+            if (hasOwnProperty.call(source, key)) {
+                target[key] = source[key]
+            }
+        }
+    }
+
+    return target
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/xtend/mutable.js b/KEMMessaging/node_modules/firebase-admin/node_modules/xtend/mutable.js
new file mode 100644
index 0000000000000000000000000000000000000000..72debede6ca58592fe93b5ab22d434311a76861b
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/xtend/mutable.js
@@ -0,0 +1,17 @@
+module.exports = extend
+
+var hasOwnProperty = Object.prototype.hasOwnProperty;
+
+function extend(target) {
+    for (var i = 1; i < arguments.length; i++) {
+        var source = arguments[i]
+
+        for (var key in source) {
+            if (hasOwnProperty.call(source, key)) {
+                target[key] = source[key]
+            }
+        }
+    }
+
+    return target
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/xtend/package.json b/KEMMessaging/node_modules/firebase-admin/node_modules/xtend/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..1c97ca8bd0c876f75afb2abe882652f98cd62bb9
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/xtend/package.json
@@ -0,0 +1,101 @@
+{
+  "_args": [
+    [
+      {
+        "raw": "xtend@https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
+        "scope": null,
+        "escapedName": "xtend",
+        "name": "xtend",
+        "rawSpec": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
+        "spec": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
+        "type": "remote"
+      },
+      "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin"
+    ]
+  ],
+  "_from": "xtend@>=4.0.1 <5.0.0",
+  "_id": "xtend@4.0.1",
+  "_inCache": true,
+  "_location": "/firebase-admin/xtend",
+  "_phantomChildren": {},
+  "_requested": {
+    "raw": "xtend@https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
+    "scope": null,
+    "escapedName": "xtend",
+    "name": "xtend",
+    "rawSpec": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
+    "spec": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
+    "type": "remote"
+  },
+  "_requiredBy": [
+    "/firebase-admin",
+    "/firebase-admin/jsonwebtoken"
+  ],
+  "_resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
+  "_shasum": "a5c6d532be656e23db820efb943a1f04998d63af",
+  "_shrinkwrap": null,
+  "_spec": "xtend@https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
+  "_where": "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging/node_modules/firebase-admin",
+  "author": {
+    "name": "Raynos",
+    "email": "raynos2@gmail.com"
+  },
+  "bugs": {
+    "url": "https://github.com/Raynos/xtend/issues",
+    "email": "raynos2@gmail.com"
+  },
+  "contributors": [
+    {
+      "name": "Jake Verbaten"
+    },
+    {
+      "name": "Matt Esch"
+    }
+  ],
+  "dependencies": {},
+  "description": "extend like a boss",
+  "devDependencies": {
+    "tape": "~1.1.0"
+  },
+  "engines": {
+    "node": ">=0.4"
+  },
+  "homepage": "https://github.com/Raynos/xtend",
+  "keywords": [
+    "extend",
+    "merge",
+    "options",
+    "opts",
+    "object",
+    "array"
+  ],
+  "license": "MIT",
+  "main": "immutable",
+  "name": "xtend",
+  "optionalDependencies": {},
+  "readme": "# xtend\n\n[![browser support][3]][4]\n\n[![locked](http://badges.github.io/stability-badges/dist/locked.svg)](http://github.com/badges/stability-badges)\n\nExtend like a boss\n\nxtend is a basic utility library which allows you to extend an object by appending all of the properties from each object in a list. When there are identical properties, the right-most property takes precedence.\n\n## Examples\n\n```js\nvar extend = require(\"xtend\")\n\n// extend returns a new object. Does not mutate arguments\nvar combination = extend({\n    a: \"a\",\n    b: 'c'\n}, {\n    b: \"b\"\n})\n// { a: \"a\", b: \"b\" }\n```\n\n## Stability status: Locked\n\n## MIT Licenced\n\n\n  [3]: http://ci.testling.com/Raynos/xtend.png\n  [4]: http://ci.testling.com/Raynos/xtend\n",
+  "readmeFilename": "README.md",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/Raynos/xtend.git"
+  },
+  "scripts": {
+    "test": "node test"
+  },
+  "testling": {
+    "files": "test.js",
+    "browsers": [
+      "ie/7..latest",
+      "firefox/16..latest",
+      "firefox/nightly",
+      "chrome/22..latest",
+      "chrome/canary",
+      "opera/12..latest",
+      "opera/next",
+      "safari/5.1..latest",
+      "ipad/6.0..latest",
+      "iphone/6.0..latest"
+    ]
+  },
+  "version": "4.0.1"
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/node_modules/xtend/test.js b/KEMMessaging/node_modules/firebase-admin/node_modules/xtend/test.js
new file mode 100644
index 0000000000000000000000000000000000000000..093a2b061e81ae56054714a1096f451c7f8910c4
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/node_modules/xtend/test.js
@@ -0,0 +1,83 @@
+var test = require("tape")
+var extend = require("./")
+var mutableExtend = require("./mutable")
+
+test("merge", function(assert) {
+    var a = { a: "foo" }
+    var b = { b: "bar" }
+
+    assert.deepEqual(extend(a, b), { a: "foo", b: "bar" })
+    assert.end()
+})
+
+test("replace", function(assert) {
+    var a = { a: "foo" }
+    var b = { a: "bar" }
+
+    assert.deepEqual(extend(a, b), { a: "bar" })
+    assert.end()
+})
+
+test("undefined", function(assert) {
+    var a = { a: undefined }
+    var b = { b: "foo" }
+
+    assert.deepEqual(extend(a, b), { a: undefined, b: "foo" })
+    assert.deepEqual(extend(b, a), { a: undefined, b: "foo" })
+    assert.end()
+})
+
+test("handle 0", function(assert) {
+    var a = { a: "default" }
+    var b = { a: 0 }
+
+    assert.deepEqual(extend(a, b), { a: 0 })
+    assert.deepEqual(extend(b, a), { a: "default" })
+    assert.end()
+})
+
+test("is immutable", function (assert) {
+    var record = {}
+
+    extend(record, { foo: "bar" })
+    assert.equal(record.foo, undefined)
+    assert.end()
+})
+
+test("null as argument", function (assert) {
+    var a = { foo: "bar" }
+    var b = null
+    var c = void 0
+
+    assert.deepEqual(extend(b, a, c), { foo: "bar" })
+    assert.end()
+})
+
+test("mutable", function (assert) {
+    var a = { foo: "bar" }
+
+    mutableExtend(a, { bar: "baz" })
+
+    assert.equal(a.bar, "baz")
+    assert.end()
+})
+
+test("null prototype", function(assert) {
+    var a = { a: "foo" }
+    var b = Object.create(null)
+    b.b = "bar";
+
+    assert.deepEqual(extend(a, b), { a: "foo", b: "bar" })
+    assert.end()
+})
+
+test("null prototype mutable", function (assert) {
+    var a = { foo: "bar" }
+    var b = Object.create(null)
+    b.bar = "baz";
+
+    mutableExtend(a, b)
+
+    assert.equal(a.bar, "baz")
+    assert.end()
+})
diff --git a/KEMMessaging/node_modules/firebase-admin/npm-shrinkwrap.json b/KEMMessaging/node_modules/firebase-admin/npm-shrinkwrap.json
new file mode 100644
index 0000000000000000000000000000000000000000..0c443b11c48f2555eb8950d8d27fb400e5bbd4ec
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/npm-shrinkwrap.json
@@ -0,0 +1,111 @@
+{
+  "name": "firebase-admin",
+  "version": "4.0.3",
+  "dependencies": {
+    "@types/jsonwebtoken": {
+      "version": "7.1.33",
+      "from": "@types/jsonwebtoken@>=7.1.33 <8.0.0",
+      "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-7.1.33.tgz"
+    },
+    "@types/node": {
+      "version": "6.0.49",
+      "from": "@types/node@*",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.49.tgz"
+    },
+    "base64-url": {
+      "version": "1.3.3",
+      "from": "base64-url@>=1.2.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/base64-url/-/base64-url-1.3.3.tgz"
+    },
+    "base64url": {
+      "version": "2.0.0",
+      "from": "base64url@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/base64url/-/base64url-2.0.0.tgz"
+    },
+    "buffer-equal-constant-time": {
+      "version": "1.0.1",
+      "from": "buffer-equal-constant-time@1.0.1",
+      "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz"
+    },
+    "ecdsa-sig-formatter": {
+      "version": "1.0.7",
+      "from": "ecdsa-sig-formatter@1.0.7",
+      "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.7.tgz"
+    },
+    "faye-websocket": {
+      "version": "0.9.3",
+      "from": "faye-websocket@0.9.3",
+      "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.9.3.tgz"
+    },
+    "hoek": {
+      "version": "2.16.3",
+      "from": "hoek@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz"
+    },
+    "isemail": {
+      "version": "1.2.0",
+      "from": "isemail@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz"
+    },
+    "joi": {
+      "version": "6.10.1",
+      "from": "joi@>=6.10.1 <7.0.0",
+      "resolved": "https://registry.npmjs.org/joi/-/joi-6.10.1.tgz"
+    },
+    "jsonwebtoken": {
+      "version": "7.1.9",
+      "from": "jsonwebtoken@7.1.9",
+      "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-7.1.9.tgz"
+    },
+    "jwa": {
+      "version": "1.1.4",
+      "from": "jwa@>=1.1.4 <2.0.0",
+      "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.4.tgz"
+    },
+    "jws": {
+      "version": "3.1.4",
+      "from": "jws@>=3.1.3 <4.0.0",
+      "resolved": "https://registry.npmjs.org/jws/-/jws-3.1.4.tgz"
+    },
+    "lodash.once": {
+      "version": "4.1.1",
+      "from": "lodash.once@>=4.0.0 <5.0.0",
+      "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz"
+    },
+    "moment": {
+      "version": "2.16.0",
+      "from": "moment@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/moment/-/moment-2.16.0.tgz"
+    },
+    "ms": {
+      "version": "0.7.2",
+      "from": "ms@>=0.7.1 <0.8.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz"
+    },
+    "safe-buffer": {
+      "version": "5.0.1",
+      "from": "safe-buffer@>=5.0.1 <6.0.0",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz"
+    },
+    "topo": {
+      "version": "1.1.0",
+      "from": "topo@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/topo/-/topo-1.1.0.tgz"
+    },
+    "websocket-driver": {
+      "version": "0.6.5",
+      "from": "websocket-driver@>=0.5.1",
+      "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz"
+    },
+    "websocket-extensions": {
+      "version": "0.1.1",
+      "from": "websocket-extensions@>=0.1.1",
+      "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz"
+    },
+    "xtend": {
+      "version": "4.0.1",
+      "from": "xtend@>=4.0.1 <5.0.0",
+      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz"
+    }
+  }
+}
diff --git a/KEMMessaging/node_modules/firebase-admin/package.json b/KEMMessaging/node_modules/firebase-admin/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..01253e9d5a76fe3c09de94f54ea138ca5c1e9b0f
--- /dev/null
+++ b/KEMMessaging/node_modules/firebase-admin/package.json
@@ -0,0 +1,237 @@
+{
+  "_args": [
+    [
+      {
+        "raw": "firebase-admin",
+        "scope": null,
+        "escapedName": "firebase-admin",
+        "name": "firebase-admin",
+        "rawSpec": "",
+        "spec": "latest",
+        "type": "tag"
+      },
+      "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging"
+    ]
+  ],
+  "_from": "firebase-admin@latest",
+  "_id": "firebase-admin@4.0.3",
+  "_inCache": true,
+  "_location": "/firebase-admin",
+  "_nodeVersion": "0.12.13",
+  "_npmOperationalInternal": {
+    "host": "packages-12-west.internal.npmjs.com",
+    "tmp": "tmp/firebase-admin-4.0.3.tgz_1479765999690_0.8157484552357346"
+  },
+  "_npmUser": {
+    "name": "firebase",
+    "email": "operations+plainlogo@firebase.com"
+  },
+  "_npmVersion": "2.15.0",
+  "_phantomChildren": {},
+  "_requested": {
+    "raw": "firebase-admin",
+    "scope": null,
+    "escapedName": "firebase-admin",
+    "name": "firebase-admin",
+    "rawSpec": "",
+    "spec": "latest",
+    "type": "tag"
+  },
+  "_requiredBy": [
+    "#USER",
+    "/"
+  ],
+  "_resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-4.0.3.tgz",
+  "_shasum": "df2815424a23329c7ee597e29ea8bfeb67ee7db2",
+  "_shrinkwrap": {
+    "name": "firebase-admin",
+    "version": "4.0.3",
+    "dependencies": {
+      "@types/jsonwebtoken": {
+        "version": "7.1.33",
+        "from": "@types/jsonwebtoken@>=7.1.33 <8.0.0",
+        "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-7.1.33.tgz"
+      },
+      "@types/node": {
+        "version": "6.0.49",
+        "from": "@types/node@*",
+        "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.49.tgz"
+      },
+      "base64-url": {
+        "version": "1.3.3",
+        "from": "base64-url@>=1.2.1 <2.0.0",
+        "resolved": "https://registry.npmjs.org/base64-url/-/base64-url-1.3.3.tgz"
+      },
+      "base64url": {
+        "version": "2.0.0",
+        "from": "base64url@>=2.0.0 <3.0.0",
+        "resolved": "https://registry.npmjs.org/base64url/-/base64url-2.0.0.tgz"
+      },
+      "buffer-equal-constant-time": {
+        "version": "1.0.1",
+        "from": "buffer-equal-constant-time@1.0.1",
+        "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz"
+      },
+      "ecdsa-sig-formatter": {
+        "version": "1.0.7",
+        "from": "ecdsa-sig-formatter@1.0.7",
+        "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.7.tgz"
+      },
+      "faye-websocket": {
+        "version": "0.9.3",
+        "from": "faye-websocket@0.9.3",
+        "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.9.3.tgz"
+      },
+      "hoek": {
+        "version": "2.16.3",
+        "from": "hoek@>=2.0.0 <3.0.0",
+        "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz"
+      },
+      "isemail": {
+        "version": "1.2.0",
+        "from": "isemail@>=1.0.0 <2.0.0",
+        "resolved": "https://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz"
+      },
+      "joi": {
+        "version": "6.10.1",
+        "from": "joi@>=6.10.1 <7.0.0",
+        "resolved": "https://registry.npmjs.org/joi/-/joi-6.10.1.tgz"
+      },
+      "jsonwebtoken": {
+        "version": "7.1.9",
+        "from": "jsonwebtoken@7.1.9",
+        "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-7.1.9.tgz"
+      },
+      "jwa": {
+        "version": "1.1.4",
+        "from": "jwa@>=1.1.4 <2.0.0",
+        "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.4.tgz"
+      },
+      "jws": {
+        "version": "3.1.4",
+        "from": "jws@>=3.1.3 <4.0.0",
+        "resolved": "https://registry.npmjs.org/jws/-/jws-3.1.4.tgz"
+      },
+      "lodash.once": {
+        "version": "4.1.1",
+        "from": "lodash.once@>=4.0.0 <5.0.0",
+        "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz"
+      },
+      "moment": {
+        "version": "2.16.0",
+        "from": "moment@>=2.0.0 <3.0.0",
+        "resolved": "https://registry.npmjs.org/moment/-/moment-2.16.0.tgz"
+      },
+      "ms": {
+        "version": "0.7.2",
+        "from": "ms@>=0.7.1 <0.8.0",
+        "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz"
+      },
+      "safe-buffer": {
+        "version": "5.0.1",
+        "from": "safe-buffer@>=5.0.1 <6.0.0",
+        "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz"
+      },
+      "topo": {
+        "version": "1.1.0",
+        "from": "topo@>=1.0.0 <2.0.0",
+        "resolved": "https://registry.npmjs.org/topo/-/topo-1.1.0.tgz"
+      },
+      "websocket-driver": {
+        "version": "0.6.5",
+        "from": "websocket-driver@>=0.5.1",
+        "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz"
+      },
+      "websocket-extensions": {
+        "version": "0.1.1",
+        "from": "websocket-extensions@>=0.1.1",
+        "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz"
+      },
+      "xtend": {
+        "version": "4.0.1",
+        "from": "xtend@>=4.0.1 <5.0.0",
+        "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz"
+      }
+    }
+  },
+  "_spec": "firebase-admin",
+  "_where": "/Users/wahyudinakbar/Desktop/TugasBesar3_AngularJSandFirebase/KEMMessaging",
+  "author": {
+    "name": "Firebase",
+    "url": "https://firebase.google.com/"
+  },
+  "dependencies": {
+    "@types/jsonwebtoken": "^7.1.33",
+    "faye-websocket": "0.9.3",
+    "jsonwebtoken": "7.1.9"
+  },
+  "description": "Firebase admin SDK for Node.js",
+  "devDependencies": {
+    "@types/chai": "^3.4.34",
+    "@types/chai-as-promised": "0.0.29",
+    "@types/firebase-token-generator": "^2.0.28",
+    "@types/lodash": "^4.14.38",
+    "@types/mocha": "^2.2.32",
+    "@types/nock": "^8.0.33",
+    "@types/request": "0.0.32",
+    "@types/request-promise": "^4.1.33",
+    "@types/sinon": "^1.16.31",
+    "@types/sinon-chai": "^2.7.27",
+    "chai": "^3.5.0",
+    "chai-as-promised": "^6.0.0",
+    "del": "^2.2.1",
+    "firebase-token-generator": "^2.0.0",
+    "gulp": "^3.9.1",
+    "gulp-exit": "0.0.2",
+    "gulp-header": "^1.8.8",
+    "gulp-istanbul": "^1.1.1",
+    "gulp-mocha": "^3.0.1",
+    "gulp-replace": "^0.5.4",
+    "gulp-tslint": "^6.0.2",
+    "gulp-typescript": "^3.1.2",
+    "lodash": "^4.6.1",
+    "merge2": "^1.0.2",
+    "nock": "^8.0.0",
+    "request": "^2.75.0",
+    "request-promise": "^4.1.1",
+    "run-sequence": "^1.1.5",
+    "sinon": "^1.17.3",
+    "sinon-chai": "^2.8.0",
+    "tslint": "^3.5.0",
+    "typescript": "^2.0.3",
+    "typings": "^1.0.4"
+  },
+  "directories": {},
+  "dist": {
+    "shasum": "df2815424a23329c7ee597e29ea8bfeb67ee7db2",
+    "tarball": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-4.0.3.tgz"
+  },
+  "files": [
+    "lib/",
+    "README.md",
+    "package.json",
+    "npm-shrinkwrap.json"
+  ],
+  "homepage": "https://firebase.google.com/",
+  "keywords": [
+    "admin",
+    "database",
+    "Firebase",
+    "realtime",
+    "authentication"
+  ],
+  "license": "SEE LICENSE IN https://firebase.google.com/terms/",
+  "main": "lib/index.js",
+  "maintainers": [
+    {
+      "name": "firebase",
+      "email": "operations@firebase.com"
+    }
+  ],
+  "name": "firebase-admin",
+  "optionalDependencies": {},
+  "readme": "ERROR: No README data found!",
+  "scripts": {},
+  "types": "./lib/index.d.ts",
+  "version": "4.0.3"
+}
diff --git a/KEMMessaging/package.json b/KEMMessaging/package.json
index f810a4d15d1c31b9a5a974ea95732136a2b4fdbb..8827d95b903c7c848bbdcc74a8bced3941681b0b 100644
--- a/KEMMessaging/package.json
+++ b/KEMMessaging/package.json
@@ -11,6 +11,7 @@
   "dependencies": {
     "body-parser": "^1.15.2",
     "express": "^4.14.0",
-    "firebase": "^3.6.1"
+    "firebase": "^3.6.1",
+    "firebase-admin": "^4.0.3"
   }
 }
diff --git a/KEMMessaging/serviceAccountKey.json b/KEMMessaging/serviceAccountKey.json
new file mode 100644
index 0000000000000000000000000000000000000000..c67115a0530d49f49b5d997c2e2293a25e7f75cd
--- /dev/null
+++ b/KEMMessaging/serviceAccountKey.json
@@ -0,0 +1,12 @@
+{
+  "type": "service_account",
+  "project_id": "kemmessaging-150309",
+  "private_key_id": "abc24e84aa3c16d079f0af3ba8774b1d455a73de",
+  "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQClXBYKhYFsALc2\nwv8i3BgD1EYxrgou2BS58Rr0PXNcxWmml66/OLp28QvyFeJUfsv/DirTBhPfb1BK\n1nuMfhrTk3rY9ttoPWjrfb9lX4pQBSGMK+V0INjp0gvM+S64BnGTYvajql85BY0b\n1I6OMTnNEoWRz7WfpCv1tli4Ynzz0EPP+naSuiE0riD1vePvxx7l2F7QEljS9aMM\n/FfgMYhsYa7KeNq52iPIJcju/1cDGk6ZMacZJDJFNd8WhCurpVjZUT+/NJxDvEiP\nqm1W+9udk4U/WOwxmbbeGzXIsMpeDV0WIGZonPBzz+/Fb6Y9eko+jL8eEF4yL0uz\nLFEXfnA/AgMBAAECggEBAJH1jp8K6QpkN1RnGr2yeKAopy0C6ooewWy/nYMpGsMw\nnekmymCPukdyzZCKMJVUtswTvUk3fCMlJkJov/Vq+lL3QuBwRYrlac8z19WrV3L6\nlHod5RN0SwNZHIF5Efvt9CKcoAgnQpYaiEuge5SXbuXNC4mBRlf7mbHxmq5mgNTT\n/RvP43s9n9n3NkpYiVIyr3ARV1P/CIMnjkPqsIiTCGMzCBaQGgGwa5LfsiMesoA3\nlOKszxTvLPLXRRPm9TXcdMndHnptVPSOT/MDhLjQlCoGquIKpwYo1sG5BWRfePZL\nHvJOvd6sVInKrip9pNMRuSVuB6RKmHlGlpvOL3AA2IECgYEA1KY9j1Lvg5penVFg\nbrHefa8QUSNtejtap7tB8hO3HfBN5VQMs0eJxHyhJQn8q9WLZ+Rwrdgj/0tiZUki\n4DQ57jpMsq+rpzM2KTJO8NtT2b6IxXi2tRYQAGcEX48aPBerhrcJhy2Nm0L4tNzu\nQ+S6QXPSn2ryv5IzflzyzehSAKcCgYEAxxHjtVEiVLWlXZy5IsaeK3N1fvnmoOkI\nQ886XDm3aUnubA/k6WB+1VB+2Op+hPKIL/sFgZ55BYt0s7UujqPp+I9KVD2c7Wi7\n6lMua1QoiLXR+eea2MEwlNIlo6U6PHfbkMfAT4Fla0FXkQ554blWFuvnRpjxYUoi\nmrwzKTKSLqkCgYEAuz5CWHBzvFLyWt3r5qyyN8Mtv/RNEuMumSEXGTxo8nDFdlhC\n8p3cXmpLTpzzoq7fGLUazsjSMZrEYmE612bFV9J39KMgp5I9b5r/za+irsnKDu+T\nGfL6VhBf1nDgbed9vppvRltDJGKdMkyTdK7znmyJGpyGcU8gDnVzywF1K2MCgYAP\n8Be6CY/lFlHyB70u0pYRRoIus1VKpr2ZqDq07Y4IqPmkvzUFlksxSuuM9GFCxaQv\nqzpKoWRxFDQ4uxXKJ8dwthAuZGxu+YaqARTjVO6V23C/QFK+beE02QpYar8Z3kK+\n+a8k7mgvSSD4pR8O+maxGRwAI/iXYHcaylySPNFFWQKBgQC5Yq5vh9DXTGh+z8V3\nMeRK1zyBabDaFe2TuyS0uUfhjAzys7G74kIAC03t9dvzzZCmQyzXP2P4kDXvx2zG\nn0hTH9jwlojyj5LeH8DTegWe3BwNdoPXtFb+lYzSaWBnHK9f85eEgwNBDzqImWL4\nrleZpTx/8Qc829u+B43Ba2MczA==\n-----END PRIVATE KEY-----\n",
+  "client_email": "firebase-adminsdk-pmu87@kemmessaging-150309.iam.gserviceaccount.com",
+  "client_id": "116926435242958892965",
+  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
+  "token_uri": "https://accounts.google.com/o/oauth2/token",
+  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
+  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-pmu87%40kemmessaging-150309.iam.gserviceaccount.com"
+}
diff --git a/KEMProject/WebContent/catalog.jsp b/KEMProject/WebContent/catalog.jsp
index 5d2e9e0a7c834adf12989fd24a7db882ba6ceadc..64409d7065cdd351159cb1948357901f61e833a4 100755
--- a/KEMProject/WebContent/catalog.jsp
+++ b/KEMProject/WebContent/catalog.jsp
@@ -87,9 +87,6 @@
     	System.out.println("new token: " + session.getAttribute("token"));
     }
 %>
-
-
-	
 		<!-- ref: http://stackoverflow.com/questions/15445430/how-can-i-make-my-navi-bar-the-same-across-my-html -->
 		<div class="title">
 		<span id="j01">Sale</span><span id="j02">Project</span>
@@ -209,7 +206,7 @@
 	         	User u2 = market.dataUser(session.getAttribute("token").toString(), Integer.toString(p.getId_Saler()));
 	    	%>
 	    		<div class ="Product" ng-init="checkOnline('<%= u2.getUsername() %>',<%= p.getId_Product() %>)">
-		    		<b><span class="Username" ng-click="user= '<%= u2.getUsername() %>'; isUser('<%= u2.getUsername() %>', '<%= u.getUsername() %>')"><span class="circle" id="cir<%= p.getId_Product() %>"></span><%= u2.getUsername() %></span></br></b>
+		    		<b><span class="Username" ng-click="user= '<%= u2.getUsername() %>';rcv ='<%= u2.getEmail() %>'; isUser('<%= u2.getUsername() %>','<%= u.getUsername() %>',<%= p.getId_Product() %>);"><span class="circle" id="cir<%= p.getId_Product() %>"></span><%= u2.getUsername() %></span></br></b>
 
 		    		<span class="Added">added this on <%= day %>, <%= date %>, at <%= hour %></span>
 		    		<div class="InfoProduct">
@@ -278,49 +275,75 @@
 					  var ol = firebase.database().ref('/presence/'+user);
 					  	ol.on('value', function(snapshot) {
 					  		var count = snapshot.numChildren();
-					  		console.log(count);
 					  		if(count == 0){
 					  			$('#cir'+id).removeClass( "online" ).addClass("offline");
 					  	    	console.log(user+"sign out");
+					  	    	return false;
 					  	    } else {
 					  	    	$('#cir'+id).removeClass( "offline" ).addClass("online");
 					  	    	console.log(user+"sign in");
+					  	    	return true;
 					  	    }
-					  	    return count;
 					  	    
 					  	});
 				  };
+				  var user = firebase.auth().currentUser;
+
+				  if (user) {
+				    console.log("user ga null");
+				  } else {
+					 console.log("user null");
+				  }
+				  $scope.token = null;
+				  firebase.auth().onAuthStateChanged(function(user) {
+				  	  if (user) {
+				  		  console.log("user not null");
+				  			user.getToken().then(function(data) {
+					  		    $scope.token = data;
+					  		  $scope.formsubmit = function() {
+								  var $http = angular.injector(['ng']).get('$http');
+								  
+								  var dataObj = {
+											message: $scope.message,
+											token: $scope.token,
+											sender:'<%= u.getEmail() %>',
+											rcv: $scope.rcv
+									};
+								  console.log($scope.message);
+								  console.log("token kow: "+$scope.token);
+								$http({
+									  url: 'http://localhost:8081/addMessage',
+								      method: "POST",
+								      data: dataObj,
+								      headers: {
+								          'Access-Control-Allow-Origin': '*',
+								          'Access-Control-Allow-Methods': 'POST, GET',
+								          'Access-Control-Allow-Headers': 'Content-Type'
+								      }
+								  }).then(function mySucces(response) {
+									  $( ".bodychat" ).append( '<li><div class="sentdialog">'+$scope.message+'</div></li>' );
+								    }, function myError(response) {
+								    	console.log("error");
+								      $scope.myWelcome = response.statusText;
+								  });
+								return false;
+						        }
+					  		});
+				  	  }
+				  	});
 				  
 				  $scope.message = {};
-				  
-				  $scope.formsubmit = function() {
-					  var $http = angular.injector(['ng']).get('$http');
-					  var dataObj = {
-								message: $scope.message
-						};
-					  console.log($scope.message);
-					$http({
-						  url: 'http://localhost:8081/addMessage',
-					      method: "POST",
-					      data: dataObj,
-					      headers: {
-					          'Access-Control-Allow-Origin': '*',
-					          'Access-Control-Allow-Methods': 'POST, GET',
-					          'Access-Control-Allow-Headers': 'Content-Type'
-					      }
-					  }).then(function mySucces(response) {
-						  $( ".bodychat" ).append( '<li><div class="sentdialog">'+$scope.message+'</div></li>' );
-					    }, function myError(response) {
-					    	console.log("error");
-					      $scope.myWelcome = response.statusText;
-					  });
-					return false;
-			        }
-				  
+				  $scope.rcv = null;
 				  $scope.user = null;
-				  $scope.isUser = function(user, login) {
-					    if (user != login)
-					    	$scope.chat = true;
+				  $scope.isUser = function(user, login, id) {
+					    if (user != login){
+					    	var cir = document.getElementById("cir"+id).className;
+					    	if(cir == 'circle online'){
+					    		$scope.chat = true;
+					    	}else {
+					    		$scope.chat = false;
+					    	}
+					    }
 					    else $scope.chat = false;
 					  };
 				});
@@ -369,6 +392,7 @@
 				  firebase.auth().onAuthStateChanged(function(user) {
 				  	  if (user) {
 				  		  console.log("sign in");
+				  		  
 				  		  var listRef = firebase.database().ref("presence/"+"<%= u.getUsername() %>");
 				  		  var userRef = listRef.push();
 				  		  // Add ourselves to presence list when online.