<commit_before>define(['backbone', 'underscore', 'channels', 'mixin', 'rivetView', 'viewContext'], function (Backbone, _, channels, mixin, rivetView, ViewContext) {

    var BaseView = Backbone.View.extend({
        options : {
            name : 'BaseView',
            appendView : true,
            ModelType : undefined,
            bindings : [
                // Example: [stringObjectToListenTo, stringEventName, stringCallbackFunction]
                //          ['model', 'change:something', 'callbackFunction']
                // Bindings have to be all strings, since config does not have access to the view's context
                // if strings are provided it is assumed that the context is the view
            ],
            templateHtml : undefined,
            modelData : undefined,
            rivetConfig : undefined
        },
        defaultBindings : [],
        initialize : initialize,
        start : start,
        render : render,
        dataToJSON : dataToJSON,
        bindEventListeners : bindEventListeners,
        remove : remove,
        children: null,
        addChild: addChild,
        removeChild: removeChild

        // Dynamically created, so the cache is not shared on the prototype:
        // elementCache: elementCache
    });

    BaseView.beforeRenderDone = 'beforeRenderDone';
    BaseView.renderDone = 'renderDone';
    BaseView.afterRenderDone = 'afterRenderDone';

    // Share channels among all Views
    BaseView.prototype.channels = BaseView.prototype.channels || channels;

    return BaseView;

    function initialize (options) {
        var modelData,
            self = this;

        this.options = _.extend({}, this.options, options);

        var ModelType = this.options.ModelType || Backbone.Model;

        this.elementCache = _.memoize(elementCache);
        if (this.options.templateHtml) {
            this.template = _.template(this.options.templateHtml);
        }

        if(!this.model) {
            modelData = this.options.modelData;
            _.each(modelData, function(datum, key) {
                if (datum instanceof ViewContext) {
                    modelData[key] = datum.getBoundFunction(self);
                }
            });
            this.model = new ModelType(this.options.modelData);
        } else {
            this.model = options.model;
        }

        if (this.options.bindings) {
            this.bindEventListeners(this.options.bindings);
        }

        if ('auto' === this.options.rivetConfig) {
            this.model.set('viewId', this.cid);
            this.domEl = this.cid;
            this.rivetView = rivetView({
                rivetScope : '#' + this.cid,
                rivetPrefix : 'rv'
            })
        } else if (this.options.rivetConfig) {
            this.rivetView = rivetView({
                rivetScope : this.options.rivetConfig.scope,
                rivetPrefix : this.options.rivetConfig.prefix,
                instaUpdateRivets : (this.options.rivetConfig.instaUpdateRivets ? true : false)
            })
        }

        this.children = [];
    }

    /**
     * Wrapper method for lifecycle methods.
     *
     * In order, this method:
     * - Calls this.beforeRender()
     * - Starts any child views
     * - Notifies that beforeRender is done
     * - If the view has a parent, waits for its parent to render
     * - Calls this.render()
     * - Notifies that render is done
     * - Calls this.afterRender()
     * - Notifies that afterRender is done
     * - Resolves the returned promise
     *
     * @param {jQuery.promise} $parentRenderPromise - If passed in, the start method was called from a parent view start() method.
     * @returns {jQuery.promise} A promise that is resolved when when the start method has completed
     */
    function start ($parentRenderPromise) {
        var self = this,
            $deferred = new $.Deferred(),
            $beforeRenderDeferred = _runLifeCycleMethod.call(this, this.beforeRender, 'BeforeRender');

        // ParentView calls .start() on all children
        // ParentView doesn't render until all children have notified that they are done
        // After rendering, the ParentView notifies all children and they continue their lifecycle
        _.defer(function () {
            $
                .when(
                    $beforeRenderDeferred
                )
                .always(function () {
                    $deferred.notify(BaseView.beforeRenderDone);
                })
                .then(function () {
                    if ($parentRenderPromise) {
                        return $parentRenderPromise;
                    }
                })
                .then(
                function () {
                    var $renderDeferred = _runLifeCycleMethod.call(self, self.render, 'Render');
                    $
                        .when(
                            $renderDeferred
                        )
                        .always(function () {
                            $deferred.notify(BaseView.renderDone);
                        })
                        .then(
                        function () {
                            var $afterRenderDeferred = _runLifeCycleMethod.call(self, self.afterRender, 'AfterRender');
                            $
                                .when(
                                    $afterRenderDeferred,
                                    startChildren.call(self, $deferred)
                                )
                                .always(function () {
                                    $deferred.notify(BaseView.afterRenderDone);
                                })
                                .then(
                                    _resolveStart.call(self, $deferred),
                                    _rejectStart.call(self, $deferred)
                                );
                        },
                        _rejectStart.call(self, $deferred)
                    );
                },
                _rejectStart.call(self, $deferred));
        });

        return $deferred.promise();
    }

    function startChildren ($parentDeferred) {;
        _(this.children).each(function (child) {
            var $afterRenderDeferred = new $.Deferred();

            $parentDeferred.progress(function (step) {
                if (step === BaseView.renderDone) {
                    $afterRenderDeferred.resolve();
                }
            });

            child.start($afterRenderDeferred.promise());
        });
    }

    function render () {
        if (this.$el && this.template) {
            if (this.options.appendView) {
                this.$el.append(this.template(this.dataToJSON()));
                this.setElement(this.$el.children().last());
            } else {
                this.$el.html(this.template(this.dataToJSON()));
            }
        }
    }

    // This function is memoized in initialize
    function elementCache (selector) {
        console.log(selector);
        return this.$el.find(selector);
    }

    function dataToJSON () {
        return this.model ? this.model.toJSON() : {};
    }

    /**
     * bindEventListeners
     * Bind all event listeners specified in 'defaultListeners' and 'options.listeners' using 'listenTo'
     *
     * @param (Array[Array]) listenerArray - A collection of arrays of arguments that will be used with 'Backbone.Events.listenTo'
     *
     * @example:
     *      bindEventListeners([['myModel', 'change:something', 'myCallbackFunction']]);
     *
     * @remarks
     * Passing in an array with a string as the first parameter will attempt to bind to this[firstArgument] so that
     * it is possible to listen to view properties that have not yet been instantiated (i.e. viewModels)
     */
    function bindEventListeners (listenerArray) {
        var self = this,
            listenerArgs;

        this.stopListening();

        listenerArgs = _.map(listenerArray.concat(this.defaultBindings), function (argsArray) {

            // Since the view config object doesn't have access to the view's context, we must provide it
            _.each([argsArray[0], argsArray[1] , argsArray[2]], function (arg, index) {
                if (_.isString(arg) && index != 1) {
                    argsArray[index] = _getProperty(self, arg);
                } else if (index == 1) {
                    argsArray[index] = arg;
                }
            });

            return argsArray;
        });

        // TODO: test that duplicate items will pick the bindings from options, throwing out defaults
        listenerArray = _.uniq(listenerArgs, function (a, b) {
            return _.identity(a);
        });

        _.each(listenerArray, function (listenerArgs) {
            self.listenTo.apply(self, listenerArgs);
        });
    }

    // --------------------------
    // Private Methods

    /**
     * Life cycle methods have an event triggered before the run.
     * If a life cycle method has one or more arguments, then the first argument passed in is its deferred.
     * The life cycle method will automatically return this deferred, otherwise it will pass through whatever
     * the method itself returns.
     *
     * @param lifeCycleMethod
     * @param lifeCycleMethodName
     * @returns {*}
     * @private
     */
    function _runLifeCycleMethod (lifeCycleMethod, lifeCycleMethodName) {
        if (!lifeCycleMethod) {
            return undefined;
        }

        return mixin({}, lifeCycleMethod)({
            async : lifeCycleMethod.length,
            preEvent : {
                methodName : lifeCycleMethodName,
                name : this.options.name + ':pre' + lifeCycleMethodName,
                channel : this.channels.views
            },
            postEvent : {
                methodName : lifeCycleMethodName,
                name : this.options.name + ':post' + lifeCycleMethodName,
                channel : this.channels.views
            }
        }).call(this);
    }

    /**
     * A convenience wrapper for creating life cycle method references.
     * @param lifeCycleMethod
     * @param lifeCycleMethodName
     * @returns {*}
     * @private
     */
    function _lifeCycleMethodReference (lifeCycleMethod, lifeCycleMethodName) {
        return function () {
            return _runLifeCycleMethod.call(this, lifeCycleMethod, lifeCycleMethodName);
        }.bind(this);
    }

    function _resolveStart ($deferred) {
        return function () {
            $deferred.resolve();
        }.bind(this);
    }

    function _rejectStart ($deferred) {
        return function () {
            $deferred.reject();
        }.bind(this);
    }

    function _getProperty (obj, parts, create) {
        if (typeof parts === 'string') {
            parts = parts.split('.');
        }

        var part;
        while (typeof obj === 'object' && obj && parts.length) {
            part = parts.shift();
            if (!(part in obj) && create) {
                obj[part] = {};
            }
            obj = obj[part];
        }

        return obj;
    }

    function remove () {
        _(this.children).each(function (child) {
            child.remove();
        });
        Backbone.View.prototype.remove.apply(this, arguments);
    }

    function addChild(childView) {
        if (!_(this.children).contains(childView)) {
            this.children.push(childView);
        }
    }

    function removeChild(childView) {
        this.children = _(this.children).without(childView);
    }
});
<commit_msg>Minor Deletion. Stray semi-colon<commit_after>define(['backbone', 'underscore', 'channels', 'mixin', 'rivetView', 'viewContext'], function (Backbone, _, channels, mixin, rivetView, ViewContext) {

    var BaseView = Backbone.View.extend({
        options : {
            name : 'BaseView',
            appendView : true,
            ModelType : undefined,
            bindings : [
                // Example: [stringObjectToListenTo, stringEventName, stringCallbackFunction]
                //          ['model', 'change:something', 'callbackFunction']
                // Bindings have to be all strings, since config does not have access to the view's context
                // if strings are provided it is assumed that the context is the view
            ],
            templateHtml : undefined,
            modelData : undefined,
            rivetConfig : undefined
        },
        defaultBindings : [],
        initialize : initialize,
        start : start,
        render : render,
        dataToJSON : dataToJSON,
        bindEventListeners : bindEventListeners,
        remove : remove,
        children: null,
        addChild: addChild,
        removeChild: removeChild

        // Dynamically created, so the cache is not shared on the prototype:
        // elementCache: elementCache
    });

    BaseView.beforeRenderDone = 'beforeRenderDone';
    BaseView.renderDone = 'renderDone';
    BaseView.afterRenderDone = 'afterRenderDone';

    // Share channels among all Views
    BaseView.prototype.channels = BaseView.prototype.channels || channels;

    return BaseView;

    function initialize (options) {
        var modelData,
            self = this;

        this.options = _.extend({}, this.options, options);

        var ModelType = this.options.ModelType || Backbone.Model;

        this.elementCache = _.memoize(elementCache);
        if (this.options.templateHtml) {
            this.template = _.template(this.options.templateHtml);
        }

        if(!this.model) {
            modelData = this.options.modelData;
            _.each(modelData, function(datum, key) {
                if (datum instanceof ViewContext) {
                    modelData[key] = datum.getBoundFunction(self);
                }
            });
            this.model = new ModelType(this.options.modelData);
        } else {
            this.model = options.model;
        }

        if (this.options.bindings) {
            this.bindEventListeners(this.options.bindings);
        }

        if ('auto' === this.options.rivetConfig) {
            this.model.set('viewId', this.cid);
            this.domEl = this.cid;
            this.rivetView = rivetView({
                rivetScope : '#' + this.cid,
                rivetPrefix : 'rv'
            })
        } else if (this.options.rivetConfig) {
            this.rivetView = rivetView({
                rivetScope : this.options.rivetConfig.scope,
                rivetPrefix : this.options.rivetConfig.prefix,
                instaUpdateRivets : (this.options.rivetConfig.instaUpdateRivets ? true : false)
            })
        }

        this.children = [];
    }

    /**
     * Wrapper method for lifecycle methods.
     *
     * In order, this method:
     * - Calls this.beforeRender()
     * - Starts any child views
     * - Notifies that beforeRender is done
     * - If the view has a parent, waits for its parent to render
     * - Calls this.render()
     * - Notifies that render is done
     * - Calls this.afterRender()
     * - Notifies that afterRender is done
     * - Resolves the returned promise
     *
     * @param {jQuery.promise} $parentRenderPromise - If passed in, the start method was called from a parent view start() method.
     * @returns {jQuery.promise} A promise that is resolved when when the start method has completed
     */
    function start ($parentRenderPromise) {
        var self = this,
            $deferred = new $.Deferred(),
            $beforeRenderDeferred = _runLifeCycleMethod.call(this, this.beforeRender, 'BeforeRender');

        // ParentView calls .start() on all children
        // ParentView doesn't render until all children have notified that they are done
        // After rendering, the ParentView notifies all children and they continue their lifecycle
        _.defer(function () {
            $
                .when(
                    $beforeRenderDeferred
                )
                .always(function () {
                    $deferred.notify(BaseView.beforeRenderDone);
                })
                .then(function () {
                    if ($parentRenderPromise) {
                        return $parentRenderPromise;
                    }
                })
                .then(
                function () {
                    var $renderDeferred = _runLifeCycleMethod.call(self, self.render, 'Render');
                    $
                        .when(
                            $renderDeferred
                        )
                        .always(function () {
                            $deferred.notify(BaseView.renderDone);
                        })
                        .then(
                        function () {
                            var $afterRenderDeferred = _runLifeCycleMethod.call(self, self.afterRender, 'AfterRender');
                            $
                                .when(
                                    $afterRenderDeferred,
                                    startChildren.call(self, $deferred)
                                )
                                .always(function () {
                                    $deferred.notify(BaseView.afterRenderDone);
                                })
                                .then(
                                    _resolveStart.call(self, $deferred),
                                    _rejectStart.call(self, $deferred)
                                );
                        },
                        _rejectStart.call(self, $deferred)
                    );
                },
                _rejectStart.call(self, $deferred));
        });

        return $deferred.promise();
    }

    function startChildren ($parentDeferred) {
        _(this.children).each(function (child) {
            var $afterRenderDeferred = new $.Deferred();

            $parentDeferred.progress(function (step) {
                if (step === BaseView.renderDone) {
                    $afterRenderDeferred.resolve();
                }
            });

            child.start($afterRenderDeferred.promise());
        });
    }

    function render () {
        if (this.$el && this.template) {
            if (this.options.appendView) {
                this.$el.append(this.template(this.dataToJSON()));
                this.setElement(this.$el.children().last());
            } else {
                this.$el.html(this.template(this.dataToJSON()));
            }
        }
    }

    // This function is memoized in initialize
    function elementCache (selector) {
        console.log(selector);
        return this.$el.find(selector);
    }

    function dataToJSON () {
        return this.model ? this.model.toJSON() : {};
    }

    /**
     * bindEventListeners
     * Bind all event listeners specified in 'defaultListeners' and 'options.listeners' using 'listenTo'
     *
     * @param (Array[Array]) listenerArray - A collection of arrays of arguments that will be used with 'Backbone.Events.listenTo'
     *
     * @example:
     *      bindEventListeners([['myModel', 'change:something', 'myCallbackFunction']]);
     *
     * @remarks
     * Passing in an array with a string as the first parameter will attempt to bind to this[firstArgument] so that
     * it is possible to listen to view properties that have not yet been instantiated (i.e. viewModels)
     */
    function bindEventListeners (listenerArray) {
        var self = this,
            listenerArgs;

        this.stopListening();

        listenerArgs = _.map(listenerArray.concat(this.defaultBindings), function (argsArray) {

            // Since the view config object doesn't have access to the view's context, we must provide it
            _.each([argsArray[0], argsArray[1] , argsArray[2]], function (arg, index) {
                if (_.isString(arg) && index != 1) {
                    argsArray[index] = _getProperty(self, arg);
                } else if (index == 1) {
                    argsArray[index] = arg;
                }
            });

            return argsArray;
        });

        // TODO: test that duplicate items will pick the bindings from options, throwing out defaults
        listenerArray = _.uniq(listenerArgs, function (a, b) {
            return _.identity(a);
        });

        _.each(listenerArray, function (listenerArgs) {
            self.listenTo.apply(self, listenerArgs);
        });
    }

    // --------------------------
    // Private Methods

    /**
     * Life cycle methods have an event triggered before the run.
     * If a life cycle method has one or more arguments, then the first argument passed in is its deferred.
     * The life cycle method will automatically return this deferred, otherwise it will pass through whatever
     * the method itself returns.
     *
     * @param lifeCycleMethod
     * @param lifeCycleMethodName
     * @returns {*}
     * @private
     */
    function _runLifeCycleMethod (lifeCycleMethod, lifeCycleMethodName) {
        if (!lifeCycleMethod) {
            return undefined;
        }

        return mixin({}, lifeCycleMethod)({
            async : lifeCycleMethod.length,
            preEvent : {
                methodName : lifeCycleMethodName,
                name : this.options.name + ':pre' + lifeCycleMethodName,
                channel : this.channels.views
            },
            postEvent : {
                methodName : lifeCycleMethodName,
                name : this.options.name + ':post' + lifeCycleMethodName,
                channel : this.channels.views
            }
        }).call(this);
    }

    /**
     * A convenience wrapper for creating life cycle method references.
     * @param lifeCycleMethod
     * @param lifeCycleMethodName
     * @returns {*}
     * @private
     */
    function _lifeCycleMethodReference (lifeCycleMethod, lifeCycleMethodName) {
        return function () {
            return _runLifeCycleMethod.call(this, lifeCycleMethod, lifeCycleMethodName);
        }.bind(this);
    }

    function _resolveStart ($deferred) {
        return function () {
            $deferred.resolve();
        }.bind(this);
    }

    function _rejectStart ($deferred) {
        return function () {
            $deferred.reject();
        }.bind(this);
    }

    function _getProperty (obj, parts, create) {
        if (typeof parts === 'string') {
            parts = parts.split('.');
        }

        var part;
        while (typeof obj === 'object' && obj && parts.length) {
            part = parts.shift();
            if (!(part in obj) && create) {
                obj[part] = {};
            }
            obj = obj[part];
        }

        return obj;
    }

    function remove () {
        _(this.children).each(function (child) {
            child.remove();
        });
        Backbone.View.prototype.remove.apply(this, arguments);
    }

    function addChild(childView) {
        if (!_(this.children).contains(childView)) {
            this.children.push(childView);
        }
    }

    function removeChild(childView) {
        this.children = _(this.children).without(childView);
    }
});
<|endoftext|>


<commit_before>import PropTypes from "prop-types";
import {connect} from 'react-redux';
import React, {Component} from 'react';
import {withRouter} from "react-router-dom";
import routes from '../routes';
import Login from '../components/Login';
import Layout from "../components/Layout";
import {DEFAULT_HOST} from '../constants';
import {getQueryToken, stripQueryToken} from '../utils/utils';

import {
  authenticate, fetchCredentials, logout,
  processes as processesAction,
  versions as versionsAction,
  plugins as pluginsAction,
  changeTheme, fetchTheme
} from '../actions';

import {LIGHT_THEME, DARK_THEME} from '../constants';

import { getCredentials, getAuthenticationError, getProcesses, getTheme } from '../reducers/selectors';

class AppContainer extends Component {
  queryStringAuthenticate() {
    if (this.props.credentials.authenticating) {
      return;
    }

    const token = getQueryToken(this.props.lcation);

    if (!token) {
      return;
    }
    const host = process.env.NODE_ENV === 'development' ? DEFAULT_HOST : window.location.host;
    if (token === this.props.credentials.token && this.props.credentials.host === host) {
      return;
    }
    return this.props.authenticate(host, token);
  }

  componentDidMount() {
    this.props.fetchCredentials();
    this.props.fetchTheme();
  }

  requireAuthentication() {
    return !(this.props.credentials.authenticating ||
             this.props.credentials.authenticated) &&
      this.props.credentials.token &&
      this.props.credentials.host;
  }

  componentDidUpdate(){
    if (!this.queryStringAuthenticate() && this.requireAuthentication()) {
      this.props.authenticate(this.props.credentials.host, this.props.credentials.token);
    }

    if (getQueryToken(this.props.location) &&
        (!this.props.credentials.authenticating ||
         this.props.credentials.authenticated)) {
      this.props.history.replace(stripQueryToken(this.props.location));
    }

    if (this.props.credentials.authenticated && !this.props.initialized) {
      this.props.fetchProcesses();
      this.props.fetchServices();
      this.props.fetchPlugins();
    }
  }

  shouldRenderLogin() {
    return this.props.authenticationError ||
      !(this.props.credentials.authenticated || this.props.credentials.authenticating);
  }

  toggleTheme() {
    if (this.props.theme === LIGHT_THEME) {
      this.props.changeTheme(DARK_THEME);
    } else {
      this.props.changeTheme(LIGHT_THEME);
    }
  }

  renderBody() {
    if (this.shouldRenderLogin()) {
      return <Login credentials={this.props.credentials} authenticate={this.props.authenticate} error={this.props.authenticationError} />;
    } else if (this.props.credentials.authenticating) {
      return <React.Fragment/>;
    }
    return (
      <Layout location={this.props.location}
              logout={this.props.logout}
              toggleTheme={() => this.toggleTheme()}
              currentTheme={this.props.theme}>
        <React.Fragment>{routes}</React.Fragment>
      </Layout>
    );
  }

  render() {
    return
{this.renderBody()}
;
  }
}

AppContainer.propTypes = {
  credentials: PropTypes.object,
  initialized: PropTypes.bool,
  authenticationError: PropTypes.string,
  authenticate: PropTypes.func,
  logout: PropTypes.func,
  fetchCredentials: PropTypes.func,
  initBlockHeader: PropTypes.func,
  fetchProcesses: PropTypes.func,
  fetchServices: PropTypes.func,
  fetchPlugins: PropTypes.func,
  fetchVersions: PropTypes.func,
  location: PropTypes.object,
  theme: PropTypes.string,
  changeTheme: PropTypes.func,
  fetchTheme: PropTypes.func,
};

function mapStateToProps(state) {
  return {
    initialized: getProcesses(state).length > 0,
    credentials: getCredentials(state),
    authenticationError: getAuthenticationError(state),
    theme: getTheme(state),
  };
}

export default withRouter(connect(
  mapStateToProps,
  {
    authenticate: authenticate.request,
    logout: logout.request,
    fetchCredentials: fetchCredentials.request,
    fetchProcesses: processesAction.request,
    fetchServices: processesAction.request,
    fetchVersions: versionsAction.request,
    fetchPlugins: pluginsAction.request,
    changeTheme: changeTheme.request,
    fetchTheme: fetchTheme.request
  },
)(AppContainer));
<commit_msg>formatting<commit_after>import PropTypes from "prop-types";
import {connect} from 'react-redux';
import React, {Component} from 'react';
import {withRouter} from "react-router-dom";
import routes from '../routes';
import Login from '../components/Login';
import Layout from "../components/Layout";
import {DEFAULT_HOST} from '../constants';
import {getQueryToken, stripQueryToken} from '../utils/utils';

import {
  authenticate, fetchCredentials, logout,
  processes as processesAction,
  versions as versionsAction,
  plugins as pluginsAction,
  changeTheme, fetchTheme
} from '../actions';

import {LIGHT_THEME, DARK_THEME} from '../constants';

import {
  getCredentials, getAuthenticationError, getProcesses, getTheme
} from '../reducers/selectors';

class AppContainer extends Component {
  queryStringAuthenticate() {
    if (this.props.credentials.authenticating) {
      return;
    }

    const token = getQueryToken(this.props.lcation);

    if (!token) {
      return;
    }
    const host = process.env.NODE_ENV === 'development' ? DEFAULT_HOST : window.location.host;
    if (token === this.props.credentials.token && this.props.credentials.host === host) {
      return;
    }
    return this.props.authenticate(host, token);
  }

  componentDidMount() {
    this.props.fetchCredentials();
    this.props.fetchTheme();
  }

  requireAuthentication() {
    return !(this.props.credentials.authenticating ||
             this.props.credentials.authenticated) &&
      this.props.credentials.token &&
      this.props.credentials.host;
  }

  componentDidUpdate(){
    if (!this.queryStringAuthenticate() && this.requireAuthentication()) {
      this.props.authenticate(this.props.credentials.host, this.props.credentials.token);
    }

    if (getQueryToken(this.props.location) &&
        (!this.props.credentials.authenticating ||
         this.props.credentials.authenticated)) {
      this.props.history.replace(stripQueryToken(this.props.location));
    }

    if (this.props.credentials.authenticated && !this.props.initialized) {
      this.props.fetchProcesses();
      this.props.fetchServices();
      this.props.fetchPlugins();
    }
  }

  shouldRenderLogin() {
    return this.props.authenticationError ||
      !(this.props.credentials.authenticated || this.props.credentials.authenticating);
  }

  toggleTheme() {
    if (this.props.theme === LIGHT_THEME) {
      this.props.changeTheme(DARK_THEME);
    } else {
      this.props.changeTheme(LIGHT_THEME);
    }
  }

  renderBody() {
    if (this.shouldRenderLogin()) {
      return (
          <Login credentials={this.props.credentials}
                 authenticate={this.props.authenticate}
                 error={this.props.authenticationError} />
      );
    } else if (this.props.credentials.authenticating) {
      return <React.Fragment/>;
    }
    return (
      <Layout location={this.props.location}
              logout={this.props.logout}
              toggleTheme={() => this.toggleTheme()}
              currentTheme={this.props.theme}>
        <React.Fragment>{routes}</React.Fragment>
      </Layout>
    );
  }

  render() {
    return
{this.renderBody()}
;
  }
}

AppContainer.propTypes = {
  credentials: PropTypes.object,
  initialized: PropTypes.bool,
  authenticationError: PropTypes.string,
  authenticate: PropTypes.func,
  logout: PropTypes.func,
  fetchCredentials: PropTypes.func,
  initBlockHeader: PropTypes.func,
  fetchProcesses: PropTypes.func,
  fetchServices: PropTypes.func,
  fetchPlugins: PropTypes.func,
  fetchVersions: PropTypes.func,
  location: PropTypes.object,
  theme: PropTypes.string,
  changeTheme: PropTypes.func,
  fetchTheme: PropTypes.func,
};

function mapStateToProps(state) {
  return {
    initialized: getProcesses(state).length > 0,
    credentials: getCredentials(state),
    authenticationError: getAuthenticationError(state),
    theme: getTheme(state),
  };
}

export default withRouter(connect(
  mapStateToProps,
  {
    authenticate: authenticate.request,
    logout: logout.request,
    fetchCredentials: fetchCredentials.request,
    fetchProcesses: processesAction.request,
    fetchServices: processesAction.request,
    fetchVersions: versionsAction.request,
    fetchPlugins: pluginsAction.request,
    changeTheme: changeTheme.request,
    fetchTheme: fetchTheme.request
  },
)(AppContainer));
<|endoftext|>


<commit_before>var setEditorialVoteEventListeners = function() {
    $(document).on('click', '.love-editorial', function() {
        var $this = $(this),
            $loveCount = $($this.siblings()[0]),
            $heartIcon = $this.children()[0];
        if ($heartIcon.classList.contains('red-text')) {
            $.web2py.flash('Already voted the editorial');
        } else {
            if (isLoggedIn === false) {
                $.web2py.flash('Please login to cast your vote');
            } else {
                $.ajax({
                    url: loveEditorialURL + '/' + $(this).data()['id'],
                    method: 'POST',
                    success: function(response) {
                        $loveCount.html(response['love_count']);
                        $heartIcon.classList.add('red-text');
                        $.web2py.flash('Vote submitted');
                    },
                    error: function(response) {
                        if (response.status === 401) {
                            $.web2py.flash('Please login to cast your vote');
                        } else {
                            $.web2py.flash('Error submitting your vote');
                        }
                    }
                });
            }
        }
    });
};

var initTooltips = function() {
    $('.tooltipped').tooltip({
        delay: 50
    });
};

(function($) {
    "use strict";

    /* Handle the case of single digit in a time stamp */
    var formatTimeStamp = function(num) {
        var strnum = num.toString();

        return strnum.length == 1 ? '0' + strnum : strnum;
    };

    /* Transform the timestamps from IST to client browser timestamp */
    var transformTimestamps = function() {
        var clientOffset = new Date().getTimezoneOffset() * 60 * 1000;
        var ISTOffset = -330 * 60 * 1000;
        var convertedTimestamp, ISTTimestamp, d;

        $('.stopstalk-timestamp').each(function(i, td) {
            ISTTimestamp = new Date(td.textContent.replace(/-/g, '/')).getTime();
            d = new Date(ISTTimestamp + ISTOffset - clientOffset);
            convertedTimestamp = [d.getFullYear(),
                d.getMonth() + 1,
                d.getDate()
            ].map(formatTimeStamp).join('-') + " " + [d.getHours(),
                d.getMinutes(),
                d.getSeconds()
            ].map(formatTimeStamp).join(':');
            $(this).html(convertedTimestamp);
        });
    };

    /* Download a submission as a file */
    var downloadSubmission = function(fileName, text) {
        var element = document.createElement('a');

        element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
        element.setAttribute('download', fileName);
        element.style.display = 'none';
        document.body.appendChild(element);
        element.click();
        document.body.removeChild(element);
    };

    /* Copy the code to the clipboard */
    var copyToClipBoard = function(copyText) {
        var textField = document.createElement('textarea');

        textField.innerHTML = copyText;
        document.body.appendChild(textField);
        textField.select();
        document.execCommand("copy");
        textField.remove();

        $.web2py.flash("Copied to Clipboard");
    };

    /* Escape characters in html to be representable as string */
    var htmlifySubmission = function(solutionCode) {
        return solutionCode.replace(/&/g, "&")
            .replace(/>/g, ">")
            .replace(/</g, "<")
            .replace(/"/g, """).trim(' ');
    };

    /* Get a url parameter by the key from a string url */
    var getParameterByName = function (name, url) {
        if (!url) {
          url = window.location.href;
        }
        name = name.replace(/[\[\]]/g, "\\$&");
        var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
            results = regex.exec(url);
        if (!results) return null;
        if (!results[2]) return '';
        return decodeURIComponent(results[2].replace(/\+/g, " "));
    };

    var markPulseButtonClick = function(elementID, key) {
        if (isLoggedIn && !clickedButton[key]) {
            $.ajax({
                url: markReadURL,
                data: {key: key},
                success: function() {
                    clickedButton[key] = true;
                    $('#' + elementID).removeClass('pulse');
                }
            });
        }
    };

    var problemDifficultyResponseHandler = function(response) {
        if(response["score"]) $(".difficulty-list-item input[value='" + response["score"] + "']").prop("checked", true);
        $("#problem-difficulty-modal-form").attr("data-problem", response["problem_id"]);
    };

    var getNextProblem = function(explicitClick, problemId) {
        explicitClick = explicitClick || false;
        problemId = problemId || null;

        if(explicitClick) $('#problem-difficulty-modal-form').trigger('reset');

        $.ajax({
            url: getNextProblemURL,
            method: 'GET',
            data: {problem_id: problemId},
            success: function(response) {
                if(response["result"] == "all_caught") {
                    $('#problem-difficulty-actual-content').addClass("hide");
                    $('#problem-difficulty-all-caught-up').removeClass("hide");
                } else {
                    $('#problem-difficulty-actual-content').removeClass("hide");
                    $('#problem-difficulty-all-caught-up').addClass("hide");
                    $('#problem-difficulty-title').html("How difficult is " + response["plink"] + "?");
                    problemDifficultyResponseHandler(response);
                }
                $('#problem-difficulty-modal').modal('open');
                problemDifficultyModalOpen = true;
            },
            error: function(e) {
                console.log("Failed to get the next problem", e);
            }
        });
    };

    var openProblemDifficultyModal = function(explicitClick, problemId) {
        var cacheValue = localStorage.getItem("lastShowedProblemDifficulty");
        if (!isLoggedIn ||
            (cacheValue &&
             (Date.now() - cacheValue < 72 * 60 * 60 * 1000) && !explicitClick)) {
            // Modal showed less than 72 hours before;
            return;
        }

        getNextProblem(explicitClick, problemId);
    };

    var initProblemDifficultySubmitHandler = function() {
        $(document).on("change", "input[type=radio][name=problem_difficulty_value]", function() {
            var $thisForm = $('#problem-difficulty-modal-form'),
                $thisTitle = $('#problem-difficulty-title'),
                $thisProblemLink = $("#problem-details-link");

            $.ajax({
                method: 'POST',
                url: problemDifficultySubmitURL + '.json',
                data: {
                    "score":  $("input[name='problem_difficulty_value']:checked").val(),
                    "problem_id": $("#problem-difficulty-modal-form").attr("data-problem")
                },
                success: function(response) {
                    if(response["result"] == "all_caught") {
                        $('#problem-difficulty-actual-content').addClass("hide");
                        $('#problem-difficulty-all-caught-up').removeClass("hide");
                        return;
                    }
                    setTimeout(function() {
                        $('#problem-difficulty-actual-content').removeClass("hide");
                        $('#problem-difficulty-all-caught-up').addClass("hide");
                        problemDifficultyResponseHandler(response);
                        $('#problem-difficulty-modal-submit-button').val('Submit');
                        $('#problem-difficulty-modal-submit-button').removeClass('disabled');

                        $thisForm.trigger('reset');

                        $thisForm.fadeOut(function() {
                            $thisForm.fadeIn();
                        });

                        $thisTitle.fadeOut(function() {
                            $thisTitle.html("How difficult is " + response["plink"] + "?");
                            $thisTitle.fadeIn();
                        });
                    }, 100);
                },
                error: function(err) {
                    console.log(err);
                }
            });
            e.preventDefault();
        });
    };

    $(document).ready(function() {

        var $viewDownloadButton = $('#final-view-download-button'),
            $downloadButton = $('#final-download-button'),
            $downloadModal = $('#download-submission-modal'),
            $viewFileName = $('#view_download_file_name'),
            $viewPreLoader = $('#view-submission-preloader'),
            $viewPre = $('#view-submission-pre'),
            $viewModal = $('#view-submission-modal'),
            $linkToSite = $('#link-to-site');

        transformTimestamps();

        $("#welcome a").on('touchend', function(){
            window.location.href = $(this).attr('href');
        });

        $('.collapsible').collapsible({
            accordion: false // A setting that changes the collapsible behavior to expandable instead of the default accordion style
        });

        $('select').material_select();

        $('#talenthub-launch-modal').modal({
            dismissible: true,
            opacity: 0.8,
            complete: function() {
                showReczeeTalenthubModal = "False";
                $.ajax({
                    url: markReadURL,
                    data: {key: "talenthub"}
                });
            }
        });

        if (showReczeeTalenthubModal === "True") {
            $('#talenthub-launch-modal').modal('open');
        }

        $('#problem-difficulty-modal').modal({
            dismissible: true,
            complete: function() {
                localStorage.setItem("lastShowedProblemDifficulty", Date.now());
                problemDifficultyModalOpen = false;
            }
        });

        $(document).on('click', '#problem-difficulty-title .problem-listing', function() {
            localStorage.setItem("lastShowedProblemDifficulty", Date.now());
        });

        $(document).on('click', '#skip-this-problem', function() {
            getNextProblem(true);
        });

        initTooltips();

        // if(loggedInUserId < thresholdUserId)  openProblemDifficultyModal();

        initProblemDifficultySubmitHandler();

        $(document).on('click', '#explain-problem-difficulty', function() {
            if (!isLoggedIn) {
                $.web2py.flash("Login to suggest problem difficulty!");
                return;
            } else {
                showProblemDifficultyOnboarding = "False";
                openProblemDifficultyModal(true);
                $.ajax({
                    url: markReadURL,
                    data: {key: "problem_difficulty"}
                });
            }
        });

        $(document).on('click', '#problem-page-difficulty-button', function() {
            openProblemDifficultyModal(true, problemId);
            $("#problem-difficulty-modal-form").attr("data-problem", problemId);
        });

        $('#open-side-nav').click(function() {
            if (typeof ga !== 'undefined') {
                ga('send', {
                    hitType: 'event',
                    eventCategory: 'button',
                    eventAction: 'click',
                    eventLabel: 'Open Side Navbar'
                });
            }
        });

        $('#open-side-nav').sideNav();

        // Remove focus from any focused element
        if (document.activeElement) {
            document.activeElement.blur();
        }

        var todoTrSelectors = ".submissions-table tr," +
                              ".user-editorials-table tr," +
                              "#problem-setter-page-table tr," +
                              "#problem-response tr," +
                              ".trendings-html-table tr," +
                              ".todo-list-icon";

        $(document).on('mouseenter', todoTrSelectors, function() {
            var todoIcon = $(this).find('.add-to-todo-list');
            todoIcon.css("display", "inline-flex");
        });

        $(document).on('mouseleave', todoTrSelectors, function() {
            var todoIcon = $(this).find('.add-to-todo-list');
            todoIcon.hide();
        });

        $(document).on('click', '.add-to-todo-list', function() {
            var stopstalkLink = this.parentElement.firstChild["href"],
                problemLink = getParameterByName("plink", stopstalkLink),
                thisElement = this,
                $thisElement = $(this),
                problemId = $thisElement.data()["pid"];
            $.ajax({
                url: addTodoURL,
                method: 'POST',
                data: {pid: problemId},
                success: function(response) {
                    var tooltipID = thisElement.getAttribute("data-tooltip-id");
                    $thisElement.remove();
                    $('#' + tooltipID).remove();
                    $.web2py.flash(response);
                },
                error: function(e) {
                    $.web2py.flash("Some error occurred");
                }
            });
        });

        $(document).on('click', '.delete-editorial', function() {
            var result = confirm("Are you sure you want to DELETE the editorial ?")
            if(!result) return;
            var $this = $(this);
            $.ajax({
                url: deleteEditorialURL + '/' + $this.data('id'),
                method: 'POST',
                success: function(response) {
                    if (response === "SUCCESS") {
                        $this.parent().parent().fadeOut();
                        $.web2py.flash("Editorial deleted successfully!");
                    } else {
                        $.web2py.flash("Can't delete accepted Editorial!");
                    }
                },
                error: function(err) {
                    $.web2py.flash("Something went wrong!");
                }
            });
        });

        $(document).on('click', '.view-submission-button', function() {
            var site = $(this).data('site');
            var viewLink = $(this).data('view-link');

            var onViewModalClose = function() {
                $viewDownloadButton.addClass('disabled');
                $viewFileName.val('');
                $viewPreLoader.removeClass('hide');
                $viewPre.addClass('hide');
                $viewPre.removeClass('prettyprint');
                $viewPre.removeClass('prettyprinted');
                $viewPre.html('');
                $('#copy-to-clipboard').addClass('hide');
                $linkToSite.html('');
                $linkToSite.attr('href', '');
            };

            $linkToSite.html('View on ' + site);
            $linkToSite.attr('href', viewLink);

            $viewModal.modal({
                complete: onViewModalClose
            });

            $viewModal.modal('open');

            $.ajax({
                method: 'GET',
                url: '/default/download_submission',
                data: {
                    site: site,
                    viewLink: viewLink
                }
            }).done(function(response) {
                var solutionText;

                $viewPreLoader.addClass('hide');
                $viewPre.removeClass('hide');

                $('#copy-to-clipboard').removeClass('hide');

                if (response != -1) {
                    solutionText = htmlifySubmission(response);
                } else {
                    solutionText = "// Unable to retrieve submission from " + site + "\n" + "/* Possible reasons :-\n\t * " + site + " is down\n\t * The submission is from an ongoing contest\n\t * There was some error from our side. \n\t   Please write to us (https://www.stopstalk.com/contact_us)\n */";
                }

                $viewPre.html(solutionText);
                $viewModal.one('click', '#copy-to-clipboard', function() {
                    if (response != -1) {
                        copyToClipBoard(response);
                    } else {
                        copyToClipBoard(solutionText);
                    }
                });

                $viewPre.addClass('prettyprint');
                PR.prettyPrint();
                if (response != -1) {
                    $viewDownloadButton.removeClass('disabled');
                    $viewFileName.on('keydown', function() {
                        if (event.which == 13) {
                            $('#final-view-download-button').trigger('click');
                        }
                    });

                    $(document).one('click', '#final-view-download-button', function() {
                        var fileName = $viewFileName.val();
                        if (fileName) {
                            downloadSubmission(fileName, response);
                            $viewModal.modal('close');
                            onViewModalClose();
                        } else {
                            $.web2py.flash("Please enter a file name");
                        }
                    });
                } else {
                    $.web2py.flash("Unable to Download");
                }
            });
        });

        $(document).on('click', '#heart-button', function() {
            markPulseButtonClick('heart-button', 'heart_button');
        });

        $(document).on('click', '#onboarding-button', function() {
            markPulseButtonClick('onboarding-button', 'onboarding_button');
        });

        $(document).on('click', '.download-submission-button', function() {
            var site = $(this).data('site');
            var viewLink = $(this).data('view-link');

            var onDownloadModalClose = function() {
                /* Callback function on Modal close */
                $downloadButton.addClass('disabled');
                $('#file_name').val('');
            };

            $downloadModal.modal({
                complete: onDownloadModalClose
            });

            $downloadModal.modal('open');

            $.ajax({
                method: 'GET',
                url: '/default/download_submission',
                data: {
                    site: site,
                    viewLink: viewLink
                }
            }).done(function(response) {
                if (response != -1) {
                    $downloadButton.removeClass('disabled');
                    $('#file_name').on('keydown', function() {
                        if (event.which == 13) {
                            $('#final-download-button').trigger('click');
                        }
                    });

                    $(document).one('click', '#final-download-button', function() {
                        var fileName = $('#file_name').val();
                        if (fileName) {
                            downloadSubmission(fileName, response);
                            $downloadModal.modal('close');
                            onDownloadModalClose();
                        } else {
                            $.web2py.flash("Please enter a file name");
                        }
                    });
                } else {
                    $.web2py.flash("Unable to Download");
                }
            });
        });
    });
})(jQuery);
<commit_msg>dont show modal to new users<commit_after>var setEditorialVoteEventListeners = function() {
    $(document).on('click', '.love-editorial', function() {
        var $this = $(this),
            $loveCount = $($this.siblings()[0]),
            $heartIcon = $this.children()[0];
        if ($heartIcon.classList.contains('red-text')) {
            $.web2py.flash('Already voted the editorial');
        } else {
            if (isLoggedIn === false) {
                $.web2py.flash('Please login to cast your vote');
            } else {
                $.ajax({
                    url: loveEditorialURL + '/' + $(this).data()['id'],
                    method: 'POST',
                    success: function(response) {
                        $loveCount.html(response['love_count']);
                        $heartIcon.classList.add('red-text');
                        $.web2py.flash('Vote submitted');
                    },
                    error: function(response) {
                        if (response.status === 401) {
                            $.web2py.flash('Please login to cast your vote');
                        } else {
                            $.web2py.flash('Error submitting your vote');
                        }
                    }
                });
            }
        }
    });
};

var initTooltips = function() {
    $('.tooltipped').tooltip({
        delay: 50
    });
};

(function($) {
    "use strict";

    /* Handle the case of single digit in a time stamp */
    var formatTimeStamp = function(num) {
        var strnum = num.toString();

        return strnum.length == 1 ? '0' + strnum : strnum;
    };

    /* Transform the timestamps from IST to client browser timestamp */
    var transformTimestamps = function() {
        var clientOffset = new Date().getTimezoneOffset() * 60 * 1000;
        var ISTOffset = -330 * 60 * 1000;
        var convertedTimestamp, ISTTimestamp, d;

        $('.stopstalk-timestamp').each(function(i, td) {
            ISTTimestamp = new Date(td.textContent.replace(/-/g, '/')).getTime();
            d = new Date(ISTTimestamp + ISTOffset - clientOffset);
            convertedTimestamp = [d.getFullYear(),
                d.getMonth() + 1,
                d.getDate()
            ].map(formatTimeStamp).join('-') + " " + [d.getHours(),
                d.getMinutes(),
                d.getSeconds()
            ].map(formatTimeStamp).join(':');
            $(this).html(convertedTimestamp);
        });
    };

    /* Download a submission as a file */
    var downloadSubmission = function(fileName, text) {
        var element = document.createElement('a');

        element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
        element.setAttribute('download', fileName);
        element.style.display = 'none';
        document.body.appendChild(element);
        element.click();
        document.body.removeChild(element);
    };

    /* Copy the code to the clipboard */
    var copyToClipBoard = function(copyText) {
        var textField = document.createElement('textarea');

        textField.innerHTML = copyText;
        document.body.appendChild(textField);
        textField.select();
        document.execCommand("copy");
        textField.remove();

        $.web2py.flash("Copied to Clipboard");
    };

    /* Escape characters in html to be representable as string */
    var htmlifySubmission = function(solutionCode) {
        return solutionCode.replace(/&/g, "&")
            .replace(/>/g, ">")
            .replace(/</g, "<")
            .replace(/"/g, """).trim(' ');
    };

    /* Get a url parameter by the key from a string url */
    var getParameterByName = function (name, url) {
        if (!url) {
          url = window.location.href;
        }
        name = name.replace(/[\[\]]/g, "\\$&");
        var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
            results = regex.exec(url);
        if (!results) return null;
        if (!results[2]) return '';
        return decodeURIComponent(results[2].replace(/\+/g, " "));
    };

    var markPulseButtonClick = function(elementID, key) {
        if (isLoggedIn && !clickedButton[key]) {
            $.ajax({
                url: markReadURL,
                data: {key: key},
                success: function() {
                    clickedButton[key] = true;
                    $('#' + elementID).removeClass('pulse');
                }
            });
        }
    };

    var problemDifficultyResponseHandler = function(response) {
        if(response["score"]) $(".difficulty-list-item input[value='" + response["score"] + "']").prop("checked", true);
        $("#problem-difficulty-modal-form").attr("data-problem", response["problem_id"]);
    };

    var getNextProblem = function(explicitClick, problemId) {
        explicitClick = explicitClick || false;
        problemId = problemId || null;

        if(explicitClick) $('#problem-difficulty-modal-form').trigger('reset');

        $.ajax({
            url: getNextProblemURL,
            method: 'GET',
            data: {problem_id: problemId},
            success: function(response) {
                if(response["result"] == "all_caught") {
                    $('#problem-difficulty-actual-content').addClass("hide");
                    $('#problem-difficulty-all-caught-up').removeClass("hide");
                } else {
                    $('#problem-difficulty-actual-content').removeClass("hide");
                    $('#problem-difficulty-all-caught-up').addClass("hide");
                    $('#problem-difficulty-title').html("How difficult is " + response["plink"] + "?");
                    problemDifficultyResponseHandler(response);
                }
                $('#problem-difficulty-modal').modal('open');
                problemDifficultyModalOpen = true;
            },
            error: function(e) {
                console.log("Failed to get the next problem", e);
            }
        });
    };

    var openProblemDifficultyModal = function(explicitClick, problemId) {
        var cacheValue = localStorage.getItem("lastShowedProblemDifficulty");
        if (!isLoggedIn ||
            (cacheValue &&
             (Date.now() - cacheValue < 72 * 60 * 60 * 1000) && !explicitClick)) {
            // Modal showed less than 72 hours before;
            return;
        }

        getNextProblem(explicitClick, problemId);
    };

    var initProblemDifficultySubmitHandler = function() {
        $(document).on("change", "input[type=radio][name=problem_difficulty_value]", function() {
            var $thisForm = $('#problem-difficulty-modal-form'),
                $thisTitle = $('#problem-difficulty-title'),
                $thisProblemLink = $("#problem-details-link");

            $.ajax({
                method: 'POST',
                url: problemDifficultySubmitURL + '.json',
                data: {
                    "score":  $("input[name='problem_difficulty_value']:checked").val(),
                    "problem_id": $("#problem-difficulty-modal-form").attr("data-problem")
                },
                success: function(response) {
                    if(response["result"] == "all_caught") {
                        $('#problem-difficulty-actual-content').addClass("hide");
                        $('#problem-difficulty-all-caught-up').removeClass("hide");
                        return;
                    }
                    setTimeout(function() {
                        $('#problem-difficulty-actual-content').removeClass("hide");
                        $('#problem-difficulty-all-caught-up').addClass("hide");
                        problemDifficultyResponseHandler(response);
                        $('#problem-difficulty-modal-submit-button').val('Submit');
                        $('#problem-difficulty-modal-submit-button').removeClass('disabled');

                        $thisForm.trigger('reset');

                        $thisForm.fadeOut(function() {
                            $thisForm.fadeIn();
                        });

                        $thisTitle.fadeOut(function() {
                            $thisTitle.html("How difficult is " + response["plink"] + "?");
                            $thisTitle.fadeIn();
                        });
                    }, 100);
                },
                error: function(err) {
                    console.log(err);
                }
            });
            e.preventDefault();
        });
    };

    $(document).ready(function() {

        var $viewDownloadButton = $('#final-view-download-button'),
            $downloadButton = $('#final-download-button'),
            $downloadModal = $('#download-submission-modal'),
            $viewFileName = $('#view_download_file_name'),
            $viewPreLoader = $('#view-submission-preloader'),
            $viewPre = $('#view-submission-pre'),
            $viewModal = $('#view-submission-modal'),
            $linkToSite = $('#link-to-site');

        transformTimestamps();

        $("#welcome a").on('touchend', function(){
            window.location.href = $(this).attr('href');
        });

        $('.collapsible').collapsible({
            accordion: false // A setting that changes the collapsible behavior to expandable instead of the default accordion style
        });

        $('select').material_select();

        $('#talenthub-launch-modal').modal({
            dismissible: true,
            opacity: 0.8,
            complete: function() {
                showReczeeTalenthubModal = "False";
                $.ajax({
                    url: markReadURL,
                    data: {key: "talenthub"}
                });
            }
        });

        if (loggedInUserId < thresholdUserId && showReczeeTalenthubModal === "True") {
            $('#talenthub-launch-modal').modal('open');
        }

        $('#problem-difficulty-modal').modal({
            dismissible: true,
            complete: function() {
                localStorage.setItem("lastShowedProblemDifficulty", Date.now());
                problemDifficultyModalOpen = false;
            }
        });

        $(document).on('click', '#problem-difficulty-title .problem-listing', function() {
            localStorage.setItem("lastShowedProblemDifficulty", Date.now());
        });

        $(document).on('click', '#skip-this-problem', function() {
            getNextProblem(true);
        });

        initTooltips();

        // if(loggedInUserId < thresholdUserId)  openProblemDifficultyModal();

        initProblemDifficultySubmitHandler();

        $(document).on('click', '#explain-problem-difficulty', function() {
            if (!isLoggedIn) {
                $.web2py.flash("Login to suggest problem difficulty!");
                return;
            } else {
                showProblemDifficultyOnboarding = "False";
                openProblemDifficultyModal(true);
                $.ajax({
                    url: markReadURL,
                    data: {key: "problem_difficulty"}
                });
            }
        });

        $(document).on('click', '#problem-page-difficulty-button', function() {
            openProblemDifficultyModal(true, problemId);
            $("#problem-difficulty-modal-form").attr("data-problem", problemId);
        });

        $('#open-side-nav').click(function() {
            if (typeof ga !== 'undefined') {
                ga('send', {
                    hitType: 'event',
                    eventCategory: 'button',
                    eventAction: 'click',
                    eventLabel: 'Open Side Navbar'
                });
            }
        });

        $('#open-side-nav').sideNav();

        // Remove focus from any focused element
        if (document.activeElement) {
            document.activeElement.blur();
        }

        var todoTrSelectors = ".submissions-table tr," +
                              ".user-editorials-table tr," +
                              "#problem-setter-page-table tr," +
                              "#problem-response tr," +
                              ".trendings-html-table tr," +
                              ".todo-list-icon";

        $(document).on('mouseenter', todoTrSelectors, function() {
            var todoIcon = $(this).find('.add-to-todo-list');
            todoIcon.css("display", "inline-flex");
        });

        $(document).on('mouseleave', todoTrSelectors, function() {
            var todoIcon = $(this).find('.add-to-todo-list');
            todoIcon.hide();
        });

        $(document).on('click', '.add-to-todo-list', function() {
            var stopstalkLink = this.parentElement.firstChild["href"],
                problemLink = getParameterByName("plink", stopstalkLink),
                thisElement = this,
                $thisElement = $(this),
                problemId = $thisElement.data()["pid"];
            $.ajax({
                url: addTodoURL,
                method: 'POST',
                data: {pid: problemId},
                success: function(response) {
                    var tooltipID = thisElement.getAttribute("data-tooltip-id");
                    $thisElement.remove();
                    $('#' + tooltipID).remove();
                    $.web2py.flash(response);
                },
                error: function(e) {
                    $.web2py.flash("Some error occurred");
                }
            });
        });

        $(document).on('click', '.delete-editorial', function() {
            var result = confirm("Are you sure you want to DELETE the editorial ?")
            if(!result) return;
            var $this = $(this);
            $.ajax({
                url: deleteEditorialURL + '/' + $this.data('id'),
                method: 'POST',
                success: function(response) {
                    if (response === "SUCCESS") {
                        $this.parent().parent().fadeOut();
                        $.web2py.flash("Editorial deleted successfully!");
                    } else {
                        $.web2py.flash("Can't delete accepted Editorial!");
                    }
                },
                error: function(err) {
                    $.web2py.flash("Something went wrong!");
                }
            });
        });

        $(document).on('click', '.view-submission-button', function() {
            var site = $(this).data('site');
            var viewLink = $(this).data('view-link');

            var onViewModalClose = function() {
                $viewDownloadButton.addClass('disabled');
                $viewFileName.val('');
                $viewPreLoader.removeClass('hide');
                $viewPre.addClass('hide');
                $viewPre.removeClass('prettyprint');
                $viewPre.removeClass('prettyprinted');
                $viewPre.html('');
                $('#copy-to-clipboard').addClass('hide');
                $linkToSite.html('');
                $linkToSite.attr('href', '');
            };

            $linkToSite.html('View on ' + site);
            $linkToSite.attr('href', viewLink);

            $viewModal.modal({
                complete: onViewModalClose
            });

            $viewModal.modal('open');

            $.ajax({
                method: 'GET',
                url: '/default/download_submission',
                data: {
                    site: site,
                    viewLink: viewLink
                }
            }).done(function(response) {
                var solutionText;

                $viewPreLoader.addClass('hide');
                $viewPre.removeClass('hide');

                $('#copy-to-clipboard').removeClass('hide');

                if (response != -1) {
                    solutionText = htmlifySubmission(response);
                } else {
                    solutionText = "// Unable to retrieve submission from " + site + "\n" + "/* Possible reasons :-\n\t * " + site + " is down\n\t * The submission is from an ongoing contest\n\t * There was some error from our side. \n\t   Please write to us (https://www.stopstalk.com/contact_us)\n */";
                }

                $viewPre.html(solutionText);
                $viewModal.one('click', '#copy-to-clipboard', function() {
                    if (response != -1) {
                        copyToClipBoard(response);
                    } else {
                        copyToClipBoard(solutionText);
                    }
                });

                $viewPre.addClass('prettyprint');
                PR.prettyPrint();
                if (response != -1) {
                    $viewDownloadButton.removeClass('disabled');
                    $viewFileName.on('keydown', function() {
                        if (event.which == 13) {
                            $('#final-view-download-button').trigger('click');
                        }
                    });

                    $(document).one('click', '#final-view-download-button', function() {
                        var fileName = $viewFileName.val();
                        if (fileName) {
                            downloadSubmission(fileName, response);
                            $viewModal.modal('close');
                            onViewModalClose();
                        } else {
                            $.web2py.flash("Please enter a file name");
                        }
                    });
                } else {
                    $.web2py.flash("Unable to Download");
                }
            });
        });

        $(document).on('click', '#heart-button', function() {
            markPulseButtonClick('heart-button', 'heart_button');
        });

        $(document).on('click', '#onboarding-button', function() {
            markPulseButtonClick('onboarding-button', 'onboarding_button');
        });

        $(document).on('click', '.download-submission-button', function() {
            var site = $(this).data('site');
            var viewLink = $(this).data('view-link');

            var onDownloadModalClose = function() {
                /* Callback function on Modal close */
                $downloadButton.addClass('disabled');
                $('#file_name').val('');
            };

            $downloadModal.modal({
                complete: onDownloadModalClose
            });

            $downloadModal.modal('open');

            $.ajax({
                method: 'GET',
                url: '/default/download_submission',
                data: {
                    site: site,
                    viewLink: viewLink
                }
            }).done(function(response) {
                if (response != -1) {
                    $downloadButton.removeClass('disabled');
                    $('#file_name').on('keydown', function() {
                        if (event.which == 13) {
                            $('#final-download-button').trigger('click');
                        }
                    });

                    $(document).one('click', '#final-download-button', function() {
                        var fileName = $('#file_name').val();
                        if (fileName) {
                            downloadSubmission(fileName, response);
                            $downloadModal.modal('close');
                            onDownloadModalClose();
                        } else {
                            $.web2py.flash("Please enter a file name");
                        }
                    });
                } else {
                    $.web2py.flash("Unable to Download");
                }
            });
        });
    });
})(jQuery);
<|endoftext|>


<commit_before>require(["jquery"], function ($) {

  console.log('dropins.');

  var dbChooseOptions = {
    success: function(files) {
      // name, link, bytes, icon, thumbnailLink
      $('#message').load( files[0].link, function () {
        onMessageChange();
      });
    },
    cancel: function() {

    },
    linkType: "direct", // or "direct"
    multiselect: false, // or true
    extensions: ['.md', '.txt', '.markdown', '.rsa'],
  };

  $('#dbChooseFile').click( function () {
    if( Dropbox.isBrowserSupported() )
      Dropbox.choose( dbChooseOptions );
  });

  $('#dbSaveFile').click( function () {
    if( Dropbox.isBrowserSupported() )
      Dropbox.save("http://google.com", "google.txt");
  });

});
<commit_msg>Update dropins.js<commit_after>require(["jquery"], function ($) {
  "use strict";
  console.log('dropins.');

  var dbChooseOptions = {
    success: function(files) {
      // name, link, bytes, icon, thumbnailLink
      $('#message').load( files[0].link, function () {
        onMessageChange();
      });
    },
    cancel: function() {

    },
    linkType: "direct", // or "direct"
    multiselect: false, // or true
    extensions: ['.md', '.txt', '.markdown', '.rsa'],
  };

  $('#dbChooseFile').click( function () {
    if( Dropbox.isBrowserSupported() )
      Dropbox.choose( dbChooseOptions );
  });

  $('#dbSaveFile').click( function () {
    if( Dropbox.isBrowserSupported() )
      Dropbox.save("http://google.com", "google.txt");
  });

});
<|endoftext|>


<commit_before>/* json-hierarchy.js - v1.0.0.20190910
Dependencies:
    d3.js ^ v5
Copyright (c) 2019 taurenshaman
*/

var D3Mate = {
    hierarchyData: null,
    tip: null,
    svg: null,
    g: null,

    tree: null,
    zoom: null
}

var JsonHierarchy = {
    // 参数
    svgContainer: null, // 存放svg的div，如果为null，则自己在body中append svg
    width: 960,
    height: 600,
    iconWidth: 30,
	iconHeight: 40,

    maxLabelWidth: 250,
    transitionDuration: 750,
    transitionEase: 'cubic-in-out',
    minRadius: 5,
    scalingFactor: 2,

    callbackAfterProcess: null,

    convertItem: function(key, item){
        let node = {};
        node.title = key;
        if (typeof item === 'object'){ // null, array, object
            if(Array.isArray(item)){
                node.children = this.arrayToList(item);
            }
            else if(item === null){
                node.title = key;
                node.description = key;
            }
            else{
                node.children = this.objToList(item);
            }
        }
        else if (typeof item === 'undefined'){
            node.title = key;
            node.description = key;
        }
        else if (typeof item === 'string'){
            node.title = key;
            node.description = key;
            node.children = this.valueToList(item);
        }
        else { // number/bigint/boolean/...
            node.title = key;
            node.description = key;
            node.children = this.valueToList(item);
        }
        return node;
    },

    valueToList: function(item) {
        let items = [];
        let node = {
            title: item,
            description: item
        };
        if(item.length > 32){
            node.title = item.substring(0, 30) + "...";
        }
        items.push(node);
        return items;
    },

    objToList: function(obj) {
        let items = [];
        for(var someKey in obj) {
            // We check if this key exists in the obj
            if (obj.hasOwnProperty(someKey)) {
                var item = obj[someKey];
                let node = this.convertItem(someKey, item);
                items.push(node);
            }
        }
        return items;
    },

    arrayToList: function(array){
        let items = [];
        for (var i = 0; i < array.length; i++) {
            var item = array[i];
            let node = this.convertItem(i, item);
            items.push(node);
        }
        return items;
    },

    refreshSvg: function (root) {
        let x0 = Infinity;
        let x1 = -x0;
        root.each(d => {
            if (d.x > x1) x1 = d.x;
            if (d.x < x0) x0 = d.x;
        });

        const svg = D3Mate.svg; //d3.create("svg")
        // clear first
        svg.selectAll("*").remove();

        svg.attr("viewBox", [0, 0, this.width, x1 - x0 + root.dx * 2]);

        const g = svg.append("g")
            .attr("font-family", "sans-serif")
            .attr("font-size", 10)
            .attr("transform", `translate(${root.dy / 3},${root.dx - x0})`);
        D3Mate.g = g;

        const link = g.append("g")
            .attr("fill", "none")
            .attr("stroke", "#555")
            .attr("stroke-opacity", 0.4)
            .attr("stroke-width", 1.5)
            .selectAll("path")
            .data(root.links())
            .join("path")
            .attr("d", d3.linkHorizontal()
                .x(d => d.y)
                .y(d => d.x));

        const node = g.append("g")
            .attr("stroke-linejoin", "round")
            .attr("stroke-width", 3)
            .selectAll("g")
            .data(root.descendants())
            .join("g")
            .attr("transform", d => `translate(${d.y},${d.x})`);

        node.append("circle")
            .attr("fill", d => d.children ? "#555" : "#999")
            .attr("r", 2.5);

        node.append("text")
            .attr("dy", "0.31em")
            .attr("x", d => d.children ? -6 : 6)
            .attr("text-anchor", d => d.children ? "end" : "start")
            .text(d => d.data.title)
            .clone(true).lower()
            .attr("stroke", "white");
    },

    processData: function (url, json) {
        // convert any json to hierarchy json
        let tree = {
            title: "ROOT",
            description: url
        };

        let children = [];
        if (Array.isArray(json)) {
            children = this.arrayToList(json);
        }
        else{
            children = this.objToList(json);
        }
        if (children.length) tree.children = children;

        // console.log("tree:");
        // console.log(tree);
        D3Mate.hierarchyData = tree;

        const root = d3.hierarchy(tree);
        // console.log("root:");
        // console.log(root);
        root.dx = 10;
        root.dy = this.width / (root.height + 1);

        var tmp = d3.tree().nodeSize([root.dx, root.dy])(root);
        this.refreshSvg(tmp);
    },

    process: function (url) {
        var self = this;

        d3.json(url, {crossOrigin: "anonymous"}).then(function(jsonData){
            var root = self.processData(url, jsonData);
        });
    },

    zoomed: function() {
        const {transform} = d3.event;
        D3Mate.g.attr("transform", transform);
        D3Mate.g.attr("stroke-width", 1 / transform.k);
    },

    init: function () {
        // svg
        if (this.svgContainer === null)
            D3Mate.svg = d3.select("body").append("svg")
                .attr("width", this.width)
                .attr("height", this.height);
        else
            D3Mate.svg = d3.select("#" + this.svgContainer).append("svg")
                .attr("width", this.width)
                .attr("height", this.height);
        // tip
        // D3Mate.tip = d3.tip()
        //   .attr('class', 'd3-tip')
        //   .offset([-10, 0])
        //   .html(function (d) {
        //       //var tmp = graphData.dataRelations.first(function (i) { return i.uri == d.relation });
        //       return "" + (d.description === null ? d.title : d.description) + "";
        //   });
        // D3Mate.svg.call(D3Mate.tip);
        // zoom
        D3Mate.svg.call(d3.zoom()
            //.extent([[0, 0], [this.width, this.height]])
            .scaleExtent([1, 16])
            .on("zoom", this.zoomed));
    }
}<commit_msg>可以对要绘制的array中的条目数进行限制：limitedItems=64；节点增加tooltip。<commit_after>/* json-hierarchy.js - v1.0.0.20190910
* https://github.com/13f/lore-graph
* Dependencies:
*    d3.js ^ v5
* Copyright (c) 2019 taurenshaman
*/

var D3Mate = {
    hierarchyData: null,
    tip: null,
    svg: null,
    g: null,

    tree: null,
    zoom: null
}

var JsonHierarchy = {
    // 参数
    svgContainer: null, // 存放svg的div，如果为null，则自己在body中append svg
    width: 960,
    height: 600,
    iconWidth: 30,
    iconHeight: 40,

    limitedItems: 64, // 用于性能优化。对于array，只展示limitedItems条数据

    maxLabelWidth: 250,
    transitionDuration: 750,
    transitionEase: 'cubic-in-out',
    minRadius: 5,
    scalingFactor: 2,

    callbackAfterProcess: null,

    convertItem: function(key, item){
        let node = {};
        node.title = key;
        if (typeof item === 'object'){ // null, array, object
            if(Array.isArray(item)){
                node.children = this.arrayToList(item);
            }
            else if(item === null){
                node.title = key;
                node.description = key;
            }
            else{
                node.children = this.objToList(item);
            }
        }
        else if (typeof item === 'undefined'){
            node.title = key;
            node.description = key;
        }
        else if (typeof item === 'string'){
            node.title = key;
            node.description = key;
            node.children = this.valueToList(item);
        }
        else { // number/bigint/boolean/...
            node.title = key;
            node.description = key;
            node.children = this.valueToList(item);
        }
        return node;
    },

    valueToList: function(item) {
        let items = [];
        let node = {
            title: item,
            description: item
        };
        if(item.length > 32){
            node.title = item.substring(0, 30) + "...";
        }
        items.push(node);
        return items;
    },

    objToList: function(obj) {
        let items = [];
        for(var someKey in obj) {
            // We check if this key exists in the obj
            if (obj.hasOwnProperty(someKey)) {
                var item = obj[someKey];
                let node = this.convertItem(someKey, item);
                items.push(node);
            }
        }
        return items;
    },

    arrayToList: function(array){
        let items = [];
        for (var i = 0; i < array.length && i < this.limitedItems; i++) {
            var item = array[i];
            let node = this.convertItem(i, item);
            items.push(node);
        }
        // add a ... item
        if(array.length >= this.limitedItems){
            items.push({
                title: "...",
                description: "Total count: " + array.length
            });
        }
        return items;
    },

    refreshSvg: function (root) {
        let x0 = Infinity;
        let x1 = -x0;
        root.each(d => {
            if (d.x > x1) x1 = d.x;
            if (d.x < x0) x0 = d.x;
        });

        const svg = D3Mate.svg; //d3.create("svg")
        // clear first
        svg.selectAll("*").remove();

        svg.attr("viewBox", [0, 0, this.width, x1 - x0 + root.dx * 2]);

        const g = svg.append("g")
            .attr("font-family", "sans-serif")
            .attr("font-size", 10)
            .attr("transform", `translate(${root.dy / 3},${root.dx - x0})`);
        D3Mate.g = g;

        const link = g.append("g")
            .attr("fill", "none")
            .attr("stroke", "#555")
            .attr("stroke-opacity", 0.4)
            .attr("stroke-width", 1.5)
            .selectAll("path")
            .data(root.links())
            .join("path")
            .attr("d", d3.linkHorizontal()
                .x(d => d.y)
                .y(d => d.x));

        const node = g.append("g")
            .attr("stroke-linejoin", "round")
            .attr("stroke-width", 3)
            .selectAll("g")
            .data(root.descendants())
            .join("g")
            .attr("transform", d => `translate(${d.y},${d.x})`);

        node.append("circle")
            .attr("fill", d => d.children ? "#555" : "#999")
            .attr("r", 2.5);

        node.append("text")
            .attr("dy", "0.31em")
            .attr("x", d => d.children ? -6 : 6)
            .attr("text-anchor", d => d.children ? "end" : "start")
            .text(d => d.data.title)
            .clone(true).lower()
            .attr("stroke", "white");

        node.append("title")
            .text((d, i) => d.data.description ? d.data.description : d.data.title);
    },

    processData: function (url, json) {
        // convert any json to hierarchy json
        let tree = {
            title: "ROOT",
            description: url
        };

        let children = [];
        if (Array.isArray(json)) {
            children = this.arrayToList(json);
        }
        else{
            children = this.objToList(json);
        }
        if (children.length) tree.children = children;

        // console.log("tree:");
        // console.log(tree);
        D3Mate.hierarchyData = tree;

        const root = d3.hierarchy(tree);
        // console.log("root:");
        // console.log(root);
        root.dx = 10;
        root.dy = this.width / (root.height + 1);

        var tmp = d3.tree().nodeSize([root.dx, root.dy])(root);
        this.refreshSvg(tmp);
    },

    process: function (url) {
        var self = this;

        d3.json(url, {crossOrigin: "anonymous"}).then(function(jsonData){
            var root = self.processData(url, jsonData);
        });
    },

    zoomed: function() {
        const {transform} = d3.event;
        D3Mate.g.attr("transform", transform);
        D3Mate.g.attr("stroke-width", 1 / transform.k);
    },

    init: function () {
        // svg
        if (this.svgContainer === null)
            D3Mate.svg = d3.select("body").append("svg")
                .attr("width", this.width)
                .attr("height", this.height);
        else
            D3Mate.svg = d3.select("#" + this.svgContainer).append("svg")
                .attr("width", this.width)
                .attr("height", this.height);
        // tip
        // D3Mate.tip = d3.tip()
        //   .attr('class', 'd3-tip')
        //   .offset([-10, 0])
        //   .html(function (d) {
        //       //var tmp = graphData.dataRelations.first(function (i) { return i.uri == d.relation });
        //       return "" + (d.description === null ? d.title : d.description) + "";
        //   });
        // D3Mate.svg.call(D3Mate.tip);
        // zoom
        D3Mate.svg.call(d3.zoom()
            //.extent([[0, 0], [this.width, this.height]])
            //.scaleExtent([1, 16])
            .on("zoom", this.zoomed));
    }
}<|endoftext|>


<commit_before>/**
 * GIVEN: two strings
 * RETURNS: true if one string is the permutation of the other
 * EXAMPLES:
 * isPermutation('abcde', 'ecdba') => true
 * isPermutation('abcde', 'cbafg') => false
 */

function isPermutation(s1, s2) {
  var set = new Array(255);
  var i;

  for (i = 0; i < 255; i++) set[i] = 0;

  for (i = 0; i < s1.length; i++) {
    set[s1.charCodeAt(i)]++;
  }

  for (i = 0; i < s2.length; i++) {
    set[s2.charCodeAt(i)]--;
  }

  for (i = 0; i < 255; i++) {
    if (set[i] !== 0) {
      return false
    }
  }

  return true;
}

console.assert(isPermutation('abcde', 'ecdba'), 'should be permutation of each other');
console.assert(!isPermutation('abcde', 'cbafg'), 'should not be permutation');

console.assert('correct');<commit_msg>simplify<commit_after>/**
 * GIVEN: two strings
 * RETURNS: true if one string is the permutation of the other
 * EXAMPLES:
 * isPermutation('abcde', 'ecdba') => true
 * isPermutation('abcde', 'cbafg') => false
 */

function isPermutation(s1, s2) {
  var set = new Array(255);
  var i;

  for (i = 0; i < 255; i++) set[i] = 0;
  for (i = 0; i < s1.length; i++) set[s1.charCodeAt(i)]++;
  for (i = 0; i < s2.length; i++) set[s2.charCodeAt(i)]--;

  for (i = 0; i < 255; i++) {
    if (set[i] !== 0) {
      return false
    }
  }

  return true;
}

console.assert(isPermutation('abcde', 'ecdba'), 'should be permutation of each other');
console.assert(!isPermutation('abcde', 'cbafg'), 'should not be permutation');

console.assert('correct');<|endoftext|>