<commit_before>/**
 * Based on code developed by the Jupyter development team.
 */
define([
    'jquery',
    'bootstraptour',
    'handlebars',
    'text!kbase/templates/tour/tour_panel.html',
    'css!kbase/css/kbaseTour.css'
], function($, Tour, Handlebars, TourTmpl) {
    "use strict";

    var NarrativeTour = function(narrative, notebook, events) {
        var that = this;
        this.notebook = notebook;
        this.narrative = narrative;
        this.step_duration = 0;
        this.events = events;
        this.template = Handlebars.compile(TourTmpl);
        this.tour_steps = [{
                title: "Welcome to the Narrative Tour", // add a grayed out background.
                placement: 'bottom',
                orphan: true,
                content: '
This tour will demonstrate how to use KBase’s Narrative User Interface to begin creating Narratives for data analysis. Think of a Narrative as an advanced lab notebook that contains all of your data, analyses, notes, visualizations, custom scripts, and results.
Use the left and right arrow buttons to go backwards and forwards through this tour.',
                backdrop: true
            },
            {
                element: "#notebook_name",
                title: "Narrative Name",
                placement: 'bottom',
                content: 'By default, each new Narrative is named “Untitled.” Click on this name and enter a new title.'
            },
            {
                element: '#kb-view-mode',
                title: 'Toggle View Only',
                placement: 'bottom',
                content: 'If you have edit permission for this Narrative, you can choose View Only (uneditable) or Edit mode'
            },
            {
                element: '#kb-update-btn',
                title: 'Narrative Update',
                placement: 'bottom',
                content: 'If there\'s an update to the Narrative Interface, this button will appear. Click it before you start working on your Narrative.',
                onShow: function(tour) {
                    $('#kb-update-btn').show();
                },
                onHide: function(tour) {
                    $('#kb-update-btn').hide();
                }
            },
            {
                element: $('#kb-share-btn .kb-nav-btn-txt'),
                title: 'Share with others',
                placement: 'bottom',
                content: 'Click the Share button to open a dialog box allowing you to search for and select KBase users you want to share with. You can give them view-only access, editing privileges, or the ability to edit and share the Narrative with other users. By default, each Narrative you create is private. You can choose to make your Narrative public or share it with certain collaborators.'
            },
            {
                element: '#kb-save-btn',
                title: 'Save the Narrative',
                placement: 'bottom',
                content: 'You should periodically save your Narrative by clicking the save button. KBase does autosave your Narrative whenever an App is run, but other changes should be saved manually.'
            },
            {
                element: '#signin-button',
                title: 'Profile and Logout',
                placement: 'left',
                content: 'Click here for a menu that will let you view and edit your user profile or log out.'
            },
            {
                element: '.kb-side-header[kb-data-id="0"]',
                title: 'Analyze Tab',
                placement: 'bottom',
                content: 'The Analyze tab contains both the data you have added to this Narrative and the analysis tools in KBase--called Apps.',
                onShow: function(tour) {
                    $('.kb-side-header[kb-data-id="0"]').click();
                }
            },
            {
                element: $('.kb-side-tab[kb-data-id="0"]').find('button > .fa-arrow-right').first(), //$('.kb-side-tab[kb-data-id="0"] > button > .fa-arrow-right'),
                title: 'Data Slideout',
                placement: 'left',
                content: 'This arrow opens the data slideout, which allows you to add data to your Narrative from a variety of sources.',
                onShow: function(tour) {
                    that.openDataSlideout(true);
                }
            },
            {
                element: '.kb-side-overlay-container .kb-side-header:nth-child(1)', // my data tab
                title: 'My Data',
                placement: 'bottom',
                content: 'The My Data tab shows data from your other Narratives. If this is your first Narrative, it will be empty.',
                onShow: function(tour) {
                    that.openDataSlideout(true);
                    $('.kb-side-overlay-container .kb-side-header:nth-child(1)').click();
                }
            },
            {
                element: '.kb-side-overlay-container .kb-side-header:nth-child(2)', // shared with me tab
                title: 'Shared With Me',
                placement: 'bottom',
                content: 'The Shared With Me tab contains data from any Narratives that have been shared with you by collaborators.',
                onShow: function(tour) {
                    that.openDataSlideout(true);
                    $('.kb-side-overlay-container .kb-side-header:nth-child(2)').click();
                }
            },
            {
                element: '.kb-side-overlay-container .kb-side-header:nth-child(3)', // public tab
                title: 'Public Data',
                placement: 'bottom',
                content: 'The Public tab provides direct access to public data that KBase periodically imports from several sources. These sources are listed on the KBase website kbase.us/data-policy-and-sources',
                onShow: function(tour) {
                    that.openDataSlideout(true);
                    $('.kb-side-overlay-container .kb-side-header:nth-child(3)').click();
                }
            },
            {
                element: '.kb-side-overlay-container .kb-side-header:nth-child(4)', // example tab
                title: 'Example Data',
                placement: 'bottom',
                content: 'The Example tab contains sample data that can be used to try out KBase analysis tools.',
                onShow: function(tour) {
                    that.openDataSlideout(true);
                    $('.kb-side-overlay-container .kb-side-header:nth-child(4)').click();
                }
            },
            {
                element: '.kb-side-overlay-container .kb-side-header:nth-child(5)', // import tab
                title: 'Import Data',
                placement: 'bottom',
                content: 'Finally, the Import tab allows you to upload your own data for analysis. Any data you add are kept private unless you choose to share your Narrative. This and other data you add are private unless you choose to share your Narrative. Click the drop-down menu to see a list of currently uploadable data types.',
                onShow: function(tour) {
                    that.openDataSlideout(true);
                    $('.kb-side-overlay-container .kb-side-header:nth-child(5)').click();
                }
            },
            {
                element: '.kb-narr-side-panel-set > .kb-side-separator:nth-child(2)', // The 'Apps' area
                title: 'Apps in KBase',
                placement: 'right',
                content: 'In KBase, you can run complex analyses on the data in your Narrative by using Apps. All of the Apps available in KBase are listed just below the Data Panel. Click an App name to add it to your Narrative, or click the “...” that appears to the right of the name when hovering your mouse to see more information about the App.',
                onShow: function(tour) {
                    $('.kb-side-header[kb-data-id="0"]').click();
                    that.openDataSlideout(false);
                }
            },
            {
                element: '.kb-side-separator:nth-child(2) .kb-function-body .kb-data-list-obj-row:first', //'.kb-narr-side-panel-set > .kb-side-separator:nth-child(2)', // [...] or more... btn on first app
                title: 'App Information',
                placement: 'right',
                content: 'After clicking the "..." to see a short description of an App, click the "more..." link at the end of the description to open another tab with detailed information about the App.',
                onShow: function(tour) {
                    $('.kb-side-header[kb-data-id="0"]').click();
                    $('.kb-side-separator:nth-child(2) .kb-function-body .kb-data-list-obj-row:first').click();
                    // get first ellipsis and click on it.
                }
            },
            {
                element: '.kb-side-header[kb-data-id="1"]',
                title: 'Narratives Tab',
                placement: 'bottom',
                content: '
This tab lists all your Narratives and those that have been shared with you. Click the name of any Narrative to open it in a new window. Hovering over a Narrative name will reveal options for viewing its history, reverting to an earlier version, and copying or deleting it. This tab also lets you create a new, empty Narrative or copy a Narrative, complete with all its data and contents.',
                onShow: function(tour) {
                    $('.kb-side-header[kb-data-id="1"]').click();
                }
            },
            {
                element: '#kb-add-md-cell',
                title: 'Markdown Cells',
                placement: 'left',
                content: 'You can include formatted text in your Narratives in markdown cells, which can be inserted by clicking the paragraph icon at the bottom of the Narrative. Markdown cells can also contain raw text, HTML, or LaTeX.'
            },
            {
                title: "End of Basic Features Tour",
                orphan: true,
                content: "
You have now been introduced to the basic features of the Narrative Interface. We hope you conduct interesting and creative research using these tools and are able to expand your collaborator network with other KBase users. If you have any questions or feature requests, please follow the Contact Us link in the hamburger menu at the top left.
To learn about advanced features of the Narrative Interface, click the right arrow button to proceed. To exit the tour, click the X at the top right of this box.",
                backdrop: true
            },
            {
                element: '#kb-ipy-menu',
                title: 'Kernel Controls',
                placement: 'bottom',
                content: 'Access control options for the Jupyter kernel that powers the Narrative Interface. This is useful for restarting or reconnecting to KBase after your network connection has been disrupted.',
            },
            // {
            //     element: '#kb-settings-btn',
            //     title: 'Adjust Global Settings',
            //     placement: 'bottom',
            //     content: 'Enable advanced or developer features for your Narrative in the Settings Menu. These option are enabled for individual Narratives. Refresh your browser to enable these settings for your Narrative.'
            // },
            {
                element: '#kb-add-code-cell',
                title: 'Code Cells',
                placement: 'left',
                content: 'Code Cells allow you to use Python and other coding languages to create custom scripts in your Narrative.'
            },
            {
                title: 'End of Advanced Features Tour',
                orphan: true,
                content: 'You have now been introduced to the advanced features of the Narrative Interface. The Narrative User Guide has more information. If you have any questions or feature requests, please follow the Contact Us link in the hamburger menu.',
                backdrop: true
            }

        ];

        this.tour = new Tour({
            storage: false, // start tour from beginning every time
            debug: true,
            reflex: true, // click on element to continue tour
            animation: false,
            duration: this.step_duration,
            onPause: this.toggle_pause_play,
            onResume: this.toggle_pause_play,
            steps: this.tour_steps,
            template: function(i, step) {
                return that.template({ step: (i + 1), totalSteps: that.tour_steps.length });
            },
            orphan: true
        });

    };

    /**
     * Opens the data slideout if it's not open already.
     */
    NarrativeTour.prototype.openDataSlideout = function(setOpen) {
        if (setOpen) {
            this.narrative.showDataOverlay();
            // $(document).trigger('showSidePanelOverlay.Narrative');
            // $('.kb-side-tab[kb-data-id="0"]').find('button > .fa-arrow-right')
            //                                  .first()
            //                                  .click();
        } else {
            this.narrative.hideOverlay();
            // $(document).trigger('hideSidePanelOverlay.Narrative');
        }
    };

    NarrativeTour.prototype.start = function() {
        this.tour.init();
        this.tour.start();
        if (this.tour.ended()) {
            this.tour.restart();
        }
    };

    NarrativeTour.prototype.stop = function() {
        if (this.tour && !this.tour.ended()) {
            this.tour.end();
        }
    };

    NarrativeTour.prototype.command_icon_hack = function() {
        $('#modal_indicator').css('min-height', '18px');
    };

    NarrativeTour.prototype.toggle_pause_play = function() {
        $('#tour-pause').toggleClass('fa-pause fa-play');
    };

    NarrativeTour.prototype.edit_mode = function() {
        this.notebook.focus_cell();
        this.notebook.edit_mode();
    };

    return { 'Tour': NarrativeTour };

});
<commit_msg>improved wording of import tab tour text<commit_after>/**
 * Based on code developed by the Jupyter development team.
 */
define([
    'jquery',
    'bootstraptour',
    'handlebars',
    'text!kbase/templates/tour/tour_panel.html',
    'css!kbase/css/kbaseTour.css'
], function($, Tour, Handlebars, TourTmpl) {
    "use strict";

    var NarrativeTour = function(narrative, notebook, events) {
        var that = this;
        this.notebook = notebook;
        this.narrative = narrative;
        this.step_duration = 0;
        this.events = events;
        this.template = Handlebars.compile(TourTmpl);
        this.tour_steps = [{
                title: "Welcome to the Narrative Tour", // add a grayed out background.
                placement: 'bottom',
                orphan: true,
                content: '
This tour will demonstrate how to use KBase’s Narrative User Interface to begin creating Narratives for data analysis. Think of a Narrative as an advanced lab notebook that contains all of your data, analyses, notes, visualizations, custom scripts, and results.
Use the left and right arrow buttons to go backwards and forwards through this tour.',
                backdrop: true
            },
            {
                element: "#notebook_name",
                title: "Narrative Name",
                placement: 'bottom',
                content: 'By default, each new Narrative is named “Untitled.” Click on this name and enter a new title.'
            },
            {
                element: '#kb-view-mode',
                title: 'Toggle View Only',
                placement: 'bottom',
                content: 'If you have edit permission for this Narrative, you can choose View Only (uneditable) or Edit mode'
            },
            {
                element: '#kb-update-btn',
                title: 'Narrative Update',
                placement: 'bottom',
                content: 'If there\'s an update to the Narrative Interface, this button will appear. Click it before you start working on your Narrative.',
                onShow: function(tour) {
                    $('#kb-update-btn').show();
                },
                onHide: function(tour) {
                    $('#kb-update-btn').hide();
                }
            },
            {
                element: $('#kb-share-btn .kb-nav-btn-txt'),
                title: 'Share with others',
                placement: 'bottom',
                content: 'Click the Share button to open a dialog box allowing you to search for and select KBase users you want to share with. You can give them view-only access, editing privileges, or the ability to edit and share the Narrative with other users. By default, each Narrative you create is private. You can choose to make your Narrative public or share it with certain collaborators.'
            },
            {
                element: '#kb-save-btn',
                title: 'Save the Narrative',
                placement: 'bottom',
                content: 'You should periodically save your Narrative by clicking the save button. KBase does autosave your Narrative whenever an App is run, but other changes should be saved manually.'
            },
            {
                element: '#signin-button',
                title: 'Profile and Logout',
                placement: 'left',
                content: 'Click here for a menu that will let you view and edit your user profile or log out.'
            },
            {
                element: '.kb-side-header[kb-data-id="0"]',
                title: 'Analyze Tab',
                placement: 'bottom',
                content: 'The Analyze tab contains both the data you have added to this Narrative and the analysis tools in KBase--called Apps.',
                onShow: function(tour) {
                    $('.kb-side-header[kb-data-id="0"]').click();
                }
            },
            {
                element: $('.kb-side-tab[kb-data-id="0"]').find('button > .fa-arrow-right').first(), //$('.kb-side-tab[kb-data-id="0"] > button > .fa-arrow-right'),
                title: 'Data Slideout',
                placement: 'left',
                content: 'This arrow opens the data slideout, which allows you to add data to your Narrative from a variety of sources.',
                onShow: function(tour) {
                    that.openDataSlideout(true);
                }
            },
            {
                element: '.kb-side-overlay-container .kb-side-header:nth-child(1)', // my data tab
                title: 'My Data',
                placement: 'bottom',
                content: 'The My Data tab shows data from your other Narratives. If this is your first Narrative, it will be empty.',
                onShow: function(tour) {
                    that.openDataSlideout(true);
                    $('.kb-side-overlay-container .kb-side-header:nth-child(1)').click();
                }
            },
            {
                element: '.kb-side-overlay-container .kb-side-header:nth-child(2)', // shared with me tab
                title: 'Shared With Me',
                placement: 'bottom',
                content: 'The Shared With Me tab contains data from any Narratives that have been shared with you by collaborators.',
                onShow: function(tour) {
                    that.openDataSlideout(true);
                    $('.kb-side-overlay-container .kb-side-header:nth-child(2)').click();
                }
            },
            {
                element: '.kb-side-overlay-container .kb-side-header:nth-child(3)', // public tab
                title: 'Public Data',
                placement: 'bottom',
                content: 'The Public tab provides direct access to public data that KBase periodically imports from several sources. These sources are listed on the KBase website kbase.us/data-policy-and-sources',
                onShow: function(tour) {
                    that.openDataSlideout(true);
                    $('.kb-side-overlay-container .kb-side-header:nth-child(3)').click();
                }
            },
            {
                element: '.kb-side-overlay-container .kb-side-header:nth-child(4)', // example tab
                title: 'Example Data',
                placement: 'bottom',
                content: 'The Example tab contains sample data that can be used to try out KBase analysis tools.',
                onShow: function(tour) {
                    that.openDataSlideout(true);
                    $('.kb-side-overlay-container .kb-side-header:nth-child(4)').click();
                }
            },
            {
                element: '.kb-side-overlay-container .kb-side-header:nth-child(5)', // import tab
                title: 'Import Data',
                placement: 'bottom',
                content: 'Finally, the Import tab allows you to upload your own data for analysis. Any data you add are kept private unless you choose to share your Narrative. The Data Upload/Download Guide has more information about how to import your data.',
                onShow: function(tour) {
                    that.openDataSlideout(true);
                    $('.kb-side-overlay-container .kb-side-header:nth-child(5)').click();
                }
            },
            {
                element: '.kb-narr-side-panel-set > .kb-side-separator:nth-child(2)', // The 'Apps' area
                title: 'Apps in KBase',
                placement: 'right',
                content: 'In KBase, you can run complex analyses on the data in your Narrative by using Apps. All of the Apps available in KBase are listed just below the Data Panel. Click an App name to add it to your Narrative, or click the “...” that appears to the right of the name when hovering your mouse to see more information about the App.',
                onShow: function(tour) {
                    $('.kb-side-header[kb-data-id="0"]').click();
                    that.openDataSlideout(false);
                }
            },
            {
                element: '.kb-side-separator:nth-child(2) .kb-function-body .kb-data-list-obj-row:first', //'.kb-narr-side-panel-set > .kb-side-separator:nth-child(2)', // [...] or more... btn on first app
                title: 'App Information',
                placement: 'right',
                content: 'After clicking the "..." to see a short description of an App, click the "more..." link at the end of the description to open another tab with detailed information about the App.',
                onShow: function(tour) {
                    $('.kb-side-header[kb-data-id="0"]').click();
                    $('.kb-side-separator:nth-child(2) .kb-function-body .kb-data-list-obj-row:first').click();
                    // get first ellipsis and click on it.
                }
            },
            {
                element: '.kb-side-header[kb-data-id="1"]',
                title: 'Narratives Tab',
                placement: 'bottom',
                content: '
This tab lists all your Narratives and those that have been shared with you. Click the name of any Narrative to open it in a new window. Hovering over a Narrative name will reveal options for viewing its history, reverting to an earlier version, and copying or deleting it. This tab also lets you create a new, empty Narrative or copy a Narrative, complete with all its data and contents.',
                onShow: function(tour) {
                    $('.kb-side-header[kb-data-id="1"]').click();
                }
            },
            {
                element: '#kb-add-md-cell',
                title: 'Markdown Cells',
                placement: 'left',
                content: 'You can include formatted text in your Narratives in markdown cells, which can be inserted by clicking the paragraph icon at the bottom of the Narrative. Markdown cells can also contain raw text, HTML, or LaTeX.'
            },
            {
                title: "End of Basic Features Tour",
                orphan: true,
                content: "
You have now been introduced to the basic features of the Narrative Interface. We hope you conduct interesting and creative research using these tools and are able to expand your collaborator network with other KBase users. If you have any questions or feature requests, please follow the Contact Us link in the hamburger menu at the top left.
To learn about advanced features of the Narrative Interface, click the right arrow button to proceed. To exit the tour, click the X at the top right of this box.",
                backdrop: true
            },
            {
                element: '#kb-ipy-menu',
                title: 'Kernel Controls',
                placement: 'bottom',
                content: 'Access control options for the Jupyter kernel that powers the Narrative Interface. This is useful for restarting or reconnecting to KBase after your network connection has been disrupted.',
            },
            // {
            //     element: '#kb-settings-btn',
            //     title: 'Adjust Global Settings',
            //     placement: 'bottom',
            //     content: 'Enable advanced or developer features for your Narrative in the Settings Menu. These option are enabled for individual Narratives. Refresh your browser to enable these settings for your Narrative.'
            // },
            {
                element: '#kb-add-code-cell',
                title: 'Code Cells',
                placement: 'left',
                content: 'Code Cells allow you to use Python and other coding languages to create custom scripts in your Narrative.'
            },
            {
                title: 'End of Advanced Features Tour',
                orphan: true,
                content: 'You have now been introduced to the advanced features of the Narrative Interface. The Narrative User Guide has more information. If you have any questions or feature requests, please follow the Contact Us link in the hamburger menu.',
                backdrop: true
            }

        ];

        this.tour = new Tour({
            storage: false, // start tour from beginning every time
            debug: true,
            reflex: true, // click on element to continue tour
            animation: false,
            duration: this.step_duration,
            onPause: this.toggle_pause_play,
            onResume: this.toggle_pause_play,
            steps: this.tour_steps,
            template: function(i, step) {
                return that.template({ step: (i + 1), totalSteps: that.tour_steps.length });
            },
            orphan: true
        });

    };

    /**
     * Opens the data slideout if it's not open already.
     */
    NarrativeTour.prototype.openDataSlideout = function(setOpen) {
        if (setOpen) {
            this.narrative.showDataOverlay();
            // $(document).trigger('showSidePanelOverlay.Narrative');
            // $('.kb-side-tab[kb-data-id="0"]').find('button > .fa-arrow-right')
            //                                  .first()
            //                                  .click();
        } else {
            this.narrative.hideOverlay();
            // $(document).trigger('hideSidePanelOverlay.Narrative');
        }
    };

    NarrativeTour.prototype.start = function() {
        this.tour.init();
        this.tour.start();
        if (this.tour.ended()) {
            this.tour.restart();
        }
    };

    NarrativeTour.prototype.stop = function() {
        if (this.tour && !this.tour.ended()) {
            this.tour.end();
        }
    };

    NarrativeTour.prototype.command_icon_hack = function() {
        $('#modal_indicator').css('min-height', '18px');
    };

    NarrativeTour.prototype.toggle_pause_play = function() {
        $('#tour-pause').toggleClass('fa-pause fa-play');
    };

    NarrativeTour.prototype.edit_mode = function() {
        this.notebook.focus_cell();
        this.notebook.edit_mode();
    };

    return { 'Tour': NarrativeTour };

});
<|endoftext|>


<commit_before>var tabMargin = 0;

function tabSwitch(btn) {
  var node = document.getElementById('main');

  if(tabMargin == 0) {
    node.style.margin = '0';
    btn.style.background = '#aaa';
    tabMargin = 1;
  }else {
    node.style.margin = '0 0 0 -150px';
    btn.style.background = '#fff';
    tabMargin = 0;
  }
}

function starting() {
  var node = document.getElementById('startPage');

  node.style.margin = '-100vh 0 0 0';
}

function getAndLocatePoints(category) {
  url = '';
  if (category) {
    url = "/api/v1/tourism_point/?category=" + category;
  } else {
    url = "/api/v1/tourism_point/"
  }
  $.ajax({
    url: url
  }).done(function(data) {
    for (point in data) {
      if (data.hasOwnProperty(point)) {
        console.log(data[point]);
      }
    }
  }).fail(function(data) {
    console.log('error');
    console.log(data);
  });
}

$(function(){
  getAndLocatePoints();
});
<commit_msg>[fix] startpage<commit_after>var tabMargin = 0;
var flgLocate = 0;

if(navigator.geolocation) {
  flgLocate = 1;
}

function tabSwitch(btn) {
  var node = document.getElementById('main');

  if(tabMargin == 0) {
    node.style.margin = '0';
    btn.style.background = '#aaa';
    tabMargin = 1;
  }else {
    node.style.margin = '0 0 0 -150px';
    btn.style.background = '#fff';
    tabMargin = 0;
  }
}

function starting() {
  if(flgLocate == '1') {
    var node = document.getElementById('startPage');

    node.style.margin = '-100vh 0 0 0';
  }
}

function getAndLocatePoints(category) {
  url = '';
  if (category) {
    url = "/api/v1/tourism_point/?category=" + category;
  } else {
    url = "/api/v1/tourism_point/"
  }
  $.ajax({
    url: url
  }).done(function(data) {
    for (point in data) {
      if (data.hasOwnProperty(point)) {
        console.log(data[point]);
      }
    }
  }).fail(function(data) {
    console.log('error');
    console.log(data);
  });
}

$(function(){
  getAndLocatePoints();
});
<|endoftext|>


<commit_before>/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
 * Use of this file is governed by the BSD 3-clause license that
 * can be found in the LICENSE.txt file in the project root.
 */
exports.atn = require('./atn/index');
exports.codepointat = require('./polyfills/codepointat');
exports.dfa = require('./dfa/index');
exports.fromcodepoint = require('./polyfills/fromcodepoint');
exports.tree = require('./tree/index');
exports.error = require('./error/index');
exports.Token = require('./Token').Token;
exports.CharStreams = require('./CharStreams');
exports.CommonToken = require('./Token').CommonToken;
exports.InputStream = require('./InputStream');
exports.FileStream = require('./FileStream');
exports.CommonTokenStream = require('./CommonTokenStream');
exports.Lexer = require('./Lexer');
exports.Parser = require('./Parser');
var pc = require('./PredictionContext');
exports.PredictionContextCache = pc.PredictionContextCache;
exports.ParserRuleContext = require('./ParserRuleContext');
exports.Interval = require('./IntervalSet').Interval;
exports.Utils = require('./Utils');
<commit_msg>adds IntervalSet to the export list<commit_after>/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
 * Use of this file is governed by the BSD 3-clause license that
 * can be found in the LICENSE.txt file in the project root.
 */
exports.atn = require('./atn/index');
exports.codepointat = require('./polyfills/codepointat');
exports.dfa = require('./dfa/index');
exports.fromcodepoint = require('./polyfills/fromcodepoint');
exports.tree = require('./tree/index');
exports.error = require('./error/index');
exports.Token = require('./Token').Token;
exports.CharStreams = require('./CharStreams');
exports.CommonToken = require('./Token').CommonToken;
exports.InputStream = require('./InputStream');
exports.FileStream = require('./FileStream');
exports.CommonTokenStream = require('./CommonTokenStream');
exports.Lexer = require('./Lexer');
exports.Parser = require('./Parser');
var pc = require('./PredictionContext');
exports.PredictionContextCache = pc.PredictionContextCache;
exports.ParserRuleContext = require('./ParserRuleContext');
exports.Interval = require('./IntervalSet').Interval;
exports.IntervalSet = require('./IntervalSet').IntervalSet;
exports.Utils = require('./Utils');
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { getExperiment, getParams, getRunInfo, getRunTags } from '../reducers/Reducers';
import { connect } from 'react-redux';
import './RunView.css';
import HtmlTableView from './HtmlTableView';
import { Link } from 'react-router-dom';
import Routes from '../Routes';
import { Dropdown, MenuItem } from 'react-bootstrap';
import ArtifactPage from './ArtifactPage';
import { getLatestMetrics } from '../reducers/MetricReducer';
import { Experiment } from '../sdk/MlflowMessages';
import Utils from '../utils/Utils';
import { MLFLOW_INTERNAL_PREFIX } from "../utils/TagUtils";
import { NoteInfo } from "../utils/NoteUtils";
import BreadcrumbTitle from "./BreadcrumbTitle";
import RenameRunModal from "./modals/RenameRunModal";
import NoteEditorView from "./NoteEditorView";
import NoteShowView from "./NoteShowView";

const NOTES_KEY = 'notes';
const PARAMETERS_KEY = 'parameters';
const METRICS_KEY = 'metrics';
const ARTIFACTS_KEY = 'artifacts';
const TAGS_KEY = 'tags';

class RunView extends Component {
  constructor(props) {
    super(props);
    this.onClickExpander = this.onClickExpander.bind(this);
    this.getExpanderClassName = this.getExpanderClassName.bind(this);
    this.handleRenameRunClick = this.handleRenameRunClick.bind(this);
    this.hideRenameRunModal = this.hideRenameRunModal.bind(this);
    this.handleExposeNotesEditorClick = this.handleExposeNotesEditorClick.bind(this);
    this.handleSubmittedNote = this.handleSubmittedNote.bind(this);
    this.handleNoteEditorViewCancel = this.handleNoteEditorViewCancel.bind(this);
    this.renderNoteSection = this.renderNoteSection.bind(this);
    this.state.showTags = getVisibleTagValues(props.tags).length > 0;
  }

  static propTypes = {
    runUuid: PropTypes.string.isRequired,
    run: PropTypes.object.isRequired,
    experiment: PropTypes.instanceOf(Experiment).isRequired,
    experimentId: PropTypes.number.isRequired,
    params: PropTypes.object.isRequired,
    tags: PropTypes.object.isRequired,
    latestMetrics: PropTypes.object.isRequired,
    getMetricPagePath: PropTypes.func.isRequired,
    runDisplayName: PropTypes.string.isRequired,
    runName: PropTypes.string.isRequired,
  };

  state = {
    showNotesEditor: false,
    showNotes: true,
    showParameters: true,
    showMetrics: true,
    showArtifacts: true,
    showTags: true,
    showRunRenameModal: false,
  };

  onClickExpander(key) {
    switch (key) {
      case NOTES_KEY: {
        this.setState({ showNotes: !this.state.showNotes });
        return;
      }
      case PARAMETERS_KEY: {
        this.setState({ showParameters: !this.state.showParameters });
        return;
      }
      case METRICS_KEY: {
        this.setState({ showMetrics: !this.state.showMetrics });
        return;
      }
      case TAGS_KEY: {
        this.setState({ showTags: !this.state.showTags });
        return;
      }
      case ARTIFACTS_KEY: {
        this.setState({ showArtifacts: !this.state.showArtifacts });
        return;
      }
      default:
    }
  }

  getExpanderClassName(key) {
    switch (key) {
      case NOTES_KEY: {
        return this.state.showNotes ? 'fa-caret-down' : 'fa-caret-right';
      }
      case PARAMETERS_KEY: {
        return this.state.showParameters ? 'fa-caret-down' : 'fa-caret-right';
      }
      case METRICS_KEY: {
        return this.state.showMetrics ? 'fa-caret-down' : 'fa-caret-right';
      }
      case TAGS_KEY: {
        return this.state.showTags ? 'fa-caret-down' : 'fa-caret-right';
      }
      case ARTIFACTS_KEY: {
        return this.state.showArtifacts ? 'fa-caret-down' : 'fa-caret-right';
      }
      default: {
        return null;
      }
    }
  }

  handleExposeNotesEditorClick() {
    this.setState({ showNotesEditor: true, showNotes: true });
  }

  handleNoteEditorViewCancel() {
    this.setState({ showNotesEditor: false });
  }

  handleRenameRunClick() {
    this.setState({ showRunRenameModal: true });
  }

  hideRenameRunModal() {
    this.setState({ showRunRenameModal: false });
  }

  renderNoteSection(noteInfo) {
    if (this.state.showNotes) {
      if (this.state.showNotesEditor) {
        return <NoteEditorView
            runUuid={this.props.runUuid}
            noteInfo={noteInfo}
            submitCallback={this.handleSubmittedNote}
            cancelCallback={this.handleNoteEditorViewCancel}/>;
      } else if (noteInfo) {
        return <NoteShowView content={noteInfo.content}/>;
      } else {
        return None;
      }
    }
    return null;
  }

  getRunCommand() {
    const { run, params } = this.props;
    let runCommand = null;
    if (run.source_type === "PROJECT") {
      runCommand = 'mlflow run ' + shellEscape(run.source_name);
      if (run.source_version && run.source_version !== "latest") {
        runCommand += ' -v ' + shellEscape(run.source_version);
      }
      if (run.entry_point_name && run.entry_point_name !== "main") {
        runCommand += ' -e ' + shellEscape(run.entry_point_name);
      }
      Object.values(params).sort().forEach(p => {
        runCommand += ' -P ' + shellEscape(p.key + '=' + p.value);
      });
    }
    return runCommand;
  }

  render() {
    const { run, params, tags, latestMetrics, getMetricPagePath } = this.props;
    const noteInfo = NoteInfo.fromRunTags(tags);
    const startTime = run.getStartTime() ? Utils.formatTimestamp(run.getStartTime()) : '(unknown)';
    const duration =
      run.getStartTime() && run.getEndTime() ? run.getEndTime() - run.getStartTime() : null;
    const tableStyles = {
      table: {
        width: 'auto',
        minWidth: '400px',
      },
      th: {
        width: 'auto',
        minWidth: '200px',
        marginRight: '80px',
      }
    };
    const runCommand = this.getRunCommand();
    return (

          <BreadcrumbTitle
            experiment={this.props.experiment}
            title={this.props.runDisplayName}
          />
          <Dropdown id="dropdown-custom-1" className="mlflow-dropdown">
             <Dropdown.Toggle noCaret className="mlflow-dropdown-button">

             </Dropdown.Toggle>
             <Dropdown.Menu className="mlflow-menu header-menu">
               <MenuItem
                 className="mlflow-menu-item"
                 onClick={this.handleRenameRunClick}
               >
                 Rename
               </MenuItem>
             </Dropdown.Menu>
          </Dropdown>
          <RenameRunModal
            runUuid={this.props.runUuid}
            experimentId={this.props.experimentId}
            onClose={this.hideRenameRunModal}
            runName={this.props.runName}
            open={this.state.showRunRenameModal} />

            Date:
            {startTime}

            Run ID:
            {run.getRunUuid()}

            Source:

              {Utils.renderSourceTypeIcon(run.source_type)}
              {Utils.renderSource(run, tags)}

          {run.source_version ?

              Git Commit:
              {Utils.renderVersion(run, false)}

            : null
          }
          {run.source_type === "PROJECT" ?

              Entry Point:
              {run.entry_point_name || "main"}

            : null
          }

            User:
            {run.getUserId()}

          {duration !== null ?

              Duration:
              {Utils.formatDuration(duration)}

            : null
          }
          {tags['mlflow.parentRunId'] !== undefined ?

              Parent Run:

                <Link to={Routes.getRunPageRoute(this.props.experimentId,
                    tags['mlflow.parentRunId'].value)}>
                  {tags['mlflow.parentRunId'].value}
                </Link>

            : null
          }
          {tags['mlflow.databricks.runURL'] !== undefined ?

              Job Output:

                Logs

            : null
          }

        {runCommand ?

Run Command

            <textarea className="run-command text-area" readOnly value={runCommand}/>

          : null
        }

             this.onClickExpander(NOTES_KEY)}
              className="RunView-notes-headline">
              <i className={`fa ${this.getExpanderClassName(NOTES_KEY)}`}/>{' '}Notes

            {!this.state.showNotes || !this.state.showNotesEditor ?
              {' '}

                  <i className={`fa fa-edit`}/>

              :
              null
            }

          {this.renderNoteSection(noteInfo)}

 this.onClickExpander(PARAMETERS_KEY)} className="table-name">
            <i className={`fa ${this.getExpanderClassName(PARAMETERS_KEY)}`}/>
            {' '}Parameters

          {this.state.showParameters ?
            <HtmlTableView
              columns={["Name", "Value"]}
              values={getParamValues(params)}
              styles={tableStyles}
            /> :
            null
          }

 this.onClickExpander(METRICS_KEY)} className="table-name">
            <i className={`fa ${this.getExpanderClassName(METRICS_KEY)}`}/>
            {' '}Metrics

          {this.state.showMetrics ?
            <HtmlTableView
              columns={["Name", "Value"]}
              values={getMetricValues(latestMetrics, getMetricPagePath)}
              styles={tableStyles}
            /> :
            null
          }

 this.onClickExpander(TAGS_KEY)} className="table-name">
            <i className={`fa ${this.getExpanderClassName(TAGS_KEY)}`}/>
            {' '}Tags

          {this.state.showTags ?
            <HtmlTableView
              columns={["Name", "Value"]}
              values={getVisibleTagValues(tags)}
              styles={tableStyles}
            /> :
            null
          }

 this.onClickExpander(ARTIFACTS_KEY)} className="table-name">
              <i className={`fa ${this.getExpanderClassName(ARTIFACTS_KEY)}`}/>
              {' '}Artifacts

            {this.state.showArtifacts ?
              <ArtifactPage runUuid={this.props.runUuid} isHydrated/> :
              null
            }

    );
  }

  handleSubmittedNote(err) {
    if (err) {
      // Do nothing; error is handled by the note editor view
    } else {
      // Successfully submitted note, close the editor
      this.setState({ showNotesEditor: false });
    }
  }
}

const mapStateToProps = (state, ownProps) => {
  const { runUuid, experimentId } = ownProps;
  const run = getRunInfo(runUuid, state);
  const experiment = getExperiment(experimentId, state);
  const params = getParams(runUuid, state);
  const tags = getRunTags(runUuid, state);
  const latestMetrics = getLatestMetrics(runUuid, state);
  const runDisplayName = Utils.getRunDisplayName(tags, runUuid);
  const runName = Utils.getRunName(tags, runUuid);
  return { run, experiment, params, tags, latestMetrics, runDisplayName, runName};
};

export default connect(mapStateToProps)(RunView);

// Private helper functions.

const getParamValues = (params) => {
  return Object.values(params).sort().map((p) =>
    [p.getKey(), p.getValue()]
  );
};

const getVisibleTagValues = (tags) => {
  // Collate tag objects into list of [key, value] lists and filter MLflow-internal tags
  return Object.values(tags).map((t) =>
    [t.getKey(), t.getValue()]
  ).filter(t =>
    !t[0].startsWith(MLFLOW_INTERNAL_PREFIX)
  );
};

const getMetricValues = (latestMetrics, getMetricPagePath) => {
  return Object.values(latestMetrics).sort().map((m) => {
    const key = m.key;
    return [
      <Link to={getMetricPagePath(key)} title="Plot chart">
        {key}

      </Link>,
      Utils.formatMetric(m.value)
    ];
  });
};

const shellEscape = (str) => {
  if (/["\r\n\t ]/.test(str)) {
    return '"' + str.replace(/"/g, '\\"') + '"';
  }
  return str;
};
<commit_msg>Make job logs link open in new window (#939)<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { getExperiment, getParams, getRunInfo, getRunTags } from '../reducers/Reducers';
import { connect } from 'react-redux';
import './RunView.css';
import HtmlTableView from './HtmlTableView';
import { Link } from 'react-router-dom';
import Routes from '../Routes';
import { Dropdown, MenuItem } from 'react-bootstrap';
import ArtifactPage from './ArtifactPage';
import { getLatestMetrics } from '../reducers/MetricReducer';
import { Experiment } from '../sdk/MlflowMessages';
import Utils from '../utils/Utils';
import { MLFLOW_INTERNAL_PREFIX } from "../utils/TagUtils";
import { NoteInfo } from "../utils/NoteUtils";
import BreadcrumbTitle from "./BreadcrumbTitle";
import RenameRunModal from "./modals/RenameRunModal";
import NoteEditorView from "./NoteEditorView";
import NoteShowView from "./NoteShowView";

const NOTES_KEY = 'notes';
const PARAMETERS_KEY = 'parameters';
const METRICS_KEY = 'metrics';
const ARTIFACTS_KEY = 'artifacts';
const TAGS_KEY = 'tags';

class RunView extends Component {
  constructor(props) {
    super(props);
    this.onClickExpander = this.onClickExpander.bind(this);
    this.getExpanderClassName = this.getExpanderClassName.bind(this);
    this.handleRenameRunClick = this.handleRenameRunClick.bind(this);
    this.hideRenameRunModal = this.hideRenameRunModal.bind(this);
    this.handleExposeNotesEditorClick = this.handleExposeNotesEditorClick.bind(this);
    this.handleSubmittedNote = this.handleSubmittedNote.bind(this);
    this.handleNoteEditorViewCancel = this.handleNoteEditorViewCancel.bind(this);
    this.renderNoteSection = this.renderNoteSection.bind(this);
    this.state.showTags = getVisibleTagValues(props.tags).length > 0;
  }

  static propTypes = {
    runUuid: PropTypes.string.isRequired,
    run: PropTypes.object.isRequired,
    experiment: PropTypes.instanceOf(Experiment).isRequired,
    experimentId: PropTypes.number.isRequired,
    params: PropTypes.object.isRequired,
    tags: PropTypes.object.isRequired,
    latestMetrics: PropTypes.object.isRequired,
    getMetricPagePath: PropTypes.func.isRequired,
    runDisplayName: PropTypes.string.isRequired,
    runName: PropTypes.string.isRequired,
  };

  state = {
    showNotesEditor: false,
    showNotes: true,
    showParameters: true,
    showMetrics: true,
    showArtifacts: true,
    showTags: true,
    showRunRenameModal: false,
  };

  onClickExpander(key) {
    switch (key) {
      case NOTES_KEY: {
        this.setState({ showNotes: !this.state.showNotes });
        return;
      }
      case PARAMETERS_KEY: {
        this.setState({ showParameters: !this.state.showParameters });
        return;
      }
      case METRICS_KEY: {
        this.setState({ showMetrics: !this.state.showMetrics });
        return;
      }
      case TAGS_KEY: {
        this.setState({ showTags: !this.state.showTags });
        return;
      }
      case ARTIFACTS_KEY: {
        this.setState({ showArtifacts: !this.state.showArtifacts });
        return;
      }
      default:
    }
  }

  getExpanderClassName(key) {
    switch (key) {
      case NOTES_KEY: {
        return this.state.showNotes ? 'fa-caret-down' : 'fa-caret-right';
      }
      case PARAMETERS_KEY: {
        return this.state.showParameters ? 'fa-caret-down' : 'fa-caret-right';
      }
      case METRICS_KEY: {
        return this.state.showMetrics ? 'fa-caret-down' : 'fa-caret-right';
      }
      case TAGS_KEY: {
        return this.state.showTags ? 'fa-caret-down' : 'fa-caret-right';
      }
      case ARTIFACTS_KEY: {
        return this.state.showArtifacts ? 'fa-caret-down' : 'fa-caret-right';
      }
      default: {
        return null;
      }
    }
  }

  handleExposeNotesEditorClick() {
    this.setState({ showNotesEditor: true, showNotes: true });
  }

  handleNoteEditorViewCancel() {
    this.setState({ showNotesEditor: false });
  }

  handleRenameRunClick() {
    this.setState({ showRunRenameModal: true });
  }

  hideRenameRunModal() {
    this.setState({ showRunRenameModal: false });
  }

  renderNoteSection(noteInfo) {
    if (this.state.showNotes) {
      if (this.state.showNotesEditor) {
        return <NoteEditorView
            runUuid={this.props.runUuid}
            noteInfo={noteInfo}
            submitCallback={this.handleSubmittedNote}
            cancelCallback={this.handleNoteEditorViewCancel}/>;
      } else if (noteInfo) {
        return <NoteShowView content={noteInfo.content}/>;
      } else {
        return None;
      }
    }
    return null;
  }

  getRunCommand() {
    const { run, params } = this.props;
    let runCommand = null;
    if (run.source_type === "PROJECT") {
      runCommand = 'mlflow run ' + shellEscape(run.source_name);
      if (run.source_version && run.source_version !== "latest") {
        runCommand += ' -v ' + shellEscape(run.source_version);
      }
      if (run.entry_point_name && run.entry_point_name !== "main") {
        runCommand += ' -e ' + shellEscape(run.entry_point_name);
      }
      Object.values(params).sort().forEach(p => {
        runCommand += ' -P ' + shellEscape(p.key + '=' + p.value);
      });
    }
    return runCommand;
  }

  render() {
    const { run, params, tags, latestMetrics, getMetricPagePath } = this.props;
    const noteInfo = NoteInfo.fromRunTags(tags);
    const startTime = run.getStartTime() ? Utils.formatTimestamp(run.getStartTime()) : '(unknown)';
    const duration =
      run.getStartTime() && run.getEndTime() ? run.getEndTime() - run.getStartTime() : null;
    const tableStyles = {
      table: {
        width: 'auto',
        minWidth: '400px',
      },
      th: {
        width: 'auto',
        minWidth: '200px',
        marginRight: '80px',
      }
    };
    const runCommand = this.getRunCommand();
    return (

          <BreadcrumbTitle
            experiment={this.props.experiment}
            title={this.props.runDisplayName}
          />
          <Dropdown id="dropdown-custom-1" className="mlflow-dropdown">
             <Dropdown.Toggle noCaret className="mlflow-dropdown-button">

             </Dropdown.Toggle>
             <Dropdown.Menu className="mlflow-menu header-menu">
               <MenuItem
                 className="mlflow-menu-item"
                 onClick={this.handleRenameRunClick}
               >
                 Rename
               </MenuItem>
             </Dropdown.Menu>
          </Dropdown>
          <RenameRunModal
            runUuid={this.props.runUuid}
            experimentId={this.props.experimentId}
            onClose={this.hideRenameRunModal}
            runName={this.props.runName}
            open={this.state.showRunRenameModal} />

            Date:
            {startTime}

            Run ID:
            {run.getRunUuid()}

            Source:

              {Utils.renderSourceTypeIcon(run.source_type)}
              {Utils.renderSource(run, tags)}

          {run.source_version ?

              Git Commit:
              {Utils.renderVersion(run, false)}

            : null
          }
          {run.source_type === "PROJECT" ?

              Entry Point:
              {run.entry_point_name || "main"}

            : null
          }

            User:
            {run.getUserId()}

          {duration !== null ?

              Duration:
              {Utils.formatDuration(duration)}

            : null
          }
          {tags['mlflow.parentRunId'] !== undefined ?

              Parent Run:

                <Link to={Routes.getRunPageRoute(this.props.experimentId,
                    tags['mlflow.parentRunId'].value)}>
                  {tags['mlflow.parentRunId'].value}
                </Link>

            : null
          }
          {tags['mlflow.databricks.runURL'] !== undefined ?

              Job Output:

                Logs

            : null
          }

        {runCommand ?

Run Command

            <textarea className="run-command text-area" readOnly value={runCommand}/>

          : null
        }

             this.onClickExpander(NOTES_KEY)}
              className="RunView-notes-headline">
              <i className={`fa ${this.getExpanderClassName(NOTES_KEY)}`}/>{' '}Notes

            {!this.state.showNotes || !this.state.showNotesEditor ?
              {' '}

                  <i className={`fa fa-edit`}/>

              :
              null
            }

          {this.renderNoteSection(noteInfo)}

 this.onClickExpander(PARAMETERS_KEY)} className="table-name">
            <i className={`fa ${this.getExpanderClassName(PARAMETERS_KEY)}`}/>
            {' '}Parameters

          {this.state.showParameters ?
            <HtmlTableView
              columns={["Name", "Value"]}
              values={getParamValues(params)}
              styles={tableStyles}
            /> :
            null
          }

 this.onClickExpander(METRICS_KEY)} className="table-name">
            <i className={`fa ${this.getExpanderClassName(METRICS_KEY)}`}/>
            {' '}Metrics

          {this.state.showMetrics ?
            <HtmlTableView
              columns={["Name", "Value"]}
              values={getMetricValues(latestMetrics, getMetricPagePath)}
              styles={tableStyles}
            /> :
            null
          }

 this.onClickExpander(TAGS_KEY)} className="table-name">
            <i className={`fa ${this.getExpanderClassName(TAGS_KEY)}`}/>
            {' '}Tags

          {this.state.showTags ?
            <HtmlTableView
              columns={["Name", "Value"]}
              values={getVisibleTagValues(tags)}
              styles={tableStyles}
            /> :
            null
          }

 this.onClickExpander(ARTIFACTS_KEY)} className="table-name">
              <i className={`fa ${this.getExpanderClassName(ARTIFACTS_KEY)}`}/>
              {' '}Artifacts

            {this.state.showArtifacts ?
              <ArtifactPage runUuid={this.props.runUuid} isHydrated/> :
              null
            }

    );
  }

  handleSubmittedNote(err) {
    if (err) {
      // Do nothing; error is handled by the note editor view
    } else {
      // Successfully submitted note, close the editor
      this.setState({ showNotesEditor: false });
    }
  }
}

const mapStateToProps = (state, ownProps) => {
  const { runUuid, experimentId } = ownProps;
  const run = getRunInfo(runUuid, state);
  const experiment = getExperiment(experimentId, state);
  const params = getParams(runUuid, state);
  const tags = getRunTags(runUuid, state);
  const latestMetrics = getLatestMetrics(runUuid, state);
  const runDisplayName = Utils.getRunDisplayName(tags, runUuid);
  const runName = Utils.getRunName(tags, runUuid);
  return { run, experiment, params, tags, latestMetrics, runDisplayName, runName};
};

export default connect(mapStateToProps)(RunView);

// Private helper functions.

const getParamValues = (params) => {
  return Object.values(params).sort().map((p) =>
    [p.getKey(), p.getValue()]
  );
};

const getVisibleTagValues = (tags) => {
  // Collate tag objects into list of [key, value] lists and filter MLflow-internal tags
  return Object.values(tags).map((t) =>
    [t.getKey(), t.getValue()]
  ).filter(t =>
    !t[0].startsWith(MLFLOW_INTERNAL_PREFIX)
  );
};

const getMetricValues = (latestMetrics, getMetricPagePath) => {
  return Object.values(latestMetrics).sort().map((m) => {
    const key = m.key;
    return [
      <Link to={getMetricPagePath(key)} title="Plot chart">
        {key}

      </Link>,
      Utils.formatMetric(m.value)
    ];
  });
};

const shellEscape = (str) => {
  if (/["\r\n\t ]/.test(str)) {
    return '"' + str.replace(/"/g, '\\"') + '"';
  }
  return str;
};
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Crypto from 'utils/crypto'
import { connect as connectSocket } from 'utils/socket'
import Nav from 'components/Nav'
import shortId from 'shortid'
import ChatInput from 'components/Chat'
import Connecting from 'components/Connecting'
import Message from 'components/Message'
import Username from 'components/Username'
import Notice from 'components/Notice'
import Modal from 'react-modal'
import About from 'components/About'
import Settings from 'components/Settings'
import Welcome from 'components/Welcome'
import RoomLocked from 'components/RoomLocked'
import { X, AlertCircle } from 'react-feather'
import { defer } from 'lodash'
import Tinycon from 'tinycon'
import beepFile from 'audio/beep.mp3'
import Zoom from 'utils/ImageZoom'
import classNames from 'classnames'
import { getObjectUrl } from 'utils/file'
import { connect } from 'react-redux'
import {
  receiveEncryptedMessage,
  createUser,
  openModal,
  closeModal,
  setScrolledToBottom,
  toggleWindowFocus,
  toggleSoundEnabled,
  toggleSocketConnected,
  receiveUnencryptedMessage,
  sendUnencryptedMessage,
  sendEncryptedMessage,
  setLanguage
} from 'actions'
import T from 'components/T'

import styles from './styles.module.scss'

const crypto = new Crypto()

Modal.setAppElement('#root');

class Home extends Component {
  constructor(props) {
    super(props)

    this.state = {
      zoomableImages: [],
      focusChat: false,
    }

    this.hasConnected = false
  }

  async componentWillMount() {
    const roomId = encodeURI(this.props.match.params.roomId)

    const user = await this.createUser()

    const socket = connectSocket(roomId)

    this.socket = socket;

    socket.on('disconnect', () => {
      this.props.toggleSocketConnected(false)
    })

    socket.on('connect', () => {
      this.initApp(user)
      this.props.toggleSocketConnected(true)
    })

    socket.on('USER_ENTER', (payload) => {
      this.props.receiveUnencryptedMessage('USER_ENTER', payload)
      this.props.sendEncryptedMessage({
        type: 'ADD_USER',
        payload: {
          username: this.props.username,
          publicKey: this.props.publicKey,
          isOwner: this.props.iAmOwner,
          id: this.props.userId,
        },
      })
      if (payload.users.length === 1) {
        this.props.openModal('Welcome');
      }
    })

    socket.on('USER_EXIT', (payload) => {
      this.props.receiveUnencryptedMessage('USER_EXIT', payload)
    })

    socket.on('ENCRYPTED_MESSAGE', (payload) => {
      this.props.receiveEncryptedMessage(payload)
    })

    socket.on('TOGGLE_LOCK_ROOM', (payload) => {
      this.props.receiveUnencryptedMessage('TOGGLE_LOCK_ROOM', payload)
    })

    socket.on('ROOM_LOCKED', (payload) => {
      this.props.openModal('Room Locked')
    });

    window.addEventListener('beforeunload', (evt) => {
      socket.emit('USER_DISCONNECT')
    });
  }

  componentDidMount() {
    this.bindEvents()

    this.beep = window.Audio && new window.Audio(beepFile)
  }

  componentWillReceiveProps(nextProps) {
    Tinycon.setBubble(nextProps.faviconCount)

    if (nextProps.faviconCount !== 0 && nextProps.faviconCount !== this.props.faviconCount && this.props.soundIsEnabled) {
      this.beep.play()
    }
  }

  componentDidUpdate(prevProps) {
    if (prevProps.activities.length < this.props.activities.length) {
      this.scrollToBottomIfShould()
    }
  }

  onScroll() {
    const messageStreamHeight = this.messageStream.clientHeight
    const activitiesListHeight = this.activitiesList.clientHeight

    const bodyRect = document.body.getBoundingClientRect()
    const elemRect = this.activitiesList.getBoundingClientRect()
    const offset = elemRect.top - bodyRect.top
    const activitiesListYPos = offset

    const scrolledToBottom = (activitiesListHeight + (activitiesListYPos - 60)) <= messageStreamHeight
    if (scrolledToBottom) {
      if (!this.props.scrolledToBottom) {
        this.props.setScrolledToBottom(true)
      }
    } else if (this.props.scrolledToBottom) {
      this.props.setScrolledToBottom(false)
    }
  }

  getFileDisplay(activity) {
    const type = activity.fileType
    if (type.match('image.*')) {
      return (
         this._zoomableImage = c}
          className="image-transfer zoomable"
          src={`data:${activity.fileType};base64,${activity.encodedFile}`}
          alt={`${activity.fileName} from ${activity.username}`}
          onLoad={this.handleImageDisplay.bind(this)}
        />
      )
    }
    return null
  }

  getActivityComponent(activity) {
    switch (activity.type) {
      case 'TEXT_MESSAGE':
        return (
          <Message
            sender={activity.username}
            message={activity.text}
            timestamp={activity.timestamp}
          />
        )
      case 'USER_ENTER':
        return (
          <Notice>

              <T data={{
                username: <Username key={0} username={activity.username} />
              }} path='userJoined'/>

          </Notice>
        )
      case 'USER_EXIT':
        return (
          <Notice>

              <T data={{
                username: <Username key={0} username={activity.username} />
              }} path='userLeft'/>

          </Notice>
        )
      case 'TOGGLE_LOCK_ROOM':
        if (activity.locked) {
          return (
            <Notice>

<T data={{
                username: <Username key={0} username={activity.username} />
              }} path='lockedRoom'/>

            </Notice>
          )
        } else {
          return (
            <Notice>

<T data={{
                username: <Username key={0} username={activity.username} />
              }} path='unlockedRoom'/>

            </Notice>
          )
        }
      case 'NOTICE':
        return (
          <Notice>

{activity.message}

          </Notice>
        )
      case 'CHANGE_USERNAME':
        return (
          <Notice>

<T data={{
              oldUsername: <Username key={0} username={activity.currentUsername} />,
              newUsername: <Username key={1} username={activity.newUsername} />
            }} path='nameChange'/>

          </Notice>
        )
      case 'USER_ACTION':
        return (
          <Notice>

* <Username username={activity.username} /> {activity.action}

          </Notice>
        )
      case 'RECEIVE_FILE':
        const downloadUrl = getObjectUrl(activity.encodedFile, activity.fileType)
        return (

            <T data={{
              username: <Username key={0} username={activity.username} />,
            }} path='userSentFile'/>

              <T data={{
                filename: activity.fileName,
              }} path='downloadFile'/>

            {this.getFileDisplay(activity)}

        )
      case 'SEND_FILE':
        const url = getObjectUrl(activity.encodedFile, activity.fileType)
        return (
          <Notice>

              <T data={{
                filename: {activity.fileName},
              }} path='sentFile'/>

            {this.getFileDisplay(activity)}
          </Notice>
        )
      default:
        return false
    }
  }

  getModal() {
    switch (this.props.modalComponent) {
      case 'Connecting':
        return {
          component: <Connecting />,
          title: 'Connecting...',
          preventClose: true,
        }
      case 'About':
        return {
          component: <About roomId={this.props.roomId} />,
          title: this.props.translations.aboutHeader,
        }
      case 'Settings':
        return {
          component: <Settings roomId={this.props.roomId} toggleSoundEnabled={this.props.toggleSoundEnabled} soundIsEnabled={this.props.soundIsEnabled} setLanguage={this.props.setLanguage} language={this.props.language} translations={this.props.translations} />,
          title: this.props.translations.settingsHeader,
        }
      case 'Welcome':
        return {
          component: <Welcome roomId={this.props.roomId} close={this.props.closeModal} translations={this.props.translations} />,
          title: this.props.translations.welcomeHeader,
        }
      case 'Room Locked':
        return {
          component: <RoomLocked modalContent={this.props.translations.lockedRoomHeader} />,
          title: this.props.translations.lockedRoomHeader,
          preventClose: true,
        }
      default:
        return {
          component: null,
          title: null,
        }
    }
  }

  initApp(user) {
    this.socket.emit('USER_ENTER', {
      publicKey: user.publicKey,
    })
  }

  handleImageDisplay() {
    Zoom(this._zoomableImage)
    this.scrollToBottomIfShould()
  }

  scrollToBottomIfShould() {
    if (this.props.scrolledToBottom) {
      setTimeout(() => {
        this.messageStream.scrollTop = this.messageStream.scrollHeight
      }, 0)
    }
  }

  scrollToBottom() {
    this.messageStream.scrollTop = this.messageStream.scrollHeight
    this.props.setScrolledToBottom(true)
  }

  bindEvents() {
    this.messageStream.addEventListener('scroll', this.onScroll.bind(this))

    window.onfocus = () => {
      this.props.toggleWindowFocus(true)
    }

    window.onblur = () => {
      this.props.toggleWindowFocus(false)
    }
  }

  createUser() {
    return new Promise(async (resolve) => {
      const username = shortId.generate()

      const encryptDecryptKeys = await crypto.createEncryptDecryptKeys()
      const exportedEncryptDecryptPrivateKey = await crypto.exportKey(encryptDecryptKeys.privateKey)
      const exportedEncryptDecryptPublicKey = await crypto.exportKey(encryptDecryptKeys.publicKey)

      this.props.createUser({
        username,
        publicKey: exportedEncryptDecryptPublicKey,
        privateKey: exportedEncryptDecryptPrivateKey,
      })

      resolve({
        publicKey: exportedEncryptDecryptPublicKey,
      })
    })
  }

  handleChatClick() {
    this.setState({ focusChat: true })
    defer(() => this.setState({ focusChat: false }))
  }

  render() {
    const modalOpts = this.getModal()
    return (

          {!this.props.socketConnected &&

              <AlertCircle size="15" /> Disconnected

          }
           this.props.sendUnencryptedMessage('TOGGLE_LOCK_ROOM')}
            openModal={this.props.openModal}
            iAmOwner={this.props.iAmOwner}
            userId={this.props.userId}
            translations={this.props.translations}
          />

 this.messageStream = el}>

 this.activitiesList = el}>

<button className='btn btn-link' onClick={this.props.openModal.bind(this, 'About')}> <T path='agreement'/></button>

              {this.props.activities.map((activity, index) => (
                <li key={index} className={`activity-item ${activity.type}`}>
                  {this.getActivityComponent(activity)}

              ))}

            <ChatInput scrollToBottom={this.scrollToBottom.bind(this)} focusChat={this.state.focusChat} />

        <Modal
          isOpen={Boolean(this.props.modalComponent)}
          contentLabel="Modal"
          style={{ overlay: { zIndex: 10 } }}
          className={{
            base: 'react-modal-content',
            afterOpen: 'react-modal-content_after-open',
            beforeClose: 'react-modal-content_before-close',
          }}
          overlayClassName={{
            base: 'react-modal-overlay',
            afterOpen: 'react-modal-overlay_after-open',
            beforeClose: 'react-modal-overlay_before-close',
          }}
          shouldCloseOnOverlayClick={!modalOpts.preventClose}
          onRequestClose={this.props.closeModal}
        >

            {!modalOpts.preventClose &&
              <button onClick={this.props.closeModal} className="btn btn-link btn-plain close-modal">
                <X />
              </button>
            }

              {modalOpts.title}

            {modalOpts.component}

        </Modal>

    )
  }
}

Home.defaultProps = {
  modalComponent: null,
}

Home.propTypes = {
  receiveEncryptedMessage: PropTypes.func.isRequired,
  createUser: PropTypes.func.isRequired,
  activities: PropTypes.array.isRequired,
  username: PropTypes.string.isRequired,
  publicKey: PropTypes.object.isRequired,
  members: PropTypes.array.isRequired,
  match: PropTypes.object.isRequired,
  roomId: PropTypes.string.isRequired,
  roomLocked: PropTypes.bool.isRequired,
  modalComponent: PropTypes.string,
  openModal: PropTypes.func.isRequired,
  closeModal: PropTypes.func.isRequired,
  setScrolledToBottom: PropTypes.func.isRequired,
  scrolledToBottom: PropTypes.bool.isRequired,
  iAmOwner: PropTypes.bool.isRequired,
  userId: PropTypes.string.isRequired,
  toggleWindowFocus: PropTypes.func.isRequired,
  faviconCount: PropTypes.number.isRequired,
  soundIsEnabled: PropTypes.bool.isRequired,
  toggleSoundEnabled: PropTypes.func.isRequired,
  toggleSocketConnected: PropTypes.func.isRequired,
  socketConnected: PropTypes.bool.isRequired,
  sendUnencryptedMessage: PropTypes.func.isRequired,
  sendEncryptedMessage: PropTypes.func.isRequired
}

const mapStateToProps = (state) => {
  const me = state.room.members.find(m => m.id === state.user.id)

  return {
    activities: state.activities.items,
    userId: state.user.id,
    username: state.user.username,
    publicKey: state.user.publicKey,
    privateKey: state.user.privateKey,
    members: state.room.members.filter(m => m.username && m.publicKey),
    roomId: state.room.id,
    roomLocked: state.room.isLocked,
    modalComponent: state.app.modalComponent,
    scrolledToBottom: state.app.scrolledToBottom,
    iAmOwner: Boolean(me && me.isOwner),
    faviconCount: state.app.unreadMessageCount,
    soundIsEnabled: state.app.soundIsEnabled,
    socketConnected: state.app.socketConnected,
    language: state.app.language,
    translations: state.app.translations,
  }
}

const mapDispatchToProps = {
  receiveEncryptedMessage,
  createUser,
  openModal,
  closeModal,
  setScrolledToBottom,
  toggleWindowFocus,
  toggleSoundEnabled,
  toggleSocketConnected,
  receiveUnencryptedMessage,
  sendUnencryptedMessage,
  sendEncryptedMessage,
  setLanguage
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Home)
<commit_msg>Fix download links (#140)<commit_after>import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Crypto from 'utils/crypto'
import { connect as connectSocket } from 'utils/socket'
import Nav from 'components/Nav'
import shortId from 'shortid'
import ChatInput from 'components/Chat'
import Connecting from 'components/Connecting'
import Message from 'components/Message'
import Username from 'components/Username'
import Notice from 'components/Notice'
import Modal from 'react-modal'
import About from 'components/About'
import Settings from 'components/Settings'
import Welcome from 'components/Welcome'
import RoomLocked from 'components/RoomLocked'
import { X, AlertCircle } from 'react-feather'
import { defer } from 'lodash'
import Tinycon from 'tinycon'
import beepFile from 'audio/beep.mp3'
import Zoom from 'utils/ImageZoom'
import classNames from 'classnames'
import { getObjectUrl } from 'utils/file'
import { connect } from 'react-redux'
import {
  receiveEncryptedMessage,
  createUser,
  openModal,
  closeModal,
  setScrolledToBottom,
  toggleWindowFocus,
  toggleSoundEnabled,
  toggleSocketConnected,
  receiveUnencryptedMessage,
  sendUnencryptedMessage,
  sendEncryptedMessage,
  setLanguage
} from 'actions'
import T from 'components/T'

import styles from './styles.module.scss'

const crypto = new Crypto()

Modal.setAppElement('#root');

class Home extends Component {
  constructor(props) {
    super(props)

    this.state = {
      zoomableImages: [],
      focusChat: false,
    }

    this.hasConnected = false
  }

  async componentWillMount() {
    const roomId = encodeURI(this.props.match.params.roomId)

    const user = await this.createUser()

    const socket = connectSocket(roomId)

    this.socket = socket;

    socket.on('disconnect', () => {
      this.props.toggleSocketConnected(false)
    })

    socket.on('connect', () => {
      this.initApp(user)
      this.props.toggleSocketConnected(true)
    })

    socket.on('USER_ENTER', (payload) => {
      this.props.receiveUnencryptedMessage('USER_ENTER', payload)
      this.props.sendEncryptedMessage({
        type: 'ADD_USER',
        payload: {
          username: this.props.username,
          publicKey: this.props.publicKey,
          isOwner: this.props.iAmOwner,
          id: this.props.userId,
        },
      })
      if (payload.users.length === 1) {
        this.props.openModal('Welcome');
      }
    })

    socket.on('USER_EXIT', (payload) => {
      this.props.receiveUnencryptedMessage('USER_EXIT', payload)
    })

    socket.on('ENCRYPTED_MESSAGE', (payload) => {
      this.props.receiveEncryptedMessage(payload)
    })

    socket.on('TOGGLE_LOCK_ROOM', (payload) => {
      this.props.receiveUnencryptedMessage('TOGGLE_LOCK_ROOM', payload)
    })

    socket.on('ROOM_LOCKED', (payload) => {
      this.props.openModal('Room Locked')
    });

    window.addEventListener('beforeunload', (evt) => {
      socket.emit('USER_DISCONNECT')
    });
  }

  componentDidMount() {
    this.bindEvents()

    this.beep = window.Audio && new window.Audio(beepFile)
  }

  componentWillReceiveProps(nextProps) {
    Tinycon.setBubble(nextProps.faviconCount)

    if (nextProps.faviconCount !== 0 && nextProps.faviconCount !== this.props.faviconCount && this.props.soundIsEnabled) {
      this.beep.play()
    }
  }

  componentDidUpdate(prevProps) {
    if (prevProps.activities.length < this.props.activities.length) {
      this.scrollToBottomIfShould()
    }
  }

  onScroll() {
    const messageStreamHeight = this.messageStream.clientHeight
    const activitiesListHeight = this.activitiesList.clientHeight

    const bodyRect = document.body.getBoundingClientRect()
    const elemRect = this.activitiesList.getBoundingClientRect()
    const offset = elemRect.top - bodyRect.top
    const activitiesListYPos = offset

    const scrolledToBottom = (activitiesListHeight + (activitiesListYPos - 60)) <= messageStreamHeight
    if (scrolledToBottom) {
      if (!this.props.scrolledToBottom) {
        this.props.setScrolledToBottom(true)
      }
    } else if (this.props.scrolledToBottom) {
      this.props.setScrolledToBottom(false)
    }
  }

  getFileDisplay(activity) {
    const type = activity.fileType
    if (type.match('image.*')) {
      return (
         this._zoomableImage = c}
          className="image-transfer zoomable"
          src={`data:${activity.fileType};base64,${activity.encodedFile}`}
          alt={`${activity.fileName} from ${activity.username}`}
          onLoad={this.handleImageDisplay.bind(this)}
        />
      )
    }
    return null
  }

  getActivityComponent(activity) {
    switch (activity.type) {
      case 'TEXT_MESSAGE':
        return (
          <Message
            sender={activity.username}
            message={activity.text}
            timestamp={activity.timestamp}
          />
        )
      case 'USER_ENTER':
        return (
          <Notice>

              <T data={{
                username: <Username key={0} username={activity.username} />
              }} path='userJoined'/>

          </Notice>
        )
      case 'USER_EXIT':
        return (
          <Notice>

              <T data={{
                username: <Username key={0} username={activity.username} />
              }} path='userLeft'/>

          </Notice>
        )
      case 'TOGGLE_LOCK_ROOM':
        if (activity.locked) {
          return (
            <Notice>

<T data={{
                username: <Username key={0} username={activity.username} />
              }} path='lockedRoom'/>

            </Notice>
          )
        } else {
          return (
            <Notice>

<T data={{
                username: <Username key={0} username={activity.username} />
              }} path='unlockedRoom'/>

            </Notice>
          )
        }
      case 'NOTICE':
        return (
          <Notice>

{activity.message}

          </Notice>
        )
      case 'CHANGE_USERNAME':
        return (
          <Notice>

<T data={{
              oldUsername: <Username key={0} username={activity.currentUsername} />,
              newUsername: <Username key={1} username={activity.newUsername} />
            }} path='nameChange'/>

          </Notice>
        )
      case 'USER_ACTION':
        return (
          <Notice>

* <Username username={activity.username} /> {activity.action}

          </Notice>
        )
      case 'RECEIVE_FILE':
        const downloadUrl = getObjectUrl(activity.encodedFile, activity.fileType)
        return (

            <T data={{
              username: <Username key={0} username={activity.username} />,
            }} path='userSentFile'/>

              <T data={{
                filename: activity.fileName,
              }} path='downloadFile'/>

            {this.getFileDisplay(activity)}

        )
      case 'SEND_FILE':
        const url = getObjectUrl(activity.encodedFile, activity.fileType)
        return (
          <Notice>

              <T data={{
                filename: {activity.fileName},
              }} path='sentFile'/>

            {this.getFileDisplay(activity)}
          </Notice>
        )
      default:
        return false
    }
  }

  getModal() {
    switch (this.props.modalComponent) {
      case 'Connecting':
        return {
          component: <Connecting />,
          title: 'Connecting...',
          preventClose: true,
        }
      case 'About':
        return {
          component: <About roomId={this.props.roomId} />,
          title: this.props.translations.aboutHeader,
        }
      case 'Settings':
        return {
          component: <Settings roomId={this.props.roomId} toggleSoundEnabled={this.props.toggleSoundEnabled} soundIsEnabled={this.props.soundIsEnabled} setLanguage={this.props.setLanguage} language={this.props.language} translations={this.props.translations} />,
          title: this.props.translations.settingsHeader,
        }
      case 'Welcome':
        return {
          component: <Welcome roomId={this.props.roomId} close={this.props.closeModal} translations={this.props.translations} />,
          title: this.props.translations.welcomeHeader,
        }
      case 'Room Locked':
        return {
          component: <RoomLocked modalContent={this.props.translations.lockedRoomHeader} />,
          title: this.props.translations.lockedRoomHeader,
          preventClose: true,
        }
      default:
        return {
          component: null,
          title: null,
        }
    }
  }

  initApp(user) {
    this.socket.emit('USER_ENTER', {
      publicKey: user.publicKey,
    })
  }

  handleImageDisplay() {
    Zoom(this._zoomableImage)
    this.scrollToBottomIfShould()
  }

  scrollToBottomIfShould() {
    if (this.props.scrolledToBottom) {
      setTimeout(() => {
        this.messageStream.scrollTop = this.messageStream.scrollHeight
      }, 0)
    }
  }

  scrollToBottom() {
    this.messageStream.scrollTop = this.messageStream.scrollHeight
    this.props.setScrolledToBottom(true)
  }

  bindEvents() {
    this.messageStream.addEventListener('scroll', this.onScroll.bind(this))

    window.onfocus = () => {
      this.props.toggleWindowFocus(true)
    }

    window.onblur = () => {
      this.props.toggleWindowFocus(false)
    }
  }

  createUser() {
    return new Promise(async (resolve) => {
      const username = shortId.generate()

      const encryptDecryptKeys = await crypto.createEncryptDecryptKeys()
      const exportedEncryptDecryptPrivateKey = await crypto.exportKey(encryptDecryptKeys.privateKey)
      const exportedEncryptDecryptPublicKey = await crypto.exportKey(encryptDecryptKeys.publicKey)

      this.props.createUser({
        username,
        publicKey: exportedEncryptDecryptPublicKey,
        privateKey: exportedEncryptDecryptPrivateKey,
      })

      resolve({
        publicKey: exportedEncryptDecryptPublicKey,
      })
    })
  }

  handleChatClick() {
    this.setState({ focusChat: true })
    defer(() => this.setState({ focusChat: false }))
  }

  render() {
    const modalOpts = this.getModal()
    return (

          {!this.props.socketConnected &&

              <AlertCircle size="15" /> Disconnected

          }
           this.props.sendUnencryptedMessage('TOGGLE_LOCK_ROOM')}
            openModal={this.props.openModal}
            iAmOwner={this.props.iAmOwner}
            userId={this.props.userId}
            translations={this.props.translations}
          />

 this.messageStream = el}>

 this.activitiesList = el}>

<button className='btn btn-link' onClick={this.props.openModal.bind(this, 'About')}> <T path='agreement'/></button>

              {this.props.activities.map((activity, index) => (
                <li key={index} className={`activity-item ${activity.type}`}>
                  {this.getActivityComponent(activity)}

              ))}

            <ChatInput scrollToBottom={this.scrollToBottom.bind(this)} focusChat={this.state.focusChat} />

        <Modal
          isOpen={Boolean(this.props.modalComponent)}
          contentLabel="Modal"
          style={{ overlay: { zIndex: 10 } }}
          className={{
            base: 'react-modal-content',
            afterOpen: 'react-modal-content_after-open',
            beforeClose: 'react-modal-content_before-close',
          }}
          overlayClassName={{
            base: 'react-modal-overlay',
            afterOpen: 'react-modal-overlay_after-open',
            beforeClose: 'react-modal-overlay_before-close',
          }}
          shouldCloseOnOverlayClick={!modalOpts.preventClose}
          onRequestClose={this.props.closeModal}
        >

            {!modalOpts.preventClose &&
              <button onClick={this.props.closeModal} className="btn btn-link btn-plain close-modal">
                <X />
              </button>
            }

              {modalOpts.title}

            {modalOpts.component}

        </Modal>

    )
  }
}

Home.defaultProps = {
  modalComponent: null,
}

Home.propTypes = {
  receiveEncryptedMessage: PropTypes.func.isRequired,
  createUser: PropTypes.func.isRequired,
  activities: PropTypes.array.isRequired,
  username: PropTypes.string.isRequired,
  publicKey: PropTypes.object.isRequired,
  members: PropTypes.array.isRequired,
  match: PropTypes.object.isRequired,
  roomId: PropTypes.string.isRequired,
  roomLocked: PropTypes.bool.isRequired,
  modalComponent: PropTypes.string,
  openModal: PropTypes.func.isRequired,
  closeModal: PropTypes.func.isRequired,
  setScrolledToBottom: PropTypes.func.isRequired,
  scrolledToBottom: PropTypes.bool.isRequired,
  iAmOwner: PropTypes.bool.isRequired,
  userId: PropTypes.string.isRequired,
  toggleWindowFocus: PropTypes.func.isRequired,
  faviconCount: PropTypes.number.isRequired,
  soundIsEnabled: PropTypes.bool.isRequired,
  toggleSoundEnabled: PropTypes.func.isRequired,
  toggleSocketConnected: PropTypes.func.isRequired,
  socketConnected: PropTypes.bool.isRequired,
  sendUnencryptedMessage: PropTypes.func.isRequired,
  sendEncryptedMessage: PropTypes.func.isRequired
}

const mapStateToProps = (state) => {
  const me = state.room.members.find(m => m.id === state.user.id)

  return {
    activities: state.activities.items,
    userId: state.user.id,
    username: state.user.username,
    publicKey: state.user.publicKey,
    privateKey: state.user.privateKey,
    members: state.room.members.filter(m => m.username && m.publicKey),
    roomId: state.room.id,
    roomLocked: state.room.isLocked,
    modalComponent: state.app.modalComponent,
    scrolledToBottom: state.app.scrolledToBottom,
    iAmOwner: Boolean(me && me.isOwner),
    faviconCount: state.app.unreadMessageCount,
    soundIsEnabled: state.app.soundIsEnabled,
    socketConnected: state.app.socketConnected,
    language: state.app.language,
    translations: state.app.translations,
  }
}

const mapDispatchToProps = {
  receiveEncryptedMessage,
  createUser,
  openModal,
  closeModal,
  setScrolledToBottom,
  toggleWindowFocus,
  toggleSoundEnabled,
  toggleSocketConnected,
  receiveUnencryptedMessage,
  sendUnencryptedMessage,
  sendEncryptedMessage,
  setLanguage
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Home)
<|endoftext|>


<commit_before>app.factory('localesFactory', function ($http, AuthService){
	return {

		getLocales: function () {
			return AuthService.getLoggedInUser()
				.then(function (user) {
					console.log('user is:', user);
					return $http.get('api/locale?organizers=' + user._id);
				})
				.then(function (res) {
					console.log('locales: ', res.data);
					return res.data;
				});
			},
		getConferences: function (localeId) {
			return $http.get('api/conference?locale=' + localeId).then(function (res) {
				return res.data;
			});
		},
		updateOrganizer: function(localeId, organizerArr, organizerId){

			organizerArr = organizerArr.map(function(organizer){
				return organizer._id;
			});

            organizerArr =  _.uniq(organizerArr);
            console.log('after uniq',organizerArr);
            if(organizerId)
                organizerArr.push(organizerId);
			return $http.put('api/locale/'+localeId,{organizers: organizerArr}).then(function(res){
				return res.data;
			});

		},

		addOrganizer: function(localeId, organizerid){

			// return $http.put('api/locale/'+localeId,{organizers: organizerArr}).then(function(res){
			// 	return res.data;
			// });
		}
 	};
});<commit_msg>removed console logs<commit_after>app.factory('localesFactory', function ($http, AuthService){
	return {

		getLocales: function () {
			return AuthService.getLoggedInUser()
				.then(function (user) {

					return $http.get('api/locale?organizers=' + user._id);
				})
				.then(function (res) {

					return res.data;
				});
			},
		getConferences: function (localeId) {
			return $http.get('api/conference?locale=' + localeId).then(function (res) {
				return res.data;
			});
		},
		updateOrganizer: function(localeId, organizerArr, organizerId){

			organizerArr = organizerArr.map(function(organizer){
				return organizer._id;
			});

            organizerArr =  _.uniq(organizerArr);

            if(organizerId)
                organizerArr.push(organizerId);
			return $http.put('api/locale/'+localeId,{organizers: organizerArr}).then(function(res){
				return res.data;
			});

		},

		addOrganizer: function(localeId, organizerid){

			// return $http.put('api/locale/'+localeId,{organizers: organizerArr}).then(function(res){
			// 	return res.data;
			// });
		}
 	};
});<|endoftext|>


<commit_before>var Butler = new Class({
    _accessors: {
        /*
        key: {
            // The buck stops here for this custom set method.
            // Any returned value goes into the ether because
            // the original set code block is ignored when this is invoked

            set: function(prop, val){},

            // isPrevious flag lets you choose whether to pull data from this._data or this._previousData
            get: function(isPrevious){
                //Example
                var data = isPrevious ? this._data : this._previousData;
                return data['somekey'];
            },

            getPrevious: function(){}
        }
        */
    },

    _accessorName: undefined,

    options: {
        accessors: {}
    },

    setupAccessors: function(){
        this.setAccessor(Object.merge({}, this._accessors, this.options.accessors));

        return this;
    },

    isAccessing: function(){
        return !!this._accessorName;
    },

    /**
     * Accessor functions pass through to trigger flags
     * to signify that an accessor is being used.
     */
    _processAccess: function(name, fnc){
        var value;

        if (name) {
            // this._accessing++;
            this._accessorName = name;

            value = fnc();

            // this._accessing--;
            this._accessorName = void 0;
        }

        return value;
    },

    setAccessor: function(name, obj){
        var accessors = {};

        if (!!name && Type.isObject(obj)) {

            /**
             * Decorate the functions in obj so that it will be easy to prevent
             * recursive calls to itself because the decorated function tracks
             * the name is.
             */
            Object.each(obj, function(fnc, type) {
                var f;
                if (fnc && !accessors[type]) {
                    f = accessors[type] = function(){
                        return this._processAccess(name, fnc.pass(arguments, this));
                    }.bind(this);

                    f._orig = fnc;
                }
            }, this);

            this._accessors[name] = accessors;
        }

        return this;
    }.overloadSetter(),

    getAccessor: function(name, type){
        var accessors = this._accessors[name];

        if (type) {
            return accessors && accessors[type];
        }

        return accessors;
    },

    unsetAccessor: function(name, type){
        /**
         * Tried using delete, but it the properties have DontDelete
         * Reference: http://perfectionkills.com/understanding-delete/
         */
        if (name) {
            if (type) {
                this._accessors[name][type] = void 0;
            } else {
                this._accessors[name] = void 0;
            }
        }

        return this;
    }
});

exports.Butler = Butler;<commit_msg>Update Butler so that it properly sets _accessors.<commit_after>var Butler = new Class({
    _accessors: {
        /*
        key: {
            // The buck stops here for this custom set method.
            // Any returned value goes into the ether because
            // the original set code block is ignored when this is invoked

            set: function(prop, val){},

            // isPrevious flag lets you choose whether to pull data from this._data or this._previousData
            get: function(isPrevious){
                //Example
                var data = isPrevious ? this._data : this._previousData;
                return data['somekey'];
            },

            getPrevious: function(){}
        }
        */
    },

    _accessorName: undefined,

    options: {
        accessors: {}
    },

    setupAccessors: function(){
        var accessors = this._accessors;

        this._accessors = {};

        this.setAccessor(Object.merge({}, accessors, this.options.accessors));

        return this;
    },

    isAccessing: function(){
        return !!this._accessorName;
    },

    /**
     * Accessor functions pass through to trigger flags
     * to signify that an accessor is being used.
     */
    _processAccess: function(name, fnc){
        var value;

        if (name) {
            // this._accessing++;
            this._accessorName = name;

            value = fnc();

            // this._accessing--;
            this._accessorName = void 0;
        }

        return value;
    },

    setAccessor: function(name, obj){
        var accessors = {};

        if (!!name && Type.isObject(obj)) {

            /**
             * Decorate the functions in obj so that it will be easy to prevent
             * recursive calls to itself because the decorated function tracks
             * the name is.
             */
            Object.each(obj, function(fnc, type) {
                var f;
                if (fnc && !accessors[type]) {
                    f = accessors[type] = function(){
                        return this._processAccess(name, fnc.pass(arguments, this));
                    }.bind(this);

                    f._orig = fnc;
                }
            }, this);

            this._accessors[name] = accessors;
        }

        return this;
    }.overloadSetter(),

    getAccessor: function(name, type){
        var accessors = this._accessors[name];

        if (type) {
            return accessors && accessors[type];
        }

        return accessors;
    },

    unsetAccessor: function(name, type){
        /**
         * Tried using delete, but it the properties have DontDelete
         * Reference: http://perfectionkills.com/understanding-delete/
         */
        if (name) {
            if (type) {
                this._accessors[name][type] = void 0;
            } else {
                this._accessors[name] = void 0;
            }
        }

        return this;
    }
});

exports.Butler = Butler;<|endoftext|>


<commit_before>'use strict';

app.directive('pikaday', function() {
  return {
    restrict: 'A',
    scope: {
      pikaday: '=',
    },
    link: function (scope, elem, attrs) {

      var picker = new Pikaday({

        field: elem[0],
        trigger: document.getElementById(attrs.triggerId),
        bound: attrs.bound !== 'false',
        format: attrs.format || 'ddd MMM D YYYY', // Requires Moment.js for custom formatting
        defaultDate: new Date(attrs.defaultDate),
        setDefaultDate: attrs.setDefaultDate === 'true',
        firstDay: attrs.firstDay ? parseInt(attrs.firstDay) : 0,
        minDate: new Date(attrs.minDate),
        maxDate: new Date(attrs.maxDate),
        yearRange: attrs.yearRange ? JSON.parse(attrs.yearRange) : 10, // Accepts int (10) or 2 elem array ([1992, 1998]) as strings
        isRTL: attrs.isRTL === 'true',
        i18n: {
          previousMonth : 'Previous Month',
          nextMonth     : 'Next Month',
          months        : ['January','February','March','April','May','June','July','August','September','October','November','December'],
          weekdays      : ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
          weekdaysShort : ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']
        },
        yearSuffix: attrs.yearSuffix || '',
        showMonthAfterYear: attrs.showMonthAfterYear === 'true',

        // Update scope whenever new date selected
        onSelect: function () {
          setTimeout(function(){
            scope.$apply();
          });
        }
      });
      scope.pikaday = picker;
    }
  };
});
<commit_msg>added 1.2 compatable position attr<commit_after>'use strict';

app.directive('pikaday', function() {
  return {
    restrict: 'A',
    scope: {
      pikaday: '=',
    },
    link: function (scope, elem, attrs) {

      var picker = new Pikaday({

        field: elem[0],
        trigger: document.getElementById(attrs.triggerId),
        bound: attrs.bound !== 'false',
        position: attrs.position || '',
        format: attrs.format || 'ddd MMM D YYYY', // Requires Moment.js for custom formatting
        defaultDate: new Date(attrs.defaultDate),
        setDefaultDate: attrs.setDefaultDate === 'true',
        firstDay: attrs.firstDay ? parseInt(attrs.firstDay) : 0,
        minDate: new Date(attrs.minDate),
        maxDate: new Date(attrs.maxDate),
        yearRange: attrs.yearRange ? JSON.parse(attrs.yearRange) : 10, // Accepts int (10) or 2 elem array ([1992, 1998]) as strings
        isRTL: attrs.isRTL === 'true',
        i18n: {
          previousMonth : 'Previous Month',
          nextMonth     : 'Next Month',
          months        : ['January','February','March','April','May','June','July','August','September','October','November','December'],
          weekdays      : ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
          weekdaysShort : ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']
        },
        yearSuffix: attrs.yearSuffix || '',
        showMonthAfterYear: attrs.showMonthAfterYear === 'true',

        onSelect: function () {
          setTimeout(function(){
            scope.$apply();
          });
        }
      });
      scope.pikaday = picker;
    }
  };
});
<|endoftext|>


<commit_before>import {
    filesSelector,
    jobsSelector,
    otusSelector,
    subtractionsSelector,
    usersSelector
} from "./listSelectors";

describe("Selectors tests", () => {
    const state = {
        files: { documents: [{ id: "foo" }, { id: "fud" }] },
        jobs: { documents: [{ id: "bar" }, { id: "baz" }] },
        otus: { documents: [{ id: "qux" }, { id: "quark" }] },
        subtraction: { documents: [{ id: "hello" }, { id: "world" }] },
        users: {
            list: {
                documents: [{ id: "test" }, { id: "example" }],
                page: 1,
                page_count: 1
            }
        }
    };
    let result;
    let expected;

    it("filesSelector: returns data used to render a list of files", () => {
        result = filesSelector(state);
        expected = ["foo", "fud"];
        expect(result).toEqual(expected);
    });

    it("jobsSelector: returns data used to render a list of jobs", () => {
        result = jobsSelector(state);
        expected = ["bar", "baz"];
        expect(result).toEqual(expected);
    });

    it("otusSelector: returns data used to render a list of otus", () => {
        result = otusSelector(state);
        expected = ["qux", "quark"];
        expect(result).toEqual(expected);
    });

    it("subtractionsSelector: returns data used to render a list of subtractions", () => {
        result = subtractionsSelector(state);
        expected = ["hello", "world"];
        expect(result).toEqual(expected);
    });

    it("usersSelector: returns data used to render a list of users", () => {
        result = usersSelector(state);
        expected = {
            documents: ["test", "example"],
            page: 1,
            page_count: 1
        };
        expect(result).toEqual(expected);

        result = usersSelector({ users: { list: null } });
        expected = { documents: null, page: 0, page_count: 0 };
        expect(result).toEqual(expected);
    });

});
<commit_msg>Update test<commit_after>import {
    filesSelector,
    otusSelector,
    subtractionsSelector,
    usersSelector
} from "./listSelectors";

describe("Selectors tests", () => {
    const state = {
        files: { documents: [{ id: "foo" }, { id: "fud" }] },
        otus: { documents: [{ id: "qux" }, { id: "quark" }] },
        subtraction: { documents: [{ id: "hello" }, { id: "world" }] },
        users: {
            list: {
                documents: [{ id: "test" }, { id: "example" }],
                page: 1,
                page_count: 1
            }
        }
    };
    let result;
    let expected;

    it("filesSelector: returns data used to render a list of files", () => {
        result = filesSelector(state);
        expected = ["foo", "fud"];
        expect(result).toEqual(expected);
    });

    it("otusSelector: returns data used to render a list of otus", () => {
        result = otusSelector(state);
        expected = ["qux", "quark"];
        expect(result).toEqual(expected);
    });

    it("subtractionsSelector: returns data used to render a list of subtractions", () => {
        result = subtractionsSelector(state);
        expected = ["hello", "world"];
        expect(result).toEqual(expected);
    });

    it("usersSelector: returns data used to render a list of users", () => {
        result = usersSelector(state);
        expected = {
            documents: ["test", "example"],
            page: 1,
            page_count: 1
        };
        expect(result).toEqual(expected);

        result = usersSelector({ users: { list: null } });
        expected = { documents: null, page: 0, page_count: 0 };
        expect(result).toEqual(expected);
    });

});
<|endoftext|>