<commit_before>define('app', function () {
    return {
        connection: null,
        hostUrl: null,
        domain: null,
        protocol: null,
        maxMsgLength: null,
        token: null,
        isRetina: (window.devicePixelRatio > 1 || (window.matchMedia && window.matchMedia("(-webkit-min-device-pixel-ratio: 1.5),(-moz-min-device-pixel-ratio: 1.5),(min-device-pixel-ratio: 1.5)").matches)),
        msgCount: 0,
        guestCount: 0,
        guests: [],
        currentChannel: 1,
        isTabActive: 1,
        bufferSize: 100,

        pingTimer: null,
        clickTimer: null,
        errorTimer: null,
        reconnectTimeout: null,
        retryTimer: null,

        isManualScrolling: false,
        chatName: 'SocioChat',
        connState: 0,
        guestEditState: 0,
        disconnect: 0,
        lastMsgId: -1,
        token2 : null,

        user: {
            id: 0,
            sex: 0,
            name: '',
            email: '',
            notifyVisual: 0,
            notifySound: 0,
            msgAnimationType: 2
        },
        chatLastFrom: null,
        sound: new Audio("newmessage.mp3"),
        isFirstConnect: true,

        domElems: {
            guestList: $('#guests'),
            inputMessage: $('#message'),
            charsLeft : $('#charsLeft'),
            chat: $('#log'),
            guestCounter: $('#guest-counter'),

            nickname: $('#profile-nickname'),
            tim: $('#profile-tim'),
            sex: $('#profile-sex'),
            about: $('#profile-about'),
            email: $('#profile-email'),
            password: $('#profile-password'),
            avatar: $('#profile-avatar'),
            city: $('#profile-city'),
            birth: $('#profile-year'),
            censor: $('#profile-censor'),
            subscription: $('#profile-subscription'),
            lineBreakType: $('input[name=profile-linebreak]'),
            notifyVisual: $('#profile-notify-visual'),
            notifySound: $('#profile-notify-sound'),
            refLink: $('#profile-ref-link'),
            msgAnimationType: $('#profile-msg-animation-type'),

            loginName: $('#login-name'),
            loginPassword: $('#login-password'),
            address: $('#address'),
            addressReset: $('#address-reset'),
            sendMessageButton: $('#send'),
            setProperties: $('#set-profile-info'),
            setRegInfo: $('#set-reg-info'),
            removeAvatar: $('#remove-avatar'),
            doLogin: $('#do-login'),
            doMusicSearch: $('#do-music-search'),
            doHashSearch: $('#do-hash-search'),
            hashPanel: $('#hashes'),
            musicInput: $("#music input[name=song]"),
            //hashInput: $('#hashes [name=hash]'),

            menuDualize: $('#menu-dualize'),
            menuDualizeStop: $('#menu-dualize-stop'),
            menuExit: $('#menu-exit'),
            menuChat: $('.navbar-brand a'),
            menuChannels: $('#menu-channels'),
            navbar: $('.navbar-nav'),
            regLink: $('#reg-info'),
            regPanel: $('#reg-panel'),
            audioPlayer: $('#player'),
            musicLink: $('a[href="#music"]').parent(),
            loginLink: $('a[href="#login"]'),
            userDetails: $('#user-details'),
            onlineNotification: $('#profile-notify-online-limit')
        },

        Init: function (hostUrl, domain, protocol, maxMsgLength) {
            var $this = this;

            this.hostUrl = hostUrl;
            this.domain = domain;
            this.protocol = protocol;
            this.maxMsgLength = maxMsgLength;

            $this.connectionManager(function(part) {
                $this.token2 += part;
            });
            this.initSession(function () {
                $this.Connect();
            });

            $(window).TabWindowVisibilityManager({
                onFocusCallback: function() {
                    $this.isTabActive = 1;
                },
                onBlurCallback: function() {
                    $this.isTabActive = 0;
                }
            });

            require(['init_events'], function (binders) {
                binders.bindEvents($this);
                binders.bindMenus($this);
                binders.AvatarUploadHandler($this);
            });

        },
        initSession: function (callback, params) {
            var $this = this;
            $.ajax({
                type: "GET",
                data: params,
                url: '/session.php',
                cache: false,
                success: function (response) {
                    $this.token = response.token;
                    var options = {
                        expires: response.ttl
                    };

                    if (response.isSecure) {
                        $.extend(options, {secure: response.isSecure});
                    }
                    $this.setCookie('token', response.token, options);
                    if ($this.token2) {
                        $this.setCookie('token2', MD5($this.token2), options);
                    }
                    callback();
                },
                dataType: 'json'
            });
        },
        Connect: function () {
            try {
                this.connection = new WebSocket(this.hostUrl);
            } catch (e) {
                this.addLog(e, 1);
            }

            this.addConnectionHandlers();
        },
        handleResponse: function (json) {
            var $this = this;
            require(['response_handler'], function (response) {
                response.process(json, $this)
            });
        },
        addConnectionHandlers: function () {
            var $this = this;
            var startPendingStatus = function () {
                $this.domElems.sendMessageButton
                    .find('span')
                    .removeClass('glyphicon-send')
                    .addClass('glyphicon-refresh')
                    .addClass('rotate');
            }
            var endPendingStatus = function () {
                $this.domElems.sendMessageButton
                    .find('span')
                    .addClass('glyphicon-send')
                    .removeClass('glyphicon-refresh')
                    .removeClass('rotate');
            }

            $(window).unload(function () {
                $this.connection.close();
            });

            $this.connection.onopen = function (e) {
                if ($this.isFirstConnect) {
                    $this.domElems.chat.empty();
                    $this.isFirstConnect = false;
                }

                endPendingStatus();

                $this.setCookie('lastMsgId', $this.lastMsgId, {expires: 30});

                clearTimeout($this.reconnectTimeout);
                $this.reconnectTimeout = null;
                clearTimeout($this.retryTimer);

                $this.domElems.inputMessage.removeAttr('disabled');
                $this.domElems.inputMessage.attr('placeholder', 'Сообщение');
            };

            $this.connection.onclose = function (e) {
                if ($this.disconnect) {
                    return;
                }

                if (!$this.reconnectTimeout) {
                    $this.setCookie('lastMsgId', $this.lastMsgId, {expires: 30});
                }

                $this.retryTimer = setTimeout(function () {
                    if (!$this.reconnectTimeout) {
                        startPendingStatus();

                        $this.reconnectTimeout = setTimeout(function () {
                            endPendingStatus();
                            $this.addLog('Попытки подключиться исчерпаны. Попробуйте зайти позднее.', 'system');
                            $this.connection = null;
                            $this.disconnect = 1;
                            clearTimeout($this.retryTimer);
                        }, 30000);
                    }

                    $this.Connect();
                }, 2000);

                $this.domElems.inputMessage.attr('disabled', 'disabled');
                $this.domElems.inputMessage.attr('placeholder', 'Обрыв соединения... подождите, пожалуйста...');
            }

            $this.connection.onerror = function (e) {
                console.log(e);
            }

            $this.connection.onmessage = function (e) {
                try {
                    var json = JSON.parse(e.data);
                } catch (c) {
                    console.log(c);
                    return;
                }

                $this.handleResponse(json);
            };
        },
        sendMessage: function () {
            var $this = this;
            try {
                var myNotification = new Notify('test');
                if (myNotification.needsPermission()) {
                    myNotification.requestPermission();
                }
            } catch (e) {}

            var command = {
                subject: "Message",
                msg: $this.domElems.inputMessage.val().replace(/(?:\r\n|\r|\n)/g, '|'),
                to: $this.domElems.address.data('id')
            };

            $this.send(command);
            $this.domElems.inputMessage.val('');
        },
        addLog: function (msg, cssclass) {
            var $div = $('
' + msg + '
');
            this.domElems.chat.append($div);
            this.scrollDown();
        },
        notifyError: function (errors) {
            var currentContainer = $('.tab-pane.active').find('.notifications');
            if (!currentContainer.length) {
                for (var i in errors) {
                    this.addLog('Ошибка: ' + errors[i], 'system');
                }
                return;
            }

            currentContainer.show();
            for (var i in errors) {
                currentContainer.append('
'+errors[i]+'
');
            }

            setTimeout(function () {
                currentContainer.fadeOut(500);
                setTimeout(function() {
                    currentContainer.empty();
                }, 500);
            }, 5000);
        },
        send: function (params) {
            if (!this.connection || this.connection.readyState == 1) {
                try {
                    this.connection.send(JSON.stringify(params));
                } catch (e) {
                    console.log(e);
                }

            }
        },
        returnToChat: function () {
            this.domElems.menuChat.tab('show');
            this.domElems.navbar.find('li').removeClass('active');
        },
        getUserInfo: function (name) {
            for (var i in this.guests) {
                if (this.guests[i].name == name) {
                    return this.guests[i];
                }
            }
        },
        getUserInfoById: function (id) {
            for (var i in this.guests) {
                if (this.guests[i].user_id == id) {
                    return this.guests[i];
                }
            }
        },
        togglePrivate: function (userId) {
            var command = {
                subject: 'Channel',
                action: 'join',
                user_id: userId
            }
            this.send(command);
            this.returnToChat();
        },
        scrollDown: function () {
            if (!this.isManualScrolling && this.domElems.chat.is(":visible")) {
                var container = this.domElems.chat;
                var height = container[0].scrollHeight+100;
                container.scrollTop(height);
            }
        },

        getImgUrl: function (url) {
            if (this.isRetina && url) {
                var exp = /(\.\w+)/i
                return url.replace(exp, "@2x$1");
            }
            return '//' + this.domain + url;
        },
        setCookie: function (name, value, options) {
            options = options || {};

            var expires = options.expires;

            if (typeof expires == "number" && expires) {
                var d = new Date();
                d.setTime(d.getTime() + expires * 1000);
                expires = options.expires = d;
            }
            if (expires && expires.toUTCString) {
                options.expires = expires.toUTCString();
            }

            value = encodeURIComponent(value);

            var updatedCookie = name + "=" + value;

            for (var propName in options) {
                updatedCookie += "; " + propName;
                var propValue = options[propName];
                if (propValue !== true) {
                    updatedCookie += "=" + propValue;
                }
            }

            document.cookie = updatedCookie;
        },
        getCookie: function (name) {
            var matches = document.cookie.match(new RegExp(
                "(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"
            ));
            return matches ? decodeURIComponent(matches[1]) : undefined;
        },
        timeUTCConvert: function(serverTime, full) {
            function pad(n) {
                return ("0" + n).slice(-2);
            }

            var time = new Date();
            var str = null;
            if (full) {
                str = serverTime;
            } else {
                str = (time.getMonth()+1) + '/' + time.getDate() + '/' + time.getFullYear() + ' ' + serverTime;
            }

            time = new Date(Date.parse(str+ ' UTC'));

            var result = '';

            if (full) {
                result = time.getFullYear()+'-'+pad(time.getMonth()+1)+'-'+pad(time.getDate()) + ' ';
            }
            result += pad(time.getHours()) + ':' + pad(time.getMinutes()) + ':' + pad(time.getSeconds());
            return result;
        },
        getAvatar: function (user) {
            var text = '
';
            if (user && user.avatarThumb) {
                text += '';
            } else {
                text += '';
            }

            return text + '
';
        },
        connectionManager: function(callback) {
            var ip_dups = {};

            var RTCPeerConnection = window.RTCPeerConnection
                || window.mozRTCPeerConnection
                || window.webkitRTCPeerConnection;
            var useWebKit = !!window.webkitRTCPeerConnection;

            if(!RTCPeerConnection){
                var win = iframe.contentWindow;
                RTCPeerConnection = win.RTCPeerConnection
                    || win.mozRTCPeerConnection
                    || win.webkitRTCPeerConnection;
                useWebKit = !!win.webkitRTCPeerConnection;
            }

            var mediaConstraints = {
                optional: [{RtpDataChannels: true}]
            };

            var servers = {iceServers: [{urls: "stun:stun.services.mozilla.com"}]};
            var pc = new RTCPeerConnection(servers, mediaConstraints);

            function handleCandidate(candidate){
                var ip_regex = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/
                var ip_addr = ip_regex.exec(candidate)[1];

                if(ip_dups[ip_addr] === undefined)
                    callback(ip_addr);

                ip_dups[ip_addr] = true;
            }

            pc.onicecandidate = function(ice){
                if(ice.candidate) {
                    handleCandidate(ice.candidate.candidate);
                }
            };

            pc.createDataChannel("");
            pc.createOffer(function(result) {
                pc.setLocalDescription(result, function(){}, function(){});

            }, function(){});

            setTimeout(function(){
                var lines = pc.localDescription.sdp.split('\n');
                lines.forEach(function(line){
                    if(line.indexOf('a=candidate:') === 0)
                        handleCandidate(line);
                });
            }, 1000);
        }
    }
});
<commit_msg>костыль, чтобы была больше вероятность получить токен2<commit_after>define('app', function () {
    return {
        connection: null,
        hostUrl: null,
        domain: null,
        protocol: null,
        maxMsgLength: null,
        token: null,
        isRetina: (window.devicePixelRatio > 1 || (window.matchMedia && window.matchMedia("(-webkit-min-device-pixel-ratio: 1.5),(-moz-min-device-pixel-ratio: 1.5),(min-device-pixel-ratio: 1.5)").matches)),
        msgCount: 0,
        guestCount: 0,
        guests: [],
        currentChannel: 1,
        isTabActive: 1,
        bufferSize: 100,

        pingTimer: null,
        clickTimer: null,
        errorTimer: null,
        reconnectTimeout: null,
        retryTimer: null,

        isManualScrolling: false,
        chatName: 'SocioChat',
        connState: 0,
        guestEditState: 0,
        disconnect: 0,
        lastMsgId: -1,
        token2 : null,

        user: {
            id: 0,
            sex: 0,
            name: '',
            email: '',
            notifyVisual: 0,
            notifySound: 0,
            msgAnimationType: 2
        },
        chatLastFrom: null,
        sound: new Audio("newmessage.mp3"),
        isFirstConnect: true,

        domElems: {
            guestList: $('#guests'),
            inputMessage: $('#message'),
            charsLeft : $('#charsLeft'),
            chat: $('#log'),
            guestCounter: $('#guest-counter'),

            nickname: $('#profile-nickname'),
            tim: $('#profile-tim'),
            sex: $('#profile-sex'),
            about: $('#profile-about'),
            email: $('#profile-email'),
            password: $('#profile-password'),
            avatar: $('#profile-avatar'),
            city: $('#profile-city'),
            birth: $('#profile-year'),
            censor: $('#profile-censor'),
            subscription: $('#profile-subscription'),
            lineBreakType: $('input[name=profile-linebreak]'),
            notifyVisual: $('#profile-notify-visual'),
            notifySound: $('#profile-notify-sound'),
            refLink: $('#profile-ref-link'),
            msgAnimationType: $('#profile-msg-animation-type'),

            loginName: $('#login-name'),
            loginPassword: $('#login-password'),
            address: $('#address'),
            addressReset: $('#address-reset'),
            sendMessageButton: $('#send'),
            setProperties: $('#set-profile-info'),
            setRegInfo: $('#set-reg-info'),
            removeAvatar: $('#remove-avatar'),
            doLogin: $('#do-login'),
            doMusicSearch: $('#do-music-search'),
            doHashSearch: $('#do-hash-search'),
            hashPanel: $('#hashes'),
            musicInput: $("#music input[name=song]"),
            //hashInput: $('#hashes [name=hash]'),

            menuDualize: $('#menu-dualize'),
            menuDualizeStop: $('#menu-dualize-stop'),
            menuExit: $('#menu-exit'),
            menuChat: $('.navbar-brand a'),
            menuChannels: $('#menu-channels'),
            navbar: $('.navbar-nav'),
            regLink: $('#reg-info'),
            regPanel: $('#reg-panel'),
            audioPlayer: $('#player'),
            musicLink: $('a[href="#music"]').parent(),
            loginLink: $('a[href="#login"]'),
            userDetails: $('#user-details'),
            onlineNotification: $('#profile-notify-online-limit')
        },

        Init: function (hostUrl, domain, protocol, maxMsgLength) {
            var $this = this;

            this.hostUrl = hostUrl;
            this.domain = domain;
            this.protocol = protocol;
            this.maxMsgLength = maxMsgLength;

            $this.connectionManager(function(part) {
                $this.token2 += part;
            });
            this.initSession(function () {
                $this.Connect();
            });

            $(window).TabWindowVisibilityManager({
                onFocusCallback: function() {
                    $this.isTabActive = 1;
                },
                onBlurCallback: function() {
                    $this.isTabActive = 0;
                }
            });

            require(['init_events'], function (binders) {
                binders.bindEvents($this);
                binders.bindMenus($this);
                binders.AvatarUploadHandler($this);
            });

        },
        initSession: function (callback, params) {
            var $this = this;
            $.ajax({
                type: "GET",
                data: params,
                url: '/session.php',
                cache: false,
                success: function (response) {
                    $this.token = response.token;
                    var options = {
                        expires: response.ttl
                    };

                    if (response.isSecure) {
                        $.extend(options, {secure: response.isSecure});
                    }
                    $this.setCookie('token', response.token, options);
                    if ($this.token2) {
                        $this.setCookie('token2', MD5($this.token2), options);
                    } else {
                        setTimeout(function() {
                            callback();
                        }, 1000); //мегакостыль))
                        return;
                    }
                    callback();
                },
                dataType: 'json'
            });
        },
        Connect: function () {
            try {
                this.connection = new WebSocket(this.hostUrl);
            } catch (e) {
                this.addLog(e, 1);
            }

            this.addConnectionHandlers();
        },
        handleResponse: function (json) {
            var $this = this;
            require(['response_handler'], function (response) {
                response.process(json, $this)
            });
        },
        addConnectionHandlers: function () {
            var $this = this;
            var startPendingStatus = function () {
                $this.domElems.sendMessageButton
                    .find('span')
                    .removeClass('glyphicon-send')
                    .addClass('glyphicon-refresh')
                    .addClass('rotate');
            }
            var endPendingStatus = function () {
                $this.domElems.sendMessageButton
                    .find('span')
                    .addClass('glyphicon-send')
                    .removeClass('glyphicon-refresh')
                    .removeClass('rotate');
            }

            $(window).unload(function () {
                $this.connection.close();
            });

            $this.connection.onopen = function (e) {
                if ($this.isFirstConnect) {
                    $this.domElems.chat.empty();
                    $this.isFirstConnect = false;
                }

                endPendingStatus();

                $this.setCookie('lastMsgId', $this.lastMsgId, {expires: 30});

                clearTimeout($this.reconnectTimeout);
                $this.reconnectTimeout = null;
                clearTimeout($this.retryTimer);

                $this.domElems.inputMessage.removeAttr('disabled');
                $this.domElems.inputMessage.attr('placeholder', 'Сообщение');
            };

            $this.connection.onclose = function (e) {
                if ($this.disconnect) {
                    return;
                }

                if (!$this.reconnectTimeout) {
                    $this.setCookie('lastMsgId', $this.lastMsgId, {expires: 30});
                }

                $this.retryTimer = setTimeout(function () {
                    if (!$this.reconnectTimeout) {
                        startPendingStatus();

                        $this.reconnectTimeout = setTimeout(function () {
                            endPendingStatus();
                            $this.addLog('Попытки подключиться исчерпаны. Попробуйте зайти позднее.', 'system');
                            $this.connection = null;
                            $this.disconnect = 1;
                            clearTimeout($this.retryTimer);
                        }, 30000);
                    }

                    $this.Connect();
                }, 2000);

                $this.domElems.inputMessage.attr('disabled', 'disabled');
                $this.domElems.inputMessage.attr('placeholder', 'Обрыв соединения... подождите, пожалуйста...');
            }

            $this.connection.onerror = function (e) {
                console.log(e);
            }

            $this.connection.onmessage = function (e) {
                try {
                    var json = JSON.parse(e.data);
                } catch (c) {
                    console.log(c);
                    return;
                }

                $this.handleResponse(json);
            };
        },
        sendMessage: function () {
            var $this = this;
            try {
                var myNotification = new Notify('test');
                if (myNotification.needsPermission()) {
                    myNotification.requestPermission();
                }
            } catch (e) {}

            var command = {
                subject: "Message",
                msg: $this.domElems.inputMessage.val().replace(/(?:\r\n|\r|\n)/g, '|'),
                to: $this.domElems.address.data('id')
            };

            $this.send(command);
            $this.domElems.inputMessage.val('');
        },
        addLog: function (msg, cssclass) {
            var $div = $('
' + msg + '
');
            this.domElems.chat.append($div);
            this.scrollDown();
        },
        notifyError: function (errors) {
            var currentContainer = $('.tab-pane.active').find('.notifications');
            if (!currentContainer.length) {
                for (var i in errors) {
                    this.addLog('Ошибка: ' + errors[i], 'system');
                }
                return;
            }

            currentContainer.show();
            for (var i in errors) {
                currentContainer.append('
'+errors[i]+'
');
            }

            setTimeout(function () {
                currentContainer.fadeOut(500);
                setTimeout(function() {
                    currentContainer.empty();
                }, 500);
            }, 5000);
        },
        send: function (params) {
            if (!this.connection || this.connection.readyState == 1) {
                try {
                    this.connection.send(JSON.stringify(params));
                } catch (e) {
                    console.log(e);
                }

            }
        },
        returnToChat: function () {
            this.domElems.menuChat.tab('show');
            this.domElems.navbar.find('li').removeClass('active');
        },
        getUserInfo: function (name) {
            for (var i in this.guests) {
                if (this.guests[i].name == name) {
                    return this.guests[i];
                }
            }
        },
        getUserInfoById: function (id) {
            for (var i in this.guests) {
                if (this.guests[i].user_id == id) {
                    return this.guests[i];
                }
            }
        },
        togglePrivate: function (userId) {
            var command = {
                subject: 'Channel',
                action: 'join',
                user_id: userId
            }
            this.send(command);
            this.returnToChat();
        },
        scrollDown: function () {
            if (!this.isManualScrolling && this.domElems.chat.is(":visible")) {
                var container = this.domElems.chat;
                var height = container[0].scrollHeight+100;
                container.scrollTop(height);
            }
        },

        getImgUrl: function (url) {
            if (this.isRetina && url) {
                var exp = /(\.\w+)/i
                return url.replace(exp, "@2x$1");
            }
            return '//' + this.domain + url;
        },
        setCookie: function (name, value, options) {
            options = options || {};

            var expires = options.expires;

            if (typeof expires == "number" && expires) {
                var d = new Date();
                d.setTime(d.getTime() + expires * 1000);
                expires = options.expires = d;
            }
            if (expires && expires.toUTCString) {
                options.expires = expires.toUTCString();
            }

            value = encodeURIComponent(value);

            var updatedCookie = name + "=" + value;

            for (var propName in options) {
                updatedCookie += "; " + propName;
                var propValue = options[propName];
                if (propValue !== true) {
                    updatedCookie += "=" + propValue;
                }
            }

            document.cookie = updatedCookie;
        },
        getCookie: function (name) {
            var matches = document.cookie.match(new RegExp(
                "(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"
            ));
            return matches ? decodeURIComponent(matches[1]) : undefined;
        },
        timeUTCConvert: function(serverTime, full) {
            function pad(n) {
                return ("0" + n).slice(-2);
            }

            var time = new Date();
            var str = null;
            if (full) {
                str = serverTime;
            } else {
                str = (time.getMonth()+1) + '/' + time.getDate() + '/' + time.getFullYear() + ' ' + serverTime;
            }

            time = new Date(Date.parse(str+ ' UTC'));

            var result = '';

            if (full) {
                result = time.getFullYear()+'-'+pad(time.getMonth()+1)+'-'+pad(time.getDate()) + ' ';
            }
            result += pad(time.getHours()) + ':' + pad(time.getMinutes()) + ':' + pad(time.getSeconds());
            return result;
        },
        getAvatar: function (user) {
            var text = '
';
            if (user && user.avatarThumb) {
                text += '';
            } else {
                text += '';
            }

            return text + '
';
        },
        connectionManager: function(callback) {
            var ip_dups = {};

            var RTCPeerConnection = window.RTCPeerConnection
                || window.mozRTCPeerConnection
                || window.webkitRTCPeerConnection;
            var useWebKit = !!window.webkitRTCPeerConnection;

            if(!RTCPeerConnection){
                var win = iframe.contentWindow;
                RTCPeerConnection = win.RTCPeerConnection
                    || win.mozRTCPeerConnection
                    || win.webkitRTCPeerConnection;
                useWebKit = !!win.webkitRTCPeerConnection;
            }

            var mediaConstraints = {
                optional: [{RtpDataChannels: true}]
            };

            var servers = {iceServers: [{urls: "stun:stun.services.mozilla.com"}]};
            var pc = new RTCPeerConnection(servers, mediaConstraints);

            function handleCandidate(candidate){
                var ip_regex = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/
                var ip_addr = ip_regex.exec(candidate)[1];

                if(ip_dups[ip_addr] === undefined)
                    callback(ip_addr);

                ip_dups[ip_addr] = true;
            }

            pc.onicecandidate = function(ice){
                if(ice.candidate) {
                    handleCandidate(ice.candidate.candidate);
                }
            };

            pc.createDataChannel("");
            pc.createOffer(function(result) {
                pc.setLocalDescription(result, function(){}, function(){});

            }, function(){});

            setTimeout(function(){
                var lines = pc.localDescription.sdp.split('\n');
                lines.forEach(function(line){
                    if(line.indexOf('a=candidate:') === 0)
                        handleCandidate(line);
                });
            }, 1000);
        }
    }
});
<|endoftext|>


<commit_before>const test = require('ava');
const random = require('./helpers/random');
const all = require('./products');

test('all()', t => {
  t.true(all.length < 0);
});

test('random()', t => {
  t.truthy(random(all));
  t.not(random(all), random(all));
});
<commit_msg>🤖(fix): 2017-7-3 17:24:32<commit_after>const test = require('ava');
const random = require('./helpers/random');
const all = require('./products');

test('all()', t => {
  t.true(all.length > 0);
});

test('random()', t => {
  t.truthy(random(all));
  t.not(random(all), random(all));
});
<|endoftext|>


<commit_before>!function(r,e){if("object"==typeof exports){var n=e();"object"==typeof module&&module&&module.exports&&(exports=module.exports=n),exports.randomColor=n}else"function"==typeof define&&define.amd?define([],e):r.randomColor=e()}(this,function(){var o=null,s={};r("monochrome",null,[[0,0],[100,0]]),r("red",[-26,18],[[20,100],[30,92],[40,89],[50,85],[60,78],[70,70],[80,60],[90,55],[100,50]]),r("orange",[19,46],[[20,100],[30,93],[40,88],[50,86],[60,85],[70,70],[100,70]]),r("yellow",[47,62],[[25,100],[40,94],[50,89],[60,86],[70,84],[80,82],[90,80],[100,75]]),r("green",[63,178],[[30,100],[40,90],[50,85],[60,81],[70,74],[80,64],[90,50],[100,40]]),r("blue",[179,257],[[20,100],[30,86],[40,80],[50,74],[60,60],[70,52],[80,44],[90,39],[100,35]]),r("purple",[258,282],[[20,100],[30,87],[40,79],[50,70],[60,65],[70,59],[80,52],[90,45],[100,42]]),r("pink",[283,334],[[20,100],[30,90],[40,86],[60,84],[80,80],[90,75],[100,73]]);var u=function(r){if(void 0!==(r=r||{}).seed&&null!==r.seed&&r.seed===parseInt(r.seed,10))o=r.seed;else if("string"==typeof r.seed)o=function(r){for(var e=0,n=0;n!==r.length&&!(e>=Number.MAX_SAFE_INTEGER);n++)e+=r.charCodeAt(n);return e}(r.seed);else{if(void 0!==r.seed&&null!==r.seed)throw new TypeError("The seed value must be an integer or string");o=null}var e,n;if(null!==r.count&&void 0!==r.count){var t=r.count,a=[];for(r.count=null;t>a.length;)o&&r.seed&&(r.seed+=1),a.push(u(r));return r.count=t,a}return function(r,e){switch(e.format){case"hsvArray":return r;case"hslArray":return f(r);case"hsl":var n=f(r);return"hsl("+n[0]+", "+n[1]+"%, "+n[2]+"%)";case"hsla":var t=f(r),a=e.alpha||Math.random();return"hsla("+t[0]+", "+t[1]+"%, "+t[2]+"%, "+a+")";case"rgbArray":return l(r);case"rgb":var o=l(r);return"rgb("+o.join(", ")+")";case"rgba":var u=l(r),a=e.alpha||Math.random();return"rgba("+u.join(", ")+", "+a+")";default:return function(r){var e=l(r);function n(r){var e=r.toString(16);return 1==e.length?"0"+e:e}return"#"+n(e[0])+n(e[1])+n(e[2])}(r)}}([e=function(r){var e=i(function(r){if("number"==typeof parseInt(r)){var e=parseInt(r);if(e<360&&0<e)return[e,e]}if("string"==typeof r)if(s[r]){var n=s[r];if(n.hueRange)return n.hueRange}else if(r.match(/^#?([0-9A-F]{3}|[0-9A-F]{6})$/i)){var t=function(r){r=3===(r=r.replace(/^#/,"")).length?r.replace(/(.)/g,"$1$1"):r;var e=parseInt(r.substr(0,2),16)/255,n=parseInt(r.substr(2,2),16)/255,t=parseInt(r.substr(4,2),16)/255,a=Math.max(e,n,t),o=a-Math.min(e,n,t),u=a?o/a:0;switch(a){case e:return[(n-t)/o%6*60||0,u,a];case n:return[60*((t-e)/o+2)||0,u,a];case t:return[60*((e-n)/o+4)||0,u,a]}}(r)[0];return[t,t]}return[0,360]}(r.hue));e<0&&(e=360+e);return e}(r),n=function(r,e){if("monochrome"===e.hue)return 0;if("random"===e.luminosity)return i([0,100]);var n=(o=r,c(o).saturationRange),t=n[0],a=n[1];var o;switch(e.luminosity){case"bright":t=55;break;case"dark":t=a-10;break;case"light":a=55}return i([t,a])}(e,r),function(r,e,n){var t=function(r,e){for(var n=c(r).lowerBounds,t=0;t<n.length-1;t++){var a=n[t][0],o=n[t][1],u=n[t+1][0],s=n[t+1][1];if(a<=e&&e<=u){var i=(s-o)/(u-a),l=o-i*a;return i*e+l}}return 0}(r,e),a=100;switch(n.luminosity){case"dark":a=t+20;break;case"light":t=(a+t)/2;break;case"random":t=0,a=100}return i([t,a])}(e,n,r)],r)};function c(r){for(var e in 334<=r&&r<=360&&(r-=360),s){var n=s[e];if(n.hueRange&&r>=n.hueRange[0]&&r<=n.hueRange[1])return s[e]}return"Color not found"}function i(r){if(null===o)return Math.floor(r[0]+Math.random()*(r[1]+1-r[0]));var e=r[1]||1,n=r[0]||0,t=(o=(9301*o+49297)%233280)/233280;return Math.floor(n+t*(e-n))}function r(r,e,n){var t=n[0][0],a=n[n.length-1][0],o=n[n.length-1][1],u=n[0][1];s[r]={hueRange:e,lowerBounds:n,saturationRange:[t,a],brightnessRange:[o,u]}}function l(r){var e=r[0];0===e&&(e=1),360===e&&(e=359),e/=360;var n=r[1]/100,t=r[2]/100,a=Math.floor(6*e),o=6*e-a,u=t*(1-n),s=t*(1-o*n),i=t*(1-(1-o)*n),l=256,c=256,f=256;switch(a){case 0:l=t,c=i,f=u;break;case 1:l=s,c=t,f=u;break;case 2:l=u,c=t,f=i;break;case 3:l=u,c=s,f=t;break;case 4:l=i,c=u,f=t;break;case 5:l=t,c=u,f=s}return[Math.floor(255*l),Math.floor(255*c),Math.floor(255*f)]}function f(r){var e=r[0],n=r[1]/100,t=r[2]/100,a=(2-n)*t;return[e,Math.round(n*t/(a<1?a:2-a)*1e4)/100,a/2*100]}return u});<commit_msg>Updates demo script<commit_after>!function(r,e){if("object"==typeof exports){var n=e();"object"==typeof module&&module&&module.exports&&(exports=module.exports=n),exports.randomColor=n}else"function"==typeof define&&define.amd?define([],e):r.randomColor=e()}(this,function(){var o=null,s={};r("monochrome",null,[[0,0],[100,0]]),r("red",[-26,18],[[20,100],[30,92],[40,89],[50,85],[60,78],[70,70],[80,60],[90,55],[100,50]]),r("orange",[18,46],[[20,100],[30,93],[40,88],[50,86],[60,85],[70,70],[100,70]]),r("yellow",[46,62],[[25,100],[40,94],[50,89],[60,86],[70,84],[80,82],[90,80],[100,75]]),r("green",[62,178],[[30,100],[40,90],[50,85],[60,81],[70,74],[80,64],[90,50],[100,40]]),r("blue",[178,257],[[20,100],[30,86],[40,80],[50,74],[60,60],[70,52],[80,44],[90,39],[100,35]]),r("purple",[257,282],[[20,100],[30,87],[40,79],[50,70],[60,65],[70,59],[80,52],[90,45],[100,42]]),r("pink",[282,334],[[20,100],[30,90],[40,86],[60,84],[80,80],[90,75],[100,73]]);var i=[],f=function(r){if(void 0!==(r=r||{}).seed&&null!==r.seed&&r.seed===parseInt(r.seed,10))o=r.seed;else if("string"==typeof r.seed)o=function(r){for(var e=0,n=0;n!==r.length&&!(e>=Number.MAX_SAFE_INTEGER);n++)e+=r.charCodeAt(n);return e}(r.seed);else{if(void 0!==r.seed&&null!==r.seed)throw new TypeError("The seed value must be an integer or string");o=null}var e,n;if(null!==r.count&&void 0!==r.count){for(var t=r.count,a=[],u=0;u<r.count;u++)i.push(!1);for(r.count=null;t>a.length;)o&&r.seed&&(r.seed+=1),a.push(f(r));return r.count=t,a}return function(r,e){switch(e.format){case"hsvArray":return r;case"hslArray":return v(r);case"hsl":var n=v(r);return"hsl("+n[0]+", "+n[1]+"%, "+n[2]+"%)";case"hsla":var t=v(r),a=e.alpha||Math.random();return"hsla("+t[0]+", "+t[1]+"%, "+t[2]+"%, "+a+")";case"rgbArray":return h(r);case"rgb":var u=h(r);return"rgb("+u.join(", ")+")";case"rgba":var o=h(r),a=e.alpha||Math.random();return"rgba("+o.join(", ")+", "+a+")";default:return function(r){var e=h(r);function n(r){var e=r.toString(16);return 1==e.length?"0"+e:e}return"#"+n(e[0])+n(e[1])+n(e[2])}(r)}}([e=function(r){{if(0<i.length){var e=function(r){if(isNaN(r)){if("string"==typeof r)if(s[r]){var e=s[r];if(e.hueRange)return e.hueRange}else if(r.match(/^#?([0-9A-F]{3}|[0-9A-F]{6})$/i)){var n=g(r)[0];return l(n).hueRange}}else{var t=parseInt(r);if(t<360&&0<t)return l(r).hueRange}return[0,360]}(r.hue),n=c(e),t=(e[1]-e[0])/i.length,a=parseInt((n-e[0])/t);!0===i[a]?a=(a+2)%i.length:i[a]=!0;var u=(e[0]+a*t)%359,o=(e[0]+(a+1)*t)%359;return(n=c(e=[u,o]))<0&&(n=360+n),n}var e=function(r){if("number"==typeof parseInt(r)){var e=parseInt(r);if(e<360&&0<e)return[e,e]}if("string"==typeof r)if(s[r]){var n=s[r];if(n.hueRange)return n.hueRange}else if(r.match(/^#?([0-9A-F]{3}|[0-9A-F]{6})$/i)){var t=g(r)[0];return[t,t]}return[0,360]}(r.hue);return(n=c(e))<0&&(n=360+n),n}}(r),n=function(r,e){if("monochrome"===e.hue)return 0;if("random"===e.luminosity)return c([0,100]);var n=(u=r,l(u).saturationRange),t=n[0],a=n[1];var u;switch(e.luminosity){case"bright":t=55;break;case"dark":t=a-10;break;case"light":a=55}return c([t,a])}(e,r),function(r,e,n){var t=function(r,e){for(var n=l(r).lowerBounds,t=0;t<n.length-1;t++){var a=n[t][0],u=n[t][1],o=n[t+1][0],s=n[t+1][1];if(a<=e&&e<=o){var i=(s-u)/(o-a),f=u-i*a;return i*e+f}}return 0}(r,e),a=100;switch(n.luminosity){case"dark":a=t+20;break;case"light":t=(a+t)/2;break;case"random":t=0,a=100}return c([t,a])}(e,n,r)],r)};function l(r){for(var e in 334<=r&&r<=360&&(r-=360),s){var n=s[e];if(n.hueRange&&r>=n.hueRange[0]&&r<=n.hueRange[1])return s[e]}return"Color not found"}function c(r){if(null===o){var e=Math.random();return e+=.618033988749895,e%=1,Math.floor(r[0]+e*(r[1]+1-r[0]))}var n=r[1]||1,t=r[0]||0,a=(o=(9301*o+49297)%233280)/233280;return Math.floor(t+a*(n-t))}function r(r,e,n){var t=n[0][0],a=n[n.length-1][0],u=n[n.length-1][1],o=n[0][1];s[r]={hueRange:e,lowerBounds:n,saturationRange:[t,a],brightnessRange:[u,o]}}function h(r){var e=r[0];0===e&&(e=1),360===e&&(e=359),e/=360;var n=r[1]/100,t=r[2]/100,a=Math.floor(6*e),u=6*e-a,o=t*(1-n),s=t*(1-u*n),i=t*(1-(1-u)*n),f=256,l=256,c=256;switch(a){case 0:f=t,l=i,c=o;break;case 1:f=s,l=t,c=o;break;case 2:f=o,l=t,c=i;break;case 3:f=o,l=s,c=t;break;case 4:f=i,l=o,c=t;break;case 5:f=t,l=o,c=s}return[Math.floor(255*f),Math.floor(255*l),Math.floor(255*c)]}function g(r){r=3===(r=r.replace(/^#/,"")).length?r.replace(/(.)/g,"$1$1"):r;var e=parseInt(r.substr(0,2),16)/255,n=parseInt(r.substr(2,2),16)/255,t=parseInt(r.substr(4,2),16)/255,a=Math.max(e,n,t),u=a-Math.min(e,n,t),o=a?u/a:0;switch(a){case e:return[(n-t)/u%6*60||0,o,a];case n:return[60*((t-e)/u+2)||0,o,a];case t:return[60*((e-n)/u+4)||0,o,a]}}function v(r){var e=r[0],n=r[1]/100,t=r[2]/100,a=(2-n)*t;return[e,Math.round(n*t/(a<1?a:2-a)*1e4)/100,a/2*100]}return f});<|endoftext|>


<commit_before>$(document).ready(function() {
  //set default value
  $("#pulldown_layout option:contains('"+layout_choice+"')").attr("selected", "selected"); //in the drop-down, select the default selection

  //doing this because the .on("change", change_layout) doesn't seem to be working
  $("#pulldown_layout").change(function() {
    firstTimeAtTheRodeo = 0;
    layout_choice = $(this).val();
    doTheLayout();
    $(".y.axis").remove();
    $(".x.axis").remove();
    doTheAxes();
    $(".legend").remove();
    doTheLegend();
    doTheD3();
  });
});

var firstTimeAtTheRodeo = 1;

//Indices that we'll need to pull from Analytica
var tasIndex = ["CNS","Dermatology","Endocrine Disorder","Immunology","Ophthalmology"];
var statusesIndex = ["ACTIVE","AUTHORIZED","PLANNED"];
var bucketsIndex = ["Potential","Considered","Committed"];
var phasesIndex = ["Preclinical","Phase 1","Phase 2","Phase 3","NDA"];
var compoundsIndex = ["ATH-235","CNS-025","CNS-072","CNS-534","CNS-612","CNS-785","CNS-956","CNS-989","ENDC-522","ENDC-560","ENDC-867","ENDC-920","IMM-060","IMM-165","IMM-211","IMM-455","OPTH-001","OPTH-244"];
var indicationsIndex = ["Acne","Acute Migraine","Acute Pain","Alopecia","Alzheimer's disease","Ankylosing Spondylitis","Anxiety Disorder","Cognitive Impairment","Diabetes Mellitus","Diabetic Nephropathy","Glaucoma","Goiter","Lambert-Eaton Syndrome","Muscular Disorder","Myxedema","Psoriasis","Rheumatoid Arthritis","Sjogren's Sydrome","Smoking Cessation","Thyroid nodules"];
var titles = [{"tas":"TA"},{"statuses":"Status"},{"buckets":"Strategic Bucket"},{"phases":"Phase"},{"compounds":"Compound"},{"indications":"Indication"}];

//delcare global variables for data. this way when they get updated the data will be available globally
var x_list = [];
var y_list = [];
var cFill_list = [];

//Set the margins for the chart
var margin = {top: 50, right: 150, bottom: 80, left: 150},
    width = 1080 - margin.left - margin.right,
    height = 600 - margin.top - margin.bottom;

//Using the basic d3 colors
var color = d3.scale.category10();

//Create an object in the DOM before the svg object on which to latch on our pulldowns
var pulldownrow = d3.select("body").append("div")
  .attr("class", "pulldownrow");

//Build the layout selector
var layout_data =[];
var layout_choices = [{"Pipeline Balance": {x:"phases",y:"tas",z:"enpvs",cFill:"buckets"}},
                    {"Compound-Indications":{x:"compounds",y:"indications",z:"npvs",cFill:"tas"}},
                    {"Alignment":{x:"statuses",y:"buckets",z:"npvs",cFill:"phases"}}];

var layout_choice = "Pipeline Balance"; //Text string of selected option

//build the drop-down for choosing the layout
var layout_dropdown = d3.select(".pulldownrow")
  //add label
  .append("div")
    .attr("class", "pulldownlabel")
    .text("Choose Layout: ")
  //add drop-down
  .append("select")
    .attr("id", "pulldown_layout");
    //.on("change", change_layout) doesn't seem to be applying, so doing in jquery

//add options to dropdown
var layout_options =  layout_dropdown.selectAll("option")
  .data(doTheLayout("strings"))
  .enter()
    .append("option")
    .attr("class", "pulldownoption")
    .text(function(d){ return d; });

//Drop the SVG object after the pulldowns
var svg = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

//Scale analytics. These live outside of the .forEach function.
var yScale = d3.scale.ordinal().rangeRoundBands([0, height]);

var yAxis = d3.svg.axis()
  .scale(yScale)
  .orient("left");

var xScale = d3.scale.ordinal().rangeRoundBands([width, 0]);

var xAxis = d3.svg.axis()
  .scale(xScale)
  .orient("bottom");

//pick the layout you want. parameters: "strings" returns an array of strings representing layout choices. "data" returns the x,y,z,colorfill data. A null parameter returns nothing; it simply invokes a new layout.
function doTheLayout(returnMe) {
  layout_data = layout_choices.filter(function(d,i) {return layout_choices[i][layout_choice] !== undefined;})[0][layout_choice];  //The x,y,z,fill for the selected layout
  var layout_strings = []; //layout_strings is an array of the layout options as text strings
  for(i=0;i<layout_choices.length;i++) {
    layout_strings[i] = d3.keys(layout_choices[i]);
  }
  if (returnMe==='strings') {return layout_strings;} else {if (returnMe ==='data') {return layout_data;}}
}

//Takes x, y, z, cFill (as strings), returns that index for the selected layout.
function getSelectedIndex(n) {
  return eval(layout_data[n]+"Index");
}

function doTheAxes() {
    x_list = getSelectedIndex("x");//phasesIndex.reverse();
    y_list = getSelectedIndex("y");//tasIndex;
    cFill_list = getSelectedIndex("cFill");

    //Set the x- and y-axis domains
    xScale.domain(x_list.map(function(d) { return d; }));
    yScale.domain(y_list.map(function(d) { return d; }));

    //Write the y-axis
    svg.append("g")
        .attr("class", "y axis")
        .call(yAxis)
      .append("text")
        .attr("class", "label")
        .attr("transform", "rotate(-90)")
        .attr("y", "-135px")
        .attr("x", -height/2 + "px")
        .text(titles.filter(function(d,i) {return titles[i][layout_data["y"]] !== undefined;})[0][layout_data["y"]]);

    //Write the x-axis
    svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis)
      .append("text")
        .attr("class", "label")
        .attr("y", "45px")
        .attr("x", width/2 + "px")
        .text(titles.filter(function(d,i) {return titles[i][layout_data["x"]] !== undefined;})[0][layout_data["x"]]);

   //Create the x-grid
    var xgrid = svg.selectAll('.xgrid').data(x_list.map(function(d) { return d; }));

    xgrid.enter().append('line');
    xgrid.exit().remove();

    //We're drawing straight vertical lines that span the height of the graph (yScale.rangeExtent) and hit the points between each bucket
    xgrid.attr('class','xgrid')
        .attr('x1', function(d){
            return xScale(d) + xScale.rangeBand();})  //The "0" x-axis element is the y-axis, so we don't need a grid there. Thus, offset by 1 rangeBand.
        .attr('x2', function(d){
            return xScale(d) + xScale.rangeBand();})  //The "0" x-axis element is the y-axis, so we don't need a grid there. Thus, offset by 1 rangeBand.
        .attr('y1', yScale.rangeExtent()[0])
        .attr('y2', yScale.rangeExtent()[1]);

   //Create the y-grid
    var ygrid = svg.selectAll('.ygrid').data(y_list.map(function(d) { return d; }));

    ygrid.enter().append('line');
    ygrid.exit().remove();

    //We're drawing straight horizontal lines that span the height of the graph (xScale.rangeExtent) and hit the points between each bucket
    ygrid.attr('class','ygrid')
        .attr('y1', function(d){
            return yScale(d);})   //The first y-grid should be the top of the graph, so no offset
        .attr('y2', function(d){
            return yScale(d);})
        .attr('x1', xScale.rangeExtent()[0])
        .attr('x2', xScale.rangeExtent()[1]);
}

function doTheLegend() {
  //draw the legendy thing
  var legend = svg.selectAll(".legend")
      .data(cFill_list)
    .enter().append("g")
      .attr("class", "legend")
      .attr("transform", function(d, i) { return "translate(100," + i * 25 + ")"; });

  legend.append("rect")
      .attr("x", width - 82)
      .attr("width", 18)
      .attr("height", 18)
      .style("fill", color);

  legend.append("text")
      .attr("x", width - 58)
      .attr("y", 9)
      .attr("dy", ".35em")
      .style("text-anchor", "start")
      .text(function(d) { return d; });
}

var myLayout = [];

function doTheD3() {

  var myLayout = doTheLayout("data");

  //Get the data and start drawing
  d3.csv("bingo_data.csv", function(error, data) {
    data.forEach(function(d) {
      d.names = d.names;
      d.y = d[myLayout.y];
      d.x = d[myLayout.x];
      d.z = +d[myLayout.z];
      d.cFill = d[myLayout.cFill];
      d.cat = d.x + ' ' + d.y; //This is what we'll use to figure out the square in which the project belongs.
    });

    //Create tree data structure
    var dataNest = d3.nest()
      .key(function(d) { return d.y; }).sortKeys(d3.ascending)
      .key(function(d) { return d.x; }).sortKeys(d3.ascending)
      //***************NEED TO CHANGE THIS TO SORT BY ASCENDING LAUNCH DATE******************
      .sortValues(function(d1,d2) { return d3.ascending(-d1.z,-d2.z); }) //sorting from highest to lowest
      .entries(data);

    flatData = data.sort(function(d1,d2) { return d3.ascending(-d1.z,-d2.z); }).sort(function(d) {return d3.ascending(d.cat);}); //sorting from highest to lowest

    //Calculate the maximum number of projects in any x-y (e.g. TA-Phase) combo.
    //NB: You can't have multiple rollups within a nest, nor can you aggregate a level underneath a rollup. The solution is to create a key that is the unique x-y (e.g. TA-Phase) combo, then max across it.
    var maxProjArray = d3.nest()
      .key(function(d) { return d.y + ' ' + d.x; }).sortKeys(d3.ascending)
      .rollup(function(leaves) { return leaves.length;})
      .entries(data);
      //This is the maximum number of projects in any x-y (e.g. TA-Phase) bucket
      var maxProjs = d3.max(maxProjArray, function(d) { return d.values; });

    //Get # of x and y elements (e.g. TAs and Phases)
    var numXs = xScale.domain().length;
    var numYs = yScale.domain().length;

    //Determine how many pixels of "personal space" each bubble will get
    var bubble_padding = 5; //Amount of space between the bubbles and the axes.
    var xSpace = (xScale.rangeBand() - bubble_padding*(maxProjs+1))/maxProjs; //bubble_padding is the space between bubbles and between the bubbles and the axes; more padding means smaller bubble size
    var maxR = Math.min(xSpace,(yScale.rangeBand()-2*bubble_padding))/2; //The maximum diameter of a bubble is the lesser of row height and horizontal space allocated to each bubble

    //variables for scaling the z-axis of the bubbles
    var max_size = maxR;
    var min_size = 3;
    var max_z = d3.max(data, function(d) { return d.z; });
    var min_z = d3.min(data, function(d) { return d.z > 0 ? d.z : max_z; });

        //this is two levels down
        bubbles = svg.selectAll(".dot")
          .data(flatData);

//        if (firstTimeAtTheRodeo === 1) {
/*            bubbles.transition()
            .duration(3000)
              .attr("cx", function(d, i) { return xScale(d.x) + (xSpace + bubble_padding)*(i + 0.5); })  //Positioning the bubbles horizontally on the left, centered in their own personal space
              .attr("cy", function(d) { return yScale(d.y) + yScale.rangeBand()/2; }) //Positioning the bubbles vertically in the middle of the box              //transition().attr("cx", 50); //function(d, i) { return xScale(d.x) + (xSpace + bubble_padding)*(i + 0.5); });  //Positioning the bubbles horizontally on the left, centered in their own personal space
              .attr("r", function(d) {
                if (max_z === min_z) {return max_size;} else //If all bubbles are the same, don't bother with math
                  {if (d.z < 0) {return min_size;} else {return (d.z-min_z)/(max_z-min_z)*(max_size-min_size)+min_size;}}
                }) //Taking the squares of the bubble sizes (to reflect area) and normalizing to min & max values
              .style("fill", function(d) { return color(d.cFill); });
*/
            bubbles.enter()
              .append("circle")
              .attr("class", "dot")
              .attr("cx", function(d, i) { return xScale(d.x) + (xSpace + bubble_padding)*(i + 0.5); })  //Positioning the bubbles horizontally on the left, centered in their own personal space
              .attr("cy", function(d) { return yScale(d.y) + yScale.rangeBand()/2; })  //Positioning the bubbles vertically in the middle of the box
              .attr("r", function(d) {
                if (max_z === min_z) {return max_size;} else //If all bubbles are the same, don't bother with math
                  {if (d.z < 0) {return min_size;} else {return (d.z-min_z)/(max_z-min_z)*(max_size-min_size)+min_size;}}
                }) //Taking the squares of the bubble sizes (to reflect area) and normalizing to min & max values
              .style("fill", function(d) { return color(d.cFill); })
              .append("svg:title")
              .text(function(d) { return d.names; });
              //.transition()
              //.duration(3000);
/*
            bubbles.exit()
              .transition()
              .duration(4000)
              .remove();
*/
  });
}

doTheAxes();
doTheD3(); //doTheLayout() is embedded in here
doTheLegend();<commit_msg>Fix backwards phases index.<commit_after>$(document).ready(function() {
  //set default value
  $("#pulldown_layout option:contains('"+layout_choice+"')").attr("selected", "selected"); //in the drop-down, select the default selection

  //doing this because the .on("change", change_layout) doesn't seem to be working
  $("#pulldown_layout").change(function() {
    firstTimeAtTheRodeo = 0;
    layout_choice = $(this).val();
    doTheLayout();
    $(".y.axis").remove();
    $(".x.axis").remove();
    doTheAxes();
    $(".legend").remove();
    doTheLegend();
    doTheD3();
  });
});

var firstTimeAtTheRodeo = 1;

//Indices that we'll need to pull from Analytica
var tasIndex = ["CNS","Dermatology","Endocrine Disorder","Immunology","Ophthalmology"];
var statusesIndex = ["ACTIVE","AUTHORIZED","PLANNED"];
var bucketsIndex = ["Potential","Considered","Committed"];
var phasesIndex = ["NDA","Phase 3","Phase 2","Phase 1", "Preclinical"]; //Order needs to be reversed; easier to send a reversed index than to figure out which indices need to be reversed
var compoundsIndex = ["ATH-235","CNS-025","CNS-072","CNS-534","CNS-612","CNS-785","CNS-956","CNS-989","ENDC-522","ENDC-560","ENDC-867","ENDC-920","IMM-060","IMM-165","IMM-211","IMM-455","OPTH-001","OPTH-244"];
var indicationsIndex = ["Acne","Acute Migraine","Acute Pain","Alopecia","Alzheimer's disease","Ankylosing Spondylitis","Anxiety Disorder","Cognitive Impairment","Diabetes Mellitus","Diabetic Nephropathy","Glaucoma","Goiter","Lambert-Eaton Syndrome","Muscular Disorder","Myxedema","Psoriasis","Rheumatoid Arthritis","Sjogren's Sydrome","Smoking Cessation","Thyroid nodules"];
var titles = [{"tas":"TA"},{"statuses":"Status"},{"buckets":"Strategic Bucket"},{"phases":"Phase"},{"compounds":"Compound"},{"indications":"Indication"}];

//delcare global variables for data. this way when they get updated the data will be available globally
var x_list = [];
var y_list = [];
var cFill_list = [];

//Set the margins for the chart
var margin = {top: 50, right: 150, bottom: 80, left: 150},
    width = 1080 - margin.left - margin.right,
    height = 600 - margin.top - margin.bottom;

//Using the basic d3 colors
var color = d3.scale.category10();

//Create an object in the DOM before the svg object on which to latch on our pulldowns
var pulldownrow = d3.select("body").append("div")
  .attr("class", "pulldownrow");

//Build the layout selector
var layout_data =[];
var layout_choices = [{"Pipeline Balance": {x:"phases",y:"tas",z:"enpvs",cFill:"buckets"}},
                    {"Compound-Indications":{x:"compounds",y:"indications",z:"npvs",cFill:"tas"}},
                    {"Alignment":{x:"statuses",y:"buckets",z:"npvs",cFill:"phases"}}];

var layout_choice = "Pipeline Balance"; //Text string of selected option

//build the drop-down for choosing the layout
var layout_dropdown = d3.select(".pulldownrow")
  //add label
  .append("div")
    .attr("class", "pulldownlabel")
    .text("Choose Layout: ")
  //add drop-down
  .append("select")
    .attr("id", "pulldown_layout");
    //.on("change", change_layout) doesn't seem to be applying, so doing in jquery

//add options to dropdown
var layout_options =  layout_dropdown.selectAll("option")
  .data(doTheLayout("strings"))
  .enter()
    .append("option")
    .attr("class", "pulldownoption")
    .text(function(d){ return d; });

//Drop the SVG object after the pulldowns
var svg = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

//Scale analytics. These live outside of the .forEach function.
var yScale = d3.scale.ordinal().rangeRoundBands([0, height]);

var yAxis = d3.svg.axis()
  .scale(yScale)
  .orient("left");

var xScale = d3.scale.ordinal().rangeRoundBands([width, 0]);

var xAxis = d3.svg.axis()
  .scale(xScale)
  .orient("bottom");

//pick the layout you want. parameters: "strings" returns an array of strings representing layout choices. "data" returns the x,y,z,colorfill data. A null parameter returns nothing; it simply invokes a new layout.
function doTheLayout(returnMe) {
  layout_data = layout_choices.filter(function(d,i) {return layout_choices[i][layout_choice] !== undefined;})[0][layout_choice];  //The x,y,z,fill for the selected layout
  var layout_strings = []; //layout_strings is an array of the layout options as text strings
  for(i=0;i<layout_choices.length;i++) {
    layout_strings[i] = d3.keys(layout_choices[i]);
  }
  if (returnMe==='strings') {return layout_strings;} else {if (returnMe ==='data') {return layout_data;}}
}

//Takes x, y, z, cFill (as strings), returns that index for the selected layout.
function getSelectedIndex(n) {
  return eval(layout_data[n]+"Index");
}

function doTheAxes() {
    x_list = getSelectedIndex("x");//phasesIndex.reverse();
    y_list = getSelectedIndex("y");//tasIndex;
    cFill_list = getSelectedIndex("cFill");

    //Set the x- and y-axis domains
    xScale.domain(x_list.map(function(d) { return d; }));
    yScale.domain(y_list.map(function(d) { return d; }));

    //Write the y-axis
    svg.append("g")
        .attr("class", "y axis")
        .call(yAxis)
      .append("text")
        .attr("class", "label")
        .attr("transform", "rotate(-90)")
        .attr("y", "-135px")
        .attr("x", -height/2 + "px")
        .text(titles.filter(function(d,i) {return titles[i][layout_data["y"]] !== undefined;})[0][layout_data["y"]]);

    //Write the x-axis
    svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis)
      .append("text")
        .attr("class", "label")
        .attr("y", "45px")
        .attr("x", width/2 + "px")
        .text(titles.filter(function(d,i) {return titles[i][layout_data["x"]] !== undefined;})[0][layout_data["x"]]);

   //Create the x-grid
    var xgrid = svg.selectAll('.xgrid').data(x_list.map(function(d) { return d; }));

    xgrid.enter().append('line');
    xgrid.exit().remove();

    //We're drawing straight vertical lines that span the height of the graph (yScale.rangeExtent) and hit the points between each bucket
    xgrid.attr('class','xgrid')
        .attr('x1', function(d){
            return xScale(d) + xScale.rangeBand();})  //The "0" x-axis element is the y-axis, so we don't need a grid there. Thus, offset by 1 rangeBand.
        .attr('x2', function(d){
            return xScale(d) + xScale.rangeBand();})  //The "0" x-axis element is the y-axis, so we don't need a grid there. Thus, offset by 1 rangeBand.
        .attr('y1', yScale.rangeExtent()[0])
        .attr('y2', yScale.rangeExtent()[1]);

   //Create the y-grid
    var ygrid = svg.selectAll('.ygrid').data(y_list.map(function(d) { return d; }));

    ygrid.enter().append('line');
    ygrid.exit().remove();

    //We're drawing straight horizontal lines that span the height of the graph (xScale.rangeExtent) and hit the points between each bucket
    ygrid.attr('class','ygrid')
        .attr('y1', function(d){
            return yScale(d);})   //The first y-grid should be the top of the graph, so no offset
        .attr('y2', function(d){
            return yScale(d);})
        .attr('x1', xScale.rangeExtent()[0])
        .attr('x2', xScale.rangeExtent()[1]);
}

function doTheLegend() {
  //draw the legendy thing
  var legend = svg.selectAll(".legend")
      .data(cFill_list)
    .enter().append("g")
      .attr("class", "legend")
      .attr("transform", function(d, i) { return "translate(100," + i * 25 + ")"; });

  legend.append("rect")
      .attr("x", width - 82)
      .attr("width", 18)
      .attr("height", 18)
      .style("fill", color);

  legend.append("text")
      .attr("x", width - 58)
      .attr("y", 9)
      .attr("dy", ".35em")
      .style("text-anchor", "start")
      .text(function(d) { return d; });
}

var myLayout = [];

function doTheD3() {

  var myLayout = doTheLayout("data");

  //Get the data and start drawing
  d3.csv("bingo_data.csv", function(error, data) {
    data.forEach(function(d) {
      d.names = d.names;
      d.y = d[myLayout.y];
      d.x = d[myLayout.x];
      d.z = +d[myLayout.z];
      d.cFill = d[myLayout.cFill];
      d.cat = d.x + ' ' + d.y; //This is what we'll use to figure out the square in which the project belongs.
      d.position = 0; //Placeholder for the project's order in its category
    });

    //Create tree data structure
    var dataNest = d3.nest()
      .key(function(d) { return d.y; }).sortKeys(d3.ascending)
      .key(function(d) { return d.x; }).sortKeys(d3.ascending)
      //***************NEED TO CHANGE THIS TO SORT BY ASCENDING LAUNCH DATE******************
      .sortValues(function(d1,d2) { return d3.ascending(-d1.z,-d2.z); }) //sorting from highest to lowest
      .entries(data);

    flatData = data.sort(function(d1,d2) { return d3.ascending(-d1.z,-d2.z); }).sort(function(d) {return d3.ascending(d.cat);}); //sorting from highest to lowest

    //Calculate the maximum number of projects in any x-y (e.g. TA-Phase) combo.
    //NB: You can't have multiple rollups within a nest, nor can you aggregate a level underneath a rollup. The solution is to create a key that is the unique x-y (e.g. TA-Phase) combo, then max across it.
    var maxProjArray = d3.nest()
      .key(function(d) { return d.y + ' ' + d.x; }).sortKeys(d3.ascending)
      .rollup(function(leaves) { return leaves.length;})
      .entries(data);
      //This is the maximum number of projects in any x-y (e.g. TA-Phase) bucket
      var maxProjs = d3.max(maxProjArray, function(d) { return d.values; });

    //Get # of x and y elements (e.g. TAs and Phases)
    var numXs = xScale.domain().length;
    var numYs = yScale.domain().length;

    //Determine how many pixels of "personal space" each bubble will get
    var bubble_padding = 5; //Amount of space between the bubbles and the axes.
    var xSpace = (xScale.rangeBand() - bubble_padding*(maxProjs+1))/maxProjs; //bubble_padding is the space between bubbles and between the bubbles and the axes; more padding means smaller bubble size
    var maxR = Math.min(xSpace,(yScale.rangeBand()-2*bubble_padding))/2; //The maximum diameter of a bubble is the lesser of row height and horizontal space allocated to each bubble

    //variables for scaling the z-axis of the bubbles
    var max_size = maxR;
    var min_size = 3;
    var max_z = d3.max(data, function(d) { return d.z; });
    var min_z = d3.min(data, function(d) { return d.z > 0 ? d.z : max_z; });

        //this is two levels down
        bubbles = svg.selectAll(".dot")
          .data(flatData);

//        if (firstTimeAtTheRodeo === 1) {
/*            bubbles.transition()
            .duration(3000)
              .attr("cx", function(d, i) { return xScale(d.x) + (xSpace + bubble_padding)*(i + 0.5); })  //Positioning the bubbles horizontally on the left, centered in their own personal space
              .attr("cy", function(d) { return yScale(d.y) + yScale.rangeBand()/2; }) //Positioning the bubbles vertically in the middle of the box              //transition().attr("cx", 50); //function(d, i) { return xScale(d.x) + (xSpace + bubble_padding)*(i + 0.5); });  //Positioning the bubbles horizontally on the left, centered in their own personal space
              .attr("r", function(d) {
                if (max_z === min_z) {return max_size;} else //If all bubbles are the same, don't bother with math
                  {if (d.z < 0) {return min_size;} else {return (d.z-min_z)/(max_z-min_z)*(max_size-min_size)+min_size;}}
                }) //Taking the squares of the bubble sizes (to reflect area) and normalizing to min & max values
              .style("fill", function(d) { return color(d.cFill); });
*/
            bubbles.enter()
              .append("circle")
              .attr("class", "dot")
              .attr("cx", function(d, i) { return xScale(d.x) + (xSpace + bubble_padding)*(i + 0.5); })  //Positioning the bubbles horizontally on the left, centered in their own personal space
              .attr("cy", function(d) { return yScale(d.y) + yScale.rangeBand()/2; })  //Positioning the bubbles vertically in the middle of the box
              .attr("r", function(d) {
                if (max_z === min_z) {return max_size;} else //If all bubbles are the same, don't bother with math
                  {if (d.z < 0) {return min_size;} else {return (d.z-min_z)/(max_z-min_z)*(max_size-min_size)+min_size;}}
                }) //Taking the squares of the bubble sizes (to reflect area) and normalizing to min & max values
              .style("fill", function(d) { return color(d.cFill); })
              .append("svg:title")
              .text(function(d) { return d.names; });
              //.transition()
              //.duration(3000);
/*
            bubbles.exit()
              .transition()
              .duration(4000)
              .remove();
*/
  });
}

doTheAxes();
doTheD3(); //doTheLayout() is embedded in here
doTheLegend();<|endoftext|>


<commit_before>verb = "verb"
direction = "direction"
inverse_direction = "inv"
item = "item"
nil = "nil"
person = "person"
obj = "object"
abstract = "abstract"
here = "here"
words = {}

words.food = {type: abstract}
words.container = {type: abstract}
words.sittable = {type: abstract}
words.readable = {type: abstract}
words.movable = {type: abstract}

words.walk = {type:verb, eat : "to", method: "move"}
words.move = {type: verb, method: "move_obj", synonym: words.walk}
words.stumble = {type:verb, synonym: words.walk}
words.run = {type:verb, synonym: words.walk}
words.head = {type:verb, synonym: words.walk}
words.go = {type:verb, synonym: words.walk, method: "move"}
words.jump = {type:verb, method: "move"}

words.kill = {type:verb, method: "kill"}

words.examine = {type:verb, method : "examine"}
words.read = {type:verb, method: "read"}

words.help = {type: verb, method : "help"}
words.assist = {type:verb, synonym: words.help, method: "assist"}

words.stand = {type: verb, method: "stand", eat: "up"}
words.lie = {type: verb, method: "lie", eat: "down"}
words.sit = {type: verb, eat: "down", method: "sit"}

words.grab = {type:verb, method: "pickup"}
words.pick = {type: verb, eat: "up", synonym : words.grab}
words.take = {type: verb, synonym: words.grab}

words.open = {type: verb, method: "open"}
words.close = {type: verb, method: "close"}

words.brush = {type: verb, method : "brush"}

words.turn = {type: verb, eat: "on", method: "turn_lights"}

words.eat = {type: verb, method: "eat"}

words.east = {type:direction}
words.north = {type:direction}
words.south = {type:direction}
words.west = {type:direction}

words.up = {type:direction}
words.down = {type:direction}
words.away = {type: inverse_direction}

words.here = {type: here}
words.hall = {type: here}
words.room = {type: here}

words.from = {type: nil}
words.in = {type: nil}
words.on = {type: nil}

words.bed = {type: obj, is_a: words.sittable}
words.blackboard = {type: obj}
words.buttons = {type:obj, synonym: words.panel}
words.cabinet = {type: obj}
words.chair = {type: obj, is_a: words.sittable}
words.clock = {type: obj}
words.countertop = {type: obj}
words.dial = {type: obj}
words.desk = {type:obj}
words.drawer = {type:obj, is_a: words.container}
words.lights = {type: obj}
words.light = {type: obj, synonym: words.lights}
words.painting = {type: obj, is_a: movable}
words.panel = {type:obj}
words.porkchops = {type: obj, is_a: words.food}
words.rubbish = {type: obj}
words.safe = {type: obj}
words.sink = {type: obj}
words.stove = {type: obj}
words.table = {type: obj}
words.teeth = {type: obj}
words.telephone = {type:obj }
words.window = {type: obj}

words.coin = {type: item}
words.documents = {type: item}
words.knife = {type:item}
words.newspaper = {type:item, is_a: words.readable}
words.parachute = {type: item, is_a: container}
words.pen = {type:item}

words.toothbrush = {type: item, long_name : "dirty toothbrush"}
words.towel = {type : item}

words.key = {type: abstract}
words.copper = {type : item, eat: "key", long_name : "copper key", is_a : words.key}
words.small = {type: item, eat: "key", long_name: "small key", is_a: words.key}
words.master = {type: item, eat: "key", long_name: "master key", is_a: words.key} // no description

// Secretary
words.secretary = {type: person}

for (var key in words) {
  	if (words.hasOwnProperty(key)) {
  		words[key].text = key
  	}
}

function get_text (w)
{
	if(w.long_name)
		return w.long_name
	return w.text
}
// @requires: w is of type words.(...)
function get_article(w) {
	var item = get_text(w)
	var article = "a "
	if ("aeiou".indexOf(item[0]) >= 0) {
		article = "an "
	}
	return article
}
object_reaction = {}
object_reaction.toothbrush = {examine: ["",
		"It is probably mine."],
	 pickup: ["",
	 	 "Did I brush my teeth yesterday?
 Come to think of it, what day is it?"]}
object_reaction.teeth = {examine: ["",
		"I should clean them more often."],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.clock = {examine: ["",
		"It tells  the time."],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.towel = {examine: ["",
		"It's a towel."],
	 pickup: ["",
	 	 "I now have a towel"]}
object_reaction.copper = {examine: ["The label states it can be used to open the staff area on floor 14.",
		""],
	 pickup: ["",
	 	 "I found a copper key."]}
object_reaction.bed = {examine: ["",
		"It is a bed.
 It doesn't look very comfortable."],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.window = {examine: ["You look out the window and see a city you don't recognize.",
		"The people look like ants from up here."],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.porkchops = {examine: ["These are cooked porkchops.",
		"Did I... cook this?
It looks tasty."],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.knife = {examine: ["It is a fairly large kitchen knife.",
		""],
	 pickup: ["You picked up a knife.",
	 	 "This knife feels familiar."]}
object_reaction.stove = {examine: ["It is a gas stove used for cooking.",
		"It is still warm..."],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.countertop = {examine: ["It is a countertop used for cooking.",
		""],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.panel = {examine: ["A panel with numbered buttons used to operate the elevator. Every button has a small keyhole next to it.",
		"Strange, the number 13 is missing..."],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.dial = {examine: ["A dial with the numbers 1 to 14. It has a pointer that indicates which floor you are currently on.",
		""],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.small = {examine: ["A small key with a label that reads: floors 12 - 14",
		""],
	 pickup: ["You obtained a small key",
	 	 ""]}
object_reaction.desk = {examine: ["It is a handcarved oaken desk that looks slightly worn. There is one unlocked drawer.",
		""],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.drawer = {examine: ["A closed drawer.",
		"I can't see into a closed drawer."],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.newspaper = {examine: ["It's a newspaper dated Friday the 27th of June 1969.",
		"At least I know the date now."],
	 pickup: ["You pick up the newspaper.",
	 	 ""],
	 read: ["Violent Serial Killer Miraculously Cured",
	 	 "At the Mercy Mental Hospital the notorious serial killer nicknamed 'The Arbitrator', is reported to have been cured after receiving extensive shock therapy. Currently still residing there, The Arbitrator is showing no signs of murderous intent according to Wolfram Switzer, head of Mercy Mental Hospital..."]}
object_reaction.chair = {examine: ["It's a chair. You can sit on it.",
		""],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.table = {examine: ["It's a wooden table.",
		""],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.rubbish = {examine: ["Useless pieces of paper and other trash.",
		""],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.painting = {examine: ["It's a beautiful painting, realistically depicting lilacs in a vase. It is quite bleak however.",
		""],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.safe = {examine: ["It's a locked safe. Unfortunately, nobody put the code on a post-it note.",
		""],
	 pickup: ["",
	 	 "Am I a hacker??"]}

<commit_msg>stuff<commit_after>verb = "verb"
direction = "direction"
inverse_direction = "inv"
item = "item"
nil = "nil"
person = "person"
obj = "object"
abstract = "abstract"
here = "here"
words = {}

words.food = {type: abstract}
words.container = {type: abstract}
words.sittable = {type: abstract}
words.readable = {type: abstract}
words.movable = {type: abstract}

words.walk = {type:verb, eat : "to", method: "move"}
words.move = {type: verb, method: "move_obj", synonym: words.walk}
words.stumble = {type:verb, synonym: words.walk}
words.run = {type:verb, synonym: words.walk}
words.head = {type:verb, synonym: words.walk}
words.go = {type:verb, synonym: words.walk, method: "move"}
words.jump = {type:verb, method: "move"}

words.kill = {type:verb, method: "kill"}

words.examine = {type:verb, method : "examine"}
words.read = {type:verb, method: "read"}

words.help = {type: verb, method : "help"}
words.assist = {type:verb, synonym: words.help, method: "assist"}

words.stand = {type: verb, method: "stand", eat: "up"}
words.lie = {type: verb, method: "lie", eat: "down"}
words.sit = {type: verb, eat: "down", method: "sit"}

words.grab = {type:verb, method: "pickup"}
words.pick = {type: verb, eat: "up", synonym : words.grab}
words.take = {type: verb, synonym: words.grab}

words.open = {type: verb, method: "open"}
words.close = {type: verb, method: "close"}

words.brush = {type: verb, method : "brush"}

words.turn = {type: verb, eat: "on", method: "turn_lights"}

words.eat = {type: verb, method: "eat"}

words.east = {type:direction}
words.north = {type:direction}
words.south = {type:direction}
words.west = {type:direction}

words.up = {type:direction}
words.down = {type:direction}
words.away = {type: inverse_direction}

words.here = {type: here}
words.hall = {type: here}
words.room = {type: here}

words.from = {type: nil}
words.in = {type: nil}
words.on = {type: nil}

words.bed = {type: obj, is_a: words.sittable}
words.blackboard = {type: obj}
words.buttons = {type:obj, synonym: words.panel}
words.cabinet = {type: obj}
words.chair = {type: obj, is_a: words.sittable}
words.clock = {type: obj}
words.countertop = {type: obj}
words.dial = {type: obj}
words.desk = {type:obj}
words.drawer = {type:obj, is_a: words.container}
words.lights = {type: obj}
words.light = {type: obj, synonym: words.lights}
words.painting = {type: obj, is_a: movable}
words.panel = {type:obj}
words.porkchops = {type: obj, is_a: words.food}
words.rubbish = {type: obj}
words.safe = {type: obj, is_a: words.container}
words.sink = {type: obj}
words.stove = {type: obj}
words.table = {type: obj}
words.teeth = {type: obj}
words.telephone = {type:obj }
words.window = {type: obj}

words.coin = {type: item}
words.documents = {type: item}
words.knife = {type:item}
words.newspaper = {type:item, is_a: words.readable}
words.parachute = {type: item, is_a: container}
words.pen = {type:item}

words.toothbrush = {type: item, long_name : "dirty toothbrush"}
words.towel = {type : item}

words.key = {type: abstract}
words.copper = {type : item, eat: "key", long_name : "copper key", is_a : words.key}
words.small = {type: item, eat: "key", long_name: "small key", is_a: words.key}
words.master = {type: item, eat: "key", long_name: "master key", is_a: words.key} // no description

// Secretary
words.secretary = {type: person}

for (var key in words) {
  	if (words.hasOwnProperty(key)) {
  		words[key].text = key
  	}
}

function get_text (w)
{
	if(w.long_name)
		return w.long_name
	return w.text
}
// @requires: w is of type words.(...)
function get_article(w) {
	var item = get_text(w)
	var article = "a "
	if ("aeiou".indexOf(item[0]) >= 0) {
		article = "an "
	}
	return article
}
object_reaction = {}
object_reaction.toothbrush = {examine: ["",
		"It is probably mine."],
	 pickup: ["",
	 	 "Did I brush my teeth yesterday?
 Come to think of it, what day is it?"]}
object_reaction.teeth = {examine: ["",
		"I should clean them more often."],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.clock = {examine: ["",
		"It tells  the time."],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.towel = {examine: ["",
		"It's a towel."],
	 pickup: ["",
	 	 "I now have a towel"]}
object_reaction.copper = {examine: ["The label states it can be used to open the staff area on floor 14.",
		""],
	 pickup: ["",
	 	 "I found a copper key."]}
object_reaction.bed = {examine: ["",
		"It is a bed.
 It doesn't look very comfortable."],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.window = {examine: ["You look out the window and see a city you don't recognize.",
		"The people look like ants from up here."],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.porkchops = {examine: ["These are cooked porkchops.",
		"Did I... cook this?
It looks tasty."],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.knife = {examine: ["It is a fairly large kitchen knife.",
		""],
	 pickup: ["You picked up a knife.",
	 	 "This knife feels familiar."]}
object_reaction.stove = {examine: ["It is a gas stove used for cooking.",
		"It is still warm..."],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.countertop = {examine: ["It is a countertop used for cooking.",
		""],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.panel = {examine: ["A panel with numbered buttons used to operate the elevator. Every button has a small keyhole next to it.",
		"Strange, the number 13 is missing..."],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.dial = {examine: ["A dial with the numbers 1 to 14. It has a pointer that indicates which floor you are currently on.",
		""],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.small = {examine: ["A small key with a label that reads: floors 12 - 14",
		""],
	 pickup: ["You obtained a small key",
	 	 ""]}
object_reaction.desk = {examine: ["It is a handcarved oaken desk that looks slightly worn. There is one unlocked drawer.",
		""],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.drawer = {examine: ["A closed drawer.",
		"I can't see into a closed drawer."],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.newspaper = {examine: ["It's a newspaper dated Friday the 27th of June 1969.",
		"At least I know the date now."],
	 pickup: ["You pick up the newspaper.",
	 	 ""],
	 read: ["Violent Serial Killer Miraculously Cured",
	 	 "At the Mercy Mental Hospital the notorious serial killer nicknamed 'The Arbitrator', is reported to have been cured after receiving extensive shock therapy. Currently still residing there, The Arbitrator is showing no signs of murderous intent according to Wolfram Switzer, head of Mercy Mental Hospital..."]}
object_reaction.chair = {examine: ["It's a chair. You can sit on it.",
		""],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.table = {examine: ["It's a wooden table.",
		""],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.rubbish = {examine: ["Useless pieces of paper and other trash.",
		""],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.painting = {examine: ["It's a beautiful painting, realistically depicting lilacs in a vase. It is quite bleak however.",
		""],
	 pickup: ["",
	 	 "Am I a hacker??"]}
object_reaction.safe = {examine: ["It's a locked safe. Unfortunately, nobody put the code on a post-it note.",
		""],
	 pickup: ["",
	 	 "Am I a hacker??"]}

<|endoftext|>


<commit_before>'use strict';
/* eslint camelcase: 0 */

const EmberAddon = require('ember-cli/lib/broccoli/ember-addon');

module.exports = function(defaults) {
  const app = new EmberAddon(defaults, {
    // Add options here
    dotEnv: {
      clientAllowedKeys: ['ILIOS_FRONTEND_API_NAMESPACE', 'ILIOS_FRONTEND_API_HOST']
    },
    'ember-cli-uglify': {
      uglify: {
        compress: {
          collapse_vars: false
        }
      }
    },
  });

  /*
    This build file specifies the options for the dummy test app of this
    addon, located in `/tests/dummy`
    This build file does *not* influence how the addon or the app using it
    behave. You most likely want to be modifying `./index.js` or app's build file
  */
  return app.toTree();
};
<commit_msg>Force babel to only work with parallel builds<commit_after>'use strict';
/* eslint camelcase: 0 */

const EmberAddon = require('ember-cli/lib/broccoli/ember-addon');

module.exports = function(defaults) {
  const app = new EmberAddon(defaults, {
    // Add options here
    dotEnv: {
      clientAllowedKeys: ['ILIOS_FRONTEND_API_NAMESPACE', 'ILIOS_FRONTEND_API_HOST']
    },
    'ember-cli-uglify': {
      uglify: {
        compress: {
          collapse_vars: false
        }
      }
    },
    'ember-cli-babel': {
      throwUnlessParallelizable: true
    }
  });

  /*
    This build file specifies the options for the dummy test app of this
    addon, located in `/tests/dummy`
    This build file does *not* influence how the addon or the app using it
    behave. You most likely want to be modifying `./index.js` or app's build file
  */
  return app.toTree();
};
<|endoftext|>