<commit_before>(function (jStorage, undefined) {
    function writeCookie(name, value, days) {
        if (days) {
            var date = new Date();
            date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
            var expires = "; expires=" + date.toGMTString();
        }
        else var expires = "";
        document.cookie = name + "=" + value + expires + "; path=/";
    }

    function readCookie(name) {
        var nameEQ = name + "=";
        var ca = document.cookie.split(';');
        for (var i = 0; i < ca.length; i++) {
            var c = ca[i];
            while (c.charAt(0) == ' ') c = c.substring(1, c.length);
            if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
        }
        return null;
    }

    function eraseCookie(name) {
        writeCookie(name, "", -1);
    }

    function githubRequest(method, address, token, data, callback) {
        var xmlhttp;
        if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
            xmlhttp = new XMLHttpRequest();
        }
        else {// code for IE6, IE5
            xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        }

        xmlhttp.dataType = "json";

        xmlhttp.open(method, address, true);

        xmlhttp.onreadystatechange = function () {
            if (this.readyState == 4) {
                if (this.status >= 200 && this.status < 300 || this.status === 304) {
                    var responseData = this.responseText ? JSON.parse(this.responseText) : {};
                    responseData['last-modified'] = this.getResponseHeader("Last-Modified");
                    callback(null, responseData, this);
                } else {
                    callback({ path: address, request: this, error: this.status });
                }
            }
        };

        //xmlhttp.setRequestHeader('Accept', 'application/vnd.github.raw+json');
        xmlhttp.setRequestHeader('Accept', 'application/json;charset=UTF-8');
        xmlhttp.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
        //xmlhttp.setRequestHeader("Access-Control-Allow-Origin", window.location.protocol + '//' + window.location.host);
        //xmlhttp.setRequestHeader('Content-Type', 'application/xml');
        if (token) {
            xmlhttp.setRequestHeader('Authorization', 'token ' + token);
        }

        data ? xmlhttp.send(JSON.stringify(data)) : xmlhttp.send();
    }

    jStorage.providers.github = {
        init: function (wrapper, config) {
            var self = this;

            console.log('github init');

            this._config = config;
            this._hasCallback = config && typeof (config.callback) === "function";
            this._state = 'random' + new Date().getTime();
            this._code = false;
            this._shaCache = {};

            this.ensureAuth(wrapper, config);

            // https://github.com/settings/tokens/new
            var token = this._config.token;
            var addr = "https://api.github.com/";
            //githubRequest("GET", addr, token, false, function () {
            //    console.log(arguments);
            //});

            // Get current users repositories
            //addr = "https://api.github.com/user/repos";
            //githubRequest("GET", addr, token, false, function () {
            //    if (arguments.length >= 2) {
            //        var response = arguments[1];
            //        //console.log(response);
            //        for (var i = 0; i < response.length; i++) {
            //            if (response[i].name == "brfskagagard") {
            //                console.log(response[i]);
            //            }
            //        }
            //    }
            //});

            // Get collaborators for a given respository
            //addr = "https://api.github.com/repos/flowertwig-org/brfskagagard/collaborators";
            //githubRequest("GET", addr, token, false, function () {
            //    console.log(arguments);
            //});

            // Get summary of readme
            //addr = "https://api.github.com/repos/flowertwig-org/brfskagagard/readme";
            //githubRequest("GET", addr, token, false, function () {
            //    console.log(arguments);
            //});

            // Get content of file
            //addr = "https://api.github.com/repos/" + this._config.repo + "/contents/index.html";
            //githubRequest("GET", addr, token, false, function () {
            //    console.log(arguments[0]);
            //    console.log(arguments[1]);
            //    console.log(atob(arguments[1].content));
            //});

            this._hasRepo = config && typeof (config.repo) === "string";
            this._hasToken = config && typeof (config.token) === "string";

            var callStatus = false;
            if (this._hasRepo && this._hasToken) {
                callStatus = {
                    'isOK': true,
                    'code': 0,
                    'msg': ''
                };
            } else {
                var msg = '';
                if (!this._hasToken) {
                    msg += 'No user token specified. ';
                }
                if (!this._hasRepo) {
                    msg += 'No repository specified. ';
                }
                callStatus = {
                    'isOK': false,
                    'code': -1,
                    'msg': msg
                };
            }

            if (self._hasCallback) {
                try {
                    self._config.callback(wrapper, callStatus);
                } catch (e) {
                    // TODO: handle error
                }
            }
        },
        get: function (name, callback) {
            var self = this;
            addr = "https://api.github.com/repos/" + this._config.repo + "/contents/" + name;
            githubRequest("GET", addr, self._config.token, false, function () {
                if (arguments.length >= 2) {
                    var info = arguments[1];
                    if (info.type == "file") {
                        var data = arguments[1].content;
                        self._shaCache[name] = info.sha;
                        callback(
                            {
                                'name': info.path,
                                'size': info.size,
                                'mime-type': 'text/html',
                                'modified': info['last-modified'],
                                'data': atob(data)
                            },
                            { 'isOK': true, 'msg': '', 'code': 0 });
                    } else {
                        callback(null, { 'isOK': false, 'msg': 'This is not a valid file', 'code': -1 });
                    }
                } else {
                    callback(null, { 'isOK': false, 'msg': arguments[0].request.statusText, 'code': arguments[0].request.status });
                }
            });
        },
        set: function (name, content, callback) {
            var self = this;
            // update content of file
            addr = "https://api.github.com/repos/" + self._config.repo + "/contents/" + name;
            var data = {
                "message": "jStorage Test update",
                "content": btoa(content)
            };
            // This is required to update existing file (we need to tell github from what version we are trying to update)
            var sha = self._shaCache[name];
            if (sha) {
                data["sha"] = sha;
            }

            githubRequest("PUT", addr, self._config.token, data, function () {
                if (arguments.length >= 2) {
                    var info = arguments[1];
                    if (info.type == "file") {
                        var data = arguments[1].content;
                        callback(
                            {
                                'name': info.path,
                                'size': info.size,
                                'mime-type': 'text/html',
                                'modified': info['last-modified'],
                            },
                            { 'isOK': true, 'msg': '', 'code': 0 });
                    } else {
                        callback(null, { 'isOK': false, 'msg': 'This is not a valid file', 'code': -1 });
                    }
                } else {
                    callback(null, { 'isOK': false, 'msg': arguments[0].request.statusText, 'code': arguments[0].request.status });
                }
            });
        },
        del: function (name, callback) {
            console.log('github del');
        },
        list: function (name, callback) {
            console.log('github list');
        },
        exists: function (name, callback) {
            console.log('github exists');
        },
        ensureAuth: function (wrapper, config) {
            // TODO: we require token today, allow for oauth fetching of token here

            //var scope = 'public_repo';
            //if (config.access && config.access == "private") {
            //    scope = 'repo';
            //}

            //// https://dev.jstorage.flowertwig.org/tests/github.html
            //var redirectUrl = window.location.protocol + '//' + window.location.host + window.location.pathname;

            //var sections = window.location.search.split("&");
            //for (var i = 0; i < sections.length; i++) {
            //    var pair = sections[i].split('=');
            //    if (pair.length == 2) {
            //        var key = pair[0];
            //        var value = pair[1];

            //        key = key.replace(/^\?/, '');

            //        console.log('key: ' + key);
            //        console.log('value: ' + value);

            //        switch (key) {
            //            case 'state':
            //                _state = value;
            //                break;
            //            case 'code':
            //                _code = value;
            //                writeCookie('jStorage-github-code', value, 1);
            //                break;
            //        }
            //    }
            //}

            //var step = readCookie('jStorage-github-step');
            //switch (step) {
            //    default:
            //        writeCookie('jStorage-github-step', 'step2');
            //        writeCookie('jStorage-github-state', this._state, 1);

            //        window.location.assign('https://github.com/login/oauth/authorize?client_id=' + config.clientId + '&redirect_uri=' + redirectUrl + '&scope=' + scope + '&state=' + this._state);
            //        break;
            //    case 'step2':
            //        // TODO: Validate so state in cookie matches the state in query param.
            //        var code = readCookie('jStorage-github-code');

            //        var addr = 'https://github.com/login/oauth/access_token';
            //        //var addr = "https://githubservice.jstorage.flowertwig.org/api/Values";
            //        var data = 'client_id=' + config.clientId + '&client_secret=' + config.clientSecret + '&code=' + code + '&redirect_uri=' + redirectUrl;

            //        //var s = document.createElement('script'),
            //        //    h = document.getElementsByTagName('head')[0];
            //        //s.src = addr;
            //        //h.appendChild(s);

            //        //document.getElementsByName('client_id')[0].value = config.clientId;
            //        //document.getElementsByName('client_secret')[0].value = config.clientSecret;
            //        //document.getElementsByName('code')[0].value = code;
            //        //document.getElementsByName('redirect_uri')[0].value = redirectUrl;

            //        githubRequest('POST', addr, false, data, function() {
            //            console.log(arguments);
            //        });

            //        //request('https://github.com/login/oauth/access_token?client_id=' + config.clientId + '&client_secret=' + config.clientSecret + '&code=' + code + '&redirect_uri=' + redirectUrl);
            //        //https://github.com/login/oauth/access_token?client_id=df3a0f28472a4ad20f39&client_secret=f3029af7a93f39319b580dea5afbce693bb56876&code=d58c49123ecdaa0ba73c&redirect_uri=https://dev.jstorage.flowertwig.org/tests/github.html
            //            //access_token=9c32c17fe2225a36cc04a0f8975b8cd64a4210e0&scope=public_repo&token_type=bearer
            //        //writeCookie('jStorage-github-step', 'step3');
            //        break;
            //    case 'step3':
            //        //eraseCookie('jStorage-github-step');
            //        //eraseCookie('jStorage-github-state');
            //        //eraseCookie('jStorage-github-code');
            //        break;
            //}
        }
    };
})(jStorage);<commit_msg>Github, del method and "can create storage" test compliant<commit_after>(function (jStorage, undefined) {
    function writeCookie(name, value, days) {
        if (days) {
            var date = new Date();
            date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
            var expires = "; expires=" + date.toGMTString();
        }
        else var expires = "";
        document.cookie = name + "=" + value + expires + "; path=/";
    }

    function readCookie(name) {
        var nameEQ = name + "=";
        var ca = document.cookie.split(';');
        for (var i = 0; i < ca.length; i++) {
            var c = ca[i];
            while (c.charAt(0) == ' ') c = c.substring(1, c.length);
            if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
        }
        return null;
    }

    function eraseCookie(name) {
        writeCookie(name, "", -1);
    }

    function githubRequest(method, address, token, data, callback) {
        var xmlhttp;
        if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
            xmlhttp = new XMLHttpRequest();
        }
        else {// code for IE6, IE5
            xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        }

        xmlhttp.dataType = "json";

        xmlhttp.open(method, address, true);

        xmlhttp.onreadystatechange = function () {
            if (this.readyState == 4) {
                if (this.status >= 200 && this.status < 300 || this.status === 304) {
                    var responseData = this.responseText ? JSON.parse(this.responseText) : {};
                    responseData['last-modified'] = this.getResponseHeader("Last-Modified");
                    callback(null, responseData, this);
                } else {
                    callback({ path: address, request: this, error: this.status });
                }
            }
        };

        //xmlhttp.setRequestHeader('Accept', 'application/vnd.github.raw+json');
        xmlhttp.setRequestHeader('Accept', 'application/json;charset=UTF-8');
        xmlhttp.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
        //xmlhttp.setRequestHeader("Access-Control-Allow-Origin", window.location.protocol + '//' + window.location.host);
        //xmlhttp.setRequestHeader('Content-Type', 'application/xml');
        if (token) {
            xmlhttp.setRequestHeader('Authorization', 'token ' + token);
        }

        data ? xmlhttp.send(JSON.stringify(data)) : xmlhttp.send();
    }

    jStorage.providers.github = {
        init: function (wrapper, config) {
            var self = this;

            console.log('github init');

            this._config = config;
            this._hasCallback = config && typeof (config.callback) === "function";
            this._state = 'random' + new Date().getTime();
            this._code = false;
            this._shaCache = {};

            this.ensureAuth(wrapper, config);

            // https://github.com/settings/tokens/new
            var token = this._config.token;
            var addr = "https://api.github.com/";
            //githubRequest("GET", addr, token, false, function () {
            //    console.log(arguments);
            //});

            // Get current users repositories
            //addr = "https://api.github.com/user/repos";
            //githubRequest("GET", addr, token, false, function () {
            //    if (arguments.length >= 2) {
            //        var response = arguments[1];
            //        //console.log(response);
            //        for (var i = 0; i < response.length; i++) {
            //            if (response[i].name == "brfskagagard") {
            //                console.log(response[i]);
            //            }
            //        }
            //    }
            //});

            // Get collaborators for a given respository
            //addr = "https://api.github.com/repos/flowertwig-org/brfskagagard/collaborators";
            //githubRequest("GET", addr, token, false, function () {
            //    console.log(arguments);
            //});

            // Get summary of readme
            //addr = "https://api.github.com/repos/flowertwig-org/brfskagagard/readme";
            //githubRequest("GET", addr, token, false, function () {
            //    console.log(arguments);
            //});

            // Get content of file
            //addr = "https://api.github.com/repos/" + this._config.repo + "/contents/index.html";
            //githubRequest("GET", addr, token, false, function () {
            //    console.log(arguments[0]);
            //    console.log(arguments[1]);
            //    console.log(atob(arguments[1].content));
            //});

            this._hasRepo = config && typeof (config.repo) === "string";
            this._hasToken = config && typeof (config.token) === "string";

            var callStatus = false;
            if (this._hasRepo && this._hasToken) {
                callStatus = {
                    'isOK': true,
                    'code': 0,
                    'msg': ''
                };
            } else {
                var msg = '';
                if (!this._hasToken) {
                    msg += 'No user token specified. ';
                }
                if (!this._hasRepo) {
                    msg += 'No repository specified. ';
                }
                callStatus = {
                    'isOK': false,
                    'code': -1,
                    'msg': msg
                };
            }

            if (self._hasCallback) {
                try {
                    self._config.callback(wrapper, callStatus);
                } catch (e) {
                    // TODO: handle error
                }
            }
        },
        get: function (name, callback) {
            var self = this;
            addr = "https://api.github.com/repos/" + this._config.repo + "/contents/" + name;
            githubRequest("GET", addr, self._config.token, false, function () {
                if (arguments.length >= 2) {
                    var info = arguments[1];
                    if (info.type == "file") {
                        var data = arguments[1].content;
                        self._shaCache[name] = info.sha;
                        callback(
                            {
                                'name': info.path,
                                'size': info.size,
                                'mime-type': 'text/html',
                                'modified': info['last-modified'],
                                'data': atob(data)
                            },
                            { 'isOK': true, 'msg': '', 'code': 0 });
                    } else {
                        callback(null, { 'isOK': false, 'msg': 'This is not a valid file', 'code': -1 });
                    }
                } else {
                    callback(null, { 'isOK': false, 'msg': arguments[0].request.statusText, 'code': arguments[0].request.status });
                }
            });
        },
        set: function (name, content, callback) {
            var self = this;
            // update content of file
            addr = "https://api.github.com/repos/" + self._config.repo + "/contents/" + name;
            var data = {
                "message": "jStorage Test update",
                "content": btoa(content)
            };
            // This is required to update existing file (we need to tell github from what version we are trying to update)
            var sha = self._shaCache[name];
            if (sha) {
                data["sha"] = sha;
            }

            githubRequest("PUT", addr, self._config.token, data, function () {
                if (arguments.length >= 2) {
                    var info = arguments[1];
                    if (info.content && info.content.type == "file") {
                        callback(
                            {
                                'name': info.content.path,
                                'size': info.content.size,
                                'mime-type': 'text/html',
                                'modified': info['last-modified'],
                            },
                            { 'isOK': true, 'msg': '', 'code': 0 });
                    } else {
                        callback(null, { 'isOK': false, 'msg': 'This is not a valid file', 'code': -1 });
                    }
                } else {
                    callback(null, { 'isOK': false, 'msg': arguments[0].request.statusText, 'code': arguments[0].request.status });
                }
            });
        },
        del: function (name, callback) {
            var self = this;
            // update content of file
            addr = "https://api.github.com/repos/" + self._config.repo + "/contents/" + name;
            // sha is required to remove file, so we need to have called get before we can delete a file right now.
            var sha = self._shaCache[name];
            var data = {
                "message": "jStorage Test delete",
                "sha": sha

            };

            githubRequest("DELETE", addr, self._config.token, data, function () {
                if (arguments.length >= 2) {
                    var data = arguments[1].content;
                    callback({ 'isOK': true, 'msg': '', 'code': 0 });
                } else {
                    callback({ 'isOK': false, 'msg': arguments[0].request.statusText, 'code': arguments[0].request.status });
                }
            });
        },
        list: function (name, callback) {
            console.log('github list');
        },
        exists: function (name, callback) {
            console.log('github exists');
        },
        ensureAuth: function (wrapper, config) {
            // TODO: we require token today, allow for oauth fetching of token here

            //var scope = 'public_repo';
            //if (config.access && config.access == "private") {
            //    scope = 'repo';
            //}

            //// https://dev.jstorage.flowertwig.org/tests/github.html
            //var redirectUrl = window.location.protocol + '//' + window.location.host + window.location.pathname;

            //var sections = window.location.search.split("&");
            //for (var i = 0; i < sections.length; i++) {
            //    var pair = sections[i].split('=');
            //    if (pair.length == 2) {
            //        var key = pair[0];
            //        var value = pair[1];

            //        key = key.replace(/^\?/, '');

            //        console.log('key: ' + key);
            //        console.log('value: ' + value);

            //        switch (key) {
            //            case 'state':
            //                _state = value;
            //                break;
            //            case 'code':
            //                _code = value;
            //                writeCookie('jStorage-github-code', value, 1);
            //                break;
            //        }
            //    }
            //}

            //var step = readCookie('jStorage-github-step');
            //switch (step) {
            //    default:
            //        writeCookie('jStorage-github-step', 'step2');
            //        writeCookie('jStorage-github-state', this._state, 1);

            //        window.location.assign('https://github.com/login/oauth/authorize?client_id=' + config.clientId + '&redirect_uri=' + redirectUrl + '&scope=' + scope + '&state=' + this._state);
            //        break;
            //    case 'step2':
            //        // TODO: Validate so state in cookie matches the state in query param.
            //        var code = readCookie('jStorage-github-code');

            //        var addr = 'https://github.com/login/oauth/access_token';
            //        //var addr = "https://githubservice.jstorage.flowertwig.org/api/Values";
            //        var data = 'client_id=' + config.clientId + '&client_secret=' + config.clientSecret + '&code=' + code + '&redirect_uri=' + redirectUrl;

            //        //var s = document.createElement('script'),
            //        //    h = document.getElementsByTagName('head')[0];
            //        //s.src = addr;
            //        //h.appendChild(s);

            //        //document.getElementsByName('client_id')[0].value = config.clientId;
            //        //document.getElementsByName('client_secret')[0].value = config.clientSecret;
            //        //document.getElementsByName('code')[0].value = code;
            //        //document.getElementsByName('redirect_uri')[0].value = redirectUrl;

            //        githubRequest('POST', addr, false, data, function() {
            //            console.log(arguments);
            //        });

            //        //request('https://github.com/login/oauth/access_token?client_id=' + config.clientId + '&client_secret=' + config.clientSecret + '&code=' + code + '&redirect_uri=' + redirectUrl);
            //        //https://github.com/login/oauth/access_token?client_id=df3a0f28472a4ad20f39&client_secret=f3029af7a93f39319b580dea5afbce693bb56876&code=d58c49123ecdaa0ba73c&redirect_uri=https://dev.jstorage.flowertwig.org/tests/github.html
            //            //access_token=9c32c17fe2225a36cc04a0f8975b8cd64a4210e0&scope=public_repo&token_type=bearer
            //        //writeCookie('jStorage-github-step', 'step3');
            //        break;
            //    case 'step3':
            //        //eraseCookie('jStorage-github-step');
            //        //eraseCookie('jStorage-github-state');
            //        //eraseCookie('jStorage-github-code');
            //        break;
            //}
        }
    };
})(jStorage);<|endoftext|>


<commit_before>
import { MeetingSeries } from '/imports/meetingseries'

Template.minutesList.helpers({
    buttonBackground: function () {
        return (this.isFinalized) ? "default" : "info";
    },

    addMinutesPath: function () {
        let ms = new MeetingSeries(this.meetingSeriesId);
        return (ms.addNewMinutesAllowed()) ? "/minutesadd/" + this.meetingSeriesId : "";
    },

    addMinutesNotAllowed: function () {
        let ms = new MeetingSeries(this.meetingSeriesId);
        return !ms.addNewMinutesAllowed();
    },

    isDeleteNotAllowed: function () {
        return (this.isFinalized || this.isUnfinalized);
    }
});

Template.minutesList.events({
    "click #deleteMinutes": function (evt) {
        let disabled = evt.currentTarget.getAttribute('disabled');
        if (disabled) return;

        console.log("Remove Meeting Minute " + this._id + " from Series: " + this.meetingSeries_id);
        confirmationDialog(
            /* callback called if user wants to continue */
            () => {
                let ms = new MeetingSeries(this.meetingSeries_id);
                ms.removeMinutesWithId(this._id);
            },
            /* Dialog content */
            "Do you really want to delete this meeting minute?"
        );
    }
});<commit_msg>Delete Minutes: Popup dialog shows concerning minutes date.<commit_after>
import { MeetingSeries } from '/imports/meetingseries'

Template.minutesList.helpers({
    buttonBackground: function () {
        return (this.isFinalized) ? "default" : "info";
    },

    addMinutesPath: function () {
        let ms = new MeetingSeries(this.meetingSeriesId);
        return (ms.addNewMinutesAllowed()) ? "/minutesadd/" + this.meetingSeriesId : "";
    },

    addMinutesNotAllowed: function () {
        let ms = new MeetingSeries(this.meetingSeriesId);
        return !ms.addNewMinutesAllowed();
    },

    isDeleteNotAllowed: function () {
        return (this.isFinalized || this.isUnfinalized);
    }
});

Template.minutesList.events({
    "click #deleteMinutes": function (evt) {
        let disabled = evt.currentTarget.getAttribute('disabled');
        if (disabled) return;

        console.log("Remove Meeting Minute " + this._id + " from Series: " + this.meetingSeries_id);

        let dialogContent = "Do you really want to delete this meeting minute dated on <strong>" + this.date + "</strong>?";
        confirmationDialog(
            /* callback called if user wants to continue */
            () => {
                let ms = new MeetingSeries(this.meetingSeries_id);
                ms.removeMinutesWithId(this._id);
            },
            /* Dialog content */
            dialogContent
        );
    }
});<|endoftext|>


<commit_before>// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------

/// <reference path="C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0\ExtensionSDKs\Microsoft.WinJS.1.0\1.0\DesignTime\CommonConfiguration\Neutral\Microsoft.WinJS.1.0\js\base.js" />
/// <reference path="C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0\ExtensionSDKs\Microsoft.WinJS.1.0\1.0\DesignTime\CommonConfiguration\Neutral\Microsoft.WinJS.1.0\js\ui.js" />
/// <reference path="Generated\MobileServices.DevIntellisense.js" />

var _ = require('Extensions');
var Validate = require('Validate');
var Platform = require('Platform');
var MobileServiceTable = require('MobileServiceTable').MobileServiceTable;
var MobileServiceLogin = require('MobileServiceLogin').MobileServiceLogin;

function MobileServiceClient(applicationUrl, applicationKey) {
    /// <summary>
    /// Initializes a new instance of the MobileServiceClient class.
    /// </summary>
    /// <param name="applicationUrl" type="string" mayBeNull="false">
    /// The URL to the Mobile Services application.
    /// </param>
    /// <param name="applicationKey" type="string" mayBeNull="false">
    /// The Mobile Service application's key.
    /// </param>

    Validate.isString(applicationUrl, 'applicationUrl');
    Validate.notNullOrEmpty(applicationUrl, 'applicationUrl');
    Validate.isString(applicationKey, 'applicationKey');

    this.applicationUrl = applicationUrl;
    this.applicationKey = applicationKey || null;

    var sdkInfo = Platform.getSdkInfo();
    var osInfo = Platform.getOperatingSystemInfo();
    var sdkVersion = sdkInfo.fileVersion.split(".").slice(0, 2).join(".");
    this.version = "ZUMO/" + sdkVersion + " (lang=" + sdkInfo.language + "; " +
                                            "os=" + osInfo.name + "; " +
                                            "os_version=" + osInfo.version + "; " +
                                            "arch=" + osInfo.architecture + "; " +
                                            "version=" + sdkInfo.fileVersion + ")";
    this.currentUser = null;
    this._serviceFilter = null;
    this._login = new MobileServiceLogin(this);
    this.getTable = function (tableName) {
        /// <summary>
        /// Gets a reference to a table and its data operations.
        /// </summary>
        /// <param name="tableName">The name of the table.</param>
        /// <returns>A reference to the table.</returns>

        Validate.isString(tableName, 'tableName');
        Validate.notNullOrEmpty(tableName, 'tableName');
        return new MobileServiceTable(tableName, this);
    };
}

// Export the MobileServiceClient class
exports.MobileServiceClient = MobileServiceClient;

// Define the MobileServiceClient in a namespace (note: this has global effects
// unless the platform we're using chooses to ignore it because exports are
// good enough).
Platform.addToMobileServicesClientNamespace({ MobileServiceClient: MobileServiceClient });

MobileServiceClient.prototype.withFilter = function (serviceFilter) {
    /// <summary>
    /// Create a new MobileServiceClient with a filter used to process all
    /// of its HTTP requests and responses.
    /// </summary>
    /// <param name="serviceFilter" type="Function">
    /// The filter to use on the service.  The signature of a serviceFilter is
    ///    function(request, next, callback)
    ///  where
    ///    next := function(request, callback)
    ///    callback := function(error, response)
    /// </param>
    /// <returns type="MobileServiceClient">
    /// A new MobileServiceClient whose HTTP requests and responses will be
    /// filtered as desired.
    /// </returns>
    /// <remarks>
    /// The Mobile Services HTTP pipeline is a chain of filters composed
    /// together by giving each the next operation which it can invoke
    /// (zero, one, or many times as necessary).  The default continuation
    /// of a brand new MobileServiceClient will just get the HTTP response
    /// for the corresponding request.  Here's an example of a Handle
    /// implementation that will automatically retry a request that times
    /// out.
    ///     function(req, next, callback) {
    ///         next(req, function(err, rsp) {
    ///           if (rsp.statusCode >= 400) {
    ///               next(req, callback);
    ///           } else {
    ///               callback(err, rsp);
    ///           }
    ///         });
    ///     }
    /// Note that because these operations are asynchronous, this sample
    /// filter could end up actually making two HTTP requests before
    /// returning a response to the developer without the developer writing
    /// any special code to handle the situation.
    /// -
    /// Filters are composed just like standard function composition.  If
    /// we had new MobileServiceClient().withFilter(F1).withFilter(F2)
    /// .withFilter(F3), it's conceptually equivalent to saying:
    ///     var response = F3(F2(F1(next(request)));
    /// </remarks>

    Validate.notNull(serviceFilter, 'serviceFilter');

    // Clone the current instance
    var client = new MobileServiceClient(this.applicationUrl, this.applicationKey);
    client.currentUser = this.currentUser;

    // Chain the service filter with any existing filters
    var existingFilter = this._serviceFilter;
    client._serviceFilter = _.isNull(existingFilter) ?
        serviceFilter :
        function (req, next, callback) {
            // compose existingFilter with next so it can be used as the next
            // of the new serviceFilter
            var composed = function (req, callback) {
                existingFilter(req, next, callback);
            };
            serviceFilter(req, composed, callback);
        };

    return client;
};

MobileServiceClient.prototype._request = function (method, uriFragment, content, ignoreFilters, headers, callback) {
    /// <summary>
    /// Perform a web request and include the standard Mobile Services headers.
    /// </summary>
    /// <param name="method" type="string">
    /// The HTTP method used to request the resource.
    /// </param>
    /// <param name="uriFragment" type="String">
    /// URI of the resource to request (relative to the Mobile Services
    /// runtime).
    /// </param>
    /// <param name="content" type="Object">
    /// Optional content to send to the resource.
    /// </param>
    /// <param name="ignoreFilters" type="Boolean" mayBeNull="true">
    /// Optional parameter to indicate if the client filters should be ignored
    /// and the request should be sent directly. Is false by default.
    /// </param>
    /// <param name="headers" type="Object">
    /// Optional request headers
    /// </param>
    /// <param name="callback" type="function(error, response)">
    /// Handler that will be called on the response.
    /// </param>

    // Account for absent optional arguments
    if (_.isNull(callback) && (typeof headers === 'function')) {
        callback = headers;
        headers = null;
    }

    if (_.isNull(callback) && (typeof ignoreFilters === 'function')) {
        callback = ignoreFilters;
        ignoreFilters = false;
    }

    Validate.isString(method, 'method');
    Validate.notNullOrEmpty(method, 'method');
    Validate.isString(uriFragment, 'uriFragment');
    Validate.notNull(uriFragment, 'uriFragment');
    Validate.notNull(callback, 'callback');

    // Create the absolute URI
    var options = { type: method.toUpperCase() };
    options.url = _.url.combinePathSegments(this.applicationUrl, uriFragment);

    // Set MobileServices authentication, application, User-Agent and telemetry headers
    options.headers = {};
    if (!_.isNull(headers)) {
        _.extend(options.headers, headers);
    }
    options.headers["X-ZUMO-INSTALLATION-ID"] = MobileServiceClient._applicationInstallationId;
    if (!_.isNullOrEmpty(this.applicationKey)) {
        options.headers["X-ZUMO-APPLICATION"] = this.applicationKey;
    }
    if (this.currentUser && !_.isNullOrEmpty(this.currentUser.mobileServiceAuthenticationToken)) {
        options.headers["X-ZUMO-AUTH"] = this.currentUser.mobileServiceAuthenticationToken;
    }
    if (!_.isNull(MobileServiceClient._userAgent)) {
        options.headers["User-Agent"] = MobileServiceClient._userAgent;
    }
    if (!_.isNullOrEmpty["X-ZUMO-VERSION"]) {
        options.headers["X-ZUMO-VERSION"] = this.version;
    }

    // Add any content as JSON
    if (!_.isNull(content)) {
        if (!_.isString(content)) {
            options.data = _.toJson(content);
        } else {
            options.data = content;
        }

        if(!_.hasProperty(options.headers, ['Content-Type','content-type','CONTENT-TYPE','Content-type'])) {
            options.headers['Content-Type'] = 'application/json';
        }
    } else {
        // options.data must be set to null if there is no content or the xhr object
        // will set the content-type to "application/text" for non-GET requests.
        options.data = null;
    }

    // Treat any >=400 status codes as errors.  Also treat the status code 0 as
    // an error (which indicates a connection failure).
    var handler = function (error, response) {
        if (!_.isNull(error)) {
            error = _.createError(error);
        } else if (!_.isNull(response) && (response.status >= 400 || response.status === 0)) {
            error = _.createError(null, response);
            response = null;
        }
        callback(error, response);
    };

    // Make the web request
    if (!_.isNull(this._serviceFilter) && !ignoreFilters) {
        this._serviceFilter(options, Platform.webRequest, handler);
    } else {
        Platform.webRequest(options, handler);
    }
};

MobileServiceClient.prototype.login = Platform.async(
    function (provider, token, useSingleSignOn, callback) {
        /// <summary>
        /// Log a user into a Mobile Services application given a provider name and optional
        /// authentication token.
        /// </summary>
        /// <param name="provider" type="String" mayBeNull="true">
        /// Name of the authentication provider to use; one of 'facebook', 'twitter', 'google',
        /// or 'microsoftaccount'. If no provider is specified, the 'token' parameter
        /// is considered a Microsoft Account authentication token. If a provider is specified,
        /// the 'token' parameter is considered a provider-specific authentication token.
        /// </param>
        /// <param name="token" type="Object" mayBeNull="true">
        /// Optional, provider specific object with existing OAuth token to log in with.
        /// </param>
        /// <param name="useSingleSignOn" type="Boolean" mayBeNull="true">
        /// Only applies to Windows 8 clients.  Will be ignored on other platforms.
        /// Indicates if single sign-on should be used. Single sign-on requires that the
        /// application's Package SID be registered with the Windows Azure Mobile Service,
        /// but it provides a better experience as HTTP cookies are supported so that users
        /// do not have to login in everytime the application is launched.
        /// </param>
        /// <param name="callback" type="Function" mayBeNull="true">
        /// Optional callback accepting (error, user) parameters.
        /// </param>
        this._login.login(provider, token, useSingleSignOn, callback);
    });

MobileServiceClient.prototype.logout = function () {
    /// <summary>
    /// Log a user out of a Mobile Services application.
    /// </summary>
    this.currentUser = null;
};

MobileServiceClient.prototype.invokeApi = Platform.async(
    function (apiName, options, callback) {
        /// <summary>
        /// Invokes the specified custom api and returns a response object.
        /// </summary>
        /// <param name="apiName">
        /// The custom api to invoke.
        /// </param>
        /// <param name="options" mayBeNull="true">
        /// Contains additional parameter information, valid values are:
        /// body: The body of the HTTP request.
        /// method: The HTTP method to use in the request, with the default being POST,
        /// parameters: Any additional query string parameters,
        /// headers: HTTP request headers, specified as an object.
        /// </param>
        /// <param name="callback" type="Function" mayBeNull="true">
        /// Optional callback accepting (error, results) parameters.
        /// </param>

        Validate.isString(apiName, 'apiName');

        // Account for absent optional arguments
        if (_.isNull(callback)) {
            if (typeof options === 'function') {
                callback = options;
                options = null;
            }
        }
        Validate.notNull(callback, 'callback');

        var parameters, method, body, headers;
        if (!_.isNull(options)) {
            parameters = options.parameters;
            if (!_.isNull(parameters)) {
                Validate.isValidParametersObject(options.parameters);
            }

            method = options.method;
            body = options.body;
            headers = options.headers;
        }
        if (_.isNull(method)) {
            method = "POST";
        }

        // Construct the URL
        var urlFragment = _.url.combinePathSegments("api", apiName);
        if (!_.isNull(parameters)) {
            var queryString = _.url.getQueryString(parameters);
            urlFragment = _.url.combinePathAndQuery(urlFragment, queryString);
        }

        // Make the request
        this._request(
            method,
            urlFragment,
            body,
            null,
            headers,
            function (error, response) {
                if (!_.isNull(error)) {
                    callback(error, null);
                } else {
                    if (response.getResponseHeader('Content-Type').toLowerCase().indexOf('json') != -1) {
                        response.result = _.fromJson(response.responseText);
                    }

                    callback(null, response);
                }
            });

    });

function getApplicationInstallationId() {
    /// <summary>
    /// Gets or creates the static application installation ID.
    /// </summary>
    /// <returns type="string">
    /// The application installation ID.
    /// </returns>

    // Get or create a new installation ID that can be passed along on each
    // request to provide telemetry data
    var applicationInstallationId = null;

    // Check if the config settings exist
    var path = "MobileServices.Installation.config";
    var contents = Platform.readSetting(path);
    if (!_.isNull(contents)) {
        // Parse the contents of the file as JSON and pull out the
        // application's installation ID.
        try {
            var config = _.fromJson(contents);
            applicationInstallationId = config.applicationInstallationId;
        } catch (ex) {
            // Ignore any failures (like invalid JSON, etc.) which will allow
            // us to fall through to and regenerate a valid config below
        }
    }

    // If no installation ID was found, generate a new one and save the config
    // settings.  This is pulled out as a separate function because we'll do it
    // even if we successfully read an existing config but there's no
    // installation ID.
    if (_.isNullOrEmpty(applicationInstallationId)) {
        applicationInstallationId = _.createUniqueInstallationId();

        // TODO: How many other settings should we write out as well?
        var configText = _.toJson({ applicationInstallationId: applicationInstallationId });
        Platform.writeSetting(path, configText);
    }

    return applicationInstallationId;
}

/// <summary>
/// Get or set the static _applicationInstallationId by checking the settings
/// and create the value if necessary.
/// </summary>
MobileServiceClient._applicationInstallationId = getApplicationInstallationId();

/// <summary>
/// Get or set the static _userAgent by calling into the Platform.
/// </summary>
MobileServiceClient._userAgent = Platform.getUserAgent();

<commit_msg>Add check for response getResponseHeader<commit_after>// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------

/// <reference path="C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0\ExtensionSDKs\Microsoft.WinJS.1.0\1.0\DesignTime\CommonConfiguration\Neutral\Microsoft.WinJS.1.0\js\base.js" />
/// <reference path="C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0\ExtensionSDKs\Microsoft.WinJS.1.0\1.0\DesignTime\CommonConfiguration\Neutral\Microsoft.WinJS.1.0\js\ui.js" />
/// <reference path="Generated\MobileServices.DevIntellisense.js" />

var _ = require('Extensions');
var Validate = require('Validate');
var Platform = require('Platform');
var MobileServiceTable = require('MobileServiceTable').MobileServiceTable;
var MobileServiceLogin = require('MobileServiceLogin').MobileServiceLogin;

function MobileServiceClient(applicationUrl, applicationKey) {
    /// <summary>
    /// Initializes a new instance of the MobileServiceClient class.
    /// </summary>
    /// <param name="applicationUrl" type="string" mayBeNull="false">
    /// The URL to the Mobile Services application.
    /// </param>
    /// <param name="applicationKey" type="string" mayBeNull="false">
    /// The Mobile Service application's key.
    /// </param>

    Validate.isString(applicationUrl, 'applicationUrl');
    Validate.notNullOrEmpty(applicationUrl, 'applicationUrl');
    Validate.isString(applicationKey, 'applicationKey');

    this.applicationUrl = applicationUrl;
    this.applicationKey = applicationKey || null;

    var sdkInfo = Platform.getSdkInfo();
    var osInfo = Platform.getOperatingSystemInfo();
    var sdkVersion = sdkInfo.fileVersion.split(".").slice(0, 2).join(".");
    this.version = "ZUMO/" + sdkVersion + " (lang=" + sdkInfo.language + "; " +
                                            "os=" + osInfo.name + "; " +
                                            "os_version=" + osInfo.version + "; " +
                                            "arch=" + osInfo.architecture + "; " +
                                            "version=" + sdkInfo.fileVersion + ")";
    this.currentUser = null;
    this._serviceFilter = null;
    this._login = new MobileServiceLogin(this);
    this.getTable = function (tableName) {
        /// <summary>
        /// Gets a reference to a table and its data operations.
        /// </summary>
        /// <param name="tableName">The name of the table.</param>
        /// <returns>A reference to the table.</returns>

        Validate.isString(tableName, 'tableName');
        Validate.notNullOrEmpty(tableName, 'tableName');
        return new MobileServiceTable(tableName, this);
    };
}

// Export the MobileServiceClient class
exports.MobileServiceClient = MobileServiceClient;

// Define the MobileServiceClient in a namespace (note: this has global effects
// unless the platform we're using chooses to ignore it because exports are
// good enough).
Platform.addToMobileServicesClientNamespace({ MobileServiceClient: MobileServiceClient });

MobileServiceClient.prototype.withFilter = function (serviceFilter) {
    /// <summary>
    /// Create a new MobileServiceClient with a filter used to process all
    /// of its HTTP requests and responses.
    /// </summary>
    /// <param name="serviceFilter" type="Function">
    /// The filter to use on the service.  The signature of a serviceFilter is
    ///    function(request, next, callback)
    ///  where
    ///    next := function(request, callback)
    ///    callback := function(error, response)
    /// </param>
    /// <returns type="MobileServiceClient">
    /// A new MobileServiceClient whose HTTP requests and responses will be
    /// filtered as desired.
    /// </returns>
    /// <remarks>
    /// The Mobile Services HTTP pipeline is a chain of filters composed
    /// together by giving each the next operation which it can invoke
    /// (zero, one, or many times as necessary).  The default continuation
    /// of a brand new MobileServiceClient will just get the HTTP response
    /// for the corresponding request.  Here's an example of a Handle
    /// implementation that will automatically retry a request that times
    /// out.
    ///     function(req, next, callback) {
    ///         next(req, function(err, rsp) {
    ///           if (rsp.statusCode >= 400) {
    ///               next(req, callback);
    ///           } else {
    ///               callback(err, rsp);
    ///           }
    ///         });
    ///     }
    /// Note that because these operations are asynchronous, this sample
    /// filter could end up actually making two HTTP requests before
    /// returning a response to the developer without the developer writing
    /// any special code to handle the situation.
    /// -
    /// Filters are composed just like standard function composition.  If
    /// we had new MobileServiceClient().withFilter(F1).withFilter(F2)
    /// .withFilter(F3), it's conceptually equivalent to saying:
    ///     var response = F3(F2(F1(next(request)));
    /// </remarks>

    Validate.notNull(serviceFilter, 'serviceFilter');

    // Clone the current instance
    var client = new MobileServiceClient(this.applicationUrl, this.applicationKey);
    client.currentUser = this.currentUser;

    // Chain the service filter with any existing filters
    var existingFilter = this._serviceFilter;
    client._serviceFilter = _.isNull(existingFilter) ?
        serviceFilter :
        function (req, next, callback) {
            // compose existingFilter with next so it can be used as the next
            // of the new serviceFilter
            var composed = function (req, callback) {
                existingFilter(req, next, callback);
            };
            serviceFilter(req, composed, callback);
        };

    return client;
};

MobileServiceClient.prototype._request = function (method, uriFragment, content, ignoreFilters, headers, callback) {
    /// <summary>
    /// Perform a web request and include the standard Mobile Services headers.
    /// </summary>
    /// <param name="method" type="string">
    /// The HTTP method used to request the resource.
    /// </param>
    /// <param name="uriFragment" type="String">
    /// URI of the resource to request (relative to the Mobile Services
    /// runtime).
    /// </param>
    /// <param name="content" type="Object">
    /// Optional content to send to the resource.
    /// </param>
    /// <param name="ignoreFilters" type="Boolean" mayBeNull="true">
    /// Optional parameter to indicate if the client filters should be ignored
    /// and the request should be sent directly. Is false by default.
    /// </param>
    /// <param name="headers" type="Object">
    /// Optional request headers
    /// </param>
    /// <param name="callback" type="function(error, response)">
    /// Handler that will be called on the response.
    /// </param>

    // Account for absent optional arguments
    if (_.isNull(callback) && (typeof headers === 'function')) {
        callback = headers;
        headers = null;
    }

    if (_.isNull(callback) && (typeof ignoreFilters === 'function')) {
        callback = ignoreFilters;
        ignoreFilters = false;
    }

    Validate.isString(method, 'method');
    Validate.notNullOrEmpty(method, 'method');
    Validate.isString(uriFragment, 'uriFragment');
    Validate.notNull(uriFragment, 'uriFragment');
    Validate.notNull(callback, 'callback');

    // Create the absolute URI
    var options = { type: method.toUpperCase() };
    options.url = _.url.combinePathSegments(this.applicationUrl, uriFragment);

    // Set MobileServices authentication, application, User-Agent and telemetry headers
    options.headers = {};
    if (!_.isNull(headers)) {
        _.extend(options.headers, headers);
    }
    options.headers["X-ZUMO-INSTALLATION-ID"] = MobileServiceClient._applicationInstallationId;
    if (!_.isNullOrEmpty(this.applicationKey)) {
        options.headers["X-ZUMO-APPLICATION"] = this.applicationKey;
    }
    if (this.currentUser && !_.isNullOrEmpty(this.currentUser.mobileServiceAuthenticationToken)) {
        options.headers["X-ZUMO-AUTH"] = this.currentUser.mobileServiceAuthenticationToken;
    }
    if (!_.isNull(MobileServiceClient._userAgent)) {
        options.headers["User-Agent"] = MobileServiceClient._userAgent;
    }
    if (!_.isNullOrEmpty["X-ZUMO-VERSION"]) {
        options.headers["X-ZUMO-VERSION"] = this.version;
    }

    // Add any content as JSON
    if (!_.isNull(content)) {
        if (!_.isString(content)) {
            options.data = _.toJson(content);
        } else {
            options.data = content;
        }

        if(!_.hasProperty(options.headers, ['Content-Type','content-type','CONTENT-TYPE','Content-type'])) {
            options.headers['Content-Type'] = 'application/json';
        }
    } else {
        // options.data must be set to null if there is no content or the xhr object
        // will set the content-type to "application/text" for non-GET requests.
        options.data = null;
    }

    // Treat any >=400 status codes as errors.  Also treat the status code 0 as
    // an error (which indicates a connection failure).
    var handler = function (error, response) {
        if (!_.isNull(error)) {
            error = _.createError(error);
        } else if (!_.isNull(response) && (response.status >= 400 || response.status === 0)) {
            error = _.createError(null, response);
            response = null;
        }
        callback(error, response);
    };

    // Make the web request
    if (!_.isNull(this._serviceFilter) && !ignoreFilters) {
        this._serviceFilter(options, Platform.webRequest, handler);
    } else {
        Platform.webRequest(options, handler);
    }
};

MobileServiceClient.prototype.login = Platform.async(
    function (provider, token, useSingleSignOn, callback) {
        /// <summary>
        /// Log a user into a Mobile Services application given a provider name and optional
        /// authentication token.
        /// </summary>
        /// <param name="provider" type="String" mayBeNull="true">
        /// Name of the authentication provider to use; one of 'facebook', 'twitter', 'google',
        /// or 'microsoftaccount'. If no provider is specified, the 'token' parameter
        /// is considered a Microsoft Account authentication token. If a provider is specified,
        /// the 'token' parameter is considered a provider-specific authentication token.
        /// </param>
        /// <param name="token" type="Object" mayBeNull="true">
        /// Optional, provider specific object with existing OAuth token to log in with.
        /// </param>
        /// <param name="useSingleSignOn" type="Boolean" mayBeNull="true">
        /// Only applies to Windows 8 clients.  Will be ignored on other platforms.
        /// Indicates if single sign-on should be used. Single sign-on requires that the
        /// application's Package SID be registered with the Windows Azure Mobile Service,
        /// but it provides a better experience as HTTP cookies are supported so that users
        /// do not have to login in everytime the application is launched.
        /// </param>
        /// <param name="callback" type="Function" mayBeNull="true">
        /// Optional callback accepting (error, user) parameters.
        /// </param>
        this._login.login(provider, token, useSingleSignOn, callback);
    });

MobileServiceClient.prototype.logout = function () {
    /// <summary>
    /// Log a user out of a Mobile Services application.
    /// </summary>
    this.currentUser = null;
};

MobileServiceClient.prototype.invokeApi = Platform.async(
    function (apiName, options, callback) {
        /// <summary>
        /// Invokes the specified custom api and returns a response object.
        /// </summary>
        /// <param name="apiName">
        /// The custom api to invoke.
        /// </param>
        /// <param name="options" mayBeNull="true">
        /// Contains additional parameter information, valid values are:
        /// body: The body of the HTTP request.
        /// method: The HTTP method to use in the request, with the default being POST,
        /// parameters: Any additional query string parameters,
        /// headers: HTTP request headers, specified as an object.
        /// </param>
        /// <param name="callback" type="Function" mayBeNull="true">
        /// Optional callback accepting (error, results) parameters.
        /// </param>

        Validate.isString(apiName, 'apiName');

        // Account for absent optional arguments
        if (_.isNull(callback)) {
            if (typeof options === 'function') {
                callback = options;
                options = null;
            }
        }
        Validate.notNull(callback, 'callback');

        var parameters, method, body, headers;
        if (!_.isNull(options)) {
            parameters = options.parameters;
            if (!_.isNull(parameters)) {
                Validate.isValidParametersObject(options.parameters);
            }

            method = options.method;
            body = options.body;
            headers = options.headers;
        }
        if (_.isNull(method)) {
            method = "POST";
        }

        // Construct the URL
        var urlFragment = _.url.combinePathSegments("api", apiName);
        if (!_.isNull(parameters)) {
            var queryString = _.url.getQueryString(parameters);
            urlFragment = _.url.combinePathAndQuery(urlFragment, queryString);
        }

        // Make the request
        this._request(
            method,
            urlFragment,
            body,
            null,
            headers,
            function (error, response) {
                if (!_.isNull(error)) {
                    callback(error, null);
                } else {
                    if (typeof response.getResponseHeader === 'undefined') { // (when using IframeTransport, IE9)
                        try {
                            response.result = _.fromJson(response.responseText);
                        } catch(e) {
                            // Do nothing, since we don't know the content-type, failing may be ok
                        }
                    } else if (response.getResponseHeader('Content-Type').toLowerCase().indexOf('json') !== -1) {
                        response.result = _.fromJson(response.responseText);
                    }

                    callback(null, response);
                }
            });

    });

function getApplicationInstallationId() {
    /// <summary>
    /// Gets or creates the static application installation ID.
    /// </summary>
    /// <returns type="string">
    /// The application installation ID.
    /// </returns>

    // Get or create a new installation ID that can be passed along on each
    // request to provide telemetry data
    var applicationInstallationId = null;

    // Check if the config settings exist
    var path = "MobileServices.Installation.config";
    var contents = Platform.readSetting(path);
    if (!_.isNull(contents)) {
        // Parse the contents of the file as JSON and pull out the
        // application's installation ID.
        try {
            var config = _.fromJson(contents);
            applicationInstallationId = config.applicationInstallationId;
        } catch (ex) {
            // Ignore any failures (like invalid JSON, etc.) which will allow
            // us to fall through to and regenerate a valid config below
        }
    }

    // If no installation ID was found, generate a new one and save the config
    // settings.  This is pulled out as a separate function because we'll do it
    // even if we successfully read an existing config but there's no
    // installation ID.
    if (_.isNullOrEmpty(applicationInstallationId)) {
        applicationInstallationId = _.createUniqueInstallationId();

        // TODO: How many other settings should we write out as well?
        var configText = _.toJson({ applicationInstallationId: applicationInstallationId });
        Platform.writeSetting(path, configText);
    }

    return applicationInstallationId;
}

/// <summary>
/// Get or set the static _applicationInstallationId by checking the settings
/// and create the value if necessary.
/// </summary>
MobileServiceClient._applicationInstallationId = getApplicationInstallationId();

/// <summary>
/// Get or set the static _userAgent by calling into the Platform.
/// </summary>
MobileServiceClient._userAgent = Platform.getUserAgent();

<|endoftext|>


<commit_before>var find = require('findit');
var finder = find(process.cwd());
var rimraf = require('rimraf');
const exec = require('child_process').execSync;
var currentdirectory = process.cwd();
var packagesToInstall = [];
var path = require('path');

console.log("==NPM settings:==");
console.log(exec('npm config ls -l'));
exec('npm config ls -l')
finder.on('file', function (file, stat) {
  if (file.indexOf('package.json') > -1) {
    console.log(file + ' |||| ' + process.cwd());
    if (path.dirname(file) == process.cwd()) {
      console.log('ignoring: ' + file);
      return;
    }
    console.log('Execute npm install on ' + file);
    packagesToInstall.push(file.substring(0, file.lastIndexOf('/')));
  }
});
finder.on('directory', function (dir, stat, stop) {
  if (dir.indexOf('bower_components') > -1) {
    console.log('Ingnoring ' + dir);
    stop();
  }
  if (dir.indexOf('node_modules') > -1) {
    console.log('Ingnoring ' + dir);
    stop();
  }
  if (dir.indexOf('.git') > -1) {
    console.log('Ingnoring ' + dir);
    stop();
  }
  currentdirectory = dir;
});
finder.on('end', function () {
  installPackages(0, packagesToInstall);
});
var installPackages = function (index, array) {
  var dir = array[index];
  console.log('======== cleaning =======');
  console.log(dir + '/node_modules');
  rimraf(dir + '/node_modules', function () {
    console.log('======== installing =======');
    console.log(dir);
    exec('npm install', { cwd: dir });
    index++;
    if (index < array.length) {
      installPackages(index, array);
    }
  });
};
<commit_msg>Update npm_install_all.js<commit_after>var find = require('findit');
var finder = find(process.cwd());
var rimraf = require('rimraf');
const exec = require('child_process').execSync;
var currentdirectory = process.cwd();
var packagesToInstall = [];
var path = require('path');

//Fix the issue that npm overwrites the env settings with its current settings after processing the oroginal env settings, but
//it replaces false with "" so that down stream npm calls then treat "" as true :-(
process.env["npm_config_shrinkwrap"]=process.env["npm_config_shrinkwrap"]==true?"true":"false";
process.env["npm_config_unsafe_perm"]=process.env["npm_config_unsafe_perm"]==true?"true":"false";

console.log("==ENV settings:==");
console.dir(process.env);
console.log("==NPM settings:==");
var result = exec('npm config ls -l',{encoding:'utf8'});
console.log(result);

finder.on('file', function (file, stat) {
  if (file.indexOf('package.json') > -1) {
    console.log(file + ' |||| ' + process.cwd());
    if (path.dirname(file) == process.cwd()) {
      console.log('ignoring: ' + file);
      return;
    }
    console.log('Execute npm install on ' + file);
    packagesToInstall.push(file.substring(0, file.lastIndexOf('/')));
  }
});
finder.on('directory', function (dir, stat, stop) {
  if (dir.indexOf('bower_components') > -1) {
    console.log('Ingnoring ' + dir);
    stop();
  }
  if (dir.indexOf('node_modules') > -1) {
    console.log('Ingnoring ' + dir);
    stop();
  }
  if (dir.indexOf('.git') > -1) {
    console.log('Ingnoring ' + dir);
    stop();
  }
  currentdirectory = dir;
});
finder.on('end', function () {
  installPackages(0, packagesToInstall);
});
var installPackages = function (index, array) {
  var dir = array[index];
  console.log('======== cleaning =======');
  console.log(dir + '/node_modules');
  rimraf(dir + '/node_modules', function () {
    console.log('======== installing =======');
    console.log(dir);
    exec('npm install', { cwd: dir });
    index++;
    if (index < array.length) {
      installPackages(index, array);
    }
  });
};
<|endoftext|>


<commit_before>Package.describe({
  summary: "Facebook OAuth flow",
  version: "1.7.2"
});

Package.onUse(api => {
  api.versionsFrom('1.11.1');

  api.use('ecmascript', ['client', 'server']);
  api.use('oauth2', ['client', 'server']);
  api.use('oauth', ['client', 'server']);
  api.use('http', ['server']);
  api.use('random', 'client');
  api.use('service-configuration', ['client', 'server']);

  api.addFiles('facebook_client.js', 'client');
  api.addFiles('facebook_server.js', 'server');

  api.export('Facebook');
});
<commit_msg>Allows developers to override the ROOT_URL in the redirect URL<commit_after>Package.describe({
  summary: "Facebook OAuth flow",
  version: "1.7.2"
});

Package.onUse(api => {
  api.use('ecmascript', ['client', 'server']);
  api.use('oauth2', ['client', 'server']);
  api.use('oauth', ['client', 'server']);
  api.use('http', ['server']);
  api.use('random', 'client');
  api.use('service-configuration', ['client', 'server']);

  api.addFiles('facebook_client.js', 'client');
  api.addFiles('facebook_server.js', 'server');

  api.export('Facebook');
});
<|endoftext|>


<commit_before>var hbs = require('handlebars')
var fs = require('fs')
var Github = require('github-api')

module.exports = function(callback) {

  fs.readFile( process.env['CONTRIBUTORS'], function (err, data) {
    if (err) return callback(err, "Error reading contribs file for building page.")

    var everyone = JSON.parse(data)
    var newest = everyone[everyone.length - 1]

    var stats = {featured: newest, everyone: everyone}
    return getTemplate(stats, everyone)
  })

  function getTemplate(stats, everyone) {
    fs.readFile('template.hbs', function (err, data) {
      if (err) return callback(err, "Error reading template file.")

      data = data.toString()
      var template = hbs.compile(data)
      var HTML = template(stats)
      return writeRepo(HTML, stats, everyone)
    })
  }

  function writeRepo(HTML, stats, everyone) {
    var github = new Github({
      auth: "oauth",
      token: process.env['REPOROBOT_TOKEN']
    })

    var repo = github.getRepo('jlord', 'patchwork')
    var username = stats.featured.username
    var commitMes = "rebuilt with @" + username + " added\!"

    repo.write('gh-pages', 'index.html', HTML, commitMes, function(err) {
      if (err) return callback(err, "Error writing new index to Patchwork.")
      console.log([new Date(), "Rebuilt index with" + username])

      repo.write('gh-pages', 'contributors.json', JSON.stringify(everyone, null, " ") , "Added @" + username, function(err) {
        if (err) return callback(err, "Error writing contribs backup to Patchwork.")
        console.log([new Date(), "Wrote contributors backup with " + username])
        return callback(null, "Done!")
      })
    })
  }
}<commit_msg>reverse sort<commit_after>var hbs = require('handlebars')
var fs = require('fs')
var Github = require('github-api')

module.exports = function(callback) {

  fs.readFile( process.env['CONTRIBUTORS'], function (err, data) {
    if (err) return callback(err, "Error reading contribs file for building page.")

    var everyone = JSON.parse(data)
    var newest = everyone[everyone.length - 1]

    var stats = {featured: newest, everyone: everyone.reverse()}
    return getTemplate(stats, everyone)
  })

  function getTemplate(stats, everyone) {
    fs.readFile('template.hbs', function (err, data) {
      if (err) return callback(err, "Error reading template file.")

      data = data.toString()
      var template = hbs.compile(data)
      var HTML = template(stats)
      return writeRepo(HTML, stats, everyone)
    })
  }

  function writeRepo(HTML, stats, everyone) {
    var github = new Github({
      auth: "oauth",
      token: process.env['REPOROBOT_TOKEN']
    })

    var repo = github.getRepo('jlord', 'patchwork')
    var username = stats.featured.username
    var commitMes = "rebuilt with @" + username + " added\!"

    repo.write('gh-pages', 'index.html', HTML, commitMes, function(err) {
      if (err) return callback(err, "Error writing new index to Patchwork.")
      console.log([new Date(), "Rebuilt index with" + username])

      repo.write('gh-pages', 'contributors.json', JSON.stringify(everyone, null, " ") , "Added @" + username, function(err) {
        if (err) return callback(err, "Error writing contribs backup to Patchwork.")
        console.log([new Date(), "Wrote contributors backup with " + username])
        return callback(null, "Done!")
      })
    })
  }
}<|endoftext|>


<commit_before>Template._stats.helpers({
  statistics: function(){
    var user = Session.get('userObject'),
        completedBets = Bets.find({ status: 'completed' }).count(),
        wins = Bets.find({ winner: user }).count(),
        var points = Points.findOne({ wonBy: user });
        losses = completedBets - wins;

    return [wins, losses]
  }
});
<commit_msg>Resolve error in code.<commit_after>Template._stats.helpers({
  statistics: function(){
    var user = Session.get('userObject'),
        completedBets = Bets.find({ status: 'completed' }).count(),
        wins = Bets.find({ winner: user }).count(),
        points = Points.findOne({ wonBy: user }),
        losses = completedBets - wins;

    return [wins, losses]
  }
});
<|endoftext|>


<commit_before>extraInfo = {
  'bootstrap-datepicker': 'To use the bootstrap-datepicker input type, add the aldeed:autoform-bs-datepicker package to your app. You must also add the bootstrap-datepicker library javascript in your /client/lib folder or add the rajit:bootstrap3-datepicker Meteor package to your app. And of course you must be using Bootstrap 3. See the full documentation here.',
  'bootstrap-datetimepicker': 'To use the bootstrap-datetimepicker input type, add the aldeed:autoform-bs-datetimepicker package to your app. You must also add the bootstrap-datetimepicker library javascript in your /client/lib folder or add the tsega:bootstrap3-datetimepicker Meteor package to your app. And of course you must be using Bootstrap 3. See the full documentation here.',
  'select2': 'To use the select2 input type, add the aldeed:autoform-select2 package to your app. You must also add the select2 library javascript in your /client/lib folder or add the natestrauser:select2 Meteor package to your app. See the full documentation here.',
  'selectize': 'To use the selectize input type, add the comerc:autoform-selectize package to your app. You must also add the selectize library javascript in your /client/lib folder or add the jeremy:selectize Meteor package to your app. See the full documentation here.',
  'typeahead': 'To use the typeahead input type, add the comerc:autoform-typeahead package to your app. You must also add the typeahead library javascript in your /client/lib folder or add the comerc:bs-typeahead Meteor package to your app. See the full documentation here.',
};
<commit_msg>support selectize for bootstrap-3<commit_after>extraInfo = {
  'bootstrap-datepicker': 'To use the bootstrap-datepicker input type, add the aldeed:autoform-bs-datepicker package to your app. You must also add the bootstrap-datepicker library javascript in your /client/lib folder or add the rajit:bootstrap3-datepicker Meteor package to your app. And of course you must be using Bootstrap 3. See the full documentation here.',
  'bootstrap-datetimepicker': 'To use the bootstrap-datetimepicker input type, add the aldeed:autoform-bs-datetimepicker package to your app. You must also add the bootstrap-datetimepicker library javascript in your /client/lib folder or add the tsega:bootstrap3-datetimepicker Meteor package to your app. And of course you must be using Bootstrap 3. See the full documentation here.',
  'select2': 'To use the select2 input type, add the aldeed:autoform-select2 package to your app. You must also add the select2 library javascript in your /client/lib folder or add the natestrauser:select2 Meteor package to your app. See the full documentation here.',
  'selectize': 'To use the selectize input type, add the comerc:autoform-selectize package to your app. You must also add the selectize library javascript in your /client/lib folder or add the chhib:selectize-bootstrap-3 Meteor package to your app. See the full documentation here.',
  'typeahead': 'To use the typeahead input type, add the comerc:autoform-typeahead package to your app. You must also add the typeahead library javascript in your /client/lib folder or add the comerc:bs-typeahead Meteor package to your app. See the full documentation here.',
};
<|endoftext|>


<commit_before>// Globally defined
var url = "";

// wait for the DOM to be loaded
$(document).ready(function() {
    $("#Connect").click(function() {
	$.ajax({url        : "/scripts/db_connect.pl",
		type       : "post",
		data       : "url=" + $("#db_url").val(),
		dataType   : "json",
		beforeSend : onSend_dbconnect,
		success    : onSuccess
	       });
    });

});

// res is the JSON-encoded response from the server in the Ajax call
function onSuccess(res) {
    $("#connexion_msg").html(res.status);
    $("#pipeline_diagram").html(res.analyses);
    url = $("#db_url").val();
    $(".analysis_link").click(function() {
	$.ajax({url        : "/scripts/db_fetch_analyis.pl",
//		beforeSend : onSend,
		type       : "post",
		dataType   : "json",
		data       : "url=" + url + "&logic_name=" + this.id,
		success    : function(resp) {
		    if (resp.status == "ok") {
			$("#analysis_details").html(resp.analysis_info);
		    } else {
			$("#connexion_msg").html(resp.status);
		    }
		}
	       });
    });
}

function onSend_dbconnect() {
//    $('#connexion_msg').html('');
    $('#connexion_msg').html('');
}

function onSend(req, settings) {
    alert(JSON.stringify(this));
}<commit_msg>Fixed typo in script name<commit_after>// Globally defined
var url = "";

// wait for the DOM to be loaded
$(document).ready(function() {
    $("#Connect").click(function() {
	$.ajax({url        : "/scripts/db_connect.pl",
		type       : "post",
		data       : "url=" + $("#db_url").val(),
		dataType   : "json",
		beforeSend : onSend_dbconnect,
		success    : onSuccess
	       });
    });

});

// res is the JSON-encoded response from the server in the Ajax call
function onSuccess(res) {
    $("#connexion_msg").html(res.status);
    $("#pipeline_diagram").html(res.analyses);
    url = $("#db_url").val();
    $(".analysis_link").click(function() {
	$.ajax({url        : "/scripts/db_fetch_analysis.pl",
//		beforeSend : onSend,
		type       : "post",
		dataType   : "json",
		data       : "url=" + url + "&logic_name=" + this.id,
		success    : function(resp) {
		    if (resp.status == "ok") {
			$("#analysis_details").html(resp.analysis_info);
		    } else {
			$("#connexion_msg").html(resp.status);
		    }
		}
	       });
    });
}

function onSend_dbconnect() {
//    $('#connexion_msg').html('');
    $('#connexion_msg').html('');
}

function onSend(req, settings) {
    alert(JSON.stringify(this));
}<|endoftext|>


<commit_before>const aws = require('aws-sdk');
const connect = new aws.Connect();

let params = {
        InstanceId: "1e8f045a-d7f1-4405-96c1-66701c25fd32",
        EndTime: 1571184000,
        StartTime:1571153400,
        Filters:{
            Queues:["943031b0-62ce-49a7-8688-9e84accd94fc"],
            Channels:["VOICE"]
        },
        HistoricalMetrics : [
      {
         "Name" : "AFTER_CONTACT_WORK_TIME",
         "Unit" : "SECONDS",
         "Statistic" : "AVG"
      },
      {
         "Name" : "CONTACTS_QUEUED",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "CONTACTS_HANDLED",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "HANDLE_TIME",
         "Unit" : "SECONDS",
         "Statistic" : "AVG"
      },
      {
         "Name" : "CONTACTS_TRANSFERRED_OUT",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "CONTACTS_MISSED",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "OCCUPANCY",
         "Unit" : "PERCENT",
         "Statistic" : "AVG"
      },
      {
         "Name" : "QUEUED_TIME",
         "Unit" : "SECONDS",
         "Statistic" : "MAX"
      },
      {
         "Name" : "HOLD_TIME",
         "Unit" : "SECONDS",
         "Statistic" : "AVG"
      },
      {
         "Name" : "SERVICE_LEVEL",
         "Threshold" : {
            "Comparison" : "LT",
            "ThresholdValue" : 60.0
         },
         "Unit" : "PERCENT",
         "Statistic" : "AVG"
      },
      {
         "Name" : "SERVICE_LEVEL",
         "Threshold" : {
            "Comparison" : "LT",
            "ThresholdValue" : 120.0
         },
         "Unit" : "PERCENT",
         "Statistic" : "AVG"
      },
      {
         "Name" : "SERVICE_LEVEL",
         "Threshold" : {
            "Comparison" : "LT",
            "ThresholdValue" : 30.0
         },
         "Unit" : "PERCENT",
         "Statistic" : "AVG"
      },
      {
         "Name" : "CONTACTS_ABANDONED",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "CONTACTS_CONSULTED",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "CONTACTS_AGENT_HUNG_UP_FIRST",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "CONTACTS_HANDLED_INCOMING",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "CONTACTS_HANDLED_OUTBOUND",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "CONTACTS_HOLD_ABANDONS",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "CONTACTS_TRANSFERRED_IN",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "CONTACTS_TRANSFERRED_IN_FROM_QUEUE",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "CONTACTS_TRANSFERRED_OUT_FROM_QUEUE",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "CALLBACK_CONTACTS_HANDLED",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "API_CONTACTS_HANDLED",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "ABANDON_TIME",
         "Unit" : "SECONDS",
         "Statistic" : "AVG"
      },
      {
         "Name" : "QUEUE_ANSWER_TIME",
         "Unit" : "SECONDS",
         "Statistic" : "AVG"
      },
      {
         "Name" : "INTERACTION_TIME",
         "Unit" : "SECONDS",
         "Statistic" : "AVG"
      },
      {
         "Name" : "INTERACTION_AND_HOLD_TIME",
         "Unit" : "SECONDS",
         "Statistic" : "AVG"
      }
   ]
    };

exports.handler = async (event) => {

    let result = await connect.getMetricData(params, function(err, data) {
        if (err){
                 console.log(err, err.stack);
        }
        else{
             console.log(data);
        }
    }).promise();

    var metrics = result["MetricResults"]
        console.log(metrics[0].Collections);
};
<commit_msg>Add code comments<commit_after>const aws = require('aws-sdk');
const connect = new aws.Connect();

let params = {
        InstanceId: "Provide your connect instance id",
        EndTime: 1571184000,	//enter a new end time
        StartTime:1571153400,	//enter a new start time
        Filters:{
            Queues:["Provide your connect instance queue id"],
            Channels:["VOICE"]
        },
        HistoricalMetrics : [
      {
         "Name" : "AFTER_CONTACT_WORK_TIME",
         "Unit" : "SECONDS",
         "Statistic" : "AVG"
      },
      {
         "Name" : "CONTACTS_QUEUED",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "CONTACTS_HANDLED",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "HANDLE_TIME",
         "Unit" : "SECONDS",
         "Statistic" : "AVG"
      },
      {
         "Name" : "CONTACTS_TRANSFERRED_OUT",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "CONTACTS_MISSED",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "OCCUPANCY",
         "Unit" : "PERCENT",
         "Statistic" : "AVG"
      },
      {
         "Name" : "QUEUED_TIME",
         "Unit" : "SECONDS",
         "Statistic" : "MAX"
      },
      {
         "Name" : "HOLD_TIME",
         "Unit" : "SECONDS",
         "Statistic" : "AVG"
      },
      {
         "Name" : "SERVICE_LEVEL",
         "Threshold" : {
            "Comparison" : "LT",
            "ThresholdValue" : 60.0
         },
         "Unit" : "PERCENT",
         "Statistic" : "AVG"
      },
      {
         "Name" : "SERVICE_LEVEL",
         "Threshold" : {
            "Comparison" : "LT",
            "ThresholdValue" : 120.0
         },
         "Unit" : "PERCENT",
         "Statistic" : "AVG"
      },
      {
         "Name" : "SERVICE_LEVEL",
         "Threshold" : {
            "Comparison" : "LT",
            "ThresholdValue" : 30.0
         },
         "Unit" : "PERCENT",
         "Statistic" : "AVG"
      },
      {
         "Name" : "CONTACTS_ABANDONED",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "CONTACTS_CONSULTED",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "CONTACTS_AGENT_HUNG_UP_FIRST",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "CONTACTS_HANDLED_INCOMING",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "CONTACTS_HANDLED_OUTBOUND",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "CONTACTS_HOLD_ABANDONS",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "CONTACTS_TRANSFERRED_IN",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "CONTACTS_TRANSFERRED_IN_FROM_QUEUE",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "CONTACTS_TRANSFERRED_OUT_FROM_QUEUE",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "CALLBACK_CONTACTS_HANDLED",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "API_CONTACTS_HANDLED",
         "Unit" : "COUNT",
         "Statistic" : "SUM"
      },
      {
         "Name" : "ABANDON_TIME",
         "Unit" : "SECONDS",
         "Statistic" : "AVG"
      },
      {
         "Name" : "QUEUE_ANSWER_TIME",
         "Unit" : "SECONDS",
         "Statistic" : "AVG"
      },
      {
         "Name" : "INTERACTION_TIME",
         "Unit" : "SECONDS",
         "Statistic" : "AVG"
      },
      {
         "Name" : "INTERACTION_AND_HOLD_TIME",
         "Unit" : "SECONDS",
         "Statistic" : "AVG"
      }
   ]
    };

exports.handler = async (event) => {

    let result = await connect.getMetricData(params, function(err, data) {
        if (err){
                 console.log(err, err.stack);
        }
        else{
             console.log(data);
        }
    }).promise();

    var metrics = result["MetricResults"]
        console.log(metrics[0].Collections);
};
<|endoftext|>


<commit_before>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You 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.
 */

var path = require('path');
var fs = require('fs');

var sprintf = require('extern/sprintf').sprintf;

var misc = require('util/misc');
var constants = require('manifest/constants');

var validate_manifest = function(manifest_path, callback) {
  path.exists(manifest_path, function(exists) {
    if (!exists) {
      return callback('Invalid path to the manifest file');
    }

    var read_stream = fs.createReadStream(manifest_path);
    var data_buffer = [];

    read_stream.on('data', function(chunk) {
      data_buffer.push(chunk);
    });

    read_stream.on('end', function() {
      var data = data_buffer.join('');

      try {
        var manifest_object = JSON.parse(data);
      }
      catch (error) {
        return callback(new Error('Manifest file contains invalid JSON'));
      }

      var required_fields = [];
      var optional_fields = [];
      var manifest_fields = [];

      var field;

      for (field in manifest_object) {
        manifest_fields.push(field);
      }

      for (field in constants.COMMON_FIELDS) {
        if (constants.COMMON_FIELDS[field].required) {
          required_fields.push(field);
        }
        else {
          optional_fields.push(field);
        }
      }

      var application_type = manifest_object.type;
      for (field in constants.APPLICATION_FIELDS[application_type]) {
        if (constants.APPLICATION_FIELDS[application_type][field].required) {
          required_fields.push(field);
        }
        else {
          optional_fields.push(field);
        }
      }

      var all_fields = required_fields.concat(optional_fields);
      var missing_required_fields = misc.array_difference(required_fields, manifest_fields);

      // Check that the manifest contains all the required fields
      if (missing_required_fields.length > 0) {
        return callback(new Error(sprintf('Manifest file is missing required fields: %s', missing_required_fields.join(', '))));
      }

      // Check that the manifest contains valid optional fields (if any)
      if (!misc.array_is_subset_of(manifest_fields, all_fields)) {
        var invalid_fields = misc.array_difference(manifest_fields, all_fields);

        return callback(new Error(sprintf('Manifest contains invalid fields: %s', invalid_fields)));
      }

    });
  });
};

exports.validate_manifest = validate_manifest;
<commit_msg>Add validator for manifest files<commit_after>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You 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.
 */

var path = require('path');
var fs = require('fs');

var async = require('extern/async');
var sprintf = require('extern/sprintf').sprintf;

var misc = require('util/misc');
var constants = require('manifest/constants');
var validators = require('manifest/validators');

/**
 * Custom error class containing information about a invalid field
 *
 * @param {String} field Field name
 * @param {String} message Field error message
 *
 * @constructor
 */
function InvalidFieldError(field, message) {
  this.name = 'InvalidFieldError';
  this.field = field;
  this.field_message = message;
  this.message = sprintf('Field %s is not valid (%s)', this.field, this.field_message);
};

/**
 * Validate that the manifest file is valid.
 *
 * @param {String} manifest_path Absolute path to the manifest file.
 * @param {Function} callback Callback which is called with the error as the first argument if the validation fails,
 *                            without argument otherwise.
 */
var validate_manifest = function(manifest_path, callback) {
  path.exists(manifest_path, function(exists) {
    if (!exists) {
      return callback('Invalid path to the manifest file');
    }

    var read_stream = fs.createReadStream(manifest_path);
    var data_buffer = [];

    read_stream.on('data', function(chunk) {
      data_buffer.push(chunk);
    });

    read_stream.on('end', function() {
      var data = data_buffer.join('');

      try {
        var manifest_object = JSON.parse(data);
      }
      catch (error) {
        return callback(new Error('Manifest file contains invalid JSON'));
      }

      var required_fields = [];
      var optional_fields = [];
      var manifest_fields = [];

      var field;

      for (field in manifest_object) {
        manifest_fields.push(field);
      }

      for (field in constants.COMMON_FIELDS) {
        if (constants.COMMON_FIELDS[field].required) {
          required_fields.push(field);
        }
        else {
          optional_fields.push(field);
        }
      }

      var application_type = manifest_object.type;
      for (field in constants.APPLICATION_FIELDS[application_type]) {
        if (constants.APPLICATION_FIELDS[application_type][field].required) {
          required_fields.push(field);
        }
        else {
          optional_fields.push(field);
        }
      }

      var all_fields = required_fields.concat(optional_fields);
      var missing_required_fields = misc.array_difference(required_fields, manifest_fields);

      // Check that the manifest contains all the required fields
      if (missing_required_fields.length > 0) {
        return callback(new Error(sprintf('Manifest file is missing required fields: %s', missing_required_fields.join(', '))));
      }

      // Check that the manifest contains valid optional fields (if any)
      if (!misc.array_is_subset_of(manifest_fields, all_fields)) {
        var invalid_fields = misc.array_difference(manifest_fields, all_fields);

        return callback(new Error(sprintf('Manifest contains invalid fields: %s', invalid_fields)));
      }

      // Field validation
      var type, validator;
      var all_fields_object = misc.merge(constants.COMMON_FIELDS, constants.APPLICATION_FIELDS[application_type]);

      // Currently the options object which is passed to each validator function only holds information about
      // the absolute path to the directory where the manifest file is located.
      var options = { 'manifest_path': path.dirname(manifest_path) };

      async.forEach(manifest_fields, function(field, callback) {
        type = all_fields_object[field].type;
        validator = all_fields_object[field].validator;

        if (validator) {
          // Field has a custom validator specified, use this one
          validator_name = validator;
        }
        else {
          // Field has no validator specified, use a generic type validator
          if (type === 'string') {
            validator_name = 'valid_string';
          }
          else if (type === 'number') {
            validator_name = 'valid_number';
          }
        }

        // Validate the field
        if (type === 'array') {
          validators.validate_array(manifest_object[field], validator_name, options, function(error) {
            if (error) {
              return callback(new InvalidFieldError(field, error.message));
            }

            callback();
          });
        }
        else {
          validators.validate_value(manifest_object[field], validator_name, options, function(error) {
            if (error) {
              return callback(new InvalidFieldError(field, error.message));
            }

            callback();
          });
        }
      },

      function(error) {
        if (error) {
          return callback(error);
        }

        // If we came so far, we have a valid manifest file
        callback();
      });
    });
  });
};

exports.validate_manifest = validate_manifest;
<|endoftext|>