<commit_before>(function (globalScope) {

    var appInfo;
    var connectionManager;

    function defineRoute(newRoute) {

        page(newRoute.path, Emby.Page.getHandler(newRoute));
    }

    function defineRoutes(routes) {

        for (var i = 0, length = routes.length; i < length; i++) {

            var currentRoute = routes[i];

            page(currentRoute.path, Emby.Page.getHandler(currentRoute));
        }
    }

    function defineCoreRoutes() {

        var baseRoute = window.location.pathname.replace('/index.html', '');
        if (baseRoute.lastIndexOf('/') == baseRoute.length - 1) {
            baseRoute = baseRoute.substring(0, baseRoute.length - 1);
        }

        console.log('Setting page base to ' + baseRoute);

        page.base(baseRoute);

        defineRoute({
            path: '/startup/login.html',
            id: 'login',
            transition: 'slide',
            dependencies: ['startup/startup']
        });

        defineRoute({
            path: '/startup/manuallogin.html',
            id: 'manuallogin',
            transition: 'slide',
            dependencies: ['startup/startup']
        });

        defineRoute({
            path: '/startup/welcome.html',
            id: 'welcome',
            transition: 'slide',
            dependencies: ['startup/startup']
        });

        defineRoute({
            path: '/startup/connectlogin.html',
            id: 'connectlogin',
            transition: 'slide',
            dependencies: ['startup/startup']
        });

        defineRoute({
            path: '/startup/manualserver.html',
            id: 'manualserver',
            transition: 'slide',
            dependencies: ['startup/startup']
        });

        defineRoute({
            path: '/startup/selectserver.html',
            id: 'selectserver',
            transition: 'slide',
            dependencies: ['startup/startup']
        });

        defineRoute({
            path: '/index.html',
            id: 'index',
            isDefaultRoute: true,
            transition: 'slide',
            dependencies: []
        });
    }

    function definePluginRoutes() {

        var plugins = Emby.PluginManager.plugins();

        for (var i = 0, length = plugins.length; i < length; i++) {

            var plugin = plugins[i];
            if (plugin.getRoutes) {
                defineRoutes(plugin.getRoutes());
            }
        }
    }

    var localApiClient;

    function createConnectionManager() {

        if (!appInfo.deviceId) {
            appInfo.deviceId = MediaBrowser.generateDeviceId();
        }

        var credentialProvider = new MediaBrowser.CredentialProvider();
        //credentialProvider.clear();
        connectionManager = new MediaBrowser.ConnectionManager(Logger, credentialProvider, appInfo.name, appInfo.version, appInfo.deviceName, appInfo.deviceId, appInfo.capabilities);

        connectionManager.currentLoggedInServer = function () {
            var server = localApiClient ? localApiClient.serverInfo() : connectionManager.getLastUsedServer();

            if (server) {
                if (server.UserId && server.AccessToken) {
                    return server;
                }
            }

            return null;
        };

        Events.on(connectionManager, 'apiclientcreated', function (e, newApiClient) {

            //$(newApiClient).on("websocketmessage", Dashboard.onWebSocketMessageReceived).on('requestfail', Dashboard.onRequestFail);
        });

        Events.on(connectionManager, 'localusersignedin', function (e, user) {

            localApiClient = connectionManager.getApiClient(user.ServerId);
        });

        define('connectionManager', [], function () {
            return connectionManager;
        });
    }

    function initRequire() {

        var paths = {
            alert: "components/polymer/alert",
            confirm: "components/polymer/confirm",
            toast: "components/polymer/toast",
            loading: "components/polymer/loading",
            soundeffect: "components/soundeffect"
        };

        var urlArgs = "v=" + appInfo.version;
        urlArgs = "t=" + new Date().getTime();

        var config = {

            urlArgs: urlArgs,

            paths: paths,
            map: {
                '*': {
                    'css': 'js/require/requirecss',
                    'html': 'js/require/requirehtml'
                }
            },
            shim: {
                'bower_components/sly/dist/sly.min': {
                    //These script dependencies should be loaded before loading
                    //backbone.js
                    deps: ['bower_components/jquery/dist/jquery.min'],
                    //Once loaded, use the global 'Backbone' as the
                    //module value.
                    exports: 'Sly'
                }
            }
        };

        var baseRoute = window.location.href.split('?')[0].replace('/index.html', '');
        if (baseRoute.lastIndexOf('/') == baseRoute.length - 1) {
            baseRoute = baseRoute.substring(0, baseRoute.length - 1);
        }

        console.log('Setting require baseUrl to ' + baseRoute);

        config.baseUrl = baseRoute;

        requirejs.config(config);

        define("connectservice", ["apiclient/connectservice"]);
        define("serverdiscovery", ["apiclient/serverdiscovery"]);
        define("wakeonlan", ["apiclient/wakeonlan"]);
        define("webcomponentsjs", ["bower_components/webcomponentsjs/webcomponents-lite.min"]);
        define("type", ["bower_components/type/dist/type"]);
        define("Sly", ["bower_components/sly/dist/sly.min"], function () {
            return window.Sly;
        });
    }

    function loadCoreDependencies(callback) {

        var list = [
          'bower_components/page.js/page.js',
          'bower_components/bean/bean.min',
          'js/pluginmanager',
          'js/routes',
          'js/viewmanager',
          'js/globalize',
          'js/thememanager',
          'js/focusmanager',
          'js/inputmanager',
          'js/screensavermanager',
          'js/playbackmanager',
          'js/audiomanager',

          'apiclient/logger',
          'apiclient/sha1',
          'apiclient/md5',
          'apiclient/credentials',
          'apiclient/device',
          'apiclient/store',
          'apiclient/deferred',
          'apiclient/events',
          'apiclient/ajax',
          'apiclient/apiclient',
          'apiclient/connectionmanager',
          'webcomponentsjs'
        ];

        if (!globalScope.Promise) {
            list.push('bower_components/native-promise-only/lib/npo.src');
        }

        require(list, function (page, bean) {

            window.page = page;
            window.bean = bean;

            // Second level dependencies that have to be loaded after the first set
            require([
                'html!bower_components/neon-animation/neon-animated-pages.html'
            ], callback);
            Emby.AudioManager.playSoundEffect();
        });
    }

    function loadPlugins() {

        // Load installed plugins
        // Use a Promise because the web-only version won't be able access the file system, so it may have to look up the plugins from some external location

        return new Promise(function (resolve, reject) {

            var list = [
                'plugins/defaulttheme/plugin.js',
                'plugins/logoscreensaver/plugin.js',
                'plugins/keyboard/plugin.js',
                'plugins/wmctheme/plugin.js'
            ];

            require(list, function () {
                resolve();
            });
        });
    }

    function getSupportedRemoteCommands() {

        // Full list
        // https://github.com/MediaBrowser/MediaBrowser/blob/master/MediaBrowser.Model/Session/GeneralCommand.cs
        return [
            "GoHome",
            "GoToSettings",
            "VolumeUp",
            "VolumeDown",
            "Mute",
            "Unmute",
            "ToggleMute",
            "SetVolume",
            "SetAudioStreamIndex",
            "SetSubtitleStreamIndex",
            "DisplayContent",
            "GoToSearch",
            "DisplayMessage"
        ];
    }

    function getCapabilities(supportsPersistentIdentifier, deviceProfile) {

        var caps = {
            PlayableMediaTypes: ['Audio', 'Video'],

            SupportedCommands: getSupportedRemoteCommands(),
            SupportsPersistentIdentifier: supportsPersistentIdentifier,
            SupportsMediaControl: true,
            SupportedLiveMediaTypes: ['Audio', 'Video'],
            DeviceProfile: deviceProfile
        };

        return caps;
    }

    function getDefaultAppInfo() {

        return {
            name: 'Emby Theater',
            version: '3.0',
            deviceName: 'Web Browser'
        };
    }

    function loadDefaultTheme(callback) {

        Emby.ThemeManager.loadTheme('defaulttheme', callback);
    }

    function start(hostApplicationInfo) {

        // Whoever calls start will supply info about the host app. If empty, assume it's just in a browser
        var isDefaultAppInfo = false;
        if (!hostApplicationInfo) {
            hostApplicationInfo = getDefaultAppInfo();
            isDefaultAppInfo = true;
        }

        appInfo = hostApplicationInfo;
        appInfo.capabilities = getCapabilities(!isDefaultAppInfo);

        initRequire();

        loadCoreDependencies(function () {

            loadPlugins().then(function () {

                defineCoreRoutes();
                definePluginRoutes();

                createConnectionManager();

                // Start by loading the default theme. Once a user is logged in we can change the theme based on settings
                loadDefaultTheme(function () {
                    // TODO: Catch window unload event to try to gracefully stop any active media playback

                    //page('*', Emby.Page.renderContent);
                    page({
                        click: false
                    });
                });
            });
        });
    }

    globalScope.App = {
        start: start
    };

    // call start unless configured not to
    if (window.location.href.toLowerCase().indexOf('autostart=false') == -1) {
        start();
    } else {

        document.dispatchEvent(new CustomEvent("embyready", {}));
    }

    var lastLeft;
    var lastDir;

    function moveKeyFocus(dir) {

        var selector = 'input,select,textarea,button,.focusable';

        var focused = document.activeElement;

        if (!focused) {
            var elem = document.querySelector(selector);
            if (elem) {
                Emby.FocusManager.focus(elem);
            }
        }
        else {
            var rect = focused.getBoundingClientRect(),
                hght = focused.offsetHeight,
                y = rect.top + (dir === 'down' ? hght : -hght),
                x = lastLeft;

            if (!lastLeft)
                x = lastLeft = rect.left + (focused.offsetWidth / 2);

            // As the key layout may be staggered, we should assume the user wants
            // to reach the farthest key in the direction they were going.
            // We check the location slightly to the left or right of the middle of
            // the focused key first...
            var next = document.elementFromPoint(lastDir === 'left' ? x - 10 : x + 10, y);

            // ...if there was no key at that point, try the other side
            if (!next.classList.contains('lime-key'))
                next = document.elementFromPoint(x + 10, y);
        }
    }

    //document.addEventListener('keydown', function (evt) {

    //    var key = evt.key.replace(/^Arrow/, '');

    //    switch (key) {
    //        case 'Left':
    //        case 'Right':
    //        case 'Up':
    //        case 'Down':

    //            evt.preventDefault();
    //            evt.stopPropagation();

    //            moveKeyFocus(key.toLowerCase());
    //            break;
    //    }
    //}, true);

})(this);<commit_msg>removed test code<commit_after>(function (globalScope) {

    var appInfo;
    var connectionManager;

    function defineRoute(newRoute) {

        page(newRoute.path, Emby.Page.getHandler(newRoute));
    }

    function defineRoutes(routes) {

        for (var i = 0, length = routes.length; i < length; i++) {

            var currentRoute = routes[i];

            page(currentRoute.path, Emby.Page.getHandler(currentRoute));
        }
    }

    function defineCoreRoutes() {

        var baseRoute = window.location.pathname.replace('/index.html', '');
        if (baseRoute.lastIndexOf('/') == baseRoute.length - 1) {
            baseRoute = baseRoute.substring(0, baseRoute.length - 1);
        }

        console.log('Setting page base to ' + baseRoute);

        page.base(baseRoute);

        defineRoute({
            path: '/startup/login.html',
            id: 'login',
            transition: 'slide',
            dependencies: ['startup/startup']
        });

        defineRoute({
            path: '/startup/manuallogin.html',
            id: 'manuallogin',
            transition: 'slide',
            dependencies: ['startup/startup']
        });

        defineRoute({
            path: '/startup/welcome.html',
            id: 'welcome',
            transition: 'slide',
            dependencies: ['startup/startup']
        });

        defineRoute({
            path: '/startup/connectlogin.html',
            id: 'connectlogin',
            transition: 'slide',
            dependencies: ['startup/startup']
        });

        defineRoute({
            path: '/startup/manualserver.html',
            id: 'manualserver',
            transition: 'slide',
            dependencies: ['startup/startup']
        });

        defineRoute({
            path: '/startup/selectserver.html',
            id: 'selectserver',
            transition: 'slide',
            dependencies: ['startup/startup']
        });

        defineRoute({
            path: '/index.html',
            id: 'index',
            isDefaultRoute: true,
            transition: 'slide',
            dependencies: []
        });
    }

    function definePluginRoutes() {

        var plugins = Emby.PluginManager.plugins();

        for (var i = 0, length = plugins.length; i < length; i++) {

            var plugin = plugins[i];
            if (plugin.getRoutes) {
                defineRoutes(plugin.getRoutes());
            }
        }
    }

    var localApiClient;

    function createConnectionManager() {

        if (!appInfo.deviceId) {
            appInfo.deviceId = MediaBrowser.generateDeviceId();
        }

        var credentialProvider = new MediaBrowser.CredentialProvider();
        //credentialProvider.clear();
        connectionManager = new MediaBrowser.ConnectionManager(Logger, credentialProvider, appInfo.name, appInfo.version, appInfo.deviceName, appInfo.deviceId, appInfo.capabilities);

        connectionManager.currentLoggedInServer = function () {
            var server = localApiClient ? localApiClient.serverInfo() : connectionManager.getLastUsedServer();

            if (server) {
                if (server.UserId && server.AccessToken) {
                    return server;
                }
            }

            return null;
        };

        Events.on(connectionManager, 'apiclientcreated', function (e, newApiClient) {

            //$(newApiClient).on("websocketmessage", Dashboard.onWebSocketMessageReceived).on('requestfail', Dashboard.onRequestFail);
        });

        Events.on(connectionManager, 'localusersignedin', function (e, user) {

            localApiClient = connectionManager.getApiClient(user.ServerId);
        });

        define('connectionManager', [], function () {
            return connectionManager;
        });
    }

    function initRequire() {

        var paths = {
            alert: "components/polymer/alert",
            confirm: "components/polymer/confirm",
            toast: "components/polymer/toast",
            loading: "components/polymer/loading",
            soundeffect: "components/soundeffect"
        };

        var urlArgs = "v=" + appInfo.version;
        urlArgs = "t=" + new Date().getTime();

        var config = {

            urlArgs: urlArgs,

            paths: paths,
            map: {
                '*': {
                    'css': 'js/require/requirecss',
                    'html': 'js/require/requirehtml'
                }
            },
            shim: {
                'bower_components/sly/dist/sly.min': {
                    //These script dependencies should be loaded before loading
                    //backbone.js
                    deps: ['bower_components/jquery/dist/jquery.min'],
                    //Once loaded, use the global 'Backbone' as the
                    //module value.
                    exports: 'Sly'
                }
            }
        };

        var baseRoute = window.location.href.split('?')[0].replace('/index.html', '');
        if (baseRoute.lastIndexOf('/') == baseRoute.length - 1) {
            baseRoute = baseRoute.substring(0, baseRoute.length - 1);
        }

        console.log('Setting require baseUrl to ' + baseRoute);

        config.baseUrl = baseRoute;

        requirejs.config(config);

        define("connectservice", ["apiclient/connectservice"]);
        define("serverdiscovery", ["apiclient/serverdiscovery"]);
        define("wakeonlan", ["apiclient/wakeonlan"]);
        define("webcomponentsjs", ["bower_components/webcomponentsjs/webcomponents-lite.min"]);
        define("type", ["bower_components/type/dist/type"]);
        define("Sly", ["bower_components/sly/dist/sly.min"], function () {
            return window.Sly;
        });
    }

    function loadCoreDependencies(callback) {

        var list = [
          'bower_components/page.js/page.js',
          'bower_components/bean/bean.min',
          'js/pluginmanager',
          'js/routes',
          'js/viewmanager',
          'js/globalize',
          'js/thememanager',
          'js/focusmanager',
          'js/inputmanager',
          'js/screensavermanager',
          'js/playbackmanager',
          'js/audiomanager',

          'apiclient/logger',
          'apiclient/sha1',
          'apiclient/md5',
          'apiclient/credentials',
          'apiclient/device',
          'apiclient/store',
          'apiclient/deferred',
          'apiclient/events',
          'apiclient/ajax',
          'apiclient/apiclient',
          'apiclient/connectionmanager',
          'webcomponentsjs'
        ];

        if (!globalScope.Promise) {
            list.push('bower_components/native-promise-only/lib/npo.src');
        }

        require(list, function (page, bean) {

            window.page = page;
            window.bean = bean;

            // Second level dependencies that have to be loaded after the first set
            require([
                'html!bower_components/neon-animation/neon-animated-pages.html'
            ], callback);
        });
    }

    function loadPlugins() {

        // Load installed plugins
        // Use a Promise because the web-only version won't be able access the file system, so it may have to look up the plugins from some external location

        return new Promise(function (resolve, reject) {

            var list = [
                'plugins/defaulttheme/plugin.js',
                'plugins/logoscreensaver/plugin.js',
                'plugins/keyboard/plugin.js',
                'plugins/wmctheme/plugin.js'
            ];

            require(list, function () {
                resolve();
            });
        });
    }

    function getSupportedRemoteCommands() {

        // Full list
        // https://github.com/MediaBrowser/MediaBrowser/blob/master/MediaBrowser.Model/Session/GeneralCommand.cs
        return [
            "GoHome",
            "GoToSettings",
            "VolumeUp",
            "VolumeDown",
            "Mute",
            "Unmute",
            "ToggleMute",
            "SetVolume",
            "SetAudioStreamIndex",
            "SetSubtitleStreamIndex",
            "DisplayContent",
            "GoToSearch",
            "DisplayMessage"
        ];
    }

    function getCapabilities(supportsPersistentIdentifier, deviceProfile) {

        var caps = {
            PlayableMediaTypes: ['Audio', 'Video'],

            SupportedCommands: getSupportedRemoteCommands(),
            SupportsPersistentIdentifier: supportsPersistentIdentifier,
            SupportsMediaControl: true,
            SupportedLiveMediaTypes: ['Audio', 'Video'],
            DeviceProfile: deviceProfile
        };

        return caps;
    }

    function getDefaultAppInfo() {

        return {
            name: 'Emby Theater',
            version: '3.0',
            deviceName: 'Web Browser'
        };
    }

    function loadDefaultTheme(callback) {

        Emby.ThemeManager.loadTheme('defaulttheme', callback);
    }

    function start(hostApplicationInfo) {

        // Whoever calls start will supply info about the host app. If empty, assume it's just in a browser
        var isDefaultAppInfo = false;
        if (!hostApplicationInfo) {
            hostApplicationInfo = getDefaultAppInfo();
            isDefaultAppInfo = true;
        }

        appInfo = hostApplicationInfo;
        appInfo.capabilities = getCapabilities(!isDefaultAppInfo);

        initRequire();

        loadCoreDependencies(function () {

            loadPlugins().then(function () {

                defineCoreRoutes();
                definePluginRoutes();

                createConnectionManager();

                // Start by loading the default theme. Once a user is logged in we can change the theme based on settings
                loadDefaultTheme(function () {
                    // TODO: Catch window unload event to try to gracefully stop any active media playback

                    //page('*', Emby.Page.renderContent);
                    page({
                        click: false
                    });
                });
            });
        });
    }

    globalScope.App = {
        start: start
    };

    // call start unless configured not to
    if (window.location.href.toLowerCase().indexOf('autostart=false') == -1) {
        start();
    } else {

        document.dispatchEvent(new CustomEvent("embyready", {}));
    }

    var lastLeft;
    var lastDir;

    function moveKeyFocus(dir) {

        var selector = 'input,select,textarea,button,.focusable';

        var focused = document.activeElement;

        if (!focused) {
            var elem = document.querySelector(selector);
            if (elem) {
                Emby.FocusManager.focus(elem);
            }
        }
        else {
            var rect = focused.getBoundingClientRect(),
                hght = focused.offsetHeight,
                y = rect.top + (dir === 'down' ? hght : -hght),
                x = lastLeft;

            if (!lastLeft)
                x = lastLeft = rect.left + (focused.offsetWidth / 2);

            // As the key layout may be staggered, we should assume the user wants
            // to reach the farthest key in the direction they were going.
            // We check the location slightly to the left or right of the middle of
            // the focused key first...
            var next = document.elementFromPoint(lastDir === 'left' ? x - 10 : x + 10, y);

            // ...if there was no key at that point, try the other side
            if (!next.classList.contains('lime-key'))
                next = document.elementFromPoint(x + 10, y);
        }
    }

    //document.addEventListener('keydown', function (evt) {

    //    var key = evt.key.replace(/^Arrow/, '');

    //    switch (key) {
    //        case 'Left':
    //        case 'Right':
    //        case 'Up':
    //        case 'Down':

    //            evt.preventDefault();
    //            evt.stopPropagation();

    //            moveKeyFocus(key.toLowerCase());
    //            break;
    //    }
    //}, true);

})(this);<|endoftext|>


<commit_before>/**
 * Controller for Search related objects.
 * @type {*}
 */
var SearchController = Backbone.Marionette.Controller.extend({

    /**
     * Backbone collection of Workspace models.
     */
    searches: new SearchList(),

    searchNameView: null,

    searchFilterView: null,

    initialize: function (options) {

        var self = this;

        // Wire events to functions
        this.listenTo(MongoApp.dispatcher, MongoApp.events.SEARCH_FILTER_ADD, function (filter, async) {
            self.addFilter(filter, async);
        });
        this.listenTo(MongoApp.dispatcher, MongoApp.events.SEARCH_FILTER_REMOVE, function (filter) {
            self.removeFilter(filter);
        });
        this.listenTo(MongoApp.dispatcher, MongoApp.events.SEARCH_SAVE, function (search) {
            self.saveSearch(search);
        });
        this.listenTo(MongoApp.dispatcher, MongoApp.events.SEARCH_DELETE, function (search) {
            self.deleteSearch(search);
        });
        this.listenTo(MongoApp.dispatcher, MongoApp.events.SEARCH_SHOW_DIALOG, function () {
            self.showSearchDialog();
        });
        this.listenTo(MongoApp.dispatcher, MongoApp.events.SEARCH_EXPORT, function (search) {
            self.exportSearch(search);
        });
        this.listenTo(MongoApp.dispatcher, MongoApp.events.SEARCH_IMPORT, function (filterHistoryJsonText) {
            self.importSearch(filterHistoryJsonText);
        });
    },

    showSearchName: function(options) {
        this.searchNameView = new SearchNameView({model: MongoApp.search});

        options.region.show(this.searchNameView);
    },

    showSearchDescription: function(options) {
        this.searchDescriptionView = new SearchDescriptionView({model: MongoApp.search});

        options.region.show(this.searchDescriptionView);
    },

    showSearchSave: function(options) {
        this.searchSaveView = new SearchSaveView({model: MongoApp.search});

        options.region.show(this.searchSaveView);
    },

    showSearchFilterTable: function (options) {
        this.searchFilterView = new SearchFilterTableView({
            collection: MongoApp.search.get("filters")
        });
        options.region.show(this.searchFilterView);
    },

    addFilter: function (filter, async) {
        MongoApp.showPleaseWait();

        MongoApp.search.get("filters").add(filter);

        if (filter.get('id') != MongoApp.FILTER_NONE.get('id'))
            MongoApp.search.set("saved", false);

        MongoApp.dispatcher.trigger(MongoApp.events.SEARCH_FILTER_ADDED, MongoApp.search, async);
        this.updateFilterRemovable();
    },

    removeFilter: function (filter) {
        MongoApp.showPleaseWait();

        MongoApp.search.get("filters").remove(filter);
        MongoApp.search.set("saved", false);
        MongoApp.dispatcher.trigger(MongoApp.events.SEARCH_FILTER_REMOVED, MongoApp.search);
        this.updateFilterRemovable();
    },

    /**
     * Loops through ALL filters and updates their removable attribute.
     */
    updateFilterRemovable: function()
    {
        var lastFilter = _.last(MongoApp.search.get("filters").models);

        // loop through filter collection
        // filter is removable ONLY if it's
        // 1.) not the NONE filter
        // 2.) is the last filter in the list
        var self = this;
        _.each(MongoApp.search.get("filters").models, function(filter)
        {
            var button =  $("#" + filter.get("id") + "_remove_button");
            if ((filter.get("id") != MongoApp.FILTER_NONE.get("id")) &&
                (filter.get("id") == lastFilter.get("id")))
            {
                filter.set("removable", true);
            }
            else
            {
                filter.set("removable", false);
            }
        });
    },

    /**
     * Save search model to back-end
     * @param search
     */
    saveSearch: function(search) {

        var self = this;
        var saveCallback = function() {
            // update model name if user decided to change it
            search.set("name",  $('#search_save_name_field').val());
            search.set("description", $('#search_save_desc_field').val());

            var filterHistory = self.searchToFilterHistory(search);

            $.ajax({
                type: "POST",
                url: "/mongo_svr/ve/filterHistory/save",
                contentType: "application/json",
                data: JSON.stringify(filterHistory),
                dataType: "json",
                success: function(json)
                {
                    var savedSearch = self.filterHistoryToSearch(json);
                    MongoApp.dispatcher.trigger(MongoApp.events.SEARCH_LOAD, savedSearch);
                    console.log("save successful!");
                },
                error: jqueryAJAXErrorHandler
            });
        }

        var cancelCallback = function() {};

        var wysihtml5Initialized = false;
        var shownCallback = function(okButton, cancelButton) {
            // by default, set the name to be the model's name
            $('#search_save_name_field').val(search.get("name"));
            $('#search_save_desc_field').val(search.get("description"));

            // focus on input field and highlight text
            $('#search_save_name_field').focus();
            $('#search_save_name_field').select();

            // capture ENTER key event on form
//            $( "#search_save_form" ).submit(function( event ) {
//                // alias ENTER key to clicking on the confirm's OK button
//                okButton.click();
//                event.preventDefault();
//            });

            if (wysihtml5Initialized == false) {
                $('#search_save_desc_field').wysihtml5({stylesheets:[]});
                wysihtml5Initialized = true;
            }
        };

        var html =
                '
' +
                '
Name
' +
                '
' +
                '
' +
                '           <input type="text" id="search_save_name_field" name="search_save_name_field" class="input-medium">' +
                '
' +
                '
'+
                '
Description
' +
                '
' +
                '
' +
                '           <textarea id="search_save_desc_field" name="search_save_desc_field" class="textarea span12" rows="5"></textarea>'+
                '
' +
                '
'+
                '
';

        var confirmDialog = new ConfirmDialog("Save Analysis", html, "Save", saveCallback, cancelCallback, shownCallback);
        confirmDialog.show();
    },

    /**
     * Delete search from server.
     *
     * @param search
     */
    deleteSearch: function(search) {

        $.ajax({
            type: "DELETE",
            url: "/mongo_svr/ve/filterHistory/delete/" + search.get('id'),
            dataType: "json",
            success: function(json)
            {
                console.log("delete successful!");
                // TODO: give user feedback

                // if the user deletes the current search, then reload the workspace w/ default search
                if (search.get('id') == MongoApp.search.get('id')) {
                    MongoApp.dispatcher.trigger(MongoApp.events.WKSP_LOAD, MongoApp.workspace, new Search());
                }
            },
            error: jqueryAJAXErrorHandler
        });
    },

    /**
     * Queries server for a current listing of Search objects for the given workspace.
     */
    getSearches: function(workspaceKey) {

        var self = this;

        var searchList = new SearchList();

        // make synchronous REST call to server
        $.ajax({
            url: "/mongo_svr/ve/filterHistory/search/w/" + workspaceKey,
            dataType: "json",
            async: false,
            success: function(json) {

                var filterHistories = json.filterHistories;
                for (var i = 0; i < filterHistories.length; i++) {
                    var search = self.filterHistoryToSearch(filterHistories[i]);
                    searchList.add(search);
                }
            },
            error: jqueryAJAXErrorHandler
        });

        return searchList;
    },

    /**
     * Show configure search dialog
     */
    showSearchDialog: function() {

        // refresh searches
        this.searches.reset();
        this.searches.set(this.getSearches(MongoApp.workspace.get("key")).models);

        var searchTableView = new SearchTableView({
            collection: this.searches
        });

        var region = new Backbone.Marionette.Region({
            el: "#searchTableRegion"
        });
        region.show(searchTableView);
        $('#searches_modal').modal();
    },

    /**
     * Import Search model from a file on client.
     * @param JSON text for filter history javascript object.
     */
    importSearch: function(filterHistoryJsonText) {
        var filterHistory = JSON.parse(filterHistoryJsonText);
        var search = this.filterHistoryToSearch(filterHistory);
        MongoApp.dispatcher.trigger(MongoApp.events.SEARCH_LOAD, search);
    },

    /**
     * Export Search model to a file on client.
     *
     * @param search
     */
    exportSearch: function(search) {
        var filterHistory = this.searchToFilterHistory(search);
        var data = JSON.stringify(filterHistory);

        // use Data URI to save
        //window.open("data:text/json;charset=utf-8," + encodeURIComponent(data));

        // dynamically add HTML form that is hidden
        var form = $('<form>').attr(
            {
                id:      'export_search_form',
                method:  'POST',
                action:  '/mongo_svr/client_download_proxy',
                enctype: 'application/x-www-form-urlencoded'
            });
        form.append($('<input>').attr({type: 'hidden', name: 'filename', value: search.get("name") + '.json'}));
        form.append($('<input>').attr({type: 'hidden', name: 'mimeType', value: 'application/json'}));
        form.append($('<input>').attr({type: 'hidden', name: 'content', value: data}));
        $("body").append(form);

        // programmatically submit form to perform download
        $('#export_search_form').submit();

        // remove form
        $('#export_search_form').remove();

//
//
//
//        // Now we convert the data to a Data URI Scheme, which must be Base64 encoded
//        // make sure you use the appropriate method to Base64 encode your data depending
//        // on the library you chose to use.
//        // application/octet-stream simply tells your browser to treat the URL as
//        // arbitrary binary data, and won't try to display it in the browser window when
//        // opened.
//        var url = "data:application/octet-stream;base64," + $.base64('encode', data);
//
//        // To force the browser to download a file we need to use a custom method which
//        // creates a hidden iframe, which allows browsers to download any given file
//        var iframe = document.getElementById("hiddenDownloader");
//        if (iframe === null)
//        {
//            iframe = document.createElement('iframe');
//            iframe.id = "hiddenDownloader";
//            iframe.style.display = "none";
//            document.body.appendChild(iframe);
//        }
//        iframe.src = url;
    },

    /**
     * Translates a Search model into a edu.mayo.ve.message.FilterHistory object.
     * @param filterHistory
     */
    searchToFilterHistory: function(search) {
        var filterHistory = new Object();
        filterHistory.id          = search.get("id");
        filterHistory.name        = search.get("name");
        filterHistory.description = search.get("description");
        filterHistory.user        = search.get("user");
        filterHistory.key         = search.get("key");
        filterHistory.filters     = new Array();

        // translate Filter model to Querry object (except for NONE filter)
        _.each(search.get("filters").models, function(filter) {

            var filterList = new FilterList();
            filterList.add(filter);

            var querry = buildQuery(filterList, search.get("key"));

            filterHistory.filters.push(querry);

        });

        return filterHistory;
    },

    /**
     * Translates a edu.mayo.ve.message.FilterHistory object into a Search model.
     * @param filterHistory
     */
    filterHistoryToSearch: function(filterHistory) {
        var search = new Search();

        search.set('id', filterHistory.id);
        search.set('name', filterHistory.name);
        search.set('description', filterHistory.description);
        search.set('user', filterHistory.user);
        search.set('key', filterHistory.key);
        search.set('timestamp', filterHistory.timestamp);

        for (var i = 0; i < filterHistory.filters.length; i++) {
            var querry = filterHistory.filters[i];

            // each Querry object is a Filter model
            var filter = this.querryToFilter(querry);
            search.get("filters").add(filter);
        }

        return search;
    },

    /**
     * Translates a edu.mayo.ve.message.Querry object into a Filter model.
     * @param querry
     */
    querryToFilter: function(querry) {
        var filter;

        if (querry.sampleGroups.length == 1) {
            filter = new GroupFilter();

            var sampleGroupPojo = querry.sampleGroups[0];
            var inSample = sampleGroupPojo.inSample;
            if (inSample) {
                filter = MongoApp.FILTER_IN_GROUP.clone();
            } else {
                filter = MongoApp.FILTER_NOT_IN_GROUP.clone();
            }
            filter.set("genotype", filter.toGenotype(sampleGroupPojo.zygosity));
            filter.set("sampleStatus", filter.toSampleStatus(sampleGroupPojo.allAnySample));
            filter.set("value", new SampleGroup().fromPojo(sampleGroupPojo));
        }
        else if (querry.infoFlagFilters.length == 1) {
            filter = new Filter().fromInfoFlagFilterPojo(querry.infoFlagFilters[0]);
        }
        else if (querry.infoNumberFilters.length == 1) {
            filter = new Filter().fromInfoNumberFilterPojo(querry.infoNumberFilters[0]);
        }
        else if (querry.infoStringFilters.length == 1) {
            filter = new Filter().fromInfoStringFilterPojo(querry.infoStringFilters[0]);
        }
        else if (querry.sampleNumberFilters.length == 1) {
            filter = new Filter().fromSampleNumberFilterPojo(querry.sampleNumberFilters[0]);
        }
        else if (querry.customNumberFilters.length == 1) {
            filter = new AltAlleleDepthFilter();
            filter.set("value", querry.customNumberFilters[0].value);
        }

        if (filter != undefined)
            filter.setFilterDisplay();

        return filter;
    }
});<commit_msg>Fixed bug where saving an Analysis would cause the entire Analysis to be re-run.<commit_after>/**
 * Controller for Search related objects.
 * @type {*}
 */
var SearchController = Backbone.Marionette.Controller.extend({

    /**
     * Backbone collection of Workspace models.
     */
    searches: new SearchList(),

    searchNameView: null,

    searchFilterView: null,

    initialize: function (options) {

        var self = this;

        // Wire events to functions
        this.listenTo(MongoApp.dispatcher, MongoApp.events.SEARCH_FILTER_ADD, function (filter, async) {
            self.addFilter(filter, async);
        });
        this.listenTo(MongoApp.dispatcher, MongoApp.events.SEARCH_FILTER_REMOVE, function (filter) {
            self.removeFilter(filter);
        });
        this.listenTo(MongoApp.dispatcher, MongoApp.events.SEARCH_SAVE, function (search) {
            self.saveSearch(search);
        });
        this.listenTo(MongoApp.dispatcher, MongoApp.events.SEARCH_DELETE, function (search) {
            self.deleteSearch(search);
        });
        this.listenTo(MongoApp.dispatcher, MongoApp.events.SEARCH_SHOW_DIALOG, function () {
            self.showSearchDialog();
        });
        this.listenTo(MongoApp.dispatcher, MongoApp.events.SEARCH_EXPORT, function (search) {
            self.exportSearch(search);
        });
        this.listenTo(MongoApp.dispatcher, MongoApp.events.SEARCH_IMPORT, function (filterHistoryJsonText) {
            self.importSearch(filterHistoryJsonText);
        });
    },

    showSearchName: function(options) {
        this.searchNameView = new SearchNameView({model: MongoApp.search});

        options.region.show(this.searchNameView);
    },

    showSearchDescription: function(options) {
        this.searchDescriptionView = new SearchDescriptionView({model: MongoApp.search});

        options.region.show(this.searchDescriptionView);
    },

    showSearchSave: function(options) {
        this.searchSaveView = new SearchSaveView({model: MongoApp.search});

        options.region.show(this.searchSaveView);
    },

    showSearchFilterTable: function (options) {
        this.searchFilterView = new SearchFilterTableView({
            collection: MongoApp.search.get("filters")
        });
        options.region.show(this.searchFilterView);
    },

    addFilter: function (filter, async) {
        MongoApp.showPleaseWait();

        MongoApp.search.get("filters").add(filter);

        if (filter.get('id') != MongoApp.FILTER_NONE.get('id'))
            MongoApp.search.set("saved", false);

        MongoApp.dispatcher.trigger(MongoApp.events.SEARCH_FILTER_ADDED, MongoApp.search, async);
        this.updateFilterRemovable();
    },

    removeFilter: function (filter) {
        MongoApp.showPleaseWait();

        MongoApp.search.get("filters").remove(filter);
        MongoApp.search.set("saved", false);
        MongoApp.dispatcher.trigger(MongoApp.events.SEARCH_FILTER_REMOVED, MongoApp.search);
        this.updateFilterRemovable();
    },

    /**
     * Loops through ALL filters and updates their removable attribute.
     */
    updateFilterRemovable: function()
    {
        var lastFilter = _.last(MongoApp.search.get("filters").models);

        // loop through filter collection
        // filter is removable ONLY if it's
        // 1.) not the NONE filter
        // 2.) is the last filter in the list
        var self = this;
        _.each(MongoApp.search.get("filters").models, function(filter)
        {
            var button =  $("#" + filter.get("id") + "_remove_button");
            if ((filter.get("id") != MongoApp.FILTER_NONE.get("id")) &&
                (filter.get("id") == lastFilter.get("id")))
            {
                filter.set("removable", true);
            }
            else
            {
                filter.set("removable", false);
            }
        });
    },

    /**
     * Save search model to back-end
     * @param search
     */
    saveSearch: function(search) {

        var self = this;
        var saveCallback = function() {
            // update model name if user decided to change it
            search.set("name",  $('#search_save_name_field').val());
            search.set("description", $('#search_save_desc_field').val());

            var filterHistory = self.searchToFilterHistory(search);

            $.ajax({
                type: "POST",
                url: "/mongo_svr/ve/filterHistory/save",
                contentType: "application/json",
                data: JSON.stringify(filterHistory),
                dataType: "json",
                success: function(json)
                {
                    var savedSearch = self.filterHistoryToSearch(json);
                    MongoApp.search.set("id", savedSearch.get("id"));
                    MongoApp.search.set("timestamp", savedSearch.get("timestamp"));
                    MongoApp.search.set("saved", true);
                    console.log("save successful!");
                },
                error: jqueryAJAXErrorHandler
            });
        }

        var cancelCallback = function() {};

        var wysihtml5Initialized = false;
        var shownCallback = function(okButton, cancelButton) {
            // by default, set the name to be the model's name
            $('#search_save_name_field').val(search.get("name"));
            $('#search_save_desc_field').val(search.get("description"));

            // focus on input field and highlight text
            $('#search_save_name_field').focus();
            $('#search_save_name_field').select();

            // capture ENTER key event on form
//            $( "#search_save_form" ).submit(function( event ) {
//                // alias ENTER key to clicking on the confirm's OK button
//                okButton.click();
//                event.preventDefault();
//            });

            if (wysihtml5Initialized == false) {
                $('#search_save_desc_field').wysihtml5({stylesheets:[]});
                wysihtml5Initialized = true;
            }
        };

        var html =
                '
' +
                '
Name
' +
                '
' +
                '
' +
                '           <input type="text" id="search_save_name_field" name="search_save_name_field" class="input-medium">' +
                '
' +
                '
'+
                '
Description
' +
                '
' +
                '
' +
                '           <textarea id="search_save_desc_field" name="search_save_desc_field" class="textarea span12" rows="5"></textarea>'+
                '
' +
                '
'+
                '
';

        var confirmDialog = new ConfirmDialog("Save Analysis", html, "Save", saveCallback, cancelCallback, shownCallback);
        confirmDialog.show();
    },

    /**
     * Delete search from server.
     *
     * @param search
     */
    deleteSearch: function(search) {

        $.ajax({
            type: "DELETE",
            url: "/mongo_svr/ve/filterHistory/delete/" + search.get('id'),
            dataType: "json",
            success: function(json)
            {
                console.log("delete successful!");
                // TODO: give user feedback

                // if the user deletes the current search, then reload the workspace w/ default search
                if (search.get('id') == MongoApp.search.get('id')) {
                    MongoApp.dispatcher.trigger(MongoApp.events.WKSP_LOAD, MongoApp.workspace, new Search());
                }
            },
            error: jqueryAJAXErrorHandler
        });
    },

    /**
     * Queries server for a current listing of Search objects for the given workspace.
     */
    getSearches: function(workspaceKey) {

        var self = this;

        var searchList = new SearchList();

        // make synchronous REST call to server
        $.ajax({
            url: "/mongo_svr/ve/filterHistory/search/w/" + workspaceKey,
            dataType: "json",
            async: false,
            success: function(json) {

                var filterHistories = json.filterHistories;
                for (var i = 0; i < filterHistories.length; i++) {
                    var search = self.filterHistoryToSearch(filterHistories[i]);
                    searchList.add(search);
                }
            },
            error: jqueryAJAXErrorHandler
        });

        return searchList;
    },

    /**
     * Show configure search dialog
     */
    showSearchDialog: function() {

        // refresh searches
        this.searches.reset();
        this.searches.set(this.getSearches(MongoApp.workspace.get("key")).models);

        var searchTableView = new SearchTableView({
            collection: this.searches
        });

        var region = new Backbone.Marionette.Region({
            el: "#searchTableRegion"
        });
        region.show(searchTableView);
        $('#searches_modal').modal();
    },

    /**
     * Import Search model from a file on client.
     * @param JSON text for filter history javascript object.
     */
    importSearch: function(filterHistoryJsonText) {
        var filterHistory = JSON.parse(filterHistoryJsonText);
        var search = this.filterHistoryToSearch(filterHistory);
        MongoApp.dispatcher.trigger(MongoApp.events.SEARCH_LOAD, search);
    },

    /**
     * Export Search model to a file on client.
     *
     * @param search
     */
    exportSearch: function(search) {
        var filterHistory = this.searchToFilterHistory(search);
        var data = JSON.stringify(filterHistory);

        // use Data URI to save
        //window.open("data:text/json;charset=utf-8," + encodeURIComponent(data));

        // dynamically add HTML form that is hidden
        var form = $('<form>').attr(
            {
                id:      'export_search_form',
                method:  'POST',
                action:  '/mongo_svr/client_download_proxy',
                enctype: 'application/x-www-form-urlencoded'
            });
        form.append($('<input>').attr({type: 'hidden', name: 'filename', value: search.get("name") + '.json'}));
        form.append($('<input>').attr({type: 'hidden', name: 'mimeType', value: 'application/json'}));
        form.append($('<input>').attr({type: 'hidden', name: 'content', value: data}));
        $("body").append(form);

        // programmatically submit form to perform download
        $('#export_search_form').submit();

        // remove form
        $('#export_search_form').remove();

//
//
//
//        // Now we convert the data to a Data URI Scheme, which must be Base64 encoded
//        // make sure you use the appropriate method to Base64 encode your data depending
//        // on the library you chose to use.
//        // application/octet-stream simply tells your browser to treat the URL as
//        // arbitrary binary data, and won't try to display it in the browser window when
//        // opened.
//        var url = "data:application/octet-stream;base64," + $.base64('encode', data);
//
//        // To force the browser to download a file we need to use a custom method which
//        // creates a hidden iframe, which allows browsers to download any given file
//        var iframe = document.getElementById("hiddenDownloader");
//        if (iframe === null)
//        {
//            iframe = document.createElement('iframe');
//            iframe.id = "hiddenDownloader";
//            iframe.style.display = "none";
//            document.body.appendChild(iframe);
//        }
//        iframe.src = url;
    },

    /**
     * Translates a Search model into a edu.mayo.ve.message.FilterHistory object.
     * @param filterHistory
     */
    searchToFilterHistory: function(search) {
        var filterHistory = new Object();
        filterHistory.id          = search.get("id");
        filterHistory.name        = search.get("name");
        filterHistory.description = search.get("description");
        filterHistory.user        = search.get("user");
        filterHistory.key         = search.get("key");
        filterHistory.filters     = new Array();

        // translate Filter model to Querry object (except for NONE filter)
        _.each(search.get("filters").models, function(filter) {

            var filterList = new FilterList();
            filterList.add(filter);

            var querry = buildQuery(filterList, search.get("key"));

            filterHistory.filters.push(querry);

        });

        return filterHistory;
    },

    /**
     * Translates a edu.mayo.ve.message.FilterHistory object into a Search model.
     * @param filterHistory
     */
    filterHistoryToSearch: function(filterHistory) {
        var search = new Search();

        search.set('id', filterHistory.id);
        search.set('name', filterHistory.name);
        search.set('description', filterHistory.description);
        search.set('user', filterHistory.user);
        search.set('key', filterHistory.key);
        search.set('timestamp', filterHistory.timestamp);

        for (var i = 0; i < filterHistory.filters.length; i++) {
            var querry = filterHistory.filters[i];

            // each Querry object is a Filter model
            var filter = this.querryToFilter(querry);
            search.get("filters").add(filter);
        }

        return search;
    },

    /**
     * Translates a edu.mayo.ve.message.Querry object into a Filter model.
     * @param querry
     */
    querryToFilter: function(querry) {
        var filter;

        if (querry.sampleGroups.length == 1) {
            filter = new GroupFilter();

            var sampleGroupPojo = querry.sampleGroups[0];
            var inSample = sampleGroupPojo.inSample;
            if (inSample) {
                filter = MongoApp.FILTER_IN_GROUP.clone();
            } else {
                filter = MongoApp.FILTER_NOT_IN_GROUP.clone();
            }
            filter.set("genotype", filter.toGenotype(sampleGroupPojo.zygosity));
            filter.set("sampleStatus", filter.toSampleStatus(sampleGroupPojo.allAnySample));
            filter.set("value", new SampleGroup().fromPojo(sampleGroupPojo));
        }
        else if (querry.infoFlagFilters.length == 1) {
            filter = new Filter().fromInfoFlagFilterPojo(querry.infoFlagFilters[0]);
        }
        else if (querry.infoNumberFilters.length == 1) {
            filter = new Filter().fromInfoNumberFilterPojo(querry.infoNumberFilters[0]);
        }
        else if (querry.infoStringFilters.length == 1) {
            filter = new Filter().fromInfoStringFilterPojo(querry.infoStringFilters[0]);
        }
        else if (querry.sampleNumberFilters.length == 1) {
            filter = new Filter().fromSampleNumberFilterPojo(querry.sampleNumberFilters[0]);
        }
        else if (querry.customNumberFilters.length == 1) {
            filter = new AltAlleleDepthFilter();
            filter.set("value", querry.customNumberFilters[0].value);
        }

        if (filter != undefined)
            filter.setFilterDisplay();

        return filter;
    }
});<|endoftext|>


<commit_before>// Copyright 2016, Google, Inc.
// 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.

'use strict';

process.env.DEBUG = 'actions-on-google:*';
let Assistant = require('actions-on-google').ApiAiAssistant;
let express = require('express');
let bodyParser = require('body-parser');

let app = express();
app.use(bodyParser.json({type: 'application/json'}));

// [START YourAction]
app.post('/', function (req, res) {
  const assistant = new Assistant({request: req, response: res});
  console.log('Request headers: ' + JSON.stringify(req.headers));
  console.log('Request body: ' + JSON.stringify(req.body));

  // Fulfill action business logic
  function responseHandler (assistant) {
    // Complete your fulfillment logic and send a response

   getJsonEvents( function (events) {
	   assistant.tell('Hello, World1!');
     var prefixContent =""

	   var speechText = "";
        if (events.length == 0) {
            speechText = "There is a problem connecting to thermostat at this time. Please try again later.";
             assistant.tell(speechText);
        } else {
            for (i = 0; i < 1; i++) {
                speechText = speechText + events[i] + " ";
            }
           // speechText = speechText + " Wanna go deeper in history?";
             assistant.tell(prefixContent + speechText);
        }
    });
  }
function getJsonEvents(eventCallback) {
	   assistant.tell('Hello, World1!');
   var url = 'https://web.lntdemoprojects.com/RASWCFService/RASWCFService.svc/GetThermostatHome/6402/5967/76632';
var https = require('https');
    https.get(url, function(res) {
        var body = '';

        res.on('data', function (chunk) {
            body += chunk;
        });

        res.on('end', function () {
            var stringResult = body;
            eventCallback(stringResult);
        });
    }).on('error', function (e) {
        console.log("Got error: ", e);
    });
}
  assistant.handleRequest(responseHandler);
});
// [END YourAction]

if (module === require.main) {
  // [START server]
  // Start the server
  let server = app.listen(process.env.PORT || 8080, function () {
    let port = server.address().port;
    console.log('App listening on port %s', port);
  });
  // [END server]
}

module.exports = app;
<commit_msg>updated2<commit_after>// Copyright 2016, Google, Inc.
// 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.

'use strict';

process.env.DEBUG = 'actions-on-google:*';
let Assistant = require('actions-on-google').ApiAiAssistant;
let express = require('express');
let bodyParser = require('body-parser');

let app = express();
app.use(bodyParser.json({type: 'application/json'}));

// [START YourAction]
app.post('/', function (req, res) {
  const assistant = new Assistant({request: req, response: res});
  console.log('Request headers: ' + JSON.stringify(req.headers));
  console.log('Request body: ' + JSON.stringify(req.body));

  // Fulfill action business logic
  function responseHandler (assistant) {
    // Complete your fulfillment logic and send a response

   getJsonEvents( function (events) {
	   assistant.tell('Hello, World1!');
     var prefixContent =""

	   var speechText = "";
        if (events.length == 0) {
            speechText = "There is a problem connecting to thermostat at this time. Please try again later.";
             assistant.tell(speechText);
        } else {
            for (i = 0; i < 1; i++) {
                speechText = speechText + events[i] + " ";
            }
           // speechText = speechText + " Wanna go deeper in history?";
             assistant.tell(prefixContent + speechText);
        }
    });
  }
function getJsonEvents(eventCallback) {
	   assistant.tell('Hello, World!!');
   let url = 'https://web.lntdemoprojects.com/RASWCFService/RASWCFService.svc/GetThermostatHome/6402/5967/76632';
let https = require('https');
    https.get(url, function(res) {
        var body = '';

        res.on('data', function (chunk) {
            body += chunk;
        });

        res.on('end', function () {
            let stringResult = body;
            eventCallback(stringResult);
        });
    }).on('error', function (e) {
        console.log("Got error: ", e);
    });
}
  assistant.handleRequest(responseHandler);
});
// [END YourAction]

if (module === require.main) {
  // [START server]
  // Start the server
  let server = app.listen(process.env.PORT || 8080, function () {
    let port = server.address().port;
    console.log('App listening on port %s', port);
  });
  // [END server]
}

module.exports = app;
<|endoftext|>


<commit_before>import React from 'react';
import { expect } from 'chai';
import { shallow } from 'enzyme';
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import Controls from '../client/controls';
import Challenge from '../client/containers/challenge';
import Challenges from '../client/components/challenges';
import InputRegexValidation from '../client/containers/inputRegexValidation';
import reducer from '../client/reducers/index';

const finalStore = applyMiddleware(thunk)(createStore);
const testStore = finalStore(reducer);

describe('<Controls />', () => {
  it('should have div tag', () => {
    const wrapper = shallow(<Controls store={testStore} />);
    expect(wrapper.find('div')).to.have.length(1);
  });
});

describe('<Challenges />', () => {
  const wrapper = shallow(<Challenges store={testStore} />);
  it('should have a state', () => {
    expect(wrapper.state()).to.be.defined;
    expect(wrapper.state('solution') === 'abc').to.equal(true);
  });
});

describe('<Challenge />', () => {
  const wrapper = shallow(<Challenge store={testStore} />);
  it('should have props challengeInfo', () => {
    expect(wrapper.props().challengeInfo).to.be.defined;
  });
});

describe('<InputRegexValidation />', () => {
  it('checkRegex should be defined', () => {
    const wrapper = shallow(<InputRegexValidation store={testStore} />);
    expect(wrapper.checkRegex).to.be.defined;
  });

  it('checkRegex should be a function', () => {
    const wrapper = shallow(<InputRegexValidation store={testStore} />);
    expect(wrapper.instance().checkRegex).to.be.a('function');
  });
});

// Invariant Violation: Could not find "store" in either the context or props of.
// Either wrap the root component in a <Provider>, or explicitly pass "store" as a prop to
<commit_msg>[TEST] - Add tests for inputValidator.jsx from Reducers folder<commit_after>import React from 'react';
import { expect } from 'chai';
import { shallow } from 'enzyme';
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import Controls from '../client/controls/controls';
import Challenge from '../client/challenge/challenge';
import Challenges from '../client/challenges';
import InputRegexValidation from '../client/challenge/inputRegexValidation';
import reducer from '../client/reducers/index';

import { inputValidator } from '../client/reducers/inputValidation';
import { regexValidator } from '../client/reducers/regexValidation';

const finalStore = applyMiddleware(thunk)(createStore);
const testStore = finalStore(reducer);

describe('<Controls />', () => {
  it('should have div tag', () => {
    const wrapper = shallow(<Controls store={testStore} />);
    expect(wrapper.find('div')).to.have.length(1);
  });
});

describe('[Reducer]: InputValidator', () => {
  it('should be a function.', () => {
    // console.log(inputValidator,'***');
    expect(typeof inputValidator).to.equal('function');
  });

  it('should return an object with a property of wellFormedInput.', () => {
    const action = { newInput: '/abc/'};
    const result = inputValidator({}, action);
    expect(result.hasOwnProperty('wellFormedInput')).to.equal(true);
  });

  it('should check if user input is in proper regex format.', () => {
    const action = { newInput: '/abc/'};
    const action2 = { newInput: 'abc'};
    const result = inputValidator({}, action);
    const result2 = inputValidator({}, action2);
    expect(result.wellFormedInput).to.equal(true);
    expect(result2.wellFormedInput).to.equal(false);
  })

});
// describe('<InputRegexValidation />', () => {
//   const wrapper = shallow(<InputRegexValidation store={testStore} />);
//   it('checkRegex should be defined', () => {
//     expect(wrapper.checkRegex).to.be.defined;
//   });

//   it('checkRegex should be a function', () => {
//     expect(wrapper.instance().checkRegex).to.be.a('function');
//   });
// });

// Invariant Violation: Could not find "store" in either the context or props of.
// Either wrap the root component in a <Provider>, or explicitly pass "store" as a prop to
<|endoftext|>


<commit_before>import { sortByYAndX } from 'utils/variables/collected-variables-utils';
import maxBy from 'lodash.maxby';

import * as ResponseFormatSimple from './response-format-simple';
import * as ResponseFormatSingle from './response-format-single';
import * as CodeList from './codes-list';
import * as Dimension from './dimension';
import * as Responses from './responses';
import { hasChild } from 'utils/codes-lists/codes-lists-utils';

import {
  DIMENSION_TYPE,
  DIMENSION_FORMATS,
  QUESTION_TYPE_ENUM,
  DATATYPE_NAME,
  DEFAULT_CODES_LIST_SELECTOR_PATH,
} from 'constants/pogues-constants';

const { PRIMARY, SECONDARY, MEASURE, LIST_MEASURE } = DIMENSION_TYPE;
const { LIST, CODES_LIST } = DIMENSION_FORMATS;
const { SIMPLE, SINGLE_CHOICE } = QUESTION_TYPE_ENUM;
const { TEXT } = DATATYPE_NAME;

// HELPERS

function getDimensionsByType(type, dimensions) {
  let dimension;

  for (let i = 0; i < dimensions.length; i += 1) {
    if (dimensions[i].dimensionType === type) {
      dimension = dimensions[i];
      break;
    }
  }

  return dimension;
}

function getDimensionsMeasures(dimensions) {
  return dimensions.reduce((acc, d) => {
    if (d.dimensionType === MEASURE) acc.push(d);
    return acc;
  }, []);
}

function getResponsesOffset(primaryState, secondaryState, activeCodeLists) {
  let responseOffset = 1;

  if (primaryState.type === CODES_LIST) {
    const {
      CODES_LIST: {
        [DEFAULT_CODES_LIST_SELECTOR_PATH]: { id: codesListIdPrimary },
      },
    } = primaryState;
    let responseOffsetSecondary = 1;

    if (secondaryState) {
      const {
        [DEFAULT_CODES_LIST_SELECTOR_PATH]: { id: codesListIdSecondary },
      } = secondaryState;
      responseOffsetSecondary = Object.keys(
        activeCodeLists[codesListIdSecondary].codes,
      ).length;
    }
    const listCodes = Object.keys(
      activeCodeLists[codesListIdPrimary].codes,
    ).map(key => activeCodeLists[codesListIdPrimary].codes[key]);
    const codes = listCodes.filter(code => !hasChild(code, listCodes));
    responseOffset = codes.length * responseOffsetSecondary;
  }
  return responseOffset;
}

function getMeasuresModel(responses, dimensions, offset) {
  const responsesModel = [];
  for (let i = 0; i < dimensions.length; i += 1) {

    if (responses[i].Datatype.typeName=== DATATYPE_NAME.DATE ) {
      responses[i].Datatype.Format  === responses[i].Datatype.Format.toLowerCase();
    }

    if (responses[i].Datatype.typeName=== DATATYPE_NAME.DURATION) {
      if(responses[i].Datatype.Minimum !== undefined){
        let strminimum = responses[i].Datatype.Minimum;
        let matches_minimum = strminimum.match(/\d+/g);
        if (responses[i].Datatype.Format === 'PTnHnM') {
          responses[i].Datatype.Mihours = matches_minimum[0] == 0 ? '' :matches_minimum[0];
          responses[i].Datatype.Miminutes =  matches_minimum[1] == 0 ? '' :matches_minimum[0];
        }
        if (responses[i].Datatype.Format === 'PnYnM') {
          responses[i].Datatype.Miyears = matches_minimum[0] == 0 ? '' :matches_minimum[0];
          responses[i].Datatype.Mimonths = matches_minimum[1] == 0 ? '' :matches_minimum[0];
        }
        if (responses[i].Datatype.Format === 'HH:CH') {
          responses[i].Datatype.Mihundhours = matches_minimum[0][0] == 0 ? matches_minimum[0].slice(1) : matches_minimum[0];
          responses[i].Datatype.Mihundredths = matches_minimum[1][0] == 0 ? matches_minimum[1].slice(1) : matches_minimum[1];
        }
      }
      if(responses[i].Datatype.Maximum !== undefined){
        let strmaximum = responses[i].Datatype.Maximum;
        let matches_maximum = strmaximum.match(/\d+/g);
        if (responses[i].Datatype.Format === 'PTnHnM') {
          responses[i].Datatype.Mahours = matches_maximum[0] == 0 ? '' :matches_maximum[0];
          responses[i].Datatype.Maminutes = matches_maximum[1] == 0 ? '' :matches_maximum[0];
        }
        if (responses[i].Datatype.Format === 'PnYnM') {
          responses[i].Datatype.Mayears = matches_maximum[0] == 0 ? '' :matches_maximum[0];
          responses[i].Datatype.Mamonths = matches_maximum[1] == 0 ? '' :matches_maximum[0];
        }
        if (responses[i].Datatype.Format === 'HH:CH') {
          responses[i].Datatype.Mahundhours = matches_maximum[0][0] == 0 ? matches_maximum[0].slice(1) : matches_maximum[0];
          responses[i].Datatype.Mahundredths = matches_maximum[1][0] == 0 ? matches_maximum[1].slice(1) : matches_maximum[1];
        }
      }
    }

    responsesModel.push({
      Label: dimensions[i].Label,
      response: responses[i * offset],
    });
  }

  return responsesModel;
}

function parseDynamic(dynamic) {
  return dynamic.split('-').map(v => {
    return v.length > 0 ? parseInt(v, 10) : 0;
  });
}

// REMOTE TO STATE

function remoteToStatePrimary(remote) {
  const { totalLabel, dynamic, CodeListReference } = remote;
  let state = {};

  if (totalLabel) {
    state.showTotalLabel = '1';
    state.totalLabel = totalLabel;
  }

  if (CodeListReference) {
    state = {
      ...state,
      type: CODES_LIST,
      [CODES_LIST]: {
        [DEFAULT_CODES_LIST_SELECTOR_PATH]: CodeList.remoteToState(
          CodeListReference,
        ),
      },
    };
  } else {
    const [numLinesMin, numLinesMax] = parseDynamic(dynamic);
    state = {
      ...state,
      type: LIST,
      [LIST]: {
        numLinesMin: numLinesMin,
        numLinesMax: numLinesMax,
      },
    };
  }

  return state;
}

function remoteToStateSecondary(remote) {
  const { totalLabel, CodeListReference } = remote;
  const state = {
    showSecondaryAxis: true,
    [DEFAULT_CODES_LIST_SELECTOR_PATH]: CodeList.remoteToState(
      CodeListReference,
    ),
  };

  if (totalLabel) {
    state.showTotalLabel = '1';
    state.totalLabel = totalLabel;
  }

  return state;
}

function remoteToStateMeasure(remote) {
  const {
    Label: label,
    response: { CodeListReference, Datatype },
  } = remote;
  const state = {};

  if (CodeListReference) {
    state.type = SINGLE_CHOICE;
    state[SINGLE_CHOICE] = ResponseFormatSingle.remoteToState({
      responses: [{ Datatype, CodeListReference }],
    });
  } else {
    state.type = SIMPLE;
    state[SIMPLE] = ResponseFormatSimple.remoteToState({
      responses: [{ Datatype }],
    });
  }

  return {
    label,
    ...state,
  };
}

export function remoteToState(remote, codesListsStore) {
  const { dimensions, responses } = remote;
  const state = {};

  // Dimensions
  const dimensionSecondaryModel = getDimensionsByType(SECONDARY, dimensions);
  const dimensionPrimaryModel = getDimensionsByType(PRIMARY, dimensions);
  const dimensionMeasuresModel = getDimensionsMeasures(dimensions);

  // Primary and secondary state
  state[PRIMARY] = remoteToStatePrimary(dimensionPrimaryModel);

  if (dimensionSecondaryModel) {
    state[SECONDARY] = remoteToStateSecondary(dimensionSecondaryModel);
  }

  // Measures
  const responsesOffset = getResponsesOffset(
    state[PRIMARY],
    state[SECONDARY],
    codesListsStore,
  );
  const responsesMeasuresModel = getMeasuresModel(
    responses,
    dimensionMeasuresModel,
    responsesOffset,
  );

  if (dimensionSecondaryModel) {
    state[MEASURE] = remoteToStateMeasure(responsesMeasuresModel[0]);
  } else {
    state[LIST_MEASURE] = responsesMeasuresModel.map(m =>
      remoteToStateMeasure(m),
    );
  }

  return state;
}

// STATE TO REMOTE

function stateToResponseState(state) {
  const { type: measureType, [measureType]: measureTypeState } = state;
  let responseState = {};

  if (measureType === SIMPLE) {
    const {
      mandatory,
      type: typeName,
      [typeName]: simpleState,
    } = measureTypeState;

    let customsimpleState = simpleState;

    if (customsimpleState.format !== undefined && typeName === DATATYPE_NAME.DATE) {
      const { format, minimum, maximum, ...durationsimpleState } = simpleState;

      durationsimpleState.format = format.toUpperCase();
      if (customsimpleState.minimum !== '') {
        durationsimpleState.minimum = minimum;
      }
      if (customsimpleState.maximum !== '') {
        durationsimpleState.maximum = maximum;
      }
      customsimpleState = durationsimpleState;
    }

    if (typeName === DATATYPE_NAME.DURATION){
      const {
        miyears,
        mimonths,
        mayears,
        mamonths,
        mihours,
        miminutes,
        mahours,
        maminutes,
        mihundhours,
        mihundredths,
        mahundhours,
        mahundredths
      } = customsimpleState;
      let durationDataType = {};
      durationDataType.format = simpleState.format;
      if (simpleState.format === 'PnYnM' ) {
        if(miyears !== "" || mimonths !== ""){
          durationDataType.minimum = `P${miyears || 0}Y${mimonths || 0}M`;
        }
        if(mayears !== "" || mamonths !== "" ){
         durationDataType.maximum = `P${mayears || 0}Y${mamonths || 0}M`;
        }
      }
      if (simpleState.format === 'PTnHnM') {
        if(mihours || miminutes){
          durationDataType.minimum = `PT${mihours || 0}H${miminutes || 0}M`;
        }
        if(mahours || maminutes){
       durationDataType.maximum = `PT${mahours || 0}H${maminutes || 0}M`;
        }
      }
      if (simpleState.format === 'HH:CH') {
        if(mihundhours || mihundredths){
          durationDataType.minimum = `${mihundhours ? ('0' + mihundhours).slice(-2) : '00'}:${mihundredths ? ('0' + mihundredths).slice(-2) : '00'}`;
         }
         if(mahundhours || mahundredths){
          durationDataType.maximum = `${mahundhours ? ('0' + mahundhours).slice(-2) : '00'}:${mahundredths ? ('0' + mahundredths).slice(-2) : '00'}`;
         }
      }
    customsimpleState = durationDataType;
  }

    responseState = { mandatory, typeName, ...customsimpleState };

  } else {
    const {
      mandatory,
      visHint,
      [DEFAULT_CODES_LIST_SELECTOR_PATH]: { id: codesListId },
    } = measureTypeState;
    responseState = {
      mandatory,
      codesListId,
      typeName: TEXT,
      maxLength: 1,
      pattern: '',
      visHint,
    };
  }

  return responseState;
}

export function stateToRemote(
  state,
  collectedVariables,
  collectedVariablesStore,
) {
  const {
    [PRIMARY]: primaryState,
    [SECONDARY]: secondaryState,
    [MEASURE]: measureState,
    [LIST_MEASURE]: listMeasuresState,
  } = state;

  const {
    type,
    [type]: { type: typePrimaryCodesList, ...primaryTypeState },
    ...totalLabelPrimaryState
  } = primaryState;
  const dimensionsModel = [];
  let responsesState = [];

  // Primary and secondary dimension
  dimensionsModel.push(
    Dimension.stateToRemote({
      type: PRIMARY,
      ...primaryTypeState,
      ...totalLabelPrimaryState,
    }),
  );

  if (secondaryState) {
    const {
      type: typeSecondaryCodesList,
      ...secondaryTypeState
    } = secondaryState;
    dimensionsModel.push(
      Dimension.stateToRemote({ type: SECONDARY, ...secondaryTypeState }),
    );
  }

  // Measures dimensions
  if (measureState) {

    dimensionsModel.push(
      Dimension.stateToRemote({ type: MEASURE, label: measureState.label }),
    );
    responsesState = [stateToResponseState(measureState)];
  } else {
    for (let i = 0; i < listMeasuresState.length; i += 1) {
      dimensionsModel.push(
        Dimension.stateToRemote({
          type: MEASURE,
          label: listMeasuresState[i].label,
        }),
      );
      responsesState.push(stateToResponseState(listMeasuresState[i]));
    }
  }

  // Responses

  const numDataTypes = measureState
    ? maxBy(collectedVariables.map(key => collectedVariablesStore[key]), 'y')
        .y || 1
    : listMeasuresState.length;
  let responsesModel = [];
  let mappingsModel = [];
  let attributesModel = [];

  for (let i = 0; i < numDataTypes; i += 1) {
    const collectedVariablesByDatatype = collectedVariables
      .sort(sortByYAndX(collectedVariablesStore))
      .map(key => collectedVariablesStore[key])
      .filter(variable => !variable.y || variable.y === i + 1)
      .map(variable => variable.id);

    const responsesModelByRow = Responses.stateToModel(
      responsesState[measureState ? 0 : i],
      collectedVariablesByDatatype,
      collectedVariablesStore,
      QUESTION_TYPE_ENUM.TABLE
    );

    responsesModel = [...responsesModel, ...responsesModelByRow.Response];
    mappingsModel = [...mappingsModel, ...responsesModelByRow.Mapping];
    attributesModel = [...attributesModel, ...responsesModelByRow.Attribute];
  }

  mappingsModel = mappingsModel.sort((m1, m2) => {
    const [x1, y1] = m1.MappingTarget.split(' ');
    const [x2, y2] = m2.MappingTarget.split(' ');
    if (!y1) return parseInt(x1, 10) - parseInt(x2, 10);
    return (
      parseInt(y1, 10) * 100 +
      parseInt(x1, 10) -
      (parseInt(y2, 10) * 100 + parseInt(x2, 10))
    );
  });
  return {
    Dimension: dimensionsModel,
    Response: responsesModel,
    Mapping: mappingsModel,
    Attribute: attributesModel,
  };
}
<commit_msg>Temporary patch to fix loading in store bug<commit_after>import { sortByYAndX } from 'utils/variables/collected-variables-utils';
import maxBy from 'lodash.maxby';

import * as ResponseFormatSimple from './response-format-simple';
import * as ResponseFormatSingle from './response-format-single';
import * as CodeList from './codes-list';
import * as Dimension from './dimension';
import * as Responses from './responses';
import { hasChild } from 'utils/codes-lists/codes-lists-utils';

import {
  DIMENSION_TYPE,
  DIMENSION_FORMATS,
  QUESTION_TYPE_ENUM,
  DATATYPE_NAME,
  DEFAULT_CODES_LIST_SELECTOR_PATH,
} from 'constants/pogues-constants';

const { PRIMARY, SECONDARY, MEASURE, LIST_MEASURE } = DIMENSION_TYPE;
const { LIST, CODES_LIST } = DIMENSION_FORMATS;
const { SIMPLE, SINGLE_CHOICE } = QUESTION_TYPE_ENUM;
const { TEXT } = DATATYPE_NAME;

// HELPERS

function getDimensionsByType(type, dimensions) {
  let dimension;

  for (let i = 0; i < dimensions.length; i += 1) {
    if (dimensions[i].dimensionType === type) {
      dimension = dimensions[i];
      break;
    }
  }

  return dimension;
}

function getDimensionsMeasures(dimensions) {
  return dimensions.reduce((acc, d) => {
    if (d.dimensionType === MEASURE) acc.push(d);
    return acc;
  }, []);
}

function getResponsesOffset(primaryState, secondaryState, activeCodeLists) {
  let responseOffset = 1;

  if (primaryState.type === CODES_LIST) {
    const {
      CODES_LIST: {
        [DEFAULT_CODES_LIST_SELECTOR_PATH]: { id: codesListIdPrimary },
      },
    } = primaryState;
    let responseOffsetSecondary = 1;

    if (secondaryState) {
      const {
        [DEFAULT_CODES_LIST_SELECTOR_PATH]: { id: codesListIdSecondary },
      } = secondaryState;
      responseOffsetSecondary = Object.keys(
        activeCodeLists[codesListIdSecondary].codes,
      ).length;
    }
    const listCodes = Object.keys(
      activeCodeLists[codesListIdPrimary].codes,
    ).map(key => activeCodeLists[codesListIdPrimary].codes[key]);
    const codes = listCodes.filter(code => !hasChild(code, listCodes));
    responseOffset = codes.length * responseOffsetSecondary;
  }
  return responseOffset;
}

function getMeasuresModel(responses, dimensions, offset) {
  debugger;
  const responsesModel = [];
  for (let i = 0; i < dimensions.length; i += 1) {

    if (responses[i].Datatype.typeName === DATATYPE_NAME.DATE) {
      if (responses[i].Datatype.Format) {
        responses[i].Datatype.Format === responses[i].Datatype.Format.toLowerCase();
      }
      else {
        console.log("WARNING : No Format for Datatype DATE in the remote instrument");
        responses[i].Datatype.Format === "yyyy-mm-dd";
      }
    }

    if (responses[i].Datatype.typeName === DATATYPE_NAME.DURATION) {
      if (responses[i].Datatype.Minimum !== undefined) {
        let strminimum = responses[i].Datatype.Minimum;
        let matches_minimum = strminimum.match(/\d+/g);
        if (responses[i].Datatype.Format === 'PTnHnM') {
          responses[i].Datatype.Mihours = matches_minimum[0] == 0 ? '' : matches_minimum[0];
          responses[i].Datatype.Miminutes = matches_minimum[1] == 0 ? '' : matches_minimum[0];
        }
        if (responses[i].Datatype.Format === 'PnYnM') {
          responses[i].Datatype.Miyears = matches_minimum[0] == 0 ? '' : matches_minimum[0];
          responses[i].Datatype.Mimonths = matches_minimum[1] == 0 ? '' : matches_minimum[0];
        }
        if (responses[i].Datatype.Format === 'HH:CH') {
          responses[i].Datatype.Mihundhours = matches_minimum[0][0] == 0 ? matches_minimum[0].slice(1) : matches_minimum[0];
          responses[i].Datatype.Mihundredths = matches_minimum[1][0] == 0 ? matches_minimum[1].slice(1) : matches_minimum[1];
        }
      }
      if (responses[i].Datatype.Maximum !== undefined) {
        let strmaximum = responses[i].Datatype.Maximum;
        let matches_maximum = strmaximum.match(/\d+/g);
        if (responses[i].Datatype.Format === 'PTnHnM') {
          responses[i].Datatype.Mahours = matches_maximum[0] == 0 ? '' : matches_maximum[0];
          responses[i].Datatype.Maminutes = matches_maximum[1] == 0 ? '' : matches_maximum[0];
        }
        if (responses[i].Datatype.Format === 'PnYnM') {
          responses[i].Datatype.Mayears = matches_maximum[0] == 0 ? '' : matches_maximum[0];
          responses[i].Datatype.Mamonths = matches_maximum[1] == 0 ? '' : matches_maximum[0];
        }
        if (responses[i].Datatype.Format === 'HH:CH') {
          responses[i].Datatype.Mahundhours = matches_maximum[0][0] == 0 ? matches_maximum[0].slice(1) : matches_maximum[0];
          responses[i].Datatype.Mahundredths = matches_maximum[1][0] == 0 ? matches_maximum[1].slice(1) : matches_maximum[1];
        }
      }
    }

    responsesModel.push({
      Label: dimensions[i].Label,
      response: responses[i * offset],
    });
  }

  return responsesModel;
}

function parseDynamic(dynamic) {
  return dynamic.split('-').map(v => {
    return v.length > 0 ? parseInt(v, 10) : 0;
  });
}

// REMOTE TO STATE

function remoteToStatePrimary(remote) {
  const { totalLabel, dynamic, CodeListReference } = remote;
  let state = {};

  if (totalLabel) {
    state.showTotalLabel = '1';
    state.totalLabel = totalLabel;
  }

  if (CodeListReference) {
    state = {
      ...state,
      type: CODES_LIST,
      [CODES_LIST]: {
        [DEFAULT_CODES_LIST_SELECTOR_PATH]: CodeList.remoteToState(
          CodeListReference,
        ),
      },
    };
  } else {
    const [numLinesMin, numLinesMax] = parseDynamic(dynamic);
    state = {
      ...state,
      type: LIST,
      [LIST]: {
        numLinesMin: numLinesMin,
        numLinesMax: numLinesMax,
      },
    };
  }

  return state;
}

function remoteToStateSecondary(remote) {
  const { totalLabel, CodeListReference } = remote;
  const state = {
    showSecondaryAxis: true,
    [DEFAULT_CODES_LIST_SELECTOR_PATH]: CodeList.remoteToState(
      CodeListReference,
    ),
  };

  if (totalLabel) {
    state.showTotalLabel = '1';
    state.totalLabel = totalLabel;
  }

  return state;
}

function remoteToStateMeasure(remote) {
  const {
    Label: label,
    response: { CodeListReference, Datatype },
  } = remote;
  const state = {};

  if (CodeListReference) {
    state.type = SINGLE_CHOICE;
    state[SINGLE_CHOICE] = ResponseFormatSingle.remoteToState({
      responses: [{ Datatype, CodeListReference }],
    });
  } else {
    state.type = SIMPLE;
    state[SIMPLE] = ResponseFormatSimple.remoteToState({
      responses: [{ Datatype }],
    });
  }

  return {
    label,
    ...state,
  };
}

export function remoteToState(remote, codesListsStore) {
  const { dimensions, responses } = remote;
  const state = {};

  // Dimensions
  const dimensionSecondaryModel = getDimensionsByType(SECONDARY, dimensions);
  const dimensionPrimaryModel = getDimensionsByType(PRIMARY, dimensions);
  const dimensionMeasuresModel = getDimensionsMeasures(dimensions);

  // Primary and secondary state
  state[PRIMARY] = remoteToStatePrimary(dimensionPrimaryModel);

  if (dimensionSecondaryModel) {
    state[SECONDARY] = remoteToStateSecondary(dimensionSecondaryModel);
  }

  // Measures
  const responsesOffset = getResponsesOffset(
    state[PRIMARY],
    state[SECONDARY],
    codesListsStore,
  );
  const responsesMeasuresModel = getMeasuresModel(
    responses,
    dimensionMeasuresModel,
    responsesOffset,
  );

  if (dimensionSecondaryModel) {
    state[MEASURE] = remoteToStateMeasure(responsesMeasuresModel[0]);
  } else {
    state[LIST_MEASURE] = responsesMeasuresModel.map(m =>
      remoteToStateMeasure(m),
    );
  }

  return state;
}

// STATE TO REMOTE

function stateToResponseState(state) {
  const { type: measureType, [measureType]: measureTypeState } = state;
  let responseState = {};

  if (measureType === SIMPLE) {
    const {
      mandatory,
      type: typeName,
      [typeName]: simpleState,
    } = measureTypeState;

    let customsimpleState = simpleState;

    if (customsimpleState.format !== undefined && typeName === DATATYPE_NAME.DATE) {
      const { format, minimum, maximum, ...durationsimpleState } = simpleState;

      durationsimpleState.format = format.toUpperCase();
      if (customsimpleState.minimum !== '') {
        durationsimpleState.minimum = minimum;
      }
      if (customsimpleState.maximum !== '') {
        durationsimpleState.maximum = maximum;
      }
      customsimpleState = durationsimpleState;
    }

    if (typeName === DATATYPE_NAME.DURATION) {
      const {
        miyears,
        mimonths,
        mayears,
        mamonths,
        mihours,
        miminutes,
        mahours,
        maminutes,
        mihundhours,
        mihundredths,
        mahundhours,
        mahundredths
      } = customsimpleState;
      let durationDataType = {};
      durationDataType.format = simpleState.format;
      if (simpleState.format === 'PnYnM') {
        if (miyears !== "" || mimonths !== "") {
          durationDataType.minimum = `P${miyears || 0}Y${mimonths || 0}M`;
        }
        if (mayears !== "" || mamonths !== "") {
          durationDataType.maximum = `P${mayears || 0}Y${mamonths || 0}M`;
        }
      }
      if (simpleState.format === 'PTnHnM') {
        if (mihours || miminutes) {
          durationDataType.minimum = `PT${mihours || 0}H${miminutes || 0}M`;
        }
        if (mahours || maminutes) {
          durationDataType.maximum = `PT${mahours || 0}H${maminutes || 0}M`;
        }
      }
      if (simpleState.format === 'HH:CH') {
        if (mihundhours || mihundredths) {
          durationDataType.minimum = `${mihundhours ? ('0' + mihundhours).slice(-2) : '00'}:${mihundredths ? ('0' + mihundredths).slice(-2) : '00'}`;
        }
        if (mahundhours || mahundredths) {
          durationDataType.maximum = `${mahundhours ? ('0' + mahundhours).slice(-2) : '00'}:${mahundredths ? ('0' + mahundredths).slice(-2) : '00'}`;
        }
      }
      customsimpleState = durationDataType;
    }

    responseState = { mandatory, typeName, ...customsimpleState };

  } else {
    const {
      mandatory,
      visHint,
      [DEFAULT_CODES_LIST_SELECTOR_PATH]: { id: codesListId },
    } = measureTypeState;
    responseState = {
      mandatory,
      codesListId,
      typeName: TEXT,
      maxLength: 1,
      pattern: '',
      visHint,
    };
  }

  return responseState;
}

export function stateToRemote(
  state,
  collectedVariables,
  collectedVariablesStore,
) {
  const {
    [PRIMARY]: primaryState,
    [SECONDARY]: secondaryState,
    [MEASURE]: measureState,
    [LIST_MEASURE]: listMeasuresState,
  } = state;

  const {
    type,
    [type]: { type: typePrimaryCodesList, ...primaryTypeState },
    ...totalLabelPrimaryState
  } = primaryState;
  const dimensionsModel = [];
  let responsesState = [];

  // Primary and secondary dimension
  dimensionsModel.push(
    Dimension.stateToRemote({
      type: PRIMARY,
      ...primaryTypeState,
      ...totalLabelPrimaryState,
    }),
  );

  if (secondaryState) {
    const {
      type: typeSecondaryCodesList,
      ...secondaryTypeState
    } = secondaryState;
    dimensionsModel.push(
      Dimension.stateToRemote({ type: SECONDARY, ...secondaryTypeState }),
    );
  }

  // Measures dimensions
  if (measureState) {

    dimensionsModel.push(
      Dimension.stateToRemote({ type: MEASURE, label: measureState.label }),
    );
    responsesState = [stateToResponseState(measureState)];
  } else {
    for (let i = 0; i < listMeasuresState.length; i += 1) {
      dimensionsModel.push(
        Dimension.stateToRemote({
          type: MEASURE,
          label: listMeasuresState[i].label,
        }),
      );
      responsesState.push(stateToResponseState(listMeasuresState[i]));
    }
  }

  // Responses

  const numDataTypes = measureState
    ? maxBy(collectedVariables.map(key => collectedVariablesStore[key]), 'y')
      .y || 1
    : listMeasuresState.length;
  let responsesModel = [];
  let mappingsModel = [];
  let attributesModel = [];

  for (let i = 0; i < numDataTypes; i += 1) {
    const collectedVariablesByDatatype = collectedVariables
      .sort(sortByYAndX(collectedVariablesStore))
      .map(key => collectedVariablesStore[key])
      .filter(variable => !variable.y || variable.y === i + 1)
      .map(variable => variable.id);

    const responsesModelByRow = Responses.stateToModel(
      responsesState[measureState ? 0 : i],
      collectedVariablesByDatatype,
      collectedVariablesStore,
      QUESTION_TYPE_ENUM.TABLE
    );

    responsesModel = [...responsesModel, ...responsesModelByRow.Response];
    mappingsModel = [...mappingsModel, ...responsesModelByRow.Mapping];
    attributesModel = [...attributesModel, ...responsesModelByRow.Attribute];
  }

  mappingsModel = mappingsModel.sort((m1, m2) => {
    const [x1, y1] = m1.MappingTarget.split(' ');
    const [x2, y2] = m2.MappingTarget.split(' ');
    if (!y1) return parseInt(x1, 10) - parseInt(x2, 10);
    return (
      parseInt(y1, 10) * 100 +
      parseInt(x1, 10) -
      (parseInt(y2, 10) * 100 + parseInt(x2, 10))
    );
  });
  return {
    Dimension: dimensionsModel,
    Response: responsesModel,
    Mapping: mappingsModel,
    Attribute: attributesModel,
  };
}
<|endoftext|>


<commit_before>chrome.runtime.sendMessage({requestFreedom: true}, function(res) {
	freedom = res.freedom;
	blockIfFree();
	fetchVisits();
});

function fetchVisits() {
	chrome.runtime.sendMessage({requestVisits: true}, function(res) {
		console.log(res);
		var counterBox = document.getElementById('turkey-counter');
		if (counterBox != null) {
			var counterMetric = document.createTextNode("You've visited YouTube " + res.visits.length + " times today.");
			counterBox.appendChild(counterMetric);
		}
	});
}

document.getElementById('content').addEventListener('DOMSubtreeModified', blockOnDebouncedDOMEvents);

function blockOnDebouncedDOMEvents() {
	console.log("detected dom subtree modifiedcation");
	var content = document.getElementById('content');
	if (content != null) {
		content.removeEventListener('DOMSubtreeModified', blockOnDebouncedDOMEvents);
		setTimeout(function () {
				blockIfFree();
				var content = document.getElementById('content');
				if (content != null) {
					content.addEventListener('DOMSubtreeModified', blockOnDebouncedDOMEvents);
				}
			}, 500);
	}
}

function blockIfFree() {
	if (freedom === null) {
		alert('freedom not set');
	} else if (freedom == "false") {
		console.log("Allow content");
		//window.clearInterval(blockId);
	} else {
		console.log("Block content!");
		blockAndDisplay();
		//blockId = window.setInterval(blockAndDisplay, 10);
	}
}

function submitReason(event) {
	if (event.keyCode == 13) {
		console.log('submit reason ' + event.keyCode);
		console.log(this.value);
		var http = new XMLHttpRequest();

		var queryString = "";
		queryString += "reason=" + this.value;

		http.open("POST", url, true);
		http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

		console.log(queryString);

		http.send(queryString);
	}
}

function blockAndDisplay() {
	var container = document.getElementById('page');

	// remove the content pane if it exists
	var content = document.getElementById('content');
	if (content != null) {
		if (content.parentNode == container) {
			container.removeChild(content);
		} else {
			console.log(content.parentNode);
		}
	}

	var maybeCounter = document.getElementById('turkey-counter');
	if (maybeCounter == null) {
		var counterBox = document.createElement('div');
		counterBox.setAttribute('id', 'turkey-counter');
		container.appendChild(counterBox);
	}

	// add the question pane if it hasn't been added yet
	var maybeQuestion = document.getElementById('question');
	if (maybeQuestion == null) {
		var question = document.createElement('div');
		question.setAttribute('id', 'question');
		var textbox = document.createElement('input');
		textbox.setAttribute('type', 'text');
		textbox.setAttribute('name', 'reason');
		textbox.onkeypress = submitReason;
		var questionText = document.createTextNode("Why are you on YouTube?");
		question.appendChild(questionText);
		question.appendChild(textbox);

		container.appendChild(question);
	}

	var mastHead = document.getElementById('video-masthead-container');
	if (mastHead != null) {
		mastHead.innerHTML = "";
	}
}
<commit_msg>factor out dom manipulations<commit_after>chrome.runtime.sendMessage({requestFreedom: true}, function(res) {
	freedom = res.freedom;
	blockIfFree();
	fetchVisits();
});

function fetchVisits() {
	chrome.runtime.sendMessage({requestVisits: true}, function(res) {
		console.log(res);
		var counterBox = document.getElementById('turkey-counter');
		if (counterBox != null) {
			var counterMetric = document.createTextNode("You've visited YouTube " + res.visits.length + " times today.");
			counterBox.appendChild(counterMetric);
		}
	});
}

document.getElementById('content').addEventListener('DOMSubtreeModified', blockOnDebouncedDOMEvents);

function blockOnDebouncedDOMEvents() {
	console.log("detected dom subtree modifiedcation");
	var content = document.getElementById('content');
	if (content != null) {
		content.removeEventListener('DOMSubtreeModified', blockOnDebouncedDOMEvents);
		setTimeout(function () {
				blockIfFree();
				var content = document.getElementById('content');
				if (content != null) {
					content.addEventListener('DOMSubtreeModified', blockOnDebouncedDOMEvents);
				}
			}, 500);
	}
}

function blockIfFree() {
	if (freedom === null) {
		alert('freedom not set');
	} else if (freedom == "false") {
		console.log("Allow content");
		//window.clearInterval(blockId);
	} else {
		console.log("Block content!");
		blockAndDisplay();
		//blockId = window.setInterval(blockAndDisplay, 10);
	}
}

function submitReason(event) {
	if (event.keyCode == 13) {
		console.log('submit reason ' + event.keyCode);
		console.log(this.value);
		var http = new XMLHttpRequest();

		var queryString = "";
		queryString += "reason=" + this.value;

		http.open("POST", url, true);
		http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

		console.log(queryString);

		http.send(queryString);
	}
}

function blockAndDisplay() {
	var container = document.getElementById('page');

	// remove the content pane if it exists
	var content = document.getElementById('content');
	if (content != null) {
		if (content.parentNode == container) {
			container.removeChild(content);
		} else {
			console.log(content.parentNode);
		}
	}

	// add the counter pane if it hasn't been added yet
	var maybeCounter = document.getElementById('turkey-counter');
	if (maybeCounter == null) {
		appendCounterPane(container);
	}

	// add the question pane if it hasn't been added yet
	var maybeQuestion = document.getElementById('question');
	if (maybeQuestion == null) {
		appendQuestionPane(container);
	}

	var mastHead = document.getElementById('video-masthead-container');
	if (mastHead != null) {
		mastHead.innerHTML = "";
	}
}

function appendCounterPane(container) {
	var counterBox = document.createElement('div');
	counterBox.setAttribute('id', 'turkey-counter');
	container.appendChild(counterBox);
}

function appendQuestionPane(container) {
	var question = document.createElement('div');
	question.setAttribute('id', 'question');
	var textbox = document.createElement('input');
	textbox.setAttribute('type', 'text');
	textbox.setAttribute('name', 'reason');
	textbox.onkeypress = submitReason;
	var questionText = document.createTextNode("Why are you on YouTube?");
	question.appendChild(questionText);
	question.appendChild(textbox);

	container.appendChild(question);
}<|endoftext|>