<commit_before>/*
Copyright 2015, 2016 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

var React = require("react");
var classNames = require('classnames');
var sdk = require("../../../index");
var Invite = require("../../../Invite");
var createRoom = require("../../../createRoom");
var MatrixClientPeg = require("../../../MatrixClientPeg");
var DMRoomMap = require('../../../utils/DMRoomMap');
var rate_limited_func = require("../../../ratelimitedfunc");
var dis = require("../../../dispatcher");
var Modal = require('../../../Modal');

const TRUNCATE_QUERY_LIST = 40;

module.exports = React.createClass({
    displayName: "ChatInviteDialog",
    propTypes: {
        title: React.PropTypes.string,
        description: React.PropTypes.oneOfType([
            React.PropTypes.element,
            React.PropTypes.string,
        ]),
        value: React.PropTypes.string,
        placeholder: React.PropTypes.string,
        roomId: React.PropTypes.string,
        button: React.PropTypes.string,
        focus: React.PropTypes.bool,
        onFinished: React.PropTypes.func.isRequired
    },

    getDefaultProps: function() {
        return {
            title: "Start a chat",
            description: "Who would you like to communicate with?",
            value: "",
            placeholder: "Email, name or matrix ID",
            button: "Start Chat",
            focus: true
        };
    },

    getInitialState: function() {
        return {
            error: false,
            inviteList: [],
            queryList: [],
        };
    },

    componentDidMount: function() {
        if (this.props.focus) {
            // Set the cursor at the end of the text input
            this.refs.textinput.value = this.props.value;
        }
        this._updateUserList();
    },

    onButtonClick: function() {
        var inviteList = this.state.inviteList.slice();
        // Check the text input field to see if user has an unconverted address
        // If there is and it's valid add it to the local inviteList
        const addrType = Invite.getAddressType(this.refs.textinput.value);
        if (addrType !== null) {
            inviteList.push(this.refs.textinput.value);
        } else if (this.refs.textinput.value.length > 0) {
            this.setState({ error: true });
            return;
        }

        if (inviteList.length > 0) {
            if (this._isDmChat(inviteList)) {
                // Direct Message chat
                var room = this._getDirectMessageRoom(inviteList[0]);
                if (room) {
                    // A Direct Message room already exists for this user and you
                    // so go straight to that room
                    dis.dispatch({
                        action: 'view_room',
                        room_id: room.roomId,
                    });
                    this.props.onFinished(true, inviteList[0]);
                } else {
                    this._startChat(inviteList);
                }
            } else {
                // Multi invite chat
                this._startChat(inviteList);
            }
        } else {
            // No addresses supplied
            this.setState({ error: true });
        }
    },

    onCancel: function() {
        this.props.onFinished(false);
    },

    onKeyDown: function(e) {
        if (e.keyCode === 27) { // escape
            e.stopPropagation();
            e.preventDefault();
            this.props.onFinished(false);
        } else if (e.keyCode === 38) { // up arrow
            e.stopPropagation();
            e.preventDefault();
            this.addressSelector.moveSelectionUp();
        } else if (e.keyCode === 40) { // down arrow
            e.stopPropagation();
            e.preventDefault();
            this.addressSelector.moveSelectionDown();
        } else if (this.state.queryList.length > 0 && (e.keyCode === 188 || e.keyCode === 13 || e.keyCode === 9)) { // comma or enter or tab
            e.stopPropagation();
            e.preventDefault();
            this.addressSelector.chooseSelection();
        } else if (this.refs.textinput.value.length === 0 && this.state.inviteList.length && e.keyCode === 8) { // backspace
            e.stopPropagation();
            e.preventDefault();
            this.onDismissed(this.state.inviteList.length - 1)();
        } else if (e.keyCode === 13) { // enter
            e.stopPropagation();
            e.preventDefault();
            if (this.refs.textinput.value == '') {
                // if there's nothing in the input box, submit the form
                this.onButtonClick();
            } else {
                const addrType = Invite.getAddressType(this.refs.textinput.value);
                if (addrType !== null) {
                    const inviteList = this.state.inviteList.slice();
                    inviteList.push(this.refs.textinput.value.trim());
                    this.setState({
                        inviteList: inviteList,
                        queryList: [],
                    });
                } else {
                    this.setState({ error: true });
                }
            }
        } else if (e.keyCode === 188 || e.keyCode === 9) { // comma or tab
            e.stopPropagation();
            e.preventDefault();
            const addrType = Invite.getAddressType(this.refs.textinput.value);
            if (addrType !== null) {
                var inviteList = this.state.inviteList.slice();
                inviteList.push(this.refs.textinput.value.trim());
                this.setState({
                    inviteList: inviteList,
                    queryList: [],
                });
            } else {
                this.setState({ error: true });
            }
        }
    },

    onQueryChanged: function(ev) {
        var query = ev.target.value;
        var queryList = [];

        // Only do search if there is something to search
        if (query.length > 0) {
            queryList = this._userList.filter((user) => {
                return this._matches(query, user);
            });
        }

        this.setState({
            queryList: queryList,
            error: false,
        });
    },

    onDismissed: function(index) {
        var self = this;
        return function() {
            var inviteList = self.state.inviteList.slice();
            inviteList.splice(index, 1);
            self.setState({
                inviteList: inviteList,
                queryList: [],
            });
        }
    },

    onClick: function(index) {
        var self = this;
        return function() {
            self.onSelected(index);
        };
    },

    onSelected: function(index) {
        var inviteList = this.state.inviteList.slice();
        inviteList.push(this.state.queryList[index].userId);
        this.setState({
            inviteList: inviteList,
            queryList: [],
        });
    },

    _getDirectMessageRoom: function(addr) {
        const dmRoomMap = new DMRoomMap(MatrixClientPeg.get());
        var dmRooms = dmRoomMap.getDMRoomsForUserId(addr);
        if (dmRooms.length > 0) {
            // Cycle through all the DM rooms and find the first non forgotten or parted room
            for (let i = 0; i < dmRooms.length; i++) {
                let room = MatrixClientPeg.get().getRoom(dmRooms[i]);
                if (room) {
                    const me = room.getMember(MatrixClientPeg.get().credentials.userId);
                    if (me.membership == 'join') {
                        return room;
                    }
                }
            }
        }
        return null;
    },

    _startChat: function(addrs) {
        if (MatrixClientPeg.get().isGuest()) {
            var NeedToRegisterDialog = sdk.getComponent("dialogs.NeedToRegisterDialog");
            Modal.createDialog(NeedToRegisterDialog, {
                title: "Please Register",
                description: "Guest users can't invite users. Please register."
            });
            return;
        }

        if (this.props.roomId) {
            // Invite new user to a room
            var self = this;
            Invite.inviteMultipleToRoom(this.props.roomId, addrs)
            .then(function(addrs) {
                var room = MatrixClientPeg.get().getRoom(self.props.roomId);
                return self._showAnyInviteErrors(addrs, room);
            })
            .catch(function(err) {
                console.error(err.stack);
                var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
                Modal.createDialog(ErrorDialog, {
                    title: "Failure to invite",
                    description: err.toString()
                });
                return null;
            })
            .done();
        } else if (this._isDmChat(addrs)) {
            // Start the DM chat
            createRoom({dmUserId: addrs[0]})
            .catch(function(err) {
                console.error(err.stack);
                var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
                Modal.createDialog(ErrorDialog, {
                    title: "Failure to invite user",
                    description: err.toString()
                });
                return null;
            })
            .done();
        } else {
            // Start multi user chat
            var self = this;
            var room;
            createRoom().then(function(roomId) {
                room = MatrixClientPeg.get().getRoom(roomId);
                return Invite.inviteMultipleToRoom(roomId, addrs);
            })
            .then(function(addrs) {
                return self._showAnyInviteErrors(addrs, room);
            })
            .catch(function(err) {
                console.error(err.stack);
                var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
                Modal.createDialog(ErrorDialog, {
                    title: "Failure to invite",
                    description: err.toString()
                });
                return null;
            })
            .done();
        }

        // Close - this will happen before the above, as that is async
        this.props.onFinished(true, addrs);
    },

    _updateUserList: new rate_limited_func(function() {
        // Get all the users
        this._userList = MatrixClientPeg.get().getUsers();
    }, 500),

    // This is the search algorithm for matching users
    _matches: function(query, user) {
        var name = user.displayName.toLowerCase();
        var uid = user.userId.toLowerCase();
        query = query.toLowerCase();

        // don't match any that are already on the invite list
        if (this._isOnInviteList(uid)) {
            return false;
        }

        // ignore current user
        if (uid === MatrixClientPeg.get().credentials.userId) {
            return false;
        }

        // direct prefix matches
        if (name.indexOf(query) === 0 || uid.indexOf(query) === 0) {
            return true;
        }

        // strip @ on uid and try matching again
        if (uid.length > 1 && uid[0] === "@" && uid.substring(1).indexOf(query) === 0) {
            return true;
        }

        // split spaces in name and try matching constituent parts
        var parts = name.split(" ");
        for (var i = 0; i < parts.length; i++) {
            if (parts[i].indexOf(query) === 0) {
                return true;
            }
        }
        return false;
    },

    _isOnInviteList: function(uid) {
        for (let i = 0; i < this.state.inviteList.length; i++) {
            if (this.state.inviteList[i].toLowerCase() === uid) {
                return true;
            }
        }
        return false;
    },

    _isDmChat: function(addrs) {
        if (addrs.length === 1 && Invite.getAddressType(addrs[0]) === "mx" && !this.props.roomId) {
            return true;
        } else {
            return false;
        }
    },

    _showAnyInviteErrors: function(addrs, room) {
        // Show user any errors
        var errorList = [];
        for (var addr in addrs) {
            if (addrs.hasOwnProperty(addr) && addrs[addr] === "error") {
                errorList.push(addr);
            }
        }

        if (errorList.length > 0) {
            var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
            Modal.createDialog(ErrorDialog, {
                title: "Failed to invite the following users to the " + room.name + " room:",
                description: errorList.join(", "),
            });
        }
        return addrs;
    },

    render: function() {
        var TintableSvg = sdk.getComponent("elements.TintableSvg");
        var AddressSelector = sdk.getComponent("elements.AddressSelector");
        this.scrollElement = null;

        var query = [];
        // create the invite list
        if (this.state.inviteList.length > 0) {
            var AddressTile = sdk.getComponent("elements.AddressTile");
            for (let i = 0; i < this.state.inviteList.length; i++) {
                query.push(
                    <AddressTile key={i} address={this.state.inviteList[i]} canDismiss={true} onDismissed={ this.onDismissed(i) } />
                );
            }
        }

        // Add the query at the end
        query.push(
            <textarea key={this.state.inviteList.length}
                rows="1"
                id="textinput"
                ref="textinput"
                className="mx_ChatInviteDialog_input"
                onChange={this.onQueryChanged}
                placeholder={this.props.placeholder}
                defaultValue={this.props.value}
                autoFocus={this.props.focus}>
            </textarea>
        );

        var error;
        var addressSelector;
        if (this.state.error) {
            error =
You have entered an invalid contact. Try using their Matrix ID or email address.

        } else {
            addressSelector = (
                <AddressSelector ref={(ref) => {this.addressSelector = ref}}
                    addressList={ this.state.queryList }
                    onSelected={ this.onSelected }
                    truncateAt={ TRUNCATE_QUERY_LIST } />
            );
        }

        return (

                    {this.props.title}

                    <TintableSvg src="img/icons-close-button.svg" width="35" height="35" />

                    { this.props.description }

{ query }

                    { error }
                    { addressSelector }

                    <button className="mx_Dialog_primary" onClick={this.onButtonClick}>
                        {this.props.button}
                    </button>

        );
    }
});
<commit_msg>Factor out adding the input field to the list<commit_after>/*
Copyright 2015, 2016 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

var React = require("react");
var classNames = require('classnames');
var sdk = require("../../../index");
var Invite = require("../../../Invite");
var createRoom = require("../../../createRoom");
var MatrixClientPeg = require("../../../MatrixClientPeg");
var DMRoomMap = require('../../../utils/DMRoomMap');
var rate_limited_func = require("../../../ratelimitedfunc");
var dis = require("../../../dispatcher");
var Modal = require('../../../Modal');

const TRUNCATE_QUERY_LIST = 40;

module.exports = React.createClass({
    displayName: "ChatInviteDialog",
    propTypes: {
        title: React.PropTypes.string,
        description: React.PropTypes.oneOfType([
            React.PropTypes.element,
            React.PropTypes.string,
        ]),
        value: React.PropTypes.string,
        placeholder: React.PropTypes.string,
        roomId: React.PropTypes.string,
        button: React.PropTypes.string,
        focus: React.PropTypes.bool,
        onFinished: React.PropTypes.func.isRequired
    },

    getDefaultProps: function() {
        return {
            title: "Start a chat",
            description: "Who would you like to communicate with?",
            value: "",
            placeholder: "Email, name or matrix ID",
            button: "Start Chat",
            focus: true
        };
    },

    getInitialState: function() {
        return {
            error: false,
            inviteList: [],
            queryList: [],
        };
    },

    componentDidMount: function() {
        if (this.props.focus) {
            // Set the cursor at the end of the text input
            this.refs.textinput.value = this.props.value;
        }
        this._updateUserList();
    },

    onButtonClick: function() {
        let inviteList = this.state.inviteList.slice();
        // Check the text input field to see if user has an unconverted address
        // If there is and it's valid add it to the local inviteList
        if (this.refs.textinput.value !== '') {
            inviteList = this._addInputToList();
            if (inviteList === false) return;
        }

        if (inviteList.length > 0) {
            if (this._isDmChat(inviteList)) {
                // Direct Message chat
                var room = this._getDirectMessageRoom(inviteList[0]);
                if (room) {
                    // A Direct Message room already exists for this user and you
                    // so go straight to that room
                    dis.dispatch({
                        action: 'view_room',
                        room_id: room.roomId,
                    });
                    this.props.onFinished(true, inviteList[0]);
                } else {
                    this._startChat(inviteList);
                }
            } else {
                // Multi invite chat
                this._startChat(inviteList);
            }
        } else {
            // No addresses supplied
            this.setState({ error: true });
        }
    },

    onCancel: function() {
        this.props.onFinished(false);
    },

    onKeyDown: function(e) {
        if (e.keyCode === 27) { // escape
            e.stopPropagation();
            e.preventDefault();
            this.props.onFinished(false);
        } else if (e.keyCode === 38) { // up arrow
            e.stopPropagation();
            e.preventDefault();
            this.addressSelector.moveSelectionUp();
        } else if (e.keyCode === 40) { // down arrow
            e.stopPropagation();
            e.preventDefault();
            this.addressSelector.moveSelectionDown();
        } else if (this.state.queryList.length > 0 && (e.keyCode === 188 || e.keyCode === 13 || e.keyCode === 9)) { // comma or enter or tab
            e.stopPropagation();
            e.preventDefault();
            this.addressSelector.chooseSelection();
        } else if (this.refs.textinput.value.length === 0 && this.state.inviteList.length && e.keyCode === 8) { // backspace
            e.stopPropagation();
            e.preventDefault();
            this.onDismissed(this.state.inviteList.length - 1)();
        } else if (e.keyCode === 13) { // enter
            e.stopPropagation();
            e.preventDefault();
            if (this.refs.textinput.value == '') {
                // if there's nothing in the input box, submit the form
                this.onButtonClick();
            } else {
                this._addInputToList();
            }
        } else if (e.keyCode === 188 || e.keyCode === 9) { // comma or tab
            e.stopPropagation();
            e.preventDefault();
            this._addInputToList();
        }
    },

    onQueryChanged: function(ev) {
        var query = ev.target.value;
        var queryList = [];

        // Only do search if there is something to search
        if (query.length > 0) {
            queryList = this._userList.filter((user) => {
                return this._matches(query, user);
            });
        }

        this.setState({
            queryList: queryList,
            error: false,
        });
    },

    onDismissed: function(index) {
        var self = this;
        return function() {
            var inviteList = self.state.inviteList.slice();
            inviteList.splice(index, 1);
            self.setState({
                inviteList: inviteList,
                queryList: [],
            });
        }
    },

    onClick: function(index) {
        var self = this;
        return function() {
            self.onSelected(index);
        };
    },

    onSelected: function(index) {
        var inviteList = this.state.inviteList.slice();
        inviteList.push(this.state.queryList[index].userId);
        this.setState({
            inviteList: inviteList,
            queryList: [],
        });
    },

    _getDirectMessageRoom: function(addr) {
        const dmRoomMap = new DMRoomMap(MatrixClientPeg.get());
        var dmRooms = dmRoomMap.getDMRoomsForUserId(addr);
        if (dmRooms.length > 0) {
            // Cycle through all the DM rooms and find the first non forgotten or parted room
            for (let i = 0; i < dmRooms.length; i++) {
                let room = MatrixClientPeg.get().getRoom(dmRooms[i]);
                if (room) {
                    const me = room.getMember(MatrixClientPeg.get().credentials.userId);
                    if (me.membership == 'join') {
                        return room;
                    }
                }
            }
        }
        return null;
    },

    _startChat: function(addrs) {
        if (MatrixClientPeg.get().isGuest()) {
            var NeedToRegisterDialog = sdk.getComponent("dialogs.NeedToRegisterDialog");
            Modal.createDialog(NeedToRegisterDialog, {
                title: "Please Register",
                description: "Guest users can't invite users. Please register."
            });
            return;
        }

        if (this.props.roomId) {
            // Invite new user to a room
            var self = this;
            Invite.inviteMultipleToRoom(this.props.roomId, addrs)
            .then(function(addrs) {
                var room = MatrixClientPeg.get().getRoom(self.props.roomId);
                return self._showAnyInviteErrors(addrs, room);
            })
            .catch(function(err) {
                console.error(err.stack);
                var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
                Modal.createDialog(ErrorDialog, {
                    title: "Failure to invite",
                    description: err.toString()
                });
                return null;
            })
            .done();
        } else if (this._isDmChat(addrs)) {
            // Start the DM chat
            createRoom({dmUserId: addrs[0]})
            .catch(function(err) {
                console.error(err.stack);
                var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
                Modal.createDialog(ErrorDialog, {
                    title: "Failure to invite user",
                    description: err.toString()
                });
                return null;
            })
            .done();
        } else {
            // Start multi user chat
            var self = this;
            var room;
            createRoom().then(function(roomId) {
                room = MatrixClientPeg.get().getRoom(roomId);
                return Invite.inviteMultipleToRoom(roomId, addrs);
            })
            .then(function(addrs) {
                return self._showAnyInviteErrors(addrs, room);
            })
            .catch(function(err) {
                console.error(err.stack);
                var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
                Modal.createDialog(ErrorDialog, {
                    title: "Failure to invite",
                    description: err.toString()
                });
                return null;
            })
            .done();
        }

        // Close - this will happen before the above, as that is async
        this.props.onFinished(true, addrs);
    },

    _updateUserList: new rate_limited_func(function() {
        // Get all the users
        this._userList = MatrixClientPeg.get().getUsers();
    }, 500),

    // This is the search algorithm for matching users
    _matches: function(query, user) {
        var name = user.displayName.toLowerCase();
        var uid = user.userId.toLowerCase();
        query = query.toLowerCase();

        // don't match any that are already on the invite list
        if (this._isOnInviteList(uid)) {
            return false;
        }

        // ignore current user
        if (uid === MatrixClientPeg.get().credentials.userId) {
            return false;
        }

        // direct prefix matches
        if (name.indexOf(query) === 0 || uid.indexOf(query) === 0) {
            return true;
        }

        // strip @ on uid and try matching again
        if (uid.length > 1 && uid[0] === "@" && uid.substring(1).indexOf(query) === 0) {
            return true;
        }

        // split spaces in name and try matching constituent parts
        var parts = name.split(" ");
        for (var i = 0; i < parts.length; i++) {
            if (parts[i].indexOf(query) === 0) {
                return true;
            }
        }
        return false;
    },

    _isOnInviteList: function(uid) {
        for (let i = 0; i < this.state.inviteList.length; i++) {
            if (this.state.inviteList[i].toLowerCase() === uid) {
                return true;
            }
        }
        return false;
    },

    _isDmChat: function(addrs) {
        if (addrs.length === 1 && Invite.getAddressType(addrs[0]) === "mx" && !this.props.roomId) {
            return true;
        } else {
            return false;
        }
    },

    _showAnyInviteErrors: function(addrs, room) {
        // Show user any errors
        var errorList = [];
        for (var addr in addrs) {
            if (addrs.hasOwnProperty(addr) && addrs[addr] === "error") {
                errorList.push(addr);
            }
        }

        if (errorList.length > 0) {
            var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
            Modal.createDialog(ErrorDialog, {
                title: "Failed to invite the following users to the " + room.name + " room:",
                description: errorList.join(", "),
            });
        }
        return addrs;
    },

    _addInputToList: function() {
        const addrType = Invite.getAddressType(this.refs.textinput.value);
        if (addrType !== null) {
            const inviteList = this.state.inviteList.slice();
            inviteList.push(this.refs.textinput.value.trim());
            this.setState({
                inviteList: inviteList,
                queryList: [],
            });
            return inviteList;
        } else {
            this.setState({ error: true });
            return false;
        }
    },

    render: function() {
        var TintableSvg = sdk.getComponent("elements.TintableSvg");
        var AddressSelector = sdk.getComponent("elements.AddressSelector");
        this.scrollElement = null;

        var query = [];
        // create the invite list
        if (this.state.inviteList.length > 0) {
            var AddressTile = sdk.getComponent("elements.AddressTile");
            for (let i = 0; i < this.state.inviteList.length; i++) {
                query.push(
                    <AddressTile key={i} address={this.state.inviteList[i]} canDismiss={true} onDismissed={ this.onDismissed(i) } />
                );
            }
        }

        // Add the query at the end
        query.push(
            <textarea key={this.state.inviteList.length}
                rows="1"
                id="textinput"
                ref="textinput"
                className="mx_ChatInviteDialog_input"
                onChange={this.onQueryChanged}
                placeholder={this.props.placeholder}
                defaultValue={this.props.value}
                autoFocus={this.props.focus}>
            </textarea>
        );

        var error;
        var addressSelector;
        if (this.state.error) {
            error =
You have entered an invalid contact. Try using their Matrix ID or email address.

        } else {
            addressSelector = (
                <AddressSelector ref={(ref) => {this.addressSelector = ref}}
                    addressList={ this.state.queryList }
                    onSelected={ this.onSelected }
                    truncateAt={ TRUNCATE_QUERY_LIST } />
            );
        }

        return (

                    {this.props.title}

                    <TintableSvg src="img/icons-close-button.svg" width="35" height="35" />

                    { this.props.description }

{ query }

                    { error }
                    { addressSelector }

                    <button className="mx_Dialog_primary" onClick={this.onButtonClick}>
                        {this.props.button}
                    </button>

        );
    }
});
<|endoftext|>


<commit_before>var cluster = require('cluster'),
    http = require('http'),
    os = require('os'),
    fs = require('fs'),
    path = require('path'),
    Q = require('q'),

    cpuCount = os.cpus().length,

    imageCache = [];

function readFile(file) {
    var deferred = Q.defer();

    fs.readFile(path.join(__dirname, 'assets', file), function(err, data) {
        deferred.resolve(data);
    });

    return deferred.promise;
}

function putAllToMemory(files) {
    var promises = [];

    files.forEach(function(file) {
        promises.push(readFile(file).then(function(data) {
            imageCache.push(data);
        }));
    });

    return Q.all(promises);
}

function getFileList() {
    var dir = path.join(__dirname, 'assets'),
        deferred = Q.defer();

    fs.readdir(dir, function(err, files) {
        deferred.resolve(files);
    });

    return deferred.promise;
}

function putAssetsIntoMemory() {
    return getFileList().then(function(files) {
        return putAllToMemory(files);
    });
}

function getRandomIndex() {
    return Math.floor(Math.random()*(imageCache.length+1));
}

function startForking() {
    var i, len, currentIndex = 0;

    if (cluster.isMaster) {
        for(i = 0, len = cpuCount; i < len; i++) {
            var worker = cluster.fork();

            worker.on('message', function(message) {
                if (message === 'fetch-index') {

                    worker.send({action:'update-index', data: getRandomIndex()});
                }
            });
        }
    } else {
        var currentResponse = null;

        http.createServer(function(req, res) {
            console.log('sending to process');
            currentResponse = res;

            process.send('fetch-index');
        }).listen(8000);

        process.on('message', function(meta) {
            console.log('on message');

            if (meta.action !== 'update-index') {return;}

            var index = meta.data,
                image = imageCache[index];

            console.log(currentResponse);

            currentResponse.statusCode = 200;
            currentResponse.setHeader('Content-Type', 'image/png');

            currentResponse.end(image);
        });

        // TODO: respawn the child process if it dies.
    }
}

putAssetsIntoMemory().then(function() {
    startForking();
});
<commit_msg>lastworking.<commit_after>var cluster = require('cluster'),
    http = require('http'),
    os = require('os'),
    fs = require('fs'),
    path = require('path'),
    Q = require('q'),

    cpuCount = os.cpus().length,

    imageCache = [];

function readFile(file) {
    var deferred = Q.defer();

    fs.readFile(path.join(__dirname, 'assets', file), function(err, data) {
        deferred.resolve(data);
    });

    return deferred.promise;
}

function putAllToMemory(files) {
    var promises = [];

    files.forEach(function(file) {
        promises.push(readFile(file).then(function(data) {
            imageCache.push(data);
        }));
    });

    return Q.all(promises);
}

function getFileList() {
    var dir = path.join(__dirname, 'assets'),
        deferred = Q.defer();

    fs.readdir(dir, function(err, files) {
        deferred.resolve(files);
    });

    return deferred.promise;
}

function putAssetsIntoMemory() {
    return getFileList().then(function(files) {
        return putAllToMemory(files);
    });
}

function getRandomIndex() {
    return Math.floor(Math.random()*(imageCache.length+1));
}

function startForking() {
    var i, len, currentIndex = 0;

    if (cluster.isMaster) {
        for(i = 0, len = cpuCount; i < len; i++) {
            var worker = cluster.fork();

            worker.on('message', function(message) {
                if (message === 'fetch-index') {

                    worker.send({action:'update-index', data: getRandomIndex()});
                }
            });
        }

        cluster.on('exit', function() {
            cluster.fork();
        })
    } else {
        var currentResponse = null;

        http.createServer(function(req, res) {
            console.log('sending to process');
            currentResponse = res;

            process.send('fetch-index');
        }).listen(3005);

        process.on('message', function(meta) {
            console.log('on message');

            if (meta.action !== 'update-index') {return;}

            var index = meta.data,
                image = imageCache[index];

            console.log(currentResponse);

            currentResponse.statusCode = 200;
            currentResponse.setHeader('Content-Type', 'image/png');

            currentResponse.end(image);
        });
    }
}

putAssetsIntoMemory().then(function() {
    startForking();
});
<|endoftext|>


<commit_before>var worklog  = require('level-worklog')
var contpara = require('continuable-para')
var pull     = require('pull-stream')
var pl       = require('pull-level')
var paramap  = require('pull-paramap')
var bytewise = require('bytewise/hex')
//53 bit integer
var MAX_INT  = 0x1fffffffffffff

var encode = bytewise.encode

module.exports = function (db, opts) {

  var logDB = db.sublevel('log')
  var clockDB = db.sublevel('clk')
  var lastDB = db.sublevel('lst')

  function get (db, key) {
    return function (cb) { db.get(encode(key), cb) }
  }

  worklog(db, logDB)

  var validation = require('./validation')(db, opts)

  db.pre(function (op, add) {
    var msg = op.value
    // index by sequence number
    add({
      key: encode([msg.author, msg.sequence]), value: op.key,
      type: 'put', prefix: clockDB
    })
    // index the latest message from each author
    add({
      key: encode(msg.author), value: msg.sequence,
      type: 'put', prefix: lastDB
    })
  })

  db.getPublicKey = function (id, cb) {
    function cont (cb) {
      clockDB.get(encode([id, 1]), function (err, hash) {
      if(err) return cb(err)
       db.get(hash, function (err, msg) {
          if(err) return cb(err)
          cb(null, msg.message)
        })
      })
    }
    return cb ? cont(cb) : cont
  }

  db.add = function (msg, cb) {
    //check that msg is valid (follows from end of database)
    //then insert into database.
    validation.validate(msg, cb)
  }

  db.createFeedStream = function (id, opts) {
    opts = opts || {}
    opts.start = encode([id, 0])
    opts.end = encode([id, MAX_INT])
    opts.keys = false
    return pull(
      pl.read(clockDB, opts),
      paramap(function (key, cb) {
        db.get(key, cb)
      })
    )

  }

  return db
d}
<commit_msg>support the needed methods for replication<commit_after>var worklog  = require('level-worklog')
var contpara = require('continuable-para')
var pull     = require('pull-stream')
var pl       = require('pull-level')
var paramap  = require('pull-paramap')
var bytewise = require('bytewise/hex')
//53 bit integer
var MAX_INT  = 0x1fffffffffffff

var encode = bytewise.encode

module.exports = function (db, opts) {

  var logDB = db.sublevel('log')
  var feedDB = db.sublevel('fd')
  var clockDB = db.sublevel('clk')
  var lastDB = db.sublevel('lst')

  function get (db, key) {
    return function (cb) { db.get(encode(key), cb) }
  }

  worklog(db, logDB)

  var validation = require('./validation')(db, opts)

  db.pre(function (op, add) {
    var msg = op.value
    // index by sequence number
    add({
      key: encode([msg.author, msg.sequence]), value: op.key,
      type: 'put', prefix: clockDB
    })
    add({
      key: encode([msg.timestamp, msg.author]), value: op.key,
      type: 'put', prefix: feedDB
    })
    // index the latest message from each author
    add({
      key: encode(msg.author), value: msg.sequence,
      type: 'put', prefix: lastDB
    })
  })

  db.getPublicKey = function (id, cb) {
    function cont (cb) {
      clockDB.get(encode([id, 1]), function (err, hash) {
      if(err) return cb(err)
       db.get(hash, function (err, msg) {
          if(err) return cb(err)
          cb(null, msg.message)
        })
      })
    }
    return cb ? cont(cb) : cont
  }

  db.add = function (msg, cb) {
    //check that msg is valid (follows from end of database)
    //then insert into database.
    var n = 1
    validation.validate(msg, function (err) {
      console.error(err)
      if(--n) throw new Error('called twice')
      cb(err)
    })
  }

  db.createFeedStream = function (id, opts) {
    opts = opts || {}
    opts.start = encode([id, 0])
    opts.end = encode([id, MAX_INT])
    opts.keys = false
    return pull(
      pl.read(clockDB, opts),
      paramap(function (key, cb) {
        db.get(key, cb)
      })
    )

  }

  db.latest = function (opts) {
    return pull(
      pl.read(lastDB),
      pull.map(function (data) {
        var d = {id: bytewise.decode(data.key), sequence: data.value}
        console.log(d)
        return d
      })
    )
  }

  db.follow = function (other, cb) {
    lastDB.put(encode(other), 0, cb)
  }

  db.createHistoryStream = function (id, seq, live) {
    return pull(
      pl.read(clockDB, {
        start:   encode([id, seq]),
        end:  encode([id, MAX_INT]),
        tail: live, live: live,
        keys: false
      }),
      paramap(function (key, cb) {
        db.get(key, cb)
      })
    )
  }

  db.createWriteStream = function (cb) {
    return pull(
      paramap(function (data, cb) {
        db.add(data, cb)
      }),
      pull.drain(null, cb)
    )
  }

  return db
}
<|endoftext|>


<commit_before>import * as textQuote from 'dom-anchor-text-quote'
import highlightRange from 'dom-highlight-range'

export function isSelectionWithinCorpus({ selection, corpus }) {
    if (selection === null || selection.isCollapsed) {
        return false
    }

    const range = selection.getRangeAt(0)
    return isWithinNode(range, corpus)
}

export async function selectionToDescriptor({ selection }) {
    if (selection === null || selection.isCollapsed) {
        return null
    }

    const range = selection.getRangeAt(0)
    const root = document.body
    return {
        strategy: 'dom-anchor-text-quote',
        content: textQuote.fromRange(root, range),
    }
}

export async function descriptorToRange({ descriptor }) {
    const root = document.body
    return textQuote.toRange(root, descriptor.content)
}

export function markRange({ range, cssClass }) {
    highlightRange(range, cssClass)
}

function isWithinNode(range, node) {
    const nodeRange = document.createRange()
    nodeRange.selectNode(node)

    return (
        range.compareBoundaryPoints(Range.START_TO_START, nodeRange) >= 0 &&
        range.compareBoundaryPoints(Range.END_TO_END, nodeRange) <= 0
    )
}
<commit_msg>Make anchoring more redundant<commit_after>import * as domTextQuote from 'dom-anchor-text-quote'
import * as domTextPosition from 'dom-anchor-text-position'
import highlightRange from 'dom-highlight-range'

export function isSelectionWithinCorpus({ selection, corpus }) {
    if (selection === null || selection.isCollapsed) {
        return false
    }

    const range = selection.getRangeAt(0)
    return isWithinNode(range, corpus)
}

export async function selectionToDescriptor({ selection }) {
    if (selection === null || selection.isCollapsed) {
        return null
    }

    const range = selection.getRangeAt(0)
    const root = document.body
    const textQuote = domTextQuote.fromRange(root, range)
    const textPosition = domTextPosition.fromRange(root, range)
    return {
        strategy: 'dom-anchor-text-position-or-quote',
        content: {
            textQuote,
            textPosition,
            string: range.toString(),
        },
    }
}

export async function descriptorToRange({ descriptor }) {
    const root = document.body
    if (descriptor.strategy === 'dom-anchor-text-quote') {
        return domTextQuote.toRange(root, descriptor.content)
    }

    const rangeFromPosition = domTextPosition.toRange(root, descriptor.content)
    if (rangeFromPosition.toString() === descriptor.content.string) {
        return rangeFromPosition
    }

    const rangeFromQuote = domTextQuote.toRange(
        root,
        descriptor.content.textQuote,
    )
    if (
        hasAncestor(
            rangeFromQuote.commonAncestorContainer,
            node => node.tagName === 'script',
        )
    ) {
        return null
    }

    return rangeFromQuote
}

export function markRange({ range, cssClass }) {
    highlightRange(range, cssClass)
}

function isWithinNode(range, node) {
    const nodeRange = document.createRange()
    nodeRange.selectNode(node)

    return (
        range.compareBoundaryPoints(Range.START_TO_START, nodeRange) >= 0 &&
        range.compareBoundaryPoints(Range.END_TO_END, nodeRange) <= 0
    )
}

function hasAncestor(node, test) {
    while (node !== document.body) {
        if (test(node)) {
            return true
        }
        node = node.parentNode
    }

    return false
}
<|endoftext|>


<commit_before>/**
 * Pieter Colpaert © Ghent University - iMinds
 * Combines connection rules, trips and services to an unsorted stream of connections
 */
var Transform = require('stream').Transform,
  util = require('util'),
  URIStrategy = require('./URIStrategy.js');

var Connections2JSONLD = function (baseUris, context) {
  Transform.call(this, { objectMode: true });
  this._contextStreamed = false;
  this._context = context;

  // Skip context if none provided
  if(!this._context) {
    this._contextStreamed = true;
  }

  this._uris = new URIStrategy(baseUris);
  this._count = 0;
};

util.inherits(Connections2JSONLD, Transform);

Connections2JSONLD.prototype._transform = function (connection, encoding, done) {
  try {
    if (!this._contextStreamed) {
      this._contextStreamed = true;
      done(null, this._context);
    } else {
      var id = this._uris.getId(connection);
      const types = ['gtfs:Regular', 'gtfs:NotAvailable', 'gtfs:MustPhone', 'gtfs:MustCoordinateWithDriver'];

      var lc = {
        "@id": id,
        "@type": "Connection",
        "departureStop": this._uris.getStopId(connection.departureStop),
        "arrivalStop": this._uris.getStopId(connection.arrivalStop),
        "departureTime": connection.departureTime,
        "arrivalTime": connection.arrivalTime,
        "gtfs:trip": this._uris.getTripId(connection),
        "gtfs:route": this._uris.getRouteId(connection)
      };

      // the headsign is already the result here of earlier checking whether there’s a trip headsign
      // or a route headsign if connection headsign was not set. It can be used reliably
      if (connection.headsign) {
        lc["direction"] = connection.headsign;
      }

      var pickupType = types[0];
      if (connection['pickup_type'] && connection['pickup_type'] !== null) {
        pickupType = types[connection['pickup_type']];
        lc["gtfs:pickupType"] = pickupType;
      }

      var dropOffType = types[0];
      if (connection['drop_off_type'] && connection['drop_off_type'] !== null) {
        dropOffType = types[connection['drop_off_type']];
        lc["gtfs:dropOffType"] = dropOffType;
      }

      done(null, lc);
    }
  } catch (err) {
    done(null, {});
  }
};

module.exports = Connections2JSONLD;
<commit_msg>Fix bug on JSON-LD conversion<commit_after>/**
 * Pieter Colpaert © Ghent University - iMinds
 * Combines connection rules, trips and services to an unsorted stream of connections
 */
var Transform = require('stream').Transform,
  util = require('util'),
  URIStrategy = require('./URIStrategy.js');

var Connections2JSONLD = function (baseUris, context) {
  Transform.call(this, { objectMode: true });
  this._contextStreamed = false;
  this._context = context;

  // Skip context if none provided
  if (!this._context) {
    this._contextStreamed = true;
  }

  this._uris = new URIStrategy(baseUris);
  this._count = 0;
};

util.inherits(Connections2JSONLD, Transform);

Connections2JSONLD.prototype._transform = function (connection, encoding, done) {
  try {
    if (!this._contextStreamed) {
      this._contextStreamed = true;
      this.push(this._context);
    }

    var id = this._uris.getId(connection);
    const types = ['gtfs:Regular', 'gtfs:NotAvailable', 'gtfs:MustPhone', 'gtfs:MustCoordinateWithDriver'];

    var lc = {
      "@id": id,
      "@type": "Connection",
      "departureStop": this._uris.getStopId(connection.departureStop),
      "arrivalStop": this._uris.getStopId(connection.arrivalStop),
      "departureTime": connection.departureTime,
      "arrivalTime": connection.arrivalTime,
      "gtfs:trip": this._uris.getTripId(connection),
      "gtfs:route": this._uris.getRouteId(connection)
    };

    // the headsign is already the result here of earlier checking whether there’s a trip headsign
    // or a route headsign if connection headsign was not set. It can be used reliably
    if (connection.headsign) {
      lc["direction"] = connection.headsign;
    }

    var pickupType = types[0];
    if (connection['pickup_type'] && connection['pickup_type'] !== null) {
      pickupType = types[connection['pickup_type']];
      lc["gtfs:pickupType"] = pickupType;
    }

    var dropOffType = types[0];
    if (connection['drop_off_type'] && connection['drop_off_type'] !== null) {
      dropOffType = types[connection['drop_off_type']];
      lc["gtfs:dropOffType"] = dropOffType;
    }

    this.push(lc);
    done();
  } catch (err) {
    done(null, {});
  }
};

module.exports = Connections2JSONLD;
<|endoftext|>


<commit_before>/**
 * Pieter Colpaert © Ghent University - iMinds
 * Combines connection rules, trips and services to an unsorted stream of connections
 */
var Transform = require('stream').Transform,
  util = require('util'),
  URIStrategy = require('./URIStrategy.js');

var Connections2JSONLD = function (baseUris, context) {
  Transform.call(this, { objectMode: true });
  this.context = context || {
    "@context": {
      "lc": "http://semweb.mmlab.be/ns/linkedconnections#",
      "Connection": "http://semweb.mmlab.be/ns/linkedconnections#Connection",
      "gtfs": "http://vocab.gtfs.org/terms#",
      "departureStop": {
        "@type": "@id",
        "@id": "http://semweb.mmlab.be/ns/linkedconnections#departureStop"
      },
      "arrivalStop": {
        "@type": "@id",
        "@id": "http://semweb.mmlab.be/ns/linkedconnections#arrivalStop"
      },
      "departureTime": "http://semweb.mmlab.be/ns/linkedconnections#departureTime",
      "arrivalTime": "http://semweb.mmlab.be/ns/linkedconnections#arrivalTime",
      "direction": "gtfs:headsign"
    }
  };

  this._uris = new URIStrategy(baseUris);
  this._count = 0;
};

util.inherits(Connections2JSONLD, Transform);

Connections2JSONLD.prototype._transform = function (connection, encoding, done) {
  var id = this._uris.getId(connection);
  const types = ['gtfs:Regular', 'gtfs:NotAvailable', 'gtfs:MustPhone', 'gtfs:MustCoordinateWithDriver'];

  var lc = {
    "@id": id,
    "@type": "Connection",
    "departureStop": this._uris.getStopId(connection.departureStop),
    "arrivalStop": this._uris.getStopId(connection.arrivalStop),
    "departureTime": connection.departureTime.toISOString(),
    "arrivalTime": connection.arrivalTime.toISOString(),
    "gtfs:trip": this._uris.getTripId(connection),
    "gtfs:route": this._uris.getRouteId(connection)
  };

  if (connection.departure_stop_headsign) {
    lc["direction"] = connection.trip.trip_headsign;
  } else if (connection.trip.trip_headsign) {
    lc["direction"] = connection.trip.trip_headsign;
  }

  var pickupType = types[0];
  if (connection['pickup_type'] && connection['pickup_type'] !== null) {
    pickupType = types[connection['pickup_type']];
    lc["gtfs:pickupType"] = pickupType;
  }

  var dropOffType = types[0];
  if (connection['drop_off_type'] && connection['drop_off_type'] !== null) {
    dropOffType = types[connection['drop_off_type']];
    lc["gtfs:dropOffType"] = pickupType;
  }

  done(null, lc);
};

module.exports = Connections2JSONLD;
<commit_msg>Fixes #58<commit_after>/**
 * Pieter Colpaert © Ghent University - iMinds
 * Combines connection rules, trips and services to an unsorted stream of connections
 */
var Transform = require('stream').Transform,
  util = require('util'),
  URIStrategy = require('./URIStrategy.js');

var Connections2JSONLD = function (baseUris, context) {
  Transform.call(this, { objectMode: true });
  this.context = context || {
    "@context": {
      "lc": "http://semweb.mmlab.be/ns/linkedconnections#",
      "Connection": "http://semweb.mmlab.be/ns/linkedconnections#Connection",
      "gtfs": "http://vocab.gtfs.org/terms#",
      "departureStop": {
        "@type": "@id",
        "@id": "http://semweb.mmlab.be/ns/linkedconnections#departureStop"
      },
      "arrivalStop": {
        "@type": "@id",
        "@id": "http://semweb.mmlab.be/ns/linkedconnections#arrivalStop"
      },
      "departureTime": "http://semweb.mmlab.be/ns/linkedconnections#departureTime",
      "arrivalTime": "http://semweb.mmlab.be/ns/linkedconnections#arrivalTime",
      "direction": "gtfs:headsign"
    }
  };

  this._uris = new URIStrategy(baseUris);
  this._count = 0;
};

util.inherits(Connections2JSONLD, Transform);

Connections2JSONLD.prototype._transform = function (connection, encoding, done) {
  var id = this._uris.getId(connection);
  const types = ['gtfs:Regular', 'gtfs:NotAvailable', 'gtfs:MustPhone', 'gtfs:MustCoordinateWithDriver'];

  var lc = {
    "@id": id,
    "@type": "Connection",
    "departureStop": this._uris.getStopId(connection.departureStop),
    "arrivalStop": this._uris.getStopId(connection.arrivalStop),
    "departureTime": connection.departureTime.toISOString(),
    "arrivalTime": connection.arrivalTime.toISOString(),
    "gtfs:trip": this._uris.getTripId(connection),
    "gtfs:route": this._uris.getRouteId(connection)
  };

  if (connection.departure_stop_headsign) {
    lc["direction"] = connection.trip.trip_headsign;
  } else if (connection.trip.trip_headsign) {
    lc["direction"] = connection.trip.trip_headsign;
  }

  var pickupType = types[0];
  if (connection['pickup_type'] && connection['pickup_type'] !== null) {
    pickupType = types[connection['pickup_type']];
    lc["gtfs:pickupType"] = pickupType;
  }

  var dropOffType = types[0];
  if (connection['drop_off_type'] && connection['drop_off_type'] !== null) {
    dropOffType = types[connection['drop_off_type']];
    lc["gtfs:dropOffType"] = dropOffType;
  }

  done(null, lc);
};

module.exports = Connections2JSONLD;
<|endoftext|>


<commit_before>'use strict';

/**
 * @license
 * (c) 2014 Cluster Labs, Inc. https://cluster.co/
 * License: MIT
 */

var events = require('events');
var fs = require('fs');
var util = require('util');

var Handlebars = require('handlebars');

var loader = require('./loader/loader');
var scriptresource = require('./loader/scriptresource');
var skitutil = require('./skitutil');

var TargetEnvironment = scriptresource.TargetEnvironment;

Handlebars.registerHelper('json', function(arg) {
  return new Handlebars.SafeString(skitutil.safeJSONStringify(arg));
});

var BOOTSTRAP_TEMPLATE = (function() {
  var templateSource = fs.readFileSync(__dirname + '/bootstrap.html').toString();
  return Handlebars.compile(templateSource);
})();

var NET_SERVER_MODULE = 'skit.platform.net:server';
var COOKIES_SERVER_MODULE = 'skit.platform.cookies:server';
var NAVIGATION_MODULE = 'skit.platform.navigation';
var PROXY_MODULE = 'skit.platform.netproxy';
var PROXY_RESOURCE = PROXY_MODULE + ':js';

function ControllerRenderer(server, controllerModule, request) {
  events.EventEmitter.apply(this);

  this.server = server;
  this.module = controllerModule;
  this.resources = loader.loadResourcesForModule(controllerModule);
  this.request = request;

  this.setupProxies_();
  this.setupNet_();
  this.setupCookies_();
};
util.inherits(ControllerRenderer, events.EventEmitter);

ControllerRenderer.ERROR = 'error';
ControllerRenderer.NOT_FOUND = 'notfound';
ControllerRenderer.REDIRECT = 'redirect';
ControllerRenderer.WRITE_HTML = 'html';
ControllerRenderer.DONE_WRITING = 'done';

ControllerRenderer.prototype.setupProxies_ = function() {
  var netproxy = this.resources.objectsByModulePath[PROXY_MODULE];
  if (!netproxy) {
    return;
  }

  this.server.eachProxy(function(name, proxy) {
    var reqWrap = {
      headers: this.request.headers,
      getCookie: this.request.getCookie
    };
    var resWrap = {
      getCookie: this.request.getCookie,
      setCookie: this.request.setCookie
    };

    var apiRequest;
    netproxy.__register__(name, {
      modifyRequestInternal: (function(apiRequest_) {
        apiRequest = apiRequest_;
        try {
          proxy.modifyRequest(reqWrap, apiRequest);
        } catch(e) {
          this.emit(ControllerRenderer.ERROR, e);
        }
      }).bind(this),
      modifyResponseInternal: (function(apiResponse) {
        try {
          proxy.modifyResponse(apiRequest, apiResponse, resWrap);
        } catch(e) {
          this.emit(ControllerRenderer.ERROR, e);
        }
      }).bind(this)
    }, this);
  }, this);
};

ControllerRenderer.prototype.setupNet_ = function() {
  var net = this.resources.objectsByModulePath[NET_SERVER_MODULE];
  if (!net) {
    return;
  }

  net.__setErrorHandler__((function(e) {
    this.emit(ControllerRenderer.ERROR, e);
  }).bind(this));
};

ControllerRenderer.prototype.setupCookies_ = function() {
  var cookies = this.resources.objectsByModulePath[COOKIES_SERVER_MODULE];
  if (!cookies) {
    return;
  }

  cookies.__setGetSet__(this.request.getCookie, this.request.setCookie);
};

ControllerRenderer.prototype.serve = function() {
  var ControllerKlass = this.resources.objectsByModulePath[this.module.modulePath];
  if (!ControllerKlass || !ControllerKlass.__controller__) {
    // Only controller modules should exist inside "public".
    var err = new Error('Module at this path is not a controller.');
    this.emit(ControllerRenderer.ERROR, err);
    return;
  }

  var headers = {};
  ['host', 'referer'].forEach(function(header) {
    headers[header] = this.request.headers[header];
  }, this);

  var requestWrap = {
    url: this.request.url,
    params: this.request.params,
    query: this.request.query,
    headers: headers,
  };
  this.controller = new ControllerKlass(requestWrap);

  var controllersToLoadInOrder = [];
  var CurrentControllerKlass = ControllerKlass;
  while (CurrentControllerKlass) {
    controllersToLoadInOrder.unshift(CurrentControllerKlass);
    CurrentControllerKlass = CurrentControllerKlass.__parent__;
  }

  var loadNext = (function() {
    var CurrentControllerKlass = controllersToLoadInOrder.shift();
    if (!CurrentControllerKlass) {
      this.render();
      return;
    }

    this.preloadController(CurrentControllerKlass, loadNext);
  }).bind(this);

  loadNext();
};

ControllerRenderer.prototype.preloadController = function(ControllerKlass, onComplete) {
  var navigation = this.resources.objectsByModulePath[NAVIGATION_MODULE];
  if (navigation) {
    navigation.__reset__(this.request.url, this.request.headers['user-agent']);
  }

  var hasPreload = ControllerKlass.prototype.hasOwnProperty('__preload__');
  var preload = ControllerKlass.prototype.__preload__;
  if (!hasPreload) {
    preload = function defaultPreload(f) { f(); };
  }

  var preloadComplete = (function(var_args) {
    if (navigation) {
      if (navigation.__notfound__()) {
        this.emit(ControllerRenderer.NOT_FOUND);
        return;
      }

      var redirectUrl = navigation.__redirect__();
      if (redirectUrl) {
        this.emit(ControllerRenderer.REDIRECT, redirectUrl);
        return;
      }
    }

    var hasLoad = ControllerKlass.prototype.hasOwnProperty('__load__');
    var load = hasLoad ? ControllerKlass.prototype.__load__ : function defaultLoad() {};
    load.apply(this.controller);

    onComplete();
  }).bind(this);

  try {
    preload.call(this.controller, preloadComplete);
  } catch (e) {
    this.emit(ControllerRenderer.ERROR, e);
  }
};

ControllerRenderer.prototype.render = function() {
  var controllerProperties = {};
  for (var k in this.controller) {
    if (this.controller.hasOwnProperty(k)) {
      controllerProperties[k] = this.controller[k];
    }
  }

  try {
    var title = this.controller.getFullTitle();
    var meta = this.controller.getFullMeta();
    var body = this.controller.renderFullBody();
  } catch (e) {
    this.emit(ControllerRenderer.ERROR, e);
    return;
  }

  var cssUrls = this.resources.cssResources.map(function(resource) {
    return this.server.getResourceUrl(resource);
  }, this);
  cssUrls = skitutil.unique(cssUrls);

  var scripts = this.resources.scriptResources;
  var scriptUrls = scripts.map(function(resource) {
    if (!resource.includeInEnvironment(TargetEnvironment.BROWSER)) {
      // continue
      return null;
    }
    return this.server.getResourceUrl(resource);
  }, this);
  scriptUrls = skitutil.unique(scriptUrls.filter(function(url) { return !!url; }));

  var clientProxyObjects = [];
  this.server.eachProxy(function(name, proxy) {
    clientProxyObjects.push({
      name: name,
      csrfToken: proxy.generateCSRF(this.request)
    });
  }, this);

  var controllerModuleResourcePath = scripts[scripts.length - 1].modulePath;
  var html = BOOTSTRAP_TEMPLATE({
    title: title,
    meta: meta,
    body: body,
    currentUrlAfterRedirect: this.request.originalUrl !== this.request.url ? this.request.url : null,

    cssUrls: cssUrls,
    scriptUrls: scriptUrls,

    netproxyModulePath: PROXY_RESOURCE,
    clientProxyObjects: clientProxyObjects,

    controllerModulePath: controllerModuleResourcePath,
    controllerProperties: controllerProperties,
  });

  // TODO(taylor): Render CSS before the preload is done.
  this.emit(ControllerRenderer.WRITE_HTML, html);
  this.emit(ControllerRenderer.DONE_WRITING);
};

module.exports = ControllerRenderer;
<commit_msg>Catch JSON encode errors so we can figure out what object is the problem.<commit_after>'use strict';

/**
 * @license
 * (c) 2014 Cluster Labs, Inc. https://cluster.co/
 * License: MIT
 */

var events = require('events');
var fs = require('fs');
var util = require('util');

var Handlebars = require('handlebars');

var loader = require('./loader/loader');
var scriptresource = require('./loader/scriptresource');
var skitutil = require('./skitutil');

var TargetEnvironment = scriptresource.TargetEnvironment;

Handlebars.registerHelper('json', function(arg) {
  try {
    return new Handlebars.SafeString(skitutil.safeJSONStringify(arg));
  } catch (e) {
    var err = new Error('Could not JSON-encode object: ' + arg);
    err.originalError = e;
    throw err;
  }
});

var BOOTSTRAP_TEMPLATE = (function() {
  var templateSource = fs.readFileSync(__dirname + '/bootstrap.html').toString();
  return Handlebars.compile(templateSource);
})();

var NET_SERVER_MODULE = 'skit.platform.net:server';
var COOKIES_SERVER_MODULE = 'skit.platform.cookies:server';
var NAVIGATION_MODULE = 'skit.platform.navigation';
var PROXY_MODULE = 'skit.platform.netproxy';
var PROXY_RESOURCE = PROXY_MODULE + ':js';

function ControllerRenderer(server, controllerModule, request) {
  events.EventEmitter.apply(this);

  this.server = server;
  this.module = controllerModule;
  this.resources = loader.loadResourcesForModule(controllerModule);
  this.request = request;

  this.setupProxies_();
  this.setupNet_();
  this.setupCookies_();
};
util.inherits(ControllerRenderer, events.EventEmitter);

ControllerRenderer.ERROR = 'error';
ControllerRenderer.NOT_FOUND = 'notfound';
ControllerRenderer.REDIRECT = 'redirect';
ControllerRenderer.WRITE_HTML = 'html';
ControllerRenderer.DONE_WRITING = 'done';

ControllerRenderer.prototype.setupProxies_ = function() {
  var netproxy = this.resources.objectsByModulePath[PROXY_MODULE];
  if (!netproxy) {
    return;
  }

  this.server.eachProxy(function(name, proxy) {
    var reqWrap = {
      headers: this.request.headers,
      getCookie: this.request.getCookie
    };
    var resWrap = {
      getCookie: this.request.getCookie,
      setCookie: this.request.setCookie
    };

    var apiRequest;
    netproxy.__register__(name, {
      modifyRequestInternal: (function(apiRequest_) {
        apiRequest = apiRequest_;
        try {
          proxy.modifyRequest(reqWrap, apiRequest);
        } catch(e) {
          this.emit(ControllerRenderer.ERROR, e);
        }
      }).bind(this),
      modifyResponseInternal: (function(apiResponse) {
        try {
          proxy.modifyResponse(apiRequest, apiResponse, resWrap);
        } catch(e) {
          this.emit(ControllerRenderer.ERROR, e);
        }
      }).bind(this)
    }, this);
  }, this);
};

ControllerRenderer.prototype.setupNet_ = function() {
  var net = this.resources.objectsByModulePath[NET_SERVER_MODULE];
  if (!net) {
    return;
  }

  net.__setErrorHandler__((function(e) {
    this.emit(ControllerRenderer.ERROR, e);
  }).bind(this));
};

ControllerRenderer.prototype.setupCookies_ = function() {
  var cookies = this.resources.objectsByModulePath[COOKIES_SERVER_MODULE];
  if (!cookies) {
    return;
  }

  cookies.__setGetSet__(this.request.getCookie, this.request.setCookie);
};

ControllerRenderer.prototype.serve = function() {
  var ControllerKlass = this.resources.objectsByModulePath[this.module.modulePath];
  if (!ControllerKlass || !ControllerKlass.__controller__) {
    // Only controller modules should exist inside "public".
    var err = new Error('Module at this path is not a controller.');
    this.emit(ControllerRenderer.ERROR, err);
    return;
  }

  var headers = {};
  ['host', 'referer'].forEach(function(header) {
    headers[header] = this.request.headers[header];
  }, this);

  var requestWrap = {
    url: this.request.url,
    params: this.request.params,
    query: this.request.query,
    headers: headers,
  };
  this.controller = new ControllerKlass(requestWrap);

  var controllersToLoadInOrder = [];
  var CurrentControllerKlass = ControllerKlass;
  while (CurrentControllerKlass) {
    controllersToLoadInOrder.unshift(CurrentControllerKlass);
    CurrentControllerKlass = CurrentControllerKlass.__parent__;
  }

  var loadNext = (function() {
    var CurrentControllerKlass = controllersToLoadInOrder.shift();
    if (!CurrentControllerKlass) {
      this.render();
      return;
    }

    this.preloadController(CurrentControllerKlass, loadNext);
  }).bind(this);

  loadNext();
};

ControllerRenderer.prototype.preloadController = function(ControllerKlass, onComplete) {
  var navigation = this.resources.objectsByModulePath[NAVIGATION_MODULE];
  if (navigation) {
    navigation.__reset__(this.request.url, this.request.headers['user-agent']);
  }

  var hasPreload = ControllerKlass.prototype.hasOwnProperty('__preload__');
  var preload = ControllerKlass.prototype.__preload__;
  if (!hasPreload) {
    preload = function defaultPreload(f) { f(); };
  }

  var preloadComplete = (function(var_args) {
    if (navigation) {
      if (navigation.__notfound__()) {
        this.emit(ControllerRenderer.NOT_FOUND);
        return;
      }

      var redirectUrl = navigation.__redirect__();
      if (redirectUrl) {
        this.emit(ControllerRenderer.REDIRECT, redirectUrl);
        return;
      }
    }

    var hasLoad = ControllerKlass.prototype.hasOwnProperty('__load__');
    var load = hasLoad ? ControllerKlass.prototype.__load__ : function defaultLoad() {};
    load.apply(this.controller);

    onComplete();
  }).bind(this);

  try {
    preload.call(this.controller, preloadComplete);
  } catch (e) {
    this.emit(ControllerRenderer.ERROR, e);
  }
};

ControllerRenderer.prototype.render = function() {
  var controllerProperties = {};
  for (var k in this.controller) {
    if (this.controller.hasOwnProperty(k)) {
      controllerProperties[k] = this.controller[k];
    }
  }

  try {
    var title = this.controller.getFullTitle();
    var meta = this.controller.getFullMeta();
    var body = this.controller.renderFullBody();
  } catch (e) {
    this.emit(ControllerRenderer.ERROR, e);
    return;
  }

  var cssUrls = this.resources.cssResources.map(function(resource) {
    return this.server.getResourceUrl(resource);
  }, this);
  cssUrls = skitutil.unique(cssUrls);

  var scripts = this.resources.scriptResources;
  var scriptUrls = scripts.map(function(resource) {
    if (!resource.includeInEnvironment(TargetEnvironment.BROWSER)) {
      // continue
      return null;
    }
    return this.server.getResourceUrl(resource);
  }, this);
  scriptUrls = skitutil.unique(scriptUrls.filter(function(url) { return !!url; }));

  var clientProxyObjects = [];
  this.server.eachProxy(function(name, proxy) {
    clientProxyObjects.push({
      name: name,
      csrfToken: proxy.generateCSRF(this.request)
    });
  }, this);

  var controllerModuleResourcePath = scripts[scripts.length - 1].modulePath;
  var html = BOOTSTRAP_TEMPLATE({
    title: title,
    meta: meta,
    body: body,
    currentUrlAfterRedirect: this.request.originalUrl !== this.request.url ? this.request.url : null,

    cssUrls: cssUrls,
    scriptUrls: scriptUrls,

    netproxyModulePath: PROXY_RESOURCE,
    clientProxyObjects: clientProxyObjects,

    controllerModulePath: controllerModuleResourcePath,
    controllerProperties: controllerProperties,
  });

  // TODO(taylor): Render CSS before the preload is done.
  this.emit(ControllerRenderer.WRITE_HTML, html);
  this.emit(ControllerRenderer.DONE_WRITING);
};

module.exports = ControllerRenderer;
<|endoftext|>


<commit_before>
//Dummy wrapper for console.log for IE9
if (!(window.console && console.log)) {
    console = {
        log: function () { },
        debug: function () { },
        info: function () { },
        warn: function () { },
        error: function () { }
    };
}

function navigate(hash) {
    console.log(hash);
    if (hash.length == 0) hash = '#o';
    hash = hash.toLowerCase();
    var anchor = hash.substring(1);
    var parts = anchor.split('-');
    var toppage = parts[0];

    // reset everything
    $('.tablesorter-childRow>td').hide();
    $('.dropdown2>td').hide();
    $('.primaryrow>td').show();
    $('.primaryrow2>td').show();
    // make arrows point the right way
    $('.icon-chevron-down').removeClass('icon-chevron-down').addClass('icon-chevron-right');
    $('.primaryrow').css('background-color', '#ffffff');

    $('.nav-collapse ul li').removeClass('active');
    $('div.reportpage').hide();
    $('#' + toppage + '-nav').addClass('active');
    $('#' + toppage).show();

    if (parts.length > 1) {
        var primary = parts[1];
        console.log("primary = " + primary);

        var iconid = "#" + toppage + "-" + primary + "--icon";
        var dropdownid = "#" + toppage + "-" + primary + "--dropdown";

        $(dropdownid).show();
        $(iconid).parentsUntil("tbody", 'tr').css('background-color', '#dddddd');
        $(iconid).removeClass('icon-chevron-right').addClass('icon-chevron-down');

        if (parts.length > 2) {
            var secondary = parts[2];
            console.log("secondary = " + secondary);

            var iconid2 = "#" + toppage + "-" + primary + "-" + secondary + "--icon";
            var dropdownid2 = "#" + toppage + "-" + primary + "-" + secondary + "--dropdown";

            $(dropdownid2).show();
            $(iconid2).removeClass('icon-chevron-right').addClass('icon-chevron-down');
        }
    }
}

$(document).ready(function () {

    $('#o').find('br').remove();//for removing br form id o

    var hash = window.location.hash.substr(1);
    if (hash == "" || hash == undefined) {
        $("#o-nav").addClass('active');
    } else {
        $('ul.catalogNav').children().removeClass('active');
        $("#" + hash + "-nav").addClass('active');
    }

    $('body').bind('touchmove', function (e) {
        e.preventDefault();
    });

    $(window).bind('hashchange', function () {

        var hash = window.location.hash.substr(1);
        $('ul.catalogNav').children().removeClass('active');
        $("#" + hash + "-nav").addClass('active');
    });

    var timeOut = (navigator.userAgent.indexOf('Firefox') >= 0) ? 20 : 1;

    $(".catalogNav > li > a").on("click", function () {

        setTimeout(function() {
            window.scrollTo(0, 0);
        }, timeOut);
    });

    $.extend($.tablesorter.themes.bootstrap, {
        // these classes are added to the table. To see other table classes available,
        // look here: http://twitter.github.com/bootstrap/base-css.html#tables
        table: 'table table-bordered',
        header: 'bootstrap-header', // give the header a gradient background
        footerRow: '',
        footerCells: '',
        icons: '', // add "icon-white" to make them white; this icon class is added to the <i> in the header
        sortNone: 'bootstrap-icon-unsorted',
        sortAsc: 'icon-chevron-up',
        sortDesc: 'icon-chevron-down',
        active: '', // applied when column is sorted
        hover: '', // use custom css here - bootstrap class may not override it
        filterRow: '', // filter row class
        even: '', // odd row zebra striping
        odd: ''  // even row zebra striping
    });

    $(".tableL1").tablesorter({
        theme: 'bootstrap',
        widthFixed: true,
        headerTemplate: '{content} {icon}',
        widgets: ["uitheme", "filter", "stickyHeaders"],
        widgetOptions: {
            filter_reset: ".reset",
            filter_hideFilters: true
        },
        cssChildRow: "tablesorter-childRow"
    });

    $('.tableL1').delegate('.togglex', 'click', function () {
        var id = $(this).attr('id');
        var toppage = id.split('-')[0];
        var dropdownid = "#" + id + "--dropdown";

        var hash = "#" + id;
        if ($(dropdownid).is(":visible")) {
            hash = "#" + toppage;
        }
        // history.replaceState(null, null, hash);
        navigate(hash);
        $('.cb').prop('checked', false);
        return false;
    });

    $('.tableL2').delegate('.togglex', 'click', function () {
        var id = $(this).attr('id');

        console.log("l2click: " + id);

        var parts = id.split('-');
        var toppage = parts[0];
        var primary = parts[1];
        var dropdownid = "#" + id + "--dropdown";

        var hash = "#" + id;
        if ($(dropdownid).is(":visible")) {
            console.log("l2clickVISIBLE");
            hash = "#" + toppage + "-" + primary;
        }
        else {
            console.log("not visible");
        }
        // history.replaceState(null, null, hash);
        navigate(hash);
        $('.cb').prop('checked', false);
        return false;
    });

    $(".tableL3").tablesorter({
        theme: 'bootstrap',
        widthFixed: true,
        headerTemplate: '{content} {icon}',
        widgets: ["uitheme", "filter", "stickyHeaders"],
        widgetOptions: {
            filter_reset: ".reset",
            filter_hideFilters: true
        },
        cssChildRow: "tablesorter-childRow"
    });

    $('.tableL3').delegate('.togglex', 'click', function () {
        var id = $(this).attr('id');
        var toppage = id.split('-')[0];
        var dropdownid = "#" + id + "--dropdown";

        var hash = "#" + id;
        if ($(dropdownid).is(":visible")) {
            hash = "#" + toppage;
        }
        // history.replaceState(null, null, hash);
        navigate(hash);
        return false;
    });

    $(".cb").click(function(){
        if($(this).is(":checked")) {
            var elementList = $(".tableL1").find(".togglex");
            for ( var i = 0; i < elementList.length; i++ ) {
                var item = elementList[i];
                var id = item["id"];

                var anchor = id.toLowerCase().substring(1);
                var parts = anchor.split('-');
                var toppage = parts[0];

                if (parts.length > 1) {
                    var primary = parts[1];
                    var iconid = "#" + toppage + "-" + primary + "--icon";
                    var dropdownid = "#" + id + "--dropdown";
                    $(iconid).removeClass('icon-chevron-right').addClass('icon-chevron-down');
                    $(dropdownid).show();
                    var disableLink = function(){ return false;};
					$('a').bind('click', disableLink);
                    if (parts.length > 2) {
                        var secondary = parts[2];
                        var iconid2 = "#" + toppage + "-" + primary + "-" + secondary + "--icon";
                        var dropdownid2 = "#" + toppage + "-" + primary + "-" + secondary + "--dropdown";
                        $(iconid2).removeClass('icon-chevron-right').addClass('icon-chevron-down');
                        $(dropdownid2).show();
                    }
                }
            }
        }else {
            // reset everything
            $('.tablesorter-childRow>td').hide();
            $('.dropdown2>td').hide();
            $('.primaryrow>td').show();
            $('.primaryrow2>td').show();
            // make arrows point the right way
            $('.icon-chevron-down').removeClass('icon-chevron-down').addClass('icon-chevron-right');
            $('.primaryrow').css('background-color', '#ffffff');
            $('a').unbind('click', disableLink);
        }
    });

    navigate($(location).attr('hash'));

    $(window).bind('hashchange', function () { //detect hash change
        navigate(window.location.hash);
    });

     //tooltips
    $('.l-Table').popover({
        trigger: 'focus hover', delay: { show: 500, hide: 100 }, placement: 'top', content:
            'Persistent Relational Table'
    });
    $('.l-Materialized_View').popover({
        trigger: 'focus hover', delay: { show: 500, hide: 100 }, placement: 'top', content:
            'Views are always materialized and incrementally maintained.'
    });
    $('.l-Replicated').popover({
        trigger: 'focus hover', delay: { show: 500, hide: 100 }, placement: 'top', content:
            'Table data is present at all partitions. Updates are a multi-partition operation.'
    });
    $('.l-Partitioned').popover({
        trigger: 'focus hover', delay: { show: 500, hide: 100 }, placement: 'top', content:
            'Table data is partitioned on the hash of a column. Data is replicated to k+1 hosts.'
    });
    $('.l-Has-PKey').popover({
        trigger: 'focus hover', delay: { show: 500, hide: 100 }, placement: 'top', content:
            'The table has a primary key and corresponding index.'
    });
    $('.l-No-PKey').popover({
        trigger: 'focus hover', delay: { show: 500, hide: 100 }, placement: 'top', content:
            'The table has no primary key. Deletes and updates will require scans.'
    });
    $('.l-Read').popover({
        trigger: 'focus hover', delay: { show: 500, hide: 100 }, placement: 'top', content:
            'This procedure doesn\'t alter the content of the database.'
    });
    $('.l-Write').popover({
        trigger: 'focus hover', delay: { show: 500, hide: 100 }, placement: 'top', content:
            'This procedure can alter the contents of the database.'
    });
    $('.l-Single').popover({
        trigger: 'focus hover', delay: { show: 500, hide: 100 }, placement: 'top', content:
            'This procedure only runs at one partition.'
    });
    $('.l-Multi').popover({
        trigger: 'focus hover', delay: { show: 500, hide: 100 }, placement: 'top', content:
            'This procedure runs at all partitions, which can affect performance.'
    });
    $('.l-Java').popover({
        trigger: 'focus hover', delay: { show: 500, hide: 100 }, placement: 'top', content:
            'This procedure uses Java code for logic.'
    });
    $('.l-Single-Stmt').popover({
        trigger: 'focus hover', delay: { show: 500, hide: 100 }, placement: 'top', content:
            'This procedure was defined in the DDL file as a single SQL statement.'
    });
    $('.l-Scans').popover({
        trigger: 'focus hover', delay: { show: 500, hide: 100 }, placement: 'top', content:
            'This procedure or statement might be using full table scans. While this isn\'t ' +
            'always bad, it\'s possible adding an index could improve performance.'
    });
    $('.l-Determinism').popover({
        trigger: 'focus hover', delay: { show: 500, hide: 100 }, placement: 'top', content:
            'This statement or procedure could potentially use SQL that outputs non-deterministic ' +
            'results which then may be used to modify state. If this happens, the cluster will ' +
            'halt. Consider adding an ORDER BY clause to make a SELECT statement deterministic.'
    });

    sizes_update_all();
});

function numberWithCommas(n) {
    n = Math.round(n / 1000.0);
    var parts = n.toString().split(".");
    return parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",") + (parts[1] ? "." + parts[1] : "") + " K";
}

function size_table_element(name, nrow) {
    var id = "s-size-".concat(nrow, '-', name);
    var e = document.getElementById(id);
    return e;
}

function size_table_value(name, nrow) {
    var elem = size_table_element(name, nrow);
    var value = Math.floor(name == "count" ? elem.value : elem.innerHTML);
    return value;
}

function size_table_update(name, nrow, value) {
    var elem = size_table_element(name, nrow);
    if (elem != null) {
        elem.innerHTML = numberWithCommas(value);
    }
}

function size_summary_element(type, name) {
    var id = "s-size-summary-".concat(type, '-', name);
    var e = document.getElementById(id);
    return e;
}

function size_summary_value(type, name) {
    var elem = size_summary_element(type, name);
    var value = Math.floor(elem.innerHTML);
    return value;
}

function size_summary_update(type, name, value) {
    var elem = size_summary_element(type, name);
    if (elem != null) {
        elem.innerHTML = numberWithCommas(value);
    }
}

function sizes_get_row(nrow) {
    return {
        "count": size_table_value("count", nrow),
        "rmin": size_table_value("rmin", nrow),
        "rmax": size_table_value("rmax", nrow),
        "imin": size_table_value("imin", nrow),
        "imax": size_table_value("imax", nrow),
        "tmin": size_table_value("tmin", nrow),
        "tmax": size_table_value("tmax", nrow)
    };
}

// Do the size worksheet calculations for a single row.
function sizes_update_row(nrow) {
    var v = sizes_get_row(nrow);
    size_table_update("tmin", nrow, (v["rmin"] + v["imin"]) * v["count"]);
    size_table_update("tmax", nrow, (v["rmax"] + v["imax"]) * v["count"]);
}

/*
 * Update the size worksheet summary.
 */
function sizes_update_summary() {
    var ntables = size_summary_value("table", "count");
    var nviews = size_summary_value("view", "count");
    var nrow = 0;
    var tmin = 0;
    var tmax = 0;
    var vmin = 0;
    var vmax = 0;
    var imin = 0;
    var imax = 0;
    for (var ntable = 0; ntable < ntables; ++ntable) {
        var v = sizes_get_row(++nrow);
        tmin += (v["rmin"] * v["count"]);
        tmax += (v["rmax"] * v["count"]);
        imin += (v["imin"] * v["count"]);
        imax += (v["imax"] * v["count"]);
    }
    for (var nview = 0; nview < nviews; ++nview) {
        var v = sizes_get_row(++nrow);
        vmin += (v["rmin"] * v["count"]);
        vmax += (v["rmax"] * v["count"]);
        imin += (v["imin"] * v["count"]);
        imax += (v["imax"] * v["count"]);
    }
    size_summary_update("table", "min", tmin);
    size_summary_update("table", "max", tmax);
    size_summary_update("view", "min", vmin);
    size_summary_update("view", "max", vmax);
    size_summary_update("index", "min", imin);
    size_summary_update("index", "max", imax);
    size_summary_update("total", "min", tmin + vmin + imin);
    size_summary_update("total", "max", tmax + vmax + imax);
}

/*
 * Do all the size worksheet calculations at once.
 * Call sizes_update_row() when a single row is changed.
 */
function sizes_update_all() {
    // Use the summary counts to determine the number of table rows.
    var ntables = size_summary_value("table", "count");
    var nviews = size_summary_value("view", "count");
    for (var nrow = 1; nrow <= ntables + nviews; ++nrow) {
        sizes_update_row(nrow);
    }
    sizes_update_summary();
}<commit_msg>ENG-7084 fixed indentation<commit_after>
//Dummy wrapper for console.log for IE9
if (!(window.console && console.log)) {
    console = {
        log: function () { },
        debug: function () { },
        info: function () { },
        warn: function () { },
        error: function () { }
    };
}

function navigate(hash) {
    console.log(hash);
    if (hash.length == 0) hash = '#o';
    hash = hash.toLowerCase();
    var anchor = hash.substring(1);
    var parts = anchor.split('-');
    var toppage = parts[0];

    // reset everything
    $('.tablesorter-childRow>td').hide();
    $('.dropdown2>td').hide();
    $('.primaryrow>td').show();
    $('.primaryrow2>td').show();
    // make arrows point the right way
    $('.icon-chevron-down').removeClass('icon-chevron-down').addClass('icon-chevron-right');
    $('.primaryrow').css('background-color', '#ffffff');

    $('.nav-collapse ul li').removeClass('active');
    $('div.reportpage').hide();
    $('#' + toppage + '-nav').addClass('active');
    $('#' + toppage).show();

    if (parts.length > 1) {
        var primary = parts[1];
        console.log("primary = " + primary);

        var iconid = "#" + toppage + "-" + primary + "--icon";
        var dropdownid = "#" + toppage + "-" + primary + "--dropdown";

        $(dropdownid).show();
        $(iconid).parentsUntil("tbody", 'tr').css('background-color', '#dddddd');
        $(iconid).removeClass('icon-chevron-right').addClass('icon-chevron-down');

        if (parts.length > 2) {
            var secondary = parts[2];
            console.log("secondary = " + secondary);

            var iconid2 = "#" + toppage + "-" + primary + "-" + secondary + "--icon";
            var dropdownid2 = "#" + toppage + "-" + primary + "-" + secondary + "--dropdown";

            $(dropdownid2).show();
            $(iconid2).removeClass('icon-chevron-right').addClass('icon-chevron-down');
        }
    }
}

$(document).ready(function () {

    $('#o').find('br').remove();//for removing br form id o

    var hash = window.location.hash.substr(1);
    if (hash == "" || hash == undefined) {
        $("#o-nav").addClass('active');
    } else {
        $('ul.catalogNav').children().removeClass('active');
        $("#" + hash + "-nav").addClass('active');
    }

    $('body').bind('touchmove', function (e) {
        e.preventDefault();
    });

    $(window).bind('hashchange', function () {

        var hash = window.location.hash.substr(1);
        $('ul.catalogNav').children().removeClass('active');
        $("#" + hash + "-nav").addClass('active');
    });

    var timeOut = (navigator.userAgent.indexOf('Firefox') >= 0) ? 20 : 1;

    $(".catalogNav > li > a").on("click", function () {

        setTimeout(function() {
            window.scrollTo(0, 0);
        }, timeOut);
    });

    $.extend($.tablesorter.themes.bootstrap, {
        // these classes are added to the table. To see other table classes available,
        // look here: http://twitter.github.com/bootstrap/base-css.html#tables
        table: 'table table-bordered',
        header: 'bootstrap-header', // give the header a gradient background
        footerRow: '',
        footerCells: '',
        icons: '', // add "icon-white" to make them white; this icon class is added to the <i> in the header
        sortNone: 'bootstrap-icon-unsorted',
        sortAsc: 'icon-chevron-up',
        sortDesc: 'icon-chevron-down',
        active: '', // applied when column is sorted
        hover: '', // use custom css here - bootstrap class may not override it
        filterRow: '', // filter row class
        even: '', // odd row zebra striping
        odd: ''  // even row zebra striping
    });

    $(".tableL1").tablesorter({
        theme: 'bootstrap',
        widthFixed: true,
        headerTemplate: '{content} {icon}',
        widgets: ["uitheme", "filter", "stickyHeaders"],
        widgetOptions: {
            filter_reset: ".reset",
            filter_hideFilters: true
        },
        cssChildRow: "tablesorter-childRow"
    });

    $('.tableL1').delegate('.togglex', 'click', function () {
        var id = $(this).attr('id');
        var toppage = id.split('-')[0];
        var dropdownid = "#" + id + "--dropdown";

        var hash = "#" + id;
        if ($(dropdownid).is(":visible")) {
            hash = "#" + toppage;
        }
        // history.replaceState(null, null, hash);
        navigate(hash);
        $('.cb').prop('checked', false);
        return false;
    });

    $('.tableL2').delegate('.togglex', 'click', function () {
        var id = $(this).attr('id');

        console.log("l2click: " + id);

        var parts = id.split('-');
        var toppage = parts[0];
        var primary = parts[1];
        var dropdownid = "#" + id + "--dropdown";

        var hash = "#" + id;
        if ($(dropdownid).is(":visible")) {
            console.log("l2clickVISIBLE");
            hash = "#" + toppage + "-" + primary;
        }
        else {
            console.log("not visible");
        }
        // history.replaceState(null, null, hash);
        navigate(hash);
        $('.cb').prop('checked', false);
        return false;
    });

    $(".tableL3").tablesorter({
        theme: 'bootstrap',
        widthFixed: true,
        headerTemplate: '{content} {icon}',
        widgets: ["uitheme", "filter", "stickyHeaders"],
        widgetOptions: {
            filter_reset: ".reset",
            filter_hideFilters: true
        },
        cssChildRow: "tablesorter-childRow"
    });

    $('.tableL3').delegate('.togglex', 'click', function () {
        var id = $(this).attr('id');
        var toppage = id.split('-')[0];
        var dropdownid = "#" + id + "--dropdown";

        var hash = "#" + id;
        if ($(dropdownid).is(":visible")) {
            hash = "#" + toppage;
        }
        // history.replaceState(null, null, hash);
        navigate(hash);
        return false;
    });

    $('.cb').click(function () {
        if ($(this).is(":checked")) {
            var elementList = $(".tableL1").find(".togglex");
            for ( var i = 0; i < elementList.length; i++ ) {
                var item = elementList[i];
                var id = item["id"];

                var anchor = id.toLowerCase();
                var parts = anchor.split('-');
                var toppage = parts[0];

                if (parts.length > 1) {
                    var primary = parts[1];
                    var iconid = "#" + toppage + "-" + primary + "--icon";
                    var dropdownid = "#" + id + "--dropdown";
                    $(iconid).removeClass('icon-chevron-right').addClass('icon-chevron-down');
                    $(dropdownid).show();
                    var disableLink = function(){ return false;};
					$('a').bind('click', disableLink);
                    if (parts.length > 2) {
                        var secondary = parts[2];
                        var iconid2 = "#" + toppage + "-" + primary + "-" + secondary + "--icon";
                        var dropdownid2 = "#" + toppage + "-" + primary + "-" + secondary + "--dropdown";
                        $(iconid2).removeClass('icon-chevron-right').addClass('icon-chevron-down');
                        $(dropdownid2).show();
                    }
                }
            }
        } else {
            // reset everything
            $('.tablesorter-childRow>td').hide();
            $('.dropdown2>td').hide();
            $('.primaryrow>td').show();
            $('.primaryrow2>td').show();
            // make arrows point the right way
            $('.icon-chevron-down').removeClass('icon-chevron-down').addClass('icon-chevron-right');
            $('.primaryrow').css('background-color', '#ffffff');
            $('a').unbind('click', disableLink);
        }
    });

    navigate($(location).attr('hash'));

    $(window).bind('hashchange', function () { //detect hash change
        navigate(window.location.hash);
    });

     //tooltips
    $('.l-Table').popover({
        trigger: 'focus hover', delay: { show: 500, hide: 100 }, placement: 'top', content:
            'Persistent Relational Table'
    });
    $('.l-Materialized_View').popover({
        trigger: 'focus hover', delay: { show: 500, hide: 100 }, placement: 'top', content:
            'Views are always materialized and incrementally maintained.'
    });
    $('.l-Replicated').popover({
        trigger: 'focus hover', delay: { show: 500, hide: 100 }, placement: 'top', content:
            'Table data is present at all partitions. Updates are a multi-partition operation.'
    });
    $('.l-Partitioned').popover({
        trigger: 'focus hover', delay: { show: 500, hide: 100 }, placement: 'top', content:
            'Table data is partitioned on the hash of a column. Data is replicated to k+1 hosts.'
    });
    $('.l-Has-PKey').popover({
        trigger: 'focus hover', delay: { show: 500, hide: 100 }, placement: 'top', content:
            'The table has a primary key and corresponding index.'
    });
    $('.l-No-PKey').popover({
        trigger: 'focus hover', delay: { show: 500, hide: 100 }, placement: 'top', content:
            'The table has no primary key. Deletes and updates will require scans.'
    });
    $('.l-Read').popover({
        trigger: 'focus hover', delay: { show: 500, hide: 100 }, placement: 'top', content:
            'This procedure doesn\'t alter the content of the database.'
    });
    $('.l-Write').popover({
        trigger: 'focus hover', delay: { show: 500, hide: 100 }, placement: 'top', content:
            'This procedure can alter the contents of the database.'
    });
    $('.l-Single').popover({
        trigger: 'focus hover', delay: { show: 500, hide: 100 }, placement: 'top', content:
            'This procedure only runs at one partition.'
    });
    $('.l-Multi').popover({
        trigger: 'focus hover', delay: { show: 500, hide: 100 }, placement: 'top', content:
            'This procedure runs at all partitions, which can affect performance.'
    });
    $('.l-Java').popover({
        trigger: 'focus hover', delay: { show: 500, hide: 100 }, placement: 'top', content:
            'This procedure uses Java code for logic.'
    });
    $('.l-Single-Stmt').popover({
        trigger: 'focus hover', delay: { show: 500, hide: 100 }, placement: 'top', content:
            'This procedure was defined in the DDL file as a single SQL statement.'
    });
    $('.l-Scans').popover({
        trigger: 'focus hover', delay: { show: 500, hide: 100 }, placement: 'top', content:
            'This procedure or statement might be using full table scans. While this isn\'t ' +
            'always bad, it\'s possible adding an index could improve performance.'
    });
    $('.l-Determinism').popover({
        trigger: 'focus hover', delay: { show: 500, hide: 100 }, placement: 'top', content:
            'This statement or procedure could potentially use SQL that outputs non-deterministic ' +
            'results which then may be used to modify state. If this happens, the cluster will ' +
            'halt. Consider adding an ORDER BY clause to make a SELECT statement deterministic.'
    });

    sizes_update_all();
});

function numberWithCommas(n) {
    n = Math.round(n / 1000.0);
    var parts = n.toString().split(".");
    return parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",") + (parts[1] ? "." + parts[1] : "") + " K";
}

function size_table_element(name, nrow) {
    var id = "s-size-".concat(nrow, '-', name);
    var e = document.getElementById(id);
    return e;
}

function size_table_value(name, nrow) {
    var elem = size_table_element(name, nrow);
    var value = Math.floor(name == "count" ? elem.value : elem.innerHTML);
    return value;
}

function size_table_update(name, nrow, value) {
    var elem = size_table_element(name, nrow);
    if (elem != null) {
        elem.innerHTML = numberWithCommas(value);
    }
}

function size_summary_element(type, name) {
    var id = "s-size-summary-".concat(type, '-', name);
    var e = document.getElementById(id);
    return e;
}

function size_summary_value(type, name) {
    var elem = size_summary_element(type, name);
    var value = Math.floor(elem.innerHTML);
    return value;
}

function size_summary_update(type, name, value) {
    var elem = size_summary_element(type, name);
    if (elem != null) {
        elem.innerHTML = numberWithCommas(value);
    }
}

function sizes_get_row(nrow) {
    return {
        "count": size_table_value("count", nrow),
        "rmin": size_table_value("rmin", nrow),
        "rmax": size_table_value("rmax", nrow),
        "imin": size_table_value("imin", nrow),
        "imax": size_table_value("imax", nrow),
        "tmin": size_table_value("tmin", nrow),
        "tmax": size_table_value("tmax", nrow)
    };
}

// Do the size worksheet calculations for a single row.
function sizes_update_row(nrow) {
    var v = sizes_get_row(nrow);
    size_table_update("tmin", nrow, (v["rmin"] + v["imin"]) * v["count"]);
    size_table_update("tmax", nrow, (v["rmax"] + v["imax"]) * v["count"]);
}

/*
 * Update the size worksheet summary.
 */
function sizes_update_summary() {
    var ntables = size_summary_value("table", "count");
    var nviews = size_summary_value("view", "count");
    var nrow = 0;
    var tmin = 0;
    var tmax = 0;
    var vmin = 0;
    var vmax = 0;
    var imin = 0;
    var imax = 0;
    for (var ntable = 0; ntable < ntables; ++ntable) {
        var v = sizes_get_row(++nrow);
        tmin += (v["rmin"] * v["count"]);
        tmax += (v["rmax"] * v["count"]);
        imin += (v["imin"] * v["count"]);
        imax += (v["imax"] * v["count"]);
    }
    for (var nview = 0; nview < nviews; ++nview) {
        var v = sizes_get_row(++nrow);
        vmin += (v["rmin"] * v["count"]);
        vmax += (v["rmax"] * v["count"]);
        imin += (v["imin"] * v["count"]);
        imax += (v["imax"] * v["count"]);
    }
    size_summary_update("table", "min", tmin);
    size_summary_update("table", "max", tmax);
    size_summary_update("view", "min", vmin);
    size_summary_update("view", "max", vmax);
    size_summary_update("index", "min", imin);
    size_summary_update("index", "max", imax);
    size_summary_update("total", "min", tmin + vmin + imin);
    size_summary_update("total", "max", tmax + vmax + imax);
}

/*
 * Do all the size worksheet calculations at once.
 * Call sizes_update_row() when a single row is changed.
 */
function sizes_update_all() {
    // Use the summary counts to determine the number of table rows.
    var ntables = size_summary_value("table", "count");
    var nviews = size_summary_value("view", "count");
    for (var nrow = 1; nrow <= ntables + nviews; ++nrow) {
        sizes_update_row(nrow);
    }
    sizes_update_summary();
}<|endoftext|>