<commit_before>/* eslint-disable jsdoc/require-param-type,jsdoc/require-param-description */
var _ = require('lodash'),
    core = require('./core'),
    Emitter = require('events'),
    inherits = require('inherits'),
    now = require('performance-now'),
    sdk = require('postman-collection'),
    requests = require('./request-wrapper'),
    dryRun = require('./dry-run'),

    RESPONSE_START_EVENT_BASE = 'response.start.',
    RESPONSE_END_EVENT_BASE = 'response.end.',

    RESPONSE_START = 'responseStart',
    RESPONSE_END = 'response',

    ERROR_RESTRICTED_ADDRESS = 'NETERR: getaddrinfo ENOTFOUND ',

    /**
     * Headers which get overwritten by the requester.
     *
     * @private
     * @const
     * @type {Object}
     */
    OVERWRITTEN_HEADERS = {
        cookie: true, // cookies get appended with `;`
        'content-length': true
    },

    /**
     * Creates a sdk compatible cookie from a tough-cookie compatible cookie.
     *
     * @param cookie
     * @returns {Object}
     */
    toPostmanCookie = function (cookie) {
        var expires = cookie.expiryTime();

        cookie.toJSON && (cookie = cookie.toJSON());

        return new sdk.Cookie({
            name: cookie.key,
            value: cookie.value,
            expires: Number.isFinite(expires) ? new Date(expires) : null,
            maxAge: cookie.maxAge,
            domain: cookie.domain,
            path: cookie.path,
            secure: cookie.secure,
            httpOnly: cookie.httpOnly,
            hostOnly: cookie.hostOnly,
            extensions: cookie.extensions
        });
    },

    /**
     * This method is used in conjunction with _.transform method to convert multi-value headers to multiple single
     * value headers
     *
     * @param  {Array} acc
     * @param  {Array|String} val
     * @param  {String} key
     * @return {Object}
     */
    transformMultiValueHeaders = function (acc, val, key) {
        var i, ii;

        if (Array.isArray(val)) {
            for (i = 0, ii = val.length; i < ii; i++) {
                acc.push({
                    key: key,
                    value: val[i]
                });
            }
        }
        else {
            acc.push({
                key: key,
                value: val
            });
        }
    },

    /**
     * Calculate request timings offset by adding runtime overhead which
     * helps to determine request prepare and process time taken.
     *
     * @param {Number} runtimeTimer - Runtime request start HR time
     * @param {Number} requestTimer - Request start HR time
     * @param {Object} timings - Request timings offset
     * @returns {Object}
     */
    calcTimingsOffset = function (runtimeTimer, requestTimer, timings) {
        if (!(runtimeTimer && requestTimer && timings)) { return; }

        // runtime + postman-request initialization time
        var initTime = requestTimer - runtimeTimer,
            offset = {
                request: initTime
            };

        // add initialization overhead to request offsets
        _.forOwn(timings, function (value, key) {
            offset[key] = value + initTime;
        });

        // total time taken by runtime to get the response
        // @note if offset.end is missing, that means request is not complete.
        //       this is used to calculate timings on responseStart.
        if (offset.end) {
            offset.done = now() - runtimeTimer;
        }

        return offset;
    },

    Requester;

/**
 * Creates a new Requester, which is used to make HTTP(s) requests.
 *
 * @param trace
 * @param options
 * @param {Boolean} [options.keepAlive=true] Optimizes HTTP connections by keeping them alive, so that new requests
 * to the same host are made over the same underlying TCP connection.
 * @param {CookieJar} [options.cookieJar] A cookie jar to use with Node requests.
 * @param {Boolean} [options.strictSSL]
 * @param {Boolean} [options.followRedirects=true] If false, returns a 301/302 as the response code
 * instead of following the redirect
 * @note `options.keepAlive` is only supported in Node.
 * @note `options.cookieJar` is only supported in Node.
 *
 * @constructor
 */
inherits(Requester = function (trace, options) {
    this.options = options || {};

    // protect the timeout value from being non-numeric or infinite
    if (!_.isFinite(this.options.timeout)) {
        this.options.timeout = undefined;
    }

    this.trace = trace;
    Requester.super_.call(this);
}, Emitter);

_.assign(Requester.prototype, /** @lends Requester.prototype */ {

    /**
     * Perform an HTTP request.
     *
     * @param {String} id
     * @param {Request} request
     * @param {Object} protocolProfileBehavior
     * @param {Function} callback
     */
    request (id, request, protocolProfileBehavior, callback) {
        var self = this,
            hostname,
            cookieJar,
            requestOptions,
            networkOptions = self.options.network || {},
            startTime = Date.now(),
            startTimer = now(), // high-resolution time
            cookies = [],
            responseHeaders = [],
            responseJSON = {},

            // keep track of `responseStart` and `response` triggers
            _responseStarted = false,
            _responseEnded = false,
            _responseData = {},

            // Refer: https://github.com/postmanlabs/postman-runtime/blob/v7.14.0/docs/history.md
            getExecutionHistory = function (debugInfo) {
                var history = {
                        execution: {
                            verbose: Boolean(requestOptions.verbose),
                            sessions: {},
                            data: []
                        }
                    },
                    executionData = [],
                    requestSessions = {};

                if (!Array.isArray(debugInfo)) {
                    return history;
                }

                // prepare history from request debug data
                debugInfo.forEach(function (debugData) {
                    if (!debugData) { return; }

                    // @todo cache connection sessions and fetch reused session
                    // from the requester pool.
                    if (debugData.session && !requestSessions[debugData.session.id]) {
                        requestSessions[debugData.session.id] = debugData.session.data;
                    }

                    executionData.push({
                        request: debugData.request,
                        response: debugData.response,
                        timings: debugData.timings && {
                            // runtime start time
                            start: startTime,
                            // request start time
                            requestStart: debugData.timingStart,
                            // offsets calculated are relative to runtime start time
                            offset: calcTimingsOffset(startTimer, debugData.timingStartTimer, debugData.timings)
                        },
                        session: debugData.session && {
                            id: debugData.session.id,
                            // is connection socket reused
                            reused: debugData.session.reused
                        }
                    });
                });

                // update history object
                history.execution.data = executionData;
                history.execution.sessions = requestSessions;

                return history;
            },

            /**
             * Add the missing/system headers in the request object
             *
             * @param {Object[]} headers
             */
            addMissingRequestHeaders = function (headers) {
                _.forEach(headers, function (header) {
                    var lowerCasedKey = header.key.toLowerCase();

                    // update headers which gets overwritten by the requester
                    if (OVERWRITTEN_HEADERS[lowerCasedKey]) {
                        if (Array.isArray(_.get(request.headers, ['reference', lowerCasedKey]))) {
                            request.headers.remove(header.key);
                        }

                        request.headers.upsert({
                            key: header.key,
                            value: header.value,
                            system: true
                        });
                    }
                });
            },

            /**
             * Helper function to trigger `callback` and complete the request function
             *
             * @param {Error} error - error while requesting
             * @param {Response} response - SDK Response instance
             * @param {Object} history - Request-Response History
             */
            onEnd = function (error, response, history) {
                self.emit(RESPONSE_END_EVENT_BASE + id, error, self.trace.cursor,
                    self.trace, response, request, cookies, history);

                return callback(error, response, request, cookies, history);
            },

            /**
             * Helper function to keep track of `responseStart` and `response`
             * triggers to make they are emitted in correct order.
             *
             * @todo fix requester control flow to remove this hack!
             *  this is required because CookieJar.getCookies is async method
             *  and by that time postman-request ends the request, which affects
             *  request post-send helpers because `response.start` event is not
             *  emitted on time and shared variables `cookies`, `responseJSON`,
             *  and, `responseHeaders` are initialized in onStart function.
             *
             * @param {String} trigger - trigger name
             * @param {Response} response - SDK Response instance
             * @param {Object} history - Request-Response History
             */
            onComplete = function (trigger, response, history) {
                if (trigger === RESPONSE_START) {
                    // set flag for responseStart callback
                    _responseStarted = true;

                    // if response is ended, end the response using cached data
                    if (_responseEnded) {
                        onEnd(null, _responseData.response, _responseData.history);
                    }

                    // bail out and wait for response end if not ended already
                    return;
                }

                // if response started, don't wait and end the response
                if (_responseStarted) {
                    onEnd(null, response, history);

                    return;
                }

                // wait for responseStart and cache response callback data
                _responseEnded = true;
                _responseData = {
                    response,
                    history
                };
            },

            /**
             * Helper function to trigger `responseStart` callback and
             * - transform postman-request response instance to SDK Response
             * - filter cookies
             * - filter response headers
             * - add missing request headers
             *
             * @param {Object} response - Postman-Request response instance
             */
            onStart = function (response) {
                var responseStartEventName = RESPONSE_START_EVENT_BASE + id,
                    executionData,
                    initialRequest,
                    finalRequest,
                    sdkResponse,
                    history,
                    done = function () {
                        // emit the response.start event which eventually
                        // triggers responseStart callback
                        self.emit(responseStartEventName, null, sdkResponse, request, cookies, history);

                        // trigger completion of responseStart
                        onComplete(RESPONSE_START);
                    };

                // @todo get rid of jsonifyResponse
                responseJSON = core.jsonifyResponse(response, requestOptions);

                // transform response headers to SDK compatible HeaderList
                responseHeaders = _.transform(responseJSON.headers, transformMultiValueHeaders, []);

                // initialize SDK Response instance
                sdkResponse = new sdk.Response({
                    status: response && response.statusMessage,
                    code: responseJSON.statusCode,
                    header: responseHeaders
                });

                // prepare history from request debug data
                history = getExecutionHistory(_.get(response, 'request._debug'));

                // get the initial and final (on redirect) request from history
                executionData = _.get(history, 'execution.data') || [];
                initialRequest = _.get(executionData, '[0].request') || {};
                finalRequest = executionData.length > 1 ?
                    // get final redirect
                    _.get(executionData, [executionData.length - 1, 'request']) :
                    // no redirects
                    initialRequest;

                // add missing request headers so that they get bubbled up into the UI
                addMissingRequestHeaders(initialRequest.headers);

                // pull out cookies from the cookie jar, and make them chrome compatible.
                if (cookieJar && _.isFunction(cookieJar.getCookies)) {
                    // get cookies set for the final request URL
                    cookieJar.getCookies(finalRequest.href, function (err, cookiesFromJar) {
                        if (err) {
                            return done();
                        }

                        cookies = _.transform(cookiesFromJar, function (acc, cookie) {
                            acc.push(toPostmanCookie(cookie));
                        }, []);

                        cookies = new sdk.CookieList(null, cookies);

                        done();
                    });
                }
                else {
                    cookies = new sdk.CookieList(null, []);
                    done();
                }
            };

        // at this point the request could have come from collection, auth or sandbox
        // we can't trust the integrity of this request
        // bail out if request url is empty
        if (!(request && request.url && request.url.toString && request.url.toString())) {
            return onEnd(new Error('runtime:extensions~request: request url is empty'));
        }

        cookieJar = self.options.cookieJar;
        requestOptions = core.getRequestOptions(request, self.options, protocolProfileBehavior);

        // update url with the final encoded url
        // @note this mutates the request object which will be passed in request
        // and response callbacks
        request.url.update(requestOptions.url.href);
        hostname = request.url.getHost();

        // check if host is on the `restrictedAddresses`
        if (networkOptions.restrictedAddresses && core.isAddressRestricted(hostname, networkOptions)) {
            return onEnd(new Error(ERROR_RESTRICTED_ADDRESS + hostname));
        }

        return requests(request, requestOptions, onStart, function (err, res, resBody, debug) {
            // prepare history from request debug data
            var history = getExecutionHistory(debug),
                responseTime,
                response;

            if (err) {
                // bubble up http errors
                // @todo - Should we send an empty sdk Response here?
                //
                // Sending `history` object even in case of error
                return onEnd(err, undefined, history);
            }

            // Calculate the time taken for us to get the response.
            responseTime = Date.now() - startTime;

            if (res && res.timings) {
                // update response time to actual response end time
                // of the final request in the redirect chain.
                responseTime = Math.ceil(res.timings.end);
            }

            if (resBody && resBody instanceof ArrayBuffer) {
                resBody = Buffer.from(resBody);
            }

            // Response in the SDK format
            // @todo reuse same response instance used for responseStart callback
            response = new sdk.Response({
                code: responseJSON.statusCode,
                status: res && res.statusMessage,
                header: responseHeaders,
                stream: resBody,
                responseTime: responseTime
            });

            onComplete(RESPONSE_END, response, history);
        });
    },

    /**
     * Removes all current event listeners on the requester, and makes it ready for garbage collection :).
     *
     * @param {Function=} cb - Optional callback to be called on disposal
     *
     * @todo - In the future, when the requester manages its own connections etc, close them all here.
     */
    dispose (cb) {
        // This is safe for us, because we do not use wait on events. (i.e, no part of Runtime ever waits on
        // any event to occur). We rely on callbacks for that, only choosing to use events as a way of streaming
        // information outside runtime.
        this.removeAllListeners();

        _.isFunction(cb) && cb();
    }
});

_.assign(Requester, /** @lends Requester */ {
    /**
     * Asynchronously create a new requester.
     *
     * @param trace
     * @param trace.type - type of requester to return (for now, just http)
     * @param trace.source - information about who needs this requester, e.g Auth, etc.
     * @param trace.cursor - the cursor
     * @param options
     * @param callback
     * @returns {*}
     */
    create (trace, options, callback) {
        return callback(null, new Requester(trace, options));
    },

    /**
     * A helper method to dry run the given request instance.
     * It returns the cloned request instance with the system added properties.
     *
     * @param {Request} request
     * @param {Object} options
     * @param {Object} options.cookieJar
     * @param {Object} options.protocolProfileBehavior
     * @param {Object} options.implicitCacheControl
     * @param {Object} options.implicitTraceHeader
     * @param {Function} done
     */
    dryRun
});

module.exports.Requester = Requester;
<commit_msg>Remove inherits dependency<commit_after>/* eslint-disable jsdoc/require-param-type,jsdoc/require-param-description */
var _ = require('lodash'),
    core = require('./core'),
    EventEmitter = require('events'),
    now = require('performance-now'),
    sdk = require('postman-collection'),
    requests = require('./request-wrapper'),
    dryRun = require('./dry-run'),

    RESPONSE_START_EVENT_BASE = 'response.start.',
    RESPONSE_END_EVENT_BASE = 'response.end.',

    RESPONSE_START = 'responseStart',
    RESPONSE_END = 'response',

    ERROR_RESTRICTED_ADDRESS = 'NETERR: getaddrinfo ENOTFOUND ',

    /**
     * Headers which get overwritten by the requester.
     *
     * @private
     * @const
     * @type {Object}
     */
    OVERWRITTEN_HEADERS = {
        cookie: true, // cookies get appended with `;`
        'content-length': true
    },

    /**
     * Creates a sdk compatible cookie from a tough-cookie compatible cookie.
     *
     * @param cookie
     * @returns {Object}
     */
    toPostmanCookie = function (cookie) {
        var expires = cookie.expiryTime();

        cookie.toJSON && (cookie = cookie.toJSON());

        return new sdk.Cookie({
            name: cookie.key,
            value: cookie.value,
            expires: Number.isFinite(expires) ? new Date(expires) : null,
            maxAge: cookie.maxAge,
            domain: cookie.domain,
            path: cookie.path,
            secure: cookie.secure,
            httpOnly: cookie.httpOnly,
            hostOnly: cookie.hostOnly,
            extensions: cookie.extensions
        });
    },

    /**
     * This method is used in conjunction with _.transform method to convert multi-value headers to multiple single
     * value headers
     *
     * @param  {Array} acc
     * @param  {Array|String} val
     * @param  {String} key
     * @return {Object}
     */
    transformMultiValueHeaders = function (acc, val, key) {
        var i, ii;

        if (Array.isArray(val)) {
            for (i = 0, ii = val.length; i < ii; i++) {
                acc.push({
                    key: key,
                    value: val[i]
                });
            }
        }
        else {
            acc.push({
                key: key,
                value: val
            });
        }
    },

    /**
     * Calculate request timings offset by adding runtime overhead which
     * helps to determine request prepare and process time taken.
     *
     * @param {Number} runtimeTimer - Runtime request start HR time
     * @param {Number} requestTimer - Request start HR time
     * @param {Object} timings - Request timings offset
     * @returns {Object}
     */
    calcTimingsOffset = function (runtimeTimer, requestTimer, timings) {
        if (!(runtimeTimer && requestTimer && timings)) { return; }

        // runtime + postman-request initialization time
        var initTime = requestTimer - runtimeTimer,
            offset = {
                request: initTime
            };

        // add initialization overhead to request offsets
        _.forOwn(timings, function (value, key) {
            offset[key] = value + initTime;
        });

        // total time taken by runtime to get the response
        // @note if offset.end is missing, that means request is not complete.
        //       this is used to calculate timings on responseStart.
        if (offset.end) {
            offset.done = now() - runtimeTimer;
        }

        return offset;
    };

class Requester extends EventEmitter {
    /**
     * Creates a new Requester, which is used to make HTTP(s) requests.
     *
     * @param trace
     * @param options
     * @param {Boolean} [options.keepAlive=true] Optimizes HTTP connections by keeping them alive, so that new requests
     * to the same host are made over the same underlying TCP connection.
     * @param {CookieJar} [options.cookieJar] A cookie jar to use with Node requests.
     * @param {Boolean} [options.strictSSL]
     * @param {Boolean} [options.followRedirects=true] If false, returns a 301/302 as the response code
     * instead of following the redirect
     * @note `options.keepAlive` is only supported in Node.
     * @note `options.cookieJar` is only supported in Node.
     */
    constructor (trace, options) {
        super();

        this.trace = trace;
        this.options = options || {};

        // protect the timeout value from being non-numeric or infinite
        if (!_.isFinite(this.options.timeout)) {
            this.options.timeout = undefined;
        }
    }

    /**
     * Perform an HTTP request.
     *
     * @param {String} id
     * @param {Request} request
     * @param {Object} protocolProfileBehavior
     * @param {Function} callback
     */
    request (id, request, protocolProfileBehavior, callback) {
        var self = this,
            hostname,
            cookieJar,
            requestOptions,
            networkOptions = self.options.network || {},
            startTime = Date.now(),
            startTimer = now(), // high-resolution time
            cookies = [],
            responseHeaders = [],
            responseJSON = {},

            // keep track of `responseStart` and `response` triggers
            _responseStarted = false,
            _responseEnded = false,
            _responseData = {},

            // Refer: https://github.com/postmanlabs/postman-runtime/blob/v7.14.0/docs/history.md
            getExecutionHistory = function (debugInfo) {
                var history = {
                        execution: {
                            verbose: Boolean(requestOptions.verbose),
                            sessions: {},
                            data: []
                        }
                    },
                    executionData = [],
                    requestSessions = {};

                if (!Array.isArray(debugInfo)) {
                    return history;
                }

                // prepare history from request debug data
                debugInfo.forEach(function (debugData) {
                    if (!debugData) { return; }

                    // @todo cache connection sessions and fetch reused session
                    // from the requester pool.
                    if (debugData.session && !requestSessions[debugData.session.id]) {
                        requestSessions[debugData.session.id] = debugData.session.data;
                    }

                    executionData.push({
                        request: debugData.request,
                        response: debugData.response,
                        timings: debugData.timings && {
                            // runtime start time
                            start: startTime,
                            // request start time
                            requestStart: debugData.timingStart,
                            // offsets calculated are relative to runtime start time
                            offset: calcTimingsOffset(startTimer, debugData.timingStartTimer, debugData.timings)
                        },
                        session: debugData.session && {
                            id: debugData.session.id,
                            // is connection socket reused
                            reused: debugData.session.reused
                        }
                    });
                });

                // update history object
                history.execution.data = executionData;
                history.execution.sessions = requestSessions;

                return history;
            },

            /**
             * Add the missing/system headers in the request object
             *
             * @param {Object[]} headers
             */
            addMissingRequestHeaders = function (headers) {
                _.forEach(headers, function (header) {
                    var lowerCasedKey = header.key.toLowerCase();

                    // update headers which gets overwritten by the requester
                    if (OVERWRITTEN_HEADERS[lowerCasedKey]) {
                        if (Array.isArray(_.get(request.headers, ['reference', lowerCasedKey]))) {
                            request.headers.remove(header.key);
                        }

                        request.headers.upsert({
                            key: header.key,
                            value: header.value,
                            system: true
                        });
                    }
                });
            },

            /**
             * Helper function to trigger `callback` and complete the request function
             *
             * @param {Error} error - error while requesting
             * @param {Response} response - SDK Response instance
             * @param {Object} history - Request-Response History
             */
            onEnd = function (error, response, history) {
                self.emit(RESPONSE_END_EVENT_BASE + id, error, self.trace.cursor,
                    self.trace, response, request, cookies, history);

                return callback(error, response, request, cookies, history);
            },

            /**
             * Helper function to keep track of `responseStart` and `response`
             * triggers to make they are emitted in correct order.
             *
             * @todo fix requester control flow to remove this hack!
             *  this is required because CookieJar.getCookies is async method
             *  and by that time postman-request ends the request, which affects
             *  request post-send helpers because `response.start` event is not
             *  emitted on time and shared variables `cookies`, `responseJSON`,
             *  and, `responseHeaders` are initialized in onStart function.
             *
             * @param {String} trigger - trigger name
             * @param {Response} response - SDK Response instance
             * @param {Object} history - Request-Response History
             */
            onComplete = function (trigger, response, history) {
                if (trigger === RESPONSE_START) {
                    // set flag for responseStart callback
                    _responseStarted = true;

                    // if response is ended, end the response using cached data
                    if (_responseEnded) {
                        onEnd(null, _responseData.response, _responseData.history);
                    }

                    // bail out and wait for response end if not ended already
                    return;
                }

                // if response started, don't wait and end the response
                if (_responseStarted) {
                    onEnd(null, response, history);

                    return;
                }

                // wait for responseStart and cache response callback data
                _responseEnded = true;
                _responseData = {
                    response,
                    history
                };
            },

            /**
             * Helper function to trigger `responseStart` callback and
             * - transform postman-request response instance to SDK Response
             * - filter cookies
             * - filter response headers
             * - add missing request headers
             *
             * @param {Object} response - Postman-Request response instance
             */
            onStart = function (response) {
                var responseStartEventName = RESPONSE_START_EVENT_BASE + id,
                    executionData,
                    initialRequest,
                    finalRequest,
                    sdkResponse,
                    history,
                    done = function () {
                        // emit the response.start event which eventually
                        // triggers responseStart callback
                        self.emit(responseStartEventName, null, sdkResponse, request, cookies, history);

                        // trigger completion of responseStart
                        onComplete(RESPONSE_START);
                    };

                // @todo get rid of jsonifyResponse
                responseJSON = core.jsonifyResponse(response, requestOptions);

                // transform response headers to SDK compatible HeaderList
                responseHeaders = _.transform(responseJSON.headers, transformMultiValueHeaders, []);

                // initialize SDK Response instance
                sdkResponse = new sdk.Response({
                    status: response && response.statusMessage,
                    code: responseJSON.statusCode,
                    header: responseHeaders
                });

                // prepare history from request debug data
                history = getExecutionHistory(_.get(response, 'request._debug'));

                // get the initial and final (on redirect) request from history
                executionData = _.get(history, 'execution.data') || [];
                initialRequest = _.get(executionData, '[0].request') || {};
                finalRequest = executionData.length > 1 ?
                    // get final redirect
                    _.get(executionData, [executionData.length - 1, 'request']) :
                    // no redirects
                    initialRequest;

                // add missing request headers so that they get bubbled up into the UI
                addMissingRequestHeaders(initialRequest.headers);

                // pull out cookies from the cookie jar, and make them chrome compatible.
                if (cookieJar && _.isFunction(cookieJar.getCookies)) {
                    // get cookies set for the final request URL
                    cookieJar.getCookies(finalRequest.href, function (err, cookiesFromJar) {
                        if (err) {
                            return done();
                        }

                        cookies = _.transform(cookiesFromJar, function (acc, cookie) {
                            acc.push(toPostmanCookie(cookie));
                        }, []);

                        cookies = new sdk.CookieList(null, cookies);

                        done();
                    });
                }
                else {
                    cookies = new sdk.CookieList(null, []);
                    done();
                }
            };

        // at this point the request could have come from collection, auth or sandbox
        // we can't trust the integrity of this request
        // bail out if request url is empty
        if (!(request && request.url && request.url.toString && request.url.toString())) {
            return onEnd(new Error('runtime:extensions~request: request url is empty'));
        }

        cookieJar = self.options.cookieJar;
        requestOptions = core.getRequestOptions(request, self.options, protocolProfileBehavior);

        // update url with the final encoded url
        // @note this mutates the request object which will be passed in request
        // and response callbacks
        request.url.update(requestOptions.url.href);
        hostname = request.url.getHost();

        // check if host is on the `restrictedAddresses`
        if (networkOptions.restrictedAddresses && core.isAddressRestricted(hostname, networkOptions)) {
            return onEnd(new Error(ERROR_RESTRICTED_ADDRESS + hostname));
        }

        return requests(request, requestOptions, onStart, function (err, res, resBody, debug) {
            // prepare history from request debug data
            var history = getExecutionHistory(debug),
                responseTime,
                response;

            if (err) {
                // bubble up http errors
                // @todo - Should we send an empty sdk Response here?
                //
                // Sending `history` object even in case of error
                return onEnd(err, undefined, history);
            }

            // Calculate the time taken for us to get the response.
            responseTime = Date.now() - startTime;

            if (res && res.timings) {
                // update response time to actual response end time
                // of the final request in the redirect chain.
                responseTime = Math.ceil(res.timings.end);
            }

            if (resBody && resBody instanceof ArrayBuffer) {
                resBody = Buffer.from(resBody);
            }

            // Response in the SDK format
            // @todo reuse same response instance used for responseStart callback
            response = new sdk.Response({
                code: responseJSON.statusCode,
                status: res && res.statusMessage,
                header: responseHeaders,
                stream: resBody,
                responseTime: responseTime
            });

            onComplete(RESPONSE_END, response, history);
        });
    }

    /**
     * Removes all current event listeners on the requester, and makes it ready for garbage collection :).
     *
     * @param {Function=} cb - Optional callback to be called on disposal
     *
     * @todo - In the future, when the requester manages its own connections etc, close them all here.
     */
    dispose (cb) {
        // This is safe for us, because we do not use wait on events. (i.e, no part of Runtime ever waits on
        // any event to occur). We rely on callbacks for that, only choosing to use events as a way of streaming
        // information outside runtime.
        this.removeAllListeners();

        _.isFunction(cb) && cb();
    }

    /**
     * Asynchronously create a new requester.
     *
     * @param trace
     * @param trace.type - type of requester to return (for now, just http)
     * @param trace.source - information about who needs this requester, e.g Auth, etc.
     * @param trace.cursor - the cursor
     * @param options
     * @param callback
     * @returns {*}
     */
    static create (trace, options, callback) {
        return callback(null, new Requester(trace, options));
    }

    /**
     * A helper method to dry run the given request instance.
     * It returns the cloned request instance with the system added properties.
     *
     * @param {Request} request
     * @param {Object} options
     * @param {Object} options.cookieJar
     * @param {Object} options.protocolProfileBehavior
     * @param {Object} options.implicitCacheControl
     * @param {Object} options.implicitTraceHeader
     * @param {Function} done
     */
    static dryRun (request, options, done) {
        return dryRun(request, options, done);
    }
}

module.exports.Requester = Requester;
<|endoftext|>


<commit_before>// @flow

import {performance, isResourceTimingAvailable} from '../performance';
import type {BeaconWithResourceTiming} from '../types';
import {serializeEntry} from './timingSerializer';
import {urlMaxLength} from './consts';
import {info, debug} from '../debug';
import {createTrie} from '../trie';
import {win} from '../browser';
import vars from '../vars';

// See https://w3c.github.io/resource-timing/
// See https://www.w3.org/TR/hr-time/

export function addResourceTimings(beacon: BeaconWithResourceTiming, minStartTime: ?number) {
  if (isResourceTimingAvailable && win.JSON) {
    const entries = getEntriesTransferFormat(performance.getEntriesByType('resource'), minStartTime);
    beacon['res'] = win.JSON.stringify(entries);

    if (vars.autoClearResourceTimings && performance.clearResourceTimings) {
      if (DEBUG) {
        debug('Automatically clearing resource timing buffer.');
      }
      performance.clearResourceTimings();
    }
  } else if (DEBUG) {
    info('Resource timing not supported.');
  }
}

function getEntriesTransferFormat(performanceEntries: Array<Object>, minStartTime: ?number) {
  const trie = createTrie();
  const lowerCaseReportingUrl = vars.reportingUrl != null ? vars.reportingUrl.toLowerCase() : null;

  for (let i = 0, len = performanceEntries.length; i < len; i++) {
    const entry = performanceEntries[i];
    if (minStartTime != null &&
        (entry['startTime'] - vars.highResTimestampReference + vars.referenceTimestamp) < minStartTime) {
      continue;
    } else if (entry['duration'] < 0) {
      // Some old browsers do not properly implement resource timing. They report negative durations.
      // Ignore instead of reporting these, as the data isn't usable.
      continue;
    }

    let url = entry.name;
    const lowerCaseUrl = url.toLowerCase();
    const initiatorType = entry['initiatorType'];
    if (lowerCaseUrl === 'about:blank' || lowerCaseUrl.indexOf('javascript:') === 0 || // some iframe cases
      // The image based data transmission can be visible as a resource. Do not report it.
      (lowerCaseReportingUrl != null && initiatorType === 'img' && lowerCaseUrl.indexOf(lowerCaseReportingUrl) === 0)) {
      continue;
    }

    if (url.length > urlMaxLength) {
      url = url.substring(0, urlMaxLength);
    }

    // We provide more detailed XHR insights via our XHR instrumentation.
    // The XHR instrumentation is available once the initialization was executed
    // (which is completely synchronous).
    if (initiatorType !== 'xmlhttprequest' || entry['startTime'] < vars.highResTimestampReference) {
      trie.addItem(url, serializeEntry(entry));
    }
  }

  return trie.toJs();
}
<commit_msg>XHR based transmission may also appear when certain APIs are used before the instrumentation kicks in<commit_after>// @flow

import {performance, isResourceTimingAvailable} from '../performance';
import type {BeaconWithResourceTiming} from '../types';
import {serializeEntry} from './timingSerializer';
import {urlMaxLength} from './consts';
import {info, debug} from '../debug';
import {createTrie} from '../trie';
import {win} from '../browser';
import vars from '../vars';

// See https://w3c.github.io/resource-timing/
// See https://www.w3.org/TR/hr-time/

export function addResourceTimings(beacon: BeaconWithResourceTiming, minStartTime: ?number) {
  if (isResourceTimingAvailable && win.JSON) {
    const entries = getEntriesTransferFormat(performance.getEntriesByType('resource'), minStartTime);
    beacon['res'] = win.JSON.stringify(entries);

    if (vars.autoClearResourceTimings && performance.clearResourceTimings) {
      if (DEBUG) {
        debug('Automatically clearing resource timing buffer.');
      }
      performance.clearResourceTimings();
    }
  } else if (DEBUG) {
    info('Resource timing not supported.');
  }
}

function getEntriesTransferFormat(performanceEntries: Array<Object>, minStartTime: ?number) {
  const trie = createTrie();
  const lowerCaseReportingUrl = vars.reportingUrl != null ? vars.reportingUrl.toLowerCase() : null;

  for (let i = 0, len = performanceEntries.length; i < len; i++) {
    const entry = performanceEntries[i];
    if (minStartTime != null &&
        (entry['startTime'] - vars.highResTimestampReference + vars.referenceTimestamp) < minStartTime) {
      continue;
    } else if (entry['duration'] < 0) {
      // Some old browsers do not properly implement resource timing. They report negative durations.
      // Ignore instead of reporting these, as the data isn't usable.
      continue;
    }

    let url = entry.name;
    const lowerCaseUrl = url.toLowerCase();
    const initiatorType = entry['initiatorType'];
    if (lowerCaseUrl === 'about:blank' || lowerCaseUrl.indexOf('javascript:') === 0 || // some iframe cases
      // Data transmission can be visible as a resource. Do not report it.
      (lowerCaseReportingUrl != null && lowerCaseUrl.indexOf(lowerCaseReportingUrl) === 0)) {
      continue;
    }

    if (url.length > urlMaxLength) {
      url = url.substring(0, urlMaxLength);
    }

    // We provide more detailed XHR insights via our XHR instrumentation.
    // The XHR instrumentation is available once the initialization was executed
    // (which is completely synchronous).
    if (initiatorType !== 'xmlhttprequest' || entry['startTime'] < vars.highResTimestampReference) {
      trie.addItem(url, serializeEntry(entry));
    }
  }

  return trie.toJs();
}
<|endoftext|>


<commit_before>var Busboy = require('busboy'),
    path = require('path'),
    fs = require('fs'),
    //gm = require('gm'),
    uuid = require('node-uuid'),
    config = require('../../../config/config');

module.exports = function (data) {
    return {
        getAll: function (req, res) {
            data.products.getAll()
                .then(function (products) {
                    res.send(products);
                }, function (error) {
                    res.render('error', {
                        error: error,
                        message: 'Cannot get all products!'
                    });
                });
        },
        getById: function (req, res) {
            var id = req.params.id;

            data.products.getById(id)
                .then(function (product) {
                    res.send(product);
                }, function (error) {
                    res.render('error', {
                        error: error,
                        message: 'Cannot get product by id!'
                    });
                });
        },
        create: function (req, res) {
            //Data validation
            //Price is mandatory

            var busboy = new Busboy({ headers: req.headers }),
                productData = {
                    assets : []
                };

            busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {

                var uuidFilename = uuid() + filename;
                var saveToPath = path.join(config.storageDir  + '/products/images/', path.basename(uuidFilename));

                var productImageData = {
                    title: filename,
                    src: config.storageDir + '/products/images/' + uuidFilename,
                    thumbSrc: config.storageDir + '/products/images/thumb_' + uuidFilename
                    // TODO: get width and height and assign them here
                };

                var fileStream = fs.createWriteStream(saveToPath);

                productData.assets.push(productImageData);

                file.pipe(fileStream);

                //file.on('end', function() {
                //    var pathToNewImage = path.join(path.normalize(config.storageDir  + '/products/images/'), 'thumb_' + path.basename(uuidFilename));
                //    gm(saveToPath)
                //        .options({imageMagick: true})
                //        // TODO: Choose the correct image
                //        .resize(50, 50, '%')
                //        .write(pathToNewImage, function(error){
                //            if (error) {
                //                return console.log('Image thumb cannot be created! ', arguments);
                //            }
                //        })
                //});

            });

            busboy.on('field', function(fieldname, val, fieldnameTruncated, valTruncated) {
                if(fieldname == 'description' || fieldname == 'attributes') {
                    var value = JSON.parse(val);
                }else{
                    var value = val;
                }

                productData[fieldname] = value;
            });

            busboy.on('finish', function() {
                console.log('finish busboy create');
                data.products.create(productData)
                    .then(function (createdProduct) {
                        res.json({
                            message: 'New product saved successfully!',
                            product: createdProduct
                        });
                    }, function (error) {
                        res.json({
                            message: 'New product saved successfully!',
                            success: createdProduct
                        });
                    });
            });

            req.pipe(busboy);
        },
        updateById: function (req, res) {
            var busboy = new Busboy({ headers: req.headers }),
                productData = {
                    assets : []
                };
            busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {

                var uuidFilename = uuid() + filename;
                var saveToPath = path.join(path.normalize(__dirname  + '/../../../public/storage/products/images/'), path.basename(uuidFilename));

                var productImageData = {
                    title: filename,
                    src: 'storage/products/images/' + uuidFilename
                };
                productData.assets.push(productImageData);
                file.pipe(fs.createWriteStream(saveToPath));
            });

            busboy.on('field', function(fieldname, val, fieldnameTruncated, valTruncated) {
                if(fieldname == 'description' || fieldname == 'attributes') {
                    var value = JSON.parse(val);
                }else{
                    var value = val;
                }

                productData[fieldname] = value;
            });

            busboy.on('finish', function() {
                data.products.updateProductById({id:req.params.id, updatesObject:productData})
                    .then(function (updatedProduct) {
                        res.json({
                            message: 'Product updated successfully!',
                            product: updatedProduct
                        });
                    },function (error) {
                        res.render('error', {
                            message: 'Cannot update product!',
                            error: error
                        });
                    });
            });

            req.pipe(busboy);
        },
        remove: function (req, res) {

        }
    }
};<commit_msg>changed storage folder to default openshift<commit_after>var Busboy = require('busboy'),
    path = require('path'),
    fs = require('fs'),
    //gm = require('gm'),
    uuid = require('node-uuid'),
    config = require('../../../config/config');

module.exports = function (data) {
    return {
        getAll: function (req, res) {
            data.products.getAll()
                .then(function (products) {
                    res.send(products);
                }, function (error) {
                    res.render('error', {
                        error: error,
                        message: 'Cannot get all products!'
                    });
                });
        },
        getById: function (req, res) {
            var id = req.params.id;

            data.products.getById(id)
                .then(function (product) {
                    res.send(product);
                }, function (error) {
                    res.render('error', {
                        error: error,
                        message: 'Cannot get product by id!'
                    });
                });
        },
        create: function (req, res) {
            //Data validation
            //Price is mandatory

            var busboy = new Busboy({ headers: req.headers }),
                productData = {
                    assets : []
                };

            busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {

                var uuidFilename = uuid() + filename;
                var saveToPath = path.join(config.storageDir, path.basename(uuidFilename));

                var productImageData = {
                    title: filename,
                    src: config.storageDir + uuidFilename,
                    thumbSrc: config.storageDir + uuidFilename
                    // TODO: get width and height and assign them here
                };

                var fileStream = fs.createWriteStream(saveToPath);

                productData.assets.push(productImageData);

                file.pipe(fileStream);

                //file.on('end', function() {
                //    var pathToNewImage = path.join(path.normalize(config.storageDir  + '/products/images/'), 'thumb_' + path.basename(uuidFilename));
                //    gm(saveToPath)
                //        .options({imageMagick: true})
                //        // TODO: Choose the correct image
                //        .resize(50, 50, '%')
                //        .write(pathToNewImage, function(error){
                //            if (error) {
                //                return console.log('Image thumb cannot be created! ', arguments);
                //            }
                //        })
                //});

            });

            busboy.on('field', function(fieldname, val, fieldnameTruncated, valTruncated) {
                if(fieldname == 'description' || fieldname == 'attributes') {
                    var value = JSON.parse(val);
                }else{
                    var value = val;
                }

                productData[fieldname] = value;
            });

            busboy.on('finish', function() {
                console.log('finish busboy create');
                data.products.create(productData)
                    .then(function (createdProduct) {
                        res.json({
                            message: 'New product saved successfully!',
                            product: createdProduct
                        });
                    }, function (error) {
                        res.json({
                            message: 'New product saved successfully!',
                            success: createdProduct
                        });
                    });
            });

            req.pipe(busboy);
        },
        updateById: function (req, res) {
            var busboy = new Busboy({ headers: req.headers }),
                productData = {
                    assets : []
                };
            busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {

                var uuidFilename = uuid() + filename;
                var saveToPath = path.join(path.normalize(__dirname  + '/../../../public/storage/products/images/'), path.basename(uuidFilename));

                var productImageData = {
                    title: filename,
                    src: 'storage/products/images/' + uuidFilename
                };
                productData.assets.push(productImageData);
                file.pipe(fs.createWriteStream(saveToPath));
            });

            busboy.on('field', function(fieldname, val, fieldnameTruncated, valTruncated) {
                if(fieldname == 'description' || fieldname == 'attributes') {
                    var value = JSON.parse(val);
                }else{
                    var value = val;
                }

                productData[fieldname] = value;
            });

            busboy.on('finish', function() {
                data.products.updateProductById({id:req.params.id, updatesObject:productData})
                    .then(function (updatedProduct) {
                        res.json({
                            message: 'Product updated successfully!',
                            product: updatedProduct
                        });
                    },function (error) {
                        res.render('error', {
                            message: 'Cannot update product!',
                            error: error
                        });
                    });
            });

            req.pipe(busboy);
        },
        remove: function (req, res) {

        }
    }
};<|endoftext|>


<commit_before>/** @babel */

/**
 * @TODO: Custom sorting?
 * @TODO: Complete quotes for strings
 */

import { Point, Range } from 'atom'

import { client } from '../connection'
import modules from './modules'

const bracketScope = 'meta.bracket.julia'
const completions = client.import('completions')

class AutoCompleteProvider {
  selector = '.source.julia'
  disableForSelector = `.source.julia .comment`
  excludeLowerPriority = false
  inclusionPriority = 3
  suggestionPriority = atom.config.get('julia-client.juliaOptions.autoCompletionSuggestionPriority')
  filterSuggestions = false

  getSuggestions (data) {
    if (!client.isActive()) return []

    // Don't show suggestions if preceding char is a space (unless activate manually)
    if (!data.activatedManually) {
      const { editor, bufferPosition } = data
      const { row, column } = bufferPosition
      if (column === 0) return []
      const prevCharPosition = new Point(row, column - 1)
      const range = new Range(prevCharPosition, bufferPosition)
      const text = editor.getTextInBufferRange(range)
      // If the current position is in function call, show `REPLCompletions.MethodCompletion`s
      // whatever whitespaces precede
      const { scopes } = editor.scopeDescriptorForBufferPosition(bufferPosition)
      if (!scopes.includes(bracketScope) && text.match(/\s/)) return []
    }

    const suggestions = this.rawCompletions(data).then(({ completions, prefix }) => {
      try {
        return this.processCompletions(completions, prefix)
      } catch (err) {
        return []
      }
    })
    return Promise.race([suggestions, this.sleep()])
  }

  rawCompletions (data) {
    const { editor, bufferPosition: { row, column }, activatedManually } = data
    const startPoint = new Point(row, 0)
    const endPoint = new Point(row, column)
    const lineRange = new Range(startPoint, endPoint)
    return completions({
      path: editor.getPath(),
      mod: modules.current(),
      line: editor.getTextInBufferRange(lineRange),
      column: column + 1,
      force: activatedManually || false
    })
  }

  processCompletions (completions, prefix) {
    return completions.map((completion) => {
      return this.toCompletion(completion, prefix)
    })
  }

  toCompletion (completion, prefix) {
    if (completion.constructor === String) {
      completion = {
        text: completion
      }
    }
    completion.replacementPrefix = completion._prefix ? completion._prefix : prefix
    const icon = this.makeIcon(completion.icon)
    if (icon) completion.iconHTML = icon
    // the workaround for https://github.com/atom/autocomplete-plus/issues/868, but can appear verbose
    if (!completion.description && completion.descriptionMoreURL)
      completion.description = 'Click the link below to show docs:'
    return completion
  }

  // should sync with atom-ink/lib/workspace/workspace.js
  makeIcon(icon) {
    // if not specified, just fallback to `completion.type`
    if (!icon) return ''
    if (icon.startsWith('icon-')) return `<span class="${icon}"}></span>`
    return icon.length === 1 ? icon : ''
  }

  sleepSecond = 1
  sleep () {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve(null)
      }, this.sleepSecond * 1000)
    })
  }

  onDidInsertSuggestion ({ editor, suggestion: { type } }) {
    if (type !== 'function' || atom.config.get('julia-client.juliaOptions.noAutoParenthesis')) return
    editor.mutateSelectedText(selection => {
      if (!selection.isEmpty()) return
      const { row, column } = selection.getBufferRange().start
      const currentPoint = new Point(row, column)
      const nextPoint = new Point(row, column + 1)
      const range = new Range(currentPoint, nextPoint)
      const finishRange = new Range(nextPoint, nextPoint)
      if (editor.getTextInBufferRange(range) !== '(') {
        selection.insertText('()')
      }
      selection.setBufferRange(finishRange)
    })
  }
}

export default new AutoCompleteProvider()
<commit_msg>simpler description urls<commit_after>/** @babel */

/**
 * @TODO: Custom sorting?
 * @TODO: Complete quotes for strings
 */

import { Point, Range } from 'atom'

import { client } from '../connection'
import modules from './modules'

const bracketScope = 'meta.bracket.julia'
const completions = client.import('completions')

class AutoCompleteProvider {
  selector = '.source.julia'
  disableForSelector = `.source.julia .comment`
  excludeLowerPriority = false
  inclusionPriority = 3
  suggestionPriority = atom.config.get('julia-client.juliaOptions.autoCompletionSuggestionPriority')
  filterSuggestions = false

  getSuggestions (data) {
    if (!client.isActive()) return []

    // Don't show suggestions if preceding char is a space (unless activate manually)
    if (!data.activatedManually) {
      const { editor, bufferPosition } = data
      const { row, column } = bufferPosition
      if (column === 0) return []
      const prevCharPosition = new Point(row, column - 1)
      const range = new Range(prevCharPosition, bufferPosition)
      const text = editor.getTextInBufferRange(range)
      // If the current position is in function call, show `REPLCompletions.MethodCompletion`s
      // whatever whitespaces precede
      const { scopes } = editor.scopeDescriptorForBufferPosition(bufferPosition)
      if (!scopes.includes(bracketScope) && text.match(/\s/)) return []
    }

    const suggestions = this.rawCompletions(data).then(({ completions, prefix }) => {
      try {
        return this.processCompletions(completions, prefix)
      } catch (err) {
        return []
      }
    })
    return Promise.race([suggestions, this.sleep()])
  }

  rawCompletions (data) {
    const { editor, bufferPosition: { row, column }, activatedManually } = data
    const startPoint = new Point(row, 0)
    const endPoint = new Point(row, column)
    const lineRange = new Range(startPoint, endPoint)
    return completions({
      path: editor.getPath(),
      mod: modules.current(),
      line: editor.getTextInBufferRange(lineRange),
      column: column + 1,
      force: activatedManually || false
    })
  }

  processCompletions (completions, prefix) {
    return completions.map((completion) => {
      return this.toCompletion(completion, prefix)
    })
  }

  toCompletion (completion, prefix) {
    if (completion.constructor === String) {
      completion = {
        text: completion
      }
    }
    completion.replacementPrefix = completion._prefix ? completion._prefix : prefix
    const icon = this.makeIcon(completion.icon)
    if (icon) completion.iconHTML = icon
    // workaround https://github.com/atom/autocomplete-plus/issues/868
    if (!completion.description && completion.descriptionMoreURL)
      completion.description = ' '
    return completion
  }

  // should sync with atom-ink/lib/workspace/workspace.js
  makeIcon(icon) {
    // if not specified, just fallback to `completion.type`
    if (!icon) return ''
    if (icon.startsWith('icon-')) return `<span class="${icon}"}></span>`
    return icon.length === 1 ? icon : ''
  }

  sleepSecond = 1
  sleep () {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve(null)
      }, this.sleepSecond * 1000)
    })
  }

  onDidInsertSuggestion ({ editor, suggestion: { type } }) {
    if (type !== 'function' || atom.config.get('julia-client.juliaOptions.noAutoParenthesis')) return
    editor.mutateSelectedText(selection => {
      if (!selection.isEmpty()) return
      const { row, column } = selection.getBufferRange().start
      const currentPoint = new Point(row, column)
      const nextPoint = new Point(row, column + 1)
      const range = new Range(currentPoint, nextPoint)
      const finishRange = new Range(nextPoint, nextPoint)
      if (editor.getTextInBufferRange(range) !== '(') {
        selection.insertText('()')
      }
      selection.setBufferRange(finishRange)
    })
  }
}

export default new AutoCompleteProvider()
<|endoftext|>


<commit_before>import React, {Component} from 'react';
import styled from 'styled-components';
import {colors} from '../constants';

const Table = styled.table`
  width: 100%;
  border-collapse: collapse;
`;

const Heading = styled.th`
  text-transform: uppercase;
  text-align: left;
  font-size: .6em;
`;

const Item = styled.td`
  border-top: none;
  border-bottom: none;
  border-right: .2em ${colors.black} solid;
  padding: .4em;
`;

const Row = styled.tr`
  &:nth-of-type(even) {
    background-color: ${colors.lightGrey};
  }
  &:nth-of-type(odd) {
    background-color: ${colors.darkGrey};
  }
`;

class List extends Component {
  renderQueries() {
    const {queries} = this.props;

    return queries.map((query,index) => {
      const date = new Date(query.querytime);
      const time = {
        hours: date.getHours() < 10 ? '0' + date.getHours() : date.getHours(),
        minutes: date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes(),
        seconds: date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
      };
      return (
        <Row key={index}>
          <Item>{time.hours}:{time.minutes}:{time.seconds}</Item>
          <Item>{query.origin.name}</Item>
          <Item>{query.destination.name}</Item>
        </Row>
      );
    });
  }

  render() {
    return (

            <Heading>time</Heading>
            <Heading>departure</Heading>
            <Heading>destination</Heading>

          {this.renderQueries()}

    );
  }
}

export default List;
<commit_msg>slecht<commit_after>import React, {Component} from 'react';
import styled from 'styled-components';
import {colors} from '../constants';

const Table = styled.table`
  width: 100%;
  border-collapse: collapse;
`;

const Heading = styled.th`
  text-transform: uppercase;
  text-align: left;
  font-size: .6em;
`;

const Item = styled.td`
  border-top: none;
  border-bottom: none;
  border-right: .2em ${colors.black} solid;
  padding: .4em;
`;

const Row = styled.tr`
  &:nth-of-type(even) {
    background-color: ${colors.lightGrey};
  }
  &:nth-of-type(odd) {
    background-color: ${colors.darkGrey};
  }
`;

export default class List extends Component {
  renderQueries() {
    const {queries} = this.props;

    return queries.map((query,index) => {
      const date = new Date(query.querytime);
      const time = {
        hours: date.getHours() < 10 ? '0' + date.getHours() : date.getHours(),
        minutes: date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes(),
        seconds: date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
      };
      return (
        <Row key={index}>
          <Item>{time.hours}:{time.minutes}:{time.seconds}</Item>
          <Item>{query.origin.name}</Item>
          <Item>{query.destination.name}</Item>
        </Row>
      );
    });
  }

  render() {
    return (

            <Heading>time</Heading>
            <Heading>departure</Heading>
            <Heading>destination</Heading>

          {this.renderQueries()}

    );
  }
}
<|endoftext|>


<commit_before>import React from 'react'
import Header from './header'
import Footer from './footer';

const PageComponent = ({children, appUrl}) => {
  return (

            <ShareButtons />

      {children}

  )
};

export default PageComponent;

class ShareButtons extends React.Component {
    shouldComponentUpdate() {
        return false; // we want shariff to control this component, so dont react to updates ;) (fingers crossed)
    }
    render() {
        return (

      );
    }
}
<commit_msg>removed the shareButtons from the page.js<commit_after>import React from 'react'
import Header from './header'
import Footer from './footer';

const PageComponent = ({children, appUrl}) => {
  return (

      {children}

  )
};

export default PageComponent;
<|endoftext|>


<commit_before>import React, {PropTypes} from 'react'
import ResizeHandle from 'shared/components/ResizeHandle'

const {
  node,
  string,
} = PropTypes

const ResizeContainer = React.createClass({
  propTypes: {
    children: node.isRequired,
  },

  getInitialState() {
    return {
      topHeight: '60%',
      bottomHeight: '40%',
      isDragging: false,
    }
  },

  handleStopDrag() {
    this.setState({isDragging: false})
  },

  handleStartDrag() {
    this.setState({isDragging: true})
  },

  handleMouseLeave() {
    this.setState({isDragging: false})
  },

  handleDrag(e) {
    if (!this.state.isDragging) {
      return
    }

    const appHeight = parseInt(getComputedStyle(this.refs.resizeContainer).height, 10)
    // headingOffset moves the resize handle as many pixels as the page-heading is taking up.
    const headingOffset = window.innerHeight - appHeight
    const turnToPercent = 100
    const newTopPanelPercent = Math.ceil(((e.pageY - headingOffset) / (appHeight)) * turnToPercent)
    const newBottomPanelPercent = (turnToPercent - newTopPanelPercent)

    // Don't trigger a resize unless the change in size is greater than minResizePercentage
    const minResizePercentage = 0.5
    if (Math.abs(newTopPanelPercent - parseFloat(this.state.topHeight)) < minResizePercentage) {
      return
    }

    // Don't trigger a resize if the new sizes are too small
    const minTopPanelHeight = 200
    const minBottomPanelHeight = 200
    const topHeightPixels = ((newTopPanelPercent / turnToPercent) * appHeight)
    const bottomHeightPixels = ((newBottomPanelPercent / turnToPercent) * appHeight)

    if (topHeightPixels < minTopPanelHeight || bottomHeightPixels < minBottomPanelHeight) {
      return
    }

    this.setState({topHeight: `${(newTopPanelPercent)}%`, bottomHeight: `${(newBottomPanelPercent)}%`, topHeightPixels})
  },

  renderHandle() {
    const {isDragging, topHeight} = this.state
    return (
      <ResizeHandle isDragging={isDragging} onHandleStartDrag={this.handleStartDrag} top={topHeight} />
    )
  },

  render() {
    const {topHeight, topHeightPixels, bottomHeight} = this.state
    const top = React.cloneElement(this.props.children[0], {height: topHeight, heightPixels: topHeightPixels})
    const bottom = React.cloneElement(this.props.children[1], {height: bottomHeight})
    return (

        {top}
        {this.renderHandle()}
        {bottom}

    )
  },
})

export const ResizeBottom = ({
  height,
  children,
}) => (

    {children}

)

ResizeBottom.propTypes = {
  children: node.isRequired,
  height: string,
}

export default ResizeContainer
<commit_msg>Fix for graph height issue.<commit_after>import React, {PropTypes} from 'react'
import ResizeHandle from 'shared/components/ResizeHandle'

const {
  node,
  string,
} = PropTypes

const ResizeContainer = React.createClass({
  propTypes: {
    children: node.isRequired,
  },

  getInitialState() {
    return {
      topHeight: '60%',
      bottomHeight: '40%',
      isDragging: false,
    }
  },

  handleStopDrag() {
    this.setState({isDragging: false})
  },

  handleStartDrag() {
    this.setState({isDragging: true})
  },

  handleMouseLeave() {
    this.setState({isDragging: false})
  },

  handleDrag(e) {
    if (!this.state.isDragging) {
      return
    }

    const appHeight = parseInt(getComputedStyle(this.refs.resizeContainer).height, 10)
    // headingOffset moves the resize handle as many pixels as the page-heading is taking up.
    const headingOffset = window.innerHeight - appHeight
    const turnToPercent = 100
    const newTopPanelPercent = Math.ceil(((e.pageY - headingOffset) / (appHeight)) * turnToPercent)
    const newBottomPanelPercent = (turnToPercent - newTopPanelPercent)

    // Don't trigger a resize unless the change in size is greater than minResizePercentage
    const minResizePercentage = 0.5
    if (Math.abs(newTopPanelPercent - parseFloat(this.state.topHeight)) < minResizePercentage) {
      return
    }

    // Don't trigger a resize if the new sizes are too small
    const minTopPanelHeight = 200
    const minBottomPanelHeight = 200
    const topHeightPixels = ((newTopPanelPercent / turnToPercent) * appHeight)
    const bottomHeightPixels = ((newBottomPanelPercent / turnToPercent) * appHeight)

    if (topHeightPixels < minTopPanelHeight || bottomHeightPixels < minBottomPanelHeight) {
      return
    }

    this.setState({
      topHeight: `${(newTopPanelPercent)}%`,
      bottomHeight: `${(newBottomPanelPercent)}%`,
      topHeightPixels,
      bottomHeightPixels,
    })
  },

  renderHandle() {
    const {isDragging, topHeight} = this.state
    return (
      <ResizeHandle isDragging={isDragging} onHandleStartDrag={this.handleStartDrag} top={topHeight} />
    )
  },

  render() {
    const {
      topHeight,
      topHeightPixels,
      bottomHeightPixels,
    } = this.state
    const top = React.cloneElement(this.props.children[0], {height: topHeight, heightPixels: topHeightPixels})
    const bottom = React.cloneElement(this.props.children[1], {height: bottomHeightPixels})
    return (

        {top}
        {this.renderHandle()}
        {bottom}

    )
  },
})

export const ResizeBottom = ({
  height,
  children,
}) => {
  const child = React.cloneElement(children, {height})
  return (

      {child}

  )
}

ResizeBottom.propTypes = {
  children: node.isRequired,
  height: string,
}

export default ResizeContainer
<|endoftext|>


<commit_before>function DragNDrop(elem, origin, hash) {
	this.elem = elem;
	this.origin = origin;
	this.hash = hash;
	this.init();
}

DragNDrop.prototype = {
	dpos: {},
	mpos: { mouse: {} },
	oside: {
		left:   'right',
		right:  'left',
		top:    'bottom',
		bottom: 'top',
	},
	estyle: {},

	updateHash: function(hash) {
		this.hash = hash;
	},

	init: function() {
		this.communicateMouseMove = debounce(function() {
			this.sendToBackground({mouse: this.mpos, action: 'mouse'});
		}.bind(this), 100);

		window.addEventListener("mousemove", this.mouseMoveHandler = this.handleMouseMove.bind(this));
		window.addEventListener("message",   this.messageHandler = this.handleMessage.bind(this))
		this.handleRepos({vside: 'bottom', hside: 'left', h: 0, v: 0});
	},

	uninit: function() {
		window.removeEventListener("mousemove", this.mouseMoveHandler);
		window.removeEventListener("message",   this.messageHandler);
	},

	onMessageSendFail: function(cb) {
		this.messageSendFailCallback = cb;
	},

	sendToBackground: function(msg) {
		try {
			chrome.runtime.sendMessage(msg, function(response) {});
		} catch(e) {
			error(e);
			if (this.messageSendFailCallback)
				this.messageSendFailCallback(this);
		}
	},

	handleMouseMove: function(event) {
		if (!(event instanceof MouseEvent)/* || !event.isTrusted*/)
			return;

		this.mpos.mouse.x = event.clientX;
		this.mpos.mouse.y = event.clientY;
		this.mpos.from    = 'window';
		this.mpos.iframe  = { y: this.elem.offsetTop, x: this.elem.offsetLeft }

		this.updateIframePos();
		this.communicateMouseMove();
	},

	updateIframePos: function() {
		if (this.dpos.state == 'drag') {
			var zoom = (this.dpos.internal || {}).zoom || 1;
			//    last pos outside of iframe  - mousedown pos in iframe + change in mouse screen position from mouse down
			if (this.mpos.from == 'iframe') {
				this.mpos.iframe = {
					x: (this.dpos.iframe.x + (this.mpos.internal.screen.x - this.dpos.internal.screen.x)),
					y: (this.dpos.iframe.y + (this.mpos.internal.screen.y - this.dpos.internal.screen.y)),
					w: this.elem.offsetWidth,
					h: this.elem.offsetHeight
				}
			} else {
				this.mpos.iframe = {
					x: (this.mpos.mouse.x - this.dpos.internal.client.x),
					y: (this.mpos.mouse.y - this.dpos.internal.client.y),
					w: this.elem.offsetWidth,
					h: this.elem.offsetHeight
				};
			}

			this.elem.style.left = this.estyle.left = Math.min(window.innerWidth  * zoom - this.elem.offsetWidth , Math.max(0, this.mpos.iframe.x)) + 'px';
			this.elem.style.top  = this.estyle.top  = Math.min(window.innerHeight * zoom - this.elem.offsetHeight, Math.max(0, this.mpos.iframe.y)) + 'px';
			this.estyle['-stumble-dirty-style'] = '1';
		}
	},

	applyEstyle: function(rebuild) {
		var cssText = this.cachedCssText || '';
		if (rebuild || this.estyle['-stumble-dirty-style'] != '0') {
			cssText = '';
			this.estyle['-stumble-dirty-style'] = '0';
			for (var p in this.estyle)
				cssText += p+':'+this.estyle[p]+';';
			this.cachedCssText = cssText;
		}
		if (this.isFullscreen)
			cssText += 'display: none !important;';
		if (this.elem.style.cssText != cssText)
			this.elem.style.cssText = cssText;
	},

	handleRepos: function(rpos, noMargin) {
		this.estyle[rpos.vside] = this.elem.style[rpos.vside] = rpos.v + '%';
		this.estyle[rpos.hside] = this.elem.style[rpos.hside] = rpos.h + '%';
		this.estyle[this.oside[rpos.vside]] = this.elem.style[this.oside[rpos.vside]] = 'initial';
		this.estyle[this.oside[rpos.hside]] = this.elem.style[this.oside[rpos.hside]] = 'initial';

		this.handleTrySnap(rpos)
		this.estyle['-stumble-dirty-style'] = '1';
	},

	handleTrySnap: function(rpos) {
		if (rpos.v <= 1) {
			this.estyle['margin-' + rpos.vside] = this.elem.style['margin-' + rpos.vside] = '-3px';
			this.estyle['margin-' + this.oside[rpos.vside]] = this.elem.style['margin-' + this.oside[rpos.vside]] = 'initial';
			this.estyle[rpos.vside] = this.elem.style[rpos.vside] = '0';
		} else {
			this.estyle['margin-' + rpos.vside] = this.elem.style['margin-' + rpos.vside] = 'initial';
		}
		if (rpos.h <= 1) {
			this.estyle['margin-' + rpos.hside] = this.elem.style['margin-' + rpos.hside] = '-3px';
			this.estyle['margin-' + this.oside[rpos.hside]] = this.elem.style['margin-' + this.oside[rpos.hside]] = 'initial';
			this.estyle[rpos.hside] = this.elem.style[rpos.hside] = '0';
		} else {
			this.estyle['margin-' + rpos.hside] = this.elem.style['margin-' + rpos.hside] = 'initial';
		}
		this.estyle['-stumble-dirty-style'] = '1';
	},

	handleMessage: function(event) {
		if (!event.data || !event.data.type || event.origin != this.origin)
			return;

		var handler = 'handle' + event.data.type[0].toUpperCase() + event.data.type.slice(1) + 'Message';
		this[handler](event.data.message, event.data);
	},

	handleDragMessage: function(message) {
		if (this.dpos.state == 'down') {
			['top', 'left', 'right', 'bottom'].forEach(function(side) {
				this.elem.style['margin-' + side] = 'initial';
			}.bind(this));
			this.dpos.state = 'drag';
		}
		this.mpos.internal = message;
		this.mpos.from = 'iframe';
		this.updateIframePos();
	},

	handleDownMessage: function(message) {
		if (this.dpos.state == 'down')
			return;
		this.dpos = { from: 'iframe', mouse: this.mpos.mouse, iframe: { y: this.elem.offsetTop, x: this.elem.offsetLeft }, internal: message };
		this.mpos = { from: 'iframe', mouse: this.mpos.mouse, iframe: { y: this.elem.offsetTop, x: this.elem.offsetLeft }, internal: message };
		this.dpos.state = 'down';
	},

	handleHideMessage: function(message) {
		this.elem.style.display = this.estyle.display = 'none';
		this.estyle['-stumble-dirty-style'] = '1';
	},

	handleUpMessage: function(message) {
		if (this.dpos.state != 'drag') {
			this.dpos.state = 'up';
			return;
		}
		this.dpos.state = 'up';
		var rpos = {
			v: Math.max((this.elem.offsetTop ) / window.innerHeight * 100, 0),
			h: Math.max((this.elem.offsetLeft) / window.innerWidth  * 100, 0),
			vside: 'top',
			hside: 'left',
		}
		if (rpos.v > 50) {
			rpos.v = Math.max(100 - rpos.v - 100 * this.elem.offsetHeight / window.innerHeight, 0);
			rpos.vside = 'bottom';
		}
		if (rpos.h > 50) {
			rpos.h = Math.max(100 - rpos.h - 100 * this.elem.offsetWidth  / window.innerWidth , 0);
			rpos.hside = 'right';
		}
		this.handleRepos(rpos);
		this.sendToBackground({action: 'repos', from: 'bar', data: { rpos: rpos } }, true);
	},

	handleHoverMessage: function(message) {
		//document.body.overflow = event.data.hover ? 'hidden' : 'initial';
	},

	handleRedrawMessage: function(message) {
		if (message.toolbar.h && message.toolbar.w) {
			this.elem.style.height = this.estyle.height = message.toolbar.h + 'px';
			this.elem.style.width  = this.estyle.width  = message.toolbar.w + 'px';
			this.updateIframePos();
		}
		if (message.toolbar.rpos)
			this.handleRepos(message.toolbar.rpos);
		if (message.toolbar.hidden)
			this.elem.style.display = this.estyle.display = 'none';
		else
			this.elem.style.display = this.estyle.display = 'block';
		this.estyle['-stumble-dirty-style'] = '1';
	},

	fullscreen: function(fullscreen) {
		this.isFullscreen = fullscreen;
		this.estyle['-stumble-dirty-style'] = '1';
		this.applyEstyle();
	}
}
<commit_msg>Fix bar hiding on redraw in fullscreen<commit_after>function DragNDrop(elem, origin, hash) {
	this.elem = elem;
	this.origin = origin;
	this.hash = hash;
	this.init();
}

DragNDrop.prototype = {
	dpos: {},
	mpos: { mouse: {} },
	oside: {
		left:   'right',
		right:  'left',
		top:    'bottom',
		bottom: 'top',
	},
	estyle: {},

	updateHash: function(hash) {
		this.hash = hash;
	},

	init: function() {
		this.communicateMouseMove = debounce(function() {
			this.sendToBackground({mouse: this.mpos, action: 'mouse'});
		}.bind(this), 100);

		window.addEventListener("mousemove", this.mouseMoveHandler = this.handleMouseMove.bind(this));
		window.addEventListener("message",   this.messageHandler = this.handleMessage.bind(this))
		this.handleRepos({vside: 'bottom', hside: 'left', h: 0, v: 0});
	},

	uninit: function() {
		window.removeEventListener("mousemove", this.mouseMoveHandler);
		window.removeEventListener("message",   this.messageHandler);
	},

	onMessageSendFail: function(cb) {
		this.messageSendFailCallback = cb;
	},

	sendToBackground: function(msg) {
		try {
			chrome.runtime.sendMessage(msg, function(response) {});
		} catch(e) {
			error(e);
			if (this.messageSendFailCallback)
				this.messageSendFailCallback(this);
		}
	},

	handleMouseMove: function(event) {
		if (!(event instanceof MouseEvent)/* || !event.isTrusted*/)
			return;

		this.mpos.mouse.x = event.clientX;
		this.mpos.mouse.y = event.clientY;
		this.mpos.from    = 'window';
		this.mpos.iframe  = { y: this.elem.offsetTop, x: this.elem.offsetLeft }

		this.updateIframePos();
		this.communicateMouseMove();
	},

	updateIframePos: function() {
		if (this.dpos.state == 'drag') {
			var zoom = (this.dpos.internal || {}).zoom || 1;
			//    last pos outside of iframe  - mousedown pos in iframe + change in mouse screen position from mouse down
			if (this.mpos.from == 'iframe') {
				this.mpos.iframe = {
					x: (this.dpos.iframe.x + (this.mpos.internal.screen.x - this.dpos.internal.screen.x)),
					y: (this.dpos.iframe.y + (this.mpos.internal.screen.y - this.dpos.internal.screen.y)),
					w: this.elem.offsetWidth,
					h: this.elem.offsetHeight
				}
			} else {
				this.mpos.iframe = {
					x: (this.mpos.mouse.x - this.dpos.internal.client.x),
					y: (this.mpos.mouse.y - this.dpos.internal.client.y),
					w: this.elem.offsetWidth,
					h: this.elem.offsetHeight
				};
			}

			this.elem.style.left = this.estyle.left = Math.min(window.innerWidth  * zoom - this.elem.offsetWidth , Math.max(0, this.mpos.iframe.x)) + 'px';
			this.elem.style.top  = this.estyle.top  = Math.min(window.innerHeight * zoom - this.elem.offsetHeight, Math.max(0, this.mpos.iframe.y)) + 'px';
			this.estyle['-stumble-dirty-style'] = '1';
		}
	},

	applyEstyle: function(rebuild) {
		var cssText = this.cachedCssText || '';
		if (rebuild || this.estyle['-stumble-dirty-style'] != '0') {
			cssText = '';
			this.estyle['-stumble-dirty-style'] = '0';
			for (var p in this.estyle)
				cssText += p+':'+this.estyle[p]+';';
			this.cachedCssText = cssText;
		}
		if (this.isFullscreen)
			cssText += 'display: none !important;';
		if (this.elem.style.cssText != cssText)
			this.elem.style.cssText = cssText;
	},

	handleRepos: function(rpos, noMargin) {
		this.estyle[rpos.vside] = this.elem.style[rpos.vside] = rpos.v + '%';
		this.estyle[rpos.hside] = this.elem.style[rpos.hside] = rpos.h + '%';
		this.estyle[this.oside[rpos.vside]] = this.elem.style[this.oside[rpos.vside]] = 'initial';
		this.estyle[this.oside[rpos.hside]] = this.elem.style[this.oside[rpos.hside]] = 'initial';

		this.handleTrySnap(rpos)
		this.estyle['-stumble-dirty-style'] = '1';
	},

	handleTrySnap: function(rpos) {
		if (rpos.v <= 1) {
			this.estyle['margin-' + rpos.vside] = this.elem.style['margin-' + rpos.vside] = '-3px';
			this.estyle['margin-' + this.oside[rpos.vside]] = this.elem.style['margin-' + this.oside[rpos.vside]] = 'initial';
			this.estyle[rpos.vside] = this.elem.style[rpos.vside] = '0';
		} else {
			this.estyle['margin-' + rpos.vside] = this.elem.style['margin-' + rpos.vside] = 'initial';
		}
		if (rpos.h <= 1) {
			this.estyle['margin-' + rpos.hside] = this.elem.style['margin-' + rpos.hside] = '-3px';
			this.estyle['margin-' + this.oside[rpos.hside]] = this.elem.style['margin-' + this.oside[rpos.hside]] = 'initial';
			this.estyle[rpos.hside] = this.elem.style[rpos.hside] = '0';
		} else {
			this.estyle['margin-' + rpos.hside] = this.elem.style['margin-' + rpos.hside] = 'initial';
		}
		this.estyle['-stumble-dirty-style'] = '1';
	},

	handleMessage: function(event) {
		if (!event.data || !event.data.type || event.origin != this.origin)
			return;

		var handler = 'handle' + event.data.type[0].toUpperCase() + event.data.type.slice(1) + 'Message';
		this[handler](event.data.message, event.data);
	},

	handleDragMessage: function(message) {
		if (this.dpos.state == 'down') {
			['top', 'left', 'right', 'bottom'].forEach(function(side) {
				this.elem.style['margin-' + side] = 'initial';
			}.bind(this));
			this.dpos.state = 'drag';
		}
		this.mpos.internal = message;
		this.mpos.from = 'iframe';
		this.updateIframePos();
	},

	handleDownMessage: function(message) {
		if (this.dpos.state == 'down')
			return;
		this.dpos = { from: 'iframe', mouse: this.mpos.mouse, iframe: { y: this.elem.offsetTop, x: this.elem.offsetLeft }, internal: message };
		this.mpos = { from: 'iframe', mouse: this.mpos.mouse, iframe: { y: this.elem.offsetTop, x: this.elem.offsetLeft }, internal: message };
		this.dpos.state = 'down';
	},

	handleHideMessage: function(message) {
		this.elem.style.display = this.estyle.display = 'none';
		this.estyle['-stumble-dirty-style'] = '1';
	},

	handleUpMessage: function(message) {
		if (this.dpos.state != 'drag') {
			this.dpos.state = 'up';
			return;
		}
		this.dpos.state = 'up';
		var rpos = {
			v: Math.max((this.elem.offsetTop ) / window.innerHeight * 100, 0),
			h: Math.max((this.elem.offsetLeft) / window.innerWidth  * 100, 0),
			vside: 'top',
			hside: 'left',
		}
		if (rpos.v > 50) {
			rpos.v = Math.max(100 - rpos.v - 100 * this.elem.offsetHeight / window.innerHeight, 0);
			rpos.vside = 'bottom';
		}
		if (rpos.h > 50) {
			rpos.h = Math.max(100 - rpos.h - 100 * this.elem.offsetWidth  / window.innerWidth , 0);
			rpos.hside = 'right';
		}
		this.handleRepos(rpos);
		this.sendToBackground({action: 'repos', from: 'bar', data: { rpos: rpos } }, true);
	},

	handleHoverMessage: function(message) {
		//document.body.overflow = event.data.hover ? 'hidden' : 'initial';
	},

	handleRedrawMessage: function(message) {
		if (message.toolbar.h && message.toolbar.w) {
			this.elem.style.height = this.estyle.height = message.toolbar.h + 'px';
			this.elem.style.width  = this.estyle.width  = message.toolbar.w + 'px';
			this.updateIframePos();
		}
		if (message.toolbar.rpos)
			this.handleRepos(message.toolbar.rpos);
		if (message.toolbar.hidden)
			this.estyle.display = 'none';
		else
			this.estyle.display = 'block';
		this.estyle['-stumble-dirty-style'] = '1';
		if (!this.isFullscreen)
			this.elem.style.display = this.estyle.display;
	},

	fullscreen: function(fullscreen) {
		this.isFullscreen = fullscreen;
		this.estyle['-stumble-dirty-style'] = '1';
		this.applyEstyle();
	}
}
<|endoftext|>


<commit_before>'use strict';

angular.module('events').controller('EventsController', ['$scope',
	function($scope) {

		// TODO: Get events from a database or something.  Don't hard code.
		$scope.events = [
			{
				title: 'WWU Open Source Day',
				day: 'Saturday',
				dayNum: 9,
				month: 'May',
				monthNum: 5,
				description: 'Dive into the world of open source and see how you can contribute to projects and make a difference today!',
				link: 'http://www.wwu.edu/emarket/opensourceday/',
				info:
'
\

Suggested Resources
\

Github\'s Atom text editor.
https://atom.io/
\

Git Resources
\

Try Git tutorial.
https://try.github.io
\

Git Bash.
http://git-scm.com/downloads
\

Github for Mac.
https://mac.github.com/
\

Github for Windows.
https://windows.github.com/
\

Dedicated Table Projects
\

Drupal (Jennifer Dixey)
https://www.drupal.org/
\

KeyMail (NachoBits) (Aaron Griffin)
https://github.com/NachoBits/keymail
\

Language of Languages (Jamie & Andi Douglass)
https://github.com/jamiedouglass/LanguageOfLanguages
\

Able Player (Terry Thompson)
https://github.com/ableplayer/ableplayer
\

Other Suggested Projects
\

MediaWiki (lots of bite-size bugs, written in PHP)
https://openhatch.org/projects/MediaWiki
\

openemr (social interest, looks beginner friendly)
https://openhatch.org/projects/openemr
\

OLPC (One Laptop per Child, social interest)
https://openhatch.org/projects/OLPC
\

gedit (bite-sized bugs, documentation)
http://openhatch.org/projects/gedit
\

Mifos (social interest, written in Java)
http://openhatch.org/projects/Mifos
\

Dreamwidth (lots of bite-sized bugs)
https://openhatch.org/projects/Dreamwidth
\

openspending (social/political interest, written in Python)
https://openhatch.org/projects/openspending
\

sympy (for math lovers, lots of bite-sized bugs, written in Python)
https://openhatch.org/projects/sympy
\

Firefox (lots of bite-sized bugs)
https://openhatch.org/projects/Firefox
\

'
			},
			{
				title: 'Whatcom Robotics Expo',
				day: 'Saturday',
				dayNum: 27,
				month: 'June',
				monthNum: 6,
				description: 'Whatcom county is full of different robotics groups!  Experience them all under one roof and build your path in engineering from Kindergarten to College!',
				link: 'https://www.facebook.com/events/1076239542392620/'
			}
		]
	}
]);
<commit_msg>Add cpython dedicated project to OSD event.<commit_after>'use strict';

angular.module('events').controller('EventsController', ['$scope',
	function($scope) {

		// TODO: Get events from a database or something.  Don't hard code.
		$scope.events = [
			{
				title: 'WWU Open Source Day',
				day: 'Saturday',
				dayNum: 9,
				month: 'May',
				monthNum: 5,
				description: 'Dive into the world of open source and see how you can contribute to projects and make a difference today!',
				link: 'http://www.wwu.edu/emarket/opensourceday/',
				info:
'
\

Suggested Resources
\

Github\'s Atom text editor.
https://atom.io/
\

Git Resources
\

Try Git tutorial.
https://try.github.io
\

Git Bash.
http://git-scm.com/downloads
\

Github for Mac.
https://mac.github.com/
\

Github for Windows.
https://windows.github.com/
\

Dedicated Table Projects
\

Drupal (Jennifer Dixey)
https://www.drupal.org/
\

KeyMail (NachoBits) (Aaron Griffin)
https://github.com/NachoBits/keymail
\

Language of Languages (Jamie & Andi Douglass)
https://github.com/jamiedouglass/LanguageOfLanguages
\

Able Player (Terry Thompson)
https://github.com/ableplayer/ableplayer
\

cpython (Alex Lord)
https://openhatch.org/search/?q=&language=Python
\

Other Suggested Projects
\

MediaWiki (lots of bite-size bugs, written in PHP)
https://openhatch.org/projects/MediaWiki
\

openemr (social interest, looks beginner friendly)
https://openhatch.org/projects/openemr
\

OLPC (One Laptop per Child, social interest)
https://openhatch.org/projects/OLPC
\

gedit (bite-sized bugs, documentation)
http://openhatch.org/projects/gedit
\

Mifos (social interest, written in Java)
http://openhatch.org/projects/Mifos
\

Dreamwidth (lots of bite-sized bugs)
https://openhatch.org/projects/Dreamwidth
\

openspending (social/political interest, written in Python)
https://openhatch.org/projects/openspending
\

sympy (for math lovers, lots of bite-sized bugs, written in Python)
https://openhatch.org/projects/sympy
\

Firefox (lots of bite-sized bugs)
https://openhatch.org/projects/Firefox
\

'
			},
			{
				title: 'Whatcom Robotics Expo',
				day: 'Saturday',
				dayNum: 27,
				month: 'June',
				monthNum: 6,
				description: 'Whatcom county is full of different robotics groups!  Experience them all under one roof and build your path in engineering from Kindergarten to College!',
				link: 'https://www.facebook.com/events/1076239542392620/'
			}
		]
	}
]);
<|endoftext|>


<commit_before>'use strict';

// Articles controller
angular.module('events').controller('EventsController', ['$scope', '$stateParams', '$location', 'Authentication', 'Events',
	function($scope, $stateParams, $location, Authentication, Events) {
		$scope.authentication = Authentication;

		// Create new Article
		$scope.create = function() {

			var googlePlaces = searchBox.getPlaces();
            var location;
            if (googlePlaces) {
            	var longitude = googlePlaces[0].geometry.location.lng();
				var latitude = googlePlaces[0].geometry.location.lat();

				location = [longitude, latitude];
		    }
			// Create new Article object
			var eventmodel = new Events({
				title: this.title,
				content: this.content,
				location: location
			});

			// Redirect after save
			eventmodel.$save(function(response) {
				$location.path('events/' + response._id);

				// Clear form fields
				$scope.title = '';
				$scope.content = '';
			}, function(errorResponse) {
				$scope.error = errorResponse.data.message;
			});
		};

		// Remove existing Article
		$scope.remove = function(eventmodel) {
			if (eventmodel) {
				eventmodel.$remove();

				for (var i in $scope.eventmodels) {
					if ($scope.eventmodels[i] === eventmodel) {
						$scope.eventmodels.splice(i, 1);
					}
				}
			} else {
				$scope.eventmodel.$remove(function() {
					$location.path('eventmodels');
				});
			}
		};

		// Update existing Article
		$scope.update = function() {
			var eventmodel = $scope.eventmodel;

			eventmodel.$update(function() {
				$location.path('events/' + eventmodel._id);
			}, function(errorResponse) {
				$scope.error = errorResponse.data.message;
			});
		};

		// Find a list of Articles
		$scope.find = function() {
			$scope.events = Events.query();
		};

		// Find existing Article
		$scope.findOne = function() {
			$scope.eventmodel = Events.get({
				eventId: $stateParams.eventId
			});
		};

		var input = document.getElementById('place');
		if(input)
		{
        	var searchBox = new google.maps.places.SearchBox(input);
        }
	}
]);<commit_msg>Fix some syntax bugs<commit_after>'use strict';

// Articles controller
angular.module('events').controller('EventsController', ['$scope', '$stateParams', '$location', 'Authentication', 'Events',
	function($scope, $stateParams, $location, Authentication, Events) {
		$scope.authentication = Authentication;
		var	searchBox;
		// Create new Article
		$scope.create = function() {

			var googlePlaces = searchBox.getPlaces(),
          location;

      if(googlePlaces) {
      	var longitude = googlePlaces[0].geometry.location.lng(),
						latitude = googlePlaces[0].geometry.location.lat();
				location = [longitude, latitude];
		   }

			// Create new Article object
			var eventmodel = new Events({
				title: this.title,
				content: this.content,
				location: location
			});

			// Redirect after save
			eventmodel.$save(function(response) {
				$location.path('events/' + response._id);

				// Clear form fields
				$scope.title = '';
				$scope.content = '';
			}, function(errorResponse) {
				$scope.error = errorResponse.data.message;
			});
		};

		// Remove existing Article
		$scope.remove = function(eventmodel) {
			if (eventmodel) {
				eventmodel.$remove();

				for (var i in $scope.eventmodels) {
					if ($scope.eventmodels[i] === eventmodel) {
						$scope.eventmodels.splice(i, 1);
					}
				}
			} else {
				$scope.eventmodel.$remove(function() {
					$location.path('eventmodels');
				});
			}
		};

		// Update existing Article
		$scope.update = function() {
			var eventmodel = $scope.eventmodel;

			eventmodel.$update(function() {
				$location.path('events/' + eventmodel._id);
			}, function(errorResponse) {
				$scope.error = errorResponse.data.message;
			});
		};

		// Find a list of Articles
		$scope.find = function() {
			$scope.events = Events.query();
		};

		// Find existing Article
		$scope.findOne = function() {
			$scope.eventmodel = Events.get({
				eventId: $stateParams.eventId
			});
		};

		var input = document.getElementById('place');
		if(input) {
      searchBox = new google.maps.places.SearchBox(input);
    }
	}
]);
<|endoftext|>