<commit_before>// JavaScript Document

octane.module('Router',['OctaneViews'],function (cfg) {

        // octane's own pushstate method
        function pushState(params){

            params = _.isObject(params) ? params : {};
            // update the language in the url
            var parsed = __.location().searchObject;

            octane.extend.call(parsed,params);

            var
            fragment = [],
            parsedKeys = Object.keys(parsed),
            key;

            for(var k=0,K=parsedKeys.length; k<K; k++){
                key = parsedKeys[k];
                fragment.push(key+'='+parsed[key]);
            }

            fragment = fragment.join('&');
            fragment = '?'+fragment;

            var
            language = octane.translator && octane.translator.getLang(),
            title = __.titleize(params.view) || currentView.title;

            History.pushState(
                { lang: language },
                octane.get('application.name') +' | '+ title,
                fragment
            );

            document.querySelector('head>title').innerHTML = octane.get('application.name')+' | '+title;
        }

        var
        enRoute = null,
        routingBlocked = false,
        currentView,
        // store routes called while another route is executing its loading animation
        queuedRoute = null,
        // conditions under which a route should be called, added with .routeIf()
        routeConditions = {};

        // block routing, incoming routes go to queue
        //octane.handle('block:routing',function(){
        function blockRouting(){
            routingBlocked = true;
        }//);
        // release block and route from queue
        // octane.handle('unblock:routing',function(){
        function unblockRouting(){
            routingBlocked = false;

            if(queuedRoute){
                route(queuedRoute.view).then(queuedRoute.resolver).catch(function(ex){
                    octane.log(ex);
                });
            }
        }

        // add a condition that needs to be true for the route to run
        function routeIf(viewID,condition,failCallback){

            if(!_.isArray(routeConditions[viewID])){
                routeConditions[viewID] = [];
            }
            if(!_.isFunction(condition)){
                condition = function(){
                    return true;
                }
            }
            routeConditions[viewID].push({
                check     : condition,
                onFail    : failCallback
            });
        }

        // add a deferred to execute before a view is routed
        // unlike routeIf, route will initialize whether the promise resolves or rejects
        // just keeps view from routing until something is done
        function beforeRoute(viewID,deferred,argsArray){

            octane.view(viewID) && octane.view(viewID).addBeforeLoadPromise(deferred,argsArray);
            return octane;
        }

        // add a callback to be executed when the specified view finishes its loading animation
        function routeThen(viewID,callback,argsArray){

            octane.view(viewID) && octane.view(viewID).addAfterLoadCallback(callback,argsArray);
            return octane;
        }

        // @param id [str]: id of the o-view to be called
        // @param callback [fn]: a function to be executed when the loading animation finishes
        // function's thisArg is bound to the view called
        // @param ghost [bool]: do not update the history with the view (default false)
        function route(viewID,ghost){

            return new Promise(function(resolve,reject){

                ghost = _.isBoolean(ghost) ? ghost : false;
                var
                $view = octane.view(viewID),
                viewOnScreen = ($view == currentView),
                modalOnScreen = (octane.Modal.current());

            // ensure the onscreen view isn't reanimated
            //////////////////////////////////////////////////////////////////////////////////////
                                                                                //
                if( $view && viewOnScreen && modalOnScreen){                                   //
                    octane.Modal.dismiss(modalOnScreen.id);                                     //
                    resolve();                                                                  //
                } else if ($view && !viewOnScreen){                                             //
                                                                                //
                // ensure a route isn't triggered while another route is animating              //
                // or while routing has been blocked by another module                          //
                //////////////////////////////////////////////////////////////////////////      //
                                                                                //      //
                    if(!enRoute && !routingBlocked){                                    //      //
                                                                                //      //
                        if(!checkRouteIf(viewID)){
                            reject('Routing condition not fulfilled for route "'+viewID+'"');
                            return;
                        }                                                               //      //
                        octane.fire('routing:begin');                                   //      //
                                                                                //      //
                        enRoute = viewID;                                               //      //
                                                                                //      //
                    // exit the current view before calling a new view                  //      //
                    //////////////////////////////////////////////////////////////      //      //
                                                                                //      //      //
                        if(currentView){                                        //      //      //
                            currentView.queueExit()                             //      //      //
                                .then(function(){                               //      //      //
                                    return loadView($view,ghost,currentView);   //      //      //
                                })                                              //      //      //
                                .then(resolve)                                  //      //      //
                                .catch(octane.log);                             //      //      //
                        }else{                                                  //      //      //
                            loadView($view,ghost)                               //      //      //
                                .then(resolve)                                  //      //      //
                                .catch(octane.log);                             //      //      //
                        }                                                       //      //      //
                    //////////////////////////////////////////////////////////////      //      //
                                                                                //      //
                    }else{                                                              //      //
                        // a new route was called                                       //      //
                        //if(viewID !== enRoute){
                            queuedRoute = {
                                view : viewID,
                                resolver : resolve
                            };
                            //      //
                        //} else {                                                        //      //
                            // the same route was called twice, resolve immediately
                         //   $view.callAfterLoadCallbacks();                                                           //      //
                        //    resolve();                                                  //      //
                       // }                                                               //      //
                    }                                                                   //      //
                //////////////////////////////////////////////////////////////////////////      //
                                                                                //
                }else{
                    octane.fire('routing:complete');//
                    resolve();                                                                  //
                }                                                                               //
                                                                                //
            //////////////////////////////////////////////////////////////////////////////////////

            });
        }

        // helper
        function loadView($view,ghost,previousView){
            octane.fire('view:loading');

            return $view.load().then(function(){

                octane.fire('view:loaded');
                !ghost && pushState({view:$view.id});
                // update the current view
                currentView = $view;
                // update current view in global state, jumpstart Circuit
                octane.goose('application',{
                    viewID : $view.id,
                    viewTitle : $view.title
                });
                // send previous view back intot the hidden view stack
                previousView && previousView.exit();
                // flag this route complete
                enRoute = null;
               // check for queued routes
                if(queuedRoute){
                    // route next view
                    var next = queuedRoute;
                    route(next.view).then(function(){
                        next.resolver();
                        queuedRoute = null;
                    });
                } else{
                    // signal to any blocking listeners that routing is complete
                    octane.fire('routing:complete');
                }
             });
        }

        // helper
        function checkRouteIf(viewID){

            var
            conditions = routeConditions[viewID] || [],
            checkCondition = function(condition){

                if(condition.check()){
                    // meets routing condition
                    return true;
                }else{
                    // does not meet routing condition, call fail callback
                    _.isFunction(condition.onFail) && condition.onFail();
                    return false;
                }
            };

            for(var i=0,n=conditions.length; i<n; i++){
                if (checkCondition(conditions[i])){
                    continue;
                } else {
                    return false;
                }
            }
            return true;

        }

        function setRoutingButtons(){

            var
            btns = document.querySelectorAll('[o-route]'),
            n = btns.length,
            setBtn = function(btn){
                var route = btn.getAttribute('o-route');

                // catch a click event from a child node
                // re-purpose it to be used by the octane event mediator
                btn.addEventListener('click',function(e){
                    e.stopPropagation();
                    e.stopImmediatePropagation();
                    btn.dispatchEvent(__.customEvent('octane:route',{bubbles:true}));
                },false);

                // set up the octane event mediator
                // so event won't get a second listener
                // if you call .compile() again after .initialize()
                octane.handle('octane:route',btn,function(){
                    octane.route(route);
                });
            }

            while(n--){
                // closure to capture the button and route during the loop
               setBtn(btns[n]);
            }
        }

        function setBackButtons(){
            var
            btns = document.querySelectorAll('.o-back'),
            n= btns.length,
            setBtn = function(btn){

                octane.handle('click',btn,function(){
                    History.go(-1);
                });
            };

            while(n--){
                setBtn(btns[n]);
            }
        }

        function handleStateChange(){

            var
            html = document.getElementsByTagName('html')[0],
            history =  html && html.classList.contains('history'),
            stateChangeEvent = history ? 'popstate' : 'hashchange';

            // change the view with browser's forward/back buttons
            octane.handle(stateChangeEvent,function(){
                var view = parseView();
                view && octane.route(view);
            });
        }

        // parse URL for a view
        function parseView(){

            // for HTML5 vs. HTML4 browsers
            // detect with modernizr
            var
            html = document.getElementsByTagName('html')[0],
            history =  html && html.classList.contains('history');

            if(history){
                return __.location().searchObject.view || false;
            } else {
                 var hash = window.location.hash,
                    param,
                    parsed = {};

                (function (){
                   hash = hash.replace('#?','');
                    hash = hash.split('&');
                    for(var i=0,n=hash.length;i<n;i++){
                        param = hash[i].split('=');
                        parsed[param[0]] = param[1];
                    }
               })();

               return parsed.view || false;
            }
         }

        // Router Public API
        octane.constructor.prototype.define({
            parseView       : parseView,
            route			: function(viewID,ghost){
                                return route(viewID,ghost).catch(function(ex){
                                    octane.log(ex);
                                });
                            },
            routeIf         : routeIf,
            beforeRoute     : beforeRoute,
            routeThen		: routeThen,
            pushState		: pushState,
            currentView     : function(){
                                return currentView
                            },
            getRouteQueue   : function(){
                return queuedRoute;
            },
            blockRouting    : blockRouting,
            unblockRouting  : unblockRouting
        });

        this.initialize= function(){

            octane.compiler( setRoutingButtons );
            octane.compiler( setBackButtons );
            octane.compiler( handleStateChange );

            // resize canvas to proper dimensions
            octane.handle('translated resize orientationchange',function(){
                currentView && currentView.setCanvasHeight();
            });
        }
    });

	<commit_msg>using object with predicate and onfail functions in routeIf instead of arguments 2 and 3, using new App name to refer to main model, cleaned up a for loop<commit_after>// JavaScript Document

octane.module('Router',['OctaneViews'],function (cfg) {

        // octane's own pushstate method
        function pushState(params){

            params = _.isObject(params) ? params : {};
            // update the language in the url
            var parsed = __.location().searchObject;

            octane.extend.call(parsed,params);

            var
            fragment = [],
            parsedKeys = Object.keys(parsed),
            key;

            for(var k=0,K=parsedKeys.length; k<K; k++){
                key = parsedKeys[k];
                fragment.push(key+'='+parsed[key]);
            }

            fragment = fragment.join('&');
            fragment = '?'+fragment;

            var
            language = octane.translator && octane.translator.getLang(),
            title = __.titleize(params.view) || currentView.title;

            History.pushState(
                { lang: language },
                octane.get('APP.name') +' | '+ title,
                fragment
            );

            document.querySelector('head>title').innerHTML = octane.get('App.name')+' | '+title;
        }

        var
        enRoute = null,
        routingBlocked = false,
        currentView,
        // store routes called while another route is executing its loading animation
        queuedRoute = null,
        // conditions under which a route should be called, added with .routeIf()
        routeConditions = {};

        // block routing, incoming routes go to queue
        //octane.handle('block:routing',function(){
        function blockRouting(){
            routingBlocked = true;
        }//);
        // release block and route from queue
        // octane.handle('unblock:routing',function(){
        function unblockRouting(){
            routingBlocked = false;

            if(queuedRoute){
                route(queuedRoute.view).then(queuedRoute.resolver).catch(function(ex){
                    octane.log(ex);
                });
            }
        }

        // add a condition that needs to be true for the route to run
        function routeIf(viewID,conditions){
            conditions = _.isObject(conditions) ? conditions : {};

            if(!_.isArray(routeConditions[viewID])){
                routeConditions[viewID] = [];
            }
            if(!_.isFunction(conditions.predicate)){
                conditions.predicate = function(){
                    return true;
                }
            }
            routeConditions[viewID].push(conditions);
            return octane; // chainable
        }

        // add a deferred to execute before a view is routed
        // unlike routeIf, route will initialize whether the promise resolves or rejects
        // just keeps view from routing until something is done
        function beforeRoute(viewID,deferred,argsArray){

            octane.view(viewID) && octane.view(viewID).addBeforeLoadPromise(deferred,argsArray);
            return octane;
        }

        // add a callback to be executed when the specified view finishes its loading animation
        function routeThen(viewID,callback,argsArray){

            octane.view(viewID) && octane.view(viewID).addAfterLoadCallback(callback,argsArray);
            return octane;
        }

        // @param id [str]: id of the o-view to be called
        // @param callback [fn]: a function to be executed when the loading animation finishes
        // function's thisArg is bound to the view called
        // @param ghost [bool]: do not update the history with the view (default false)
        function route(viewID,ghost){

            return new Promise(function(resolve,reject){

                ghost = _.isBoolean(ghost) ? ghost : false;
                var
                $view = octane.view(viewID),
                viewOnScreen = ($view == currentView),
                modalOnScreen = (octane.Modal.current());

            // ensure the onscreen view isn't reanimated
            //////////////////////////////////////////////////////////////////////////////////////
                                                                                //
                if( $view && viewOnScreen && modalOnScreen){                                   //
                    octane.Modal.dismiss(modalOnScreen.id);                                     //
                    resolve();                                                                  //
                } else if ($view && !viewOnScreen){                                             //
                                                                                //
                // ensure a route isn't triggered while another route is animating              //
                // or while routing has been blocked by another module                          //
                //////////////////////////////////////////////////////////////////////////      //
                                                                                //      //
                    if(!enRoute && !routingBlocked){                                    //      //
                                                                                //      //
                        if(!checkRouteIf(viewID)){
                            reject('Routing condition not fulfilled for route "'+viewID+'"');
                            return;
                        }                                                               //      //
                        octane.fire('routing:begin');                                   //      //
                                                                                //      //
                        enRoute = viewID;                                               //      //
                                                                                //      //
                    // exit the current view before calling a new view                  //      //
                    //////////////////////////////////////////////////////////////      //      //
                                                                                //      //      //
                        if(currentView){                                        //      //      //
                            currentView.queueExit()                             //      //      //
                                .then(function(){                               //      //      //
                                    return loadView($view,ghost,currentView);   //      //      //
                                })                                              //      //      //
                                .then(resolve)                                  //      //      //
                                .catch(octane.log);                             //      //      //
                        }else{                                                  //      //      //
                            loadView($view,ghost)                               //      //      //
                                .then(resolve)                                  //      //      //
                                .catch(octane.log);                             //      //      //
                        }                                                       //      //      //
                    //////////////////////////////////////////////////////////////      //      //
                                                                                //      //
                    }else{                                                              //      //
                        // a new route was called                                       //      //
                        //if(viewID !== enRoute){
                            queuedRoute = {
                                view : viewID,
                                resolver : resolve
                            };
                            //      //
                        //} else {                                                        //      //
                            // the same route was called twice, resolve immediately
                         //   $view.callAfterLoadCallbacks();                                                           //      //
                        //    resolve();                                                  //      //
                       // }                                                               //      //
                    }                                                                   //      //
                //////////////////////////////////////////////////////////////////////////      //
                                                                                //
                }else{
                    octane.fire('routing:complete');//
                    resolve();                                                                  //
                }                                                                               //
                                                                                //
            //////////////////////////////////////////////////////////////////////////////////////

            });
        }

        // helper
        function loadView($view,ghost,previousView){
            octane.fire('view:loading');

            return $view.load().then(function(){

                octane.fire('view:loaded');
                !ghost && pushState({view:$view.id});
                // update the current view
                currentView = $view;
                // update current view in global state, jumpstart Circuit
                octane.set({
                    "App.viewID" : $view.id,
                    "App.viewTitle" : $view.title
                });
                // send previous view back intot the hidden view stack
                previousView && previousView.exit();
                // flag this route complete
                enRoute = null;
               // check for queued routes
                if(queuedRoute){
                    // route next view
                    var next = queuedRoute;
                    route(next.view).then(function(){
                        next.resolver();
                        queuedRoute = null;
                    });
                } else{
                    // signal to any blocking listeners that routing is complete
                    octane.fire('routing:complete');
                }
             });
        }

        // helper
        function checkRouteIf(viewID){

            var
            conditions = routeConditions[viewID] || [],
            i=0,n=conditions.length,
            checkCondition = function(condition){

                if(condition.predicate()){
                    // meets routing condition
                    return true;
                }else{
                    // does not meet routing condition, call fail callback
                    _.isFunction(condition.onfail) && condition.onfail();
                    return false;
                }
            };

            for(;i<n;i++){
                if (checkCondition(conditions[i])){
                    continue;
                } else {
                    return false;
                }
            }
            return true;

        }

        function setRoutingButtons(){

            var
            btns = document.querySelectorAll('[o-route]'),
            n = btns.length,
            setBtn = function(btn){
                var route = btn.getAttribute('o-route');

                // catch a click event from a child node
                // re-purpose it to be used by the octane event mediator
                btn.addEventListener('click',function(e){
                    //e.stopPropagation();
                    //e.stopImmediatePropagation();
                    btn.dispatchEvent(__.customEvent('octane:route',{bubbles:true}));
                },false);

                // set up the octane event mediator
                // so event won't get a second listener
                // if you call .compile() again after .initialize()
                octane.handle('octane:route',btn,function(){
                    octane.route(route);
                });
            }

            while(n--){
                // closure to capture the button and route during the loop
               setBtn(btns[n]);
            }
        }

        function setBackButtons(){
            var
            btns = document.querySelectorAll('.o-back'),
            n= btns.length,
            setBtn = function(btn){

                octane.handle('click',btn,function(){
                    History.go(-1);
                });
            };

            while(n--){
                setBtn(btns[n]);
            }
        }

        function handleStateChange(){

            var
            html = document.getElementsByTagName('html')[0],
            history =  html && html.classList.contains('history'),
            stateChangeEvent = history ? 'popstate' : 'hashchange';

            // change the view with browser's forward/back buttons
            octane.handle(stateChangeEvent,function(){
                var view = parseView();
                view && octane.route(view);
            });
        }

        // parse URL for a view
        function parseView(){

            // for HTML5 vs. HTML4 browsers
            // detect with modernizr
            var
            html = document.getElementsByTagName('html')[0],
            history =  html && html.classList.contains('history');

            if(history){
                return __.location().searchObject.view || false;
            } else {
                 var hash = window.location.hash,
                    param,
                    parsed = {};

                (function (){
                   hash = hash.replace('#?','');
                    hash = hash.split('&');
                    for(var i=0,n=hash.length;i<n;i++){
                        param = hash[i].split('=');
                        parsed[param[0]] = param[1];
                    }
               })();

               return parsed.view || false;
            }
         }

        // Router Public API
        octane.constructor.prototype.define({
            parseView       : parseView,
            route			: function(viewID,ghost){
                                return route(viewID,ghost).catch(function(ex){
                                    octane.log(ex);
                                });
                            },
            routeIf         : routeIf,
            beforeRoute     : beforeRoute,
            routeThen		: routeThen,
            pushState		: pushState,
            currentView     : function(){
                                return currentView
                            },
            getRouteQueue   : function(){
                return queuedRoute;
            },
            blockRouting    : blockRouting,
            unblockRouting  : unblockRouting
        });

        this.initialize= function(){

            octane.compiler( setRoutingButtons );
            octane.compiler( setBackButtons );
            octane.compiler( handleStateChange );

            // resize canvas to proper dimensions
            octane.handle('translated resize orientationchange',function(){
                currentView && currentView.setCanvasHeight();
            });
        }
    });

	<|endoftext|>


<commit_before>import Rx from 'rxjs/Rx';

import { launch } from 'spawnteract';

import * as uuid from 'uuid';

import {
  ipcRenderer as ipc,
} from 'electron';

import {
  createControlSubject,
  createStdinSubject,
  createIOPubSubject,
  createShellSubject,
} from 'enchannel-zmq-backend';

import {
  createMessage,
} from '../kernel/messaging';

import {
  setExecutionState,
  setNotebookKernelInfo,
} from '../actions';

import {
  NEW_KERNEL,
  LAUNCH_KERNEL,
  SET_LANGUAGE_INFO,
  ERROR_KERNEL_LAUNCH_FAILED,
} from '../constants';

export function setLanguageInfo(langInfo) {
  return {
    type: SET_LANGUAGE_INFO,
    langInfo,
  };
}

export function acquireKernelInfo(channels) {
  const message = createMessage('kernel_info_request');

  const obs = channels.shell
    .childOf(message)
    .ofMessageType(['kernel_info_reply'])
    .first()
    .pluck('content', 'language_info')
    .map(setLanguageInfo);

  return Rx.Observable.create(observer => {
    const subscription = obs.subscribe(observer);
    channels.shell.next(message);
    return subscription;
  });
}

export function newKernelObservable(kernelSpecName, cwd) {
  return Rx.Observable.create((observer) => {
    launch(kernelSpecName, { cwd })
      .then(c => {
        const { config, spawn, connectionFile, kernelSpec } = c;

        const identity = uuid.v4();
        // TODO: I'm realizing that we could trigger on when the underlying sockets
        //       are ready with these subjects to let us know when the kernels
        //       are *really* ready
        const channels = {
          shell: createShellSubject(identity, config),
          iopub: createIOPubSubject(identity, config),
          control: createControlSubject(identity, config),
          stdin: createStdinSubject(identity, config),
        };
        observer.next(setNotebookKernelInfo({
          name: kernelSpecName,
          spec: kernelSpec,
        }));

        observer.next({
          type: NEW_KERNEL,
          channels,
          connectionFile,
          spawn,
          kernelSpecName,
          kernelSpec,
        });
        observer.complete();
      });
  });
}

export const watchExecutionStateEpic = action$ =>
  action$.ofType(NEW_KERNEL)
    .switchMap(action =>
      Rx.Observable.merge(
        action.channels.iopub
          .filter(msg => msg.header.msg_type === 'status')
          .map(msg => setExecutionState(msg.content.execution_state)),
        Rx.Observable.of(setExecutionState('idle'))
      )
    );

export const acquireKernelInfoEpic = action$ =>
  action$.ofType(NEW_KERNEL)
    .switchMap(action => {
      /* istanbul ignore if -- used for interactive debugging */
      if (process.env.DEBUG) {
        window.channels = action.channels;
      }
      return acquireKernelInfo(action.channels);
    });

export const newKernelEpic = action$ =>
  action$.ofType(LAUNCH_KERNEL)
    .do(action => {
      if (!action.kernelSpecName) {
        throw new Error('newKernel needs a kernelSpecName');
      }
      ipc.send('nteract:ping:kernel', action.kernelSpecName);
    })
    .mergeMap(action =>
      newKernelObservable(action.kernelSpecName, action.cwd)
    )
    .catch(error => Rx.Observable.of({
      type: ERROR_KERNEL_LAUNCH_FAILED,
      payload: error,
      error: true,
    }));
<commit_msg>docs(kernelLaunch): Add docstrings for kernel launch<commit_after>import Rx from 'rxjs/Rx';

import { launch } from 'spawnteract';

import * as uuid from 'uuid';

import {
  ipcRenderer as ipc,
} from 'electron';

import {
  createControlSubject,
  createStdinSubject,
  createIOPubSubject,
  createShellSubject,
} from 'enchannel-zmq-backend';

import {
  createMessage,
} from '../kernel/messaging';

import {
  setExecutionState,
  setNotebookKernelInfo,
} from '../actions';

import {
  NEW_KERNEL,
  LAUNCH_KERNEL,
  SET_LANGUAGE_INFO,
  ERROR_KERNEL_LAUNCH_FAILED,
} from '../constants';

export function setLanguageInfo(langInfo) {
  return {
    type: SET_LANGUAGE_INFO,
    langInfo,
  };
}

/**
  * Send a kernel_info_request to the kernel.
  *
  * @param  {Object}  channels  A object containing the kernel channels
  * @returns  {Observable}  The reply from the server
  */
export function acquireKernelInfo(channels) {
  const message = createMessage('kernel_info_request');

  const obs = channels.shell
    .childOf(message)
    .ofMessageType(['kernel_info_reply'])
    .first()
    .pluck('content', 'language_info')
    .map(setLanguageInfo);

  return Rx.Observable.create(observer => {
    const subscription = obs.subscribe(observer);
    channels.shell.next(message);
    return subscription;
  });
}

/**
  * Instantiate a connection to a new kernel.
  *
  * @param  {String}  kernelSpecName  The name of the kernel to launch
  * @param  {String}  cwd The working directory to launch the kernel in
  */
export function newKernelObservable(kernelSpecName, cwd) {
  return Rx.Observable.create((observer) => {
    launch(kernelSpecName, { cwd })
      .then(c => {
        const { config, spawn, connectionFile, kernelSpec } = c;

        const identity = uuid.v4();
        // TODO: I'm realizing that we could trigger on when the underlying sockets
        //       are ready with these subjects to let us know when the kernels
        //       are *really* ready
        const channels = {
          shell: createShellSubject(identity, config),
          iopub: createIOPubSubject(identity, config),
          control: createControlSubject(identity, config),
          stdin: createStdinSubject(identity, config),
        };
        observer.next(setNotebookKernelInfo({
          name: kernelSpecName,
          spec: kernelSpec,
        }));

        observer.next({
          type: NEW_KERNEL,
          channels,
          connectionFile,
          spawn,
          kernelSpecName,
          kernelSpec,
        });
        observer.complete();
      });
  });
}

/**
  * Sets the execution state after a kernel has been launched.
  *
  * @oaram  {ActionObservable}  action$ The action type
  */
export const watchExecutionStateEpic = action$ =>
  action$.ofType(NEW_KERNEL)
    .switchMap(action =>
      Rx.Observable.merge(
        action.channels.iopub
          .filter(msg => msg.header.msg_type === 'status')
          .map(msg => setExecutionState(msg.content.execution_state)),
        Rx.Observable.of(setExecutionState('idle'))
      )
    );

/**
  * Gets information about newly launched kernel.
  *
  * @param  {ActionObservable}  The action type
  */
export const acquireKernelInfoEpic = action$ =>
  action$.ofType(NEW_KERNEL)
    .switchMap(action => {
      /* istanbul ignore if -- used for interactive debugging */
      if (process.env.DEBUG) {
        window.channels = action.channels;
      }
      return acquireKernelInfo(action.channels);
    });

/**
  * Launches a new kernel.
  *
  * @param  {ActionObservable} action$  The action type, kernelSpecName, and cwd
  */
export const newKernelEpic = action$ =>
  action$.ofType(LAUNCH_KERNEL)
    .do(action => {
      if (!action.kernelSpecName) {
        throw new Error('newKernel needs a kernelSpecName');
      }
      ipc.send('nteract:ping:kernel', action.kernelSpecName);
    })
    .mergeMap(action =>
      newKernelObservable(action.kernelSpecName, action.cwd)
    )
    .catch(error => Rx.Observable.of({
      type: ERROR_KERNEL_LAUNCH_FAILED,
      payload: error,
      error: true,
    }));
<|endoftext|>


<commit_before>function startup(Cesium) {
    "use strict";
//Sandcastle_Begin
var viewer = new Cesium.Viewer('cesiumContainer', {showRenderLoopErrors : false});

var videoElement = document.getElementById('trailer');

var sphere = viewer.entities.add({
    position : Cesium.Cartesian3.fromDegrees(-79, 35, 5000),
    ellipsoid : {
        radii : new Cesium.Cartesian3(15000, 15000, 15000),
        material : videoElement
    }
});

	//Le damos funcionalidad al boton home
		viewer.homeButton.viewModel.command.beforeExecute.addEventListener(function(commandInfo){
	//Si se pulsa hacemos un flyto
		FlyTo()
		//Le decimos al botón que no haga nada mas
		commandInfo.cancel = true;
	});

	FlyTo();

	//Creamos la funcion flytogermany q nos llevara a alemania. Colocamos unas coordenadas aproximadas a nuestros datos
	function FlyTo (){
		viewer.camera.flyTo({
			destination : Cesium.Cartesian3.fromDegrees(-79, 34.7, 40000),
			orientation : {
				heading : Cesium.Math.toRadians(0.0),
				pitch : Cesium.Math.toRadians(-50.0),
				roll : 0.0
			}
		});
	};

// Since it's just an image material, we can modify the number
// of times the video repeats in each direction..
var isRepeating = true;
Sandcastle.addToolbarButton('Toggle Image Repeat', function() {
    isRepeating = !isRepeating;
});

sphere.ellipsoid.material.repeat = new Cesium.CallbackProperty(function(time, result) {
    if (!Cesium.defined(result)) {
        result = new Cesium.Cartesian2();
    }
    if (isRepeating) {
        result.x = 8;
        result.y = 8;
    } else {
        result.x = 1;
        result.y = 1;
    }
    return result;
}, false);

// Like Image, the video element doesn't have to be part of the DOM or
// otherwise on the screen to be used as a texture.
Sandcastle.addToolbarButton('Toggle Video Overlay', function() {
    if(videoElement.style.display === 'none'){
        videoElement.style.display = '';
        return;
    }
    videoElement.style.display = 'none';
});

// Older browsers do not support WebGL video textures,
// put up a friendly error message indicating such.
viewer.scene.renderError.addEventListener(function() {
    if(!videoElement.paused){
        videoElement.pause();
    }
    viewer.cesiumWidget.showErrorPanel('This browser does not support cross-origin WebGL video textures.', '', '');
});

//Sandcastle_End
    Sandcastle.finishedLoading();
}
if (typeof Cesium !== "undefined") {
    startup(Cesium);
} else if (typeof require === "function") {
    require(["Cesium"], startup);
}<commit_msg>Update video.js<commit_after>function startup(Cesium) {
    "use strict";
//Sandcastle_Begin
var viewer = new Cesium.Viewer('cesiumContainer', {showRenderLoopErrors : false});

var videoElement = document.getElementById('trailer');

var sphere = viewer.entities.add({
    position : Cesium.Cartesian3.fromDegrees(-79, 35, 5000),
    ellipsoid : {
        radii : new Cesium.Cartesian3(15000, 15000, 15000),
        material : videoElement
    }
});

	//Home button functionality
		viewer.homeButton.viewModel.command.beforeExecute.addEventListener(function(commandInfo){

		FlyTo()
		//Cancel other functionality of the home button
		commandInfo.cancel = true;
	});

	FlyTo();

	// Create the function flytogermany. Put aprrox coordinates to your data
	function FlyTo (){
		viewer.camera.flyTo({
			destination : Cesium.Cartesian3.fromDegrees(-79, 34.7, 40000),
			orientation : {
				heading : Cesium.Math.toRadians(0.0),
				pitch : Cesium.Math.toRadians(-50.0),
				roll : 0.0
			}
		});
	};

// Since it's just an image material, we can modify the number
// of times the video repeats in each direction..
var isRepeating = true;
Sandcastle.addToolbarButton('Toggle Image Repeat', function() {
    isRepeating = !isRepeating;
});

sphere.ellipsoid.material.repeat = new Cesium.CallbackProperty(function(time, result) {
    if (!Cesium.defined(result)) {
        result = new Cesium.Cartesian2();
    }
    if (isRepeating) {
        result.x = 8;
        result.y = 8;
    } else {
        result.x = 1;
        result.y = 1;
    }
    return result;
}, false);

// Like Image, the video element doesn't have to be part of the DOM or
// otherwise on the screen to be used as a texture.
Sandcastle.addToolbarButton('Toggle Video Overlay', function() {
    if(videoElement.style.display === 'none'){
        videoElement.style.display = '';
        return;
    }
    videoElement.style.display = 'none';
});

// Older browsers do not support WebGL video textures,
// put up a friendly error message indicating such.
viewer.scene.renderError.addEventListener(function() {
    if(!videoElement.paused){
        videoElement.pause();
    }
    viewer.cesiumWidget.showErrorPanel('This browser does not support cross-origin WebGL video textures.', '', '');
});

//Sandcastle_End
    Sandcastle.finishedLoading();
}
if (typeof Cesium !== "undefined") {
    startup(Cesium);
} else if (typeof require === "function") {
    require(["Cesium"], startup);
}
<|endoftext|>


<commit_before>'use strict';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { external_url_map } from '../globals';

class GeneDiseaseEvidenceSummaryCaseLevel extends Component {
    constructor(props) {
        super(props);
        this.state = {
            caseLevelEvidenceList: this.props.caseLevelEvidenceList,
            hpoTermList: this.props.hpoTermList
        };
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.caseLevelEvidenceList) {
            this.setState({caseLevelEvidenceList: nextProps.caseLevelEvidenceList});
        }
        if (nextProps.hpoTermList && nextProps.hpoTermList.length) {
            this.setState({hpoTermList: nextProps.hpoTermList});
        }
    }

    /**
     * Method to render individual table row of the logged-in user's scored evidence
     * @param {object} evidence - scored evidence and its associated case-control evidence
     * @param {number} key - unique key
     */
    renderCaseLevelEvidence(evidence, key) {
        return (

                    {evidence.variantType}

                    {evidence.variants.map((variant, i) => {
                        return (

                                    {variant.clinvarVariantTitle ?
                                        variant.clinvarVariantTitle : (variant.hgvsNames && variant.hgvsNames.GRCh37 ? variant.hgvsNames.GRCh37 : variant.hgvsNames.GRCh38)
                                    }

                        );
                    })}

                    {evidence.authors.join(', ')}, {evidence.pubYear}, PMID: {evidence.pmid}

                    {evidence.sex}

                    {evidence.ageValue ? {evidence.ageType ? Age of {evidence.ageType}:  : null}{evidence.ageValue} {evidence.ageUnit.length ? evidence.ageUnit : null} : null}

                    {evidence.ethnicity}

                    {evidence.hpoIdInDiagnosis.length ? HPO term(s): {this.state.hpoTermList.join(', ')} : null}
                    {evidence.hpoIdInDiagnosis.length && evidence.termsInDiagnosis.length ? ;  : null}
                    {evidence.termsInDiagnosis.length ? free text: {evidence.termsInDiagnosis} : null}

                    {evidence.segregationNumAffected ? evidence.segregationNumAffected : '-'}

                    {evidence.segregationNumUnaffected ? evidence.segregationNumUnaffected : '-'}

                    {evidence.segregationPublishedLodScore ?
                        Published: {evidence.segregationPublishedLodScore}
                        :
                        {evidence.segregationEstimatedLodScore ? Calculated: {evidence.segregationEstimatedLodScore} : '-'}
                    }

                    {evidence.segregationPublishedLodScore || evidence.segregationEstimatedLodScore ? {evidence.includeLodScoreInAggregateCalculation ? 'Yes' : 'No'} : '-'}

                    {evidence.previousTestingDescription}

                    {evidence.genotypingMethods.length ?
                        evidence.genotypingMethods.map((method, i) => {
                            return (
                                {i > 0 ? ;  : null}Method {i+1}: {method}
                            );
                        })
                        : null}

                    {{evidence.scoreStatus}}

                    {evidence.variantType.length ?

                            {evidence.scoreStatus !== 'Contradicts' ?
                                {typeof evidence.modifiedScore === 'number' ? evidence.modifiedScore : evidence.defaultScore}  ({evidence.defaultScore})
                                :
                                n/a
                            }

                        : null}

                    {evidence.scoreExplanation}

        );
    }

    /**
     * Method to get the total score of all scored evidence
     * @param {array} evidenceList - A list of evidence items
     */
    getTotalScore(evidenceList) {
        let allScores = [];
        evidenceList.forEach(item => {
            let score;
            if (item.scoreStatus.indexOf('Score') > -1) {
                score = typeof item.modifiedScore === 'number' ? item.modifiedScore : item.defaultScore;
                allScores.push(score);
            }
        });
        const totalScore = allScores.reduce((a, b) => a + b, 0);
        return totalScore;
    }

    render() {
        const caseLevelEvidenceList = this.state.caseLevelEvidenceList;
        let self = this;

        return (

Genetic Evidence: Case Level (variants, segregation)

                    {caseLevelEvidenceList && caseLevelEvidenceList.length ?

                                    Variant type
                                    Variant
                                    Reference
                                    Proband sex
                                    Proband age
                                    Proband ethnicity
                                    Proband phenotypes
                                    Segregations
                                    Proband previous testing
                                    Proband methods of detection
                                    Score status
                                    Proband score (default)
                                    Reason for changed score

                                    # Aff
                                    # Unaff
                                    LOD score
                                    Counted

                                {caseLevelEvidenceList.map((item, i) => {
                                    return (self.renderCaseLevelEvidence(item, i));
                                })}

                                    Total score:
                                    {this.getTotalScore(caseLevelEvidenceList)}

                        :

                            No scored Case Level evidence was found.

                    }

        );
    }
}

GeneDiseaseEvidenceSummaryCaseLevel.propTypes = {
    caseLevelEvidenceList: PropTypes.array,
    hpoTermList: PropTypes.array
};

export default GeneDiseaseEvidenceSummaryCaseLevel;<commit_msg>:nail_care: 1) Added handling to sort proband evidence table rows by 'variantType'. 2) Added handling to limit total score to 2 decimal numbers. 3) Updated the rendering of HPO terms so that each term has a line break.<commit_after>'use strict';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { external_url_map } from '../globals';

class GeneDiseaseEvidenceSummaryCaseLevel extends Component {
    constructor(props) {
        super(props);
        this.state = {
            caseLevelEvidenceList: this.props.caseLevelEvidenceList,
            hpoTermList: this.props.hpoTermList
        };
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.caseLevelEvidenceList) {
            this.setState({caseLevelEvidenceList: nextProps.caseLevelEvidenceList});
        }
        if (nextProps.hpoTermList && nextProps.hpoTermList.length) {
            this.setState({hpoTermList: nextProps.hpoTermList});
        }
    }

    /**
     * Method to render individual table row of the logged-in user's scored evidence
     * @param {object} evidence - scored evidence and its associated case-control evidence
     * @param {number} key - unique key
     */
    renderCaseLevelEvidence(evidence, key) {
        return (

                    {evidence.variantType}

                    {evidence.variants.map((variant, i) => {
                        return (

                                    {variant.clinvarVariantTitle ?
                                        variant.clinvarVariantTitle : (variant.hgvsNames && variant.hgvsNames.GRCh37 ? variant.hgvsNames.GRCh37 : variant.hgvsNames.GRCh38)
                                    }

                        );
                    })}

                    {evidence.authors.join(', ')}, {evidence.pubYear}, PMID: {evidence.pmid}

                    {evidence.sex}

                    {evidence.ageValue ? {evidence.ageType ? Age of {evidence.ageType}:  : null}{evidence.ageValue} {evidence.ageUnit.length ? evidence.ageUnit : null} : null}

                    {evidence.ethnicity}

                    {evidence.hpoIdInDiagnosis.length ? HPO term(s):
{this.state.hpoTermList.map((term, i) => {term}
)} : null}
                    {evidence.termsInDiagnosis.length ? free text:
{evidence.termsInDiagnosis} : null}

                    {evidence.segregationNumAffected ? evidence.segregationNumAffected : '-'}

                    {evidence.segregationNumUnaffected ? evidence.segregationNumUnaffected : '-'}

                    {evidence.segregationPublishedLodScore ?
                        Published: {evidence.segregationPublishedLodScore}
                        :
                        {evidence.segregationEstimatedLodScore ? Calculated: {evidence.segregationEstimatedLodScore} : '-'}
                    }

                    {evidence.segregationPublishedLodScore || evidence.segregationEstimatedLodScore ? {evidence.includeLodScoreInAggregateCalculation ? 'Yes' : 'No'} : '-'}

                    {evidence.previousTestingDescription}

                    {evidence.genotypingMethods.length ?
                        evidence.genotypingMethods.map((method, i) => {
                            return (
                                {i > 0 ? ;  : null}Method {i+1}: {method}
                            );
                        })
                        : null}

                    {{evidence.scoreStatus}}

                    {evidence.variantType.length ?

                            {evidence.scoreStatus !== 'Contradicts' ?
                                {typeof evidence.modifiedScore === 'number' ? evidence.modifiedScore : evidence.defaultScore}  ({evidence.defaultScore})
                                :
                                n/a
                            }

                        : null}

                    {evidence.scoreExplanation}

        );
    }

    /**
     * Method to get the total score of all scored evidence
     * @param {array} evidenceList - A list of evidence items
     */
    getTotalScore(evidenceList) {
        let allScores = [];
        evidenceList.forEach(item => {
            let score;
            if (item.scoreStatus.indexOf('Score') > -1) {
                score = typeof item.modifiedScore === 'number' ? item.modifiedScore : item.defaultScore;
                allScores.push(score);
            }
        });
        const totalScore = allScores.reduce((a, b) => a + b, 0);
        return parseFloat(totalScore).toFixed(2);
    }

    /**
     * Sort table rows given a list of evidence and column name
     */
    sortListbyColName(evidenceList, colName) {
        let sortedList = [];
        if (evidenceList.length) {
            sortedList = evidenceList.sort((x, y) => x[colName].toLowerCase() > y[colName].toLowerCase());
        }
        return sortedList;
    }

    render() {
        const caseLevelEvidenceList = this.state.caseLevelEvidenceList;
        let sortedEvidenceList = this.sortListbyColName(caseLevelEvidenceList, 'variantType');
        let self = this;

        return (

Genetic Evidence: Case Level (variants, segregation)

                    {sortedEvidenceList && sortedEvidenceList.length ?

                                    Variant type
                                    Variant
                                    Reference
                                    Proband sex
                                    Proband age
                                    Proband ethnicity
                                    Proband phenotypes
                                    Segregations
                                    Proband previous testing
                                    Proband methods of detection
                                    Score status
                                    Proband score (default)
                                    Reason for changed score

                                    # Aff
                                    # Unaff
                                    LOD score
                                    Counted

                                {sortedEvidenceList.map((item, i) => {
                                    return (self.renderCaseLevelEvidence(item, i));
                                })}

                                    Total score:
                                    {this.getTotalScore(sortedEvidenceList)}

                        :

                            No scored Case Level evidence was found.

                    }

        );
    }
}

GeneDiseaseEvidenceSummaryCaseLevel.propTypes = {
    caseLevelEvidenceList: PropTypes.array,
    hpoTermList: PropTypes.array
};

export default GeneDiseaseEvidenceSummaryCaseLevel;<|endoftext|>


<commit_before>var db = null;

require('mongobuilder').init(CONFIG('database'), function(err, instance) {
	if (err)
		F.error(err);
	db = instance;
	F.emit('database');
});

F.database = function(collection) {
	if (collection)
		return db.collection(collection);
	return db;
};
<commit_msg>Added async waiting for loading database.<commit_after>var db = null;

F.wait('database');

require('mongobuilder').init(CONFIG('database'), function(err, instance) {
	if (err)
		F.error(err);
	db = instance;
	F.emit('database');
	F.wait('database');
});

F.database = function(collection) {
	if (collection)
		return db.collection(collection);
	return db;
};
<|endoftext|>


<commit_before>import CiscoSpark from 'ciscospark'

export default class {
  constructor (user) {
    this.user = user
  }

  _sparkClient = () => {
    this.__sparkClient = this.__sparkClient || this._buildSparkClient()
    return this.__sparkClient
  }

  _buildSparkClient = () => {
    const spark = CiscoSpark.init({
      config: {
        credentials: {
          client_secret: process.env.SPARK_OAUTH__CLIENT_SECRET,
          client_id: process.env.SPARK_OAUTH__CLIENT_ID,
        },
      },
    })

    spark.credentials.set({
      authorization: { // TODO: which of these do we actually need?
        access_token: this.user.accessToken,
        refresh_token: this.user.refreshToken,
        token_type: 'Bearer',
      },
    })

    return spark
  }

  listRooms = () => this._sparkClient().rooms.list().then(({items}) => items)

  listRoomMembers = async (roomId) => {
    const { items } = await this._sparkClient().memberships.list({ roomId })
    return items
  }
}
<commit_msg>Only pass user token in when building spark client<commit_after>import CiscoSpark from 'ciscospark'

export default class {
  constructor (user) {
    this.user = user
  }

  _sparkClient = () => {
    this.__sparkClient = this.__sparkClient || this._buildSparkClient()
    return this.__sparkClient
  }

  _buildSparkClient = () => {
    const spark = CiscoSpark.init({
      authorization: {
        access_token: this.user.accessToken
      }
    })

    return spark
  }

  listRooms = () => this._sparkClient().rooms.list().then(({items}) => items)

  listRoomMembers = async (roomId) => {
    const { items } = await this._sparkClient().memberships.list({ roomId })
    return items
  }
}
<|endoftext|>


<commit_before>import { configureStore, getDefaultMiddleware, isPlain } from '@reduxjs/toolkit'

import rootReducer from '../bundles'
import configureReactors from './configureReactors'
import { createLocalDB, createCryptoStore, createRemoteDB } from './db'
import { proxyFetch, fetchLLSD } from './llsdFetch'

import AvatarName from '../avatarName'

// Create Redux-Store with local db, remote db and more
export default function createStore (preloadedState) {
  const db = createLocalDB()
  const extraArgument = {
    cryptoStore: createCryptoStore(db),
    db,
    remoteDB: createRemoteDB('_users'),
    proxyFetch: null,
    fetchLLSD: null,
    onAvatarLogout: [],
    circuit: null // will be set on login
  }

  const middleware = getDefaultMiddleware({
    thunk: {
      extraArgument
    },
    // Allow Uint8Array (Buffer) and AvatarName to be in actions and the state.
    serializableCheck: {
      isSerializable: value => isPlain(value) ||
        value instanceof Uint8Array ||
        value instanceof AvatarName
    }
  })

  const store = configureStore({
    reducer: rootReducer,
    middleware,
    // enable devTools in development. Please use the Redux DevTools Extension
    // http://extension.remotedev.io/
    devTools: process.env.NODE_ENV !== 'production',
    preloadedState
  })

  extraArgument.proxyFetch = proxyFetch.bind(null, store.getState)
  extraArgument.fetchLLSD = fetchLLSD.bind(null, store.getState)

  if (process.env.NODE_ENV !== 'production') {
    window.devStore = store
    window.localDB = extraArgument.db
    window.remoteDB = extraArgument.remoteDB
    window.cryptoStore = extraArgument.cryptoStore

    if (module.hot) {
      // Enable Webpack hot module replacement for reducers
      module.hot.accept('../bundles', () => {
        store.replaceReducer(rootReducer)
      })
    }
  }

  configureReactors(store)

  return store
}
<commit_msg>refactor(configureStore): split-up createStore for test utils<commit_after>import { configureStore, getDefaultMiddleware, isPlain } from '@reduxjs/toolkit'

import rootReducer from '../bundles'
import configureReactors from './configureReactors'
import { createLocalDB, createCryptoStore, createRemoteDB } from './db'
import { proxyFetch, fetchLLSD } from './llsdFetch'

import AvatarName from '../avatarName'

/**
 * Create Redux-Store with local db, remote db and more.
 */
export default function createStore (preloadedState) {
  const db = createLocalDB()
  const remoteDB = createRemoteDB('_users')

  const extraArgument = createExtraArgument(db, remoteDB)
  const store = createStoreCore(preloadedState, extraArgument)

  extraArgument.proxyFetch = proxyFetch.bind(null, store.getState)
  extraArgument.fetchLLSD = fetchLLSD.bind(null, store.getState)

  configureReactors(store)

  if (process.env.NODE_ENV !== 'production') {
    window.devStore = store
    window.localDB = extraArgument.db
    window.remoteDB = extraArgument.remoteDB
    window.cryptoStore = extraArgument.cryptoStore

    if (module.hot) {
      // Enable Webpack hot module replacement for reducers
      module.hot.accept('../bundles', () => {
        store.replaceReducer(rootReducer)
      })
    }
  }

  return store
}

/**
 * Create the thunk extraArgument.
 * It adds the localDB and remoteDB to it, but does not setup proxyFetch or fetchLLSD.
 */
export function createExtraArgument (localDB, remoteDB) {
  const extraArgument = {
    cryptoStore: createCryptoStore(localDB),
    db: localDB,
    remoteDB,
    proxyFetch: null, // Must be added after the store was created
    fetchLLSD: null, // Must be added after the store was created
    onAvatarLogout: [],
    circuit: null // will be set on login
  }
  return extraArgument
}

/**
 * Core of the store creation.
 */
export function createStoreCore (preloadedState, extraArgument) {
  const middleware = getDefaultMiddleware({
    thunk: {
      extraArgument
    },
    // Allow Uint8Array (Buffer) and AvatarName to be in actions and the state.
    serializableCheck: {
      isSerializable: value => isPlain(value) ||
        value instanceof Uint8Array ||
        value instanceof AvatarName
    }
  })

  const store = configureStore({
    reducer: rootReducer,
    middleware,
    // enable devTools in development. Please use the Redux DevTools Extension
    // http://extension.remotedev.io/
    devTools: process.env.NODE_ENV !== 'production',
    preloadedState
  })

  return store
}
<|endoftext|>


<commit_before>import * as types from '../mutation-types'
import * as d3 from 'd3'

const state = {
  colors: d3.schemeCategory10,
  selectedStat: 1,
  stats: [{
    id: 'mae',
    name: 'Mean Absolute Error',
    url: 'https://en.wikipedia.org/wiki/Mean_absolute_error',
    bestFunc: Math.min
  }, {
    id: 'log',
    name: 'Log Score',
    url: 'https://en.wikipedia.org/wiki/Scoring_rule#Logarithmic_scoring_rule',
    bestFunc: Math.max
  }]
}

// getters
const getters = {
  models: (state, getters, rootState, rootGetters) => {
    return rootState.data[rootGetters['switches/selectedRegion']]
      .seasons[rootGetters['switches/selectedSeason']]
      .models
  },

  modelIds: (state, getters) => getters.models.map(m => m.id),

  modelColors: (state, getters) => {
    return state.colors.filter((color, idx) => idx < getters.models.length)
  },

  modelMeta: (state, getters) => getters.models.map(m => m.meta),

  selectedStat: state => state.selectedStat,

  statAtLast: (state, getters) => getters.selectedStat === state.stats.length - 1,

  statAtFirst: (state, getters) => getters.selectedStat === 0,

  modelStats: (state, getters) => {
    let stats = getters.models.map(m => m.stats)

    let statsMeta = state.stats[getters.selectedStat]

    let output = {}
    // Assume if one model has no stats, no one has
    if (stats[0]) {
      // Formatted stuff
      let keys = ['oneWk', 'twoWk', 'threeWk', 'fourWk']

      output.name = statsMeta.name
      output.url = statsMeta.url
      let data = stats.map(s => s[statsMeta.id])
      output.data = data.map(d => {
        let ob = {}
        keys.forEach(key => {
          ob[key] = {
            value: d[key] ? d[key].toFixed(2) : 'NA',
            best: false
          }
        })
        return ob
      })

      // Apply properties to best item
      // Don't go for it when value is null
      if (data[0]['oneWk']) {
        keys.forEach(key => {
          let perKey = data.map(d => d[key])
          let bestIdx = perKey.indexOf(statsMeta.bestFunc(...perKey))

          output.data[bestIdx][key].best = true
        })
      }

      return output
    } else {
      return null
    }
  }
}
// actions
const actions = {
  statPrevious ({ commit, getters }) {
    if (!getters.statAtFirst) {
      commit(types.UPDATE_SELECTED_STAT, getters.selectedStat - 1)
    }
  },

  statNext ({ commit, getters }) {
    if (!getters.statAtLast) {
      commit(types.UPDATE_SELECTED_STAT, getters.selectedStat + 1)
    }
  }
}

// mutations
const mutations = {
  [types.UPDATE_SELECTED_STAT] (state, val) {
    state.selectedStat = val
  }
}

export default {
  namespaced: true,
  state,
  getters,
  actions,
  mutations
}
<commit_msg>Change 'log score' to 'mean log score'<commit_after>import * as types from '../mutation-types'
import * as d3 from 'd3'

const state = {
  colors: d3.schemeCategory10,
  selectedStat: 1,
  stats: [{
    id: 'mae',
    name: 'Mean Absolute Error',
    url: 'https://en.wikipedia.org/wiki/Mean_absolute_error',
    bestFunc: Math.min
  }, {
    id: 'log',
    name: 'Mean Log Score',
    url: 'https://en.wikipedia.org/wiki/Scoring_rule#Logarithmic_scoring_rule',
    bestFunc: Math.max
  }]
}

// getters
const getters = {
  models: (state, getters, rootState, rootGetters) => {
    return rootState.data[rootGetters['switches/selectedRegion']]
      .seasons[rootGetters['switches/selectedSeason']]
      .models
  },

  modelIds: (state, getters) => getters.models.map(m => m.id),

  modelColors: (state, getters) => {
    return state.colors.filter((color, idx) => idx < getters.models.length)
  },

  modelMeta: (state, getters) => getters.models.map(m => m.meta),

  selectedStat: state => state.selectedStat,

  statAtLast: (state, getters) => getters.selectedStat === state.stats.length - 1,

  statAtFirst: (state, getters) => getters.selectedStat === 0,

  modelStats: (state, getters) => {
    let stats = getters.models.map(m => m.stats)

    let statsMeta = state.stats[getters.selectedStat]

    let output = {}
    // Assume if one model has no stats, no one has
    if (stats[0]) {
      // Formatted stuff
      let keys = ['oneWk', 'twoWk', 'threeWk', 'fourWk']

      output.name = statsMeta.name
      output.url = statsMeta.url
      let data = stats.map(s => s[statsMeta.id])
      output.data = data.map(d => {
        let ob = {}
        keys.forEach(key => {
          ob[key] = {
            value: d[key] ? d[key].toFixed(2) : 'NA',
            best: false
          }
        })
        return ob
      })

      // Apply properties to best item
      // Don't go for it when value is null
      if (data[0]['oneWk']) {
        keys.forEach(key => {
          let perKey = data.map(d => d[key])
          let bestIdx = perKey.indexOf(statsMeta.bestFunc(...perKey))

          output.data[bestIdx][key].best = true
        })
      }

      return output
    } else {
      return null
    }
  }
}
// actions
const actions = {
  statPrevious ({ commit, getters }) {
    if (!getters.statAtFirst) {
      commit(types.UPDATE_SELECTED_STAT, getters.selectedStat - 1)
    }
  },

  statNext ({ commit, getters }) {
    if (!getters.statAtLast) {
      commit(types.UPDATE_SELECTED_STAT, getters.selectedStat + 1)
    }
  }
}

// mutations
const mutations = {
  [types.UPDATE_SELECTED_STAT] (state, val) {
    state.selectedStat = val
  }
}

export default {
  namespaced: true,
  state,
  getters,
  actions,
  mutations
}
<|endoftext|>


<commit_before>/*
Copyright 2017 Vector Creations Ltd
Copyright 2017, 2018 New Vector Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.

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

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import dis from '../dispatcher';
import {Store} from 'flux/utils';
import {MatrixClientPeg} from '../MatrixClientPeg';
import * as sdk from '../index';
import Modal from '../Modal';
import { _t } from '../languageHandler';
import { getCachedRoomIDForAlias, storeRoomAliasInCache } from '../RoomAliasCache';

const INITIAL_STATE = {
    // Whether we're joining the currently viewed room (see isJoining())
    joining: false,
    // Any error that has occurred during joining
    joinError: null,
    // The room ID of the room currently being viewed
    roomId: null,

    // The event to scroll to when the room is first viewed
    initialEventId: null,
    // Whether to highlight the initial event
    isInitialEventHighlighted: false,

    // The room alias of the room (or null if not originally specified in view_room)
    roomAlias: null,
    // Whether the current room is loading
    roomLoading: false,
    // Any error that has occurred during loading
    roomLoadError: null,

    forwardingEvent: null,

    quotingEvent: null,
    matrixClientIsReady: false,
};

/**
 * A class for storing application state for RoomView. This is the RoomView's interface
*  with a subset of the js-sdk.
 *  ```
 */
class RoomViewStore extends Store {
    constructor() {
        super(dis);

        // Initialise state
        this._state = INITIAL_STATE;
        if (MatrixClientPeg.get()) {
            this._state.matrixClientIsReady = MatrixClientPeg.get().isInitialSyncComplete();
        }
    }

    _setState(newState) {
        this._state = Object.assign(this._state, newState);
        this.__emitChange();
    }

    __onDispatch(payload) {
        switch (payload.action) {
            // view_room:
            //      - room_alias:   '#somealias:matrix.org'
            //      - room_id:      '!roomid123:matrix.org'
            //      - event_id:     '$213456782:matrix.org'
            //      - event_offset: 100
            //      - highlighted:  true
            case 'view_room':
                this._viewRoom(payload);
                break;
            case 'view_my_groups':
            case 'view_group':
                this._setState({
                    roomId: null,
                    roomAlias: null,
                });
                break;
            case 'view_room_error':
                this._viewRoomError(payload);
                break;
            case 'will_join':
                this._setState({
                    joining: true,
                });
                break;
            case 'cancel_join':
                this._setState({
                    joining: false,
                });
                break;
            // join_room:
            //      - opts: options for joinRoom
            case 'join_room':
                this._joinRoom(payload);
                break;
            case 'join_room_error':
                this._joinRoomError(payload);
                break;
            case 'on_client_not_viable':
            case 'on_logged_out':
                this.reset();
                break;
            case 'forward_event':
                this._setState({
                    forwardingEvent: payload.event,
                });
                break;
            case 'reply_to_event':
                // If currently viewed room does not match the room in which we wish to reply then change rooms
                // this can happen when performing a search across all rooms
                if (payload.event && payload.event.getRoomId() !== this._state.roomId) {
                    dis.dispatch({
                        action: 'view_room',
                        room_id: payload.event.getRoomId(),
                        replyingToEvent: payload.event,
                    });
                } else {
                    this._setState({
                        replyingToEvent: payload.event,
                    });
                }
                break;
            case 'open_room_settings': {
                const RoomSettingsDialog = sdk.getComponent("dialogs.RoomSettingsDialog");
                Modal.createTrackedDialog('Room settings', '', RoomSettingsDialog, {
                    roomId: payload.room_id || this._state.roomId,
                }, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true);
                break;
            }
            case 'sync_state':
                this._setState({
                    matrixClientIsReady: MatrixClientPeg.get().isInitialSyncComplete(),
                });
                break;
        }
    }

    async _viewRoom(payload) {
        if (payload.room_id) {
            const newState = {
                roomId: payload.room_id,
                roomAlias: payload.room_alias,
                initialEventId: payload.event_id,
                isInitialEventHighlighted: payload.highlighted,
                forwardingEvent: null,
                roomLoading: false,
                roomLoadError: null,
                // should peek by default
                shouldPeek: payload.should_peek === undefined ? true : payload.should_peek,
                // have we sent a join request for this room and are waiting for a response?
                joining: payload.joining || false,
                // Reset replyingToEvent because we don't want cross-room because bad UX
                replyingToEvent: null,
                // pull the user out of Room Settings
                isEditingSettings: false,
            };

            // Allow being given an event to be replied to when switching rooms but sanity check its for this room
            if (payload.replyingToEvent && payload.replyingToEvent.getRoomId() === payload.room_id) {
                newState.replyingToEvent = payload.replyingToEvent;
            }

            if (this._state.forwardingEvent) {
                dis.dispatch({
                    action: 'send_event',
                    room_id: newState.roomId,
                    event: this._state.forwardingEvent,
                });
            }

            this._setState(newState);

            if (payload.auto_join) {
                this._joinRoom(payload);
            }
        } else if (payload.room_alias) {
            // Try the room alias to room ID navigation cache first to avoid
            // blocking room navigation on the homeserver.
            let roomId = getCachedRoomIDForAlias(payload.room_alias);
            if (!roomId) {
                // Room alias cache miss, so let's ask the homeserver. Resolve the alias
                // and then do a second dispatch with the room ID acquired.
                this._setState({
                    roomId: null,
                    initialEventId: null,
                    initialEventPixelOffset: null,
                    isInitialEventHighlighted: null,
                    roomAlias: payload.room_alias,
                    roomLoading: true,
                    roomLoadError: null,
                });
                try {
                    const result = await MatrixClientPeg.get().getRoomIdForAlias(payload.room_alias);
                    storeRoomAliasInCache(payload.room_alias, result.room_id);
                    roomId = result.room_id;
                } catch (err) {
                    dis.dispatch({
                        action: 'view_room_error',
                        room_id: null,
                        room_alias: payload.room_alias,
                        err,
                    });
                    return;
                }
            }

            dis.dispatch({
                action: 'view_room',
                room_id: roomId,
                event_id: payload.event_id,
                highlighted: payload.highlighted,
                room_alias: payload.room_alias,
                auto_join: payload.auto_join,
                oob_data: payload.oob_data,
            });
        }
    }

    _viewRoomError(payload) {
        this._setState({
            roomId: payload.room_id,
            roomAlias: payload.room_alias,
            roomLoading: false,
            roomLoadError: payload.err,
        });
    }

    _joinRoom(payload) {
        this._setState({
            joining: true,
        });
        MatrixClientPeg.get().joinRoom(
            this._state.roomAlias || this._state.roomId, payload.opts,
        ).then(() => {
            // We don't actually need to do anything here: we do *not*
            // clear the 'joining' flag because the Room object and/or
            // our 'joined' member event may not have come down the sync
            // stream yet, and that's the point at which we'd consider
            // the user joined to the room.
        }, (err) => {
            dis.dispatch({
                action: 'join_room_error',
                err: err,
            });
            let msg = err.message ? err.message : JSON.stringify(err);
            // XXX: We are relying on the error message returned by browsers here.
            // This isn't great, but it does generalize the error being shown to users.
            if (msg && msg.startsWith("CORS request rejected")) {
                msg = _t("There was an error joining the room");
            }
            if (err.errcode === 'M_INCOMPATIBLE_ROOM_VERSION') {
                msg = <div>
                    {_t("Sorry, your homeserver is too old to participate in this room.")}<br />
                    {_t("Please contact your homeserver administrator.")}
                </div>;
            }
            const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
            Modal.createTrackedDialog('Failed to join room', '', ErrorDialog, {
                title: _t("Failed to join room"),
                description: msg,
            });
        });
    }

    _joinRoomError(payload) {
        this._setState({
            joining: false,
            joinError: payload.err,
        });
    }

    reset() {
        this._state = Object.assign({}, INITIAL_STATE);
    }

    // The room ID of the room currently being viewed
    getRoomId() {
        return this._state.roomId;
    }

    // The event to scroll to when the room is first viewed
    getInitialEventId() {
        return this._state.initialEventId;
    }

    // Whether to highlight the initial event
    isInitialEventHighlighted() {
        return this._state.isInitialEventHighlighted;
    }

    // The room alias of the room (or null if not originally specified in view_room)
    getRoomAlias() {
        return this._state.roomAlias;
    }

    // Whether the current room is loading (true whilst resolving an alias)
    isRoomLoading() {
        return this._state.roomLoading;
    }

    // Any error that has occurred during loading
    getRoomLoadError() {
        return this._state.roomLoadError;
    }

    // True if we're expecting the user to be joined to the room currently being
    // viewed. Note that this is left true after the join request has finished,
    // since we should still consider a join to be in progress until the room
    // & member events come down the sync.
    //
    // This flag remains true after the room has been sucessfully joined,
    // (this store doesn't listen for the appropriate member events)
    // so you should always observe the joined state from the member event
    // if a room object is present.
    // ie. The correct logic is:
    // if (room) {
    //     if (myMember.membership == 'joined') {
    //         // user is joined to the room
    //     } else {
    //         // Not joined
    //     }
    // } else {
    //     if (RoomViewStore.isJoining()) {
    //         // show spinner
    //     } else {
    //         // show join prompt
    //     }
    // }
    isJoining() {
        return this._state.joining;
    }

    // Any error that has occurred during joining
    getJoinError() {
        return this._state.joinError;
    }

    // The mxEvent if one is about to be forwarded
    getForwardingEvent() {
        return this._state.forwardingEvent;
    }

    // The mxEvent if one is currently being replied to/quoted
    getQuotingEvent() {
        return this._state.replyingToEvent;
    }

    shouldPeek() {
        return this._state.shouldPeek && this._state.matrixClientIsReady;
    }
}

let singletonRoomViewStore = null;
if (!singletonRoomViewStore) {
    singletonRoomViewStore = new RoomViewStore();
}
export default singletonRoomViewStore;
<commit_msg>Only emit in RoomViewStore when state actually changes<commit_after>/*
Copyright 2017 Vector Creations Ltd
Copyright 2017, 2018 New Vector Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.

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

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import dis from '../dispatcher';
import {Store} from 'flux/utils';
import {MatrixClientPeg} from '../MatrixClientPeg';
import * as sdk from '../index';
import Modal from '../Modal';
import { _t } from '../languageHandler';
import { getCachedRoomIDForAlias, storeRoomAliasInCache } from '../RoomAliasCache';

const INITIAL_STATE = {
    // Whether we're joining the currently viewed room (see isJoining())
    joining: false,
    // Any error that has occurred during joining
    joinError: null,
    // The room ID of the room currently being viewed
    roomId: null,

    // The event to scroll to when the room is first viewed
    initialEventId: null,
    // Whether to highlight the initial event
    isInitialEventHighlighted: false,

    // The room alias of the room (or null if not originally specified in view_room)
    roomAlias: null,
    // Whether the current room is loading
    roomLoading: false,
    // Any error that has occurred during loading
    roomLoadError: null,

    forwardingEvent: null,

    quotingEvent: null,
    matrixClientIsReady: false,
};

/**
 * A class for storing application state for RoomView. This is the RoomView's interface
*  with a subset of the js-sdk.
 *  ```
 */
class RoomViewStore extends Store {
    constructor() {
        super(dis);

        // Initialise state
        this._state = INITIAL_STATE;
        if (MatrixClientPeg.get()) {
            this._state.matrixClientIsReady = MatrixClientPeg.get().isInitialSyncComplete();
        }
    }

    _setState(newState) {
        // If values haven't changed, there's nothing to do.
        // This only tries a shallow comparison, so unchanged objects will slip
        // through, but that's probably okay for now.
        let stateChanged = false;
        for (const key of Object.keys(newState)) {
            if (this._state[key] !== newState[key]) {
                stateChanged = true;
                break;
            }
        }
        if (!stateChanged) {
            return;
        }

        this._state = Object.assign(this._state, newState);
        this.__emitChange();
    }

    __onDispatch(payload) {
        switch (payload.action) {
            // view_room:
            //      - room_alias:   '#somealias:matrix.org'
            //      - room_id:      '!roomid123:matrix.org'
            //      - event_id:     '$213456782:matrix.org'
            //      - event_offset: 100
            //      - highlighted:  true
            case 'view_room':
                this._viewRoom(payload);
                break;
            case 'view_my_groups':
            case 'view_group':
                this._setState({
                    roomId: null,
                    roomAlias: null,
                });
                break;
            case 'view_room_error':
                this._viewRoomError(payload);
                break;
            case 'will_join':
                this._setState({
                    joining: true,
                });
                break;
            case 'cancel_join':
                this._setState({
                    joining: false,
                });
                break;
            // join_room:
            //      - opts: options for joinRoom
            case 'join_room':
                this._joinRoom(payload);
                break;
            case 'join_room_error':
                this._joinRoomError(payload);
                break;
            case 'on_client_not_viable':
            case 'on_logged_out':
                this.reset();
                break;
            case 'forward_event':
                this._setState({
                    forwardingEvent: payload.event,
                });
                break;
            case 'reply_to_event':
                // If currently viewed room does not match the room in which we wish to reply then change rooms
                // this can happen when performing a search across all rooms
                if (payload.event && payload.event.getRoomId() !== this._state.roomId) {
                    dis.dispatch({
                        action: 'view_room',
                        room_id: payload.event.getRoomId(),
                        replyingToEvent: payload.event,
                    });
                } else {
                    this._setState({
                        replyingToEvent: payload.event,
                    });
                }
                break;
            case 'open_room_settings': {
                const RoomSettingsDialog = sdk.getComponent("dialogs.RoomSettingsDialog");
                Modal.createTrackedDialog('Room settings', '', RoomSettingsDialog, {
                    roomId: payload.room_id || this._state.roomId,
                }, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true);
                break;
            }
            case 'sync_state':
                this._setState({
                    matrixClientIsReady: MatrixClientPeg.get().isInitialSyncComplete(),
                });
                break;
        }
    }

    async _viewRoom(payload) {
        if (payload.room_id) {
            const newState = {
                roomId: payload.room_id,
                roomAlias: payload.room_alias,
                initialEventId: payload.event_id,
                isInitialEventHighlighted: payload.highlighted,
                forwardingEvent: null,
                roomLoading: false,
                roomLoadError: null,
                // should peek by default
                shouldPeek: payload.should_peek === undefined ? true : payload.should_peek,
                // have we sent a join request for this room and are waiting for a response?
                joining: payload.joining || false,
                // Reset replyingToEvent because we don't want cross-room because bad UX
                replyingToEvent: null,
                // pull the user out of Room Settings
                isEditingSettings: false,
            };

            // Allow being given an event to be replied to when switching rooms but sanity check its for this room
            if (payload.replyingToEvent && payload.replyingToEvent.getRoomId() === payload.room_id) {
                newState.replyingToEvent = payload.replyingToEvent;
            }

            if (this._state.forwardingEvent) {
                dis.dispatch({
                    action: 'send_event',
                    room_id: newState.roomId,
                    event: this._state.forwardingEvent,
                });
            }

            this._setState(newState);

            if (payload.auto_join) {
                this._joinRoom(payload);
            }
        } else if (payload.room_alias) {
            // Try the room alias to room ID navigation cache first to avoid
            // blocking room navigation on the homeserver.
            let roomId = getCachedRoomIDForAlias(payload.room_alias);
            if (!roomId) {
                // Room alias cache miss, so let's ask the homeserver. Resolve the alias
                // and then do a second dispatch with the room ID acquired.
                this._setState({
                    roomId: null,
                    initialEventId: null,
                    initialEventPixelOffset: null,
                    isInitialEventHighlighted: null,
                    roomAlias: payload.room_alias,
                    roomLoading: true,
                    roomLoadError: null,
                });
                try {
                    const result = await MatrixClientPeg.get().getRoomIdForAlias(payload.room_alias);
                    storeRoomAliasInCache(payload.room_alias, result.room_id);
                    roomId = result.room_id;
                } catch (err) {
                    dis.dispatch({
                        action: 'view_room_error',
                        room_id: null,
                        room_alias: payload.room_alias,
                        err,
                    });
                    return;
                }
            }

            dis.dispatch({
                action: 'view_room',
                room_id: roomId,
                event_id: payload.event_id,
                highlighted: payload.highlighted,
                room_alias: payload.room_alias,
                auto_join: payload.auto_join,
                oob_data: payload.oob_data,
            });
        }
    }

    _viewRoomError(payload) {
        this._setState({
            roomId: payload.room_id,
            roomAlias: payload.room_alias,
            roomLoading: false,
            roomLoadError: payload.err,
        });
    }

    _joinRoom(payload) {
        this._setState({
            joining: true,
        });
        MatrixClientPeg.get().joinRoom(
            this._state.roomAlias || this._state.roomId, payload.opts,
        ).then(() => {
            // We don't actually need to do anything here: we do *not*
            // clear the 'joining' flag because the Room object and/or
            // our 'joined' member event may not have come down the sync
            // stream yet, and that's the point at which we'd consider
            // the user joined to the room.
        }, (err) => {
            dis.dispatch({
                action: 'join_room_error',
                err: err,
            });
            let msg = err.message ? err.message : JSON.stringify(err);
            // XXX: We are relying on the error message returned by browsers here.
            // This isn't great, but it does generalize the error being shown to users.
            if (msg && msg.startsWith("CORS request rejected")) {
                msg = _t("There was an error joining the room");
            }
            if (err.errcode === 'M_INCOMPATIBLE_ROOM_VERSION') {
                msg = <div>
                    {_t("Sorry, your homeserver is too old to participate in this room.")}<br />
                    {_t("Please contact your homeserver administrator.")}
                </div>;
            }
            const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
            Modal.createTrackedDialog('Failed to join room', '', ErrorDialog, {
                title: _t("Failed to join room"),
                description: msg,
            });
        });
    }

    _joinRoomError(payload) {
        this._setState({
            joining: false,
            joinError: payload.err,
        });
    }

    reset() {
        this._state = Object.assign({}, INITIAL_STATE);
    }

    // The room ID of the room currently being viewed
    getRoomId() {
        return this._state.roomId;
    }

    // The event to scroll to when the room is first viewed
    getInitialEventId() {
        return this._state.initialEventId;
    }

    // Whether to highlight the initial event
    isInitialEventHighlighted() {
        return this._state.isInitialEventHighlighted;
    }

    // The room alias of the room (or null if not originally specified in view_room)
    getRoomAlias() {
        return this._state.roomAlias;
    }

    // Whether the current room is loading (true whilst resolving an alias)
    isRoomLoading() {
        return this._state.roomLoading;
    }

    // Any error that has occurred during loading
    getRoomLoadError() {
        return this._state.roomLoadError;
    }

    // True if we're expecting the user to be joined to the room currently being
    // viewed. Note that this is left true after the join request has finished,
    // since we should still consider a join to be in progress until the room
    // & member events come down the sync.
    //
    // This flag remains true after the room has been sucessfully joined,
    // (this store doesn't listen for the appropriate member events)
    // so you should always observe the joined state from the member event
    // if a room object is present.
    // ie. The correct logic is:
    // if (room) {
    //     if (myMember.membership == 'joined') {
    //         // user is joined to the room
    //     } else {
    //         // Not joined
    //     }
    // } else {
    //     if (RoomViewStore.isJoining()) {
    //         // show spinner
    //     } else {
    //         // show join prompt
    //     }
    // }
    isJoining() {
        return this._state.joining;
    }

    // Any error that has occurred during joining
    getJoinError() {
        return this._state.joinError;
    }

    // The mxEvent if one is about to be forwarded
    getForwardingEvent() {
        return this._state.forwardingEvent;
    }

    // The mxEvent if one is currently being replied to/quoted
    getQuotingEvent() {
        return this._state.replyingToEvent;
    }

    shouldPeek() {
        return this._state.shouldPeek && this._state.matrixClientIsReady;
    }
}

let singletonRoomViewStore = null;
if (!singletonRoomViewStore) {
    singletonRoomViewStore = new RoomViewStore();
}
export default singletonRoomViewStore;
<|endoftext|>