<commit_before>/**
 * WinJS OAuth for Twitter v1.1
 * https://github.com/cauld/twitter-oauth-for-winjs
 * Copyright Manifold 2012. All rights reserved.
 * Apache License, Version 2.0
 */

/*global Windows: false, WinJS: false, XMLHttpRequest: false */
/*jslint nomen: true, plusplus: true, sloppy: true, white: true */

var TwitterOAuth = WinJS.Class.define(
    //Constructor
    function (consumerKey, consumerSecret, accessToken, accessTokenSecret, callbackUrl) {
        this._consumerKey = consumerKey;
        this._consumerSecret = consumerSecret;

        //If we already have accessToken then doTwitterWebAuth can be avoided
        this._accessToken = accessToken || null;
        this._accessTokenSecret = accessTokenSecret || null;

        //Define the OAuth callback url, not normally important for desktop apps
        this._callbackURL = callbackUrl || 'http://localhost/auth/twitter/callback';
    },
    //instanceMembers
    {
        _authorizeURL: 'https://api.twitter.com/oauth/authorize',
        _requestTokenURL: 'https://api.twitter.com/oauth/request_token',
        _accessTokenURL: 'https://api.twitter.com/oauth/access_token',

        //Signs internal requests used during the process of access token retrieval
        _sendAuthorizedRequest: function (url, method, headerParams, callback) {
            var authzHeader = this._getOAuthRequestHeaders(headerParams);

            this._xhrRequest(method, url, authzHeader, function (result) {
                callback(result);
            });
        },

        _xhrRequest: function (method, url, authzHeader, callback) {
            try {
                var request = new XMLHttpRequest();
                request.open(method, url, true);
                request.onreadystatechange = function () {
                    if (request.readyState === 4) {
                        if (request.status === 200) {
                            callback(request.responseText);
                        } else {
                            callback(false);
                        }
                    }
                };
                request.setRequestHeader("Authorization", authzHeader);
                request.send();
            } catch (err) {
                //console.log("Error sending request: " + err);
                callback(false);
            }
        },

        //Generate an OAuth 1.0a HMAC-SHA1 signature for an HTTP request
        _generateHmacSha1Signature: function (sigBaseString, keyText) {
            var keyMaterial,
                macAlgorithmProvider,
                tbs,
                key,
                signatureBuffer,
                signature;

            keyMaterial = Windows.Security.Cryptography.CryptographicBuffer.convertStringToBinary(keyText, Windows.Security.Cryptography.BinaryStringEncoding.Utf8);
            macAlgorithmProvider = Windows.Security.Cryptography.Core.MacAlgorithmProvider.openAlgorithm("HMAC_SHA1");
            key = macAlgorithmProvider.createKey(keyMaterial);
            tbs = Windows.Security.Cryptography.CryptographicBuffer.convertStringToBinary(sigBaseString, Windows.Security.Cryptography.BinaryStringEncoding.Utf8);
            signatureBuffer = Windows.Security.Cryptography.Core.CryptographicEngine.sign(key, tbs);
            signature = Windows.Security.Cryptography.CryptographicBuffer.encodeToBase64String(signatureBuffer);

            return signature;
        },

        _getSortedKeys: function (obj) {
            var key,
                keys = [];

            for (key in obj) {
                if (obj.hasOwnProperty(key)) {
                    keys[keys.length] = key;
                }
            }

            return keys.sort();
        },

        /**
         * Assembles proper headers based on a series of provided tokens, secrets, and signatures
         * References:
         * https://dev.twitter.com/docs/auth/authorizing-request
         * https://dev.twitter.com/docs/auth/creating-signature
         * Debug oauth signing errors here - https://dev.twitter.com/apps/3400014/oauth
         */
        _getOAuthRequestHeaders: function (headerParams) {
            var i,
                k,
                kv,
                sortedKeys,
                sigParams,
                sigBaseString,
                sigBaseStringParams = '',
                queryParamsKey,
                keyText,
                signature,
                headers,
                timestamp = Math.round(new Date().getTime() / 1000.0),
                nonce = Math.random();

            // Acquiring a request token
            nonce = Math.floor(nonce * 1000000000);

            sigParams = {
                oauth_callback: !headerParams.oauthTokenSecret ? encodeURIComponent(this._callbackURL) : "",
                oauth_consumer_key: headerParams.consumerKey,
                oauth_nonce: nonce,
                oauth_signature_method: 'HMAC-SHA1',
                oauth_timestamp: timestamp,
                oauth_token: headerParams.oauthToken || "",
                oauth_verifier: headerParams.oauthVerifier || "",
                oauth_version: '1.0'
            };

            //We need to combine the oauth params with any query params
            if (headerParams.queryParams) {
                for (queryParamsKey in headerParams.queryParams) {
                    if (headerParams.queryParams.hasOwnProperty(queryParamsKey)) {
                        sigParams[queryParamsKey] = headerParams.queryParams[queryParamsKey];
                    }
                }
            }

            // Compute base signature string and sign it.
            // This is a common operation that is required for all requests even after the token is obtained.
            // Parameters need to be sorted in alphabetical order
            // Keys and values should be URL Encoded.
            sortedKeys = this._getSortedKeys(sigParams);
            for (i = 0; i < sortedKeys.length; i++) {
                k = sortedKeys[i];
                kv = sigParams[sortedKeys[i]];
                if (kv && kv !== '') {
                    if (sigBaseStringParams !== '') {
                        sigBaseStringParams += '&';
                    }
                    sigBaseStringParams += k + '=' + kv;
                }
            }

            sigBaseString = headerParams.method + "&" + encodeURIComponent(headerParams.url) + "&" + encodeURIComponent(sigBaseStringParams);

            keyText = encodeURIComponent(headerParams.consumerSecret) + "&";
            if (headerParams.oauthTokenSecret) {
                keyText += encodeURIComponent(headerParams.oauthTokenSecret);
            }

            signature = this._generateHmacSha1Signature(sigBaseString, keyText);
            headers = "OAuth " + (!headerParams.oauthTokenSecret ? ("oauth_callback=\"" + encodeURIComponent(this._callbackURL) + "\", ") : "") +
                "oauth_consumer_key=\"" + headerParams.consumerKey +
                "\", oauth_nonce=\"" + nonce +
                "\", oauth_signature=\"" + encodeURIComponent(signature) +
                "\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"" + timestamp +
                (headerParams.oauthToken ? ("\", oauth_token=\"" + headerParams.oauthToken) : "") +
                (headerParams.oauthVerifier ? ("\", oauth_verify=\"" + headerParams.oauthVerifier) : "") +
                "\", oauth_version=\"1.0\"";

            return headers;
        },

        //Gets a request token which is used to initiate a 3 legged oauth call
        _getRequestToken: function (callback) {
            var i,
                splits,
                headerParams,
                keyValPairs,
                requestToken,
                requestTokenSecret;

            headerParams = {
                consumerKey: this._consumerKey,
                consumerSecret: this._consumerSecret,
                url: this._requestTokenURL,
                method: 'POST'
            };

            this._sendAuthorizedRequest(this._requestTokenURL, 'POST', headerParams, function (response) {
                keyValPairs = response.split("&");

                //Grab the returned request tokens
                for (i = 0; i < keyValPairs.length; i++) {
                    splits = keyValPairs[i].split("=");
                    switch (splits[0]) {
                        case "oauth_token":
                            requestToken = splits[1];
                            break;
                        case "oauth_token_secret":
                            requestTokenSecret = splits[1];
                            break;
                    }
                }

                callback({
                    oauth_token: requestToken,
                    oauth_token_secret: requestTokenSecret
                });
            });
        },

        //Gets a user specific access token & secret which is used to sign requests on a users behalf
        _getAccessToken: function (requestToken, oauthVerifier, callback) {
            var i,
                splits,
                headerParams,
                keyValPairs,
                userAccessToken,
                userAccessTokenSecret,
                twitterUserId,
                screenName;

            headerParams = {
                consumerKey: this._consumerKey,
                consumerSecret: this._consumerSecret,
                oauthToken: requestToken,
                oauthVerifier: oauthVerifier,
                url: this._accessTokenURL,
                method: 'POST'
            };

            this._sendAuthorizedRequest(this._accessTokenURL, 'POST', headerParams, function (response) {
                if (response === false) {
                    //Request failes, most likely the user cancelled the request
                    callback(false);
                } else {
                    keyValPairs = response.split("&");

                    //Disect the important parts
                    for (i = 0; i < keyValPairs.length; i++) {
                        splits = keyValPairs[i].split("=");
                        switch (splits[0]) {
                            case "oauth_token":
                                userAccessToken = splits[1];
                                break;
                            case "oauth_token_secret":
                                userAccessTokenSecret = splits[1];
                                break;
                            case "user_id":
                                twitterUserId = splits[1];
                                break;
                            case "screen_name":
                                screenName = splits[1];
                                break;
                        }
                    }

                    callback({
                        oauth_token: userAccessToken,
                        oauth_token_secret: userAccessTokenSecret,
                        twitter_user_id: twitterUserId,
                        screen_name: screenName
                    });
                }
            });
        },

        setAccessToken: function (accessToken, accessTokenSecret) {
            this._accessToken = accessToken;
            this._accessTokenSecret = accessTokenSecret;
        },

        /**
         * Get approval for our app from the user.
         * Gets us approved access tokens for making future requests on the users behalf.
         * https://dev.twitter.com/docs/api/1/get/oauth/authorize
         **/
        doTwitterWebAuth: function (callback) {
            var self = this,
                i,
                splits,
                responseKeyValPairs,
                startURI,
                endURI,
                oauthVerifier;

            this._getRequestToken(function (requestTokenData) {
                //Send the user to get app authorization
                startURI = new Windows.Foundation.Uri(self._authorizeURL + "?oauth_token=" + requestTokenData.oauth_token);
                endURI = new Windows.Foundation.Uri(self._callbackURL);

                Windows.Security.Authentication.Web.WebAuthenticationBroker.authenticateAsync(
                Windows.Security.Authentication.Web.WebAuthenticationOptions.none, startURI, endURI)
                    .done(function (result) {
                        var twitterResponseData = result.responseData,
                            twitterResponseStatus = result.responseStatus;

                        if (twitterResponseStatus === Windows.Security.Authentication.Web.WebAuthenticationStatus.errorHttp) {
                            //console.log("Error returned: " + result.responseErrorDetail);
                            callback(false);
                        } else {
                            //The authorize request when successful will return an oauthVerifier
                            //https://dev.twitter.com/docs/auth/authorizing-request
                            responseKeyValPairs = twitterResponseData.split("?")[1].split("&");

                            //Disect the important parts
                            for (i = 0; i < responseKeyValPairs.length; i++) {
                                splits = responseKeyValPairs[i].split("=");
                                switch (splits[0]) {
                                    case "oauth_verifier":
                                        oauthVerifier = splits[1];
                                        break;
                                }
                            }

                            //With the user request token in hand we can request a perm user access token
                            self._getAccessToken(requestTokenData.oauth_token, oauthVerifier, function (accessTokenData) {
                                if (accessTokenData === false) {
                                    //Request failes, most likely the user cancelled the request
                                    callback(false);
                                } else {
                                    //Set this in the instance, but return as well so it can be saved off as needed
                                    self._accessToken = accessTokenData.oauth_token;
                                    self._accessTokenSecret = accessTokenData.oauth_token_secret;
                                    callback(accessTokenData);
                                }
                            });
                        }
                    }, function (err) {
                        //console.log("Error returned by WebAuth broker: " + err.message);
                        callback(false);
                    });
            });
        },

        //Signs a request with the apps consumer secret & the users access token secret
        //Note: queryParms must be an object with key/value pairs (values should be urlencoded)
        sendAuthorizedRequestForUser: function (url, method, queryParams) {
            var self = this,
                promise,
                headerParams,
                authzHeader;

            promise = new WinJS.Promise(function (complete) {
                headerParams = {
                    consumerKey: self._consumerKey,
                    consumerSecret: self._consumerSecret,
                    oauthToken: self._accessToken,
                    oauthTokenSecret: self._accessTokenSecret,
                    url: url,
                    method: method
                };

                if (queryParams) {
                    headerParams.queryParams = queryParams;
                }

                if (method === 'GET' && queryParams) {
                    var i = 0,
                        key,
                        queryString = '';

                    for (key in queryParams) {
                        if (queryParams.hasOwnProperty(key)) {
                            if (i > 0) {
                                queryString += '&';
                            }
                            queryString += key + '=' + queryParams[key];
                            i++;
                        }
                    }
                    url += '?' + queryString;
                }

                authzHeader = self._getOAuthRequestHeaders(headerParams);
                self._xhrRequest(method, url, authzHeader, function (results) {
                    complete(results);
                });
            });

            return promise;
        }
    },
    //staticMembers
    {}
);<commit_msg>Added support for returning API rate limit info for authenticated calls.  Bumping version to 1.2.<commit_after>/**
 * WinJS OAuth for Twitter
 * https://github.com/cauld/twitter-oauth-for-winjs
 * Copyright Manifold 2012. All rights reserved.
 * Apache License, Version 2.0
 */

/*global Windows: false, WinJS: false, XMLHttpRequest: false */
/*jslint nomen: true, plusplus: true, sloppy: true, white: true */

var TwitterOAuth = WinJS.Class.define(
    //Constructor
    function (consumerKey, consumerSecret, accessToken, accessTokenSecret, callbackUrl) {
        this._consumerKey = consumerKey;
        this._consumerSecret = consumerSecret;

        //If we already have accessToken then doTwitterWebAuth can be avoided
        this._accessToken = accessToken || null;
        this._accessTokenSecret = accessTokenSecret || null;

        //Define the OAuth callback url, not normally important for desktop apps
        this._callbackURL = callbackUrl || 'http://localhost/auth/twitter/callback';
    },
    //instanceMembers
    {
        _authorizeURL: 'https://api.twitter.com/oauth/authorize',
        _requestTokenURL: 'https://api.twitter.com/oauth/request_token',
        _accessTokenURL: 'https://api.twitter.com/oauth/access_token',

        //Signs internal requests used during the process of access token retrieval
        _sendAuthorizedRequest: function (url, method, headerParams, callback) {
            var authzHeader = this._getOAuthRequestHeaders(headerParams);

            this._xhrRequest(method, url, authzHeader, function (result, statusCode) {
                callback(result, statusCode);
            });
        },

        _xhrRequest: function (method, url, authzHeader, callback) {
            var request,
                extraResponseInfo;

            try {
                request = new XMLHttpRequest();
                request.open(method, url, true);
                request.onreadystatechange = function () {
                    if (request.readyState === 4) {
                        if (request.status === 200) {
                            //In v1.1 Twitter moved the API rate limit into the response headers
                            //Ref 1: https://dev.twitter.com/docs/rate-limiting-faq#checking
                            //Ref 2: https://dev.twitter.com/docs/rate-limiting/1.1/limits
                            extraResponseInfo = {
                                "X-Rate-Limit-Limit": request.getResponseHeader('X-Rate-Limit-Limit') || null,
                                "X-Rate-Limit-Remaining": request.getResponseHeader('X-Rate-Limit-Remaining') || null,
                                "X-Rate-Limit-Reset": request.getResponseHeader('X-Rate-Limit-Reset') || null
                            };

                            callback(request.responseText, 200, extraResponseInfo);
                        } else {
                            callback(false, request.status); //429 is rate limit exceeded
                        }
                    }
                };
                request.setRequestHeader("Authorization", authzHeader);
                request.send();
            } catch (err) {
                //console.log("Error sending request: " + err);
                callback(false, 500);
            }
        },

        //Generate an OAuth 1.0a HMAC-SHA1 signature for an HTTP request
        _generateHmacSha1Signature: function (sigBaseString, keyText) {
            var keyMaterial,
                macAlgorithmProvider,
                tbs,
                key,
                signatureBuffer,
                signature;

            keyMaterial = Windows.Security.Cryptography.CryptographicBuffer.convertStringToBinary(keyText, Windows.Security.Cryptography.BinaryStringEncoding.Utf8);
            macAlgorithmProvider = Windows.Security.Cryptography.Core.MacAlgorithmProvider.openAlgorithm("HMAC_SHA1");
            key = macAlgorithmProvider.createKey(keyMaterial);
            tbs = Windows.Security.Cryptography.CryptographicBuffer.convertStringToBinary(sigBaseString, Windows.Security.Cryptography.BinaryStringEncoding.Utf8);
            signatureBuffer = Windows.Security.Cryptography.Core.CryptographicEngine.sign(key, tbs);
            signature = Windows.Security.Cryptography.CryptographicBuffer.encodeToBase64String(signatureBuffer);

            return signature;
        },

        _getSortedKeys: function (obj) {
            var key,
                keys = [];

            for (key in obj) {
                if (obj.hasOwnProperty(key)) {
                    keys[keys.length] = key;
                }
            }

            return keys.sort();
        },

        /**
         * Assembles proper headers based on a series of provided tokens, secrets, and signatures
         * References:
         * https://dev.twitter.com/docs/auth/authorizing-request
         * https://dev.twitter.com/docs/auth/creating-signature
         * Debug oauth signing errors here - https://dev.twitter.com/apps/3400014/oauth
         */
        _getOAuthRequestHeaders: function (headerParams) {
            var i,
                k,
                kv,
                sortedKeys,
                sigParams,
                sigBaseString,
                sigBaseStringParams = '',
                queryParamsKey,
                keyText,
                signature,
                headers,
                timestamp = Math.round(new Date().getTime() / 1000.0),
                nonce = Math.random();

            // Acquiring a request token
            nonce = Math.floor(nonce * 1000000000);

            sigParams = {
                oauth_callback: !headerParams.oauthTokenSecret ? encodeURIComponent(this._callbackURL) : "",
                oauth_consumer_key: headerParams.consumerKey,
                oauth_nonce: nonce,
                oauth_signature_method: 'HMAC-SHA1',
                oauth_timestamp: timestamp,
                oauth_token: headerParams.oauthToken || "",
                oauth_verifier: headerParams.oauthVerifier || "",
                oauth_version: '1.0'
            };

            //We need to combine the oauth params with any query params
            if (headerParams.queryParams) {
                for (queryParamsKey in headerParams.queryParams) {
                    if (headerParams.queryParams.hasOwnProperty(queryParamsKey)) {
                        sigParams[queryParamsKey] = headerParams.queryParams[queryParamsKey];
                    }
                }
            }

            // Compute base signature string and sign it.
            // This is a common operation that is required for all requests even after the token is obtained.
            // Parameters need to be sorted in alphabetical order
            // Keys and values should be URL Encoded.
            sortedKeys = this._getSortedKeys(sigParams);
            for (i = 0; i < sortedKeys.length; i++) {
                k = sortedKeys[i];
                kv = sigParams[sortedKeys[i]];
                if (kv && kv !== '') {
                    if (sigBaseStringParams !== '') {
                        sigBaseStringParams += '&';
                    }
                    sigBaseStringParams += k + '=' + kv;
                }
            }

            sigBaseString = headerParams.method + "&" + encodeURIComponent(headerParams.url) + "&" + encodeURIComponent(sigBaseStringParams);

            keyText = encodeURIComponent(headerParams.consumerSecret) + "&";
            if (headerParams.oauthTokenSecret) {
                keyText += encodeURIComponent(headerParams.oauthTokenSecret);
            }

            signature = this._generateHmacSha1Signature(sigBaseString, keyText);
            headers = "OAuth " + (!headerParams.oauthTokenSecret ? ("oauth_callback=\"" + encodeURIComponent(this._callbackURL) + "\", ") : "") +
                "oauth_consumer_key=\"" + headerParams.consumerKey +
                "\", oauth_nonce=\"" + nonce +
                "\", oauth_signature=\"" + encodeURIComponent(signature) +
                "\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"" + timestamp +
                (headerParams.oauthToken ? ("\", oauth_token=\"" + headerParams.oauthToken) : "") +
                (headerParams.oauthVerifier ? ("\", oauth_verify=\"" + headerParams.oauthVerifier) : "") +
                "\", oauth_version=\"1.0\"";

            return headers;
        },

        //Gets a request token which is used to initiate a 3 legged oauth call
        _getRequestToken: function (callback) {
            var i,
                splits,
                headerParams,
                keyValPairs,
                requestToken,
                requestTokenSecret;

            headerParams = {
                consumerKey: this._consumerKey,
                consumerSecret: this._consumerSecret,
                url: this._requestTokenURL,
                method: 'POST'
            };

            this._sendAuthorizedRequest(this._requestTokenURL, 'POST', headerParams, function (response) {
                keyValPairs = response.split("&");

                //Grab the returned request tokens
                for (i = 0; i < keyValPairs.length; i++) {
                    splits = keyValPairs[i].split("=");
                    switch (splits[0]) {
                        case "oauth_token":
                            requestToken = splits[1];
                            break;
                        case "oauth_token_secret":
                            requestTokenSecret = splits[1];
                            break;
                    }
                }

                callback({
                    oauth_token: requestToken,
                    oauth_token_secret: requestTokenSecret
                });
            });
        },

        //Gets a user specific access token & secret which is used to sign requests on a users behalf
        _getAccessToken: function (requestToken, oauthVerifier, callback) {
            var i,
                splits,
                headerParams,
                keyValPairs,
                userAccessToken,
                userAccessTokenSecret,
                twitterUserId,
                screenName;

            headerParams = {
                consumerKey: this._consumerKey,
                consumerSecret: this._consumerSecret,
                oauthToken: requestToken,
                oauthVerifier: oauthVerifier,
                url: this._accessTokenURL,
                method: 'POST'
            };

            this._sendAuthorizedRequest(this._accessTokenURL, 'POST', headerParams, function (response) {
                if (response === false) {
                    //Request failes, most likely the user cancelled the request
                    callback(false);
                } else {
                    keyValPairs = response.split("&");

                    //Disect the important parts
                    for (i = 0; i < keyValPairs.length; i++) {
                        splits = keyValPairs[i].split("=");
                        switch (splits[0]) {
                            case "oauth_token":
                                userAccessToken = splits[1];
                                break;
                            case "oauth_token_secret":
                                userAccessTokenSecret = splits[1];
                                break;
                            case "user_id":
                                twitterUserId = splits[1];
                                break;
                            case "screen_name":
                                screenName = splits[1];
                                break;
                        }
                    }

                    callback({
                        oauth_token: userAccessToken,
                        oauth_token_secret: userAccessTokenSecret,
                        twitter_user_id: twitterUserId,
                        screen_name: screenName
                    });
                }
            });
        },

        setAccessToken: function (accessToken, accessTokenSecret) {
            this._accessToken = accessToken;
            this._accessTokenSecret = accessTokenSecret;
        },

        /**
         * Get approval for our app from the user.
         * Gets us approved access tokens for making future requests on the users behalf.
         * https://dev.twitter.com/docs/api/1/get/oauth/authorize
         **/
        doTwitterWebAuth: function (callback) {
            var self = this,
                i,
                splits,
                responseKeyValPairs,
                startURI,
                endURI,
                oauthVerifier;

            this._getRequestToken(function (requestTokenData) {
                //Send the user to get app authorization
                startURI = new Windows.Foundation.Uri(self._authorizeURL + "?oauth_token=" + requestTokenData.oauth_token);
                endURI = new Windows.Foundation.Uri(self._callbackURL);

                Windows.Security.Authentication.Web.WebAuthenticationBroker.authenticateAsync(
                Windows.Security.Authentication.Web.WebAuthenticationOptions.none, startURI, endURI)
                    .done(function (result) {
                        var twitterResponseData = result.responseData,
                            twitterResponseStatus = result.responseStatus;

                        if (twitterResponseStatus === Windows.Security.Authentication.Web.WebAuthenticationStatus.errorHttp) {
                            //console.log("Error returned: " + result.responseErrorDetail);
                            callback(false);
                        } else {
                            //The authorize request when successful will return an oauthVerifier
                            //https://dev.twitter.com/docs/auth/authorizing-request
                            responseKeyValPairs = twitterResponseData.split("?")[1].split("&");

                            //Disect the important parts
                            for (i = 0; i < responseKeyValPairs.length; i++) {
                                splits = responseKeyValPairs[i].split("=");
                                switch (splits[0]) {
                                    case "oauth_verifier":
                                        oauthVerifier = splits[1];
                                        break;
                                }
                            }

                            //With the user request token in hand we can request a perm user access token
                            self._getAccessToken(requestTokenData.oauth_token, oauthVerifier, function (accessTokenData) {
                                if (accessTokenData === false) {
                                    //Request failes, most likely the user cancelled the request
                                    callback(false);
                                } else {
                                    //Set this in the instance, but return as well so it can be saved off as needed
                                    self._accessToken = accessTokenData.oauth_token;
                                    self._accessTokenSecret = accessTokenData.oauth_token_secret;
                                    callback(accessTokenData);
                                }
                            });
                        }
                    }, function (err) {
                        //console.log("Error returned by WebAuth broker: " + err.message);
                        callback(false);
                    });
            });
        },

        //Signs a request with the apps consumer secret & the users access token secret
        //Note: queryParms must be an object with key/value pairs (values should be urlencoded)
        sendAuthorizedRequestForUser: function (url, method, queryParams) {
            var self = this,
                promise,
                headerParams,
                authzHeader;

            promise = new WinJS.Promise(function (complete) {
                headerParams = {
                    consumerKey: self._consumerKey,
                    consumerSecret: self._consumerSecret,
                    oauthToken: self._accessToken,
                    oauthTokenSecret: self._accessTokenSecret,
                    url: url,
                    method: method
                };

                if (queryParams) {
                    headerParams.queryParams = queryParams;
                }

                if (method === 'GET' && queryParams) {
                    var i = 0,
                        key,
                        queryString = '';

                    for (key in queryParams) {
                        if (queryParams.hasOwnProperty(key)) {
                            if (i > 0) {
                                queryString += '&';
                            }
                            queryString += key + '=' + queryParams[key];
                            i++;
                        }
                    }
                    url += '?' + queryString;
                }

                authzHeader = self._getOAuthRequestHeaders(headerParams);
                self._xhrRequest(method, url, authzHeader, function (results, statusCode, extraResponseInfo) {
                    complete({
                        results: results,
                        statusCode: statusCode,
                        extraResponseInfo: extraResponseInfo
                    });
                });
            });

            return promise;
        }
    },
    //staticMembers
    {}
);<|endoftext|>


<commit_before>import React from 'react'
import {
	Alert,
	Platform,
} from 'react-native'
import { connect } from 'react-redux'
import firebase from 'react-native-firebase'
import Permissions from 'react-native-permissions'

const subscribeToDefaults = (messaging) => {
	const defaultTopics = ['emergency']

	defaultTopics.forEach((topic) => {
		messaging.subscribeToTopic(topic)
		console.log('Subscribed to ' + topic)
	})
}

class PushNotificationContainer extends React.Component {
	componentDidMount() {
		this.checkPermission()

		this.onTokenRefreshListener = firebase.messaging().onTokenRefresh((fcmToken) => {
			// Process your token as required
			console.log('Firebase Token (refresh):', fcmToken)

			subscribeToDefaults(firebase.messaging())
			if (this.props.user.isLoggedIn) this.props.registerToken(fcmToken)
		})

		this.messageListener = firebase.messaging().onMessage((message) => {
			console.log('New message received: ', message)
		})

		this.notificationListener = firebase.notifications().onNotification((notification) => {
			console.log('New notification received: ', notification)
		})
	}

	componentWillUnmount() {
		// stop listening for events
		this.onTokenRefreshListener()
		this.messageListener()
	}

	getNotificationToken = () => {
		firebase.messaging().getToken()
			.then((fcmToken) => {
				if (fcmToken) {
					console.log('Firebase Token: ', fcmToken)

					// Subscribe to default topics
					subscribeToDefaults(firebase.messaging())
				}
			})
	}

	getSoftPermission = () => {
		Alert.alert(
			'Allow this app to send you notifications?',
			'We need access so we can keep you informed.',
			[
				{
					text: 'No',
					onPress: () => {}
				},
				{
					text: 'Yes',
					onPress: this.getPermission
				}
			]
		)
	}

	getPermission = () => {
		Permissions.request('notification')
			.then((response) => {
				// if authorized, act
				if (response === 'authorized') {
					this.getNotificationToken()
				}
			})
	}

	showLocalNotification = (notif) => {
		// NOTE: will not work until we configure local notifications
		if (notif && notif.notification) {

		}
	}

	checkPermission = () => {
		if (Platform.OS === 'ios') {
			// check for permission and either ask for it
			// or if we already have it then update the device tokens
			Permissions.check('notification')
				.then((response) => {
					if (response === 'undetermined') {
						this.getPermission()
					} else if (response === 'authorized') {
						this.getNotificationToken()
					}
				})
		} else {
			// android always has permissions, just go get the notification token
			this.getNotificationToken()
		}
	}

	// Set device information along with app push ID token
	updateServerToken = (token) => {
		console.log('push token', token)

		// TODO: send token to server so we can push notifications here
	}

	render() {
		return null // TODO: render error message if user does not allow location
	}
}

function mapStateToProps(state, props) {
	return { user: state.user }
}

const mapDispatchToProps = (dispatch, ownProps) => (
	{
		registerToken: (token) => {
			dispatch({ type: 'REGISTER_TOKEN', token })
		}
	}
)

module.exports = connect(mapStateToProps, mapDispatchToProps)(PushNotificationContainer)
<commit_msg>Dispatch update messages action when a notification is received in-app<commit_after>import React from 'react'
import {
	Alert,
	Platform,
} from 'react-native'
import { connect } from 'react-redux'
import firebase from 'react-native-firebase'
import Permissions from 'react-native-permissions'

const subscribeToDefaults = (messaging) => {
	const defaultTopics = ['emergency']

	defaultTopics.forEach((topic) => {
		messaging.subscribeToTopic(topic)
		console.log('Subscribed to ' + topic)
	})
}

class PushNotificationContainer extends React.Component {
	componentDidMount() {
		this.checkPermission()

		this.onTokenRefreshListener = firebase.messaging().onTokenRefresh((fcmToken) => {
			// Process your token as required
			console.log('Firebase Token (refresh):', fcmToken)

			subscribeToDefaults(firebase.messaging())
			if (this.props.user.isLoggedIn) this.props.registerToken(fcmToken)
		})

		this.messageListener = firebase.messaging().onMessage((message) => {
			console.log('New message received: ', message)
			this.props.updateMessages()
		})

		this.notificationListener = firebase.notifications().onNotification((notification) => {
			console.log('New notification received: ', notification)
			this.props.updateMessages()
		})
	}

	componentWillUnmount() {
		// stop listening for events
		this.onTokenRefreshListener()
		this.messageListener()
	}

	getNotificationToken = () => {
		firebase.messaging().getToken()
			.then((fcmToken) => {
				if (fcmToken) {
					console.log('Firebase Token: ', fcmToken)

					// Subscribe to default topics
					subscribeToDefaults(firebase.messaging())
				}
			})
	}

	getSoftPermission = () => {
		Alert.alert(
			'Allow this app to send you notifications?',
			'We need access so we can keep you informed.',
			[
				{
					text: 'No',
					onPress: () => {}
				},
				{
					text: 'Yes',
					onPress: this.getPermission
				}
			]
		)
	}

	getPermission = () => {
		Permissions.request('notification')
			.then((response) => {
				// if authorized, act
				if (response === 'authorized') {
					this.getNotificationToken()
				}
			})
	}

	showLocalNotification = (notif) => {
		// NOTE: will not work until we configure local notifications
		if (notif && notif.notification) {

		}
	}

	checkPermission = () => {
		if (Platform.OS === 'ios') {
			// check for permission and either ask for it
			// or if we already have it then update the device tokens
			Permissions.check('notification')
				.then((response) => {
					if (response === 'undetermined') {
						this.getPermission()
					} else if (response === 'authorized') {
						this.getNotificationToken()
					}
				})
		} else {
			// android always has permissions, just go get the notification token
			this.getNotificationToken()
		}
	}

	// Set device information along with app push ID token
	updateServerToken = (token) => {
		console.log('push token', token)

		// TODO: send token to server so we can push notifications here
	}

	render() {
		return null // TODO: render error message if user does not allow location
	}
}

function mapStateToProps(state, props) {
	return { user: state.user }
}

const mapDispatchToProps = (dispatch, ownProps) => (
	{
		registerToken: (token) => {
			dispatch({ type: 'REGISTER_TOKEN', token })
		},
		updateMessages: () => {
			dispatch({ type: 'UPDATE_MESSAGES' })
		}
	}
)

module.exports = connect(mapStateToProps, mapDispatchToProps)(PushNotificationContainer)
<|endoftext|>


<commit_before>/**
 *
 * App.js
 *
 */

import React, { useEffect, useState, useMemo, lazy, Suspense } from 'react';
import { Switch, Route } from 'react-router-dom';
import {
  LoadingIndicatorPage,
  auth,
  request,
  useNotification,
  TrackingContext,
} from '@strapi/helper-plugin';
import { SkipToContent } from '@strapi/design-system/Main';
import { useIntl } from 'react-intl';
import PrivateRoute from '../../components/PrivateRoute';
import { createRoute, makeUniqueRoutes } from '../../utils';
import AuthPage from '../AuthPage';
import NotFoundPage from '../NotFoundPage';
import { getUID } from './utils';
import routes from './utils/routes';

const AuthenticatedApp = lazy(() =>
  import(/* webpackChunkName: "Admin-authenticatedApp" */ '../../components/AuthenticatedApp')
);

function App() {
  const toggleNotification = useNotification();
  const { formatMessage } = useIntl();
  const [{ isLoading, hasAdmin, uuid }, setState] = useState({ isLoading: true, hasAdmin: false });

  const authRoutes = useMemo(() => {
    return makeUniqueRoutes(
      routes.map(({ to, Component, exact }) => createRoute(Component, to, exact))
    );
  }, []);

  useEffect(() => {
    const currentToken = auth.getToken();

    const renewToken = async () => {
      try {
        const {
          data: { token },
        } = await request('/admin/renew-token', {
          method: 'POST',
          body: { token: currentToken },
        });
        auth.updateToken(token);
      } catch (err) {
        // Refresh app
        auth.clearAppStorage();
        window.location.reload();
      }
    };

    if (currentToken) {
      renewToken();
    }
  }, []);

  useEffect(() => {
    const getData = async () => {
      try {
        const {
          data: { hasAdmin, uuid },
        } = await request('/admin/init', { method: 'GET' });

        if (uuid) {
          try {
            const deviceId = await getUID();

            fetch('https://analytics.strapi.io/track', {
              method: 'POST',
              body: JSON.stringify({
                event: 'didInitializeAdministration',
                uuid,
                deviceId,
              }),
              headers: {
                'Content-Type': 'application/json',
              },
            });
          } catch (e) {
            // Silent.
          }
        }

        setState({ isLoading: false, hasAdmin, uuid });
      } catch (err) {
        toggleNotification({
          type: 'warning',
          message: { id: 'app.containers.App.notification.error.init' },
        });
      }
    };

    getData();
  }, [toggleNotification]);

  const setHasAdmin = hasAdmin => setState(prev => ({ ...prev, hasAdmin }));

  if (isLoading) {
    return <LoadingIndicatorPage />;
  }

  return (
    <Suspense fallback={<LoadingIndicatorPage />}>
      <SkipToContent>{formatMessage({ id: 'skipToContent' })}</SkipToContent>
      <TrackingContext.Provider value={uuid}>
        <Switch>
          {authRoutes}
          <Route
            path="/auth/:authType"
            render={routerProps => (
              <AuthPage {...routerProps} setHasAdmin={setHasAdmin} hasAdmin={hasAdmin} />
            )}
            exact
          />
          <PrivateRoute path="/" component={AuthenticatedApp} />
          <Route path="" component={NotFoundPage} />
        </Switch>
      </TrackingContext.Provider>
    </Suspense>
  );
}

export default App;
<commit_msg>Added fingerprint prefix in order to match the one on strapi website<commit_after>/**
 *
 * App.js
 *
 */

import React, { useEffect, useState, useMemo, lazy, Suspense } from 'react';
import { Switch, Route } from 'react-router-dom';
import {
  LoadingIndicatorPage,
  auth,
  request,
  useNotification,
  TrackingContext,
} from '@strapi/helper-plugin';
import { SkipToContent } from '@strapi/design-system/Main';
import { useIntl } from 'react-intl';
import PrivateRoute from '../../components/PrivateRoute';
import { createRoute, makeUniqueRoutes } from '../../utils';
import AuthPage from '../AuthPage';
import NotFoundPage from '../NotFoundPage';
import { getUID } from './utils';
import routes from './utils/routes';

const AuthenticatedApp = lazy(() =>
  import(/* webpackChunkName: "Admin-authenticatedApp" */ '../../components/AuthenticatedApp')
);

function App() {
  const toggleNotification = useNotification();
  const { formatMessage } = useIntl();
  const [{ isLoading, hasAdmin, uuid }, setState] = useState({ isLoading: true, hasAdmin: false });

  const authRoutes = useMemo(() => {
    return makeUniqueRoutes(
      routes.map(({ to, Component, exact }) => createRoute(Component, to, exact))
    );
  }, []);

  useEffect(() => {
    const currentToken = auth.getToken();

    const renewToken = async () => {
      try {
        const {
          data: { token },
        } = await request('/admin/renew-token', {
          method: 'POST',
          body: { token: currentToken },
        });
        auth.updateToken(token);
      } catch (err) {
        // Refresh app
        auth.clearAppStorage();
        window.location.reload();
      }
    };

    if (currentToken) {
      renewToken();
    }
  }, []);

  useEffect(() => {
    const getData = async () => {
      try {
        const {
          data: { hasAdmin, uuid },
        } = await request('/admin/init', { method: 'GET' });

        if (uuid) {
          try {
            const deviceId = await getUID();

            fetch('https://analytics.strapi.io/track', {
              method: 'POST',
              body: JSON.stringify({
                event: 'didInitializeAdministration',
                uuid,
                deviceId: `web-fingerprint-${deviceId}`,
              }),
              headers: {
                'Content-Type': 'application/json',
              },
            });
          } catch (e) {
            // Silent.
          }
        }

        setState({ isLoading: false, hasAdmin, uuid });
      } catch (err) {
        toggleNotification({
          type: 'warning',
          message: { id: 'app.containers.App.notification.error.init' },
        });
      }
    };

    getData();
  }, [toggleNotification]);

  const setHasAdmin = hasAdmin => setState(prev => ({ ...prev, hasAdmin }));

  if (isLoading) {
    return <LoadingIndicatorPage />;
  }

  return (
    <Suspense fallback={<LoadingIndicatorPage />}>
      <SkipToContent>{formatMessage({ id: 'skipToContent' })}</SkipToContent>
      <TrackingContext.Provider value={uuid}>
        <Switch>
          {authRoutes}
          <Route
            path="/auth/:authType"
            render={routerProps => (
              <AuthPage {...routerProps} setHasAdmin={setHasAdmin} hasAdmin={hasAdmin} />
            )}
            exact
          />
          <PrivateRoute path="/" component={AuthenticatedApp} />
          <Route path="" component={NotFoundPage} />
        </Switch>
      </TrackingContext.Provider>
    </Suspense>
  );
}

export default App;
<|endoftext|>


<commit_before>export { default } from './Scan';
<commit_msg>removed redundant dir<commit_after><|endoftext|>


<commit_before>var session;

function mockPromise(resolveWith, rejectWith) {
  return new Ember.RSVP.Promise(function(resolve, reject) {
    if (!Ember.isEmpty(resolveWith) && !!resolveWith) {
      resolve(resolveWith);
    } else {
      reject(rejectWith);
    }
  });
}

var storeMock;
var StoreMock = Ember.SimpleAuth.Stores.Ephemeral.extend({
  restore: function() {
    this.restoreInvoked = true;
    return this._super();
  }
});

var authenticatorMock;
var AuthenticatorMock = Ember.Object.extend(Ember.Evented, {
  restore: function(content) {
    return mockPromise(AuthenticatorMock._resolve);
  },
  authenticate: function(properties) {
    this.authenticateInvoked     = true;
    this.authenticateInvokedWith = properties;
    return mockPromise(AuthenticatorMock._resolve, AuthenticatorMock._reject);
  },
  invalidate: function(properties) {
    this.invalidateInvoked     = true;
    this.invalidateInvokedWith = properties;
    return mockPromise(AuthenticatorMock._resolve);
  }
});

module('Ember.SimpleAuth.Session', {
  setup: function() {
    window.AuthenticatorMock = AuthenticatorMock;
    authenticatorMock        = AuthenticatorMock.create();
    storeMock                = StoreMock.create();
    Ember.run(function() {
      session = Ember.SimpleAuth.Session.create({ authenticator: authenticatorMock, store: storeMock });
    });
  },
  teardown: function() {
    delete window.AuthenticatorMock;
    delete window.Authenticators;
  }
});

test('is not authenticated when just created', function() {
  session = Ember.SimpleAuth.Session.create({ store: storeMock });

  ok(!session.get('isAuthenticated'), 'Ember.Session is not authenticated when just created.');
});

test('restores its state during initialization', function() {
  storeMock.persist({ authenticator: 'AuthenticatorMock' });
  AuthenticatorMock._resolve = { some: 'content' };
  Ember.run(function() {
    session = Ember.SimpleAuth.Session.create({ store: storeMock });
  });

  ok(storeMock.restoreInvoked, 'Ember.Session restores its content from the store during initialization.');
  ok(session.get('authenticator') instanceof AuthenticatorMock, 'Ember.Session restores the authenticator as a new instance of the class read from the store during initialization.');
  ok(session.get('isAuthenticated'), 'Ember.Session is authenticated when the restored authenticator resolves during initialization.');
  deepEqual(session.get('content'), { some: 'content' }, 'Ember.Session sets its content when the restored authenticator resolves during initialization.');

  AuthenticatorMock._resolve = false;
  storeMock.persist({ key1: 'value1', key2: 'value2' });
  Ember.run(function() {
    session = Ember.SimpleAuth.Session.create({ store: storeMock });
  });

  equal(session.get('authenticator'), null, 'Ember.Session does not assign the authenticator during initialization when the authenticator rejects.');
  ok(!session.get('isAuthenticated'), 'Ember.Session is not authenticated when the restored authenticator rejects during initialization.');
  equal(session.get('content'), null, 'Ember.Session does not set its content when the restored authenticator rejects during initialization.');
  equal(storeMock.restore().key1, null, 'Ember.Session clears the store when the restored authenticator rejects during initialization.');
  equal(storeMock.restore().key2, null, 'Ember.Session clears the store when the restored authenticator rejects during initialization.');
});

test('authenticates itself with an authenticator', function() {
  var resolved;
  AuthenticatorMock._resolve = { key: 'value' };
  Ember.run(function() {
    session.authenticate(authenticatorMock).then(function() {
      resolved = true;
    });
  });

  ok(authenticatorMock.authenticateInvoked, 'Ember.Session authenticates with the passed authenticator on setup.');
  ok(session.get('isAuthenticated'), 'Ember.Session is authenticated after setup when the authenticator resolves.');
  equal(session.get('key'), 'value', 'Ember.Session sets all properties that the authenticator resolves with during setup.');
  equal(session.get('authenticator'), authenticatorMock, 'Ember.Session saves the authenticator during setup when the authenticator resolves.');
  ok(resolved, 'Ember.Session returns a resolving promise on setup when the authenticator resolves.');

  var rejected;
  var rejectedWith;
  AuthenticatorMock._resolve = false;
  AuthenticatorMock._reject = { error: 'message' };
  Ember.run(function() {
    session = Ember.SimpleAuth.Session.create({ store: storeMock });
    session.authenticate(authenticatorMock).then(function() {}, function(error) {
      rejected     = true;
      rejectedWith = error;
    });
  });

  ok(!session.get('isAuthenticated'), 'Ember.Session is not authenticated after setup when the authenticator rejects.');
  equal(session.get('authenticator'), null, 'Ember.Session does not save the authenticator during setup when the authenticator rejects.');
  ok(rejected, 'Ember.Session returns a rejecting promise on setup when the authenticator rejects.');
  deepEqual(rejectedWith, { error: 'message'}, 'Ember.Session returns a promise that rejects with the error from the authenticator on setup when the authenticator rejects.');
});

test('invalidates itself', function() {
  AuthenticatorMock._resolve = true;
  Ember.run(function() {
    session.authenticate(authenticatorMock);
  });
  AuthenticatorMock._resolve = false;
  AuthenticatorMock._reject = { error: 'message' };
  session.set('isAuthenticated', true);
  Ember.run(function() {
    session.invalidate();
  });

  ok(session.get('isAuthenticated'), 'Ember.Session remains authenticated after unauthentication when the authenticator rejects.');
  equal(session.get('authenticator'), authenticatorMock, 'Ember.Session does not unset the authenticator after unauthentication when the authenticator rejects.');

  AuthenticatorMock._resolve = true;
  Ember.run(function() {
    session.set('content', { key: 'value' });
    session.invalidate();
  });

  ok(authenticatorMock.invalidateInvoked, 'Ember.Session invalidates with the authenticator on invalidation.');
  deepEqual(authenticatorMock.invalidateInvokedWith, { key: 'value' }, 'Ember.Session passes its content to the authenticator on invalidation.');
  ok(!session.get('isAuthenticated'), 'Ember.Session is not authenticated after unauthentication when the authenticator resolves.');
  equal(session.get('aurhenticator'), null, 'Ember.Session unsets the authenticator after unauthentication when the authenticator resolves.');
  equal(session.get('content'), null, 'Ember.Session unsets its content object after unauthentication when the authenticator resolves.');

  Ember.run(function() {
    authenticatorMock.trigger('ember-simple-auth:session-updated', { key: 'other value' });
  });

  equal(session.get('key'), null, 'Ember.Session stops listening to the "updated_session_data" of the authenticator after unauthentication when the authenticator resolves.');
});

test('observes changes of the observer', function() {
  window.Authenticators                        = Ember.Namespace.create();
  window.Authenticators.OtherAuthenticatorMock = AuthenticatorMock.extend();
  var otherAuthenticatorMock                   = window.Authenticators.OtherAuthenticatorMock.create();
  AuthenticatorMock._resolve = true;
  Ember.run(function() {
    session.authenticate(otherAuthenticatorMock).then(function() {
      otherAuthenticatorMock.trigger('ember-simple-auth:session-updated', { key: 'value' });
    });
  });

  equal(session.get('key'), 'value', 'Ember.Session subscribes to the "updated_session_data" of the authenticator when it is assigned.');
  equal(storeMock.restore().authenticator, 'Authenticators.OtherAuthenticatorMock', "Ember.Session saves the authenticator's prototype to the store when it is assigned.");
});
<commit_msg>test cleanup<commit_after>var session;

function mockPromise(resolveWith, rejectWith) {
  return new Ember.RSVP.Promise(function(resolve, reject) {
    if (!Ember.isEmpty(resolveWith) && !!resolveWith) {
      resolve(resolveWith);
    } else {
      reject(rejectWith);
    }
  });
}

var storeMock;
var StoreMock = Ember.SimpleAuth.Stores.Ephemeral.extend({
  restore: function() {
    this.restoreInvoked = true;
    return this._super();
  }
});

var authenticatorMock;
var AuthenticatorMock = Ember.Object.extend(Ember.Evented, {
  restore: function(content) {
    return mockPromise(AuthenticatorMock._resolve);
  },
  authenticate: function(properties) {
    this.authenticateInvoked     = true;
    this.authenticateInvokedWith = properties;
    return mockPromise(AuthenticatorMock._resolve, AuthenticatorMock._reject);
  },
  invalidate: function(properties) {
    this.invalidateInvoked     = true;
    this.invalidateInvokedWith = properties;
    return mockPromise(AuthenticatorMock._resolve);
  }
});

module('Ember.SimpleAuth.Session', {
  setup: function() {
    window.AuthenticatorMock = AuthenticatorMock;
    authenticatorMock        = AuthenticatorMock.create();
    storeMock                = StoreMock.create();
    Ember.run(function() {
      session = Ember.SimpleAuth.Session.create({ authenticator: authenticatorMock, store: storeMock });
    });
  },
  teardown: function() {
    delete window.AuthenticatorMock;
    delete window.Authenticators;
  }
});

test('is not authenticated when just created', function() {
  session = Ember.SimpleAuth.Session.create({ store: storeMock });

  ok(!session.get('isAuthenticated'), 'Ember.Session is not authenticated when just created.');
});

test('restores its state during initialization', function() {
  storeMock.persist({ authenticator: 'AuthenticatorMock' });
  AuthenticatorMock._resolve = { some: 'content' };
  Ember.run(function() {
    session = Ember.SimpleAuth.Session.create({ store: storeMock });
  });

  ok(storeMock.restoreInvoked, 'Ember.Session restores its content from the store during initialization.');
  ok(session.get('authenticator') instanceof AuthenticatorMock, 'Ember.Session restores the authenticator as a new instance of the class read from the store during initialization.');
  ok(session.get('isAuthenticated'), 'Ember.Session is authenticated when the restored authenticator resolves during initialization.');
  deepEqual(session.get('content'), { some: 'content' }, 'Ember.Session sets its content when the restored authenticator resolves during initialization.');

  AuthenticatorMock._resolve = false;
  storeMock.persist({ key1: 'value1' });
  Ember.run(function() {
    session = Ember.SimpleAuth.Session.create({ store: storeMock });
  });

  equal(session.get('authenticator'), null, 'Ember.Session does not assign the authenticator during initialization when the authenticator rejects.');
  ok(!session.get('isAuthenticated'), 'Ember.Session is not authenticated when the restored authenticator rejects during initialization.');
  equal(session.get('content'), null, 'Ember.Session does not set its content when the restored authenticator rejects during initialization.');
  equal(storeMock.restore().key1, null, 'Ember.Session clears the store when the restored authenticator rejects during initialization.');
});

test('authenticates itself with an authenticator', function() {
  var resolved;
  AuthenticatorMock._resolve = { key: 'value' };
  Ember.run(function() {
    session.authenticate(authenticatorMock).then(function() {
      resolved = true;
    });
  });

  ok(authenticatorMock.authenticateInvoked, 'Ember.Session authenticates with the passed authenticator on setup.');
  ok(session.get('isAuthenticated'), 'Ember.Session is authenticated after setup when the authenticator resolves.');
  equal(session.get('key'), 'value', 'Ember.Session sets all properties that the authenticator resolves with during setup.');
  equal(session.get('authenticator'), authenticatorMock, 'Ember.Session saves the authenticator during setup when the authenticator resolves.');
  ok(resolved, 'Ember.Session returns a resolving promise on setup when the authenticator resolves.');

  var rejected;
  var rejectedWith;
  AuthenticatorMock._resolve = false;
  AuthenticatorMock._reject = { error: 'message' };
  Ember.run(function() {
    session = Ember.SimpleAuth.Session.create({ store: storeMock });
    session.authenticate(authenticatorMock).then(function() {}, function(error) {
      rejected     = true;
      rejectedWith = error;
    });
  });

  ok(!session.get('isAuthenticated'), 'Ember.Session is not authenticated after setup when the authenticator rejects.');
  equal(session.get('authenticator'), null, 'Ember.Session does not save the authenticator during setup when the authenticator rejects.');
  ok(rejected, 'Ember.Session returns a rejecting promise on setup when the authenticator rejects.');
  deepEqual(rejectedWith, { error: 'message'}, 'Ember.Session returns a promise that rejects with the error from the authenticator on setup when the authenticator rejects.');
});

test('invalidates itself', function() {
  AuthenticatorMock._resolve = true;
  Ember.run(function() {
    session.authenticate(authenticatorMock);
  });
  AuthenticatorMock._resolve = false;
  AuthenticatorMock._reject = { error: 'message' };
  session.set('isAuthenticated', true);
  Ember.run(function() {
    session.invalidate();
  });

  ok(session.get('isAuthenticated'), 'Ember.Session remains authenticated after unauthentication when the authenticator rejects.');
  equal(session.get('authenticator'), authenticatorMock, 'Ember.Session does not unset the authenticator after unauthentication when the authenticator rejects.');

  AuthenticatorMock._resolve = true;
  Ember.run(function() {
    session.set('content', { key: 'value' });
    session.invalidate();
  });

  ok(authenticatorMock.invalidateInvoked, 'Ember.Session invalidates with the authenticator on invalidation.');
  deepEqual(authenticatorMock.invalidateInvokedWith, { key: 'value' }, 'Ember.Session passes its content to the authenticator on invalidation.');
  ok(!session.get('isAuthenticated'), 'Ember.Session is not authenticated after unauthentication when the authenticator resolves.');
  equal(session.get('aurhenticator'), null, 'Ember.Session unsets the authenticator after unauthentication when the authenticator resolves.');
  equal(session.get('content'), null, 'Ember.Session unsets its content object after unauthentication when the authenticator resolves.');

  Ember.run(function() {
    authenticatorMock.trigger('ember-simple-auth:session-updated', { key: 'other value' });
  });

  equal(session.get('key'), null, 'Ember.Session stops listening to the "updated_session_data" of the authenticator after unauthentication when the authenticator resolves.');
});

test('observes changes of the observer', function() {
  window.Authenticators                        = Ember.Namespace.create();
  window.Authenticators.OtherAuthenticatorMock = AuthenticatorMock.extend();
  var otherAuthenticatorMock                   = window.Authenticators.OtherAuthenticatorMock.create();
  AuthenticatorMock._resolve = true;
  Ember.run(function() {
    session.authenticate(otherAuthenticatorMock).then(function() {
      otherAuthenticatorMock.trigger('ember-simple-auth:session-updated', { key: 'value' });
    });
  });

  equal(session.get('key'), 'value', 'Ember.Session subscribes to the "updated_session_data" of the authenticator when it is assigned.');
  equal(storeMock.restore().authenticator, 'Authenticators.OtherAuthenticatorMock', "Ember.Session saves the authenticator's prototype to the store when it is assigned.");
});
<|endoftext|>


<commit_before>function determinant(m) {
  if (m.length == 1) {
    return m[0][0];
  }

  m[0].reduce(function (acc, x, col) {
    return acc + Math.pow(-1, col) * x * determinant(minor(m, { i: 0, j: col }));
  });
};

function minor(m, idxs) {

  function removeElement(index, m) {
    return m.slice(0, index).concat(m.slice(index + 1));
  }

  var result = removeElement(idxs.i, m.map(removeElement.bind(null, idxs.j)));
  console.log('result', result);

  return result;
}

console.log( minor([[1,3],[2,5]], {i: 0, j: 0}) );

exports.determinant = determinant;<commit_msg>All tests are passed<commit_after>function determinant(m) {
  if (m.length == 1) {
    return m[0][0];
  }

  return m[0].reduce(function (acc, x, col) {
    return acc + ( col & 1 ? -1 : 1 ) * x * determinant( minor(m, { i: 0, j: col }) );
  }, 0);
};

function minor(m, idxs) {

  function removeElement(index, m) {
    return m.slice(0, index).concat(m.slice(index + 1));
  }

  return removeElement(idxs.i, m.map(removeElement.bind(null, idxs.j)));
}

exports.determinant = determinant;<|endoftext|>


<commit_before>import styles from './EventDetail.css';
import React, { Component } from 'react';
import LoadingIndicator from 'app/components/LoadingIndicator';
import Image from 'app/components/Image';
import CommentView from 'app/components/Comments/CommentView';
import { FlexRow, FlexColumn, FlexItem } from 'app/components/FlexBox';
import Button from 'app/components/Button';
import Icon from 'app/components/Icon';
import Markdown from 'app/components/Markdown';
import JoinEventForm from './JoinEventForm';
import RegisteredCell from './RegisteredCell';
import RegisteredSummary from './RegisteredSummary';
import { AttendanceStatus } from 'app/components/UserAttendance';
import { sendMessage } from 'app/utils/websockets';

const InterestedButton = ({ value, onClick }) => {
  const [icon, text] = value
    ? ['check', 'Du er interessert']
    : ['plus', 'Jeg er interessert'];

  return (
    <Button onClick={onClick}>
      <Icon name={icon} />
      {' '}
      {text}
    </Button>
  );
};

/**
 *
 */
export type Props = {
  event: Event,
  eventId: Number,
  comments: Array,
  pools: Array,
  registrations: Array,
  currentRegistration: Object,
  loggedIn: boolean,
  isUserInterested: boolean,
  currentUser: Object,
  register: (eventId: Number) => Promise<*>,
  unregister: (eventId: Number, registrationId: Number) => Promise<*>,
  payment: (eventId: Number, token: string) => Promise<*>,
};

/**
 *
 */
export default class EventDetail extends Component {
  state = {
    joinFormOpen: false
  };

  props: Props;

  componentDidMount() {
    sendMessage('SUBSCRIBE', `event-${this.props.eventId}`);
  }

  componentWillUnmount() {
    sendMessage('UNSUBSCRIBE', `event-${this.props.eventId}`);
  }

  handleRegistration = ({ captchaResponse, feedback }) => {
    if (this.props.currentRegistration) {
      this.props.unregister(this.props.eventId, this.props.currentRegistration.id);
    } else {
      this.props.register(this.props.eventId, captchaResponse);
    }
    console.log(feedback);
  }

  toggleJoinFormOpen = () => {
    this.setState({ joinFormOpen: !this.state.joinFormOpen });
  };

  handleToken = (token) => {
    this.props.payment(this.props.event.id, token.id);
  }

  render() {
    const {
      event, loggedIn, currentUser, comments,
      pools, registrations, currentRegistration
    } = this.props;

    if (!event.id) {
      return <LoadingIndicator loading />;
    }

    return (

          <Image src={event.cover} />

        <FlexRow alignItems='center' justifyContent='space-between'>

{event.title}

          <InterestedButton value={this.props.isUserInterested} />
        </FlexRow>

        <FlexRow>
          <FlexColumn className={styles.description}>
            <Markdown>{event.text}</Markdown>
          </FlexColumn>
          <FlexColumn className={styles.meta}>

Starter om 3 timer

Finner sted i {event.location}

            {loggedIn && (
              <FlexItem>

Påmeldte:

                <FlexRow className={styles.registeredThumbnails}>
                  {registrations.slice(0, 10).map((reg) => (
                    <RegisteredCell key={reg.user.id} user={reg.user} />
                  ))}
                </FlexRow>
                <RegisteredSummary registrations={registrations} />
                <AttendanceStatus title='Påmeldte' pools={pools} />
              </FlexItem>
            )}
          </FlexColumn>
        </FlexRow>

        <FlexRow>
          {loggedIn && (
            <FlexColumn className={styles.join}>

                Bli med på dette arrangementet
                {' '}
                <Icon
                  name={this.state.joinFormOpen ? 'angle-up' : 'angle-right'}
                />

              {this.state.joinFormOpen && (

                  <JoinEventForm
                    event={event}
                    registration={currentRegistration}
                    currentUser={currentUser}
                    onToken={this.handleToken}
                    onSubmit={this.handleRegistration}
                  />

              )}
            </FlexColumn>
          )}

          <FlexColumn className={styles.openFor}>
            Åpent for

              {(pools || []).map((pool) => (

{pool.permissionGroups}

            ))}

          </FlexColumn>
        </FlexRow>

        <CommentView
          formEnabled
          user={currentUser}
          commentTarget={event.commentTarget}
          loggedIn={loggedIn}
          comments={comments}
        />

    );
  }
}
<commit_msg>Fix startTime and permissionGroups<commit_after>import styles from './EventDetail.css';
import React, { Component } from 'react';
import LoadingIndicator from 'app/components/LoadingIndicator';
import Image from 'app/components/Image';
import CommentView from 'app/components/Comments/CommentView';
import { FlexRow, FlexColumn, FlexItem } from 'app/components/FlexBox';
import Button from 'app/components/Button';
import Icon from 'app/components/Icon';
import Markdown from 'app/components/Markdown';
import JoinEventForm from './JoinEventForm';
import RegisteredCell from './RegisteredCell';
import RegisteredSummary from './RegisteredSummary';
import { AttendanceStatus } from 'app/components/UserAttendance';
import { sendMessage } from 'app/utils/websockets';
import Time from 'app/components/Time';

const InterestedButton = ({ value, onClick }) => {
  const [icon, text] = value
    ? ['check', 'Du er interessert']
    : ['plus', 'Jeg er interessert'];

  return (
    <Button onClick={onClick}>
      <Icon name={icon} />
      {' '}
      {text}
    </Button>
  );
};

/**
 *
 */
export type Props = {
  event: Event,
  eventId: Number,
  comments: Array,
  pools: Array,
  registrations: Array,
  currentRegistration: Object,
  loggedIn: boolean,
  isUserInterested: boolean,
  currentUser: Object,
  register: (eventId: Number) => Promise<*>,
  unregister: (eventId: Number, registrationId: Number) => Promise<*>,
  payment: (eventId: Number, token: string) => Promise<*>,
};

/**
 *
 */
export default class EventDetail extends Component {
  state = {
    joinFormOpen: false
  };

  props: Props;

  componentDidMount() {
    sendMessage('SUBSCRIBE', `event-${this.props.eventId}`);
  }

  componentWillUnmount() {
    sendMessage('UNSUBSCRIBE', `event-${this.props.eventId}`);
  }

  handleRegistration = ({ captchaResponse, feedback }) => {
    if (this.props.currentRegistration) {
      this.props.unregister(this.props.eventId, this.props.currentRegistration.id);
    } else {
      this.props.register(this.props.eventId, captchaResponse);
    }
    console.log(feedback);
  }

  toggleJoinFormOpen = () => {
    this.setState({ joinFormOpen: !this.state.joinFormOpen });
  };

  handleToken = (token) => {
    this.props.payment(this.props.event.id, token.id);
  }

  render() {
    const {
      event, loggedIn, currentUser, comments,
      pools, registrations, currentRegistration
    } = this.props;

    if (!event.id) {
      return <LoadingIndicator loading />;
    }

    return (

          <Image src={event.cover} />

        <FlexRow alignItems='center' justifyContent='space-between'>

{event.title}

          <InterestedButton value={this.props.isUserInterested} />
        </FlexRow>

        <FlexRow>
          <FlexColumn className={styles.description}>
            <Markdown>{event.text}</Markdown>
          </FlexColumn>
          <FlexColumn className={styles.meta}>

Starter <Time time={event.startTime} format='DD.MM.YYYY HH:mm' />

Finner sted i {event.location}

            {loggedIn && (
              <FlexItem>

Påmeldte:

                <FlexRow className={styles.registeredThumbnails}>
                  {registrations.slice(0, 10).map((reg) => (
                    <RegisteredCell key={reg.user.id} user={reg.user} />
                  ))}
                </FlexRow>
                <RegisteredSummary registrations={registrations} />
                <AttendanceStatus title='Påmeldte' pools={pools} />
              </FlexItem>
            )}
          </FlexColumn>
        </FlexRow>

        <FlexRow>
          {loggedIn && (
            <FlexColumn className={styles.join}>

                Bli med på dette arrangementet
                {' '}
                <Icon
                  name={this.state.joinFormOpen ? 'angle-up' : 'angle-right'}
                />

              {this.state.joinFormOpen && (

                  <JoinEventForm
                    event={event}
                    registration={currentRegistration}
                    currentUser={currentUser}
                    onToken={this.handleToken}
                    onSubmit={this.handleRegistration}
                  />

              )}
            </FlexColumn>
          )}

          <FlexColumn className={styles.openFor}>
            Åpent for

              {(pools || []).map((pool) => (
                pool.permissionGroups.map((group) => (
{group.name}
))
            ))}

          </FlexColumn>
        </FlexRow>

        <CommentView
          formEnabled
          user={currentUser}
          commentTarget={event.commentTarget}
          loggedIn={loggedIn}
          comments={comments}
        />

    );
  }
}
<|endoftext|>


<commit_before>'use strict';

angular.module('qldarchApp').controller('UserSettingsCtrl', function($scope, Auth, toaster, Uris, $http, $state) {
  $scope.user = {};
  $scope.user.username = Auth.user.username;
  $scope.user.email = Auth.user.email;

  $scope.update = function() {
    $scope.user.username = Auth.user.username;
    $scope.user.email = Auth.user.email;

    $http.put(Uris.JSON_ROOT + 'user', jQuery.param($scope.user), {
      headers : {
        'Content-Type' : 'application/x-www-form-urlencoded'
      }
    }).then(function() {
      // User saved
      $state.go('main');
      toaster.pop('success', 'Password Updated', 'You have successfully updated your password.');
    }, function() {
      toaster.pop('error', 'Error occured.', 'Sorry, we couldn\t update your password at this time');
    });
  };
});<commit_msg>updated change password service<commit_after>'use strict';

angular.module('qldarchApp').controller('UserSettingsCtrl', function($scope, Auth, toaster, Uris, $http, $state) {
  $scope.user = {};
  $scope.user.username = Auth.user.username;
  $scope.user.email = Auth.user.email;

  $scope.update = function() {
    $scope.user.username = Auth.user.username;
    $scope.user.email = Auth.user.email;

    $http.put(Uris.WS_ROOT + 'account/password', jQuery.param($scope.user), {
      headers : {
        'Content-Type' : 'application/x-www-form-urlencoded'
      }
    }).then(function() {
      // User saved
      $state.go('main');
      toaster.pop('success', 'Password Updated', 'You have successfully updated your password.');
    }, function() {
      toaster.pop('error', 'Error occured.', 'Sorry, we couldn\t update your password at this time');
    });
  };
});<|endoftext|>


<commit_before>/**
 * Created by rob on 2/17/2017.
 */
'use strict';

angular.module('eutilsUI').controller('searchController', ['$scope', 'dataBases', 'queryResults', function($scope, dataBases, queryResults) {

    dataBases.unshift("All DataBases");
    $scope.dataBases = dataBases;
    $scope.slectedDB = dataBases[0];

    $scope.searchDb = function(txt,slectedDB) {
         console.log(slectedDB);
        queryResults.getQueryResults(txt).query(function(response){
                console.log(response);
            },
            function(response){
                $scope.message = "Error: "+response.status + " " + response.statusText;
            });

         $scope.searchTxt = '';
    };

}]);
<commit_msg>add database to filter by start on transition to results<commit_after>/**
 * Created by rob on 2/17/2017.
 */
'use strict';

angular.module('eutilsUI').controller('searchController', ['$scope', 'dataBases', 'queryResults', function($scope, dataBases, queryResults) {

    dataBases.unshift("All DataBases");
    $scope.dataBases = dataBases;
    $scope.slectedDB = dataBases[0];

    $scope.searchDb = function(txt,slectedDB) {

        queryResults.getQueryResults(txt,slectedDB).query(function(response){
                console.log(response);
            },
            function(response){
                $scope.message = "Error: "+response.status + " " + response.statusText;
            });

         $scope.searchTxt = '';
    };

}])
    .controller('resultsController', ['$scope', function ($scope) {
          console.log('resultsController', $scope);
    }]);
<|endoftext|>


<commit_before>//  popup for ddsc including graph
//
//
//todo: move these classes to lizard.views
// Modal view that opens when clicking on a location

Lizard.Map.TimeserieView = Backbone.Marionette.ItemView.extend({
  template:function(model){
    return _.template($('#location-modal-timeserie').html(), {
      name: model.name,
      uuid: model.url.split("eries/")[1].split("/")[0],
      events: model.events,
    }, {variable: 'timeserie'});
  },
  uuid: null,
  events: {
    'click .graph-this': "drawGraph",
    'click .fav': 'toggleFavorite',
  },
  tagName: 'li',
  toggleFavorite: function() {
    var favorite = this.model.get('favorite');
    if(favorite) {
      this.model.set({"favorite": false});
      this.$el.find('i.icon-star').removeClass('icon-star').addClass('icon-star-empty');
    } else {
      this.model.set({"favorite": true});
      this.$el.find('i.icon-star-empty').removeClass('icon-star-empty').addClass('icon-star');
    }
    uuid = this.uuid;
    type = 'timeseries';
    Lizard.Utils.Favorites.toggleSelected(this.model);
  },
  // One Timeserie has many Events. An Events list is only
  // loaded when it is explcitly chosen, with caching.
  drawGraph: function(clickedon){
    // Gets the element that is clicked and it's datasets
    var data_url = clickedon.target.dataset.url;
    // $('#modal-graph-wrapper').removeClass('hidden');
    // $('#modal-graph-wrapper').find('.flot-graph').loadPlotData(data_url + '?eventsformat=flot');
  }
});

// Modal view that opens when clicking on a location
Lizard.Map.TimeseriesView = Backbone.Marionette.CollectionView.extend({
  collection: timeseriesCollection,
  itemView: Lizard.Map.TimeserieView,
  tagName: 'ul',
  onBeforeRender: function(){
    this.collection.url = settings.timeseries_url +
      '?location=' + this.locationuuid;
  }
});

Lizard.Map.ModalTimeserie = Lizard.Map.TimeserieView.extend({
  template:function(model){
    return _.template($('#location-modal-timeserie').html(), {
      name: model.name,
      uuid: model.url.split("eries/")[1].split("/")[0],
      events: model.events,
    }, {variable: 'timeserie'});
  },
  drawGraph: function(clickedon){
    // Gets the element that is clicked and it's datasets
    var data_url = clickedon.target.dataset.url;
    $('#modal-graph-wrapper').removeClass('hidden');
    $('#modal-graph-wrapper').find('.flot-graph').loadPlotData(data_url + '?eventsformat=flot');
  }
});

// Modal view that opens when clicking on a location
Lizard.Map.ModalTimeseriesView = Lizard.Map.TimeseriesView.extend({
  itemView: Lizard.Map.ModalTimeserie,
  onRender: function (model){
    $('#location-modal-label').html(this.location);
  }
});

Lizard.Popups.DdscTimeseries = {
  modalInfo: function (e){
    var marker = e.target;
    var model = marker.valueOf().options.bbModel;
    $('#modal-graph-wrapper').find('.flot-graph').empty();
    modalView = new Lizard.Map.ModalTimeseriesView();
    modalView.locationuuid = model.attributes.uuid;
    modalView.location = model.attributes.name;
    timeseriesCollection.reset();
    timeseriesCollection.fetch({cache: true});
    Lizard.mapView.modalitems.show(modalView.render());
    $('#location-modal').modal();
  },
  getPopupContent: function (marker){
    var model = marker.valueOf().options.bbModel;
    popupView = new Lizard.Map.TimeseriesView();
    popupView.locationuuid = model.attributes.uuid;
    popupView.location = model.attributes.name;
    timeseriesCollection.reset();
    timeseriesCollection.fetch({async: false,cache: true});
    popupContent = popupView.render().el;
    return popupContent;
  },
  updateInfo: function (e) {
    var marker = e.target;
    console.log(e);
    // props = marker.valueOf().options;
    // e.layer._map._controlContainer.innerHTML = '
Datapunt
' + (props ?
    //         '' + props.name + '
' +
    //         'Punt: ' + props.code
    //         : 'Zweef over de punten');
  },
  selectforCollage: function(e) {
    var marker = e.target;
    var properties = marker.valueOf().options;
    var wsitem = properties.bbModel;
    wsitem.set({title: wsitem.attributes.name});
    Collage.add(wsitem);
  }
};<commit_msg>This didn't work with the url formation when specifying page_size. An ampersand did the trick.<commit_after>//  popup for ddsc including graph
//
//
//todo: move these classes to lizard.views
// Modal view that opens when clicking on a location

Lizard.Map.TimeserieView = Backbone.Marionette.ItemView.extend({
  template:function(model){
    return _.template($('#location-modal-timeserie').html(), {
      name: model.name,
      uuid: model.url.split("eries/")[1].split("/")[0],
      events: model.events,
    }, {variable: 'timeserie'});
  },
  uuid: null,
  events: {
    'click .graph-this': "drawGraph",
    'click .fav': 'toggleFavorite',
  },
  tagName: 'li',
  toggleFavorite: function() {
    var favorite = this.model.get('favorite');
    if(favorite) {
      this.model.set({"favorite": false});
      this.$el.find('i.icon-star').removeClass('icon-star').addClass('icon-star-empty');
    } else {
      this.model.set({"favorite": true});
      this.$el.find('i.icon-star-empty').removeClass('icon-star-empty').addClass('icon-star');
    }
    uuid = this.uuid;
    type = 'timeseries';
    Lizard.Utils.Favorites.toggleSelected(this.model);
  },
  // One Timeserie has many Events. An Events list is only
  // loaded when it is explcitly chosen, with caching.
  drawGraph: function(clickedon){
    // Gets the element that is clicked and it's datasets
    var data_url = clickedon.target.dataset.url;
    // $('#modal-graph-wrapper').removeClass('hidden');
    // $('#modal-graph-wrapper').find('.flot-graph').loadPlotData(data_url + '?eventsformat=flot');
  }
});

// Modal view that opens when clicking on a location
Lizard.Map.TimeseriesView = Backbone.Marionette.CollectionView.extend({
  collection: timeseriesCollection,
  itemView: Lizard.Map.TimeserieView,
  tagName: 'ul',
  onBeforeRender: function(){
    this.collection.url = settings.timeseries_url +
      '&location=' + this.locationuuid;
  }
});

Lizard.Map.ModalTimeserie = Lizard.Map.TimeserieView.extend({
  template:function(model){
    return _.template($('#location-modal-timeserie').html(), {
      name: model.name,
      uuid: model.url.split("eries/")[1].split("/")[0],
      events: model.events,
    }, {variable: 'timeserie'});
  },
  drawGraph: function(clickedon){
    // Gets the element that is clicked and it's datasets
    var data_url = clickedon.target.dataset.url;
    $('#modal-graph-wrapper').removeClass('hidden');
    $('#modal-graph-wrapper').find('.flot-graph').loadPlotData(data_url + '?eventsformat=flot');
  }
});

// Modal view that opens when clicking on a location
Lizard.Map.ModalTimeseriesView = Lizard.Map.TimeseriesView.extend({
  itemView: Lizard.Map.ModalTimeserie,
  onRender: function (model){
    $('#location-modal-label').html(this.location);
  }
});

Lizard.Popups.DdscTimeseries = {
  modalInfo: function (e){
    var marker = e.target;
    var model = marker.valueOf().options.bbModel;
    $('#modal-graph-wrapper').find('.flot-graph').empty();
    modalView = new Lizard.Map.ModalTimeseriesView();
    modalView.locationuuid = model.attributes.uuid;
    modalView.location = model.attributes.name;
    timeseriesCollection.reset();
    timeseriesCollection.fetch({cache: true});
    Lizard.mapView.modalitems.show(modalView.render());
    $('#location-modal').modal();
  },
  getPopupContent: function (marker){
    var model = marker.valueOf().options.bbModel;
    popupView = new Lizard.Map.TimeseriesView();
    popupView.locationuuid = model.attributes.uuid;
    popupView.location = model.attributes.name;
    timeseriesCollection.reset();
    timeseriesCollection.fetch({async: false,cache: true});
    popupContent = popupView.render().el;
    return popupContent;
  },
  updateInfo: function (e) {
    var marker = e.target;
    console.log(e);
    // props = marker.valueOf().options;
    // e.layer._map._controlContainer.innerHTML = '
Datapunt
' + (props ?
    //         '' + props.name + '
' +
    //         'Punt: ' + props.code
    //         : 'Zweef over de punten');
  },
  selectforCollage: function(e) {
    var marker = e.target;
    var properties = marker.valueOf().options;
    var wsitem = properties.bbModel;
    wsitem.set({title: wsitem.attributes.name});
    Collage.add(wsitem);
  }
};<|endoftext|>


<commit_before>$(document).ready(function () {
    // planet tabs
    $(".planets" ).tabs();

    function drawCanvas() {
        $('.planet').each(function () {
            var planet = $(this);
            // canvas
            var canvas = planet.find('canvas.planetCanvas').get(0),
                size_in_sky = $(this).data('size'), // radius of sky
                color = $(this).data('color'),
                radius = size_in_sky/90*(canvas.width*1.5);
                size_of_sol = 0.53/90*(canvas.width*1.5);

            canvas.getContext("2d").clearRect(0,0,canvas.width,canvas.height);
            drawSky(canvas, {
                startRadius: radius,
                endRadius: radius*15
            });
            drawStar(canvas, {radius: radius, color: color});
            drawOutline(canvas, {radius: size_of_sol});

        });
    }

    // resize the canvas
    $(window).resize(function () {
        var planets = $('.planet');
        planets.find('canvas.planetCanvas').width(planets.filter(':visible:first').width())
        //planets.find('canvas.planetCanvas').height($(window).height()-planets.filter(':visible:first').offset().top)
        drawCanvas();
    }).resize();

    // initialise planet
    $('.planet').each(function () {
        var planet = $(this);

        // Age
        var period = $(this).data('period'),
            period_tangle = new Tangle(planet.get(0), {
            initialize: function () {
                            this.age_on_earth = 15;
                        },
            update:     function () {
                            this.age_on_planet = this.age_on_earth * (365.256363 / period);
                        }
        });

        // Gravity
        var gravity = $(this).data('gravity'),
            gravity_tangle = new Tangle(planet.get(0), {
            initialize: function () {
                            this.weight_on_earth = 50;
                        },
            update:     function () {
                            this.vertical_jump = 35 * (9.81/gravity);
                            this.weight_on_planet = (this.weight_on_earth / 9.81) * gravity;
                            // A cow weighs 360kg, a chicken weighs 1.5 kg
                            this.weight_in_cows = (this.weight_on_planet / 360);
                            this.extra_weight_in_chickens = (this.weight_on_planet % 360)/1.5
                            this.weight_in_babies = this.weight_on_planet / 3.3
                            if(this.weight_in_cows > 1){
                                this.equiv_weight = Math.floor(this.weight_in_cows) + " cow"
                                if(this.weight_in_cows > 2){
                                    this.equiv_weight = this.equiv_weight + "s"
                                }
                                if(Math.floor(this.extra_weight_in_chickens) > 0){
                                    this.equiv_weight = this.equiv_weight + " and " +
                                        Math.floor(this.extra_weight_in_chickens) + " chickens"
                                }

                            } else {
                                this.equiv_weight = Math.round(this.weight_in_babies) + " newborn babies"
                            }
                         }
        });

    });
});

// Draw the sky with radial gradient from the center of the canvas
// Options:
//  startX, startY, startRadius, endX, endY, endRadius
function drawSky(canvas, options) {
    var context = canvas.getContext("2d");

    var centerX = canvas.width / 2;
    var centerY = canvas.height / 2;

    //
    options = options || {};
    if (options.startX == null) { options.startX = centerX; }
    if (options.startY == null) { options.startY = centerY; }
    if (options.startRadius == null) { options.startRadius = 0; }
    if (options.startColor == null) { options.startColor = "#8ED6FF"; }  // light blue
    if (options.endX == null) { options.endX = centerX; }
    if (options.endY == null) { options.endY = centerY; }
    if (options.endRadius == null) { options.endRadius = Math.max(canvas.width, canvas.height);; }
    if (options.endColor == null) { options.endColor = "#004CB3"; }  // dark blue

    // Rectangle for gradient
    context.beginPath();
    context.rect(0, 0, canvas.width, canvas.height);

    // Gradient
    var outerRadius =  Math.min(canvas.width, canvas.height);
    var grd = context.createRadialGradient(
            options.startX, options.startY, options.startRadius,
            options.endX, options.endY, options.endRadius);
    grd.addColorStop(0, options.startColor);
    grd.addColorStop(1, options.endColor);
    context.fillStyle = grd;
    context.fill();
}
// Draw a circle with the given radius and color.
// drawStar(canvas, {x: 200, y: 100, radius: 70, color:'#FFFFFF'});
function drawStar(canvas, options) {
    var context = canvas.getContext("2d");

    var centerX = canvas.width / 2;
    var centerY = canvas.height / 2;

    options = options || {};
    if (options.x==null) {
        options.x = centerX;
    }

    if (options.y == null) {
        options.y = centerY;
    }

    // circle
    context.beginPath();
    var arc  = context.arc(options.x, options.y, options.radius, 0, 2 * Math.PI, false);
    context.fillStyle = options.color
    context.fill();
    context.lineWidth = 1;
    context.strokeStyle = options.color
    context.stroke();

    return arc;
}

// Draw a circle with the given radius (outline only).
// drawOutline(canvas, {radius: 70, color:'#FFFFFF'});
function drawOutline(canvas, options) {
    var context = canvas.getContext("2d");

    var centerX = canvas.width / 2;
    var centerY = canvas.height / 2;

    if (options.x==null) {
        options.x = centerX;
    }

    if (options.y == null) {
        options.y = centerY;
    }

    // circle
    context.beginPath();
    var arc  = context.arc(options.x, options.y, options.radius, 0, 2 * Math.PI, false);
    context.fillStyle = "None";
    context.fill();
    context.lineWidth = 1;
    context.strokeStyle = "#000000"
    context.stroke();

    return arc;
}
<commit_msg>Improve rounding of weight<commit_after>$(document).ready(function () {
    // planet tabs
    $(".planets" ).tabs();

    function drawCanvas() {
        $('.planet').each(function () {
            var planet = $(this);
            // canvas
            var canvas = planet.find('canvas.planetCanvas').get(0),
                size_in_sky = $(this).data('size'), // radius of sky
                color = $(this).data('color'),
                radius = size_in_sky/90*(canvas.width*1.5);
                size_of_sol = 0.53/90*(canvas.width*1.5);

            canvas.getContext("2d").clearRect(0,0,canvas.width,canvas.height);
            drawSky(canvas, {
                startRadius: radius,
                endRadius: radius*15
            });
            drawStar(canvas, {radius: radius, color: color});
            drawOutline(canvas, {radius: size_of_sol});

        });
    }

    // resize the canvas
    $(window).resize(function () {
        var planets = $('.planet');
        planets.find('canvas.planetCanvas').width(planets.filter(':visible:first').width())
        //planets.find('canvas.planetCanvas').height($(window).height()-planets.filter(':visible:first').offset().top)
        drawCanvas();
    }).resize();

    // initialise planet
    $('.planet').each(function () {
        var planet = $(this);

        // Age
        var period = $(this).data('period'),
            period_tangle = new Tangle(planet.get(0), {
            initialize: function () {
                            this.age_on_earth = 15;
                        },
            update:     function () {
                            this.age_on_planet = this.age_on_earth * (365.256363 / period);
                        }
        });

        // Gravity
        var gravity = $(this).data('gravity'),
            gravity_tangle = new Tangle(planet.get(0), {
            initialize: function () {
                            this.weight_on_earth = 50;
                        },
            update:     function () {
                            this.vertical_jump = 35 * (9.81/gravity);
                            this.weight_on_planet = Math.round((this.weight_on_earth / 9.81) * gravity);
                            // A cow weighs 360kg, a chicken weighs 1.5 kg
                            this.weight_in_cows = (this.weight_on_planet / 360);
                            this.extra_weight_in_chickens = (this.weight_on_planet % 360) / 1.5
                            this.weight_in_babies = this.weight_on_planet / 3.3
                            if(this.weight_in_cows > 1){
                                this.equiv_weight = Math.floor(this.weight_in_cows) + " cow"
                                if(this.weight_in_cows > 2){
                                    this.equiv_weight = this.equiv_weight + "s"
                                }
                                if(Math.floor(this.extra_weight_in_chickens) > 0){
                                    this.equiv_weight = this.equiv_weight + " and " +
                                        Math.floor(this.extra_weight_in_chickens) + " chickens"
                                }

                            } else {
                                this.equiv_weight = Math.round(this.weight_in_babies) + " newborn babies"
                            }
                         }
        });

    });
});

// Draw the sky with radial gradient from the center of the canvas
// Options:
//  startX, startY, startRadius, endX, endY, endRadius
function drawSky(canvas, options) {
    var context = canvas.getContext("2d");

    var centerX = canvas.width / 2;
    var centerY = canvas.height / 2;

    //
    options = options || {};
    if (options.startX == null) { options.startX = centerX; }
    if (options.startY == null) { options.startY = centerY; }
    if (options.startRadius == null) { options.startRadius = 0; }
    if (options.startColor == null) { options.startColor = "#8ED6FF"; }  // light blue
    if (options.endX == null) { options.endX = centerX; }
    if (options.endY == null) { options.endY = centerY; }
    if (options.endRadius == null) { options.endRadius = Math.max(canvas.width, canvas.height);; }
    if (options.endColor == null) { options.endColor = "#004CB3"; }  // dark blue

    // Rectangle for gradient
    context.beginPath();
    context.rect(0, 0, canvas.width, canvas.height);

    // Gradient
    var outerRadius =  Math.min(canvas.width, canvas.height);
    var grd = context.createRadialGradient(
            options.startX, options.startY, options.startRadius,
            options.endX, options.endY, options.endRadius);
    grd.addColorStop(0, options.startColor);
    grd.addColorStop(1, options.endColor);
    context.fillStyle = grd;
    context.fill();
}
// Draw a circle with the given radius and color.
// drawStar(canvas, {x: 200, y: 100, radius: 70, color:'#FFFFFF'});
function drawStar(canvas, options) {
    var context = canvas.getContext("2d");

    var centerX = canvas.width / 2;
    var centerY = canvas.height / 2;

    options = options || {};
    if (options.x==null) {
        options.x = centerX;
    }

    if (options.y == null) {
        options.y = centerY;
    }

    // circle
    context.beginPath();
    var arc  = context.arc(options.x, options.y, options.radius, 0, 2 * Math.PI, false);
    context.fillStyle = options.color
    context.fill();
    context.lineWidth = 1;
    context.strokeStyle = options.color
    context.stroke();

    return arc;
}

// Draw a circle with the given radius (outline only).
// drawOutline(canvas, {radius: 70, color:'#FFFFFF'});
function drawOutline(canvas, options) {
    var context = canvas.getContext("2d");

    var centerX = canvas.width / 2;
    var centerY = canvas.height / 2;

    if (options.x==null) {
        options.x = centerX;
    }

    if (options.y == null) {
        options.y = centerY;
    }

    // circle
    context.beginPath();
    var arc  = context.arc(options.x, options.y, options.radius, 0, 2 * Math.PI, false);
    context.fillStyle = "None";
    context.fill();
    context.lineWidth = 1;
    context.strokeStyle = "#000000"
    context.stroke();

    return arc;
}
<|endoftext|>