<commit_before>'use strict';

var KinnectedAppControllers = angular.module('KinnectedControllers',['KinnectedServices']);

angular.module('KinnectedApp').controller('IndexController',
  ['$scope', '$state', 'AuthService','Flash',
  function ($scope, $state, AuthService,Flash) {

    $scope.login = function () {

      // initial values
      $scope.error = false;
      $scope.disabled = true;

      // call login from service
      AuthService.login($scope.loginForm.email, $scope.loginForm.password)
        // handle success
        .then(function () {
          $state.go('profile.home');
          $scope.disabled = false;
          $scope.loginForm = {};
        })
        // handle error
        .catch(function () {
          $scope.error = true;
          var message = 'Invalid Username or Password bro :)';
          console.log("testing");
          Flash.create('danger', message);
          $scope.disabled = false;
          $scope.loginForm = {};
        });

    };

}]);

angular.module('KinnectedApp').controller('profileSearchController',
  ['$scope', '$state', 'AuthService','$http','Flash',
  function ($scope, $state, AuthService,$http,Flash) {
      var getpeople = function(){
        $http({
          url:'/api/users/all',
          method:'GET',})
        .success(function(data){
          $scope.users = data.data;
          console.log($scope.users);
        })
        .error(function(data){
          console.log("messed up for the search");
        })
      }
  }]);

angular.module('KinnectedApp').controller('profileController',
  ['$scope', '$state', 'AuthService','$http','Flash',
  function ($scope, $state, AuthService,$http,Flash) {

    $scope.logout = function () {

      // call logout from service
      AuthService.logout()
        .then(function () {
          $state.go('home');
        });

    };
    var firstTime = function () {
        var message = 'Welcome! Fill in your profile information and get that job!.';
        Flash.create('info', message);
    };

    $scope.updateProfile = function(){
      $http({
        url:'/api/users/update',
        method:'GET',
        params:$scope.userData})
        .success(function(data,status){
          console.log("successful update");
          $state.go('profile.home');
        })
        .error(function(data){
          console.log("failed update");
        })
    }

    var init = function(){
       AuthService.getUserData().then(function(data){
          $scope.userData = data.data;

          //have a filler if they havn't updated their profile yet
          if($scope.userData.major == null){
            $scope.userData.major = "Fill in your major!";
          }
          if($scope.userData.gradyear == null){
            $scope.userData.gradyear = "Fill in your Grad Year!";
          }
       })
    }
    firstTime()
    init()

}]);

angular.module('KinnectedApp').controller('logoutController',
  ['$scope', '$state', 'AuthService',
  function ($scope, $state, AuthService) {

    $scope.logout = function () {

      // call logout from service
      AuthService.logout()
        .then(function () {
          $state.go('home');
        });

    };

}]);

angular.module('KinnectedApp').controller('registerController',
  ['$scope', '$location', 'AuthService','$state',
  function ($scope, $location, AuthService,$state) {

    $scope.register = function () {

      // initial values
      $scope.error = false;
      $scope.disabled = true;

      // call register from service
      AuthService.register($scope.registerForm.first_name,
                           $scope.registerForm.last_name,
                           $scope.registerForm.email,
                           $scope.registerForm.password)
        // handle success
        .then(function () {
          $scope.disabled = false;
          $scope.registerForm = {};
          $state.go('profile.home');
        })
        // handle error
        .catch(function () {
          $scope.error = true;
          $scope.errorMessage = "Something went wrong!";
          $scope.disabled = false;
          $scope.registerForm = {};
        });

    };

}]);<commit_msg>removed init messages everytime<commit_after>'use strict';

var KinnectedAppControllers = angular.module('KinnectedControllers',['KinnectedServices']);

angular.module('KinnectedApp').controller('IndexController',
  ['$scope', '$state', 'AuthService','Flash',
  function ($scope, $state, AuthService,Flash) {

    $scope.login = function () {

      // initial values
      $scope.error = false;
      $scope.disabled = true;

      // call login from service
      AuthService.login($scope.loginForm.email, $scope.loginForm.password)
        // handle success
        .then(function () {
          $state.go('profile.home');
          $scope.disabled = false;
          $scope.loginForm = {};
        })
        // handle error
        .catch(function () {
          $scope.error = true;
          var message = 'Invalid Username or Password bro :)';
          console.log("testing");
          Flash.create('danger', message);
          $scope.disabled = false;
          $scope.loginForm = {};
        });

    };

}]);

angular.module('KinnectedApp').controller('profileSearchController',
  ['$scope', '$state', 'AuthService','$http','Flash',
  function ($scope, $state, AuthService,$http,Flash) {
      var getpeople = function(){
        $http({
          url:'/api/users/all',
          method:'GET',})
        .success(function(data){
          $scope.users = data.data;
          console.log($scope.users);
        })
        .error(function(data){
          console.log("messed up for the search");
        })
      }
  }]);

angular.module('KinnectedApp').controller('profileController',
  ['$scope', '$state', 'AuthService','$http','Flash',
  function ($scope, $state, AuthService,$http,Flash) {

    $scope.logout = function () {

      // call logout from service
      AuthService.logout()
        .then(function () {
          $state.go('home');
        });

    };
    var firstTime = function () {
        var message = 'Welcome! Fill in your profile information and get that job!.';
        Flash.create('info', message);
    };

    $scope.updateProfile = function(){
      $http({
        url:'/api/users/update',
        method:'GET',
        params:$scope.userData})
        .success(function(data,status){
          console.log("successful update");
          $state.go('profile.home');
        })
        .error(function(data){
          console.log("failed update");
        })
    }

    var init = function(){
       AuthService.getUserData().then(function(data){
          $scope.userData = data.data;

          //have a filler if they havn't updated their profile yet
          if($scope.userData.major == null){
            $scope.userData.major = "Fill in your major!";
          }
          if($scope.userData.gradyear == null){
            $scope.userData.gradyear = "Fill in your Grad Year!";
          }
       })
    }

    init()

}]);

angular.module('KinnectedApp').controller('logoutController',
  ['$scope', '$state', 'AuthService',
  function ($scope, $state, AuthService) {

    $scope.logout = function () {

      // call logout from service
      AuthService.logout()
        .then(function () {
          $state.go('home');
        });

    };

}]);

angular.module('KinnectedApp').controller('registerController',
  ['$scope', '$location', 'AuthService','$state',
  function ($scope, $location, AuthService,$state) {

    $scope.register = function () {

      // initial values
      $scope.error = false;
      $scope.disabled = true;

      // call register from service
      AuthService.register($scope.registerForm.first_name,
                           $scope.registerForm.last_name,
                           $scope.registerForm.email,
                           $scope.registerForm.password)
        // handle success
        .then(function () {
          $scope.disabled = false;
          $scope.registerForm = {};
          $state.go('profile.home');
        })
        // handle error
        .catch(function () {
          $scope.error = true;
          $scope.errorMessage = "Something went wrong!";
          $scope.disabled = false;
          $scope.registerForm = {};
        });

    };

}]);<|endoftext|>


<commit_before>
var app = angular.module('app', []);

app.controller('appController', ['$scope', '$http', function($scope, $http) {

  $http.get("https://api-equite-parole.github.io/api/2017-02-01--2017-02-26/chaines-generalistes.json").then(function(result) {

    //console.log(result);

    var content = [];
    angular.forEach(result.data, function(value, key) {
      content.push({
        "label": key,
        "value": value.total_temps_antenne.secondes,
        "color": "#2484c1"
      });
    });

    var data = {
      "sortOrder": "value-desc",
      "content": content
    };

    var pie = new d3pie("pieChart", {
      "header": {
        "title": {
          "text": "Temps de parole du 1er Février 2017 au 26 Février 2017",
          "fontSize": 24,
          "font": "open sans"
        },
        "subtitle": {
          "text": "Equité de temps de parole pour les candidats à la présidentielle 2017",
          "color": "#999999",
          "fontSize": 12,
          "font": "open sans"
        },
        "titleSubtitlePadding": 9
      },
      "footer": {
        "color": "#999999",
        "fontSize": 10,
        "font": "open sans",
        "location": "bottom-left"
      },
      "size": {
        "canvasWidth":900,
        "pieOuterRadius": "90%"
      },
      "data": data,
      "labels": {
        "outer": {
          "pieDistance": 32
        },
        "inner": {
          "hideWhenLessThanPercentage": 3
        },
        "mainLabel": {
          "fontSize": 11
        },
        "percentage": {
          "color": "#ffffff",
          "decimalPlaces": 0
        },
        "value": {
          "color": "#adadad",
          "fontSize": 11
        },
        "lines": {
          "enabled": true
        },
        "truncation": {
          "enabled": true
        }
      },
      "effects": {
        "pullOutSegmentOnClick": {
          "effect": "linear",
          "speed": 400,
          "size": 8
        }
      },
      "misc": {
        "gradient": {
          "enabled": true,
          "percentage": 100
        }
      }
    });

  });

}]);
<commit_msg>publish<commit_after>
var app = angular.module('app', []);

app.controller('appController', ['$scope', '$http', function($scope, $http) {

  $http.get("https://api-equite-parole.github.io/api/2017-02-01--2017-02-26/chaines-generalistes.json").then(function(result) {

    //console.log(result);

    var content = [];
    angular.forEach(result.data, function(value, key) {
      content.push({
        "label": key,
        "value": value.total_temps_antenne.secondes,
        "color": "#2484c1"
      });
    });

    var data = {
      "sortOrder": "value-desc",
      "content": content
    };

    var pie = new d3pie("pieChart", {
      "header": {
        "title": {
          "text": "Temps d'antenne du 1er Février 2017 au 26 Février 2017",
          "fontSize": 24,
          "font": "open sans"
        },
        "subtitle": {
          "text": "Equité de temps de parole pour les candidats à la présidentielle 2017",
          "color": "#999999",
          "fontSize": 12,
          "font": "open sans"
        },
        "titleSubtitlePadding": 9
      },
      "footer": {
        "color": "#999999",
        "fontSize": 10,
        "font": "open sans",
        "location": "bottom-left"
      },
      "size": {
        "canvasWidth":900,
        "pieOuterRadius": "90%"
      },
      "data": data,
      "labels": {
        "outer": {
          "pieDistance": 32
        },
        "inner": {
          "hideWhenLessThanPercentage": 3
        },
        "mainLabel": {
          "fontSize": 11
        },
        "percentage": {
          "color": "#ffffff",
          "decimalPlaces": 0
        },
        "value": {
          "color": "#adadad",
          "fontSize": 11
        },
        "lines": {
          "enabled": true
        },
        "truncation": {
          "enabled": true
        }
      },
      "effects": {
        "pullOutSegmentOnClick": {
          "effect": "linear",
          "speed": 400,
          "size": 8
        }
      },
      "misc": {
        "gradient": {
          "enabled": true,
          "percentage": 100
        }
      }
    });

  });

}]);
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 Glyptodon LLC
 *
 * 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.
 */

/**
 * A directive which displays the contents of a filesystem received through the
 * Guacamole client.
 */
angular.module('client').directive('guacFileBrowser', [function guacFileBrowser() {

    return {
        restrict: 'E',
        replace: true,
        scope: {

            /**
             * The client whose file transfers should be managed by this
             * directive.
             *
             * @type ManagedClient
             */
            client : '=',

            /**
             * @type ManagedFilesystem
             */
            filesystem : '='

        },

        templateUrl: 'app/client/templates/guacFileBrowser.html',
        controller: ['$scope', '$element', '$injector', function guacFileBrowserController($scope, $element, $injector) {

            // Required types
            var ManagedFilesystem = $injector.get('ManagedFilesystem');

            // Required services
            var $interpolate     = $injector.get('$interpolate');
            var $templateRequest = $injector.get('$templateRequest');

            /**
             * The jQuery-wrapped element representing the contents of the
             * current directory within the file browser.
             *
             * @type Element[]
             */
            var currentDirectoryContents = $element.find('.current-directory-contents');

            /**
             * Statically-cached template HTML used to render each file within
             * a directory. Once available, this will be used through
             * createFileElement() to generate the DOM elements which make up
             * a directory listing.
             *
             * @type String
             */
            var fileTemplate = null;

            /**
             * Returns whether the given file is a normal file.
             *
             * @param {ManagedFilesystem.File} file
             *     The file to test.
             *
             * @returns {Boolean}
             *     true if the given file is a normal file, false otherwise.
             */
            $scope.isNormalFile = function isNormalFile(file) {
                return file.type === ManagedFilesystem.File.Type.NORMAL;
            };

            /**
             * Returns whether the given file is a directory.
             *
             * @param {ManagedFilesystem.File} file
             *     The file to test.
             *
             * @returns {Boolean}
             *     true if the given file is a directory, false otherwise.
             */
            $scope.isDirectory = function isDirectory(file) {
                return file.type === ManagedFilesystem.File.Type.DIRECTORY;
            };

            /**
             * Changes the currently-displayed directory to the given
             * directory.
             *
             * @param {ManagedFilesystem.File} file
             *     The directory to change to.
             */
            $scope.changeDirectory = function changeDirectory(file) {
                ManagedFilesystem.changeDirectory($scope.filesystem, file);
            };

            /**
             * Initiates a download of the given file. The progress of the
             * download can be observed through guacFileTransferManager.
             *
             * @param {ManagedFilesystem.File} file
             *     The file to download.
             */
            $scope.downloadFile = function downloadFile(file) {
                ManagedFilesystem.downloadFile($scope.client, $scope.filesystem, file.streamName);
            };

            /**
             * Creates a new element representing the given file and properly
             * handling user events, bypassing the overhead incurred through
             * use of ngRepeat and related techniques.
             *
             * Note that this function depends on the availability of the
             * statically-cached fileTemplate.
             *
             * @param {ManagedFilesystem.File} file
             *     The file to generate an element for.
             *
             * @returns {Element[]}
             *     A jQuery-wrapped array containing a single DOM element
             *     representing the given file.
             */
            var createFileElement = function createFileElement(file) {

                // Create from internal template
                var element = angular.element($interpolate(fileTemplate)(file));

                // Double-clicking on unknown file types will do nothing
                var fileAction = function doNothing() {};

                // Change current directory when directories are clicked
                if ($scope.isDirectory(file)) {
                    element.addClass('directory');
                    fileAction = function changeDirectory() {
                        $scope.changeDirectory(file);
                    };
                }

                // Initiate downloads when normal files are clicked
                else if ($scope.isNormalFile(file)) {
                    element.addClass('normal-file');
                    fileAction = function downloadFile() {
                        $scope.downloadFile(file);
                    };
                }

                // Mark file as focused upon click
                element.on('click', function focusFile(e) {

                    // Fire file-specific action if already focused
                    if (element.hasClass('focused')) {
                        fileAction();
                        element.removeClass('focused');
                    }

                    // Otherwise mark as focused
                    else {
                        element.parent().children().removeClass('focused');
                        element.addClass('focused');
                    }

                    // Do not allow default action
                    e.preventDefault();
                    e.stopPropagation();

                });

                // Prevent text selection during navigation
                element.on('selectstart', function avoidSelect(e) {
                    e.preventDefault();
                    e.stopPropagation();
                });

                return element;

            };

            /**
             * Sorts the given map of files, returning an array of those files
             * grouped by file type (directories first, followed by non-
             * directories) and sorted lexicographically.
             *
             * @param {Object.<String, ManagedFilesystem.File>} files
             *     The map of files to sort.
             *
             * @returns {ManagedFilesystem.File[]}
             *     An array of all files in the given map, sorted
             *     lexicographically with directories first, followed by non-
             *     directories.
             */
            var sortFiles = function sortFiles(files) {

                // Get all given files as an array
                var unsortedFiles = [];
                for (var name in files)
                    unsortedFiles.push(files[name]);

                // Sort files - directories first, followed by all other files
                // sorted by name
                return unsortedFiles.sort(function fileComparator(a, b) {

                    // Directories come before non-directories
                    if ($scope.isDirectory(a) && !$scope.isDirectory(b))
                        return -1;

                    // Non-directories come after directories
                    if (!$scope.isDirectory(a) && $scope.isDirectory(b))
                        return 1;

                    // All other combinations are sorted by name
                    return a.name.localeCompare(b.name);

                });

            };

            // Watch directory contents once file template is available
            $templateRequest('app/client/templates/file.html').then(function fileTemplateRetrieved(html) {

                // Store file template statically
                fileTemplate = html;

                // Update the contents of the file browser whenever the current directory (or its contents) changes
                $scope.$watch('filesystem.currentDirectory.files', function currentDirectoryChanged(files) {

                    // Clear current content
                    currentDirectoryContents.html('');

                    // Display all files within current directory, sorted
                    angular.forEach(sortFiles(files), function displayFile(file) {
                        currentDirectoryContents.append(createFileElement(file));
                    });

                });

            }); // end retrieve file template

        }]

    };
}]);
<commit_msg>GUAC-1293: Rename click handler sensibly. No need to prevent default, etc. for clicks.<commit_after>/*
 * Copyright (C) 2015 Glyptodon LLC
 *
 * 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.
 */

/**
 * A directive which displays the contents of a filesystem received through the
 * Guacamole client.
 */
angular.module('client').directive('guacFileBrowser', [function guacFileBrowser() {

    return {
        restrict: 'E',
        replace: true,
        scope: {

            /**
             * The client whose file transfers should be managed by this
             * directive.
             *
             * @type ManagedClient
             */
            client : '=',

            /**
             * @type ManagedFilesystem
             */
            filesystem : '='

        },

        templateUrl: 'app/client/templates/guacFileBrowser.html',
        controller: ['$scope', '$element', '$injector', function guacFileBrowserController($scope, $element, $injector) {

            // Required types
            var ManagedFilesystem = $injector.get('ManagedFilesystem');

            // Required services
            var $interpolate     = $injector.get('$interpolate');
            var $templateRequest = $injector.get('$templateRequest');

            /**
             * The jQuery-wrapped element representing the contents of the
             * current directory within the file browser.
             *
             * @type Element[]
             */
            var currentDirectoryContents = $element.find('.current-directory-contents');

            /**
             * Statically-cached template HTML used to render each file within
             * a directory. Once available, this will be used through
             * createFileElement() to generate the DOM elements which make up
             * a directory listing.
             *
             * @type String
             */
            var fileTemplate = null;

            /**
             * Returns whether the given file is a normal file.
             *
             * @param {ManagedFilesystem.File} file
             *     The file to test.
             *
             * @returns {Boolean}
             *     true if the given file is a normal file, false otherwise.
             */
            $scope.isNormalFile = function isNormalFile(file) {
                return file.type === ManagedFilesystem.File.Type.NORMAL;
            };

            /**
             * Returns whether the given file is a directory.
             *
             * @param {ManagedFilesystem.File} file
             *     The file to test.
             *
             * @returns {Boolean}
             *     true if the given file is a directory, false otherwise.
             */
            $scope.isDirectory = function isDirectory(file) {
                return file.type === ManagedFilesystem.File.Type.DIRECTORY;
            };

            /**
             * Changes the currently-displayed directory to the given
             * directory.
             *
             * @param {ManagedFilesystem.File} file
             *     The directory to change to.
             */
            $scope.changeDirectory = function changeDirectory(file) {
                ManagedFilesystem.changeDirectory($scope.filesystem, file);
            };

            /**
             * Initiates a download of the given file. The progress of the
             * download can be observed through guacFileTransferManager.
             *
             * @param {ManagedFilesystem.File} file
             *     The file to download.
             */
            $scope.downloadFile = function downloadFile(file) {
                ManagedFilesystem.downloadFile($scope.client, $scope.filesystem, file.streamName);
            };

            /**
             * Creates a new element representing the given file and properly
             * handling user events, bypassing the overhead incurred through
             * use of ngRepeat and related techniques.
             *
             * Note that this function depends on the availability of the
             * statically-cached fileTemplate.
             *
             * @param {ManagedFilesystem.File} file
             *     The file to generate an element for.
             *
             * @returns {Element[]}
             *     A jQuery-wrapped array containing a single DOM element
             *     representing the given file.
             */
            var createFileElement = function createFileElement(file) {

                // Create from internal template
                var element = angular.element($interpolate(fileTemplate)(file));

                // Double-clicking on unknown file types will do nothing
                var fileAction = function doNothing() {};

                // Change current directory when directories are clicked
                if ($scope.isDirectory(file)) {
                    element.addClass('directory');
                    fileAction = function changeDirectory() {
                        $scope.changeDirectory(file);
                    };
                }

                // Initiate downloads when normal files are clicked
                else if ($scope.isNormalFile(file)) {
                    element.addClass('normal-file');
                    fileAction = function downloadFile() {
                        $scope.downloadFile(file);
                    };
                }

                // Mark file as focused upon click
                element.on('click', function handleFileClick() {

                    // Fire file-specific action if already focused
                    if (element.hasClass('focused')) {
                        fileAction();
                        element.removeClass('focused');
                    }

                    // Otherwise mark as focused
                    else {
                        element.parent().children().removeClass('focused');
                        element.addClass('focused');
                    }

                });

                // Prevent text selection during navigation
                element.on('selectstart', function avoidSelect(e) {
                    e.preventDefault();
                    e.stopPropagation();
                });

                return element;

            };

            /**
             * Sorts the given map of files, returning an array of those files
             * grouped by file type (directories first, followed by non-
             * directories) and sorted lexicographically.
             *
             * @param {Object.<String, ManagedFilesystem.File>} files
             *     The map of files to sort.
             *
             * @returns {ManagedFilesystem.File[]}
             *     An array of all files in the given map, sorted
             *     lexicographically with directories first, followed by non-
             *     directories.
             */
            var sortFiles = function sortFiles(files) {

                // Get all given files as an array
                var unsortedFiles = [];
                for (var name in files)
                    unsortedFiles.push(files[name]);

                // Sort files - directories first, followed by all other files
                // sorted by name
                return unsortedFiles.sort(function fileComparator(a, b) {

                    // Directories come before non-directories
                    if ($scope.isDirectory(a) && !$scope.isDirectory(b))
                        return -1;

                    // Non-directories come after directories
                    if (!$scope.isDirectory(a) && $scope.isDirectory(b))
                        return 1;

                    // All other combinations are sorted by name
                    return a.name.localeCompare(b.name);

                });

            };

            // Watch directory contents once file template is available
            $templateRequest('app/client/templates/file.html').then(function fileTemplateRetrieved(html) {

                // Store file template statically
                fileTemplate = html;

                // Update the contents of the file browser whenever the current directory (or its contents) changes
                $scope.$watch('filesystem.currentDirectory.files', function currentDirectoryChanged(files) {

                    // Clear current content
                    currentDirectoryContents.html('');

                    // Display all files within current directory, sorted
                    angular.forEach(sortFiles(files), function displayFile(file) {
                        currentDirectoryContents.append(createFileElement(file));
                    });

                });

            }); // end retrieve file template

        }]

    };
}]);
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

/**
 * The controller for the root of the application.
 */
angular.module('index').controller('indexController', ['$scope', '$injector',
        function indexController($scope, $injector) {

    // Required services
    var $document        = $injector.get('$document');
    var $window          = $injector.get('$window');
    var clipboardService = $injector.get('clipboardService');
    var guacNotification = $injector.get('guacNotification');

    /**
     * The notification service.
     */
    $scope.guacNotification = guacNotification;

    /**
     * The message to display to the user as instructions for the login
     * process.
     *
     * @type TranslatableMessage
     */
    $scope.loginHelpText = null;

    /**
     * The credentials that the authentication service is has already accepted,
     * pending additional credentials, if any. If the user is logged in, or no
     * credentials have been accepted, this will be null. If credentials have
     * been accepted, this will be a map of name/value pairs corresponding to
     * the parameters submitted in a previous authentication attempt.
     *
     * @type Object.<String, String>
     */
    $scope.acceptedCredentials = null;

    /**
     * The credentials that the authentication service is currently expecting,
     * if any. If the user is logged in, this will be null.
     *
     * @type Field[]
     */
    $scope.expectedCredentials = null;

    /**
     * Basic page-level information.
     */
    $scope.page = {

        /**
         * The title of the page.
         *
         * @type String
         */
        title: '',

        /**
         * The name of the CSS class to apply to the page body, if any.
         *
         * @type String
         */
        bodyClassName: ''

    };

    // Create event listeners at the global level
    var keyboard = new Guacamole.Keyboard($document[0]);

    // Broadcast keydown events
    keyboard.onkeydown = function onkeydown(keysym) {

        // Do not handle key events if not logged in
        if ($scope.expectedCredentials)
            return true;

        // Warn of pending keydown
        var guacBeforeKeydownEvent = $scope.$broadcast('guacBeforeKeydown', keysym, keyboard);
        if (guacBeforeKeydownEvent.defaultPrevented)
            return true;

        // If not prevented via guacBeforeKeydown, fire corresponding keydown event
        var guacKeydownEvent = $scope.$broadcast('guacKeydown', keysym, keyboard);
        return !guacKeydownEvent.defaultPrevented;

    };

    // Broadcast keyup events
    keyboard.onkeyup = function onkeyup(keysym) {

        // Do not handle key events if not logged in
        if ($scope.expectedCredentials)
            return;

        // Warn of pending keyup
        var guacBeforeKeydownEvent = $scope.$broadcast('guacBeforeKeyup', keysym, keyboard);
        if (guacBeforeKeydownEvent.defaultPrevented)
            return;

        // If not prevented via guacBeforeKeyup, fire corresponding keydown event
        $scope.$broadcast('guacKeyup', keysym, keyboard);

    };

    // Release all keys when window loses focus
    $window.onblur = function () {
        keyboard.reset();
    };

    /**
     * Checks whether the clipboard data has changed, firing a new
     * "guacClipboard" event if it has.
     */
    var checkClipboard = function checkClipboard() {
        clipboardService.getLocalClipboard().then(function clipboardRead(data) {
            $scope.$broadcast('guacClipboard', data);
        });
    };

    // Attempt to read the clipboard if it may have changed
    $window.addEventListener('load',  checkClipboard, true);
    $window.addEventListener('copy',  checkClipboard);
    $window.addEventListener('cut',   checkClipboard);
    $window.addEventListener('focus', function focusGained(e) {

        // Only recheck clipboard if it's the window itself that gained focus
        if (e.target === $window)
            checkClipboard();

    }, true);

    // Display login screen if a whole new set of credentials is needed
    $scope.$on('guacInvalidCredentials', function loginInvalid(event, parameters, error) {
        $scope.page.title = 'APP.NAME';
        $scope.page.bodyClassName = '';
        $scope.loginHelpText = null;
        $scope.acceptedCredentials = {};
        $scope.expectedCredentials = error.expected;
    });

    // Prompt for remaining credentials if provided credentials were not enough
    $scope.$on('guacInsufficientCredentials', function loginInsufficient(event, parameters, error) {
        $scope.page.title = 'APP.NAME';
        $scope.page.bodyClassName = '';
        $scope.loginHelpText = error.translatableMessage;
        $scope.acceptedCredentials = parameters;
        $scope.expectedCredentials = error.expected;
    });

    // Update title and CSS class upon navigation
    $scope.$on('$routeChangeSuccess', function(event, current, previous) {

        // If the current route is available
        if (current.$$route) {

            // Clear login screen if route change was successful (and thus
            // login was either successful or not required)
            $scope.loginHelpText = null;
            $scope.acceptedCredentials = null;
            $scope.expectedCredentials = null;

            // Set title
            var title = current.$$route.title;
            if (title)
                $scope.page.title = title;

            // Set body CSS class
            $scope.page.bodyClassName = current.$$route.bodyClassName || '';
        }

    });

}]);
<commit_msg>GUACAMOLE-352: Leverage Guacamole.Keyboard.InputSink within webapp as a default destination for input events.<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

/**
 * The controller for the root of the application.
 */
angular.module('index').controller('indexController', ['$scope', '$injector',
        function indexController($scope, $injector) {

    // Required services
    var $document        = $injector.get('$document');
    var $window          = $injector.get('$window');
    var clipboardService = $injector.get('clipboardService');
    var guacNotification = $injector.get('guacNotification');

    /**
     * The notification service.
     */
    $scope.guacNotification = guacNotification;

    /**
     * The message to display to the user as instructions for the login
     * process.
     *
     * @type TranslatableMessage
     */
    $scope.loginHelpText = null;

    /**
     * The credentials that the authentication service is has already accepted,
     * pending additional credentials, if any. If the user is logged in, or no
     * credentials have been accepted, this will be null. If credentials have
     * been accepted, this will be a map of name/value pairs corresponding to
     * the parameters submitted in a previous authentication attempt.
     *
     * @type Object.<String, String>
     */
    $scope.acceptedCredentials = null;

    /**
     * The credentials that the authentication service is currently expecting,
     * if any. If the user is logged in, this will be null.
     *
     * @type Field[]
     */
    $scope.expectedCredentials = null;

    /**
     * Basic page-level information.
     */
    $scope.page = {

        /**
         * The title of the page.
         *
         * @type String
         */
        title: '',

        /**
         * The name of the CSS class to apply to the page body, if any.
         *
         * @type String
         */
        bodyClassName: ''

    };

    // Add default destination for input events
    var sink = new Guacamole.Keyboard.InputSink();
    $document[0].body.appendChild(sink.getElement());

    // Create event listeners at the global level
    var keyboard = new Guacamole.Keyboard($document[0]);

    // Broadcast keydown events
    keyboard.onkeydown = function onkeydown(keysym) {

        // Do not handle key events if not logged in
        if ($scope.expectedCredentials)
            return true;

        // Warn of pending keydown
        var guacBeforeKeydownEvent = $scope.$broadcast('guacBeforeKeydown', keysym, keyboard);
        if (guacBeforeKeydownEvent.defaultPrevented)
            return true;

        // If not prevented via guacBeforeKeydown, fire corresponding keydown event
        var guacKeydownEvent = $scope.$broadcast('guacKeydown', keysym, keyboard);
        return !guacKeydownEvent.defaultPrevented;

    };

    // Broadcast keyup events
    keyboard.onkeyup = function onkeyup(keysym) {

        // Do not handle key events if not logged in
        if ($scope.expectedCredentials)
            return;

        // Warn of pending keyup
        var guacBeforeKeydownEvent = $scope.$broadcast('guacBeforeKeyup', keysym, keyboard);
        if (guacBeforeKeydownEvent.defaultPrevented)
            return;

        // If not prevented via guacBeforeKeyup, fire corresponding keydown event
        $scope.$broadcast('guacKeyup', keysym, keyboard);

    };

    // Release all keys when window loses focus
    $window.onblur = function () {
        keyboard.reset();
    };

    /**
     * Checks whether the clipboard data has changed, firing a new
     * "guacClipboard" event if it has.
     */
    var checkClipboard = function checkClipboard() {
        clipboardService.getLocalClipboard().then(function clipboardRead(data) {
            $scope.$broadcast('guacClipboard', data);
        });
    };

    // Attempt to read the clipboard if it may have changed
    $window.addEventListener('load',  checkClipboard, true);
    $window.addEventListener('copy',  checkClipboard);
    $window.addEventListener('cut',   checkClipboard);
    $window.addEventListener('focus', function focusGained(e) {

        // Only recheck clipboard if it's the window itself that gained focus
        if (e.target === $window)
            checkClipboard();

    }, true);

    // Display login screen if a whole new set of credentials is needed
    $scope.$on('guacInvalidCredentials', function loginInvalid(event, parameters, error) {
        $scope.page.title = 'APP.NAME';
        $scope.page.bodyClassName = '';
        $scope.loginHelpText = null;
        $scope.acceptedCredentials = {};
        $scope.expectedCredentials = error.expected;
    });

    // Prompt for remaining credentials if provided credentials were not enough
    $scope.$on('guacInsufficientCredentials', function loginInsufficient(event, parameters, error) {
        $scope.page.title = 'APP.NAME';
        $scope.page.bodyClassName = '';
        $scope.loginHelpText = error.translatableMessage;
        $scope.acceptedCredentials = parameters;
        $scope.expectedCredentials = error.expected;
    });

    // Update title and CSS class upon navigation
    $scope.$on('$routeChangeSuccess', function(event, current, previous) {

        // If the current route is available
        if (current.$$route) {

            // Clear login screen if route change was successful (and thus
            // login was either successful or not required)
            $scope.loginHelpText = null;
            $scope.acceptedCredentials = null;
            $scope.expectedCredentials = null;

            // Set title
            var title = current.$$route.title;
            if (title)
                $scope.page.title = title;

            // Set body CSS class
            $scope.page.bodyClassName = current.$$route.bodyClassName || '';
        }

    });

}]);
<|endoftext|>


<commit_before>if (typeof Number.prototype.toRadians == 'undefined') {
    Number.prototype.toRadians = function() {
        return this * Math.PI / 180;
    }
}

window.markerData = [];
window.Markers = {};

$(function() {

  self = this;

  map = document.getElementById('map-contours');
  this.mapBBox = map.getBoundingClientRect();

  this.mapLatLngBBox = [
    {lat: 60.9518, lng: -14.8535},
    {lat: 35.1379, lng: 42.4512}
  ];

  this.markerPrototype = $('#marker-prototype');
  this.markerSize = {
    w: this.markerPrototype.children('img').width(),
    h: this.markerPrototype.children('img').height()
  }

  this.markerLayer = $('#marker-layer');
  this.markers = [];

  this.update = function() {
    self.clearAllMarkers();

    markerData.forEach(function(obj) {
      if ($('#minbeds').val() == obj.year) {
        self.placeMarker(self.latLngToXY(obj.latitude, obj.longitude));
      }
    })
 };

  this.placeMarker = function(pos) {
    var marker = self.markerPrototype.clone(),
        w = self.markerSize.w,
        h = self.markerSize.h;
    marker.removeAttr("id");

    self.markers.push(marker);
    self.markerLayer.append(marker);

    //x = self.mapBBox.left + pos.x - w / 2;
    //y = self.mapBBox.top + pos.y - h;
    dx = self.mapBBox.left - w/2;
    dy = self.mapBBox.top - h*2;
    x = pos.x + dx;
    y = pos.y + dy;

    marker.offset({ top: y, left: x });
    console.log(pos, marker.offset());
  };

  this.clearAllMarkers = function() {
    self.markers.length = 0;
    self.markerLayer.empty();
  };

  this.latLngToXY = function(lat, lng) {
    var dy, dx, verticalFactor, pos;

    xKmPerPx = self.mapWidthAtLat(lat) / self.mapBBox.width;
    yKmPerPx = self.mapHeightAtLng(lng) / self.mapBBox.width;

    dy = self.sphericalDistance(
      {lat: self.mapLatLngBBox[0].lat, lng: lng},
      {lat: lat, lng: lng}
    );
    dx = self.sphericalDistance(
      {lat: lat, lng: self.mapLatLngBBox[0].lng},
      {lat: lat, lng: lng}
    );

    pos = {
      x: dx / xKmPerPx,
      y: dy / yKmPerPx
    };

    return pos;
  };

  this.sphericalDistance = function(from, to) {
    var φ1 = from.lat.toRadians(),
        φ2 = to.lat.toRadians(),
        Δλ = (to.lng - from.lng).toRadians(),
        R = 6378.137; // gives d in km

    return Math.acos( Math.sin(φ1)*Math.sin(φ2) + Math.cos(φ1)*Math.cos(φ2) * Math.cos(Δλ) ) * R;
  };

  this.mapWidthAtLat = function(lat) {
    return self.sphericalDistance(
      {lat: lat, lng: self.mapLatLngBBox[0].lng},
      {lat: lat, lng: self.mapLatLngBBox[1].lng}
    );
  };

  this.mapHeightAtLng = function(lng) {
    return self.sphericalDistance(
      {lat: self.mapLatLngBBox[0].lat, lng: lng},
      {lat: self.mapLatLngBBox[1].lat, lng: lng}
    );
  };

  //$(window).resize(this.resize);
  this.update();
  window.Markers.update = this.update;
});

/* jquery slider */

$(function() {
  var select = $( "#minbeds" );
  var slider = $( "

" ).insertAfter( select ).slider({
    min: 1,
    max: 6,
    range: "min",
    value: select[ 0 ].selectedIndex + 1,
    slide: function( event, ui ) {
      select[ 0 ].selectedIndex = ui.value - 1;
      updateYear();
    }
  });
  $( "#minbeds" ).change(function() {
    slider.slider( "value", this.selectedIndex + 1 );

    updateYear();
  });

  function updateYear() {
    console.log($( "#minbeds" ).val());
    Markers.update();
  }
});

<commit_msg>update marker positions on resize<commit_after>if (typeof Number.prototype.toRadians == 'undefined') {
    Number.prototype.toRadians = function() {
        return this * Math.PI / 180;
    }
}

window.markerData = [];
window.Markers = {};

$(function() {

  self = this;

  map = document.getElementById('map-contours');
  this.mapBBox = map.getBoundingClientRect();

  this.mapLatLngBBox = [
    {lat: 60.9518, lng: -14.8535},
    {lat: 35.1379, lng: 42.4512}
  ];

  this.markerPrototype = $('#marker-prototype');
  this.markerSize = {
    w: this.markerPrototype.children('img').width(),
    h: this.markerPrototype.children('img').height()
  }

  this.markerLayer = $('#marker-layer');
  this.markers = [];

  this.update = function() {
    self.clearAllMarkers();

    markerData.forEach(function(obj) {
      if ($('#minbeds').val() == obj.year) {
        self.placeMarker({lat: obj.latitude, lng: obj.longitude});
      }
    })
  };

  this.onResize = function() {
    self.mapBBox = map.getBoundingClientRect();
    self.markers.forEach(self.setMarkerPosition);
  };

  this.setMarkerPosition = function(marker) {
    var dx, dy, w, h, x, y, pos;

    pos = self.latLngToXY(marker.data("latitude"), marker.data("longitude"));
    w = self.markerSize.w,
    h = self.markerSize.h;
    dx = self.mapBBox.left - w/2;
    dy = self.mapBBox.top - h*2;
    x = pos.x + dx;
    y = pos.y + dy;

    marker.offset({ top: y, left: x });
  };

  this.placeMarker = function(coords) {
    var marker = self.markerPrototype.clone();
    marker.removeAttr("id");
    marker.attr("data-latitude", coords.lat);
    marker.attr("data-longitude", coords.lng);

    self.markers.push(marker);
    self.markerLayer.append(marker);
    self.setMarkerPosition(marker);
  };

  this.clearAllMarkers = function() {
    self.markers.length = 0;
    self.markerLayer.empty();
  };

  this.latLngToXY = function(lat, lng) {
    var dy, dx, verticalFactor, pos;

    xKmPerPx = self.mapWidthAtLat(lat) / self.mapBBox.width;
    yKmPerPx = self.mapHeightAtLng(lng) / self.mapBBox.width;

    dy = self.sphericalDistance(
      {lat: self.mapLatLngBBox[0].lat, lng: lng},
      {lat: lat, lng: lng}
    );
    dx = self.sphericalDistance(
      {lat: lat, lng: self.mapLatLngBBox[0].lng},
      {lat: lat, lng: lng}
    );

    pos = {
      x: dx / xKmPerPx,
      y: dy / yKmPerPx
    };

    return pos;
  };

  this.sphericalDistance = function(from, to) {
    var φ1 = from.lat.toRadians(),
        φ2 = to.lat.toRadians(),
        Δλ = (to.lng - from.lng).toRadians(),
        R = 6378.137; // gives d in km

    return Math.acos( Math.sin(φ1)*Math.sin(φ2) + Math.cos(φ1)*Math.cos(φ2) * Math.cos(Δλ) ) * R;
  };

  this.mapWidthAtLat = function(lat) {
    return self.sphericalDistance(
      {lat: lat, lng: self.mapLatLngBBox[0].lng},
      {lat: lat, lng: self.mapLatLngBBox[1].lng}
    );
  };

  this.mapHeightAtLng = function(lng) {
    return self.sphericalDistance(
      {lat: self.mapLatLngBBox[0].lat, lng: lng},
      {lat: self.mapLatLngBBox[1].lat, lng: lng}
    );
  };

  $(window).resize(this.onResize);
  this.update();
  window.Markers.update = this.update;
});

/* jquery slider */

$(function() {
  var select = $( "#minbeds" );
  var slider = $( "

" ).insertAfter( select ).slider({
    min: 1,
    max: 6,
    range: "min",
    value: select[ 0 ].selectedIndex + 1,
    slide: function( event, ui ) {
      select[ 0 ].selectedIndex = ui.value - 1;
      updateYear();
    }
  });
  $( "#minbeds" ).change(function() {
    slider.slider( "value", this.selectedIndex + 1 );

    updateYear();
  });

  function updateYear() {
    console.log($( "#minbeds" ).val());
    Markers.update();
  }
});

<|endoftext|>


<commit_before>var channel_list = ["ESL_SC2", "OgamingSC2", "cretetion", "freecodecamp", "storbeck", "habathcx", "RobotCaleb", "noobs2ninjas"];

function getinfo() {
    channel_list.forEach(function() {
        $.getJSON(url, function(data) {
            console.log(dat);
        });
    });
}
<commit_msg>Add the API call<commit_after>var channel_list = ["ESL_SC2", "OgamingSC2", "cretetion", "freecodecamp", "storbeck", "habathcx", "RobotCaleb", "noobs2ninjas"];

function getinfo() {
    channel_list.forEach(function(c) {
        var url = "https://wind-bow.gomix.me/twitch-api/streams/" + c + "/?callback=?";
        $.getJSON(url, function(data) {
            console.log(data);
        });
    });
}

$(document)
    .ready(getinfo);
<|endoftext|>


<commit_before>---
---
// dashes above allow this file to be processed by jekyll

function getRandom(min, max) {
  return Math.random() * (max - min) + min;
}

var Game = Backbone.Model.extend({

});

Game.GameView = Backbone.View.extend({
  className: "game",

  template: _.template( $("#game-ui-template").html() ),

  events: {
    "click .music": "music"
  },

  initialize: function() {
    // {{ site.baseurl }} places the base url of this site when this file is processed by jekyll
    this.song = new buzz.sound( "{{ site.baseurl }}/sounds/song1", { formats: [ "mp3", "wav" ] });
    this.song.play().fadeIn().loop();
  },

  music: function(e) {
    var $music = this.$el.find('.music');

    if ( $music.hasClass('paused') ) {
      $music.removeClass('paused');
      $music.html('pause music');
      this.song.play().loop();
    } else {
      $music.addClass('paused');
      $music.html('play music');
      this.song.pause();
    }
  },

  render: function() {
    this.$el.html( this.template() );

    $('body').prepend( this.$el );
    return this;
  }
})

Game.Jumper = Backbone.Model.extend({
  defaults: {
    width: 36,
    height: 68,
    speed: getRandom(10, 100),
    delay: getRandom(10, 100),
    x: 10,
    y: 0
  }
});

Game.JumperView = Backbone.View.extend({
  className: "jumper",
  keysDown: {},

  initialize: function() {
    _.bindAll(this, "keyDownHandler");
    $(document).bind('keydown', this.keyDownHandler);

    _.bindAll(this, "keyUpHandler");
    $(document).bind('keyup', this.keyUpHandler);
  },

  events: {
    //"keypress": "keyDownHandler",
    //"keyup": "keyUpHandler"
  },

  keyDownHandler: function(e) {

    var jumper = this.model.attributes;

    this.keysDown[e.keyCode] = true;
    console.log(jumper.speed);

    if (40 in this.keysDown) {}

    if (38 in this.keysDown && 39 in this.keysDown) {
      this.$el.addClass("jump").removeClass('left').delay(jumper.delay).animate({
        bottom: '+=' + jumper.speed*2,
        left: '+=' + jumper.speed*2
      }, 120, function() {

      }).animate({
        bottom: '-=' + jumper.speed*2,
        left: '+=' + jumper.speed*2
      }, 80, function() {

      });
    } else if (38 in this.keysDown && 37 in this.keysDown) {
      this.$el.addClass("jump").delay(jumper.delay).animate({
        bottom: '+=' + jumper.speed*2,
        left: '-=' + jumper.speed*2
      }, 120, function() {

      }).animate({
        bottom: '-=' + jumper.speed*2,
        left: '-=' + jumper.speed*2
      }, 80, function() {

      });
    } else if (38 in this.keysDown) {
      this.$el.addClass("jump").delay(jumper.delay).animate({
        bottom: '+=' + jumper.speed*2
      }, 120, function() {

      }).animate({
        bottom: '-=' + jumper.speed*2
      }, 80, function() {

      });
    }

    if (39 in this.keysDown) {
      this.$el.addClass('walk').removeClass('left').animate({
        left: '+=' + jumper.speed
      }, 100, function() {
      });
    }

    if (37 in this.keysDown) {
      this.$el.addClass('left walk').animate({
        left: '-=' + jumper.speed
      }, 100, function() {
      });
    }

    if($(document).find($(this.el)).size() <= 0) {
      $(document).unbind('keydown', this.keyUpHandler);
    }
  },

  keyUpHandler: function(e) {
    delete this.keysDown[e.keyCode];
    this.$el.removeClass('walk jump');

    if($(document).find($(this.el)).size() <= 0) {
      $(document).unbind('keyup', this.keyUpHandler);
    }
  },

  render: function() {
    $(".game").append( this.$el );
    this.$el.delay(500).animate({ bottom: 40, left: getRandom(0, 1000) }, 1000);
    return this;
  }

});

Game.Router = Backbone.Router.extend({

  start: function() {
    this.game = new Game;
    this.gameView = new Game.GameView({ model: this.game });
    this.gameView.render();

    this.jumper = new Game.Jumper({ speed: getRandom(40, 100), delay: getRandom(100, 1000) });
    this.jumperView = new Game.JumperView({ model: this.jumper });
    this.jumperView.render();
  },

  loop: function() {
    (function() {
      var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
                                  window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
      window.requestAnimationFrame = requestAnimationFrame;
    })();

    fps = 1;
    now = lastFrameTimestamp = (new Date).getTime();
    interval = 1000 / fps;
    counter = 0;

    function tick() {
      now = (new Date).getTime();
      if(now - lastFrameTimestamp > interval) {
        lastFrameTimestamp = now;

        this.jumper = new Game.Jumper({ speed: getRandom(40, 80), delay: getRandom(0, 100) });
        this.jumperView = new Game.JumperView({ model: this.jumper });
        this.jumperView.render();
      }
      requestAnimationFrame(tick);
    }
    requestAnimationFrame(tick);
  }

});

var game = new Game;
var gameRouter = new Game.Router({ model: game });
gameRouter.start();
gameRouter.loop();

<commit_msg>now less random<commit_after>---
---
// dashes above allow this file to be processed by jekyll

function getRandom(min, max) {
  return Math.random() * (max - min) + min;
}

var Game = Backbone.Model.extend({

});

Game.GameView = Backbone.View.extend({
  className: "game",

  template: _.template( $("#game-ui-template").html() ),

  events: {
    "click .music": "music"
  },

  initialize: function() {
    // {{ site.baseurl }} places the base url of this site when this file is processed by jekyll
    this.song = new buzz.sound( "{{ site.baseurl }}/sounds/song1", { formats: [ "mp3", "wav" ] });
    this.song.play().fadeIn().loop();
  },

  music: function(e) {
    var $music = this.$el.find('.music');

    if ( $music.hasClass('paused') ) {
      $music.removeClass('paused');
      $music.html('pause music');
      this.song.play().loop();
    } else {
      $music.addClass('paused');
      $music.html('play music');
      this.song.pause();
    }
  },

  render: function() {
    this.$el.html( this.template() );

    $('body').prepend( this.$el );
    return this;
  }
})

Game.Jumper = Backbone.Model.extend({
  defaults: {
    width: 36,
    height: 68,
    speed: getRandom(10, 100),
    delay: getRandom(10, 100),
    x: 10,
    y: 0
  }
});

Game.JumperView = Backbone.View.extend({
  className: "jumper",
  keysDown: {},

  initialize: function() {
    _.bindAll(this, "keyDownHandler");
    $(document).bind('keydown', this.keyDownHandler);

    _.bindAll(this, "keyUpHandler");
    $(document).bind('keyup', this.keyUpHandler);
  },

  events: {
    //"keypress": "keyDownHandler",
    //"keyup": "keyUpHandler"
  },

  keyDownHandler: function(e) {

    var jumper = this.model.attributes;

    this.keysDown[e.keyCode] = true;
    console.log(jumper.speed);

    if (40 in this.keysDown) {}

    if (38 in this.keysDown && 39 in this.keysDown) {
      this.$el.addClass("jump").removeClass('left').delay(jumper.delay).animate({
        bottom: '+=' + jumper.speed*2,
        left: '+=' + jumper.speed*2
      }, 120, function() {

      }).animate({
        bottom: '-=' + jumper.speed*2,
        left: '+=' + jumper.speed*2
      }, 80, function() {

      });
    } else if (38 in this.keysDown && 37 in this.keysDown) {
      this.$el.addClass("jump").delay(jumper.delay).animate({
        bottom: '+=' + jumper.speed*2,
        left: '-=' + jumper.speed*2
      }, 120, function() {

      }).animate({
        bottom: '-=' + jumper.speed*2,
        left: '-=' + jumper.speed*2
      }, 80, function() {

      });
    } else if (38 in this.keysDown) {
      this.$el.addClass("jump").delay(jumper.delay).animate({
        bottom: '+=' + jumper.speed*2
      }, 120, function() {

      }).animate({
        bottom: '-=' + jumper.speed*2
      }, 80, function() {

      });
    }

    if (39 in this.keysDown) {
      this.$el.addClass('walk').removeClass('left').animate({
        left: '+=' + jumper.speed
      }, 100, function() {
      });
    }

    if (37 in this.keysDown) {
      this.$el.addClass('left walk').animate({
        left: '-=' + jumper.speed
      }, 100, function() {
      });
    }

    if($(document).find($(this.el)).size() <= 0) {
      $(document).unbind('keydown', this.keyUpHandler);
    }
  },

  keyUpHandler: function(e) {
    delete this.keysDown[e.keyCode];
    this.$el.removeClass('walk jump');

    if($(document).find($(this.el)).size() <= 0) {
      $(document).unbind('keyup', this.keyUpHandler);
    }
  },

  render: function() {
    $(".game").append( this.$el );
    this.$el.delay(500).animate({ bottom: 40, left: getRandom(0, 1000) }, 1000);
    return this;
  }

});

Game.Router = Backbone.Router.extend({

  start: function() {
    this.game = new Game;
    this.gameView = new Game.GameView({ model: this.game });
    this.gameView.render();

    this.jumper = new Game.Jumper({ speed: getRandom(40, 100), delay: getRandom(100, 1000) });
    this.jumperView = new Game.JumperView({ model: this.jumper });
    this.jumperView.render();
  },

  loop: function() {
    (function() {
      var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
                                  window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
      window.requestAnimationFrame = requestAnimationFrame;
    })();

    fps = 1;
    now = lastFrameTimestamp = (new Date).getTime();
    interval = 1000 / fps;
    counter = 0;

    function tick() {
      now = (new Date).getTime();
      if(now - lastFrameTimestamp > interval) {
        lastFrameTimestamp = now;

        this.jumper = new Game.Jumper({ speed: getRandom(40, 80), delay: getRandom(0, 10) });
        this.jumperView = new Game.JumperView({ model: this.jumper });
        this.jumperView.render();
      }
      requestAnimationFrame(tick);
    }
    requestAnimationFrame(tick);
  }

});

var game = new Game;
var gameRouter = new Game.Router({ model: game });
gameRouter.start();
gameRouter.loop();

<|endoftext|>


<commit_before>/**
 *  entry point for table
 */

$(function() {

  var Table = cdb.core.View.extend({

    el: document.body,

    events: {
      'keypress': 'keyPress',
      'keyup': 'keyUp'
    },

    initialize: function() {
      this.user = new cdb.admin.User(this.options.user_data);

      this._initModels();
      this._initViews();

      // init data
      // table change will raise the map and columns fetch
      this.table.fetch();

    },

    appyQuery: function(sql) {
      var self = this;
      self.sqlView.setSQL(sql);
      self.table.useSQLView(self.sqlView);
      // if there is some error the query is rollbacked
      self.sqlView.fetch();
    },

    _initModels: function() {
      var self = this;
      this.table = new cdb.admin.CartoDBTableMetadata({
        id: this.options.table_id
      });
      this.columns = this.table.data();
      this.map = new cdb.admin.Map();
      this.infowindow = new cdb.geo.ui.InfowindowModel({
        template_name: 'table/views/infowindow_light'
      });
      this.sqlView = new cdb.admin.SQLViewData();
      this.geocoder = new cdb.admin.Geocoding('', this.table);

      //TODO: load this from an initial data file or d
      var layers = [
        {
          url: 'http://tile.stamen.com/toner/{z}/{x}/{y}.png',
          maxZoom: 17
        },
        {
          url: 'http://a.tiles.mapbox.com/v3/mapbox.mapbox-light/{z}/{x}/{y}.png',
          maxZoom: 17
        },
        //'http://tile.stamen.com/terrain/{z}/{x}/{y}.png',
        //'http://tile.stamen.com/watercolor/{z}/{x}/{y}.png',
        {
          url: 'http://a.tiles.mapbox.com/v3/mapbox.mapbox-streets/{z}/{x}/{y}.png',
          maxZoom: 17
        }

      ];

      this.baseLayers = this.user.layers;
      _(layers).map(function(m) {
        self.baseLayers.add(new cdb.admin.TileLayer({
          urlTemplate: m.url,
          read_only: true,
          maxZoom: m.maxZoom
        }));
      });

      // fetch or create map id
      this.map.relatedTo(this.table);

      this.map.bind('change:dataLayer', _.once(function() {

        // cache the value to access it in all the view
        self.dataLayer = self.map.get('dataLayer');

        // when the layer query changes the table should change
        self.dataLayer.bind('change:query', function() {
          var sql = this.get('query');
          if(sql) {
            self.appyQuery(sql);
          } else {
            self.table.useSQLView(null); }
        });

        self.sqlView.bind('error', function() {
          self.dataLayer.save({query: null}, {silent: true});
        });

        // trigger the event to ping all views
        self.dataLayer.trigger('change:query');

        var infowindowData = self.dataLayer.get('infowindow');
        if(infowindowData) {
          self.infowindow.set(infowindowData);
        } else {
          _(self.table.get('schema')).each(function(v) {
            self.infowindow.addField(v[0]);
          });
        }

        // check all the fields in the infowindows are in table schema
        // remove the missing ones
        self.table.bind('change:schema', function() {
          var columns = self.table.columnNames();
          _(self.infowindow.get('fields')).each(function(c) {
            if(!_.contains(columns, c.name)) {
              self.infowindow.removeField(c.name);
            }
          });

        });

        self.infowindow.bind('change:fields change:template_name', function() {
          // call with silent so the layer is no realoded
          // if some view needs to be changed when infowindow is changed it should be
          // subscribed to infowindow model not to dataLayer
          // (which is only a data container for infowindow)
          self.dataLayer.save({ infowindow: self.infowindow.toJSON() }, { silent: true });
        });

      }));

    },

    _initViews: function() {
      var self = this;

      this.header = new cdb.admin.Header({
        el: this.$('header'),
        model: this.table,
        user: this.user,
        geocoder: this.geocoder
      });
      this.addView(this.header);

      this.tabs = new cdb.admin.Tabs({
        el: this.$('nav')
      });
      this.addView(this.tabs);

      this.workView = new cdb.ui.common.TabPane({
        el: this.$('.panes')
      });

      this.addView(this.workView);

      this.tableTab = new cdb.admin.TableTab({
        model: this.table
      });

      this.mapTab = new cdb.admin.MapTab({
        model: this.map,
        baseLayers: this.baseLayers,
        table: this.table,
        infowindow: this.infowindow
      });

      this.globalError = new cdb.admin.GlobalError({
        el: $('.globalerror')
      });

      this.table.bind('notice', this.globalError.showError, this.globalError);

      this.addView(this.globalError);

      // used to show progress on stuff being done
      var bkg_importer = this.bkg_importer = new cdb.ui.common.BackgroundImporter({
        template_base: 'table/views/geocoder_progress',
        import_: this.geocoder
      });
      this.$el.append(this.bkg_importer.render().el);

      this.geocoder.bind('start', function() {
        self.bkg_importer.changeState(self.geocoder);
      });

      this.geocoder.bind('progress', function() {
        self.bkg_importer.render();
        if(self.geocoder.total_connections%10 == 0) {
          //self.dataLayer.trigger('change');
        }
      });

      this.geocoder.bind('finish', function() {
        self.bkg_importer.changeState(self.geocoder);
      });

      this.menu = new cdb.admin.RightMenu({});
      this.$el.append(this.menu.render().el);
      this.menu.hide();
      this.addView(this.menu);

      this.map.bind('change:dataLayer', _.once(function() {

        self.header.setDataLayer(self.dataLayer);

        self.table.bind('change:name', function() {
          self.dataLayer.set({ table_name: self.table.get('name') });
          self.dataLayer.save();
        });

        self.dataLayer.set({
          table_name: self.table.get('name'),
          user_name: self.user.get("username"),
          sql: sql,
          extra_params: {
            map_key: self.user.get('api_key')
          },
          sql_api_domain: cdb.config.get('sql_api_domain'),
          sql_api_endpoint: cdb.config.get('sql_api_endpoint'),
          sql_api_port: cdb.config.get('sql_api_port'),
          tiler_domain: cdb.config.get('tiler_domain'),
          tiler_port: cdb.config.get('tiler_port')
        });

        self.dataLayer.save();

        // set api key when we have api key and the data layer loaded
        var sql = self.table.isInSQLView() ?
                      self.table.data().getSQL() :
                      undefined;

        // lateral menu modules
        var sql = new cdb.admin.mod.SQL({
          model: self.dataLayer,
          sqlView: self.sqlView,
          table: self.table
        });

        sql.bind('writeSQL', self.appyQuery, self);

        var carto = new cdb.admin.mod.Carto({
          model: self.dataLayer,
          table: self.table
        });

        var infowindow = new cdb.admin.mod.InfoWindow({
          table: self.table,
          model: self.infowindow
        });
        self.menu.addModule(sql.render(), ['table', 'map']);
        self.menu.addModule(carto.render(), 'map');
        self.menu.addModule(infowindow.render(), 'map');

        var addRow = self.menu.addToolButton('add_row', 'table');
        var addColumn = self.menu.addToolButton('add_column', 'table');
        addColumn.bind('click', function() {
            new cdb.admin.NewColumnDialog({
              table: self.table
            }).appendToBody().open();
        });
        addRow.bind('click', function() {
          self.table.data().addRow({ at: 0});
        });

      }));

      this.workView.addTab('table', this.tableTab.render());
      this.workView.addTab('map', this.mapTab.render());
      this.workView.bind('tabEnabled:map', this.mapTab.enableMap, this.mapTab);

      this.workView.bind('tabEnabled', this.tabs.activate);
      this.workView.active('table');

      // global click
      enableClickOut(this.$el);

      this.mapTab.bind('missingClick', function() {
        self.menu.hide();
      });
      this.tableTab.tableView.bind('cellClick', function() {
        self.menu.hide();
      });

      // On resize window...
      $(window).bind("resize", this._onResize);

    },

    // Close all dialogs in window resize
    _onResize: function(e) {
      cdb.god.trigger("closeDialogs");
    },

    keyUp: function(e) {
    },

    keyPress: function(e) {
      /*if(e.which == 19) {
        this.menu.show();
        this.menu.active('sql_mod');
        e.preventDefault();
        return false;
      }*/
    }

  });

    cdb._test = cdb._test || {};
    cdb._test.Table = Table;

    var TableRouter = Backbone.Router.extend({

        initialize: function(table) {
          var self = this;
          this.table = table;
          /*
          this.table.table.bind('change:dataSource', function() {
            if(this.isInSQLView()) {
              var sql = this.data().getSQL();
              if(!this.alterTableData(sql)) {
                self.navigate('table/' + encodeURIComponent(sql));
              }
            } else {
              self.navigate('table');
            }
          });
          */
        },

        routes: {
            '': 'index',
            'table': 'index',
            'table/:sql': 'table_sql',
            'map': 'map'
        },

        index: function() {
          this.table.workView.active('table');
          this.table.menu.showTools('table');
        },

        table_sql: function(sql) {
          this.index();
          if(!this.table.table.alterTableData(sql)) {
            this.table.sqlView.setSQL(decodeURIComponent(sql));
            this.table.table.useSQLView(this.table.sqlView);
          }
        },

        map: function() {
          this.table.workView.active('map');
          this.table.menu.showTools('map');
        }

    });

    cdb.init(function() {
      cdb.config.set(config);
      cdb.templates.namespace = 'cartodb/';
      var table = new Table({
        table_id: table_id,
        user_data: user_data
      });
      var router = new TableRouter(table);
      // expose to debug
      window.table = table;
      Backbone.history.start();
    });

});
<commit_msg>assign default position values for info windows<commit_after>/**
 *  entry point for table
 */

$(function() {

  var Table = cdb.core.View.extend({

    el: document.body,

    events: {
      'keypress': 'keyPress',
      'keyup': 'keyUp'
    },

    initialize: function() {
      this.user = new cdb.admin.User(this.options.user_data);

      this._initModels();
      this._initViews();

      // init data
      // table change will raise the map and columns fetch
      this.table.fetch();

    },

    appyQuery: function(sql) {
      var self = this;
      self.sqlView.setSQL(sql);
      self.table.useSQLView(self.sqlView);
      // if there is some error the query is rollbacked
      self.sqlView.fetch();
    },

    _initModels: function() {
      var self = this;
      this.table = new cdb.admin.CartoDBTableMetadata({
        id: this.options.table_id
      });
      this.columns = this.table.data();
      this.map = new cdb.admin.Map();
      this.infowindow = new cdb.geo.ui.InfowindowModel({
        template_name: 'table/views/infowindow_light'
      });
      this.sqlView = new cdb.admin.SQLViewData();
      this.geocoder = new cdb.admin.Geocoding('', this.table);

      //TODO: load this from an initial data file or d
      var layers = [
        {
          url: 'http://tile.stamen.com/toner/{z}/{x}/{y}.png',
          maxZoom: 17
        },
        {
          url: 'http://a.tiles.mapbox.com/v3/mapbox.mapbox-light/{z}/{x}/{y}.png',
          maxZoom: 17
        },
        //'http://tile.stamen.com/terrain/{z}/{x}/{y}.png',
        //'http://tile.stamen.com/watercolor/{z}/{x}/{y}.png',
        {
          url: 'http://a.tiles.mapbox.com/v3/mapbox.mapbox-streets/{z}/{x}/{y}.png',
          maxZoom: 17
        }

      ];

      this.baseLayers = this.user.layers;
      _(layers).map(function(m) {
        self.baseLayers.add(new cdb.admin.TileLayer({
          urlTemplate: m.url,
          read_only: true,
          maxZoom: m.maxZoom
        }));
      });

      // fetch or create map id
      this.map.relatedTo(this.table);

      this.map.bind('change:dataLayer', _.once(function() {

        // cache the value to access it in all the view
        self.dataLayer = self.map.get('dataLayer');

        // when the layer query changes the table should change
        self.dataLayer.bind('change:query', function() {
          var sql = this.get('query');
          if(sql) {
            self.appyQuery(sql);
          } else {
            self.table.useSQLView(null); }
        });

        self.sqlView.bind('error', function() {
          self.dataLayer.save({query: null}, {silent: true});
        });

        // trigger the event to ping all views
        self.dataLayer.trigger('change:query');

        var infowindowData = self.dataLayer.get('infowindow');
        if(infowindowData) {
          self.infowindow.set(infowindowData);
        } else {
          // assign a position from start
          var pos = 0;
          _(self.table.get('schema')).each(function(v) {
            self.infowindow.addField(v[0], pos);
            ++pos;
          });
        }

        // check all the fields in the infowindows are in table schema
        // remove the missing ones
        self.table.bind('change:schema', function() {
          var columns = self.table.columnNames();
          _(self.infowindow.get('fields')).each(function(c) {
            if(!_.contains(columns, c.name)) {
              self.infowindow.removeField(c.name);
            }
          });

        });

        self.infowindow.bind('change:fields change:template_name', function() {
          // call with silent so the layer is no realoded
          // if some view needs to be changed when infowindow is changed it should be
          // subscribed to infowindow model not to dataLayer
          // (which is only a data container for infowindow)
          self.dataLayer.save({ infowindow: self.infowindow.toJSON() }, { silent: true });
        });

      }));

    },

    _initViews: function() {
      var self = this;

      this.header = new cdb.admin.Header({
        el: this.$('header'),
        model: this.table,
        user: this.user,
        geocoder: this.geocoder
      });
      this.addView(this.header);

      this.tabs = new cdb.admin.Tabs({
        el: this.$('nav')
      });
      this.addView(this.tabs);

      this.workView = new cdb.ui.common.TabPane({
        el: this.$('.panes')
      });

      this.addView(this.workView);

      this.tableTab = new cdb.admin.TableTab({
        model: this.table
      });

      this.mapTab = new cdb.admin.MapTab({
        model: this.map,
        baseLayers: this.baseLayers,
        table: this.table,
        infowindow: this.infowindow
      });

      this.globalError = new cdb.admin.GlobalError({
        el: $('.globalerror')
      });

      this.table.bind('notice', this.globalError.showError, this.globalError);

      this.addView(this.globalError);

      // used to show progress on stuff being done
      var bkg_importer = this.bkg_importer = new cdb.ui.common.BackgroundImporter({
        template_base: 'table/views/geocoder_progress',
        import_: this.geocoder
      });
      this.$el.append(this.bkg_importer.render().el);

      this.geocoder.bind('start', function() {
        self.bkg_importer.changeState(self.geocoder);
      });

      this.geocoder.bind('progress', function() {
        self.bkg_importer.render();
        if(self.geocoder.total_connections%10 == 0) {
          //self.dataLayer.trigger('change');
        }
      });

      this.geocoder.bind('finish', function() {
        self.bkg_importer.changeState(self.geocoder);
      });

      this.menu = new cdb.admin.RightMenu({});
      this.$el.append(this.menu.render().el);
      this.menu.hide();
      this.addView(this.menu);

      this.map.bind('change:dataLayer', _.once(function() {

        self.header.setDataLayer(self.dataLayer);

        self.table.bind('change:name', function() {
          self.dataLayer.set({ table_name: self.table.get('name') });
          self.dataLayer.save();
        });

        self.dataLayer.set({
          table_name: self.table.get('name'),
          user_name: self.user.get("username"),
          sql: sql,
          extra_params: {
            map_key: self.user.get('api_key')
          },
          sql_api_domain: cdb.config.get('sql_api_domain'),
          sql_api_endpoint: cdb.config.get('sql_api_endpoint'),
          sql_api_port: cdb.config.get('sql_api_port'),
          tiler_domain: cdb.config.get('tiler_domain'),
          tiler_port: cdb.config.get('tiler_port')
        });

        self.dataLayer.save();

        // set api key when we have api key and the data layer loaded
        var sql = self.table.isInSQLView() ?
                      self.table.data().getSQL() :
                      undefined;

        // lateral menu modules
        var sql = new cdb.admin.mod.SQL({
          model: self.dataLayer,
          sqlView: self.sqlView,
          table: self.table
        });

        sql.bind('writeSQL', self.appyQuery, self);

        var carto = new cdb.admin.mod.Carto({
          model: self.dataLayer,
          table: self.table
        });

        var infowindow = new cdb.admin.mod.InfoWindow({
          table: self.table,
          model: self.infowindow
        });
        self.menu.addModule(sql.render(), ['table', 'map']);
        self.menu.addModule(carto.render(), 'map');
        self.menu.addModule(infowindow.render(), 'map');

        var addRow = self.menu.addToolButton('add_row', 'table');
        var addColumn = self.menu.addToolButton('add_column', 'table');
        addColumn.bind('click', function() {
            new cdb.admin.NewColumnDialog({
              table: self.table
            }).appendToBody().open();
        });
        addRow.bind('click', function() {
          self.table.data().addRow({ at: 0});
        });

      }));

      this.workView.addTab('table', this.tableTab.render());
      this.workView.addTab('map', this.mapTab.render());
      this.workView.bind('tabEnabled:map', this.mapTab.enableMap, this.mapTab);

      this.workView.bind('tabEnabled', this.tabs.activate);
      this.workView.active('table');

      // global click
      enableClickOut(this.$el);

      this.mapTab.bind('missingClick', function() {
        self.menu.hide();
      });
      this.tableTab.tableView.bind('cellClick', function() {
        self.menu.hide();
      });

      // On resize window...
      $(window).bind("resize", this._onResize);

    },

    // Close all dialogs in window resize
    _onResize: function(e) {
      cdb.god.trigger("closeDialogs");
    },

    keyUp: function(e) {
    },

    keyPress: function(e) {
      /*if(e.which == 19) {
        this.menu.show();
        this.menu.active('sql_mod');
        e.preventDefault();
        return false;
      }*/
    }

  });

    cdb._test = cdb._test || {};
    cdb._test.Table = Table;

    var TableRouter = Backbone.Router.extend({

        initialize: function(table) {
          var self = this;
          this.table = table;
          /*
          this.table.table.bind('change:dataSource', function() {
            if(this.isInSQLView()) {
              var sql = this.data().getSQL();
              if(!this.alterTableData(sql)) {
                self.navigate('table/' + encodeURIComponent(sql));
              }
            } else {
              self.navigate('table');
            }
          });
          */
        },

        routes: {
            '': 'index',
            'table': 'index',
            'table/:sql': 'table_sql',
            'map': 'map'
        },

        index: function() {
          this.table.workView.active('table');
          this.table.menu.showTools('table');
        },

        table_sql: function(sql) {
          this.index();
          if(!this.table.table.alterTableData(sql)) {
            this.table.sqlView.setSQL(decodeURIComponent(sql));
            this.table.table.useSQLView(this.table.sqlView);
          }
        },

        map: function() {
          this.table.workView.active('map');
          this.table.menu.showTools('map');
        }

    });

    cdb.init(function() {
      cdb.config.set(config);
      cdb.templates.namespace = 'cartodb/';
      var table = new Table({
        table_id: table_id,
        user_data: user_data
      });
      var router = new TableRouter(table);
      // expose to debug
      window.table = table;
      Backbone.history.start();
    });

});
<|endoftext|>