<commit_before>'use strict';

module.exports = {
  app: {
    title: 'GalaJSy',
    description: 'Full-Stack JavaScript with MongoDB, Express, AngularJS, and Node.js',
    keywords: 'mongodb, express, angularjs, node.js, mongoose, passport',
    googleAnalyticsTrackingID: process.env.GOOGLE_ANALYTICS_TRACKING_ID || 'GOOGLE_ANALYTICS_TRACKING_ID'
  },
  db: {
    promise: global.Promise
  },
  port: process.env.PORT || 3000,
  host: process.env.HOST || '0.0.0.0',
  // DOMAIN config should be set to the fully qualified application accessible ec2-35-163-71-140.us-west-2.compute.amazonaws.com
  // URL. For example: https://www.myapp.com (including port if required).
  domain: 'https://galajsy.herokuapp.com',
  // Session Cookie settings
  sessionCookie: {
    // session expiration is set by default to 24 hours
    maxAge: 24 * (60 * 60 * 1000),
    // httpOnly flag makes sure the cookie is only accessed
    // through the HTTP protocol and not JS/browser
    httpOnly: true,
    // secure cookie should be turned to true to provide additional
    // layer of security so that the cookie is set only when working
    // in HTTPS mode.
    secure: false
  },
  // sessionSecret should be changed for security measures and concerns
  sessionSecret: process.env.SESSION_SECRET || 'GALAJSY',
  // sessionKey is the cookie session name
  sessionKey: 'sessionId',
  sessionCollection: 'sessions',
  // Lusca config
  csrf: {
    csrf: false,
    csp: false,
    xframe: 'SAMEORIGIN',
    p3p: 'ABCDEF',
    xssProtection: true
  },
  logo: 'modules/core/client/img/brand/logo.png',
  favicon: 'modules/core/client/img/brand/favicon.ico',
  illegalUsernames: ['meanjs', 'administrator', 'password', 'admin', 'user',
    'unknown', 'anonymous', 'null', 'undefined', 'api'
  ],
  uploads: {
    profile: {
      image: {
        dest: './modules/users/client/img/profile/uploads/',
        limits: {
          fileSize: 1 * 1024 * 1024 // Max file size in bytes (1 MB)
        }
      }
    }
  },
  shared: {
    owasp: {
      allowPassphrases: true,
      maxLength: 128,
      minLength: 10,
      minPhraseLength: 20,
      minOptionalTestsToPass: 4
    }
  }

};
<commit_msg>ignore<commit_after>'use strict';

module.exports = {
  app: {
    title: 'GalaJSy',
    description: 'Full-Stack JavaScript with MongoDB, Express, AngularJS, and Node.js',
    keywords: 'mongodb, express, angularjs, node.js, mongoose, passport',
    googleAnalyticsTrackingID: process.env.GOOGLE_ANALYTICS_TRACKING_ID || 'GOOGLE_ANALYTICS_TRACKING_ID'
  },
  db: {
    promise: global.Promise
  },
  port: process.env.PORT || 3000,
  host: process.env.HOST || 'localhost',
  // DOMAIN config should be set to the fully qualified application accessible ec2-35-163-71-140.us-west-2.compute.amazonaws.com
  // URL. For example: https://www.myapp.com (including port if required).
  domain: process.env.DOMAIN,
  // Session Cookie settings
  sessionCookie: {
    // session expiration is set by default to 24 hours
    maxAge: 24 * (60 * 60 * 1000),
    // httpOnly flag makes sure the cookie is only accessed
    // through the HTTP protocol and not JS/browser
    httpOnly: true,
    // secure cookie should be turned to true to provide additional
    // layer of security so that the cookie is set only when working
    // in HTTPS mode.
    secure: false
  },
  // sessionSecret should be changed for security measures and concerns
  sessionSecret: process.env.SESSION_SECRET || 'GALAJSY',
  // sessionKey is the cookie session name
  sessionKey: 'sessionId',
  sessionCollection: 'sessions',
  // Lusca config
  csrf: {
    csrf: false,
    csp: false,
    xframe: 'SAMEORIGIN',
    p3p: 'ABCDEF',
    xssProtection: true
  },
  logo: 'modules/core/client/img/brand/logo.png',
  favicon: 'modules/core/client/img/brand/favicon.ico',
  illegalUsernames: ['meanjs', 'administrator', 'password', 'admin', 'user',
    'unknown', 'anonymous', 'null', 'undefined', 'api'
  ],
  uploads: {
    profile: {
      image: {
        dest: './modules/users/client/img/profile/uploads/',
        limits: {
          fileSize: 1 * 1024 * 1024 // Max file size in bytes (1 MB)
        }
      }
    }
  },
  shared: {
    owasp: {
      allowPassphrases: true,
      maxLength: 128,
      minLength: 10,
      minPhraseLength: 20,
      minOptionalTestsToPass: 4
    }
  }

};
<|endoftext|>


<commit_before>'use strict';

/* Directives */

angular.module('WanderApp.directives', ['ngCookies']).
  directive('appVersion', ['version', function(version) {
    return function(scope, elm, attrs) {
      elm.text(version);
    };
  }])
  .directive('dragMan', function() {
    return {
      restrict: 'A',
      link: function(scope, elm, attrs) {
        var options = {};
        elm.addClass('touch');
        if(scope.$eval(attrs.dragMan)) options = scope.$eval(attrs.dragMan); //allow options to be passed in
        options.revert = 'invalid';
        options.scroll = false;
        options.revertDuration = 200;
        elm.draggable(options);
      }
    };
  })
  .directive('mapDroppable', function() {
    return {
      restrict: 'A',
      link: function(scope, elm, attrs) {
        var options = scope.$eval(attrs.mapDroppable); //allow options to be passed in
        options.drop = function(event, ui) {
          scope.loadPlacesByPosition(event.pageX, event.pageY);
          ui.draggable.draggable('option', 'revert', true);
        };
        elm.droppable(options);
      }
    };
  })
  .directive('fbButton',['Facebook', '$cookies', function(FB, $cookies){
  	return {
            restrict: 'E',
            template: 'Login to Facebook',
            link: function(scope, element, attrs) {
            	element.bind('click', function(e) {
          			FB.login();
            	});
           }
       }
  }])

  .directive('stopEvent', function() {
    return {
      restrict: 'E',
      link: function(scope, element, attrs) {
        element.bind(attr.stopEvent, function(e) {
          e.stopPropagation();
        })
      }
    }
  })

  .directive('experienceStream', ['$timeout','$compile', '$http', 'Facebook', function($timeout, $compile, $http,  FB) {
   return {
        scope: true,
        restrict: 'E',
        templateUrl: '/resources/partials/experienceStream.html',
        link: function(scope, element, attrs){
          var nextPage;
          var currentPage;
          var loadingPage = false;

          scope.$on('init_region', initRegion);
          scope.$on('close_stream', closeStream);
          scope.$on('load_more_places', loadMorePlaces);

          function initRegion(event, region) {
            scope.places = [];

            if(region.data && region.data.length > 0) {
              var data = region.data;
              addPlacesToRegion(region);
              openStream();
            } else {
              alert('This region has no places!');
            }

            if(region.paging) {
              nextPage = region.paging.next;
            }

            scope.$apply();
          };

          // When given a response, add the places from the response to this scope
          function addPlacesToRegion(response) {
            if(response.data) {
              var data = response.data;
              scope.places = scope.places.concat(data);
              for (var i = data.length - 1; i >= 0; i--) {
                FB.getPhotosFromPlace(data[i].id, function(response) {
                    // Broadcast the response
                    scope.$broadcast('incoming_photos_'+response.place, response);
                });
              }
            }

            if(response.paging && response.paging.next) {
              nextPage = response.paging.next;
            } else {
              nextPage = undefined;
            }
            loadingPage = false;
          }

          function loadMorePlaces() {
            if(!loadingPage && nextPage) {
              loadingPage = true;
              $http.get(nextPage).success(addPlacesToRegion).error(function(response) {
                loadingPage = false;
              });
            }
          }
          function openStream() {
            scope.showStream = true;
            scope.close = closeStream;
          }
          function closeStream() {
            scope.showStream = false;
          }
        }
   };
 }])
  .directive('experienceGallery', ['$timeout','$compile', function($timeout, $compile) {
   return {
        restrict: 'E',
        templateUrl: '/resources/partials/experienceGallery.html',
        link: function(scope, element, attrs){
          var container = element.find('.experience-gallery');
          // Reset the scroll position when a new place has been initialized
          scope.$on('init_region', function() { container.scrollLeft(0) });
          // Infinite scroll - when horizontal scrollbar reaches specific percent, send an emit to get more places
          container.bind('scroll', function(event) {
            var scrollLeft = container.scrollLeft();
            var scrollWidth = container[0].scrollWidth - container.width();
            if(scrollLeft/scrollWidth > 0.75) {
              scope.$emit('load_more_places', true);
            }
          });
        }
   };
  }])

  .directive('fbPlace', ['Facebook', function(FB) {
    return {
      scope: {
        place : "=fbPlace"
      },
      restrict: 'A',
      link: function(scope, element, attrs) {
        // On new photo event, call handlePhotos function
        scope.photos = [];
        scope.place.loaded = false;
        //Flag on whether or not photos are currently being added;
        var loadingPhotos = false;
        var photoContainer =  element.find('.content-container');

        scope.$on('incoming_photos_'+scope.place.id, handlePhotos);
        photoContainer.bind('scroll', scrollHandler);

        function scrollHandler(event) {
            var scrollTop = photoContainer.scrollTop();
            var scrollHeight = photoContainer[0].scrollHeight - photoContainer.height();
            if(!loadingPhotos && scrollTop/scrollHeight > 0.75) {
              loadingPhotos = true;
              FB.getMorePhotosFromPlace(scope.place.id, scope.photos.length, function(response) {
                handlePhotos(null, response);
              });
            }
        }

        function handlePhotos(event, photos) {
          if(!scope.place.loaded) scope.place.loaded = true;
          // Handles new photos and places it into this scope
          if(photos.data.length > 0) {
            scope.photos = scope.photos.concat(photos.data);
          } else {
            photoContainer.unbind('scroll', scrollHandler);
          }

          scope.$apply();
        }

      }
    }
  }])

  .directive('itinerary', ['$timeout','$compile', function($timeout, $compile) {
   return {
        restrict: 'E',
        templateUrl: '/resources/partials/itinerary.html',
        controller: ItineraryCtrl,
        link: function(scope, element, attrs){
          //
        }
   };
 }])

  .directive('itineraryIcon', ['$timeout','$compile', function($timeout, $compile) {
   return {
        restrict: 'E',
        templateUrl: '/resources/partials/itineraryIcon.html',
        link: function(scope, element, attrs){
          //
        }
   };
 }])
  .directive('draggablePhoto', function() {
    return {
      restrict: 'A',
      link: function(scope, elm, attrs) {
        var options = {};
        scope.$on('get_new_photo_' + scope.photo.object_id, getNewPhoto);
        elm.addClass('touch');
        if(scope.$eval(attrs.draggablePhoto)) options = scope.$eval(attrs.dragMan); //allow options to be passed in
        options.revert = 'invalid';
        options.scroll = false;
        options.revertDuration = 200;

        elm.draggable(options).click(function() {
            if ( $(this).is('.ui-draggable-dragging') ) {
              return;
            }
            // click action here
            scope.$emit('showcase_init', scope.place, scope.photo);
        });

        function getNewPhoto(event, type) {
          var index = scope.photos.indexOf(scope.photo);
          if(index != -1) {
            // If the index is the last one, reset to the first of this place
            if(type == 'next') {
              if(index < scope.photos.length - 1) {
                index++;
              } else {
                index = 0;
              }
            } else {
              if(index > 0) {
                index--;
              } else {
                index = scope.photos.length - 1;
              }
            }
          } else {
            alert('Photo does not exist');
          }

          var newPhoto = scope.photos[index];
          scope.$emit('new_showcase_photo', newPhoto);
          scope.$apply();
        }
      }
    };
  })
  .directive('photoShowcase', ['$timeout','$compile', 'Facebook', function($timeout, $compile, FB) {
   return {
        restrict: 'E',
        templateUrl: '/resources/partials/showcase.html',
        link: function(scope, element, attrs){
          scope.showcase = {};
          scope.showcase.show = false;
          scope.$on('showcase_init', initShowcase);
          scope.$on('new_showcase_photo', displayPhoto);

          // Bind a swipe event to handle swiping to next/previous photo
          element.swipe({
            swipe : function(event, direction, distance, duration, fingerCount) {
              switch(direction) {
                case 'left':
                  getNewPhoto(scope.showcase.photo.object_id, 'next');
                  break;
                case 'right':
                  getNewPhoto(scope.showcase.photo.object_id, 'prev');
                  break;
              }
            }
          });

          // Bind a 'tap' event to the arrows to go next and previous
          element.find('.showcase-inner .rightarrow').swipe({
            tap : function( event, target) {
              getNewPhoto(scope.showcase.photo.object_id, 'next');
            }
          });

          element.find('.showcase-inner .leftarrow').swipe({
            tap : function( event, target) {
              getNewPhoto(scope.showcase.photo.object_id, 'prev');
            }
          });

          // Bind a 'tap' event to the outer container to handle when the user clicks on the outer container rather than swipes
          element.find('.showcase-outer').swipe({
            tap : function(event, target) {
              closeShowcase();
            }
          });

          function closeShowcase() {
            // Clear the scope, hide the lightbox and remove close showcase functionality
            scope.showcase = {};
            scope.showcase.show = false;
            scope.$apply();
            delete scope.closeShowcase;
            delete scope.getNewPhoto;
            // Remove blur class - depreciated, IE10 does not support blur
            // element.next().removeClass('blur');
            // element.next().next().removeClass('blur');
          }

          function getNewPhoto(photoId, type) {
            scope.$broadcast('get_new_photo_' + photoId, type);
          }

          function displayPhoto(event, photo) {
            FB.getUser(photo.owner, function(response) {
              if(scope.showcase){
                scope.showcase.user = {};
                scope.showcase.user.fullName = response.name;
              }
              scope.$apply();
            });
            scope.showcase.photo = photo;
          }

          function initShowcase(event, place, photo) {
            // Initiate closing the showcase
            scope.closeShowcase = closeShowcase;
            scope.getNewPhoto = getNewPhoto;

            // Display the photo
            displayPhoto(null, photo);
            scope.showcase.place = place;
            scope.showcase.show = true;
            scope.$apply();

            //Add blur to the elements behind - depreciated, IE10 does not support blur
            // element.next().addClass('blur');
            // element.next().next().addClass('blur');
          }
        }
   };
 }]);<commit_msg>scope.$apply fix<commit_after>'use strict';

/* Directives */

angular.module('WanderApp.directives', ['ngCookies']).
  directive('appVersion', ['version', function(version) {
    return function(scope, elm, attrs) {
      elm.text(version);
    };
  }])
  .directive('dragMan', function() {
    return {
      restrict: 'A',
      link: function(scope, elm, attrs) {
        var options = {};
        elm.addClass('touch');
        if(scope.$eval(attrs.dragMan)) options = scope.$eval(attrs.dragMan); //allow options to be passed in
        options.revert = 'invalid';
        options.scroll = false;
        options.revertDuration = 200;
        elm.draggable(options);
      }
    };
  })
  .directive('mapDroppable', function() {
    return {
      restrict: 'A',
      link: function(scope, elm, attrs) {
        var options = scope.$eval(attrs.mapDroppable); //allow options to be passed in
        options.drop = function(event, ui) {
          scope.loadPlacesByPosition(event.pageX, event.pageY);
          ui.draggable.draggable('option', 'revert', true);
        };
        elm.droppable(options);
      }
    };
  })
  .directive('fbButton',['Facebook', '$cookies', function(FB, $cookies){
  	return {
            restrict: 'E',
            template: 'Login to Facebook',
            link: function(scope, element, attrs) {
            	element.bind('click', function(e) {
          			FB.login();
            	});
           }
       }
  }])

  .directive('stopEvent', function() {
    return {
      restrict: 'E',
      link: function(scope, element, attrs) {
        element.bind(attr.stopEvent, function(e) {
          e.stopPropagation();
        })
      }
    }
  })

  .directive('experienceStream', ['$timeout','$compile', '$http', 'Facebook', function($timeout, $compile, $http,  FB) {
   return {
        scope: true,
        restrict: 'E',
        templateUrl: '/resources/partials/experienceStream.html',
        link: function(scope, element, attrs){
          var nextPage;
          var currentPage;
          var loadingPage = false;

          scope.$on('init_region', initRegion);
          scope.$on('close_stream', closeStream);
          scope.$on('load_more_places', loadMorePlaces);

          function initRegion(event, region) {
            scope.places = [];

            if(region.data && region.data.length > 0) {
              var data = region.data;
              addPlacesToRegion(region);
              openStream();
            } else {
              alert('This region has no places!');
            }

            if(region.paging) {
              nextPage = region.paging.next;
            }

            scope.$apply();
          };

          // When given a response, add the places from the response to this scope
          function addPlacesToRegion(response) {
            if(response.data) {
              var data = response.data;
              scope.places = scope.places.concat(data);
              for (var i = data.length - 1; i >= 0; i--) {
                FB.getPhotosFromPlace(data[i].id, function(response) {
                    // Broadcast the response
                    scope.$broadcast('incoming_photos_'+response.place, response);
                });
              }
            }

            if(response.paging && response.paging.next) {
              nextPage = response.paging.next;
            } else {
              nextPage = undefined;
            }
            loadingPage = false;
          }

          function loadMorePlaces() {
            if(!loadingPage && nextPage) {
              loadingPage = true;
              $http.get(nextPage).success(addPlacesToRegion).error(function(response) {
                loadingPage = false;
              });
            }
          }
          function openStream() {
            scope.showStream = true;
            scope.close = closeStream;
          }
          function closeStream() {
            scope.showStream = false;
          }
        }
   };
 }])
  .directive('experienceGallery', ['$timeout','$compile', function($timeout, $compile) {
   return {
        restrict: 'E',
        templateUrl: '/resources/partials/experienceGallery.html',
        link: function(scope, element, attrs){
          var container = element.find('.experience-gallery');
          // Reset the scroll position when a new place has been initialized
          scope.$on('init_region', function() { container.scrollLeft(0) });
          // Infinite scroll - when horizontal scrollbar reaches specific percent, send an emit to get more places
          container.bind('scroll', function(event) {
            var scrollLeft = container.scrollLeft();
            var scrollWidth = container[0].scrollWidth - container.width();
            if(scrollLeft/scrollWidth > 0.75) {
              scope.$emit('load_more_places', true);
            }
          });
        }
   };
  }])

  .directive('fbPlace', ['Facebook', function(FB) {
    return {
      scope: {
        place : "=fbPlace"
      },
      restrict: 'A',
      link: function(scope, element, attrs) {
        // On new photo event, call handlePhotos function
        scope.photos = [];
        scope.place.loaded = false;
        //Flag on whether or not photos are currently being added;
        var loadingPhotos = false;
        var photoContainer =  element.find('.content-container');

        scope.$on('incoming_photos_'+scope.place.id, handlePhotos);
        photoContainer.bind('scroll', scrollHandler);

        function scrollHandler(event) {
            var scrollTop = photoContainer.scrollTop();
            var scrollHeight = photoContainer[0].scrollHeight - photoContainer.height();
            if(!loadingPhotos && scrollTop/scrollHeight > 0.75) {
              loadingPhotos = true;
              FB.getMorePhotosFromPlace(scope.place.id, scope.photos.length, function(response) {
                handlePhotos(null, response);
              });
            }
        }

        function handlePhotos(event, photos) {
          if(!scope.place.loaded) scope.place.loaded = true;
          // Handles new photos and places it into this scope
          if(photos.data.length > 0) {
            scope.photos = scope.photos.concat(photos.data);
          } else {
            photoContainer.unbind('scroll', scrollHandler);
          }

          scope.$apply();
        }

      }
    }
  }])

  .directive('itinerary', ['$timeout','$compile', function($timeout, $compile) {
   return {
        restrict: 'E',
        templateUrl: '/resources/partials/itinerary.html',
        controller: ItineraryCtrl,
        link: function(scope, element, attrs){
          //
        }
   };
 }])

  .directive('itineraryIcon', ['$timeout','$compile', function($timeout, $compile) {
   return {
        restrict: 'E',
        templateUrl: '/resources/partials/itineraryIcon.html',
        link: function(scope, element, attrs){
          //
        }
   };
 }])
  .directive('draggablePhoto', function() {
    return {
      restrict: 'A',
      link: function(scope, elm, attrs) {
        var options = {};
        scope.$on('get_new_photo_' + scope.photo.object_id, getNewPhoto);
        elm.addClass('touch');
        if(scope.$eval(attrs.draggablePhoto)) options = scope.$eval(attrs.dragMan); //allow options to be passed in
        options.revert = 'invalid';
        options.scroll = false;
        options.revertDuration = 200;

        elm.draggable(options).click(function() {
            if ( $(this).is('.ui-draggable-dragging') ) {
              return;
            }
            // click action here
            scope.$emit('showcase_init', scope.place, scope.photo);
        });

        function getNewPhoto(event, type) {
          var index = scope.photos.indexOf(scope.photo);
          if(index != -1) {
            // If the index is the last one, reset to the first of this place
            if(type == 'next') {
              if(index < scope.photos.length - 1) {
                index++;
              } else {
                index = 0;
              }
            } else {
              if(index > 0) {
                index--;
              } else {
                index = scope.photos.length - 1;
              }
            }
          } else {
            alert('Photo does not exist');
          }

          var newPhoto = scope.photos[index];
          scope.$emit('new_showcase_photo', newPhoto);
          scope.$apply();
        }
      }
    };
  })
  .directive('photoShowcase', ['$timeout','$compile', 'Facebook', function($timeout, $compile, FB) {
   return {
        restrict: 'E',
        templateUrl: '/resources/partials/showcase.html',
        link: function(scope, element, attrs){
          scope.showcase = {};
          scope.showcase.show = false;
          scope.$on('showcase_init', initShowcase);
          scope.$on('new_showcase_photo', displayPhoto);

          // Bind a swipe event to handle swiping to next/previous photo
          element.swipe({
            swipe : function(event, direction, distance, duration, fingerCount) {
              switch(direction) {
                case 'left':
                  getNewPhoto(scope.showcase.photo.object_id, 'next');
                  break;
                case 'right':
                  getNewPhoto(scope.showcase.photo.object_id, 'prev');
                  break;
              }
            }
          });

          // Bind a 'tap' event to the arrows to go next and previous
          element.find('.showcase-inner .rightarrow').swipe({
            tap : function( event, target) {
              getNewPhoto(scope.showcase.photo.object_id, 'next');
            }
          });

          element.find('.showcase-inner .leftarrow').swipe({
            tap : function( event, target) {
              getNewPhoto(scope.showcase.photo.object_id, 'prev');
            }
          });

          // Bind a 'tap' event to the outer container to handle when the user clicks on the outer container rather than swipes
          element.find('.showcase-outer').swipe({
            tap : function(event, target) {
              closeShowcase();
            }
          });

          function closeShowcase() {
            // Clear the scope, hide the lightbox and remove close showcase functionality
            scope.showcase = {};
            scope.showcase.show = false;
            scope.$apply();
            delete scope.closeShowcase;
            delete scope.getNewPhoto;
            // Remove blur class - depreciated, IE10 does not support blur
            // element.next().removeClass('blur');
            // element.next().next().removeClass('blur');
          }

          function getNewPhoto(photoId, type) {
            scope.$broadcast('get_new_photo_' + photoId, type);
            scope.$apply();
          }

          function displayPhoto(event, photo) {
            FB.getUser(photo.owner, function(response) {
              if(scope.showcase){
                scope.showcase.user = {};
                scope.showcase.user.fullName = response.name;
              }
              scope.$apply();
            });
            scope.showcase.photo = photo;
          }

          function initShowcase(event, place, photo) {
            // Initiate closing the showcase
            scope.closeShowcase = closeShowcase;
            scope.getNewPhoto = getNewPhoto;

            // Display the photo
            displayPhoto(null, photo);
            scope.showcase.place = place;
            scope.showcase.show = true;
            scope.$apply();

            //Add blur to the elements behind - depreciated, IE10 does not support blur
            // element.next().addClass('blur');
            // element.next().next().addClass('blur');
          }
        }
   };
 }]);<|endoftext|>


<commit_before>//This is the loading element that tells the user to wait.
var loadingDiv = document.querySelector("#loading");
//This is the contests element that shows info on all of the contests.
var contestsDiv = document.querySelector("#contests");

function finishRequest(contests) {
    /* When the request is finished... */

    //Loop through contests
    for (var i in contests) {
        //The JSON object corresponding to this contest.
        var curr = contests[i];

        /* When done with AJAX request */
        //http://getbootstrap.com/components/#media-default

        //Create row for this contest
        var rowDiv = document.createElement("div");
        rowDiv.className = "row";
        //Create div inside rowDiv for this contest
        var contestDiv = document.createElement("div");
        contestDiv.className = "contest";
        //Create div inside contestDiv
        var mediaDiv = document.createElement("div");
        mediaDiv.className = "media";

        //Create div containing link and image
        var mediaLeftDiv = document.createElement("div");
        mediaLeftDiv.className = "media-left";
        //Create the link to the contest
        var imgLink = document.createElement("a");
        imgLink.href = "https://www.khanacademy.org/computer-programming/contest/" + curr.id;
        //Create the image that will go in our link
        var mediaObject = document.createElement("img");
        mediaObject.className = "media-object";
        mediaObject.src = "https://www.khanacademy.org" + curr.img;

        var viewEntriesBtn = document.createElement("a");
        viewEntriesBtn.className = "btn btn-sm btn-primary center-block viewEntries";
        viewEntriesBtn.textContent = "View 30 Random Entries";
        viewEntriesBtn.href = "contest.html?contest=" + curr.id + "&entries=30";

        var viewAllEntriesBtn = document.createElement("a");
        viewAllEntriesBtn.className = "btn btn-sm btn-primary center-block";
        viewAllEntriesBtn.textContent = "View all " + curr.entryCount + " Entries";
        viewAllEntriesBtn.href = "contest.html?contest=" + curr.id + "&entries=all";

        //Create the div containing the body of contest info
        var mediaBody = document.createElement("div");
        mediaBody.className = "media-body";
        //Create the div containing the contest heading
        var mediaHeading = document.createElement("h4");
        mediaHeading.className = "media-heading";
        mediaHeading.textContent = curr.name;
        var mediaSmall = document.createElement("small");
        mediaSmall.textContent = " (" + curr.entryCount + " entries)";
        //Create the div containing the contest details
        var detailsDiv = document.createElement("div");
        detailsDiv.className = "details";
        detailsDiv.innerHTML = curr.desc || "No description provided!";

        //Put image inside link
        imgLink.appendChild(mediaObject);
        //Put link inside mediaLeftDiv
        mediaLeftDiv.appendChild(imgLink);
        /* Put button into mediaLeftDiv */
        if (curr.entryCount > 30) {
            mediaLeftDiv.appendChild(viewEntriesBtn);
        }
        mediaLeftDiv.appendChild(viewAllEntriesBtn);

        //Put heading inside body
        mediaHeading.appendChild(mediaSmall);
        mediaBody.appendChild(mediaHeading);
        //Put body inside detailsDiv
        mediaBody.appendChild(detailsDiv);

        //Put mediaLeftDiv and mediaBody inside mediaDiv
        mediaDiv.appendChild(mediaLeftDiv);
        mediaDiv.appendChild(mediaBody);

        //Put mediaDiv inside contestDiv
        contestDiv.appendChild(mediaDiv);
        //Put contestDiv inside rowDiv
        rowDiv.appendChild(contestDiv);
        //Put rowDiv inside the #contests div
        contestsDiv.appendChild(rowDiv);
    }

    //Now we're done, so get rid of the loading screen.
    loadingDiv.style.display = "none";
}

//Get all of the stored contests from the Firebase database and call finishRequest when done
Contest_Judging_System.getStoredContests(finishRequest);<commit_msg>Cleaned up some comments in main.js<commit_after>/* This is the loading element that tells the user to wait. */
var loadingDiv = document.querySelector("#loading");
/* This is the contests element that shows info on all of the contests. */
var contestsDiv = document.querySelector("#contests");

function finishRequest(contests) {
    /* When the request is finished... */

    //Loop through contests
    for (var i in contests) {
        /* The JSON object corresponding to this contest. */
        var curr = contests[i];

        /* When done with AJAX request */
        /* http://getbootstrap.com/components/#media-default */

        /* Create row for this contest */
        var rowDiv = document.createElement("div");
        rowDiv.className = "row";
        /* Create div inside rowDiv for this contest */
        var contestDiv = document.createElement("div");
        contestDiv.className = "contest";
        /* Create div inside contestDiv */
        var mediaDiv = document.createElement("div");
        mediaDiv.className = "media";

        /* Create div containing link and image */
        var mediaLeftDiv = document.createElement("div");
        mediaLeftDiv.className = "media-left";
        /* Create the link to the contest */
        var imgLink = document.createElement("a");
        imgLink.href = "https://www.khanacademy.org/computer-programming/contest/" + curr.id;
        /* Create the image that will go in our link */
        var mediaObject = document.createElement("img");
        mediaObject.className = "media-object";
        mediaObject.src = "https://www.khanacademy.org" + curr.img;

        var viewEntriesBtn = document.createElement("a");
        viewEntriesBtn.className = "btn btn-sm btn-primary center-block viewEntries";
        viewEntriesBtn.textContent = "View 30 Random Entries";
        viewEntriesBtn.href = "contest.html?contest=" + curr.id + "&entries=30";

        var viewAllEntriesBtn = document.createElement("a");
        viewAllEntriesBtn.className = "btn btn-sm btn-primary center-block";
        viewAllEntriesBtn.textContent = "View all " + curr.entryCount + " Entries";
        viewAllEntriesBtn.href = "contest.html?contest=" + curr.id + "&entries=all";

        /* Create the div containing the body of contest info */
        var mediaBody = document.createElement("div");
        mediaBody.className = "media-body";
        /* Create the div containing the contest heading */
        var mediaHeading = document.createElement("h4");
        mediaHeading.className = "media-heading";
        mediaHeading.textContent = curr.name;
        var mediaSmall = document.createElement("small");
        mediaSmall.textContent = " (" + curr.entryCount + " entries)";
        /* Create the div containing the contest details */
        var detailsDiv = document.createElement("div");
        detailsDiv.className = "details";
        detailsDiv.innerHTML = curr.desc || "No description provided!";

        /* Put image inside link */
        imgLink.appendChild(mediaObject);
        /* Put link inside mediaLeftDiv */
        mediaLeftDiv.appendChild(imgLink);
        /* Put button into mediaLeftDiv */
        if (curr.entryCount > 30) {
            mediaLeftDiv.appendChild(viewEntriesBtn);
        }
        mediaLeftDiv.appendChild(viewAllEntriesBtn);

        //Put heading inside body
        mediaHeading.appendChild(mediaSmall);
        mediaBody.appendChild(mediaHeading);
        //Put body inside detailsDiv
        mediaBody.appendChild(detailsDiv);

        //Put mediaLeftDiv and mediaBody inside mediaDiv
        mediaDiv.appendChild(mediaLeftDiv);
        mediaDiv.appendChild(mediaBody);

        //Put mediaDiv inside contestDiv
        contestDiv.appendChild(mediaDiv);
        //Put contestDiv inside rowDiv
        rowDiv.appendChild(contestDiv);
        //Put rowDiv inside the #contests div
        contestsDiv.appendChild(rowDiv);
    }

    //Now we're done, so get rid of the loading screen.
    loadingDiv.style.display = "none";
}

//Get all of the stored contests from the Firebase database and call finishRequest when done
Contest_Judging_System.getStoredContests(finishRequest);<|endoftext|>


<commit_before>'use strict';

/**
 * Module dependencies.
 */
var bodyParser = require('body-parser'),
  compress = require('compression'),
  config = require('../config'),
  consolidate = require('consolidate'),
  cookieParser = require('cookie-parser'),
  express = require('express'),
  flash = require('connect-flash'),
  favicon = require('serve-favicon'),
  helmet = require('helmet'),
  logger = require('./logger'),
  methodOverride = require('method-override'),
  morgan = require('morgan'),
  path = require('path'),
  session = require('express-session'),
  SequelizeStore = require('connect-session-sequelize')(session.Store);

/**
 * Initialize local variables
 *
 */
module.exports.initLocalVariables = function(app) {
  // Setting application local variables
  app.locals.title = config.app.title;
  app.locals.description = config.app.description;
  if (config.secure && config.secure.ssl === true) {
    app.locals.secure = config.secure.ssl;
  }
  app.locals.keywords = config.app.keywords;
  app.locals.googleAnalyticsTrackingID = config.app.googleAnalyticsTrackingID;
  app.locals.facebookAppId = config.facebook.clientID;
  app.locals.jsFiles = config.files.client.js;
  app.locals.cssFiles = config.files.client.css;
  app.locals.livereload = config.livereload;
  app.locals.logo = config.logo;
  app.locals.favicon = config.favicon;

  // Passing the request url to environment locals
  app.use(function(req, res, next) {
    res.locals.host = req.protocol + '://' + req.hostname;
    res.locals.url = req.protocol + '://' + req.headers.host + req.originalUrl;
    next();
  });
};

/**
 * Initialize application middleware
 */
module.exports.initMiddleware = function(app) {
  // Showing stack errors
  app.set('showStackError', true);

  // Enable jsonp
  app.enable('jsonp callback');

  // Should be placed before express.static
  app.use(compress({
    filter: function(req, res) {
      return (/json|text|javascript|css|font|svg/).test(res.getHeader('Content-Type'));
    },
    level: 9
  }));

  // Initialize favicon middleware
  app.use(favicon(app.locals.favicon));

  // Enable logger (morgan)
  app.use(morgan(logger.getFormat(), logger.getOptions()));

  // Environment dependent middleware
  if (process.env.NODE_ENV === 'development') {
    // Disable views cache
    app.set('view cache', false);
  } else if (process.env.NODE_ENV === 'production') {
    app.locals.cache = 'memory';
  }

  // Request body parsing middleware should be above methodOverride
  app.use(bodyParser.urlencoded({
    extended: true
  }));
  app.use(bodyParser.json());
  app.use(methodOverride());

  // Add the cookie parser and flash middleware
  app.use(cookieParser());
  app.use(flash());
};

/**
 * Configure view engine
 */
module.exports.initViewEngine = function(app) {
  // Set swig as the template engine
  app.engine('server.view.html', consolidate[config.templateEngine]);

  // Set views path and view engine
  app.set('view engine', 'server.view.html');
  app.set('views', './');
};

/**
 * Configure Express session
 */
module.exports.initSession = function(app, db) {

  var sequelizeStore = new SequelizeStore({
    db: db
  });

  sequelizeStore.sync();

  // Express session storage
  app.use(session({
    saveUninitialized: true,
    resave: true,
    secret: config.sessionSecret,
    cookie: {
      maxAge: config.sessionExpiration,
      httpOnly: config.sessionCookie.httpOnly,
      secure: config.sessionCookie.secure && config.secure.ssl
    },
    key: config.sessionKey,
    store: sequelizeStore
  }));
};

/**
 * Invoke modules server configuration
 */
module.exports.initModulesConfiguration = function(app, db) {
  config.files.server.configs.forEach(function(configPath) {
    require(path.resolve(configPath))(app, db);
  });
};

/**
 * Configure Helmet headers configuration
 */
module.exports.initHelmetHeaders = function(app) {
  // Use helmet to secure Express headers
  var SIX_MONTHS = 15778476000;
  app.use(helmet.xframe());
  app.use(helmet.xssFilter());
  app.use(helmet.nosniff());
  app.use(helmet.ienoopen());
  app.use(helmet.hsts({
    maxAge: SIX_MONTHS,
    includeSubdomains: true,
    force: true
  }));
  app.disable('x-powered-by');
};

/**
 * Configure the modules static routes
 */
module.exports.initModulesClientRoutes = function(app) {
  // Setting the app router and static folder
  app.use('/', express.static(path.resolve('./public')));

  // Globbing static routing
  config.folders.client.forEach(function(staticPath) {
    app.use(staticPath, express.static(path.resolve('./' + staticPath)));
  });
};

/**
 * Configure the modules ACL policies
 */
module.exports.initModulesServerPolicies = function(app) {
  // Globbing policy files
  config.files.server.policies.forEach(function(policyPath) {
    require(path.resolve(policyPath)).invokeRolesPolicies();
  });
};

/**
 * Configure the modules server routes
 */
module.exports.initModulesServerRoutes = function(app) {
  // Globbing routing files
  config.files.server.routes.forEach(function(routePath) {
    require(path.resolve(routePath))(app);
  });
};

/**
 * Configure error handling
 */
module.exports.initErrorRoutes = function(app) {
  app.use(function(err, req, res, next) {
    // If the error object doesn't exists
    if (!err) {
      return next();
    }

    // Log it
    console.error(err.stack);

    // Redirect to error page
    res.redirect('/server-error');
  });
};

/**
 * Configure Socket.io
 */
module.exports.configureSocketIO = function(app, db) {
  // Load the Socket.io configuration
  var server = require('./socket.io')(app, db);

  // Return server object
  return server;
};

/**
 * Initialize the Express application
 */
module.exports.init = function(db) {
  // Initialize express app
  var app = express();

  // Initialize local variables
  this.initLocalVariables(app);

  // Initialize Express middleware
  this.initMiddleware(app);

  // Initialize Express view engine
  this.initViewEngine(app);

  // Initialize Helmet security headers
  this.initHelmetHeaders(app);

  // Initialize modules static client routes, before session!
  this.initModulesClientRoutes(app);

  // Initialize Express session
  this.initSession(app, db);

  // Initialize Modules configuration
  this.initModulesConfiguration(app);

  // Initialize modules server authorization policies
  this.initModulesServerPolicies(app);

  // Initialize modules server routes
  this.initModulesServerRoutes(app);

  // Initialize error routes
  this.initErrorRoutes(app);

  // Configure Socket.io
  app = this.configureSocketIO(app, db);

  return app;
};
<commit_msg>fix(config): Change Express "sessionExpiration" config reference<commit_after>'use strict';

/**
 * Module dependencies.
 */
var bodyParser = require('body-parser'),
  compress = require('compression'),
  config = require('../config'),
  consolidate = require('consolidate'),
  cookieParser = require('cookie-parser'),
  express = require('express'),
  flash = require('connect-flash'),
  favicon = require('serve-favicon'),
  helmet = require('helmet'),
  logger = require('./logger'),
  methodOverride = require('method-override'),
  morgan = require('morgan'),
  path = require('path'),
  session = require('express-session'),
  SequelizeStore = require('connect-session-sequelize')(session.Store);

/**
 * Initialize local variables
 *
 */
module.exports.initLocalVariables = function(app) {
  // Setting application local variables
  app.locals.title = config.app.title;
  app.locals.description = config.app.description;
  if (config.secure && config.secure.ssl === true) {
    app.locals.secure = config.secure.ssl;
  }
  app.locals.keywords = config.app.keywords;
  app.locals.googleAnalyticsTrackingID = config.app.googleAnalyticsTrackingID;
  app.locals.facebookAppId = config.facebook.clientID;
  app.locals.jsFiles = config.files.client.js;
  app.locals.cssFiles = config.files.client.css;
  app.locals.livereload = config.livereload;
  app.locals.logo = config.logo;
  app.locals.favicon = config.favicon;

  // Passing the request url to environment locals
  app.use(function(req, res, next) {
    res.locals.host = req.protocol + '://' + req.hostname;
    res.locals.url = req.protocol + '://' + req.headers.host + req.originalUrl;
    next();
  });
};

/**
 * Initialize application middleware
 */
module.exports.initMiddleware = function(app) {
  // Showing stack errors
  app.set('showStackError', true);

  // Enable jsonp
  app.enable('jsonp callback');

  // Should be placed before express.static
  app.use(compress({
    filter: function(req, res) {
      return (/json|text|javascript|css|font|svg/).test(res.getHeader('Content-Type'));
    },
    level: 9
  }));

  // Initialize favicon middleware
  app.use(favicon(app.locals.favicon));

  // Enable logger (morgan)
  app.use(morgan(logger.getFormat(), logger.getOptions()));

  // Environment dependent middleware
  if (process.env.NODE_ENV === 'development') {
    // Disable views cache
    app.set('view cache', false);
  } else if (process.env.NODE_ENV === 'production') {
    app.locals.cache = 'memory';
  }

  // Request body parsing middleware should be above methodOverride
  app.use(bodyParser.urlencoded({
    extended: true
  }));
  app.use(bodyParser.json());
  app.use(methodOverride());

  // Add the cookie parser and flash middleware
  app.use(cookieParser());
  app.use(flash());
};

/**
 * Configure view engine
 */
module.exports.initViewEngine = function(app) {
  // Set swig as the template engine
  app.engine('server.view.html', consolidate[config.templateEngine]);

  // Set views path and view engine
  app.set('view engine', 'server.view.html');
  app.set('views', './');
};

/**
 * Configure Express session
 */
module.exports.initSession = function(app, db) {

  var sequelizeStore = new SequelizeStore({
    db: db
  });

  sequelizeStore.sync();

  // Express session storage
  app.use(session({
    saveUninitialized: true,
    resave: true,
    secret: config.sessionSecret,
    cookie: {
      maxAge: config.sessionCookie.sessionExpiration,
      httpOnly: config.sessionCookie.httpOnly,
      secure: config.sessionCookie.secure && config.secure.ssl
    },
    key: config.sessionKey,
    store: sequelizeStore
  }));
};

/**
 * Invoke modules server configuration
 */
module.exports.initModulesConfiguration = function(app, db) {
  config.files.server.configs.forEach(function(configPath) {
    require(path.resolve(configPath))(app, db);
  });
};

/**
 * Configure Helmet headers configuration
 */
module.exports.initHelmetHeaders = function(app) {
  // Use helmet to secure Express headers
  var SIX_MONTHS = 15778476000;
  app.use(helmet.xframe());
  app.use(helmet.xssFilter());
  app.use(helmet.nosniff());
  app.use(helmet.ienoopen());
  app.use(helmet.hsts({
    maxAge: SIX_MONTHS,
    includeSubdomains: true,
    force: true
  }));
  app.disable('x-powered-by');
};

/**
 * Configure the modules static routes
 */
module.exports.initModulesClientRoutes = function(app) {
  // Setting the app router and static folder
  app.use('/', express.static(path.resolve('./public')));

  // Globbing static routing
  config.folders.client.forEach(function(staticPath) {
    app.use(staticPath, express.static(path.resolve('./' + staticPath)));
  });
};

/**
 * Configure the modules ACL policies
 */
module.exports.initModulesServerPolicies = function(app) {
  // Globbing policy files
  config.files.server.policies.forEach(function(policyPath) {
    require(path.resolve(policyPath)).invokeRolesPolicies();
  });
};

/**
 * Configure the modules server routes
 */
module.exports.initModulesServerRoutes = function(app) {
  // Globbing routing files
  config.files.server.routes.forEach(function(routePath) {
    require(path.resolve(routePath))(app);
  });
};

/**
 * Configure error handling
 */
module.exports.initErrorRoutes = function(app) {
  app.use(function(err, req, res, next) {
    // If the error object doesn't exists
    if (!err) {
      return next();
    }

    // Log it
    console.error(err.stack);

    // Redirect to error page
    res.redirect('/server-error');
  });
};

/**
 * Configure Socket.io
 */
module.exports.configureSocketIO = function(app, db) {
  // Load the Socket.io configuration
  var server = require('./socket.io')(app, db);

  // Return server object
  return server;
};

/**
 * Initialize the Express application
 */
module.exports.init = function(db) {
  // Initialize express app
  var app = express();

  // Initialize local variables
  this.initLocalVariables(app);

  // Initialize Express middleware
  this.initMiddleware(app);

  // Initialize Express view engine
  this.initViewEngine(app);

  // Initialize Helmet security headers
  this.initHelmetHeaders(app);

  // Initialize modules static client routes, before session!
  this.initModulesClientRoutes(app);

  // Initialize Express session
  this.initSession(app, db);

  // Initialize Modules configuration
  this.initModulesConfiguration(app);

  // Initialize modules server authorization policies
  this.initModulesServerPolicies(app);

  // Initialize modules server routes
  this.initModulesServerRoutes(app);

  // Initialize error routes
  this.initErrorRoutes(app);

  // Configure Socket.io
  app = this.configureSocketIO(app, db);

  return app;
};
<|endoftext|>


<commit_before>import Bluebird, {promisify} from 'bluebird'
import Collection from 'xo-collection'
import createDebug from 'debug'
import forEach from 'lodash.foreach'
import startsWith from 'lodash.startswith'
import {BaseError} from 'make-error'
import {
  createClient as createXmlRpcClient,
  createSecureClient as createSecureXmlRpcClient
} from 'xmlrpc'
import {EventEmitter} from 'events'

const debug = createDebug('xen-api')

// ===================================================================

// http://www.gnu.org/software/libc/manual/html_node/Error-Codes.html
const NETWORK_ERRORS = {
  // Connection has been closed outside of our control.
  ECONNRESET: true,

  // Connection has been aborted locally.
  ECONNABORTED: true,

  // Host is up but refuses connection (typically: no such service).
  ECONNREFUSED: true,

  // TODO: ??
  EINVAL: true,

  // Host is not reachable (does not respond).
  EHOSTUNREACH: true,

  // Connection configured timed out has been reach.
  ETIMEDOUT: true
}

const isNetworkError = (error) => NETWORK_ERRORS[error.code]

// -------------------------------------------------------------------

const XAPI_NETWORK_ERRORS = {
  HOST_STILL_BOOTING: true,
  HOST_HAS_NO_MANAGEMENT_IP: true
}

const isXapiNetworkError = (error) => XAPI_NETWORK_ERRORS[error.code]

// -------------------------------------------------------------------

const areEventsLost = (error) => error.code === 'EVENTS_LOST'

const isHostSlave = (error) => error.code === 'HOST_IS_SLAVE'

const isSessionInvalid = (error) => error.code === 'SESSION_INVALID'

// -------------------------------------------------------------------

class XapiError extends BaseError {
  constructor (error) {
    super(error[0])

    this.code = error[0]
    this.params = error.slice(1)
  }
}

export const wrapError = error => new XapiError(error)

// ===================================================================

const URL_RE = /^(http(s)?:\/\/)?([^/]+?)(?::([0-9]+))?(?:\/.*)?$/
function parseUrl (url) {
  const matches = URL_RE.exec(url)
  if (!matches) {
    throw new Error('invalid URL: ' + url)
  }

  const [, protocol, , host, port] = matches
  let [, , isSecure] = matches

  if (!protocol) {
    isSecure = true
  }

  return {
    isSecure: Boolean(isSecure),
    host,
    port: port !== undefined ?
      +port :
      isSecure ? 443 : 80
  }
}

// -------------------------------------------------------------------

const noop = () => {}

// -------------------------------------------------------------------

const notConnectedPromise = Bluebird.reject(new Error('not connected'))

// Does nothing but avoid a Bluebird message error.
notConnectedPromise.catch(noop)

// ===================================================================

const MAX_TRIES = 5

// -------------------------------------------------------------------

export class Xapi extends EventEmitter {
  constructor (opts) {
    super()

    this._url = parseUrl(opts.url)
    this._auth = opts.auth

    this._sessionId = notConnectedPromise

    this._init()

    this._pool = null
    this._objectsByRefs = Object.create(null)
    this._objectsByRefs['OpaqueRef:NULL'] = null
    this._objects = new Collection()
    this._objects.getId = (object) => object.$id

    this._fromToken = ''
    this.on('connected', this._watchEvents)
    this.on('disconnected', () => {
      this._fromToken = ''
      this._objects.clear()
    })
  }

  get sessionId () {
    if (this.status !== 'connected') {
      throw new Error('sessionId is only available when connected')
    }

    return this._sessionId.value()
  }

  get status () {
    const {_sessionId: sessionId} = this

    if (sessionId.isFulfilled()) {
      return 'connected'
    }

    if (sessionId.isPending()) {
      return 'connecting'
    }

    return 'disconnected'
  }

  get _humanId () {
    return `${this._auth.user}@${this._url.host}`
  }

  connect () {
    const {status} = this

    if (status === 'connected') {
      return Bluebird.reject(new Error('already connected'))
    }

    if (status === 'connecting') {
      return Bluebird.reject(new Error('already connecting'))
    }

    this._sessionId = this._transportCall('session.login_with_password', [
      this._auth.user,
      this._auth.password
    ])

    return this._sessionId.then(() => {
      debug('%s: connected', this._humanId)

      this.emit('connected')
    })
  }

  disconnect () {
    const {status} = this

    if (status === 'disconnected') {
      return Bluebird.reject('already disconnected')
    }

    if (status === 'connecting') {
      return this._sessionId.cancel().catch(Bluebird.CancellationError, () => {
        debug('%s: disconnected', this._humanId)

        this.emit('disconnected')
      })
    }

    this._sessionId = notConnectedPromise

    return Bluebird.resolve().then(() => {
      debug('%s: disconnected', this._humanId)

      this.emit('disconnected')
    })
  }

  // High level calls.
  call (method, ...args) {
    return this._sessionCall(method, args)
  }

  // Nice getter which returns the object for a given $id (internal to
  // this lib), UUID (unique identifier that some objects have) or
  // opaque reference (internal to XAPI).
  getObject (idOrUuidOrRef, defaultValue) {
    const object = (
      // if there is an UUID, it is also the $id.
      this.objects.all[idOrUuidOrRef] ||
      this._objectsByRefs[idOrUuidOrRef]
    )

    if (object) return object

    if (arguments.length > 1) return defaultValue

    throw new Error('there is not object can be matched to ' + idOrUuidOrRef)
  }

  getObjectByRef (ref, defaultValue) {
    const {
      _objectsByRefs: objectsByRefs
    } = this

    if (ref in objectsByRefs) {
      return objectsByRefs[ref]
    }

    if (arguments.length > 1) {
      return defaultValue
    }

    throw new Error('there is no object with the ref ' + ref)
  }

  getObjectByUuid (uuid, defaultValue) {
    const {
      // Objects ids are already UUIDs if they have one.
      _objects: {all: objectsByUuids}
    } = this

    if (uuid in objectsByUuids) {
      return objectsByUuids[uuid]
    }

    if (arguments.length > 1) {
      return defaultValue
    }

    throw new Error('there is no object with the UUID ' + uuid)
  }

  get pool () {
    return this._pool
  }

  get objects () {
    return this._objects
  }

  // Medium level call: handle session errors.
  _sessionCall (method, args) {
    if (startsWith(method, 'session.')) {
      return Bluebird.reject(
        new Error('session.*() methods are disabled from this interface')
      )
    }

    return this._sessionId.then((sessionId) => {
      return this._transportCall(method, [sessionId].concat(args))
    }).catch(isSessionInvalid, () => {
      // XAPI is sometimes reinitialized and sessions are lost.
      // Try to login again.
      debug('%s: the session has been reinitialized', this._humanId)

      this._sessionId = notConnectedPromise

      return this._sessionCall(method, args)
    })
  }

  // Low level call: handle transport errors.
  _transportCall (method, args, tries = 1) {
    debug('%s: %s(...)', this._humanId, method)

    return this._rawCall(method, args)
      .catch(isNetworkError, isXapiNetworkError, error => {
        debug('%s: network error %s', this._humanId, error.code)

        if (!(tries < MAX_TRIES)) {
          debug('%s too many network errors (%s), give up', this._humanId, tries)

          throw error
        }

        // TODO: ability to cancel the connection
        // TODO: ability to force immediate reconnection
        // TODO: implement back-off

        return Bluebird.delay(5e3).then(() => {
          // TODO: handling not responding host.

          return this._transportCall(method, args, tries + 1)
        })
      })
      .catch(isHostSlave, ({params: [master]}) => {
        debug('%s: host is slave, attempting to connect at %s', this._humanId, master)

        this._url.host = master
        this._init()

        return this._transportCall(method, args)
      })
  }

  // Lowest level call: do not handle any errors.
  _rawCall (method, args) {
    return this._xmlRpcCall(method, args)
      .then(result => {
        const {Status: status} = result

        // Return the plain result if it does not have a valid XAPI
        // format.
        if (!status) {
          return result
        }

        if (status === 'Success') {
          return result.Value
        }

        wrapError(result.ErrorDescription)
      })
      .cancellable()
  }

  _init () {
    const {isSecure, host, port} = this._url

    const client = (isSecure ?
      createSecureXmlRpcClient :
      createXmlRpcClient
    )({
      host,
      port,
      rejectUnauthorized: false,
      timeout: 10
    })

    this._xmlRpcCall = promisify(client.methodCall, client)
  }

  _normalizeObject (type, ref, object) {
    const {_objectsByRefs: objectsByRefs} = this
    const REF_RE = /^OpaqueRef:/

    forEach(object, function resolveIfLink (value, key, object) {
      if (typeof value === 'string' && REF_RE.test(value)) {
        Object.defineProperty(object, key, {
          enumerable: true,
          get: () => objectsByRefs[value]
        })
      } else if (typeof value === 'object') {
        forEach(value, resolveIfLink)
      }
    })

    object.$id = object.uuid || ref
    object.$ref = ref
    object.$type = type

    Object.defineProperty(object, '$pool', {
      enumerable: true,
      get: () => this._pool
    })
  }

  _watchEvents () {
    this.call(
      'event.from', ['*'], this._fromToken, 1e3 + 0.1
    ).then(({token, events}) => {
      this._fromToken = token

      const {
        _objects: objects,
        _objectsByRefs: objectsByRefs
      } = this

      forEach(events, event => {
        const {operation: op} = event

        const {ref} = event
        if (op === 'del') {
          const object = objectsByRefs[ref]

          if (object) {
            objects.remove(object.$id)
            delete objectsByRefs[ref]
          }
        } else {
          const {class: type, snapshot: object} = event

          this._normalizeObject(type, ref, object)
          objects.set(object)
          objectsByRefs[ref] = object

          if (object.$type === 'pool') {
            this._pool = object
          }
        }
      })
    }).catch(areEventsLost, () => {
      this._objects.clear()
    }).then(() => {
      this._watchEvents()
    }).catch(Bluebird.CancellationError, noop)
  }
}

// ===================================================================

// The default value is a factory function.
export const createClient = (opts) => new Xapi(opts)
<commit_msg>Code style and comments.<commit_after>import Bluebird, {promisify} from 'bluebird'
import Collection from 'xo-collection'
import createDebug from 'debug'
import forEach from 'lodash.foreach'
import startsWith from 'lodash.startswith'
import {BaseError} from 'make-error'
import {
  createClient as createXmlRpcClient,
  createSecureClient as createSecureXmlRpcClient
} from 'xmlrpc'
import {EventEmitter} from 'events'

const debug = createDebug('xen-api')

// ===================================================================

// http://www.gnu.org/software/libc/manual/html_node/Error-Codes.html
const NETWORK_ERRORS = {
  // Connection has been closed outside of our control.
  ECONNRESET: true,

  // Connection has been aborted locally.
  ECONNABORTED: true,

  // Host is up but refuses connection (typically: no such service).
  ECONNREFUSED: true,

  // TODO: ??
  EINVAL: true,

  // Host is not reachable (does not respond).
  EHOSTUNREACH: true,

  // Connection configured timed out has been reach.
  ETIMEDOUT: true
}

const isNetworkError = (error) => NETWORK_ERRORS[error.code]

// -------------------------------------------------------------------

const XAPI_NETWORK_ERRORS = {
  HOST_STILL_BOOTING: true,
  HOST_HAS_NO_MANAGEMENT_IP: true
}

const isXapiNetworkError = (error) => XAPI_NETWORK_ERRORS[error.code]

// -------------------------------------------------------------------

const areEventsLost = (error) => error.code === 'EVENTS_LOST'

const isHostSlave = (error) => error.code === 'HOST_IS_SLAVE'

const isSessionInvalid = (error) => error.code === 'SESSION_INVALID'

// -------------------------------------------------------------------

class XapiError extends BaseError {
  constructor (error) {
    super(error[0])

    this.code = error[0]
    this.params = error.slice(1)
  }
}

export const wrapError = error => new XapiError(error)

// ===================================================================

const URL_RE = /^(http(s)?:\/\/)?([^/]+?)(?::([0-9]+))?(?:\/.*)?$/
function parseUrl (url) {
  const matches = URL_RE.exec(url)
  if (!matches) {
    throw new Error('invalid URL: ' + url)
  }

  const [, protocol, , host, port] = matches
  let [, , isSecure] = matches

  if (!protocol) {
    isSecure = true
  }

  return {
    isSecure: Boolean(isSecure),
    host,
    port: port !== undefined ?
      +port :
      isSecure ? 443 : 80
  }
}

// -------------------------------------------------------------------

const noop = () => {}

// -------------------------------------------------------------------

const notConnectedPromise = Bluebird.reject(new Error('not connected'))

// Does nothing but avoid a Bluebird message error.
notConnectedPromise.catch(noop)

// ===================================================================

const MAX_TRIES = 5

// -------------------------------------------------------------------

export class Xapi extends EventEmitter {
  constructor (opts) {
    super()

    this._url = parseUrl(opts.url)
    this._auth = opts.auth

    this._sessionId = notConnectedPromise

    this._init()

    this._pool = null
    this._objectsByRefs = Object.create(null)
    this._objectsByRefs['OpaqueRef:NULL'] = null
    this._objects = new Collection()
    this._objects.getId = (object) => object.$id

    this._fromToken = ''
    this.on('connected', this._watchEvents)
    this.on('disconnected', () => {
      this._fromToken = ''
      this._objects.clear()
    })
  }

  get sessionId () {
    if (this.status !== 'connected') {
      throw new Error('sessionId is only available when connected')
    }

    return this._sessionId.value()
  }

  get status () {
    const {_sessionId: sessionId} = this

    if (sessionId.isFulfilled()) {
      return 'connected'
    }

    if (sessionId.isPending()) {
      return 'connecting'
    }

    return 'disconnected'
  }

  get _humanId () {
    return `${this._auth.user}@${this._url.host}`
  }

  connect () {
    const {status} = this

    if (status === 'connected') {
      return Bluebird.reject(new Error('already connected'))
    }

    if (status === 'connecting') {
      return Bluebird.reject(new Error('already connecting'))
    }

    this._sessionId = this._transportCall('session.login_with_password', [
      this._auth.user,
      this._auth.password
    ])

    return this._sessionId.then(() => {
      debug('%s: connected', this._humanId)

      this.emit('connected')
    })
  }

  disconnect () {
    const {status} = this

    if (status === 'disconnected') {
      return Bluebird.reject('already disconnected')
    }

    if (status === 'connecting') {
      return this._sessionId.cancel().catch(Bluebird.CancellationError, () => {
        debug('%s: disconnected', this._humanId)

        this.emit('disconnected')
      })
    }

    this._sessionId = notConnectedPromise

    return Bluebird.resolve().then(() => {
      debug('%s: disconnected', this._humanId)

      this.emit('disconnected')
    })
  }

  // High level calls.
  call (method, ...args) {
    return this._sessionCall(method, args)
  }

  // Nice getter which returns the object for a given $id (internal to
  // this lib), UUID (unique identifier that some objects have) or
  // opaque reference (internal to XAPI).
  getObject (idOrUuidOrRef, defaultValue) {
    const object = (
      // if there is an UUID, it is also the $id.
      this.objects.all[idOrUuidOrRef] ||
      this._objectsByRefs[idOrUuidOrRef]
    )

    if (object) return object

    if (arguments.length > 1) return defaultValue

    throw new Error('there is not object can be matched to ' + idOrUuidOrRef)
  }

  // Returns the object for a given opaque reference (internal to
  // XAPI).
  getObjectByRef (ref, defaultValue) {
    const object = this._objectsByRefs[ref]

    if (object) return object

    if (arguments.length > 1) return defaultValue

    throw new Error('there is no object with the ref ' + ref)
  }

  // Returns the object for a given UUID (unique identifier that some
  // objects have).
  getObjectByUuid (uuid, defaultValue) {
    // Objects ids are already UUIDs if they have one.
    const object = this.objects.all[uuid]

    if (object) return object

    if (arguments.length > 1) return defaultValue

    throw new Error('there is no object with the UUID ' + uuid)
  }

  get pool () {
    return this._pool
  }

  get objects () {
    return this._objects
  }

  // Medium level call: handle session errors.
  _sessionCall (method, args) {
    if (startsWith(method, 'session.')) {
      return Bluebird.reject(
        new Error('session.*() methods are disabled from this interface')
      )
    }

    return this._sessionId.then((sessionId) => {
      return this._transportCall(method, [sessionId].concat(args))
    }).catch(isSessionInvalid, () => {
      // XAPI is sometimes reinitialized and sessions are lost.
      // Try to login again.
      debug('%s: the session has been reinitialized', this._humanId)

      this._sessionId = notConnectedPromise

      return this._sessionCall(method, args)
    })
  }

  // Low level call: handle transport errors.
  _transportCall (method, args, tries = 1) {
    debug('%s: %s(...)', this._humanId, method)

    return this._rawCall(method, args)
      .catch(isNetworkError, isXapiNetworkError, error => {
        debug('%s: network error %s', this._humanId, error.code)

        if (!(tries < MAX_TRIES)) {
          debug('%s too many network errors (%s), give up', this._humanId, tries)

          throw error
        }

        // TODO: ability to cancel the connection
        // TODO: ability to force immediate reconnection
        // TODO: implement back-off

        return Bluebird.delay(5e3).then(() => {
          // TODO: handling not responding host.

          return this._transportCall(method, args, tries + 1)
        })
      })
      .catch(isHostSlave, ({params: [master]}) => {
        debug('%s: host is slave, attempting to connect at %s', this._humanId, master)

        this._url.host = master
        this._init()

        return this._transportCall(method, args)
      })
  }

  // Lowest level call: do not handle any errors.
  _rawCall (method, args) {
    return this._xmlRpcCall(method, args)
      .then(result => {
        const {Status: status} = result

        // Return the plain result if it does not have a valid XAPI
        // format.
        if (!status) {
          return result
        }

        if (status === 'Success') {
          return result.Value
        }

        wrapError(result.ErrorDescription)
      })
      .cancellable()
  }

  _init () {
    const {isSecure, host, port} = this._url

    const client = (isSecure ?
      createSecureXmlRpcClient :
      createXmlRpcClient
    )({
      host,
      port,
      rejectUnauthorized: false,
      timeout: 10
    })

    this._xmlRpcCall = promisify(client.methodCall, client)
  }

  _normalizeObject (type, ref, object) {
    const {_objectsByRefs: objectsByRefs} = this
    const REF_RE = /^OpaqueRef:/

    forEach(object, function resolveIfLink (value, key, object) {
      if (typeof value === 'string' && REF_RE.test(value)) {
        Object.defineProperty(object, key, {
          enumerable: true,
          get: () => objectsByRefs[value]
        })
      } else if (typeof value === 'object') {
        forEach(value, resolveIfLink)
      }
    })

    object.$id = object.uuid || ref
    object.$ref = ref
    object.$type = type

    Object.defineProperty(object, '$pool', {
      enumerable: true,
      get: () => this._pool
    })
  }

  _watchEvents () {
    this.call(
      'event.from', ['*'], this._fromToken, 1e3 + 0.1
    ).then(({token, events}) => {
      this._fromToken = token

      const {
        _objects: objects,
        _objectsByRefs: objectsByRefs
      } = this

      forEach(events, event => {
        const {operation: op} = event

        const {ref} = event
        if (op === 'del') {
          const object = objectsByRefs[ref]

          if (object) {
            objects.remove(object.$id)
            delete objectsByRefs[ref]
          }
        } else {
          const {class: type, snapshot: object} = event

          this._normalizeObject(type, ref, object)
          objects.set(object)
          objectsByRefs[ref] = object

          if (object.$type === 'pool') {
            this._pool = object
          }
        }
      })
    }).catch(areEventsLost, () => {
      this._objects.clear()
    }).then(() => {
      this._watchEvents()
    }).catch(Bluebird.CancellationError, noop)
  }
}

// ===================================================================

// The default value is a factory function.
export const createClient = (opts) => new Xapi(opts)
<|endoftext|>


<commit_before>var Tile = require('./tile');

// this is what a deck should look like
  // [ {id: a0, orientation: 0}, {id: a1, orientation: 0}, ... ]

// takes a `spec` argument
// the spec is an object, it contains letter keys (i.e. a, b, c)
  // and its values are arrays that contain integers representing the number of
  // each card in the deck.
// if that is confusing just look at the `cards` object below and it might make sense...
var Deck = function(spec){
  this.deck = [];
  for (var key in spec){
    for (var i = 0; i < spec[key].length; i++) {
      this.deck.push(new Tile ( key + spec[key][i] ));
    }
  }
};

// fisher yates shuffle yolo
// operates on this.deck
Deck.prototype.shuffle = function() {
  if (this.deck.length === 0) {
    console.log('you dun goofed');
  }
  var currentIndex = this.deck.length, temporaryValue, randomIndex;
  while (0 !== currentIndex){
    randomIndex = Math.floor( Math.random () * currentIndex);
    currentIndex -= 1;
    temporaryValue = this.deck[currentIndex];
    this.deck[currentIndex] = this.deck[randomIndex];
    this.deck[randomIndex] = temporaryValue;
  }
};

// returns the card from the top of the deck
Deck.prototype.pop = function() {
  return this.deck.pop();
};

module.exports = Deck;<commit_msg>clean up deck code<commit_after>var Tile = require('./tile');

// this is what a deck should look like
  // [ {id: a0, orientation: 0}, {id: a1, orientation: 0}, ... ]

// takes a `spec` argument
// the spec is an object, it contains letter keys (i.e. a, b, c)
  // and its values are arrays that contain integers representing the number of
  // each card in the deck.
// if that is confusing just look at the `cards` object below and it might make sense...
var Deck = function(spec){
  this.deck = [];
  for (var key in spec){
    for (var i = 0; i < spec[key].length; i++) {
      this.deck.push(new Tile ( key + spec[key][i] ));
    }
  }
};

// classic fisher-yates shuffle
// operates on this.deck
Deck.prototype.shuffle = function() {
  if (this.deck.length === 0) {
    console.log('you dun goofed, your deck is empty');
  }
  var currentIndex = this.deck.length, temporaryValue, randomIndex;
  while (0 !== currentIndex){
    randomIndex = Math.floor( Math.random () * currentIndex );
    currentIndex -= 1;
    temporaryValue = this.deck[currentIndex];
    this.deck[currentIndex] = this.deck[randomIndex];
    this.deck[randomIndex] = temporaryValue;
  }

  // if group approves _ inclusion, replace all that with
  // _.shuffle(this.deck);
};

// returns the card from the top of the deck
Deck.prototype.pop = function() {
  return this.deck.pop();
};

module.exports = Deck;<|endoftext|>


<commit_before>/* jshint node: true */

module.exports = function(environment) {
  var ENV = {
    modulePrefix: 'priv-o-matic',
    environment: environment,
    baseURL: '/',
    locationType: 'hash',
    EmberENV: {
      FEATURES: {
        // Here you can enable experimental features on an ember canary build
        // e.g. 'with-controller': true
      }
    },
    contentSecurityPolicy: {
      'style-src': "'self' 'unsafe-inline' http://fonts.googleapis.com",
      'font-src': "'self' http://fonts.gstatic.com",
    },
    APP: {
      // Here you can pass flags/options to your application instance
      // when it is created
    }
  };

  if (environment === 'development') {
    // ENV.APP.LOG_RESOLVER = true;
    // ENV.APP.LOG_ACTIVE_GENERATION = true;
    // ENV.APP.LOG_TRANSITIONS = true;
    // ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
    // ENV.APP.LOG_VIEW_LOOKUPS = true;
  }

  if (environment === 'test') {
    // Testem prefers this...
    ENV.baseURL = '/';
    ENV.locationType = 'none';

    // keep test console output quieter
    ENV.APP.LOG_ACTIVE_GENERATION = false;
    ENV.APP.LOG_VIEW_LOOKUPS = false;

    ENV.APP.rootElement = '#ember-testing';
  }

  if (environment === 'production') {

  }

  return ENV;
};
<commit_msg>revert<commit_after>/* jshint node: true */

module.exports = function(environment) {
  var ENV = {
    modulePrefix: 'smallprint',
    environment: environment,
    baseURL: '/',
    locationType: 'hash',
    EmberENV: {
      FEATURES: {
        // Here you can enable experimental features on an ember canary build
        // e.g. 'with-controller': true
      }
    },
    contentSecurityPolicy: {
      'style-src': "'self' 'unsafe-inline' http://fonts.googleapis.com",
      'font-src': "'self' http://fonts.gstatic.com",
    },
    APP: {
      // Here you can pass flags/options to your application instance
      // when it is created
    }
  };

  if (environment === 'development') {
    // ENV.APP.LOG_RESOLVER = true;
    // ENV.APP.LOG_ACTIVE_GENERATION = true;
    // ENV.APP.LOG_TRANSITIONS = true;
    // ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
    // ENV.APP.LOG_VIEW_LOOKUPS = true;
  }

  if (environment === 'test') {
    // Testem prefers this...
    ENV.baseURL = '/';
    ENV.locationType = 'none';

    // keep test console output quieter
    ENV.APP.LOG_ACTIVE_GENERATION = false;
    ENV.APP.LOG_VIEW_LOOKUPS = false;

    ENV.APP.rootElement = '#ember-testing';
  }

  if (environment === 'production') {

  }

  return ENV;
};
<|endoftext|>


<commit_before>define([
	'jquery',
	'underscore',
	'backbone',
	'config',
	'utils',
	'text!templates/graphs-panel.html',
	'views/panel-view-base'
], function($, _, Backbone, config, utils, templateHtml, PanelViewBase) {
    "use strict";

	var GraphsPanelView = PanelViewBase.extend({

		className: 'panel panel-default panel-anchor-bottom graphs',
		draggable: false,

		events: {
			'click .graph-toggles button': 'toggleGraphViewClicked'
		},

	    initialize: function(options)
	    {
	    	GraphsPanelView.__super__.initialize.call(this, options);

	    	var self = this;
		    this.template = _.template(templateHtml);
		    this.redrawQueue = [];
		    this.graphViews = {};
		    this.graphView;

		    this.on('panel:resize', this.adjustAndRedrawGraphs);
		    this.on('panel:show', this.adjustAndRedrawGraphs);
		},

		adjustAndRedrawGraphs: function()
		{
			var self = this;
	    	self.redrawQueue.push(setTimeout(function() {
	    		_.each(self.graphViews, function(view, viewKey) {
	    			view.fillExtents();
	    		});
	    		if (self.graphView) {
	    			if (self.graphView.graphRendered) {
		    			self.graphView.redrawGraph();
	    			} else {
		    			self.graphView.renderGraph();
	    			}
	    		}
	    	}, 250));
	    	for (var i = self.redrawQueue.length; i > 1; i--) {
	    		clearTimeout(self.redrawQueue.shift());
	    	}
		},

		render: function()
		{
			GraphsPanelView.__super__.render.call(this);
			this.$('.model-title').text(this.model.getDisplay('title'));
			this.$graphToggles = this.$('.graph-toggles');
			this.$graphToggleTemplate = $('.element-template', this.$graphToggles)
				.remove().removeClass('element-template');
			return this;
		},

		addGraphView: function(key, view, title)
		{
			this.graphViews[key] = view;
			var toggle = this.$graphToggleTemplate.clone()
				.attr('data-value', key)
				.text(title || key);
			this.$graphToggles.append(toggle)
			this.$('.graph-container').append(view.$el);
			if (!this.graphView) {
				this.toggleGraphView(key);
			} else {
				view.hide();
			}
		},

		toggleGraphViewClicked: function(evt)
		{
			this.toggleGraphView($(evt.currentTarget).attr('data-value'));
			this.updatePanelState(true);
		},

		toggleGraphView: function(key)
		{
			if (key) {
				console.log('toggle graph view:', key);
				this.graphView = this.graphViews[key];
			}
			$('button', this.$graphToggles).each(function() {
				$(this).toggleClass('active', $(this).attr('data-value') == key);
			});
			if (this.$el.is(':visible')) {
				_.each(this.graphViews, function(view, viewKey) {
					if (viewKey == key) {
						view.show();
					} else {
						view.hide();
					}
				});
			}
		}

	});

	return GraphsPanelView;
});<commit_msg>Graphs should only redraw if visible<commit_after>define([
	'jquery',
	'underscore',
	'backbone',
	'config',
	'utils',
	'text!templates/graphs-panel.html',
	'views/panel-view-base'
], function($, _, Backbone, config, utils, templateHtml, PanelViewBase) {
    "use strict";

	var GraphsPanelView = PanelViewBase.extend({

		className: 'panel panel-default panel-anchor-bottom graphs',
		draggable: false,

		events: {
			'click .graph-toggles button': 'toggleGraphViewClicked'
		},

	    initialize: function(options)
	    {
	    	GraphsPanelView.__super__.initialize.call(this, options);

	    	var self = this;
		    this.template = _.template(templateHtml);
		    this.redrawQueue = [];
		    this.graphViews = {};
		    this.graphView;

		    this.on('panel:resize', this.adjustAndRedrawGraphs);
		    this.on('panel:show', this.adjustAndRedrawGraphs);
		},

		adjustAndRedrawGraphs: function()
		{
			var self = this;
	    	self.redrawQueue.push(setTimeout(function() {
	    		_.each(self.graphViews, function(view, viewKey) {
	    			view.fillExtents();
	    		});
	    		if (self.graphView && self.$el.is(':visible')) {
	    			if (self.graphView.graphRendered) {
		    			self.graphView.redrawGraph();
	    			} else {
		    			self.graphView.renderGraph();
	    			}
	    		}
	    	}, 250));
	    	for (var i = self.redrawQueue.length; i > 1; i--) {
	    		clearTimeout(self.redrawQueue.shift());
	    	}
		},

		render: function()
		{
			GraphsPanelView.__super__.render.call(this);
			this.$('.model-title').text(this.model.getDisplay('title'));
			this.$graphToggles = this.$('.graph-toggles');
			this.$graphToggleTemplate = $('.element-template', this.$graphToggles)
				.remove().removeClass('element-template');
			return this;
		},

		addGraphView: function(key, view, title)
		{
			this.graphViews[key] = view;
			var toggle = this.$graphToggleTemplate.clone()
				.attr('data-value', key)
				.text(title || key);
			this.$graphToggles.append(toggle)
			this.$('.graph-container').append(view.$el);
			if (!this.graphView) {
				this.toggleGraphView(key);
			} else {
				view.hide();
			}
		},

		toggleGraphViewClicked: function(evt)
		{
			this.toggleGraphView($(evt.currentTarget).attr('data-value'));
			this.updatePanelState(true);
		},

		toggleGraphView: function(key)
		{
			if (key) {
				console.log('toggle graph view:', key);
				this.graphView = this.graphViews[key];
			}
			$('button', this.$graphToggles).each(function() {
				$(this).toggleClass('active', $(this).attr('data-value') == key);
			});
			if (this.$el.is(':visible')) {
				_.each(this.graphViews, function(view, viewKey) {
					if (viewKey == key) {
						view.show();
					} else {
						view.hide();
					}
				});
			}
		}

	});

	return GraphsPanelView;
});<|endoftext|>


<commit_before>/*
 * ready
 * Watch for when an element becomes available in the DOM
 * @param {String} selector
 * @param {Function} fn
 */

(function(win){
    'use strict';

    var listeners = [],
    doc = win.document,
    MutationObserver = win.MutationObserver || win.WebKitMutationObserver,
    observer;

    function ready(selector, fn){
        // Store the selector and callback to be monitored
        listeners.push({
            selector: selector,
            fn: fn
        });
        if(!observer){
            // Watch for changes in the document
            observer = new MutationObserver(check);
            observer.observe(doc.documentElement, {
                childList: true,
                subtree: true
            });
        }
        // Check if the element is currently in the DOM
        check();
    }

    function check(){
        // Check the DOM for elements matching a stored selector
        for(var i = 0, len = listeners.length, listener, elements; i < len; i++){
            listener = listeners[i];
            // Query for elements matching the specified selector
            elements = doc.querySelectorAll(listener.selector);
            for(var j = 0, jLen = elements.length, element; j < jLen; j++){
                element = elements[j];
                // Make sure the callback isn't invoked with the
                // same element more than once
                if(!element.ready){
                    element.ready = true;
                    // Invoke the callback with the element
                    listener.fn.call(element, element);
                }
            }
        }
    }

    // Expose `ready`
    win.ready = ready;

})(this);<commit_msg>Remove unneccessary query checks<commit_after>/*
 * ready
 * Watch for when an element becomes available in the DOM
 * @param {String} selector
 * @param {Function} fn
 */

(function(win){
    'use strict';

    var listeners = [],
    doc = win.document,
    MutationObserver = win.MutationObserver || win.WebKitMutationObserver,
    observer;

    function ready(selector, fn){
        // Store the selector and callback to be monitored
        listeners.push({
            selector: selector,
            fn: fn
        });
        if(!observer){
            // Watch for changes in the document
            observer = new MutationObserver(checkListeners);
            observer.observe(doc.documentElement, {
                childList: true,
                subtree: true
            });
        }
        // Check if the element is currently in the DOM
        check(selector, fn);
    }

    function checkListeners(){
        // Check the DOM for elements matching a stored selector
        for(var i = 0, len = listeners.length, listener; i < len; i++){
            listener = listeners[i];
            check(listener.selector, listener.fn);
        }
    }

    function check(selector, fn){
        // Query for elements matching the specified selector
        var elements = doc.querySelectorAll(selector), i = 0, len = elements.length, element;
        for(; i < len; i++){
            element = elements[i];
            // Make sure the callback isn't invoked with the
            // same element more than once
            if(!element.ready){
                element.ready = true;
                // Invoke the callback with the element
                fn.call(element, element);
            }
        }
    }

    // Expose `ready`
    win.ready = ready;

})(this);<|endoftext|>


<commit_before><commit_msg>Removed duplication from method.<commit_after><|endoftext|>


<commit_before>const Store = require("./store").Store;
const cards = require("./cards");
const Player = require("./player").Player;

/**
 * @typedef { import("./connection").Connection } Connection
 * @typedef { import("./cards").Card } Card
 */

class Game {
  constructor() {
    this.store = new Store();
    /**
     * @type {Object.<string, Player>}
     */
    this.players = {};
    this.trash = [];
    this.started = false;
  }

  /**
   * @param {Player[]} ps
   */
  initClients(ps) {
    const included = this.store.included.map(c => c.name);
    ps.forEach(p => p.send({included}));

    const colors = this.store.getAllCards().reduce((o, c) => {
      o[c.name] = c.color;
      o["Buy: " + c.name] = c.color;
      return o;
    }, {});
    ps.forEach(p => p.send({colors}));
  }

  /**
   * @param {boolean} debugMode
   */
  start(debugMode) {
    this.started = true;
    const ps = this.allPlayers();

    this.initClients(ps);

    ps.forEach(p => p.redrawHand());

    if (debugMode) {
      ps[0].hand.push(...this.store.getAvailable(99));
      ps[0].sendHand();
      this.allLog("!!!!!! " + ps[0].name + " IS CHEATING!!!!!!");
    }

    let turn = Math.floor(Math.random() * ps.length);
    const nextTurn = () => {
      if (this.store.gameOver()) {
        this.allLog("GAME OVER!!!");
        ps.sort((a, b) => b.getPoints() - a.getPoints()) // descending
          .map(p => `${p.name}: ${p.getPoints()}     ` +
            p.allCards()
              .filter(c => c.ofKind("victory") || c.ofKind("curse"))
              .map(c => c.name)
              .sort()
              .toString())
          .forEach(line => this.allLog(line));
        return;
      }

      ++turn;
      ps[turn % ps.length].takeTurn(nextTurn);
    };

    ps[turn].takeTurn(nextTurn);
  }

  /**
   * @param {Connection} connection
   */
  addPlayer(connection) {
    const name = connection.name;

    const player = new Player(connection, this);

    if (Object.keys(this.players).length == 0) {
      player.send({isLeader: this.store.optional()});
    } else {
      player.sendMessage("Waiting for the leader to start the game");
      this.allLog(player.name + " joined");
    }
    this.players[name] = player;

    connection.messageHandlers.chat = data => {
      this.allLog(player.name + ": " + data);
    };

    connection.messageHandlers.gameStart = data => {
      this.store.init(data.included.map(n => cards[n]), this.allPlayers().length);
      this.start(data.debugMode);
    };

    connection.ws.addEventListener("close", () => {
      this.allLog(player.name + " disconnected");
    });
  }

  allPlayers() {
    return Object.keys(this.players).map(n => this.players[n]);
  }

  /**
   * @param {Player} player
   * @return {Player[]}
   */
  otherPlayers(player) {
    return this.allPlayers().filter(p => p.name !== player.name);
  }

  /**
   * @param {Player} player
   * @param {function(Player): Promise<void>} attack
   * @return {Promise<void[]>}
   */
  parallelAttack(player, attack) {
    return Promise.all(this.otherPlayers(player).map(p => p.attacked(attack)));
  }

  /**
   * @param {Player} player
   * @param {function(Player): Promise<void>} attack
   */
  async sequentialAttack(player, attack) {
    const ps = this.allPlayers();
    ps.push(...ps.splice(0, ps.indexOf(player))); // Rotate around so player is ps[0]

    for (let i = 1; i < ps.length; ++i) {
      await ps[i].attacked(attack);
    }
  }

  allLog(text) {
    for (const id in this.players) {
      this.players[id].sendMessage(text);
    }
  }

  /**
   * @param {Player} player
   * @param {string} cardName
   * @param {object} options {toHand: boolean}
   */
  gainCard(player, cardName, {toHand = false} = {}) {
    if (!this.store.counts[cardName]) {
      throw new Error(`Out of ${cardName}`);
    }

    const card = cards[cardName];

    if (toHand) {
      player.hand.push(card);
    } else {
      player.discardPile.push(card);
    }
    this.store.bought(card);
    this.allLog(`${player.name} gained ${cardName}`);
  }

  /**
   * @param {Player} player
   * @param {string} cardName
   */
  tryGainCard(player, cardName) {
    if (this.store.counts[cardName]) {
      this.gainCard(player, cardName);
    }
  }

  /**
   * @param {Player} player
   * @param {Card} card
   */
  trashPush(player, card) {
    this.allLog(`${player.name} trashed ${card.name}`);
    this.trash.push(card);
  }
}

module.exports.Game = Game;
<commit_msg>leader shown optional cards in help<commit_after>const Store = require("./store").Store;
const cards = require("./cards");
const Player = require("./player").Player;

/**
 * @typedef { import("./connection").Connection } Connection
 * @typedef { import("./cards").Card } Card
 */

class Game {
  constructor() {
    this.store = new Store();
    /**
     * @type {Object.<string, Player>}
     */
    this.players = {};
    this.trash = [];
    this.started = false;
  }

  /**
   * @param {Player[]} ps
   */
  initClients(ps) {
    const included = this.store.included.map(c => c.name);
    ps.forEach(p => p.send({included}));

    const colors = this.store.getAllCards().reduce((o, c) => {
      o[c.name] = c.color;
      o["Buy: " + c.name] = c.color;
      return o;
    }, {});
    ps.forEach(p => p.send({colors}));
  }

  /**
   * @param {boolean} debugMode
   */
  start(debugMode) {
    this.started = true;
    const ps = this.allPlayers();

    this.initClients(ps);

    ps.forEach(p => p.redrawHand());

    if (debugMode) {
      ps[0].hand.push(...this.store.getAvailable(99));
      ps[0].sendHand();
      this.allLog("!!!!!! " + ps[0].name + " IS CHEATING!!!!!!");
    }

    let turn = Math.floor(Math.random() * ps.length);
    const nextTurn = () => {
      if (this.store.gameOver()) {
        this.allLog("GAME OVER!!!");
        ps.sort((a, b) => b.getPoints() - a.getPoints()) // descending
          .map(p => `${p.name}: ${p.getPoints()}     ` +
            p.allCards()
              .filter(c => c.ofKind("victory") || c.ofKind("curse"))
              .map(c => c.name)
              .sort()
              .toString())
          .forEach(line => this.allLog(line));
        return;
      }

      ++turn;
      ps[turn % ps.length].takeTurn(nextTurn);
    };

    ps[turn].takeTurn(nextTurn);
  }

  /**
   * @param {Connection} connection
   */
  addPlayer(connection) {
    const name = connection.name;

    const player = new Player(connection, this);

    if (Object.keys(this.players).length == 0) {
      player.send({isLeader: this.store.optional()});
      player.send({included: this.store.optional()});
    } else {
      player.sendMessage("Waiting for the leader to start the game");
      this.allLog(player.name + " joined");
    }
    this.players[name] = player;

    connection.messageHandlers.chat = data => {
      this.allLog(player.name + ": " + data);
    };

    connection.messageHandlers.gameStart = data => {
      this.store.init(data.included.map(n => cards[n]), this.allPlayers().length);
      this.start(data.debugMode);
    };

    connection.ws.addEventListener("close", () => {
      this.allLog(player.name + " disconnected");
    });
  }

  allPlayers() {
    return Object.keys(this.players).map(n => this.players[n]);
  }

  /**
   * @param {Player} player
   * @return {Player[]}
   */
  otherPlayers(player) {
    return this.allPlayers().filter(p => p.name !== player.name);
  }

  /**
   * @param {Player} player
   * @param {function(Player): Promise<void>} attack
   * @return {Promise<void[]>}
   */
  parallelAttack(player, attack) {
    return Promise.all(this.otherPlayers(player).map(p => p.attacked(attack)));
  }

  /**
   * @param {Player} player
   * @param {function(Player): Promise<void>} attack
   */
  async sequentialAttack(player, attack) {
    const ps = this.allPlayers();
    ps.push(...ps.splice(0, ps.indexOf(player))); // Rotate around so player is ps[0]

    for (let i = 1; i < ps.length; ++i) {
      await ps[i].attacked(attack);
    }
  }

  allLog(text) {
    for (const id in this.players) {
      this.players[id].sendMessage(text);
    }
  }

  /**
   * @param {Player} player
   * @param {string} cardName
   * @param {object} options {toHand: boolean}
   */
  gainCard(player, cardName, {toHand = false} = {}) {
    if (!this.store.counts[cardName]) {
      throw new Error(`Out of ${cardName}`);
    }

    const card = cards[cardName];

    if (toHand) {
      player.hand.push(card);
    } else {
      player.discardPile.push(card);
    }
    this.store.bought(card);
    this.allLog(`${player.name} gained ${cardName}`);
  }

  /**
   * @param {Player} player
   * @param {string} cardName
   */
  tryGainCard(player, cardName) {
    if (this.store.counts[cardName]) {
      this.gainCard(player, cardName);
    }
  }

  /**
   * @param {Player} player
   * @param {Card} card
   */
  trashPush(player, card) {
    this.allLog(`${player.name} trashed ${card.name}`);
    this.trash.push(card);
  }
}

module.exports.Game = Game;
<|endoftext|>