<commit_before>/*
 * Copyright (c) 2013, Yahoo! Inc. All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */

/*jslint browser: true, nomen: true, regexp: true */
/*global YUI */

YUI.add('mojito-debug-application', function (Y, NAME) {
    'use strict';

    function DebugApplication(iframe, debuggerNode, flushes, simulateFlushing, callback) {
        var self = this,
            firstFlushTime;

        this.iframe = iframe;
        this.window = iframe._node.contentWindow;
        this.document = this.window.document;
        this.debuggerNode = debuggerNode;
        this.opened = Y.Debug.mode !== 'hide';

        self.window.document.open();

        Y.Array.each(flushes, function (flush, i) {
            var flushTime = simulateFlushing ? flush.time : 0,
                writeFlushData = function () {
                    var currentTime = Y.mojito.Waterfall.now(),
                        delay;

                    if (i === 0) {
                        // First Flush
                        firstFlushTime = currentTime;
                        Y.Debug.timing.client.firstFlush = firstFlushTime;
                    }

                    delay = currentTime - firstFlushTime;

                    // Sometimes setTimeout calls the callback before the specified delay.
                    // If this happens then set another timeout with the remaining delay.
                    // This ensures that flush data are not written ahead of time.
                    // Runtime tests show that doing this makes the writing of flush data
                    // at most 1 ms late.
                    if (delay < flushTime) {
                        setTimeout(writeFlushData, flushTime - delay);
                        return;
                    }

                    self.window.document.write(flush.data);

                    if (i === 0) {
                        self._catchLinkNavigation();
                    }

                    if (i === flushes.length - 1) {
                        // Last Flush
                        Y.Debug.timing.client.lastFlush = currentTime;
                        self.window.document.close();
                        self._catchFormNavigation();
                        self.init(callback);
                    }
                };

            setTimeout(writeFlushData, flushTime);
        });
    }

    DebugApplication.prototype = {

        init: function (callback) {
            var self = this,
                iframe = self.iframe,
                window = self.window,
                document = self.document,
                loaded = false,
                showDebugger = function () {
                    self.debuggerNode.setStyle('display', 'block');
                },
                done = function () {
                    if (loaded) {
                        // If the application iframe has already loaded then a subsequent load
                        // means that the application was reloaded and the debugger didn't catch it.
                        // This reloads the entire page with the new application url such that the debugger
                        // and the application remain in sync.
                        self._navigateToUrl(window.location.href);
                        return;
                    }

                    if (self.opened) {
                        iframe.setStyle('height', 'auto');
                        iframe.setStyle('height', self.window.document.body.scrollHeight + 'px');
                    }

                    // If either catching of navigation was not possible, now it is
                    // since the iframe is fully loaded.
                    self._catchLinkNavigation();
                    self._catchFormNavigation();

                    loaded = true;

                    // Asynchronously calling callback to make sure the application is shown entirely before the debugger.
                    // This seems to avoid flickering.
                    setTimeout(function () {
                        callback();
                    }, 0);
                };

            if (Y.Debug.mode !== 'hide') {
                self.open(false);
            }

            // Hide the page when the application is unloading,
            // this is useful if the application reloads without a click to a link
            // or submitting a form. When this happens the application is out of sync
            // with the debugger until it finishes loading and the debugger reloads the page
            // with the new application url.
            Y.Node(window).on('unload', function () {
                Y.Debug.binder.node.hide();
            });

            if (document.readyState === 'complete') {
                showDebugger();
                done();
            } else if (document.readyState === 'interactive') {
                showDebugger();
            } else {
                if (document.addEventListener) {
                    document.addEventListener('DOMContentLoaded', showDebugger, false);
                } else if (document.attachEvent) {
                    document.attachEvent('DOMContentLoaded', showDebugger);
                }
            }

            iframe.on('load', done);
        },

        _urlIsInternal: function (url) {
            var m = url.match(/https?:\/\/([^\/]+)/),
                host = m && m[1];
            return host === window.location.host;
        },

        _addDebugParam: function (url) {
            var parts = url.split('?'),
                params = Y.Debug.binder.getUrlParams(parts[1]),
                paramArray = [],
                currentHooks = Y.Debug.binder.history.get('hooks'),
                currentMode = Y.Debug.binder.history.get('mode'),
                debugParam = 'debug' + (currentMode ? '.' + currentMode : '');

            // Remove any debug params.
            Y.Object.each(params, function (value, param) {
                if (/debug\.?/.test(param)) {
                    delete params[param];
                }
            });

            // Set the debug param to the current enabled hooks
            params[debugParam] = currentHooks.join(',');

            // Navigate to the new url
            Y.Object.each(params, function (value, param) {
                paramArray.push(param + (value !== null ? '=' + value : ''));
            });

            return parts[0] + '?' + paramArray.join('&');
        },

        _navigateToUrl: function (url) {
            // If the url is internal, then update the debug param with the current hooks
            // and navigate to the url.
            if (this._urlIsInternal(url)) {
                url = this._addDebugParam(url);
            }
            window.location.href = url;
        },

        _catchLinkNavigation: function () {
            if (!this.document.body) {
                // The document body is not ready yet, so this method will be called once the
                // iframe reaches its loaded state.
                return;
            }

            var self = this,
                body = Y.Node(this.document.body);

            // Catch link clicks on the application in the iframe in order to
            // refresh the entire page with the current debug hooks.
            body.delegate('click', function (e) {
                var url = e.target.get('href');
                if (url) {
                    e.preventDefault();
                    self._navigateToUrl(url);
                }
            }, 'a');

            // Don't call this method more than once.
            this._catchLinkNavigation = function () {};
        },

        _catchFormNavigation: function () {
            if (!this.document.body) {
                // The document body is not ready yet, so this method will be called once the
                // iframe reaches its loaded state.
                return;
            }

            var self = this,
                body = Y.Node(this.document.body);

            body.all('form').on('submit', function (e) {
                var form = e.currentTarget,
                    url = form.get('action'),
                    parts,
                    paramsArray = [];

                if (url) {
                    parts = url.split('?');
                } else {
                    return;
                }

                e.halt(true);

                // Add params given form's children input values.
                form.all('input').each(function (input) {
                    var name = input.get('name');
                    if (name) {
                        paramsArray.push(name + '=' + input.get('value'));
                    }
                });

                if (parts[1]) {
                    paramsArray.unshift(parts[1]);
                }

                if (paramsArray.length > 0) {
                    url = parts[0] + '?' + paramsArray.join('&');
                }

                self._navigateToUrl(url);
            }, 'form');

            // Don't call this method more than once.
            this._catchFormNavigation = function () {};
        },

        open: function (anim, done) {
            var self = this;

            if (!self.window.document.body) {
                self.window.onload = function () {
                    self._toggle(anim, 'show', done);
                };
            } else {
                self._toggle(anim, 'show', done);
            }
        },

        close: function (anim) {
            this._toggle(anim, 'hide');
        },

        _toggle: function (anim, state, done) {
            if (!state) {
                this.opened = !this.opened;
            } else if (state === 'show') {
                this.opened = true;
            } else {
                this.opened = false;
            }

            // Set iframe height to auto such that the document inside returns the correct scrollheight
            if (this.opened) {
                this.iframe.setStyle('height', 'auto');
            }

            this.iframe.transition({
                easing: 'ease-out',
                duration: anim ? 0.3 : 0,
                height: this.opened ? this.window.document.body.scrollHeight + 'px' : '0px'
            });

            if (done) {
                done();
            }

            if (this.opened) {
                this.timeout = setInterval(function () {
                    try {
                        this.iframe.setStyle('height', this.window.document.body.scrollHeight + 'px');
                    } catch (e) {
                        clearTimeout(this.timeout);
                    }
                }.bind(this), 200);
            } else {
                clearTimeout(this.timeout);
            }
        }
    };

    Y.namespace('mojito.debug').Application = DebugApplication;
}, '0.0.1', {
    requires: [
        'node',
        'mojito-debug-addon',
        'mojito-waterfall'
    ]
});
<commit_msg>Making sure that the debugger is shown after the application.<commit_after>/*
 * Copyright (c) 2013, Yahoo! Inc. All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */

/*jslint browser: true, nomen: true, regexp: true */
/*global YUI */

YUI.add('mojito-debug-application', function (Y, NAME) {
    'use strict';

    function DebugApplication(iframe, debuggerNode, flushes, simulateFlushing, callback) {
        var self = this,
            firstFlushTime;

        this.iframe = iframe;
        this.window = iframe._node.contentWindow;
        this.document = this.window.document;
        this.debuggerNode = debuggerNode;
        this.opened = Y.Debug.mode !== 'hide';

        self.window.document.open();

        Y.Array.each(flushes, function (flush, i) {
            var flushTime = simulateFlushing ? flush.time : 0,
                writeFlushData = function () {
                    var currentTime = Y.mojito.Waterfall.now(),
                        delay;

                    if (i === 0) {
                        // First Flush
                        firstFlushTime = currentTime;
                        Y.Debug.timing.client.firstFlush = firstFlushTime;
                    }

                    delay = currentTime - firstFlushTime;

                    // Sometimes setTimeout calls the callback before the specified delay.
                    // If this happens then set another timeout with the remaining delay.
                    // This ensures that flush data are not written ahead of time.
                    // Runtime tests show that doing this makes the writing of flush data
                    // at most 1 ms late.
                    if (delay < flushTime) {
                        setTimeout(writeFlushData, flushTime - delay);
                        return;
                    }

                    self.window.document.write(flush.data);

                    if (i === 0) {
                        self._catchLinkNavigation();
                    }

                    if (i === flushes.length - 1) {
                        // Last Flush
                        Y.Debug.timing.client.lastFlush = currentTime;
                        self.window.document.close();
                        self._catchFormNavigation();
                        self.init(callback);
                    }
                };

            setTimeout(writeFlushData, flushTime);
        });
    }

    DebugApplication.prototype = {

        init: function (callback) {
            var self = this,
                iframe = self.iframe,
                window = self.window,
                document = self.document,
                loaded = false,
                showDebugger = function () {
                    if (loaded) {
                        self.debuggerNode.setStyle('display', 'block');
                    }
                },
                done = function () {
                    if (loaded) {
                        // If the application iframe has already loaded then a subsequent load
                        // means that the application was reloaded and the debugger didn't catch it.
                        // This reloads the entire page with the new application url such that the debugger
                        // and the application remain in sync.
                        self._navigateToUrl(window.location.href);
                        return;
                    }

                    if (self.opened) {
                        iframe.setStyle('height', 'auto');
                        iframe.setStyle('height', self.window.document.body.scrollHeight + 'px');
                    }

                    // If either catching of navigation was not possible, now it is
                    // since the iframe is fully loaded.
                    self._catchLinkNavigation();
                    self._catchFormNavigation();

                    loaded = true;

                    // Asynchronously calling callback to make sure the application is shown entirely before the debugger.
                    // This seems to avoid flickering.
                    setTimeout(function () {
                        showDebugger();
                        callback();
                    }, 0);
                };

            if (Y.Debug.mode !== 'hide') {
                self.open(false);
            }

            // Hide the page when the application is unloading,
            // this is useful if the application reloads without a click to a link
            // or submitting a form. When this happens the application is out of sync
            // with the debugger until it finishes loading and the debugger reloads the page
            // with the new application url.
            Y.Node(window).on('unload', function () {
                Y.Debug.binder.node.hide();
            });

            if (document.readyState === 'complete') {
                showDebugger();
                done();
            } else if (document.readyState === 'interactive') {
                showDebugger();
            } else {
                if (document.addEventListener) {
                    document.addEventListener('DOMContentLoaded', showDebugger, false);
                } else if (document.attachEvent) {
                    document.attachEvent('DOMContentLoaded', showDebugger);
                }
            }

            iframe.on('load', done);
        },

        _urlIsInternal: function (url) {
            var m = url.match(/https?:\/\/([^\/]+)/),
                host = m && m[1];
            return host === window.location.host;
        },

        _addDebugParam: function (url) {
            var parts = url.split('?'),
                params = Y.Debug.binder.getUrlParams(parts[1]),
                paramArray = [],
                currentHooks = Y.Debug.binder.history.get('hooks'),
                currentMode = Y.Debug.binder.history.get('mode'),
                debugParam = 'debug' + (currentMode ? '.' + currentMode : '');

            // Remove any debug params.
            Y.Object.each(params, function (value, param) {
                if (/debug\.?/.test(param)) {
                    delete params[param];
                }
            });

            // Set the debug param to the current enabled hooks
            params[debugParam] = currentHooks.join(',');

            // Navigate to the new url
            Y.Object.each(params, function (value, param) {
                paramArray.push(param + (value !== null ? '=' + value : ''));
            });

            return parts[0] + '?' + paramArray.join('&');
        },

        _navigateToUrl: function (url) {
            // If the url is internal, then update the debug param with the current hooks
            // and navigate to the url.
            if (this._urlIsInternal(url)) {
                url = this._addDebugParam(url);
            }
            window.location.href = url;
        },

        _catchLinkNavigation: function () {
            if (!this.document.body) {
                // The document body is not ready yet, so this method will be called once the
                // iframe reaches its loaded state.
                return;
            }

            var self = this,
                body = Y.Node(this.document.body);

            // Catch link clicks on the application in the iframe in order to
            // refresh the entire page with the current debug hooks.
            body.delegate('click', function (e) {
                var url = e.target.get('href');
                if (url) {
                    e.preventDefault();
                    self._navigateToUrl(url);
                }
            }, 'a');

            // Don't call this method more than once.
            this._catchLinkNavigation = function () {};
        },

        _catchFormNavigation: function () {
            if (!this.document.body) {
                // The document body is not ready yet, so this method will be called once the
                // iframe reaches its loaded state.
                return;
            }

            var self = this,
                body = Y.Node(this.document.body);

            body.all('form').on('submit', function (e) {
                var form = e.currentTarget,
                    url = form.get('action'),
                    parts,
                    paramsArray = [];

                if (url) {
                    parts = url.split('?');
                } else {
                    return;
                }

                e.halt(true);

                // Add params given form's children input values.
                form.all('input').each(function (input) {
                    var name = input.get('name');
                    if (name) {
                        paramsArray.push(name + '=' + input.get('value'));
                    }
                });

                if (parts[1]) {
                    paramsArray.unshift(parts[1]);
                }

                if (paramsArray.length > 0) {
                    url = parts[0] + '?' + paramsArray.join('&');
                }

                self._navigateToUrl(url);
            }, 'form');

            // Don't call this method more than once.
            this._catchFormNavigation = function () {};
        },

        open: function (anim, done) {
            var self = this;

            if (!self.window.document.body) {
                self.window.onload = function () {
                    self._toggle(anim, 'show', done);
                };
            } else {
                self._toggle(anim, 'show', done);
            }
        },

        close: function (anim) {
            this._toggle(anim, 'hide');
        },

        _toggle: function (anim, state, done) {
            if (!state) {
                this.opened = !this.opened;
            } else if (state === 'show') {
                this.opened = true;
            } else {
                this.opened = false;
            }

            // Set iframe height to auto such that the document inside returns the correct scrollheight
            if (this.opened) {
                this.iframe.setStyle('height', 'auto');
            }

            this.iframe.transition({
                easing: 'ease-out',
                duration: anim ? 0.3 : 0,
                height: this.opened ? this.window.document.body.scrollHeight + 'px' : '0px'
            });

            if (done) {
                done();
            }

            if (this.opened) {
                this.timeout = setInterval(function () {
                    try {
                        this.iframe.setStyle('height', this.window.document.body.scrollHeight + 'px');
                    } catch (e) {
                        clearTimeout(this.timeout);
                    }
                }.bind(this), 200);
            } else {
                clearTimeout(this.timeout);
            }
        }
    };

    Y.namespace('mojito.debug').Application = DebugApplication;
}, '0.0.1', {
    requires: [
        'node',
        'mojito-debug-addon',
        'mojito-waterfall'
    ]
});
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */
'use strict';

const getInverseDependencies = require('node-haste').getInverseDependencies;
const querystring = require('querystring');
const url = require('url');

/**
 * Attaches a WebSocket based connection to the Packager to expose
 * Hot Module Replacement updates to the simulator.
 */
function attachHMRServer({httpServer, path, packagerServer}) {
  let client = null;

  function disconnect() {
    client = null;
    packagerServer.setHMRFileChangeListener(null);
  }

  // For the give platform and entry file, returns a promise with:
  //   - The full list of dependencies.
  //   - The shallow dependencies each file on the dependency list has
  //   - Inverse shallow dependencies map
  function getDependencies(platform, bundleEntry) {
    return packagerServer.getDependencies({
      platform: platform,
      dev: true,
      hot: true,
      entryFile: bundleEntry,
    }).then(response => {
      // for each dependency builds the object:
      // `{path: '/a/b/c.js', deps: ['modA', 'modB', ...]}`
      return Promise.all(Object.values(response.dependencies).map(dep => {
        return dep.getName().then(depName => {
          if (dep.isAsset() || dep.isAsset_DEPRECATED() || dep.isJSON()) {
            return Promise.resolve({path: dep.path, deps: []});
          }
          return packagerServer.getShallowDependencies(dep.path)
            .then(deps => {
              return {
                path: dep.path,
                name: depName,
                deps,
              };
            });
        });
      }))
      .then(deps => {
        // list with all the dependencies' filenames the bundle entry has
        const dependenciesCache = response.dependencies.map(dep => dep.path);

        // map from module name to path
        const moduleToFilenameCache = Object.create(null);
        deps.forEach(dep => moduleToFilenameCache[dep.name] = dep.path);

        // map that indicates the shallow dependency each file included on the
        // bundle has
        const shallowDependencies = Object.create(null);
        deps.forEach(dep => shallowDependencies[dep.path] = dep.deps);

        // map from module name to the modules' dependencies the bundle entry
        // has
        const dependenciesModulesCache = Object.create(null);
        return Promise.all(response.dependencies.map(dep => {
          return dep.getName().then(depName => {
            dependenciesModulesCache[depName] = dep;
          });
        })).then(() => {
          return getInverseDependencies(response)
            .then(inverseDependenciesCache => {
              return {
                dependenciesCache,
                dependenciesModulesCache,
                shallowDependencies,
                inverseDependenciesCache,
                resolutionResponse: response,
              };
            });
        });
      });
    });
  }

  const WebSocketServer = require('ws').Server;
  const wss = new WebSocketServer({
    server: httpServer,
    path: path,
  });

  console.log('[Hot Module Replacement] Server listening on', path);
  wss.on('connection', ws => {
    console.log('[Hot Module Replacement] Client connected');
    const params = querystring.parse(url.parse(ws.upgradeReq.url).query);

    getDependencies(params.platform, params.bundleEntry)
      .then(({
        dependenciesCache,
        dependenciesModulesCache,
        shallowDependencies,
        inverseDependenciesCache,
      }) => {
        client = {
          ws,
          platform: params.platform,
          bundleEntry: params.bundleEntry,
          dependenciesCache,
          dependenciesModulesCache,
          shallowDependencies,
          inverseDependenciesCache,
        };

        packagerServer.setHMRFileChangeListener((filename, stat) => {
          if (!client) {
            return;
          }
          console.log(
            `[Hot Module Replacement] File change detected (${time()})`
          );

          client.ws.send(JSON.stringify({type: 'update-start'}));
          stat.then(() => {
            return packagerServer.getShallowDependencies(filename)
              .then(deps => {
                if (!client) {
                  return [];
                }

                // if the file dependencies have change we need to invalidate the
                // dependencies caches because the list of files we need to send
                // to the client may have changed
                const oldDependencies = client.shallowDependencies[filename];
                if (arrayEquals(deps, oldDependencies)) {
                  // Need to create a resolution response to pass to the bundler
                  // to process requires after transform. By providing a
                  // specific response we can compute a non recursive one which
                  // is the least we need and improve performance.
                  return packagerServer.getDependencies({
                    platform: client.platform,
                    dev: true,
                    hot: true,
                    entryFile: filename,
                    recursive: true,
                  }).then(response => {
                    const module = packagerServer.getModuleForPath(filename);

                    return response.copy({dependencies: [module]});
                  });
                }

                // if there're new dependencies compare the full list of
                // dependencies we used to have with the one we now have
                return getDependencies(client.platform, client.bundleEntry)
                  .then(({
                    dependenciesCache,
                    dependenciesModulesCache,
                    shallowDependencies,
                    inverseDependenciesCache,
                    resolutionResponse,
                  }) => {
                    if (!client) {
                      return {};
                    }

                    // build list of modules for which we'll send HMR updates
                    const modulesToUpdate = [packagerServer.getModuleForPath(filename)];
                    Object.keys(dependenciesModulesCache).forEach(module => {
                      if (!client.dependenciesModulesCache[module]) {
                        modulesToUpdate.push(dependenciesModulesCache[module]);
                      }
                    });

                    // Need to send modules to the client in an order it can
                    // process them: if a new dependency graph was uncovered
                    // because a new dependency was added, the file that was
                    // changed, which is the root of the dependency tree that
                    // will be sent, needs to be the last module that gets
                    // processed. Reversing the new modules makes sense
                    // because we get them through the resolver which returns
                    // a BFS ordered list.
                    modulesToUpdate.reverse();

                    // invalidate caches
                    client.dependenciesCache = dependenciesCache;
                    client.dependenciesModulesCache = dependenciesModulesCache;
                    client.shallowDependencies = shallowDependencies;

                    return resolutionResponse.copy({
                      dependencies: modulesToUpdate
                    });
                  });
              })
              .then((resolutionResponse) => {
                if (!client) {
                  return;
                }

                // make sure the file was modified is part of the bundle
                if (!client.shallowDependencies[filename]) {
                  return;
                }

                const httpServerAddress = httpServer.address();

                // Sanitize the value from the HTTP server
                let packagerHost = 'localhost';
                if (httpServer.address().address &&
                    httpServer.address().address !== '::' &&
                    httpServer.address().address !== '') {
                  packagerHost = httpServerAddress.address;
                }

                let packagerPort = httpServerAddress.port;

                return packagerServer.buildBundleForHMR({
                  entryFile: client.bundleEntry,
                  platform: client.platform,
                  resolutionResponse,
                }, packagerHost, packagerPort);
              })
              .then(bundle => {
                if (!client || !bundle || bundle.isEmpty()) {
                  return;
                }

                return JSON.stringify({
                  type: 'update',
                  body: {
                    modules: bundle.getModulesNamesAndCode(),
                    inverseDependencies: inverseDependenciesCache,
                    sourceURLs: bundle.getSourceURLs(),
                    sourceMappingURLs: bundle.getSourceMappingURLs(),
                  },
                });
              })
              .catch(error => {
                // send errors to the client instead of killing packager server
                let body;
                if (error.type === 'TransformError' ||
                    error.type === 'NotFoundError' ||
                    error.type === 'UnableToResolveError') {
                  body = {
                    type: error.type,
                    description: error.description,
                    filename: error.filename,
                    lineNumber: error.lineNumber,
                  };
                } else {
                  console.error(error.stack || error);
                  body = {
                    type: 'InternalError',
                    description: 'react-packager has encountered an internal error, ' +
                      'please check your terminal error output for more details',
                  };
                }

                return JSON.stringify({type: 'error', body});
              })
              .then(update => {
                if (!client || !update) {
                  return;
                }

                console.log(
                  '[Hot Module Replacement] Sending HMR update to client (' +
                  time() + ')'
                );
                client.ws.send(update);
              });
            },
            () => {
              // do nothing, file was removed
            },
          ).finally(() => {
            client.ws.send(JSON.stringify({type: 'update-done'}));
          });
        });

        client.ws.on('error', e => {
          console.error('[Hot Module Replacement] Unexpected error', e);
          disconnect();
        });

        client.ws.on('close', () => disconnect());
      })
    .done();
  });
}

function arrayEquals(arrayA, arrayB) {
  arrayA = arrayA || [];
  arrayB = arrayB || [];
  return (
    arrayA.length === arrayB.length &&
    arrayA.every((element, index) => {
      return element === arrayB[index];
    })
  );
}

function time() {
  const date = new Date();
  return `${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}:${date.getMilliseconds()}`;
}

module.exports = attachHMRServer;
<commit_msg>Blacklist modules from being how swapped<commit_after>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */
'use strict';

const getInverseDependencies = require('node-haste').getInverseDependencies;
const querystring = require('querystring');
const url = require('url');

const blacklist = [
  'Libraries/Utilities/HMRClient.js',
];

/**
 * Attaches a WebSocket based connection to the Packager to expose
 * Hot Module Replacement updates to the simulator.
 */
function attachHMRServer({httpServer, path, packagerServer}) {
  let client = null;

  function disconnect() {
    client = null;
    packagerServer.setHMRFileChangeListener(null);
  }

  // For the give platform and entry file, returns a promise with:
  //   - The full list of dependencies.
  //   - The shallow dependencies each file on the dependency list has
  //   - Inverse shallow dependencies map
  function getDependencies(platform, bundleEntry) {
    return packagerServer.getDependencies({
      platform: platform,
      dev: true,
      hot: true,
      entryFile: bundleEntry,
    }).then(response => {
      // for each dependency builds the object:
      // `{path: '/a/b/c.js', deps: ['modA', 'modB', ...]}`
      return Promise.all(Object.values(response.dependencies).map(dep => {
        return dep.getName().then(depName => {
          if (dep.isAsset() || dep.isAsset_DEPRECATED() || dep.isJSON()) {
            return Promise.resolve({path: dep.path, deps: []});
          }
          return packagerServer.getShallowDependencies(dep.path)
            .then(deps => {
              return {
                path: dep.path,
                name: depName,
                deps,
              };
            });
        });
      }))
      .then(deps => {
        // list with all the dependencies' filenames the bundle entry has
        const dependenciesCache = response.dependencies.map(dep => dep.path);

        // map from module name to path
        const moduleToFilenameCache = Object.create(null);
        deps.forEach(dep => moduleToFilenameCache[dep.name] = dep.path);

        // map that indicates the shallow dependency each file included on the
        // bundle has
        const shallowDependencies = Object.create(null);
        deps.forEach(dep => shallowDependencies[dep.path] = dep.deps);

        // map from module name to the modules' dependencies the bundle entry
        // has
        const dependenciesModulesCache = Object.create(null);
        return Promise.all(response.dependencies.map(dep => {
          return dep.getName().then(depName => {
            dependenciesModulesCache[depName] = dep;
          });
        })).then(() => {
          return getInverseDependencies(response)
            .then(inverseDependenciesCache => {
              return {
                dependenciesCache,
                dependenciesModulesCache,
                shallowDependencies,
                inverseDependenciesCache,
                resolutionResponse: response,
              };
            });
        });
      });
    });
  }

  const WebSocketServer = require('ws').Server;
  const wss = new WebSocketServer({
    server: httpServer,
    path: path,
  });

  console.log('[Hot Module Replacement] Server listening on', path);
  wss.on('connection', ws => {
    console.log('[Hot Module Replacement] Client connected');
    const params = querystring.parse(url.parse(ws.upgradeReq.url).query);

    getDependencies(params.platform, params.bundleEntry)
      .then(({
        dependenciesCache,
        dependenciesModulesCache,
        shallowDependencies,
        inverseDependenciesCache,
      }) => {
        client = {
          ws,
          platform: params.platform,
          bundleEntry: params.bundleEntry,
          dependenciesCache,
          dependenciesModulesCache,
          shallowDependencies,
          inverseDependenciesCache,
        };

        packagerServer.setHMRFileChangeListener((filename, stat) => {
          if (!client) {
            return;
          }
          console.log(
            `[Hot Module Replacement] File change detected (${time()})`
          );

          const blacklisted = blacklist.find(path =>
            filename.indexOf(path) !== -1
          );

          if (blacklisted) {
            return;
          }

          client.ws.send(JSON.stringify({type: 'update-start'}));
          stat.then(() => {
            return packagerServer.getShallowDependencies(filename)
              .then(deps => {
                if (!client) {
                  return [];
                }

                // if the file dependencies have change we need to invalidate the
                // dependencies caches because the list of files we need to send
                // to the client may have changed
                const oldDependencies = client.shallowDependencies[filename];
                if (arrayEquals(deps, oldDependencies)) {
                  // Need to create a resolution response to pass to the bundler
                  // to process requires after transform. By providing a
                  // specific response we can compute a non recursive one which
                  // is the least we need and improve performance.
                  return packagerServer.getDependencies({
                    platform: client.platform,
                    dev: true,
                    hot: true,
                    entryFile: filename,
                    recursive: true,
                  }).then(response => {
                    const module = packagerServer.getModuleForPath(filename);

                    return response.copy({dependencies: [module]});
                  });
                }

                // if there're new dependencies compare the full list of
                // dependencies we used to have with the one we now have
                return getDependencies(client.platform, client.bundleEntry)
                  .then(({
                    dependenciesCache,
                    dependenciesModulesCache,
                    shallowDependencies,
                    inverseDependenciesCache,
                    resolutionResponse,
                  }) => {
                    if (!client) {
                      return {};
                    }

                    // build list of modules for which we'll send HMR updates
                    const modulesToUpdate = [packagerServer.getModuleForPath(filename)];
                    Object.keys(dependenciesModulesCache).forEach(module => {
                      if (!client.dependenciesModulesCache[module]) {
                        modulesToUpdate.push(dependenciesModulesCache[module]);
                      }
                    });

                    // Need to send modules to the client in an order it can
                    // process them: if a new dependency graph was uncovered
                    // because a new dependency was added, the file that was
                    // changed, which is the root of the dependency tree that
                    // will be sent, needs to be the last module that gets
                    // processed. Reversing the new modules makes sense
                    // because we get them through the resolver which returns
                    // a BFS ordered list.
                    modulesToUpdate.reverse();

                    // invalidate caches
                    client.dependenciesCache = dependenciesCache;
                    client.dependenciesModulesCache = dependenciesModulesCache;
                    client.shallowDependencies = shallowDependencies;

                    return resolutionResponse.copy({
                      dependencies: modulesToUpdate
                    });
                  });
              })
              .then((resolutionResponse) => {
                if (!client) {
                  return;
                }

                // make sure the file was modified is part of the bundle
                if (!client.shallowDependencies[filename]) {
                  return;
                }

                const httpServerAddress = httpServer.address();

                // Sanitize the value from the HTTP server
                let packagerHost = 'localhost';
                if (httpServer.address().address &&
                    httpServer.address().address !== '::' &&
                    httpServer.address().address !== '') {
                  packagerHost = httpServerAddress.address;
                }

                let packagerPort = httpServerAddress.port;

                return packagerServer.buildBundleForHMR({
                  entryFile: client.bundleEntry,
                  platform: client.platform,
                  resolutionResponse,
                }, packagerHost, packagerPort);
              })
              .then(bundle => {
                if (!client || !bundle || bundle.isEmpty()) {
                  return;
                }

                return JSON.stringify({
                  type: 'update',
                  body: {
                    modules: bundle.getModulesNamesAndCode(),
                    inverseDependencies: inverseDependenciesCache,
                    sourceURLs: bundle.getSourceURLs(),
                    sourceMappingURLs: bundle.getSourceMappingURLs(),
                  },
                });
              })
              .catch(error => {
                // send errors to the client instead of killing packager server
                let body;
                if (error.type === 'TransformError' ||
                    error.type === 'NotFoundError' ||
                    error.type === 'UnableToResolveError') {
                  body = {
                    type: error.type,
                    description: error.description,
                    filename: error.filename,
                    lineNumber: error.lineNumber,
                  };
                } else {
                  console.error(error.stack || error);
                  body = {
                    type: 'InternalError',
                    description: 'react-packager has encountered an internal error, ' +
                      'please check your terminal error output for more details',
                  };
                }

                return JSON.stringify({type: 'error', body});
              })
              .then(update => {
                if (!client || !update) {
                  return;
                }

                console.log(
                  '[Hot Module Replacement] Sending HMR update to client (' +
                  time() + ')'
                );
                client.ws.send(update);
              });
            },
            () => {
              // do nothing, file was removed
            },
          ).finally(() => {
            client.ws.send(JSON.stringify({type: 'update-done'}));
          });
        });

        client.ws.on('error', e => {
          console.error('[Hot Module Replacement] Unexpected error', e);
          disconnect();
        });

        client.ws.on('close', () => disconnect());
      })
    .done();
  });
}

function arrayEquals(arrayA, arrayB) {
  arrayA = arrayA || [];
  arrayB = arrayB || [];
  return (
    arrayA.length === arrayB.length &&
    arrayA.every((element, index) => {
      return element === arrayB[index];
    })
  );
}

function time() {
  const date = new Date();
  return `${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}:${date.getMilliseconds()}`;
}

module.exports = attachHMRServer;
<|endoftext|>


<commit_before>define([
	"dojo/_base/declare",
	"dojox/mvc",
	"dojox/mvc/StatefulModel",
	"dojo/data/ItemFileWriteStore"
], function(declare, mvc, StatefulModel, ItemFileWriteStore){
	/*=====
		declare = dojo.declare;
		mvc = dojox.mvc;
		StatefulModel = dojox.mvc.StatefulModel;
		ItemFileWriteStore = dojo.data.ItemFileWriteStore;
	=====*/

	return declare("dojox.mvc.tests.models.LoanWizardModel", [StatefulModel], {

		// data store for pie chart
		chartStore: new ItemFileWriteStore({ data: {
			"hierarchical" : false,
			"identifier"   : "id",
			"items" : [
			           { "id" : "mortgage", "x"  : 1, "y"	: 0 },
			           { "id" : "taxes", "x"  : 2, "y"	 : 0 },
			           { "id" : "otherhousing", "x"  : 3, "y"	: 0 }
			           ]
		}}),

		constructor: function (args) {
			// try to precompute address fields from the zipcode and country...
			mvc.bindInputs([this.Zip, this.Country], dojo.hitch(this, this._lookupAddrs));
			// simple dependence of percentages on input values and total
			mvc.bindInputs([this.Mortgage, this.Taxes, this.OtherHousing, this.BaseIncome, this.BonusIncome], dojo.hitch(this, this._recomputeTotalAndPercentages));

			mvc.bind(this.HousingPercent, "value", this.HousingPercent, "valid", dojo.hitch(this, this._isHousingLessThanOrEqualToThirtyThreePercent), true);

			mvc.bind(this.HousingPercent, "value", this.HousingPercent, "relevant", dojo.hitch(this, this._nonZeroRelevance), true);
			mvc.bind(this.TotalHousing, "value", this.TotalHousing, "relevant", dojo.hitch(this, this._nonZeroRelevance), true);

			this._recomputeTotalAndPercentages();  // get things going first time...
		},

		_lookupItem: function( dataSource, identity ) {
			var found_item;
			dataSource.fetchItemByIdentity( { "identity": identity,
				"onItem": function (item) { found_item = item; } } );
			return found_item;
		},

		_lookupAddrs: function() {
			if ( this.Zip.get("value") == null || isNaN(this.Zip.get("value"))) return;
			var pThis = this;
			var query = { "postalcode": this.Zip.get("value"), "country": this.Country.get("value") };
			var xhrArgs = {
					url: "zips/"+this.Zip.get("value")+".json",
					sync: true,
					content: query,
					preventCache: true,
					handleAs: "json",
					load: function(data, io) {
						pThis.City.set("value", data.postalcodes[0].placeName );
						pThis.County.set("value", data.postalcodes[0].adminName2 );
						pThis.State.set("value", data.postalcodes[0].adminCode1 );
						pThis.Zip.set("valid", true );
					},
					error: function (data) {
						// we couldn't find this country/zip combination...clear the fields and set validity=false
						pThis.City.set("value", "" );
						pThis.County.set("value", "" );
						pThis.State.set("value", "" );
						pThis.Zip.set("valid", false );
					}
			};
			//Call the synchronous xhrGet
			var deferred = dojo.xhrGet(xhrArgs);
		},

		_recomputeTotalAndPercentages: function() {
			var mortgage = parseInt(this.Mortgage.get("value"));
			var taxes = parseInt(this.Taxes.get("value"));
			var otherHousing = parseInt(this.OtherHousing.get("value"));
			var totalHousing = mortgage + taxes + otherHousing;

			var baseIncome = parseInt(this.BaseIncome.get("value"));
			var bonusIncome = parseInt(this.BonusIncome.get("value"));
			var totalIncome = baseIncome + bonusIncome;

			var housingPercentage = Math.round(totalHousing / totalIncome * 100);

			this.HousingPercent.set("value", housingPercentage);
			this.TotalHousing.set("value", totalHousing);
			this.TotalIncome.set("value", totalIncome);

			// map the values into the data source structure required for chart display as well...
			var mortgageItem = this._lookupItem(this.chartStore, "mortgage");
			var taxesItem = this._lookupItem(this.chartStore, "taxes");
			var otherItem = this._lookupItem(this.chartStore, "otherhousing");
			this.chartStore.setValue(mortgageItem, "y", mortgage);
			this.chartStore.setValue(taxesItem, "y", taxes);
			this.chartStore.setValue(otherItem, "y", otherHousing);
		},

		_isHousingLessThanOrEqualToThirtyThreePercent: function(newValue) {
			return newValue <= 33;
		},

		_nonZeroRelevance: function(newValue) {
			if ( newValue > 0 ) return true;
			else return false;
		}

	});
});
<commit_msg>dojox/mvc: remove doc parser hint, refs #13101 !strict<commit_after>define([
	"dojo/_base/declare",
	"dojox/mvc",
	"dojox/mvc/StatefulModel",
	"dojo/data/ItemFileWriteStore"
], function(declare, mvc, StatefulModel, ItemFileWriteStore){

	return declare("dojox.mvc.tests.models.LoanWizardModel", [StatefulModel], {

		// data store for pie chart
		chartStore: new ItemFileWriteStore({ data: {
			"hierarchical" : false,
			"identifier"   : "id",
			"items" : [
			           { "id" : "mortgage", "x"  : 1, "y"	: 0 },
			           { "id" : "taxes", "x"  : 2, "y"	 : 0 },
			           { "id" : "otherhousing", "x"  : 3, "y"	: 0 }
			           ]
		}}),

		constructor: function (args) {
			// try to precompute address fields from the zipcode and country...
			mvc.bindInputs([this.Zip, this.Country], dojo.hitch(this, this._lookupAddrs));
			// simple dependence of percentages on input values and total
			mvc.bindInputs([this.Mortgage, this.Taxes, this.OtherHousing, this.BaseIncome, this.BonusIncome], dojo.hitch(this, this._recomputeTotalAndPercentages));

			mvc.bind(this.HousingPercent, "value", this.HousingPercent, "valid", dojo.hitch(this, this._isHousingLessThanOrEqualToThirtyThreePercent), true);

			mvc.bind(this.HousingPercent, "value", this.HousingPercent, "relevant", dojo.hitch(this, this._nonZeroRelevance), true);
			mvc.bind(this.TotalHousing, "value", this.TotalHousing, "relevant", dojo.hitch(this, this._nonZeroRelevance), true);

			this._recomputeTotalAndPercentages();  // get things going first time...
		},

		_lookupItem: function( dataSource, identity ) {
			var found_item;
			dataSource.fetchItemByIdentity( { "identity": identity,
				"onItem": function (item) { found_item = item; } } );
			return found_item;
		},

		_lookupAddrs: function() {
			if ( this.Zip.get("value") == null || isNaN(this.Zip.get("value"))) return;
			var pThis = this;
			var query = { "postalcode": this.Zip.get("value"), "country": this.Country.get("value") };
			var xhrArgs = {
					url: "zips/"+this.Zip.get("value")+".json",
					sync: true,
					content: query,
					preventCache: true,
					handleAs: "json",
					load: function(data, io) {
						pThis.City.set("value", data.postalcodes[0].placeName );
						pThis.County.set("value", data.postalcodes[0].adminName2 );
						pThis.State.set("value", data.postalcodes[0].adminCode1 );
						pThis.Zip.set("valid", true );
					},
					error: function (data) {
						// we couldn't find this country/zip combination...clear the fields and set validity=false
						pThis.City.set("value", "" );
						pThis.County.set("value", "" );
						pThis.State.set("value", "" );
						pThis.Zip.set("valid", false );
					}
			};
			//Call the synchronous xhrGet
			var deferred = dojo.xhrGet(xhrArgs);
		},

		_recomputeTotalAndPercentages: function() {
			var mortgage = parseInt(this.Mortgage.get("value"));
			var taxes = parseInt(this.Taxes.get("value"));
			var otherHousing = parseInt(this.OtherHousing.get("value"));
			var totalHousing = mortgage + taxes + otherHousing;

			var baseIncome = parseInt(this.BaseIncome.get("value"));
			var bonusIncome = parseInt(this.BonusIncome.get("value"));
			var totalIncome = baseIncome + bonusIncome;

			var housingPercentage = Math.round(totalHousing / totalIncome * 100);

			this.HousingPercent.set("value", housingPercentage);
			this.TotalHousing.set("value", totalHousing);
			this.TotalIncome.set("value", totalIncome);

			// map the values into the data source structure required for chart display as well...
			var mortgageItem = this._lookupItem(this.chartStore, "mortgage");
			var taxesItem = this._lookupItem(this.chartStore, "taxes");
			var otherItem = this._lookupItem(this.chartStore, "otherhousing");
			this.chartStore.setValue(mortgageItem, "y", mortgage);
			this.chartStore.setValue(taxesItem, "y", taxes);
			this.chartStore.setValue(otherItem, "y", otherHousing);
		},

		_isHousingLessThanOrEqualToThirtyThreePercent: function(newValue) {
			return newValue <= 33;
		},

		_nonZeroRelevance: function(newValue) {
			if ( newValue > 0 ) return true;
			else return false;
		}

	});
});
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Mirantis, 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.
 **/

define([
  'intern!object',
  'intern/chai!assert',
  'tests/functional/helpers',
  'tests/functional/pages/common',
  'tests/functional/pages/modal'
], function(registerSuite, assert, helpers, Common, Modal) {
  'use strict';

  registerSuite(function() {
    var common,
      modal;

    return {
      name: 'Wizard Page',
      setup: function() {
        common = new Common(this.remote);
        modal = new Modal(this.remote);
        return this.remote
          .then(function() {
            return common.getIn();
          });
      },
      beforeEach: function() {
        var clusterName = common.pickRandomName('Temp');
        return this.remote
          .clickByCssSelector('.create-cluster')
          .then(function() {
            return modal.waitToOpen();
          })
          .setInputValue('[name=name]', clusterName);
      },
      afterEach: function() {
        return this.remote
          .clickByCssSelector('.close');
      },
      'Test steps manipulations': function() {
        return this.remote
          .assertElementExists('.wizard-step.active',
            'There is only one active and available step at the beginning')
          // Compute
          .pressKeys('\uE007')
          // Network
          .pressKeys('\uE007')
          // Storage
          .pressKeys('\uE007')
          // Additional Services
          .pressKeys('\uE007')
          // Finish
          .pressKeys('\uE007')
          .assertElementsExist('.wizard-step.available', 5, 'All steps are available at the end')
          .clickLinkByText('Compute')
          .clickByCssSelector('input[name=hypervisor\\:qemu]')
          .assertElementExists('.wizard-step.available',
            'Only one step is available after changing hypervisor');
      },
      'Test Compute pane: next button is disabled by when no hypervisor selected': function() {
        return this.remote
          .pressKeys('\uE007')
          .clickByCssSelector('input[name=hypervisor\\:vmware]')
          .clickByCssSelector('input[name=hypervisor\\:qemu]')
          .assertElementExists('.wizard-compute-pane .alert.empty-choice',
            'There should be the warning when no hypervisors selected')
          .assertElementExists('.next-pane-btn.disabled', 'Next button should be disabled');
      }
    };
  });
});
<commit_msg>Fix UI functional tests for Firefox 44<commit_after>/*
 * Copyright 2015 Mirantis, 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.
 **/

define([
  'intern!object',
  'intern/chai!assert',
  'tests/functional/helpers',
  'tests/functional/pages/common',
  'tests/functional/pages/modal'
], function(registerSuite, assert, helpers, Common, Modal) {
  'use strict';

  registerSuite(function() {
    var common,
      modal;

    return {
      name: 'Wizard Page',
      setup: function() {
        common = new Common(this.remote);
        modal = new Modal(this.remote);
        return this.remote
          .then(function() {
            return common.getIn();
          });
      },
      beforeEach: function() {
        var clusterName = common.pickRandomName('Temp');
        return this.remote
          .clickByCssSelector('.create-cluster')
          .then(function() {
            return modal.waitToOpen();
          })
          .setInputValue('[name=name]', clusterName);
      },
      afterEach: function() {
        return this.remote
          .then(function() {
            return modal.close();
          });
      },
      'Test steps manipulations': function() {
        return this.remote
          .assertElementExists('.wizard-step.active',
            'There is only one active and available step at the beginning')
          // Compute
          .pressKeys('\uE007')
          // Network
          .pressKeys('\uE007')
          // Storage
          .pressKeys('\uE007')
          // Additional Services
          .pressKeys('\uE007')
          // Finish
          .pressKeys('\uE007')
          .assertElementsExist('.wizard-step.available', 5, 'All steps are available at the end')
          .clickLinkByText('Compute')
          .clickByCssSelector('input[name=hypervisor\\:qemu]')
          .assertElementExists('.wizard-step.available',
            'Only one step is available after changing hypervisor');
      },
      'Test Compute pane: next button is disabled by when no hypervisor selected': function() {
        return this.remote
          .pressKeys('\uE007')
          .clickByCssSelector('input[name=hypervisor\\:vmware]')
          .clickByCssSelector('input[name=hypervisor\\:qemu]')
          .assertElementExists('.wizard-compute-pane .alert.empty-choice',
            'There should be the warning when no hypervisors selected')
          .assertElementExists('.next-pane-btn.disabled', 'Next button should be disabled');
      }
    };
  });
});
<|endoftext|>


<commit_before>var datePickers = {};

Vue.directive('datepicker', {
    bind: function(param) {
        var vm = this.vm;
        var key = this.expression;

        datePickers[key] = new Pikaday({
            field: $(this.el)[0],
            position: 'bottom',
            showTime: false,
            use24hour: true,
            maxDate: moment().toDate(),
            onSelect: function(date) {
                vm.$set(key, date);
                if (key == 'dateTimeFrom') {
                    datePickers['dateTimeTo'].setMinDate(date);
                }
            }
        });
    },
});

new Vue({
    el: '#routeApp',
    data: {
        stopSelected: null,
        dateTimeFrom: null,
        dateTimeTo: null,
        direction: null,
        stops: [],
    },
    methods: {
        updateChart: function() {
            $.ajax({
                method: 'POST',
                url: url_get_chart,
                data: {
                    datetime_from: this.dateTimeFrom.toISOString(),
                    datetime_to: this.dateTimeTo.toISOString(),
                    stop_selected: this.stopSelected,
                }
            }).done(function(response) {
                if (window.myChart){
                    window.myChart.destroy();
                }
                predictions = response.content.predictions;
                labels = [];
                data = [];
                for (var i =0; i < predictions.length; i++){
                    labels.push(predictions[i].posted_at);
                    data.push(predictions[i].prediction);
                }
                window.myChart = new Chart($(routeChart), {
                    type: 'line',
                    data: {
                        labels: labels,
                        datasets: [{
                            label: 'seconds',
                            data: data
                        }]
                    },
                    options:{
                        scales:{
                            yAxes:[{
                                ticks:{
                                    beginAtZero:true
                                }
                            }],
                            xAxes: [{
                                type: 'time',
                            }]
                        }
                    }
                });
            });
        },
        updateStops: function() {
            var vm = this;
            $.ajax({
                method: 'POST',
                url: url_get_stops_from_direction,
                data: { direction: this.direction },
            }).done(function(response) {
                vm.stopSelected = "";
                vm.stops = response.content.stops;
            });
        }
    },

});<commit_msg>Optimize UX for datepicker<commit_after>var datePickers = {};

Vue.directive('datepicker', {
    bind: function(param) {
        var vm = this.vm;
        var key = this.expression;

        datePickers[key] = new Pikaday({
            field: $(this.el)[0],
            position: 'bottom',
            showTime: false,
            use24hour: true,
            maxDate: moment().toDate(),
            onSelect: function(date) {
                vm.$set(key, date);
                if (key == 'dateTimeFrom') {
                    datePickers['dateTimeTo'].setMinDate(date);
                    datePickers['dateTimeTo'].gotoDate(date);
                    datePickers['dateTimeTo'].show();
                }
            }
        });
    },
});

new Vue({
    el: '#routeApp',
    data: {
        stopSelected: null,
        dateTimeFrom: null,
        dateTimeTo: null,
        direction: null,
        stops: [],
    },
    methods: {
        updateChart: function() {
            $.ajax({
                method: 'POST',
                url: url_get_chart,
                data: {
                    datetime_from: this.dateTimeFrom.toISOString(),
                    datetime_to: this.dateTimeTo.toISOString(),
                    stop_selected: this.stopSelected,
                }
            }).done(function(response) {
                if (window.myChart){
                    window.myChart.destroy();
                }
                predictions = response.content.predictions;
                labels = [];
                data = [];
                for (var i =0; i < predictions.length; i++){
                    labels.push(predictions[i].posted_at);
                    data.push(predictions[i].prediction);
                }
                window.myChart = new Chart($(routeChart), {
                    type: 'line',
                    data: {
                        labels: labels,
                        datasets: [{
                            label: 'seconds',
                            data: data
                        }]
                    },
                    options:{
                        scales:{
                            yAxes:[{
                                ticks:{
                                    beginAtZero:true
                                }
                            }],
                            xAxes: [{
                                type: 'time',
                            }]
                        }
                    }
                });
            });
        },
        updateStops: function() {
            var vm = this;
            $.ajax({
                method: 'POST',
                url: url_get_stops_from_direction,
                data: { direction: this.direction },
            }).done(function(response) {
                vm.stopSelected = "";
                vm.stops = response.content.stops;
            });
        }
    },

});<|endoftext|>


<commit_before>define(function(require, exports, module) {
"use strict";

var oop = require("../lib/oop");
var Mirror = require("../worker/mirror").Mirror;

var BxlWorker = exports.BxlWorker = function(sender) {
    Mirror.call(this, sender);
    this.setTimeout(250);
};

oop.inherits(BxlWorker, Mirror);

(function() {
    this.onUpdate = function() {

        var worker = this;

        var value = this.doc.getValue();
        var results = [];

        var xhr = new XMLHttpRequest();

        xhr.onreadystatechange = function() {
            if ((xhr.readyState == 4) && (xhr.status == 200)) {
                //console.log(xhr.response);
                results = xhr.response;

                var errors = [];

                for (var i = 0; results != null && i < results.length; i++) {
                    var error = results[i];
                    errors.push({
                        row: error.line - 1,
                        column: error.column,
                        text: btoa(error.message),
                        type: error.type
                    });
                }
                worker.sender.emit("lint", errors);
            }
        }

        var formData = new FormData();
        formData.append("blox-platform/generix/test/en/app/codeValidatorPage/codeValidator/sourceCode", value);

        var url = "http://teach.devel.lan:18080/blox-platform/generix/test/en/app/codeValidatorPage/codeValidator"
        xhr.open("POST", url, true);
        xhr.responseType = "json";

        xhr.send(formData);
    };
}).call(BxlWorker.prototype);

});
<commit_msg>Decoding of base64 in JS is atob(), not btoa().<commit_after>define(function(require, exports, module) {
"use strict";

var oop = require("../lib/oop");
var Mirror = require("../worker/mirror").Mirror;

var BxlWorker = exports.BxlWorker = function(sender) {
    Mirror.call(this, sender);
    this.setTimeout(250);
};

oop.inherits(BxlWorker, Mirror);

(function() {
    this.onUpdate = function() {

        var worker = this;

        var value = this.doc.getValue();
        var results = [];

        var xhr = new XMLHttpRequest();

        xhr.onreadystatechange = function() {
            if ((xhr.readyState == 4) && (xhr.status == 200)) {
                //console.log(xhr.response);
                results = xhr.response;

                var errors = [];

                for (var i = 0; results != null && i < results.length; i++) {
                    var error = results[i];
                    errors.push({
                        row: error.line - 1,
                        column: error.column,
                        text: atob(error.message),
                        type: error.type
                    });
                }
                worker.sender.emit("lint", errors);
            }
        }

        var formData = new FormData();
        formData.append("blox-platform/generix/test/en/app/codeValidatorPage/codeValidator/sourceCode", value);

        var url = "http://teach.devel.lan:18080/blox-platform/generix/test/en/app/codeValidatorPage/codeValidator"
        xhr.open("POST", url, true);
        xhr.responseType = "json";

        xhr.send(formData);
    };
}).call(BxlWorker.prototype);

});
<|endoftext|>


<commit_before>class BottomCtrl {
  constructor($scope, commands, demo, $window) {
    this.xScale = 1;

    this.updateLayerBackgroundGradientStyle($scope);

    $scope.$watch('xScale', () => {
      this.updateLayerBackgroundGradientStyle($scope);
    });

    $scope.$watch('selectedTheme', () => {
      this.updateLayerBackgroundGradientStyle($scope);
    });

    $scope.$watch('main.duration', () => this.updateXScale($scope));
    $window.addEventListener('resize', () => {
      $scope.$apply(() => this.updateXScale($scope));
    });

    this.$window = $window;

    this.loopStart = null;
    this.loopEnd = null;
    this.loopActive = false;
    commands.on('getCuePoint', callback => {
      callback(this.loopActive ? this.loopStart : null);
    });
    commands.on('setCuePoint', () => {
      var currentBEAN = BEAN_FOR_FRAME($scope.main.currentFrame);
      var currentQuantizedFrame = FRAME_FOR_BEAN(currentBEAN - currentBEAN % PROJECT.music.subdivision);
      if (this.loopStart === null) {
        this.loopStart = currentQuantizedFrame;
      } else if (this.loopEnd === null) {
        if (this.loopStart > $scope.main.currentFrame) {
          this.loopEnd = currentQuantizedFrame;
          this.loopStart = currentQuantizedFrame;
        } else {
          this.loopEnd = currentQuantizedFrame;
        }
        this.loopActive = true;
      } else {
        this.loopStart = null;
        this.loopEnd = null;
        this.loopActive = false;
      }
    });

    commands.on('multiplyLoopLengthBy', amount => {
      if (this.loopEnd === undefined || this.loopStart === undefined) {
        return;
      }

      var clampedAmount = Math.max(0, amount),
        loopLength = this.loopEnd - this.loopStart,
        newLoopLength = Math.max(1, loopLength * clampedAmount);

      this.loopEnd = this.loopStart + newLoopLength;
    });

    $scope.$watch('main.currentFrame', nextFrame => {
      if (this.loopActive && nextFrame >= this.loopEnd) {
        demo.jumpToFrame(this.loopStart);
      }
    });
  }

  getClickOffset($event) {
    var target = $('.layers-bar-container')[0];
    var rect = target.getBoundingClientRect();
    var offsetX = ($event.clientX - rect.left) | 0;
    var offsetY = ($event.clientY - rect.top) | 0;
    return {x: offsetX, y: offsetY};
  }

  musicLayerClick($event) {
    demo.jumpToFrame(this.getClickOffset($event).x / this.xScale | 0);
  }

  updateLayerBackgroundGradientStyle($scope) {
    if(!$scope.main.selectedTheme) {
      return;
    }
    var wellBgColor;
    var wellBgColorAlt;
    var wellBgBorderColor;
    if($scope.main.selectedTheme == 'dark') {
      wellBgColor = 'rgb(52, 68, 78)';
      wellBgColorAlt = 'rgb(46, 62, 72)';
      wellBgBorderColor = 'rgb(10, 26, 36)';
    } else if($scope.main.selectedTheme == 'light') {
      wellBgColor = '#efefef';
      wellBgColorAlt = '#dfdfdf';
      wellBgBorderColor = '#ababab';
    }

    var beatsPerSecond = PROJECT.music.bpm / 60;
    var secondsPerBeat = 1 / beatsPerSecond;
    var framesPerSecond = 60;
    var framesPerBeat = secondsPerBeat * framesPerSecond;
    var beatWidthInPixels = framesPerBeat * this.xScale;
    var devicePixelRatio = window.devicePixelRatio || 1;

    var entirePatternRepeatCount = 6;
    var backgroundWidth = beatWidthInPixels * 8 * devicePixelRatio;
    var repeatedBackgroundWidth = backgroundWidth * entirePatternRepeatCount;

    var backgroundCanvas = document.createElement('canvas');
    var ctx = backgroundCanvas.getContext('2d');
    backgroundCanvas.width = repeatedBackgroundWidth;
    backgroundCanvas.height = 1;
    for(var i = 0; i < entirePatternRepeatCount; i++) {
      var entirePatternRepeatOffset = i * backgroundWidth;
      ctx.fillStyle = wellBgColor;
      ctx.fillRect(entirePatternRepeatOffset, 0,
                   backgroundWidth, 1);
      ctx.fillStyle = wellBgColorAlt;
      ctx.fillRect(entirePatternRepeatOffset + backgroundWidth / 2, 0,
                   backgroundWidth, 1);
      ctx.fillStyle = wellBgBorderColor;
      for(var j = 0; j < 8; j++) {
        ctx.fillRect(entirePatternRepeatOffset + j * backgroundWidth / 8, 0,
                     1, 1);
      }
    }
    this.backgroundImageDataUrl = backgroundCanvas.toDataURL();
    this.backgroundWidth = repeatedBackgroundWidth / devicePixelRatio;
  }

  updateXScale($scope) {
    var rect = $('body')[0].getBoundingClientRect();
    this.xScale = rect.width / $scope.main.duration;
  }
}

module.exports = BottomCtrl;
<commit_msg>Remove old layer panel background<commit_after>class BottomCtrl {
  constructor($scope, commands, demo, $window) {
    this.xScale = 1;

    $scope.$watch('main.duration', () => this.updateXScale($scope));
    $window.addEventListener('resize', () => {
      $scope.$apply(() => this.updateXScale($scope));
    });

    this.$window = $window;

    this.loopStart = null;
    this.loopEnd = null;
    this.loopActive = false;
    commands.on('getCuePoint', callback => {
      callback(this.loopActive ? this.loopStart : null);
    });
    commands.on('setCuePoint', () => {
      var currentBEAN = BEAN_FOR_FRAME($scope.main.currentFrame);
      var currentQuantizedFrame = FRAME_FOR_BEAN(currentBEAN - currentBEAN % PROJECT.music.subdivision);
      if (this.loopStart === null) {
        this.loopStart = currentQuantizedFrame;
      } else if (this.loopEnd === null) {
        if (this.loopStart > $scope.main.currentFrame) {
          this.loopEnd = currentQuantizedFrame;
          this.loopStart = currentQuantizedFrame;
        } else {
          this.loopEnd = currentQuantizedFrame;
        }
        this.loopActive = true;
      } else {
        this.loopStart = null;
        this.loopEnd = null;
        this.loopActive = false;
      }
    });

    commands.on('multiplyLoopLengthBy', amount => {
      if (this.loopEnd === undefined || this.loopStart === undefined) {
        return;
      }

      var clampedAmount = Math.max(0, amount),
        loopLength = this.loopEnd - this.loopStart,
        newLoopLength = Math.max(1, loopLength * clampedAmount);

      this.loopEnd = this.loopStart + newLoopLength;
    });

    $scope.$watch('main.currentFrame', nextFrame => {
      if (this.loopActive && nextFrame >= this.loopEnd) {
        demo.jumpToFrame(this.loopStart);
      }
    });
  }

  getClickOffset($event) {
    var target = $('.layers-bar-container')[0];
    var rect = target.getBoundingClientRect();
    var offsetX = ($event.clientX - rect.left) | 0;
    var offsetY = ($event.clientY - rect.top) | 0;
    return {x: offsetX, y: offsetY};
  }

  musicLayerClick($event) {
    demo.jumpToFrame(this.getClickOffset($event).x / this.xScale | 0);
  }

  updateXScale($scope) {
    var rect = $('body')[0].getBoundingClientRect();
    this.xScale = rect.width / $scope.main.duration;
  }
}

module.exports = BottomCtrl;
<|endoftext|>


<commit_before>const keymage = require('keymage');

function menubar($window, commands, ninrc) {
  const menu = [
    {
      name: 'File',
      items: [
        {
          name: 'Exit'
        }
      ]
    },
    {
      name: 'Playback',
      items: [
        {
          name: 'Rewind to start',
          action: 'rewindToStart',
          defaultKeybind: 'shift-h',
          invoke: () => commands.jumpToFrame(0)
        },
        {
          name: 'Rewind one second',
          action: 'rewindOneSecond',
          defaultKeybind: 'k',
          invoke: () => commands.jog(-60)
        },
        {
          name: 'Forward one second',
          action: 'forwardOneSecond',
          defaultKeybind: 'j',
          invoke: () => commands.jog(60)
        },
        {
          name: 'Rewind 10 seconds',
          action: 'rewindTenSeconds',
          defaultKeybind: 'h',
          invoke: () => commands.jog(-60 * 10)
        },
        {
          name: 'Forward 10 seconds',
          action: 'forwardTenSeconds',
          defaultKeybind: 'l',
          invoke: () => commands.jog(60 * 10)
        },
        {
          name: 'Rewind one frame',
          action: 'rewindOneFrame',
          defaultKeybind: 'shift-k',
          invoke: () => commands.jog(-1)
        },
        {
          name: 'Forward one frame',
          action: 'forwardOneFrame',
          defaultKeybind: 'shift-j',
          invoke: () => commands.jog(1)
        },
        {
          name: '-'
        },
        {
          name: '0.25x playback rate',
          action: 'quarterPlaybackRate',
          defaultKeybind: '6',
          invoke: () => commands.setPlaybackRate(0.25)
        },
        {
          name: '0.5x playback rate',
          action: 'halfPlaybackRate',
          defaultKeybind: '7',
          invoke: () => commands.setPlaybackRate(0.5)
        },
        {
          name: '2x playback rate',
          action: 'doublePlaybackRate',
          defaultKeybind: '8',
          invoke: () => commands.setPlaybackRate(2)
        },
        {
          name: '4x playback rate',
          action: 'quadruplePlaybackRate',
          defaultKeybind: '9',
          invoke: () => commands.setPlaybackRate(4)
        },
        {
          name: '1x playback rate',
          action: 'resetPlaybackRate',
          defaultKeybind: '0',
          invoke: () => commands.setPlaybackRate(1)
        },
        {
          name: '-'
        },
        {
          name: 'Set cue point',
          defaultKeybind: 'g',
          action: 'setCuePoint',
          invoke: () => commands.setCuePoint()
        },
        {
          name: 'Halve loop length',
          action: 'halveLoopLength',
          defaultKeybind: 't',
          invoke: () => commands.multiplyLoopLengthBy(0.5)
        },
        {
          name: 'Double loop length',
          action: 'doubleLoopLength',
          defaultKeybind: 'y',
          invoke: () => commands.multiplyLoopLengthBy(2.0)
        },
        {
          name: '-'
        },
        {
          name: 'Toggle fullscreen',
          action: 'toggleFullscreen',
          defaultKeybind: 'f',
          invoke: () => commands.toggleFullscreen()
        },
        {
          name: 'Mute',
          action: 'toggleMute',
          defaultKeybind: 'm',
          invoke: () => commands.toggleMusic()
        },
        {
          name: 'Play/pause',
          action: 'togglePlayPause',
          defaultKeybind: 'space',
          charCode: '32',
          invoke: () => commands.playPause()
        }
      ]
    },
    {
      name: 'Render',
      items: [
        {
          name: 'Start rendering',
          action: 'startRendering',
          invoke: () => commands.startRendering()
        },
        {
          name: 'Stop rendering',
          action: 'stopRendering',
          invoke: () => commands.stopRendering()
        }
      ]
    },
    {
      name: 'Generate',
      items: [
        {
          name: 'Node',
          action: 'generateNode',
          invoke: () =>  {
            commands.pause();
            const nodeName = $window.prompt("Enter a name for the node:");
            commands.generate('node', nodeName);
          }
        }
      ]
    },
    {
      name: 'Theme',
      items: [
        {
          name: 'Dark',
          action: 'activateDarkTheme',
          invoke: () => commands.selectTheme('dark')
        },
        {
          name: 'Light',
          action: 'activateLightTheme',
          invoke: () => commands.selectTheme('light')
        }
      ]
    },
    {
      name: 'Help',
      items: [
        {
          name: 'Online wiki',
          action: 'help',
          invoke: () => $window.open('https://github.com/ninjadev/nin/wiki')
        }
      ]
    }
  ];

  return {
    restrict: 'A',
    templateUrl: 'views/menubar.html',
    link: function($scope, element, attrs) {
      menu.forEach(category => {
        category.items.forEach(item => {
          item.keybind =
            ninrc.keybinds && ninrc.keybinds[item.action]
            || item.defaultKeybind;
          if (item.keybind) {
            keymage(item.keybind, item.invoke);
          }
        });
      });

      $scope.menu = menu;

      var oldTopMenuOpen = false;
      $scope.menuState = {open: false, focus: ''};
      $window.document.querySelector('body').addEventListener('click', function() {
        $scope.$apply(function() {
          if(oldTopMenuOpen) {
            $scope.menuState.open = false;
            oldTopMenuOpen = false;
          } else {
            oldTopMenuOpen = true;
          }
        });
      });

    }
  };
}

module.exports = menubar;
<commit_msg>Swap j and k keyboard shortcuts<commit_after>const keymage = require('keymage');

function menubar($window, commands, ninrc) {
  const menu = [
    {
      name: 'File',
      items: [
        {
          name: 'Exit'
        }
      ]
    },
    {
      name: 'Playback',
      items: [
        {
          name: 'Rewind to start',
          action: 'rewindToStart',
          defaultKeybind: 'shift-h',
          invoke: () => commands.jumpToFrame(0)
        },
        {
          name: 'Rewind one second',
          action: 'rewindOneSecond',
          defaultKeybind: 'j',
          invoke: () => commands.jog(-60)
        },
        {
          name: 'Forward one second',
          action: 'forwardOneSecond',
          defaultKeybind: 'k',
          invoke: () => commands.jog(60)
        },
        {
          name: 'Rewind 10 seconds',
          action: 'rewindTenSeconds',
          defaultKeybind: 'h',
          invoke: () => commands.jog(-60 * 10)
        },
        {
          name: 'Forward 10 seconds',
          action: 'forwardTenSeconds',
          defaultKeybind: 'l',
          invoke: () => commands.jog(60 * 10)
        },
        {
          name: 'Rewind one frame',
          action: 'rewindOneFrame',
          defaultKeybind: 'shift-k',
          invoke: () => commands.jog(-1)
        },
        {
          name: 'Forward one frame',
          action: 'forwardOneFrame',
          defaultKeybind: 'shift-j',
          invoke: () => commands.jog(1)
        },
        {
          name: '-'
        },
        {
          name: '0.25x playback rate',
          action: 'quarterPlaybackRate',
          defaultKeybind: '6',
          invoke: () => commands.setPlaybackRate(0.25)
        },
        {
          name: '0.5x playback rate',
          action: 'halfPlaybackRate',
          defaultKeybind: '7',
          invoke: () => commands.setPlaybackRate(0.5)
        },
        {
          name: '2x playback rate',
          action: 'doublePlaybackRate',
          defaultKeybind: '8',
          invoke: () => commands.setPlaybackRate(2)
        },
        {
          name: '4x playback rate',
          action: 'quadruplePlaybackRate',
          defaultKeybind: '9',
          invoke: () => commands.setPlaybackRate(4)
        },
        {
          name: '1x playback rate',
          action: 'resetPlaybackRate',
          defaultKeybind: '0',
          invoke: () => commands.setPlaybackRate(1)
        },
        {
          name: '-'
        },
        {
          name: 'Set cue point',
          defaultKeybind: 'g',
          action: 'setCuePoint',
          invoke: () => commands.setCuePoint()
        },
        {
          name: 'Halve loop length',
          action: 'halveLoopLength',
          defaultKeybind: 't',
          invoke: () => commands.multiplyLoopLengthBy(0.5)
        },
        {
          name: 'Double loop length',
          action: 'doubleLoopLength',
          defaultKeybind: 'y',
          invoke: () => commands.multiplyLoopLengthBy(2.0)
        },
        {
          name: '-'
        },
        {
          name: 'Toggle fullscreen',
          action: 'toggleFullscreen',
          defaultKeybind: 'f',
          invoke: () => commands.toggleFullscreen()
        },
        {
          name: 'Mute',
          action: 'toggleMute',
          defaultKeybind: 'm',
          invoke: () => commands.toggleMusic()
        },
        {
          name: 'Play/pause',
          action: 'togglePlayPause',
          defaultKeybind: 'space',
          charCode: '32',
          invoke: () => commands.playPause()
        }
      ]
    },
    {
      name: 'Render',
      items: [
        {
          name: 'Start rendering',
          action: 'startRendering',
          invoke: () => commands.startRendering()
        },
        {
          name: 'Stop rendering',
          action: 'stopRendering',
          invoke: () => commands.stopRendering()
        }
      ]
    },
    {
      name: 'Generate',
      items: [
        {
          name: 'Node',
          action: 'generateNode',
          invoke: () =>  {
            commands.pause();
            const nodeName = $window.prompt("Enter a name for the node:");
            commands.generate('node', nodeName);
          }
        }
      ]
    },
    {
      name: 'Theme',
      items: [
        {
          name: 'Dark',
          action: 'activateDarkTheme',
          invoke: () => commands.selectTheme('dark')
        },
        {
          name: 'Light',
          action: 'activateLightTheme',
          invoke: () => commands.selectTheme('light')
        }
      ]
    },
    {
      name: 'Help',
      items: [
        {
          name: 'Online wiki',
          action: 'help',
          invoke: () => $window.open('https://github.com/ninjadev/nin/wiki')
        }
      ]
    }
  ];

  return {
    restrict: 'A',
    templateUrl: 'views/menubar.html',
    link: function($scope, element, attrs) {
      menu.forEach(category => {
        category.items.forEach(item => {
          item.keybind =
            ninrc.keybinds && ninrc.keybinds[item.action]
            || item.defaultKeybind;
          if (item.keybind) {
            keymage(item.keybind, item.invoke);
          }
        });
      });

      $scope.menu = menu;

      var oldTopMenuOpen = false;
      $scope.menuState = {open: false, focus: ''};
      $window.document.querySelector('body').addEventListener('click', function() {
        $scope.$apply(function() {
          if(oldTopMenuOpen) {
            $scope.menuState.open = false;
            oldTopMenuOpen = false;
          } else {
            oldTopMenuOpen = true;
          }
        });
      });

    }
  };
}

module.exports = menubar;
<|endoftext|>


<commit_before>
export default class AtomRipTimerView {
  constructor(serializedState) {
    this.element = document.createElement('label')
    this.element.classList.add('timer')

    var hour = document.createElement('span')
    hour.textContent = '00'

    var minute = document.createElement('span')
    minute.textContent = '00'

    var second = document.createElement('span')
    second.textContent = '00'

    const seperator = document.createElemet('span')
    seperator.textContent = ":"

    this.element.appendChild(hour)
    this.element.appendChild(seperator)

  }

  function setTime() {
           ++totalSeconds;
           secondsLabel.innerHTML = pad(totalSeconds%60);
           minutesLabel.innerHTML = pad(parseInt(totalSeconds/60));
       }

       function pad(val)
       {
           var valString = val + "";
           if(valString.length < 2)
           {
               return "0" + valString;
           }
           else
           {
               return valString;
           }
       }
}
<commit_msg>timer document<commit_after>
export default class AtomRipTimerView {
  totalSeconds: 0

  constructor(serializedState) {
    this.element = document.createElement('label')
    this.element.classList.add('timer')

    this.hour = document.createElement('span')
    this.hour.textContent = '00'

    this.minute = document.createElement('span')
    this.minute.textContent = '00'

    this.second = document.createElement('span')
    this.second.textContent = '00'

    const seperator = document.createElemet('span')
    seperator.textContent = ":"

    this.element.appendChild(hour)
    this.element.appendChild(seperator)

  }

  setTime() {
    this.totalSeconds++
    this.second.textContent = pad(totalSeconds % 60)
    this.minute.textContent = pad(Math.floor(totalSeconds / 60))
  }

  pad (val) {
    const str = val.toString()

    if(str.length < 2) return '0' + str;
    else return str
  }
}
<|endoftext|>