<commit_before>/**
 * This file is part of Wizkers.io
 *
 * The MIT License (MIT)
 *  Copyright (c) 2016 Edouard Lafargue, ed@wizkers.io
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the Software
 * is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
 * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/**
 * Bluetooth Low Energy connection, implemented using the Cordova BTLE
 * API (https://github.com/randdusing/bluetoothle)
 *
 * Note: only notifications are implemented for now.
 */
define(function (require) {

    "use strict";

    var Backbone = require('backbone'),
        abu = require('app/lib/abutils');

    // TODO: accept a list of service UUIDs and a list of Characteristic UUIDs
    //       rather than a single value.

    /**
     * Instanciates a BTLE connection
     * @param {Object} path  Contains the address of the BTLE device we want to connect to.
     * @param {Object} settings not used.
     */
    var cordovaBTLE = function (path, settings) {

        /////////
        // Initialization
        /////////
        var portOpen = false,
            deviceDisappeared = false, // becomes true if the device disappeared (we will try to
            // reconnect if it comes back
            currentService = null,
            currentCharacteristics = null,
            self = this,
            devAddress = path,
            timeoutCheckTimer = 0;

        ///////////
        // Public methods
        ///////////

        /**
         * Send data
         * @param {ArrayBuffer} data The command, already formatted for sending.
         * @param {Object} info contains the service_uuid and characterictic_uuid to write to
         */
        this.write = function (data, info, callback) {
            if (!portOpen || info == undefined || callback == undefined)
                return;

            var encodedString = bluetoothle.bytesToEncodedString((data instanceof Uint8Array) ? data : new Uint8Array(data));
            var params = {
                value: encodedString,
                address: devAddress,
                service: info.service_uuid,
                characteristic: info.characteristic_uuid,
            };
            if (info.type) {
                params.type = info.type;
            }
            bluetoothle.write(callback,
                              function(e) { console.error('BLE Write error', e)},
                              params);
        };

        /**
         * Read data from the open BTLE device
         */
        this.read = function (service, characteristic) {
            if (!portOpen)
                return;

            var readError = function(e) {
                console.log('[cordovaBTLE] Read error: ' + e);
            };

            var readSuccess = function(s) {
                // Our drivers don't want this base64 stuff, sorry
                s.value = bluetoothle.encodedStringToBytes(s.value)
                    // Pass it on to the driver
                self.trigger('data', s);
            };

            bluetoothle.read(readSuccess,readError,{
                'address': devAddress,
                'service': service,
                'characteristic': characteristic
            });

        }

        /**
         * Subscribe to a service/characteristic
         * @param {[[Type]]} subscribeInfo [[Description]]
         */
        this.subscribe = function (subscribeInfo) {
            if (!portOpen)
                return;
            // Once we are connected, we want to select the service
            // the driver asked for and subscribe to the characteristics
            // the driver wants.

            var params = {
                address: devAddress,
                service: subscribeInfo.service_uuid,
                characteristic: subscribeInfo.characteristic_uuid,
                isNotification: true
            };
            bluetoothle.subscribe(subscribeSuccess, function (err) {
                // We didn't find the service we were looking for, this means
                // this is probably not the right device. Tell the user!
                stats.fullEvent('Cordova BLE', 'subscribe_error', err.message);
                self.trigger('status', {
                    openerror: true,
                    reason: 'Could not connect to the BLE service',
                    description: + err.message
                });
                // Do a disconnect to make sure we end up in a sane state:
                self.close();
            }, params);
        }

        this.close = function () {
            console.log("[cordovaBTLE] Close BTLE connection");
            // We need to disconnect before closing, as per the doc
            bluetoothle.disconnect(function (result) {
                // OK, we can now close the device:
                bluetoothle.close(function (result) {
                    console.log(result);
                    portOpen = false;
                    self.trigger('status', {
                        portopen: portOpen
                    });
                }, function (error) {}, {
                    address: devAddress
                });
            }, function (error) {
                console.log('Disconnect error', error);
                if (error.error == 'isDisconnected') {
                    // Already disconnected, so we can close
                    bluetoothle.close(function (result) {
                        console.log(result);
                        portOpen = false;
                        self.trigger('status', {
                            portopen: portOpen
                        });
                    }, function (error) {}, {
                        address: devAddress
                    });
                }
            }, {
                address: devAddress
            });
        };

        // Has to be called by the backend_driver to actually open the port.
        // This just connects to the device
        this.open = function () {

            // Setup a callback in case we time out
            timeoutCheckTimer = setTimeout(checkConnectDelay, 15000);

            // Callback once we know Bluetooth is enabled
            function doConnect(status) {
                if (status.status != 'enabled')
                    return;
                bluetoothle.connect(trackConnect, trackError, {
                    address: devAddress
                });

            }

            // The Cordova BTLE plugin requires calling initialize at least once.
            // Note that it can be called multiple times, this is not an issue.
            bluetoothle.initialize(doConnect, function (err) {
                console.log(err);
            }, {
                request: true,
                statusReceiver: false
            });
        }

        /////////////
        // Private methods
        /////////////

        /////////////
        //   Callbacks
        /////////////

        // Track connection status
        function trackConnect(result) {
            if (result.status == 'connecting') {
                console.log(result);
                return;
            }
            if (result.status == 'connected') {
                // Right after we connect, we do a service
                // discovery, so that we can then connect to the various
                // services & characteristics. This is the Android call, the
                // iPhone call will be different:
                bluetoothle.discover(function (r) {
                    if (r.status != 'discovered')
                        return;
                    portOpen = true;
                    if (timeoutCheckTimer) {
                        clearTimeout(timeoutCheckTimer);
                        timeoutCheckTimer = 0;
                    }
                    self.trigger('status', {
                        portopen: portOpen,
                        services: r.services
                    });
                    stats.fullEvent('Cordova BLE', 'open_success', '');
                    // Need to send this to tell the front-end we're done reconnecting
                    // and back to normal
                    self.trigger('status', {
                        reconnecting: false
                    });

                }, function (err) {
                    console.log(err);
                    stats.fullEvent('Cordova BLE', 'open_error', err.message);
                }, {
                    address: devAddress
                });
                return;
            }
            if (result.status == 'disconnected') {
                console.log(result);
                // OK, the device disappeared: we will try to
                // reconnect as long as the user does not explicitely
                // ask to close
                portOpen = false;
                // Just keep reconnecting forever...
                //timeoutCheckTimer = setTimeout(checkConnectDelay, 60000);
                // We lost the connection, try to get it back
                bluetoothle.reconnect(trackConnect, trackError, {
                    address: devAddress
                });
                self.trigger('status', {
                    reconnecting: true
                });
            }
        }

        function trackError(err) {
            // This is called whenever we lose the connection
            console.log(err);
            if (!portOpen) {
                // if the port was not open and we got an error callback, this means
                // we were not able to connect in the first place...
                self.trigger('status', {
                    openerror: true,
                    reason: 'Device connection error',
                    description: 'Android error: ' + err.message
                });
                // Do a disconnect to make sure we end up in a sane state:
                self.close();
            } else {
                portOpen = false;
                // Just keep reconnecting forever...
                //timeoutCheckTimer = setTimeout(checkConnectDelay, 60000);
                // We lost the connection, try to get it back
                bluetoothle.reconnect(trackConnect, trackError, {
                    address: devAddress
                });
                self.trigger('status', {
                    reconnecting: true
                });
            }
            return;
        }

        // This is where we get notifications
        function subscribeSuccess(chrc) {
            if (chrc.status == 'subscribedResult') {
                // Our drivers don't want this base64 stuff, sorry
                chrc.value = bluetoothle.encodedStringToBytes(chrc.value)
                    // Pass it on to the driver
                self.trigger('data', chrc);
            }
        }

        // Make sure that if after X seconds we have no connection, we cancel
        // the attempt
        function checkConnectDelay() {
            console.log('Check connect delay timeout');
            if (!portOpen) {
                self.close();
                self.trigger('status', {
                    openerror: true,
                    reason: 'Device connection error',
                    description: 'Could not connect to device.'
                });
            }
        }

        console.log("[cordovaBTLE] Cordova BTLE Library loaded");

    };

    // Add event management to our serial lib, from the Backbone.Events class:
    _.extend(cordovaBTLE.prototype, Backbone.Events);
    return cordovaBTLE;
});<commit_msg>Cordova BTLE: avoid spurious disconnects and rather wait for the device to appear again in case of temporary connection loss.<commit_after>/**
 * This file is part of Wizkers.io
 *
 * The MIT License (MIT)
 *  Copyright (c) 2016 Edouard Lafargue, ed@wizkers.io
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the Software
 * is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
 * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/**
 * Bluetooth Low Energy connection, implemented using the Cordova BTLE
 * API (https://github.com/randdusing/bluetoothle)
 *
 * Note: only notifications are implemented for now.
 */
define(function (require) {

    "use strict";

    var Backbone = require('backbone'),
        abu = require('app/lib/abutils');

    // TODO: accept a list of service UUIDs and a list of Characteristic UUIDs
    //       rather than a single value.

    /**
     * Instanciates a BTLE connection
     * @param {Object} path  Contains the address of the BTLE device we want to connect to.
     * @param {Object} settings not used.
     */
    var cordovaBTLE = function (path, settings) {

        /////////
        // Initialization
        /////////
        var portOpen = false,
            deviceDisappeared = false, // becomes true if the device disappeared (we will try to
            // reconnect if it comes back
            currentService = null,
            currentCharacteristics = null,
            self = this,
            devAddress = path,
            timeoutCheckTimer = 0;

        ///////////
        // Public methods
        ///////////

        /**
         * Send data
         * @param {ArrayBuffer} data The command, already formatted for sending.
         * @param {Object} info contains the service_uuid and characterictic_uuid to write to
         */
        this.write = function (data, info, callback) {
            if (!portOpen || info == undefined || callback == undefined)
                return;

            var encodedString = bluetoothle.bytesToEncodedString((data instanceof Uint8Array) ? data : new Uint8Array(data));
            var params = {
                value: encodedString,
                address: devAddress,
                service: info.service_uuid,
                characteristic: info.characteristic_uuid,
            };
            if (info.type) {
                params.type = info.type;
            }
            bluetoothle.write(callback,
                              function(e) { console.error('BLE Write error', e)},
                              params);
        };

        /**
         * Read data from the open BTLE device
         */
        this.read = function (service, characteristic) {
            if (!portOpen)
                return;

            var readError = function(e) {
                console.log('[cordovaBTLE] Read error: ' + e);
            };

            var readSuccess = function(s) {
                // Our drivers don't want this base64 stuff, sorry
                s.value = bluetoothle.encodedStringToBytes(s.value)
                    // Pass it on to the driver
                self.trigger('data', s);
            };

            bluetoothle.read(readSuccess,readError,{
                'address': devAddress,
                'service': service,
                'characteristic': characteristic
            });

        }

        /**
         * Subscribe to a service/characteristic
         * @param {[[Type]]} subscribeInfo [[Description]]
         */
        this.subscribe = function (subscribeInfo) {
            if (!portOpen)
                return;
            // Once we are connected, we want to select the service
            // the driver asked for and subscribe to the characteristics
            // the driver wants.

            var params = {
                address: devAddress,
                service: subscribeInfo.service_uuid,
                characteristic: subscribeInfo.characteristic_uuid,
                isNotification: true
            };
            bluetoothle.subscribe(subscribeSuccess, function (err) {
                // We get a callback here both when subscribe fails and when the
                // device disconnects - only take action when we have a subscribe
                // fail, that's it.
                if (err.error == 'isDisconnected')
                    return; // don't take action, the disconnected message
                // We didn't find the service we were looking for, this means
                // this is probably not the right device. Tell the user!
                stats.fullEvent('Cordova BLE', 'subscribe_error', err.message);
                self.trigger('status', {
                    openerror: true,
                    reason: 'Could not connect to the BLE service',
                    description: err.message
                });
                // Do a disconnect to make sure we end up in a sane state:
                self.close();
            }, params);
        }

        this.close = function () {
            console.log("[cordovaBTLE] Close BTLE connection");
            // We need to disconnect before closing, as per the doc
            bluetoothle.disconnect(function (result) {
                // OK, we can now close the device:
                bluetoothle.close(function (result) {
                    console.log(result);
                    portOpen = false;
                    self.trigger('status', {
                        portopen: portOpen
                    });
                }, function (error) {}, {
                    address: devAddress
                });
            }, function (error) {
                console.log('Disconnect error', error);
                if (error.error == 'isDisconnected') {
                    // Already disconnected, so we can close
                    bluetoothle.close(function (result) {
                        console.log(result);
                        portOpen = false;
                        self.trigger('status', {
                            portopen: portOpen
                        });
                    }, function (error) {}, {
                        address: devAddress
                    });
                }
            }, {
                address: devAddress
            });
        };

        // Has to be called by the backend_driver to actually open the port.
        // This just connects to the device
        this.open = function () {

            // Setup a callback in case we time out
            timeoutCheckTimer = setTimeout(checkConnectDelay, 15000);

            // Callback once we know Bluetooth is enabled
            function doConnect(status) {
                if (status.status != 'enabled')
                    return;
                bluetoothle.connect(trackConnect, trackError, {
                    address: devAddress
                });

            }

            // The Cordova BTLE plugin requires calling initialize at least once.
            // Note that it can be called multiple times, this is not an issue.
            bluetoothle.initialize(doConnect, function (err) {
                console.log(err);
            }, {
                request: true,
                statusReceiver: false
            });
        }

        /////////////
        // Private methods
        /////////////

        /////////////
        //   Callbacks
        /////////////

        // Track connection status
        function trackConnect(result) {
            if (result.status == 'connecting') {
                console.log(result);
                return;
            }
            if (result.status == 'connected') {
                // Right after we connect, we do a service
                // discovery, so that we can then connect to the various
                // services & characteristics. This is the Android call, the
                // iPhone call will be different:
                bluetoothle.discover(function (r) {
                    if (r.status != 'discovered')
                        return;
                    portOpen = true;
                    if (timeoutCheckTimer) {
                        clearTimeout(timeoutCheckTimer);
                        timeoutCheckTimer = 0;
                    }
                    self.trigger('status', {
                        portopen: portOpen,
                        services: r.services
                    });
                    stats.fullEvent('Cordova BLE', 'open_success', '');
                    // Need to send this to tell the front-end we're done reconnecting
                    // and back to normal
                    self.trigger('status', {
                        reconnecting: false
                    });

                }, function (err) {
                    console.log(err);
                    stats.fullEvent('Cordova BLE', 'open_error', err.message);
                }, {
                    address: devAddress
                });
                return;
            }
            if (result.status == 'disconnected') {
                console.log(result);
                // OK, the device disappeared: we will try to
                // reconnect as long as the user does not explicitely
                // ask to close
                portOpen = false;
                // Just keep reconnecting forever...
                //timeoutCheckTimer = setTimeout(checkConnectDelay, 60000);
                // We lost the connection, try to get it back
                bluetoothle.reconnect(trackConnect, trackError, {
                    address: devAddress
                });
                self.trigger('status', {
                    reconnecting: true
                });
            }
        }

        function trackError(err) {
            // This is called whenever we lose the connection
            console.log(err);
            if (!portOpen) {
                // if the port was not open and we got an error callback, this means
                // we were not able to connect in the first place...
                self.trigger('status', {
                    openerror: true,
                    reason: 'Device connection error',
                    description: 'Android error: ' + err.message
                });
                // Do a disconnect to make sure we end up in a sane state:
                self.close();
            } else {
                portOpen = false;
                // Just keep reconnecting forever...
                //timeoutCheckTimer = setTimeout(checkConnectDelay, 60000);
                // We lost the connection, try to get it back
                bluetoothle.reconnect(trackConnect, trackError, {
                    address: devAddress
                });
                self.trigger('status', {
                    reconnecting: true
                });
            }
            return;
        }

        // This is where we get notifications
        function subscribeSuccess(chrc) {
            if (chrc.status == 'subscribedResult') {
                // Our drivers don't want this base64 stuff, sorry
                chrc.value = bluetoothle.encodedStringToBytes(chrc.value)
                    // Pass it on to the driver
                self.trigger('data', chrc);
            }
        }

        // Make sure that if after X seconds we have no connection, we cancel
        // the attempt
        function checkConnectDelay() {
            console.log('Check connect delay timeout');
            if (!portOpen) {
                self.close();
                self.trigger('status', {
                    openerror: true,
                    reason: 'Device connection error',
                    description: 'Could not connect to device.'
                });
            }
        }

        console.log("[cordovaBTLE] Cordova BTLE Library loaded");

    };

    // Add event management to our serial lib, from the Backbone.Events class:
    _.extend(cordovaBTLE.prototype, Backbone.Events);
    return cordovaBTLE;
});<|endoftext|>


<commit_before>const webpack = require('webpack');
const path = require('path');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const pkg = require('../package.json');
const { findPages } = require('./src/modules/utils/find');
const { LANGUAGES, LANGUAGES_SSR } = require('./src/modules/constants');

const workspaceRoot = path.join(__dirname, '../');

/**
 * @type {'legacy' | 'sync' | 'concurrent'}
 */
const reactMode = 'legacy';

module.exports = {
  webpack: (config, options) => {
    const plugins = config.plugins.concat([
      new webpack.DefinePlugin({
        'process.env': {
          ENABLE_AD: JSON.stringify(process.env.ENABLE_AD),
          GITHUB_AUTH: JSON.stringify(process.env.GITHUB_AUTH),
          LIB_VERSION: JSON.stringify(pkg.version),
          REACT_MODE: JSON.stringify(reactMode),
        },
      }),
    ]);

    if (process.env.DOCS_STATS_ENABLED) {
      plugins.push(
        // For all options see https://github.com/th0r/webpack-bundle-analyzer#as-plugin
        new BundleAnalyzerPlugin({
          analyzerMode: 'server',
          generateStatsFile: true,
          // Will be available at `.next/stats.json`
          statsFilename: 'stats.json',
        }),
      );
    }

    config.resolve.alias['react-dom$'] = 'react-dom/profiling';
    config.resolve.alias['scheduler/tracing'] = 'scheduler/tracing-profiling';

    if (reactMode !== 'legacy') {
      config.resolve.alias['react-transition-group'] = '@material-ui/react-transition-group';
    }

    // next includes node_modules in webpack externals. Some of those have dependencies
    // on the aliases defined above. If a module is an external those aliases won't be used.
    // We need tell webpack to not consider those packages as externals.
    if (options.isServer) {
      const [nextExternals, ...externals] = config.externals;

      if (externals.length > 0) {
        // currently not the case but other next plugins might introduce additional
        // rules for externals. We would need to handle those in the callback
        throw new Error('There are other externals in the webpack config.');
      }

      config.externals = [
        (context, request, callback) => {
          const hasDependencyOnRepoPackages = [
            'notistack',
            'material-table',
            '@material-ui/pickers',
          ].includes(request);

          if (hasDependencyOnRepoPackages) {
            return callback(null);
          }
          return nextExternals(context, request, callback);
        },
      ];
    }

    return Object.assign({}, config, {
      plugins,
      node: {
        fs: 'empty',
      },
      module: Object.assign({}, config.module, {
        rules: config.module.rules.concat([
          {
            test: /\.(css|md)$/,
            loader: 'emit-file-loader',
            options: {
              name: 'dist/[path][name].[ext]',
            },
          },
          {
            test: /\.(css|md)$/,
            loader: 'raw-loader',
          },
          // transpile 3rd party packages with dependencies in this repository
          {
            test: /\.(js|mjs|jsx)$/,
            include: /node_modules(\/|\\)(material-table|notistack|@material-ui(\/|\\)pickers)/,
            use: {
              loader: 'babel-loader',
              options: {
                // on the server we use the transpiled commonJS build, on client ES6 modules
                // babel needs to figure out in what context to parse the file
                sourceType: 'unambiguous',
                plugins: [
                  [
                    'babel-plugin-module-resolver',
                    {
                      alias: {
                        '@material-ui/core': '../packages/material-ui/src',
                      },
                      transformFunctions: ['require'],
                    },
                  ],
                ],
              },
            },
          },
          // required to transpile ../packages/
          {
            test: /\.(js|mjs|jsx)$/,
            include: [workspaceRoot],
            exclude: /node_modules/,
            use: options.defaultLoaders.babel,
          },
        ]),
      }),
    });
  },
  exportTrailingSlash: true,
  // Next.js provides a `defaultPathMap` argument, we could simplify the logic.
  // However, we don't in order to prevent any regression in the `findPages()` method.
  exportPathMap: () => {
    const pages = findPages();
    const map = {};

    function traverse(pages2, userLanguage) {
      const prefix = userLanguage === 'en' ? '' : `/${userLanguage}`;

      pages2.forEach(page => {
        if (!page.children) {
          map[`${prefix}${page.pathname.replace(/^\/api-docs\/(.*)/, '/api/$1')}`] = {
            page: page.pathname,
            query: {
              userLanguage,
            },
          };
          return;
        }

        traverse(page.children, userLanguage);
      });
    }

    // We want to speed-up the build of pull requests.
    if (process.env.PULL_REQUEST === 'true') {
      // eslint-disable-next-line no-console
      console.log('Considering only English for SSR');
      traverse(pages, 'en');
    } else {
      // eslint-disable-next-line no-console
      console.log('Considering various locales for SSR');
      LANGUAGES_SSR.forEach(userLanguage => {
        traverse(pages, userLanguage);
      });
    }

    return map;
  },
  experimental: {
    async rewrites() {
      return [
        { source: `/:lang(${LANGUAGES.join('|')})?/:rest`, destination: '/:rest' },
        { source: '/api/:rest*', destination: '/api-docs/:rest*' },
      ];
    },
  },
};
<commit_msg>[core] Improve the DX when iterating on components (#20128)<commit_after>const webpack = require('webpack');
const path = require('path');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const pkg = require('../package.json');
const { findPages } = require('./src/modules/utils/find');
const { LANGUAGES, LANGUAGES_SSR } = require('./src/modules/constants');

const workspaceRoot = path.join(__dirname, '../');

/**
 * @type {'legacy' | 'sync' | 'concurrent'}
 */
const reactMode = 'legacy';

module.exports = {
  typescript: {
    // Motivated by https://github.com/zeit/next.js/issues/7687
    ignoreDevErrors: true,
    ignoreBuildErrors: true,
  },
  webpack: (config, options) => {
    const plugins = config.plugins.concat([
      new webpack.DefinePlugin({
        'process.env': {
          ENABLE_AD: JSON.stringify(process.env.ENABLE_AD),
          GITHUB_AUTH: JSON.stringify(process.env.GITHUB_AUTH),
          LIB_VERSION: JSON.stringify(pkg.version),
          REACT_MODE: JSON.stringify(reactMode),
        },
      }),
    ]);

    if (process.env.DOCS_STATS_ENABLED) {
      plugins.push(
        // For all options see https://github.com/th0r/webpack-bundle-analyzer#as-plugin
        new BundleAnalyzerPlugin({
          analyzerMode: 'server',
          generateStatsFile: true,
          // Will be available at `.next/stats.json`
          statsFilename: 'stats.json',
        }),
      );
    }

    config.resolve.alias['react-dom$'] = 'react-dom/profiling';
    config.resolve.alias['scheduler/tracing'] = 'scheduler/tracing-profiling';

    if (reactMode !== 'legacy') {
      config.resolve.alias['react-transition-group'] = '@material-ui/react-transition-group';
    }

    // next includes node_modules in webpack externals. Some of those have dependencies
    // on the aliases defined above. If a module is an external those aliases won't be used.
    // We need tell webpack to not consider those packages as externals.
    if (options.isServer) {
      const [nextExternals, ...externals] = config.externals;

      if (externals.length > 0) {
        // currently not the case but other next plugins might introduce additional
        // rules for externals. We would need to handle those in the callback
        throw new Error('There are other externals in the webpack config.');
      }

      config.externals = [
        (context, request, callback) => {
          const hasDependencyOnRepoPackages = [
            'notistack',
            'material-table',
            '@material-ui/pickers',
          ].includes(request);

          if (hasDependencyOnRepoPackages) {
            return callback(null);
          }
          return nextExternals(context, request, callback);
        },
      ];
    }

    return Object.assign({}, config, {
      plugins,
      node: {
        fs: 'empty',
      },
      module: Object.assign({}, config.module, {
        rules: config.module.rules.concat([
          {
            test: /\.(css|md)$/,
            loader: 'emit-file-loader',
            options: {
              name: 'dist/[path][name].[ext]',
            },
          },
          {
            test: /\.(css|md)$/,
            loader: 'raw-loader',
          },
          // transpile 3rd party packages with dependencies in this repository
          {
            test: /\.(js|mjs|jsx)$/,
            include: /node_modules(\/|\\)(material-table|notistack|@material-ui(\/|\\)pickers)/,
            use: {
              loader: 'babel-loader',
              options: {
                // on the server we use the transpiled commonJS build, on client ES6 modules
                // babel needs to figure out in what context to parse the file
                sourceType: 'unambiguous',
                plugins: [
                  [
                    'babel-plugin-module-resolver',
                    {
                      alias: {
                        '@material-ui/core': '../packages/material-ui/src',
                      },
                      transformFunctions: ['require'],
                    },
                  ],
                ],
              },
            },
          },
          // required to transpile ../packages/
          {
            test: /\.(js|mjs|jsx)$/,
            include: [workspaceRoot],
            exclude: /node_modules/,
            use: options.defaultLoaders.babel,
          },
        ]),
      }),
    });
  },
  exportTrailingSlash: true,
  // Next.js provides a `defaultPathMap` argument, we could simplify the logic.
  // However, we don't in order to prevent any regression in the `findPages()` method.
  exportPathMap: () => {
    const pages = findPages();
    const map = {};

    function traverse(pages2, userLanguage) {
      const prefix = userLanguage === 'en' ? '' : `/${userLanguage}`;

      pages2.forEach(page => {
        if (!page.children) {
          map[`${prefix}${page.pathname.replace(/^\/api-docs\/(.*)/, '/api/$1')}`] = {
            page: page.pathname,
            query: {
              userLanguage,
            },
          };
          return;
        }

        traverse(page.children, userLanguage);
      });
    }

    // We want to speed-up the build of pull requests.
    if (process.env.PULL_REQUEST === 'true') {
      // eslint-disable-next-line no-console
      console.log('Considering only English for SSR');
      traverse(pages, 'en');
    } else {
      // eslint-disable-next-line no-console
      console.log('Considering various locales for SSR');
      LANGUAGES_SSR.forEach(userLanguage => {
        traverse(pages, userLanguage);
      });
    }

    return map;
  },
  experimental: {
    async rewrites() {
      return [
        { source: `/:lang(${LANGUAGES.join('|')})?/:rest`, destination: '/:rest' },
        { source: '/api/:rest*', destination: '/api-docs/:rest*' },
      ];
    },
  },
};
<|endoftext|>


<commit_before>'use strict';

var http = require('http');
var https = require('https');
var url = require('url');
//var querystring = require('querystring');
var fs = require('fs');
var websocket = require('websocket');		// don't forget to run "npm install websocket"

var dgram = require('dgram');

/*
	SensorReader
*/
function SensorReader()
{
	this._interval = setInterval( this._onReceivedData.bind(this), 20 );
	this._onSensorDataReady = [];
}

SensorReader.prototype.dispose = function()
{
	clearInterval( this._interval );
};

SensorReader.prototype._onReceivedData = function()
{
	var now = new Date().getTime();
	var t0 = (now % 4000) / 4000;
	var t1 = (now % 1000) / 1000;
	var t2 = (now % 333) / 333;
	var t4 = (now % 1642) / 1642;

	var temperature = (t0*30 - 15) + 50  + Math.sin( t2 * Math.PI * 2) * 2;

	var angularSpeedX =
		Math.sin( t0 * Math.PI * 2) * 15 +
		Math.sin( t1 * Math.PI * 2) * (5*(Math.sin( t4 * Math.PI * 2)+1)) +
		Math.sin( t2 * Math.PI * 2) * 2 +
		50;

	var dataPoint = {
		temperature: temperature,
		angularSpeedX: angularSpeedX,
		timestamp: new Date().getTime()
	};

	//console.log("SensorReader: read point " + dataPoint.timestamp);

	for ( var i=0; i<this._onSensorDataReady.length; ++i )
	{
		var listener = this._onSensorDataReady[i];
		listener( dataPoint );
	}
};

/*
	SensorDataSender
*/
function SensorDataSender( sensorReader, connection )
{
	this._sensorReader = sensorReader;
	this._connection = connection;

	this._interval = setInterval( this._sendData.bind(this), 50 );

	this._maxNumDataPointsToSend = 2000;
	this._dataPointsToSend = [];

	this._onSensorDataReadyHandler = this._onSensorDataReady.bind(this);
	this._sensorReader._onSensorDataReady.push( this._onSensorDataReadyHandler );

	this._instanceID = SensorDataSender.numInstances;
	SensorDataSender.numInstances++;

	console.log("SensorDataSender#"+ this._instanceID + ": created");
}
SensorDataSender.numInstances = 0;

SensorDataSender.prototype.dispose = function()
{
	clearInterval( this._interval );

	var index = this._sensorReader._onSensorDataReady.indexOf( this._onSensorDataReadyHandler );
	if (index!==-1)
	{
		this._sensorReader._onSensorDataReady.splice(index, 1);
	}
	else
	{
		console.error("something's wrong");
	}

	console.log("SensorDataSender#"+ this._instanceID + ": dispose");
};

SensorDataSender.prototype._onSensorDataReady = function( dataPoint )
{
	this._dataPointsToSend.splice(0, 0, dataPoint);
	if ( this._dataPointsToSend.length>this._maxNumDataPointsToSend )
	{
		this._dataPointsToSend.shift();
		console.warn("buffer full");
	}
};

SensorDataSender.prototype._sendData = function()
{
	//console.log("SensorDataSender#"+ this._instanceID + ": sending " + this._dataPointsToSend.length);
	var jsonData = JSON.stringify(this._dataPointsToSend);
	this._connection.sendUTF(jsonData);
	this._dataPointsToSend = [];
};

/*
	SensorMonitorServer
*/
function SensorMonitorServer()
{
	this._sensorReader = new SensorReader();
	this._sensorDataSenders = [];

	// HTTP server
	this._httpServer = http.createServer(
		function(req, res)
		{
			var path = url.parse(req.url).pathname;
			var query = url.parse(req.url).query;

			if ( path==='/')
			{
				SensorMonitorServer._serveFile( 'SensorMonitor.html', res );
			}
			else if ( path.indexOf('/files/')===0 )
			{
				var filename = path.substr(1);
				SensorMonitorServer._serveFile( filename, res );
			}
			else
			{
				SensorMonitorServer._createHTMLErrorResponse( res, 404, "Page not found");
			}
		});
	this._httpServer.listen(8080);

	// Websocket server
	this._websocketServer = new websocket.server({
		httpServer: this._httpServer
	});
	this._websocketServer.on('request',
		function(request)
		{
    		var connection = request.accept(null, request.origin);

    		//console.log("adding sender..." );
    		var sensorDataSender = new SensorDataSender( this._sensorReader, connection );
    		this._sensorDataSenders.push( sensorDataSender );

    		console.log("SensorMonitor: " + this._sensorDataSenders.length + " connections in progress");

    		connection.on('close',
    			function(connection)
    			{
					//console.log('Websocket server connection closed' + connection);
					sensorDataSender.dispose();
					var index = this._sensorDataSenders.indexOf(sensorDataSender);
					if (index!==-1)
					{
					    this._sensorDataSenders.splice(index, 1);
					}
					else
					{
						console.warn("couldn't find sender for connection...");
					}

					console.log("SensorMonitor: " + this._sensorDataSenders.length + " connections in progress");
   				}.bind(this));
		}.bind(this));

	// UDP socket
	var udpSocket = dgram.createSocket('udp4');
	udpSocket.on('listening',
		function()
		{
		    var address = udpSocket.address();
		    console.log('UDP Server listening on ' + address.address + ":" + address.port);
		});
	udpSocket.on('message',
		function(message, remote)
		{
	    	console.log('UDP socket received message: ' + remote.address + ':' + remote.port +' - ' + message);
	    	var uint8Array = new Uint8Array( message );
			for ( var i=0; i<uint8Array.length /* same as remote.size */; i++ )
			{
				//var byteAsHex = messageString.substr( i*2, 2 );
				//var byte = parseInt( byteAsHex, 16 );
				//uint8Array[i] = byte;
				console.log("byte " + i + ": " + uint8Array[i] );
			}
			return uint8Array;

	    });
	udpSocket.bind(8181, '127.0.0.1');

	console.log("SensorMonitor: server started");
}

SensorMonitorServer.prototype.dispose = function()
{
	// Stop things here!
	console.log("dispose to implement here...")
};

SensorMonitorServer._serveFile = function( filename, res )
{
	console.log("Serving file: " + filename);
	fs.readFile(filename, 'utf8',
		function(err, data)
			{
		  		if ( err )
		  		{
		    		SensorMonitorServer._createHTMLErrorResponse( res, 500, err );
		  		}
		  		else
		  		{
		  			res.writeHead(200); //{"Content-Type:": "application/json"});	// The server should certainly provide content type based on file extension
					res.write(data);
					res.end();
				}
			});
};

SensorMonitorServer._createHTMLErrorResponse = function( res, code, message )
{
	res.writeHead(code, {"Content-Type:": "text/html"});
	res.write(
		'<!DOCTYPE html>'+
		''+
		'    '+
		'        <meta charset="utf-8" />'+
		'        <title>Error</title>'+
		'    '+
		'    '+
		'
' + message + '
'+
		'    '+
		'');
	res.end();
};

/*
	Main
*/
function Main()
{
	var sensorMonitorServer = new SensorMonitorServer();

	//http://stackoverflow.com/questions/10021373/what-is-the-windows-equivalent-of-process-onsigint-in-node-js/14861513#14861513
	//http://stackoverflow.com/questions/6958780/quitting-node-js-gracefully
	if (process.platform === "win32")
	{
		var rl = require("readline").createInterface(
			{
				input: process.stdin,
				output: process.stdout
			});
		rl.on("SIGINT", function ()
			{
				process.emit("SIGINT");
			});
	}
	process.on("SIGINT", function ()
		{
			console.log("Stopping server...");
			sensorMonitorServer.dispose();
			process.exit();
		});
}

Main();

<commit_msg>Correctly transformed UPD message to float value<commit_after>'use strict';

var http = require('http');
var https = require('https');
var url = require('url');
//var querystring = require('querystring');
var fs = require('fs');
var websocket = require('websocket');		// don't forget to run "npm install websocket"

var dgram = require('dgram');

/*
	SensorReader
*/
function SensorReader()
{
	this._interval = setInterval( this._onReceivedData.bind(this), 20 );
	this._onSensorDataReady = [];
}

SensorReader.prototype.dispose = function()
{
	clearInterval( this._interval );
};

SensorReader.prototype._onReceivedData = function()
{
	var now = new Date().getTime();
	var t0 = (now % 4000) / 4000;
	var t1 = (now % 1000) / 1000;
	var t2 = (now % 333) / 333;
	var t4 = (now % 1642) / 1642;

	var temperature = (t0*30 - 15) + 50  + Math.sin( t2 * Math.PI * 2) * 2;

	var angularSpeedX =
		Math.sin( t0 * Math.PI * 2) * 15 +
		Math.sin( t1 * Math.PI * 2) * (5*(Math.sin( t4 * Math.PI * 2)+1)) +
		Math.sin( t2 * Math.PI * 2) * 2 +
		50;

	var dataPoint = {
		temperature: temperature,
		angularSpeedX: angularSpeedX,
		timestamp: new Date().getTime()
	};

	//console.log("SensorReader: read point " + dataPoint.timestamp);

	for ( var i=0; i<this._onSensorDataReady.length; ++i )
	{
		var listener = this._onSensorDataReady[i];
		listener( dataPoint );
	}
};

/*
	SensorDataSender
*/
function SensorDataSender( sensorReader, connection )
{
	this._sensorReader = sensorReader;
	this._connection = connection;

	this._interval = setInterval( this._sendData.bind(this), 50 );

	this._maxNumDataPointsToSend = 2000;
	this._dataPointsToSend = [];

	this._onSensorDataReadyHandler = this._onSensorDataReady.bind(this);
	this._sensorReader._onSensorDataReady.push( this._onSensorDataReadyHandler );

	this._instanceID = SensorDataSender.numInstances;
	SensorDataSender.numInstances++;

	console.log("SensorDataSender#"+ this._instanceID + ": created");
}
SensorDataSender.numInstances = 0;

SensorDataSender.prototype.dispose = function()
{
	clearInterval( this._interval );

	var index = this._sensorReader._onSensorDataReady.indexOf( this._onSensorDataReadyHandler );
	if (index!==-1)
	{
		this._sensorReader._onSensorDataReady.splice(index, 1);
	}
	else
	{
		console.error("something's wrong");
	}

	console.log("SensorDataSender#"+ this._instanceID + ": dispose");
};

SensorDataSender.prototype._onSensorDataReady = function( dataPoint )
{
	this._dataPointsToSend.splice(0, 0, dataPoint);
	if ( this._dataPointsToSend.length>this._maxNumDataPointsToSend )
	{
		this._dataPointsToSend.shift();
		console.warn("buffer full");
	}
};

SensorDataSender.prototype._sendData = function()
{
	//console.log("SensorDataSender#"+ this._instanceID + ": sending " + this._dataPointsToSend.length);
	var jsonData = JSON.stringify(this._dataPointsToSend);
	this._connection.sendUTF(jsonData);
	this._dataPointsToSend = [];
};

/*
	SensorMonitorServer
*/
function SensorMonitorServer()
{
	this._sensorReader = new SensorReader();
	this._sensorDataSenders = [];

	// HTTP server
	this._httpServer = http.createServer(
		function(req, res)
		{
			var path = url.parse(req.url).pathname;
			var query = url.parse(req.url).query;

			if ( path==='/')
			{
				SensorMonitorServer._serveFile( 'SensorMonitor.html', res );
			}
			else if ( path.indexOf('/files/')===0 )
			{
				var filename = path.substr(1);
				SensorMonitorServer._serveFile( filename, res );
			}
			else
			{
				SensorMonitorServer._createHTMLErrorResponse( res, 404, "Page not found");
			}
		});
	this._httpServer.listen(8080);

	// Websocket server
	this._websocketServer = new websocket.server({
		httpServer: this._httpServer
	});
	this._websocketServer.on('request',
		function(request)
		{
    		var connection = request.accept(null, request.origin);

    		//console.log("adding sender..." );
    		var sensorDataSender = new SensorDataSender( this._sensorReader, connection );
    		this._sensorDataSenders.push( sensorDataSender );

    		console.log("SensorMonitor: " + this._sensorDataSenders.length + " connections in progress");

    		connection.on('close',
    			function(connection)
    			{
					//console.log('Websocket server connection closed' + connection);
					sensorDataSender.dispose();
					var index = this._sensorDataSenders.indexOf(sensorDataSender);
					if (index!==-1)
					{
					    this._sensorDataSenders.splice(index, 1);
					}
					else
					{
						console.warn("couldn't find sender for connection...");
					}

					console.log("SensorMonitor: " + this._sensorDataSenders.length + " connections in progress");
   				}.bind(this));
		}.bind(this));

	// UDP socket
	var udpSocket = dgram.createSocket('udp4');
	udpSocket.on('listening',
		function()
		{
		    var address = udpSocket.address();
		    console.log('UDP Server listening on ' + address.address + ":" + address.port);
		});
	udpSocket.on('message',
		function(message, remote)
		{
			var text = 'UDP socket received message: ' + remote.address + ':' + remote.port;
	    	var uint8Array = new Uint8Array( message );
	    	var messageAsHex = "";
			for ( var i=0; i<uint8Array.length /* same as remote.size */; i++ )
				messageAsHex += uint8Array[i].toString(16) + " ";
			text += ': ' + messageAsHex;

			var dataView = new DataView(uint8Array.buffer);
			var dataPoint = dataView.getFloat32(0, true);
			text += ' (' + dataPoint + ')';
			console.log(text);
	    });
	udpSocket.bind(8181, '127.0.0.1');

	console.log("SensorMonitor: server started");
}

SensorMonitorServer.prototype.dispose = function()
{
	// Stop things here!
	console.log("dispose to implement here...")
};

SensorMonitorServer._serveFile = function( filename, res )
{
	console.log("Serving file: " + filename);
	fs.readFile(filename, 'utf8',
		function(err, data)
			{
		  		if ( err )
		  		{
		    		SensorMonitorServer._createHTMLErrorResponse( res, 500, err );
		  		}
		  		else
		  		{
		  			res.writeHead(200); //{"Content-Type:": "application/json"});	// The server should certainly provide content type based on file extension
					res.write(data);
					res.end();
				}
			});
};

SensorMonitorServer._createHTMLErrorResponse = function( res, code, message )
{
	res.writeHead(code, {"Content-Type:": "text/html"});
	res.write(
		'<!DOCTYPE html>'+
		''+
		'    '+
		'        <meta charset="utf-8" />'+
		'        <title>Error</title>'+
		'    '+
		'    '+
		'
' + message + '
'+
		'    '+
		'');
	res.end();
};

/*
	Main
*/
function Main()
{
	var sensorMonitorServer = new SensorMonitorServer();

	//http://stackoverflow.com/questions/10021373/what-is-the-windows-equivalent-of-process-onsigint-in-node-js/14861513#14861513
	//http://stackoverflow.com/questions/6958780/quitting-node-js-gracefully
	if (process.platform === "win32")
	{
		var rl = require("readline").createInterface(
			{
				input: process.stdin,
				output: process.stdout
			});
		rl.on("SIGINT", function ()
			{
				process.emit("SIGINT");
			});
	}
	process.on("SIGINT", function ()
		{
			console.log("Stopping server...");
			sensorMonitorServer.dispose();
			process.exit();
		});
}

Main();

<|endoftext|>


<commit_before>import {isArray, isFunction, isObject} from 'lodash/lang';
import {capitalize} from 'lodash/string'
import {keys} from 'lodash/object';

export default function connectToStores(storesConfiguration, getState) {
    // Validate the stores object
    if(!isArray(stores)) {
        throw new Error('connectToStores: you need to provide an array of store config.');
    }

    // Validate .
    if(!isFunction(getState)) {
        throw new Error('connectToStores: you need to provide an array of store config.');
    }
    // Return a wrapper function around the component
    return function connectComponent(DecoratedComponent) {

        // Save the display name for later
        const displayName = DecoratedComponent.displayName || 'Component';

        // The goal of this class is to connect a component to a list of stores with properties.
        class StoreConnector extends Component {

            constructor(props) {
                super(props);
                //Build the initial state from props.
                this.state = getState(props);
            }

            // When the component will mount, we listen to all stores changes.
            // When a change occurs the state is read again from the state.
            componentWillMount() {
                storesConfiguration.forEach(storeConf => {
                    const {properties, store} = storeConf;
                    properties.forEach((property) => {
                        if(!store || !store.definition || !store.definition[property]) {
                            console.warn(`
                                StoreConnector ${displayName}:
                                    You add a property : ${property} in your store configuration which is not in your definition : ${keys(store.definition)}
                            `);
                        }
                        const capitalizedProperty = capitalize(property);
                        storeConf.store[`add${capitalizedProperty}ChangeListener`](this.handleStoresChanged);
                        storeConf.store[`add${capitalizedProperty}ErrorListener`](this.handleStoresChanged);
                    });
                });
            }

            // When a component will receive a new props.
            componentWillReceiveProps(nextProps) {
                //if (!shallowEqual(nextProps, this.props)) {
                this.setState(getState(nextProps));
                //}
            }

            // Component unmount.
            componentWillUnmount() {
                storesConfiguration.forEach(storeConf => {
                    const {properties, store} = storeConf;
                    properties.forEach((property) => {
                        const capitalizedProperty = capitalize(property);
                        storeConf.store[`remove${capitalizedProperty}ChangeListener`](this.handleStoresChanged);
                        storeConf.store[`remove${capitalizedProperty}ErrorListener`](this.handleStoresChanged);
                    });
                });
            }

            //Handle the store changes
            handleStoresChanged = () => {
                this.setState(getState(this.props));
            }
            // Render the component with only props, some from the real props some from the state
            render() {
                const {props, state} = this;
                return (
                    <DecoratedComponent
                        {...props}
                        {...state}
                    />
                );
            }
        }
        StoreConnector.displayName = `${displayName}Connected`;
        return StoreConnector;
    };
}
<commit_msg>[connect] Fix storeConf name.<commit_after>import {isArray, isFunction, isObject} from 'lodash/lang';
import {capitalize} from 'lodash/string'
import {keys} from 'lodash/object';

export default function connectToStores(storesConfiguration, getState) {
    // Validate the stores object
    if(!isArray(storesConfiguration)) {
        throw new Error('connectToStores: you need to provide an array of store config.');
    }

    // Validate .
    if(!isFunction(getState)) {
        throw new Error('connectToStores: you need to provide function to read state from store.');
    }
    // Return a wrapper function around the component
    return function connectComponent(DecoratedComponent) {

        // Save the display name for later
        const displayName = DecoratedComponent.displayName || 'Component';

        // The goal of this class is to connect a component to a list of stores with properties.
        class StoreConnector extends Component {

            constructor(props) {
                super(props);
                //Build the initial state from props.
                this.state = getState(props);
            }

            // When the component will mount, we listen to all stores changes.
            // When a change occurs the state is read again from the state.
            componentWillMount() {
                storesConfiguration.forEach(storeConf => {
                    const {properties, store} = storeConf;
                    properties.forEach((property) => {
                        if(!store || !store.definition || !store.definition[property]) {
                            console.warn(`
                                StoreConnector ${displayName}:
                                    You add a property : ${property} in your store configuration which is not in your definition : ${keys(store.definition)}
                            `);
                        }
                        const capitalizedProperty = capitalize(property);
                        storeConf.store[`add${capitalizedProperty}ChangeListener`](this.handleStoresChanged);
                        storeConf.store[`add${capitalizedProperty}ErrorListener`](this.handleStoresChanged);
                    });
                });
            }

            // When a component will receive a new props.
            componentWillReceiveProps(nextProps) {
                //if (!shallowEqual(nextProps, this.props)) {
                this.setState(getState(nextProps));
                //}
            }

            // Component unmount.
            componentWillUnmount() {
                storesConfiguration.forEach(storeConf => {
                    const {properties, store} = storeConf;
                    properties.forEach((property) => {
                        const capitalizedProperty = capitalize(property);
                        storeConf.store[`remove${capitalizedProperty}ChangeListener`](this.handleStoresChanged);
                        storeConf.store[`remove${capitalizedProperty}ErrorListener`](this.handleStoresChanged);
                    });
                });
            }

            //Handle the store changes
            handleStoresChanged = () => {
                this.setState(getState(this.props));
            }

            // Render the component with only props, some from the real props some from the state
            render() {
                const {props, state} = this;
                return (
                    <DecoratedComponent
                        {...props}
                        {...state}
                    />
                );
            }
        }
        StoreConnector.displayName = `${displayName}Connected`;
        return StoreConnector;
    };
}
<|endoftext|>


<commit_before>var Const = require('./constants.js');
var Util = require('./util.js');
var Data = require('./data.js');

function getTitle(rating, gender) {
    if (rating < 2000 || gender === Const.gender.male && rating < 2200) return null;
    if (rating < 2100 && gender === Const.gender.female) return Const.fideTitle.WCM;
    if (rating < 2200 && gender === Const.gender.female) return Const.fideTitle.WFM;
    if (rating < 2300 && gender === Const.gender.female) return Const.fideTitle.WIM;
    if (rating < 2300) return Const.fideTitle.CM;
    if (rating < 2400 && gender === Const.gender.female) return Const.fideTitle.WGM;
    if (rating < 2400) return Const.fideTitle.FM;
    if (rating < 2500) return Const.fideTitle.IM;
    return Const.fideTitle.GM;
}

function generateFullName(gender) {
    var maleNames = ['Roosevelt', 'Antone', 'Pasquale', 'Tomas', 'Clifford',
                      'Rocco', 'Thao', 'Saul', 'Brice', 'Pete', 'Osvaldo',
                       'Austin', 'Magen', 'Judson', 'Gerard'];
    var femaleNames = ['Inell', 'Kazuko', 'Hien', 'Aleta', 'Larraine',
                       'Bethany', 'Ariel', 'Joana', 'Lorraine', 'Lizette',
                       'Emmy', 'Jolynn', 'Maranda', 'Melany', 'Miyoko', ];
    var surnames = ['Gleghorn', 'Bishopp', 'Mariacher', 'Fike', 'Popper', 'Schoenbeck', 'Palone', 'Beliard', 'Kinabrew', 'Bohan',
                    'Fedoriw', 'Pannhoff', 'Schaff', 'Seidler', 'Garing', 'Christesen', 'Schooler', 'Hershey', 'Stewardson', 'Roller',
                    'Mirelez', 'Zavadoski', 'Heywood', 'Wyse', 'Condello', 'Brensnan', 'Sippel', 'Dinsmoor', 'Yenglin', 'Trampe'];
    var name = (gender === Const.gender.female)
        ? femaleNames[Util.randomInt(0, femaleNames.length)]
        : maleNames[Util.randomInt(0, maleNames.length)];
    var surname = surnames[Util.randomInt(0, surnames.length)];
    return [name, surname];
}

module.exports = {
    generatePlayer: function (gender, fullName) {
        gender = gender ? gender : Util.randomInt(1, 3);
        fullName = fullName ? fullName : generateFullName(gender);
        var fedRating = Util.randomInt(800, 2900);
        fedRating = (fedRating < 1000) ? null : fedRating;
        var fideRating = null;
        var fideTitle = null;
        if (fedRating) {
            fideRating = (fedRating < 1999) ? null : fedRating - 200;
            fideTitle = (fideRating == null) ? null : getTitle(fideRating, gender);
        }

        return {
            name: fullName[0],
            surname: fullName[1],
            gender: gender,
            fideRating: fideRating,
            fideTitle: fideTitle,
            federationRating: fedRating,
            federationTitle: null,
            dateOfBirth: Util.randomDate(new Date(Date.UTC(1950, 0, 1)), new Date(Date.UTC(2000, 0, 1))),
            federation: Data.fideFederations[Util.randomInt(0, Data.fideFederations.length)].value,
            union: null,
            contactNumber: null,
            emailAddress: fullName[0].toLowerCase() + fullName[1].toLowerCase() + '@example.com'
        };
    },

    generateTournament: function (ownerUserId) {
        var cities = ['Durban', 'Johannesburg', 'Cape Town', 'Pretoria', 'Bloemfontein', 'Port Elizabeth', 'Germiston', 'Newcastle',
                  'Klerksdorp', 'Kimberley', 'Secunda', 'Vereeniging', 'Dundee', 'Kuruman', 'Pietermaritzburg', 'Randfontein',
                  'Welkom', 'Pholokwane', 'Wartburg', 'Port Shepstone', 'Richards Bay'];
        var types = ['Open', 'Closed', 'Cup', 'Championship', 'Memorial', 'Rapid', 'Blitz'];
        var durations = [1, 2, 3, 5, 7];

        var ratingType = Util.randomInt(1, 3);
        var federation = Data.fideFederations[Util.randomInt(0, Data.fideFederations.length)].value;
        var city = cities[Util.randomInt(0, cities.length)];
        var startDate = Util.randomDate(new Date(Date.UTC(2014, 10, 1)), new Date(Date.UTC(2015, 1, 1)));
        var endDate = new Date(startDate);
        endDate.setDate(startDate.getDate() + durations[Util.randomInt(0, durations.length)]);

        return {
            name: city + ' ' + types[Util.randomInt(0, types.length)],
            location: city,
            startDate: startDate,
            endDate: endDate,
            registrationFeeCurrencyId: 154,
            ownerUserId: ownerUserId,
            ratingType: ratingType,
            federation: federation
        };
    },

    generateSection: function(tournament) {
        var sectionNames = ['A', 'B', 'C', 'D', 'Open', 'Closed', 'Youth', 'Novice', 'Expert'];
        var fees = [0, 50, 100, 150, 200, 250];

        // Determine play system based on no. of participants.
        var maxPlayers = Util.randomInt(6, 51);

        // HACK: Since we can't handle anything except Swiss at the moment...
        //var playSystem = Util.randomInt(1, 3);
        var playSystem = Const.playSystem.swiss;

        var maxRounds = (playSystem + 1) * (maxPlayers - 1);
        if (maxRounds > 10) {
            playSystem = Const.playSystem.swiss;
        }

        var tieBreaks = (playSystem === Const.playSystem.swiss)
                ? [Util.randomInt(1, 4)]
                : [Const.tieBreak.neustadl];
        var rounds = (playSystem === Const.playSystem.swiss)
                ? Util.swissRounds(maxPlayers)
                : 0; // for RR tournaments the no. of rounds depends on the no. of participants

        var roundData = [];
        if (playSystem === Const.playSystem.swiss) {
            for (var i = 0; i != rounds; ++i) {
                var startTime = new Date(tournament.startDate);
                startTime.setHours(startTime.getHours() + 8 + i);
                roundData.push({
                    startTime: startTime,
                    status: Const.roundStatus.unpaired
                });
            }
        }

        var registrationStartDate = new Date(tournament.startDate);
        registrationStartDate.setDate(tournament.startDate.getDate() - 60);

        return {
            tournamentId: tournament._id,
            ownerUserId: tournament.ownerUserId,
            name: sectionNames[Util.randomInt(0, sectionNames.length)] + ' Section',
            playSystem: playSystem,
            tieBreaks: tieBreaks,
            rounds: rounds,
            maxPlayers: maxPlayers,
            startDate: tournament.startDate,
            endDate: tournament.endDate,
            registrationStartDate: registrationStartDate,
            registrationEndDate: tournament.startDate,
            chiefArbiter: generateFullName(Util.randomInt(0, 2)).join(' '),
            timeControls: Data.stdTimeControls[Util.randomInt(0, Data.stdTimeControls.length)],
            registrationFee: fees[Util.randomInt(0, fees.length)],
            invitationOnly: Util.randomBool(),
            provisionalRating: 1000,
            registeredPlayerIds: [],
            confirmedPlayerIds: [],
            registrationManuallyClosed: null,
            roundData: roundData,
            playerData: [],
        };
    },

    registerPlayers: function (sections, players) {
        var sect;
        var gotSwiss = false;

        for (var i = 0; i != sections.length; ++i) {
            sect = sections[i];
            if (sect.playSystem === Const.playSystem.swiss) {
                gotSwiss = true;
                break;
            }
        }

        if (!gotSwiss) {
            return null;
        }

        sect.registeredPlayerIds = players.map(function (p) {
            return p._id;
        });

        return sect;
    }
};<commit_msg>Hack datagen to only generate 3 rounds.<commit_after>var Const = require('./constants.js');
var Util = require('./util.js');
var Data = require('./data.js');

function getTitle(rating, gender) {
    if (rating < 2000 || gender === Const.gender.male && rating < 2200) return null;
    if (rating < 2100 && gender === Const.gender.female) return Const.fideTitle.WCM;
    if (rating < 2200 && gender === Const.gender.female) return Const.fideTitle.WFM;
    if (rating < 2300 && gender === Const.gender.female) return Const.fideTitle.WIM;
    if (rating < 2300) return Const.fideTitle.CM;
    if (rating < 2400 && gender === Const.gender.female) return Const.fideTitle.WGM;
    if (rating < 2400) return Const.fideTitle.FM;
    if (rating < 2500) return Const.fideTitle.IM;
    return Const.fideTitle.GM;
}

function generateFullName(gender) {
    var maleNames = ['Roosevelt', 'Antone', 'Pasquale', 'Tomas', 'Clifford',
                      'Rocco', 'Thao', 'Saul', 'Brice', 'Pete', 'Osvaldo',
                       'Austin', 'Magen', 'Judson', 'Gerard'];
    var femaleNames = ['Inell', 'Kazuko', 'Hien', 'Aleta', 'Larraine',
                       'Bethany', 'Ariel', 'Joana', 'Lorraine', 'Lizette',
                       'Emmy', 'Jolynn', 'Maranda', 'Melany', 'Miyoko', ];
    var surnames = ['Gleghorn', 'Bishopp', 'Mariacher', 'Fike', 'Popper', 'Schoenbeck', 'Palone', 'Beliard', 'Kinabrew', 'Bohan',
                    'Fedoriw', 'Pannhoff', 'Schaff', 'Seidler', 'Garing', 'Christesen', 'Schooler', 'Hershey', 'Stewardson', 'Roller',
                    'Mirelez', 'Zavadoski', 'Heywood', 'Wyse', 'Condello', 'Brensnan', 'Sippel', 'Dinsmoor', 'Yenglin', 'Trampe'];
    var name = (gender === Const.gender.female)
        ? femaleNames[Util.randomInt(0, femaleNames.length)]
        : maleNames[Util.randomInt(0, maleNames.length)];
    var surname = surnames[Util.randomInt(0, surnames.length)];
    return [name, surname];
}

module.exports = {
    generatePlayer: function (gender, fullName) {
        gender = gender ? gender : Util.randomInt(1, 3);
        fullName = fullName ? fullName : generateFullName(gender);
        var fedRating = Util.randomInt(800, 2900);
        fedRating = (fedRating < 1000) ? null : fedRating;
        var fideRating = null;
        var fideTitle = null;
        if (fedRating) {
            fideRating = (fedRating < 1999) ? null : fedRating - 200;
            fideTitle = (fideRating == null) ? null : getTitle(fideRating, gender);
        }

        return {
            name: fullName[0],
            surname: fullName[1],
            gender: gender,
            fideRating: fideRating,
            fideTitle: fideTitle,
            federationRating: fedRating,
            federationTitle: null,
            dateOfBirth: Util.randomDate(new Date(Date.UTC(1950, 0, 1)), new Date(Date.UTC(2000, 0, 1))),
            federation: Data.fideFederations[Util.randomInt(0, Data.fideFederations.length)].value,
            union: null,
            contactNumber: null,
            emailAddress: fullName[0].toLowerCase() + fullName[1].toLowerCase() + '@example.com'
        };
    },

    generateTournament: function (ownerUserId) {
        var cities = ['Durban', 'Johannesburg', 'Cape Town', 'Pretoria', 'Bloemfontein', 'Port Elizabeth', 'Germiston', 'Newcastle',
                  'Klerksdorp', 'Kimberley', 'Secunda', 'Vereeniging', 'Dundee', 'Kuruman', 'Pietermaritzburg', 'Randfontein',
                  'Welkom', 'Pholokwane', 'Wartburg', 'Port Shepstone', 'Richards Bay'];
        var types = ['Open', 'Closed', 'Cup', 'Championship', 'Memorial', 'Rapid', 'Blitz'];
        var durations = [1, 2, 3, 5, 7];

        var ratingType = Util.randomInt(1, 3);
        var federation = Data.fideFederations[Util.randomInt(0, Data.fideFederations.length)].value;
        var city = cities[Util.randomInt(0, cities.length)];
        var startDate = Util.randomDate(new Date(Date.UTC(2014, 10, 1)), new Date(Date.UTC(2015, 1, 1)));
        var endDate = new Date(startDate);
        endDate.setDate(startDate.getDate() + durations[Util.randomInt(0, durations.length)]);

        return {
            name: city + ' ' + types[Util.randomInt(0, types.length)],
            location: city,
            startDate: startDate,
            endDate: endDate,
            registrationFeeCurrencyId: 154,
            ownerUserId: ownerUserId,
            ratingType: ratingType,
            federation: federation
        };
    },

    generateSection: function(tournament) {
        var sectionNames = ['A', 'B', 'C', 'D', 'Open', 'Closed', 'Youth', 'Novice', 'Expert'];
        var fees = [0, 50, 100, 150, 200, 250];

        // Determine play system based on no. of participants.
        var maxPlayers = Util.randomInt(10, 51);

        // HACK: Since we can't handle anything except Swiss at the moment...
        //var playSystem = Util.randomInt(1, 3);
        var playSystem = Const.playSystem.swiss;

        var maxRounds = (playSystem + 1) * (maxPlayers - 1);
        if (maxRounds > 10) {
            playSystem = Const.playSystem.swiss;
        }

        var tieBreaks = (playSystem === Const.playSystem.swiss)
                ? [Util.randomInt(1, 4)]
                : [Const.tieBreak.neustadl];
        // HACK: We don't want more than 3 rounds...
        //var rounds = (playSystem === Const.playSystem.swiss)
        //        ? Util.swissRounds(maxPlayers)
        //        : 0; // for RR tournaments the no. of rounds depends on the no. of participants
        var rounds = 3;

        var roundData = [];
        if (playSystem === Const.playSystem.swiss) {
            for (var i = 0; i != rounds; ++i) {
                var startTime = new Date(tournament.startDate);
                startTime.setHours(startTime.getHours() + 8 + i);
                roundData.push({
                    startTime: startTime,
                    status: Const.roundStatus.unpaired
                });
            }
        }

        var registrationStartDate = new Date(tournament.startDate);
        registrationStartDate.setDate(tournament.startDate.getDate() - 60);

        return {
            tournamentId: tournament._id,
            ownerUserId: tournament.ownerUserId,
            name: sectionNames[Util.randomInt(0, sectionNames.length)] + ' Section',
            playSystem: playSystem,
            tieBreaks: tieBreaks,
            rounds: rounds,
            maxPlayers: maxPlayers,
            startDate: tournament.startDate,
            endDate: tournament.endDate,
            registrationStartDate: registrationStartDate,
            registrationEndDate: tournament.startDate,
            chiefArbiter: generateFullName(Util.randomInt(0, 2)).join(' '),
            timeControls: Data.stdTimeControls[Util.randomInt(0, Data.stdTimeControls.length)],
            registrationFee: fees[Util.randomInt(0, fees.length)],
            invitationOnly: Util.randomBool(),
            provisionalRating: 1000,
            registeredPlayerIds: [],
            confirmedPlayerIds: [],
            registrationManuallyClosed: null,
            roundData: roundData,
            playerData: [],
        };
    },

    registerPlayers: function (sections, players) {
        var sect;
        var gotSwiss = false;

        for (var i = 0; i != sections.length; ++i) {
            sect = sections[i];
            if (sect.playSystem === Const.playSystem.swiss) {
                gotSwiss = true;
                break;
            }
        }

        if (!gotSwiss) {
            return null;
        }

        sect.registeredPlayerIds = players.map(function (p) {
            return p._id;
        });

        return sect;
    }
};<|endoftext|>


<commit_before>// Knockout checked binding doesn't work with Bootstrap checkboxes
ko.bindingHandlers.checkbox = {
    init: function (element, valueAccessor) {
        var $element = $(element),
            handler = function (e) {
            // we need to handle change event after bootsrap will handle its event
            // to prevent incorrect changing of checkbox state
            setTimeout(function() {
                var $checkbox = $(e.target),
                    value = valueAccessor(),
                    data = $checkbox.val(),
                    isChecked = $checkbox.parent().hasClass('active');

                if (ko.unwrap(value) instanceof Array) {
                    var index = ko.utils.arrayIndexOf(ko.unwrap(value), (data));

                    if (isChecked && (index === -1)) {
                        value.push(data);
                    } else if (!isChecked && (index !== -1)) {
                        value.splice(index, 1);
                    }
                } else {
                    value(isChecked);
                }
            }, 0);
        };

        if ($element.attr('data-toggle') === 'buttons' && $element.find('input:checkbox').length) {

            if (!(ko.unwrap(valueAccessor()) instanceof Array)) {
                throw new Error('checkbox binding should be used only with array or observableArray values in this case');
            }

            $element.on('change', 'input:checkbox', handler);
        } else if ($element.attr('type') === 'checkbox') {

            if (!ko.isObservable(valueAccessor())) {
                throw new Error('checkbox binding should be used only with observable values in this case');
            }

            $element.on('change', handler);
        } else {
            throw new Error('checkbox binding should be used only with bootstrap checkboxes');
        }
    },

    update: function (element, valueAccessor) {
        var $element = $(element),
            value = ko.unwrap(valueAccessor()),
            isChecked;

        if (value instanceof Array) {
            if ($element.attr('data-toggle') === 'buttons') {
                $element.find('input:checkbox').each(function (index, el) {
                    isChecked = ko.utils.arrayIndexOf(value, el.value) !== -1;
                    $(el).parent().toggleClass('active', isChecked);
                    el.checked = isChecked;
                });
            } else {
                isChecked = ko.utils.arrayIndexOf(value, $element.val()) !== -1;
                $element.toggleClass('active', isChecked);
                $element.find('input').prop('checked', isChecked);
            }
        } else {
            isChecked = !!value;
            $element.prop('checked', isChecked);
            $element.parent().toggleClass('active', isChecked);
        }
    }
};<commit_msg>Fixed changing of selected checkbox, when it is disabled<commit_after>// Knockout checked binding doesn't work with Bootstrap checkboxes
ko.bindingHandlers.checkbox = {
    init: function (element, valueAccessor) {
        var $element = $(element),
            handler = function (e) {
            // we need to handle change event after bootsrap will handle its event
            // to prevent incorrect changing of checkbox state
            setTimeout(function() {
                var $checkbox = $(e.target),
                    value = valueAccessor(),
                    data = $checkbox.val(),
                    isChecked = $checkbox.parent().hasClass('active');

                if(!$checkbox.prop('disbled')) {
                    if (ko.unwrap(value) instanceof Array) {
                        var index = ko.utils.arrayIndexOf(ko.unwrap(value), (data));

                        if (isChecked && (index === -1)) {
                            value.push(data);
                        } else if (!isChecked && (index !== -1)) {
                            value.splice(index, 1);
                        }
                    } else {
                        value(isChecked);
                    }
                }
            }, 0);
        };

        if ($element.attr('data-toggle') === 'buttons' && $element.find('input:checkbox').length) {

            if (!(ko.unwrap(valueAccessor()) instanceof Array)) {
                throw new Error('checkbox binding should be used only with array or observableArray values in this case');
            }

            $element.on('change', 'input:checkbox', handler);
        } else if ($element.attr('type') === 'checkbox') {

            if (!ko.isObservable(valueAccessor())) {
                throw new Error('checkbox binding should be used only with observable values in this case');
            }

            $element.on('change', handler);
        } else {
            throw new Error('checkbox binding should be used only with bootstrap checkboxes');
        }
    },

    update: function (element, valueAccessor) {
        var $element = $(element),
            value = ko.unwrap(valueAccessor()),
            isChecked;

        if (value instanceof Array) {
            if ($element.attr('data-toggle') === 'buttons') {
                $element.find('input:checkbox').each(function (index, el) {
                    isChecked = ko.utils.arrayIndexOf(value, el.value) !== -1;
                    $(el).parent().toggleClass('active', isChecked);
                    el.checked = isChecked;
                });
            } else {
                isChecked = ko.utils.arrayIndexOf(value, $element.val()) !== -1;
                $element.toggleClass('active', isChecked);
                $element.find('input').prop('checked', isChecked);
            }
        } else {
            isChecked = !!value;
            $element.prop('checked', isChecked);
            $element.parent().toggleClass('active', isChecked);
        }
    }
};<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 salesforce.com, 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.
 */
({
	afterRender: function(cmp, helper) {
		//update size in case carousel width is not specified
		helper.updateSize(cmp);
		this.superAfterRender();
		helper.attachEvents(cmp);
		helper.selectDefaultPage(cmp);
	},

	rerender: function(cmp, helper) {
		var shouldRerender = false;

		if (cmp.isDirty("v.width") || cmp.isDirty("v.height") || cmp.isDirty("v.priv_carouselStyle") || cmp.isDirty("v.pageComponents")) {
			helper.updateSize(cmp, forceUpdate);
			shouldRerender = true;
		}

		if (shouldRerender) {
			this.superRerender();
			if (forceUpdate) {
				helper.selectDefaultPage(cmp);
			}
		}
	},

	unrender: function(cmp, helper) {
		helper.unrender(cmp);
		this.superUnrender();
	}
})
<commit_msg>Put forceUpdate back into carouselDeprecatedRenderer.rerender<commit_after>/*
 * Copyright (C) 2013 salesforce.com, 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.
 */
({
	afterRender: function(cmp, helper) {
		//update size in case carousel width is not specified
		helper.updateSize(cmp);
		this.superAfterRender();
		helper.attachEvents(cmp);
		helper.selectDefaultPage(cmp);
	},

	rerender: function(cmp, helper) {
		var shouldRerender = false,
            forceUpdate = cmp.isDirty("v.pageComponents");

		if (cmp.isDirty("v.width") || cmp.isDirty("v.height") || cmp.isDirty("v.priv_carouselStyle") || forceUpdate) {
			helper.updateSize(cmp, forceUpdate);
			shouldRerender = true;
		}

		if (shouldRerender) {
			this.superRerender();
			if (forceUpdate) {
				helper.selectDefaultPage(cmp);
			}
		}
	},

	unrender: function(cmp, helper) {
		helper.unrender(cmp);
		this.superUnrender();
	}
})
<|endoftext|>


<commit_before>/*
 * CODENVY CONFIDENTIAL
 * __________________
 *
 *  [2012] - [2014] Codenvy, S.A.
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Codenvy S.A. and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Codenvy S.A.
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Codenvy S.A..
 */
function EntryViewPresenter() {};

EntryViewPresenter.prototype = Presenter.prototype;

EntryViewPresenter.prototype.CURRENT_PAGE_QUERY_PARAMETER = "page";
EntryViewPresenter.prototype.ONE_PAGE_ROWS_COUNT = 20;
EntryViewPresenter.prototype.SORTING_PARAMETER = "sort";
EntryViewPresenter.prototype.ASCENDING_ORDER_PREFIX = "+";
EntryViewPresenter.prototype.DESCENDING_ORDER_PREFIX = "-";
EntryViewPresenter.prototype.DEFAULT_ORDER_PREFIX = EntryViewPresenter.prototype.ASCENDING_ORDER_PREFIX;

EntryViewPresenter.prototype.TARGET_PAGE_LINK = null;

EntryViewPresenter.prototype.mapColumnNameToSortValue = null;

EntryViewPresenter.prototype.load = function() {
    var presenter = this;
    var view = presenter.view;
    var model = presenter.model;

    var viewParams = view.getParams();
    var modelParams = presenter.getModelParams(viewParams);

    // remove redundant params
    delete modelParams.page;
    delete modelParams.sort;
    delete modelParams.per_page;

    var sortingParameterValue = modelParams.sort || null;

    model.setParams(modelParams);

    // get page count
    model.pushDoneFunction(function(data) {
        var viewParams = view.getParams();
        var modelParams = presenter.getModelParams(viewParams);

        var sortingParameterValue = modelParams.sort || null;

        var pageCount = Math.ceil(data / presenter.ONE_PAGE_ROWS_COUNT) ;

        // process pagination
        var currentPageNumber = modelParams.page;
        if (typeof currentPageNumber == "undefined") {
           currentPageNumber = 1;
        } else {
           currentPageNumber = new Number(currentPageNumber);
        }

        modelParams.per_page = presenter.ONE_PAGE_ROWS_COUNT;
        modelParams.page = currentPageNumber;

        model.popDoneFunction();
        model.pushDoneFunction(function(data) {
            var table = data[0];  // there is only one table in data

            // make table columns linked
            var columnLinkPrefixList = analytics.configuration.getProperty(presenter.widgetName, "columnLinkPrefixList");
            if (typeof columnLinkPrefixList != "undefined") {
                for (var i in columnLinkPrefixList) {
                    table = view.makeTableColumnLinked(table, i, columnLinkPrefixList[i]);
                }
            }

            // make table header as linked for sorting
            for (var i = 0; i < table.columns.length; i++) {
               var columnName = table.columns[i];
               var sortParamColumnName = presenter.mapColumnNameToSortValue[columnName];
               if (typeof sortParamColumnName == "undefined") {
                   continue;
               }

               var isAscending = presenter.isSortingOrderAscending(sortParamColumnName, sortingParameterValue);

               if (isAscending == null) {
                  var headerClassOption = "";
                  var newSortingParameterValue = presenter.DEFAULT_ORDER_PREFIX + sortParamColumnName;

               } else if (isAscending) {
                  var headerClassOption = "class='ascending'";
                  var newSortingParameterValue = presenter.DESCENDING_ORDER_PREFIX + sortParamColumnName;  // for example "-user_email"

               } else {
                  var headerClassOption = "class='descending'";
                  var newSortingParameterValue = undefined;
               }

               modelParams.sort = newSortingParameterValue;

               var headerHref = presenter.TARGET_PAGE_LINK + "?" + analytics.util.constructUrlParams(modelParams);
               table.columns[i] = "" + columnName + "";
            }

            // print table
            view.printTable(table, false);
            view.loadTableHandlers();

            // print bottom page navigation
            if (pageCount > 1) {
               // remove page parameter
               delete modelParams.page;

               // restore initial sort parameter value from URL
               if (sortingParameterValue != null) {
                   modelParams.sort = sortingParameterValue;
               } else {
                   delete modelParams.sort;
               }

               var queryString = presenter.TARGET_PAGE_LINK + "?" + analytics.util.constructUrlParams(modelParams);

               view.printBottomPageNavigator(pageCount, currentPageNumber, queryString, presenter.CURRENT_PAGE_QUERY_PARAMETER);
               view.loadPageNavigationHandlers("analytics.main.reloadWidgetOnPageNavigation");
            }

            // finish loading widget
            analytics.views.loader.needLoader = false;
        });

        model.setParams(modelParams);

        var modelViewName = analytics.configuration.getProperty(presenter.widgetName, "modelViewName");
        model.getAllResults(modelViewName);
    });

    var modelMetricName = analytics.configuration.getProperty(presenter.widgetName, "modelMetricName");
    model.getMetricValue(modelMetricName);
}

/**
 * Return:
 * true, if sortingColumn = sortingParameterValue and sortingParameterValuePrefix = "+", for example: return true if sortingColumn="user_email" and sortingParameterValue = "+user_email"
 * false, if sortingColumn = sortingParameterValue and sortingParameterValuePrefix = "-", for example: return true if sortingColumn="user_email" and sortingParameterValue = "-user_email"
 * null, if sortingParameterValue = null, of sortingColumn != sortingParameterValue
 *
 */
EntryViewPresenter.prototype.isSortingOrderAscending = function(sortingColumn, sortingParameterValue) {
   var presenter = this;

   if (sortingParameterValue == null) {
      return null;
   }

   if (sortingParameterValue.substring(1) == sortingColumn) {
      var sortingOrder = sortingParameterValue.charAt(0);
      if (sortingOrder == presenter.ASCENDING_ORDER_PREFIX) {
         return true;
      } else if (sortingOrder == presenter.DESCENDING_ORDER_PREFIX){
         return false;
      }
   }

   return null;
}<commit_msg>Fixed sorting in UI: remove passing sort=undefined<commit_after>/*
 * CODENVY CONFIDENTIAL
 * __________________
 *
 *  [2012] - [2014] Codenvy, S.A.
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Codenvy S.A. and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Codenvy S.A.
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Codenvy S.A..
 */
function EntryViewPresenter() {};

EntryViewPresenter.prototype = Presenter.prototype;

EntryViewPresenter.prototype.CURRENT_PAGE_QUERY_PARAMETER = "page";
EntryViewPresenter.prototype.ONE_PAGE_ROWS_COUNT = 20;
EntryViewPresenter.prototype.SORTING_PARAMETER = "sort";
EntryViewPresenter.prototype.ASCENDING_ORDER_PREFIX = "+";
EntryViewPresenter.prototype.DESCENDING_ORDER_PREFIX = "-";
EntryViewPresenter.prototype.DEFAULT_ORDER_PREFIX = EntryViewPresenter.prototype.ASCENDING_ORDER_PREFIX;

EntryViewPresenter.prototype.TARGET_PAGE_LINK = null;

EntryViewPresenter.prototype.mapColumnNameToSortValue = null;

EntryViewPresenter.prototype.load = function() {
    var presenter = this;
    var view = presenter.view;
    var model = presenter.model;

    var viewParams = view.getParams();
    var modelParams = presenter.getModelParams(viewParams);

    // remove redundant params
    delete modelParams.page;
    delete modelParams.sort;
    delete modelParams.per_page;

    var sortingParameterValue = modelParams.sort || null;

    model.setParams(modelParams);

    // get page count
    model.pushDoneFunction(function(data) {
        var viewParams = view.getParams();
        var modelParams = presenter.getModelParams(viewParams);

        var sortingParameterValue = modelParams.sort || null;

        var pageCount = Math.ceil(data / presenter.ONE_PAGE_ROWS_COUNT) ;

        // process pagination
        var currentPageNumber = modelParams.page;
        if (typeof currentPageNumber == "undefined") {
           currentPageNumber = 1;
        } else {
           currentPageNumber = new Number(currentPageNumber);
        }

        modelParams.per_page = presenter.ONE_PAGE_ROWS_COUNT;
        modelParams.page = currentPageNumber;

        model.popDoneFunction();
        model.pushDoneFunction(function(data) {
            var table = data[0];  // there is only one table in data

            // make table columns linked
            var columnLinkPrefixList = analytics.configuration.getProperty(presenter.widgetName, "columnLinkPrefixList");
            if (typeof columnLinkPrefixList != "undefined") {
                for (var i in columnLinkPrefixList) {
                    table = view.makeTableColumnLinked(table, i, columnLinkPrefixList[i]);
                }
            }

            // make table header as linked for sorting
            for (var i = 0; i < table.columns.length; i++) {
               var columnName = table.columns[i];
               var sortParamColumnName = presenter.mapColumnNameToSortValue[columnName];
               if (typeof sortParamColumnName == "undefined") {
                   continue;
               }

               var isAscending = presenter.isSortingOrderAscending(sortParamColumnName, sortingParameterValue);

               if (isAscending == null) {
                  var headerClassOption = "";
                  var newSortingParameterValue = presenter.DEFAULT_ORDER_PREFIX + sortParamColumnName;

               } else if (isAscending) {
                  var headerClassOption = "class='ascending'";
                  var newSortingParameterValue = presenter.DESCENDING_ORDER_PREFIX + sortParamColumnName;  // for example "-user_email"

               } else {
                  var headerClassOption = "class='descending'";
                  var newSortingParameterValue = undefined;
               }

               if (typeof newSortingParameterValue == "undefined") {
                   delete modelParams.sort;
               } else {
                   modelParams.sort = newSortingParameterValue;
               }

               var headerHref = presenter.TARGET_PAGE_LINK + "?" + analytics.util.constructUrlParams(modelParams);
               table.columns[i] = "" + columnName + "";
            }

            // print table
            view.printTable(table, false);
            view.loadTableHandlers();

            // print bottom page navigation
            if (pageCount > 1) {
               // remove page parameter
               delete modelParams.page;

               // restore initial sort parameter value from URL
               if (sortingParameterValue != null) {
                   modelParams.sort = sortingParameterValue;
               } else {
                   delete modelParams.sort;
               }

               var queryString = presenter.TARGET_PAGE_LINK + "?" + analytics.util.constructUrlParams(modelParams);

               view.printBottomPageNavigator(pageCount, currentPageNumber, queryString, presenter.CURRENT_PAGE_QUERY_PARAMETER);
               view.loadPageNavigationHandlers("analytics.main.reloadWidgetOnPageNavigation");
            }

            // finish loading widget
            analytics.views.loader.needLoader = false;
        });

        model.setParams(modelParams);

        var modelViewName = analytics.configuration.getProperty(presenter.widgetName, "modelViewName");
        model.getAllResults(modelViewName);
    });

    var modelMetricName = analytics.configuration.getProperty(presenter.widgetName, "modelMetricName");
    model.getMetricValue(modelMetricName);
}

/**
 * Return:
 * true, if sortingColumn = sortingParameterValue and sortingParameterValuePrefix = "+", for example: return true if sortingColumn="user_email" and sortingParameterValue = "+user_email"
 * false, if sortingColumn = sortingParameterValue and sortingParameterValuePrefix = "-", for example: return true if sortingColumn="user_email" and sortingParameterValue = "-user_email"
 * null, if sortingParameterValue = null, of sortingColumn != sortingParameterValue
 *
 */
EntryViewPresenter.prototype.isSortingOrderAscending = function(sortingColumn, sortingParameterValue) {
   var presenter = this;

   if (sortingParameterValue == null) {
      return null;
   }

   if (sortingParameterValue.substring(1) == sortingColumn) {
      var sortingOrder = sortingParameterValue.charAt(0);
      if (sortingOrder == presenter.ASCENDING_ORDER_PREFIX) {
         return true;
      } else if (sortingOrder == presenter.DESCENDING_ORDER_PREFIX){
         return false;
      }
   }

   return null;
}<|endoftext|>


<commit_before>import React, {Component} from 'react';
import {createPortal} from 'react-dom';

export default class Frame extends Component {
    componentDidMount() {
        this.node.addEventListener('load', this.handleLoad);
    }

    handleLoad = () => {
        this.setupFrameBaseStyle();
    };

    componentWillUnmout() {
        this.node.removeEventListener('load', this.handleLoad);
    }

    setupFrameBaseStyle() {
        this.iframeHtml = this.node.contentDocument.documentElement;
        this.iframeHead = this.node.contentDocument.head;
        this.iframeRoot = this.node.contentDocument.body;
        this.forceUpdate();
    }

    render() {
        const {children, head, title = '', style = {}, ...rest} = this.props;
        return (
            <iframe srcDoc={`<!DOCTYPE html>`} {...rest} ref={node => (this.node = node)} title={title} style={style} frameBorder="0">
                {this.iframeHead && createPortal(head, this.iframeHead)}
                {this.iframeRoot && createPortal(children, this.iframeRoot)}
            </iframe>
        );
    }
}
<commit_msg>Added guard for missing contentDocument<commit_after>import React, {Component} from 'react';
import {createPortal} from 'react-dom';

export default class Frame extends Component {
    componentDidMount() {
        this.node.addEventListener('load', this.handleLoad);
    }

    handleLoad = () => {
        this.setupFrameBaseStyle();
    };

    componentWillUnmout() {
        this.node.removeEventListener('load', this.handleLoad);
    }

    setupFrameBaseStyle() {
        if (this.node.contentDocument) {
            this.iframeHtml = this.node.contentDocument.documentElement;
            this.iframeHead = this.node.contentDocument.head;
            this.iframeRoot = this.node.contentDocument.body;
            this.forceUpdate();
        }
    }

    render() {
        const {children, head, title = '', style = {}, ...rest} = this.props;
        return (
            <iframe srcDoc={`<!DOCTYPE html>`} {...rest} ref={node => (this.node = node)} title={title} style={style} frameBorder="0">
                {this.iframeHead && createPortal(head, this.iframeHead)}
                {this.iframeRoot && createPortal(children, this.iframeRoot)}
            </iframe>
        );
    }
}
<|endoftext|>