<commit_before>'use strict';

var path = require('path');

var express = require('express');
var router = express.Router();

var handlebars = require('hbs').handlebars;

var arrrayToTree = require('file-tree');
var TreeModel = require('tree-model');

var processFiles = require('../lib/specifications/files/process-files');
var countTags = require('../lib/specifications/files/feature-files/tags').count;

var getProject = require('../lib/specifications/projects/project').get;
var getProjectData = require('../lib/specifications/projects/project').getData;
var getFileContent = require('../lib/specifications/projects/project').getFileContent;

var appConfig = require('../lib/configuration/app-config').get();

// Render the project page and send to client.
function getRender(res, appConfig, renderOptions) {
  return function render(projectData) {
    var renderingData = {};
    var view = {};
    var viewNames = [];
    var currentView;
    var projectTags = {};

    renderingData.openBurgerMenu = renderOptions.openBurgerMenu;

    // Handle no project data being found.
    if (!projectData) {
      res.render('project', renderingData);
      return;
    }

    renderingData['project'] = projectData;

    // If there are no files in the project then don't
    // try and get file contents.
    if (!projectData.files.length) {
      res.render('project', renderingData);
      return;
    }

    /*
      Applying views from configuration.
     */

    // If the project config contains specified views use them.
    currentView = renderOptions.currentView;
    if (projectData.config) {
      viewNames = Object.keys(projectData.config.views);
    }

    if (viewNames.length > 0) {
      renderingData.hasViews = true;

      // No view specified, attempt to use a DEFAULT view.
      if (currentView === false) {
        // The defaultView value may be undefined, that will result in no view logic being applied.
        currentView = viewNames
                        .filter(function(name) {
                          return !!projectData.config.views[name].default;
                        })[0] || false;
      }

      // Generate view name data for the UI.
      renderingData.viewNames = viewNames.map(function (viewName) {
        return {
          name: viewName,
          urlEncodedName: encodeURIComponent(viewName),
          isCurrent: viewName === currentView
        };
      });

      // Explicit request for no view logic to be applied.
      if (currentView === 'none') {
        view = renderingData.view = false;

      // Grab any view config that might have been specified in the project config.
      } else {
        view = renderingData.view = projectData.config.views[currentView];
      }

      // Filter the file list based on the excludedPaths in project config.
      if (view && view.hasExcludedPaths) {
        projectData.files = projectData.files.filter(view.helpers.isIncludedPath);
      }

      // Filter the file list based on the anchor path in the project config.
      if (view && view.hasAnchor) {
        projectData.files = projectData.files.filter(view.helpers.isWithinAnchor);
      }
    }

    /*
      Getting file content and rendering.
     */

    // Configure function for mapping file paths to file data.
    var pathToData = processFiles.getFilePathToFileObject(appConfig.projectRoute, projectData, getFileContent);

    // Map list of file paths to list of file data objects.
    projectData.files = projectData.files.map(pathToData);

    // Wait for content promises to resolve.
    // We don't actually care about the promise values here, they are already
    // part of the file object, we just need them all fulfilled or rejected.
    var promisesForFileContent = projectData.files.map(function(f) {return f.contentPromise;});
    return Promise.all(promisesForFileContent)
      .then(function(fileContents) {
        var tagNames = [];

        // Mix in the file content.
        projectData.files = projectData.files.map(processFiles.processFileContent);

        // If the project config contains a URL format
        // for creating links to edit files then grab it.
        if (projectData.config.editUrlFormat) {
          projectData.files.forEach(function(file) {
            var editUrlTemplate = handlebars.compile(projectData.config.editUrlFormat);
            var editUrl = editUrlTemplate({
              repoUrl: projectData.repoUrl,
              repoUrlWithoutGitSuffix: projectData.repoUrl.replace(/\.git$/i, ''),
              branchName: projectData.currentShortBranchName,
              pathToFile: file.filePath
            });

            file.editUrl = editUrl;
          });
        }

        /*
          Applying filtering based on feature and scenario tags.
         */

        var currentTags = renderOptions.currentTags;
        // Count the tags in the project.
        projectData.files.forEach(function(file) {
          if (!file.isFeatureFile || file.error) {
            return;
          }

          // This counts tags and marks when an
          // object contains the requested tag.
          projectTags = countTags(file.data, projectTags, currentTags);
        });
        tagNames = Object.keys(projectTags);
        projectData.hasTags = !!tagNames.length;
        // Mark the currently requested tag if any,
        // this is used to set the selected option
        // in the tag select box.
        tagNames.forEach(function(name) {
          // Currently on one tag is passed in the query parameter.
          if (name === currentTags) {
            projectTags[name].isCurrent = true;
          }
        });
        projectData.tags = projectTags;

        // Filter the features and scenarios based on
        // whether they contain the requested tag.
        if (currentTags) {
          projectData.files = projectData.files.filter(function(file) {
            var feature;
            var featureScenarioContainsTag = false;

            // Filter out non-feature or erroring files.
            if (!file.isFeatureFile || file.error) {
              return false;
            }

            // If the feature contains the tag keep it and take no
            // further action.
            feature = file.data;
            if (feature.containsRequestedTag) {
              return true;
            }

            feature.scenarioDefinitions.forEach(function (scenario, index, defs) {

              // if any example contains the tag keep all examples.
              if (scenario.type === 'ScenarioOutline') {
                scenario.examples.forEach(function(example) {
                  if (example.containsRequestedTag) {
                    scenario.containsRequestedTag = true;
                  }
                });
              }
              if (scenario.containsRequestedTag) {
                featureScenarioContainsTag = true;
              } else {
                // Set the scenario to undefined so it won't be rendered.
                defs[index] = undefined;
              }
            });
            // Remove undefined scenarios because handlbars' `each`
            // helper doen't ignore undefined array elements.
            feature.scenarioDefinitions = feature.scenarioDefinitions.filter(function(scenario) { return scenario !== undefined; });

            // Retain or lose the feature depending on whether a scenario
            // contained the requested tag.
            return featureScenarioContainsTag;
          });
        }

        /*
          Generate a tree data structure from the flat file list.
         */
        var fileList = projectData.files.map(function(file) { return file.filePath; });

        arrrayToTree(fileList, function(filePath, next) {

          // Fix the assumption in file-tree that we are dealing with actual
          // files on disk.
          filePath = path.relative(appConfig.rootPath, filePath);

          // Use a loop to find the file matching this part of the tree.
          var currentFile = projectData.files.filter(function(file) {
            return filePath === file.filePath;
          })[0];

          // Link the file list and the tree structure by reference.
          var leaf = {
            name: filePath,
            file: currentFile,
            isFile: true
          };

          // Continue to generate the tree.
          next(null, leaf);
        }, function(err, fileTree) {

          // Tree generation is complete.
          // Wrap in tree model convenience object.
          var treeRoot = (new TreeModel()).parse({name: 'root', children: fileTree});

          // Use the tree to construct sets of files grouped by parent directory.
          var filesByDir = {};
          var fileNodes = treeRoot.all(function(node) { return node.model.isFile; });
          fileNodes.forEach(function(fileNode) {
            var pathToNode = fileNode.getPath();

            // Derive a directory path.
            var directoryNames = pathToNode
                                  .map(function(node) {
                                    var model = node.model;
                                    if (!node.isRoot() && !model.isFile) {
                                      return node.model.name;
                                    }
                                    return '';
                                  });
            var directoryPath = path.join.apply(path, directoryNames);

            // Store the file data keyed by containing directory.
            if (!filesByDir[directoryPath]) {
              filesByDir[directoryPath] = [];
            }
            filesByDir[directoryPath].push(fileNode.model.file);
          });

          // Reference the finished file tree on the rendering data object.
          renderingData['project'].filesByDir = filesByDir;

          // Render the page.
          res.render('project', renderingData);
        });
      });
  };
}

// Pass errors to the next Express middleware for handling.
function getPassError(next) {
  return function passError(err) {
    next(err);
  };
}

// List of available features in a project.
router.get(/^\/([^\/]+)$/, function(req, res, next) {

  // Cookie variables.
  var openBurgerMenu = (req.cookies.specsOpenBurgerMenu === 'true');

  // Session variable.
  if(!req.session.branches) req.session.branches = {};
  var sessionBranches = req.session.branches;

  // The repository name from the URL.
  var repoName = req.params[0];

  // Query param indicating a particular ref should
  // be used when retrieving repo data.
  var targetBranchName = req.query.branch || false;

  // Query param causing a Git fetch.
  var projectShouldUpdate = (req.query.update === 'true');

  // Query parameter containing desired named view from project config.
  var currentView = req.query.view || false;

  // Query parameter containing desired feature tags to filer on.
  var currentTags = req.query.tags || false;
  if (currentTags === 'none') {
    currentTags = false;
  }

  // Create rendering options.
  var renderOptions = {
    openBurgerMenu: openBurgerMenu,
    currentView: currentView,
    currentTags: currentTags
  };

  // Create the render and passError functions.
  var configuredRender = getRender(res, appConfig, renderOptions);
  var configuredPassError = getPassError(next);

  // TODO: Have one place this object is created.
  var projectData = {
    repoName: repoName,
    localPathRoot: appConfig.projectsPath
  };

  // Perform a clone or fetch on the repo then get the data.
  // If this switch is set then the branch will not change.
  if (projectShouldUpdate) {

    // Set the current branch name which will be used in the update.
    // If not supplied the repo default branch will be used.
    projectData.currentBranchName = sessionBranches[repoName] || false;

    // Update the repo and get the repo data.
    getProject(projectData)
      .then(configuredRender)
      .catch(configuredPassError);

  // Change the branch.
  } else if (targetBranchName && targetBranchName !== sessionBranches[repoName]) {
    getProjectData(projectData, targetBranchName)
      .then(function(projectData) {

        // The data for the target branch was retrieved succesfully,
        // Update the branch session variable. Done here rather than
        // earlier to avoid bad requests (nonsense refs) persisting.
        sessionBranches[repoName] = projectData.currentBranchName;
        return projectData;
      })
      .then(configuredRender)
      .catch(configuredPassError);

  // Else, generate the metadata and render the page.
  } else {
    getProjectData(projectData, sessionBranches[repoName])
      .then(configuredRender)
      .catch(configuredPassError);
  }
});

module.exports = router;
<commit_msg>Move the 'view' applying logic into a separate function.<commit_after>'use strict';

var path = require('path');

var express = require('express');
var router = express.Router();

var handlebars = require('hbs').handlebars;

var arrrayToTree = require('file-tree');
var TreeModel = require('tree-model');

var processFiles = require('../lib/specifications/files/process-files');
var countTags = require('../lib/specifications/files/feature-files/tags').count;

var getProject = require('../lib/specifications/projects/project').get;
var getProjectData = require('../lib/specifications/projects/project').getData;
var getFileContent = require('../lib/specifications/projects/project').getFileContent;

var appConfig = require('../lib/configuration/app-config').get();

function applyView(projectData, renderingData) {
  var currentViewName = renderingData.currentViewName;
  var view = {};
  var viewNames = [];

  // If the project config contains specified views use them.
  if (projectData.config) {
    viewNames = Object.keys(projectData.config.views);
  }

  if (viewNames.length > 0) {
    renderingData.hasViews = true;

    // No view specified, attempt to use a DEFAULT view.
    if (currentViewName === false) {
      // The defaultView value may be undefined, that will result in no view logic being applied.
      currentViewName = viewNames
                     .filter(function(name) {
                       return !!projectData.config.views[name].default;
                     })[0] || false;
    }

    // Generate view name data for the UI.
    renderingData.viewNames = viewNames.map(function (viewName) {
      return {
        name: viewName,
        urlEncodedName: encodeURIComponent(viewName),
        isCurrent: viewName === currentViewName
      };
    });

    // Explicit request for no view logic to be applied.
    if (currentViewName === 'none') {
      view = renderingData.view = false;

    // Grab any view config that might have been specified in the project config.
    } else {
      view = renderingData.view = projectData.config.views[currentViewName];
    }

    // Filter the file list based on the excludedPaths in project config.
    if (view && view.hasExcludedPaths) {
      projectData.files = projectData.files.filter(view.helpers.isIncludedPath);
    }

    // Filter the file list based on the anchor path in the project config.
    if (view && view.hasAnchor) {
      projectData.files = projectData.files.filter(view.helpers.isWithinAnchor);
    }
  }

  return [projectData, renderingData];
}

// Render the project page and send to client.
function getRender(res, appConfig, renderOptions) {
  return function render(projectData) {
    var renderingData = {};
    var projectTags = {};

    renderingData.openBurgerMenu = renderOptions.openBurgerMenu;
    renderingData.currentViewName = renderOptions.currentViewName;

    // Handle no project data being found.
    if (!projectData) {
      res.render('project', renderingData);
      return;
    }

    renderingData['project'] = projectData;

    // If there are no files in the project then don't
    // try and get file contents.
    if (!projectData.files.length) {
      res.render('project', renderingData);
      return;
    }

    // Applying views from configuration.
    // Chrome hasn't turned destructuring assignment on yet,
    // so I'm cheating
    var ret = applyView(projectData, renderingData);
    projectData = ret[0];
    renderingData = ret[1];

    /*
      Getting file content and rendering.
     */

    // Configure function for mapping file paths to file data.
    var pathToData = processFiles.getFilePathToFileObject(appConfig.projectRoute, projectData, getFileContent);

    // Map list of file paths to list of file data objects.
    projectData.files = projectData.files.map(pathToData);

    // Wait for content promises to resolve.
    // We don't actually care about the promise values here, they are already
    // part of the file object, we just need them all fulfilled or rejected.
    var promisesForFileContent = projectData.files.map(function(f) {return f.contentPromise;});
    return Promise.all(promisesForFileContent)
      .then(function() {
        var tagNames = [];

        // Mix in the file content.
        projectData.files = projectData.files.map(processFiles.processFileContent);

        // If the project config contains a URL format
        // for creating links to edit files then grab it.
        if (projectData.config.editUrlFormat) {
          projectData.files.forEach(function(file) {
            var editUrlTemplate = handlebars.compile(projectData.config.editUrlFormat);
            var editUrl = editUrlTemplate({
              repoUrl: projectData.repoUrl,
              repoUrlWithoutGitSuffix: projectData.repoUrl.replace(/\.git$/i, ''),
              branchName: projectData.currentShortBranchName,
              pathToFile: file.filePath
            });

            file.editUrl = editUrl;
          });
        }

        /*
          Applying filtering based on feature and scenario tags.
         */

        var currentTags = renderOptions.currentTags;
        // Count the tags in the project.
        projectData.files.forEach(function(file) {
          if (!file.isFeatureFile || file.error) {
            return;
          }

          // This counts tags and marks when an
          // object contains the requested tag.
          projectTags = countTags(file.data, projectTags, currentTags);
        });
        tagNames = Object.keys(projectTags);
        projectData.hasTags = !!tagNames.length;
        // Mark the currently requested tag if any,
        // this is used to set the selected option
        // in the tag select box.
        tagNames.forEach(function(name) {
          // Currently on one tag is passed in the query parameter.
          if (name === currentTags) {
            projectTags[name].isCurrent = true;
          }
        });
        projectData.tags = projectTags;

        // Filter the features and scenarios based on
        // whether they contain the requested tag.
        if (currentTags) {
          projectData.files = projectData.files.filter(function(file) {
            var feature;
            var featureScenarioContainsTag = false;

            // Filter out non-feature or erroring files.
            if (!file.isFeatureFile || file.error) {
              return false;
            }

            // If the feature contains the tag keep it and take no
            // further action.
            feature = file.data;
            if (feature.containsRequestedTag) {
              return true;
            }

            feature.scenarioDefinitions.forEach(function (scenario, index, defs) {

              // if any example contains the tag keep all examples.
              if (scenario.type === 'ScenarioOutline') {
                scenario.examples.forEach(function(example) {
                  if (example.containsRequestedTag) {
                    scenario.containsRequestedTag = true;
                  }
                });
              }
              if (scenario.containsRequestedTag) {
                featureScenarioContainsTag = true;
              } else {
                // Set the scenario to undefined so it won't be rendered.
                defs[index] = undefined;
              }
            });
            // Remove undefined scenarios because handlbars' `each`
            // helper doen't ignore undefined array elements.
            feature.scenarioDefinitions = feature.scenarioDefinitions.filter(function(scenario) { return scenario !== undefined; });

            // Retain or lose the feature depending on whether a scenario
            // contained the requested tag.
            return featureScenarioContainsTag;
          });
        }

        /*
          Generate a tree data structure from the flat file list.
         */
        var fileList = projectData.files.map(function(file) { return file.filePath; });

        arrrayToTree(fileList, function(filePath, next) {

          // Fix the assumption in file-tree that we are dealing with actual
          // files on disk.
          filePath = path.relative(appConfig.rootPath, filePath);

          // Use a loop to find the file matching this part of the tree.
          var currentFile = projectData.files.filter(function(file) {
            return filePath === file.filePath;
          })[0];

          // Link the file list and the tree structure by reference.
          var leaf = {
            name: filePath,
            file: currentFile,
            isFile: true
          };

          // Continue to generate the tree.
          next(null, leaf);
        }, function(err, fileTree) {

          // Tree generation is complete.
          // Wrap in tree model convenience object.
          var treeRoot = (new TreeModel()).parse({name: 'root', children: fileTree});

          // Use the tree to construct sets of files grouped by parent directory.
          var filesByDir = {};
          var fileNodes = treeRoot.all(function(node) { return node.model.isFile; });
          fileNodes.forEach(function(fileNode) {
            var pathToNode = fileNode.getPath();

            // Derive a directory path.
            var directoryNames = pathToNode
                                  .map(function(node) {
                                    var model = node.model;
                                    if (!node.isRoot() && !model.isFile) {
                                      return node.model.name;
                                    }
                                    return '';
                                  });
            var directoryPath = path.join.apply(path, directoryNames);

            // Store the file data keyed by containing directory.
            if (!filesByDir[directoryPath]) {
              filesByDir[directoryPath] = [];
            }
            filesByDir[directoryPath].push(fileNode.model.file);
          });

          // Reference the finished file tree on the rendering data object.
          renderingData['project'].filesByDir = filesByDir;

          // Render the page.
          res.render('project', renderingData);
        });
      });
  };
}

// Pass errors to the next Express middleware for handling.
function getPassError(next) {
  return function passError(err) {
    next(err);
  };
}

// List of available features in a project.
router.get(/^\/([^\/]+)$/, function(req, res, next) {

  // Cookie variables.
  var openBurgerMenu = (req.cookies.specsOpenBurgerMenu === 'true');

  // Session variable.
  if(!req.session.branches) req.session.branches = {};
  var sessionBranches = req.session.branches;

  // The repository name from the URL.
  var repoName = req.params[0];

  // Query param indicating a particular ref should
  // be used when retrieving repo data.
  var targetBranchName = req.query.branch || false;

  // Query param causing a Git fetch.
  var projectShouldUpdate = (req.query.update === 'true');

  // Query parameter containing desired named view from project config.
  var currentViewName = req.query.view || false;

  // Query parameter containing desired feature tags to filer on.
  var currentTags = req.query.tags || false;
  if (currentTags === 'none') {
    currentTags = false;
  }

  // Create rendering options.
  var renderOptions = {
    openBurgerMenu: openBurgerMenu,
    currentViewName: currentViewName,
    currentTags: currentTags
  };

  // Create the render and passError functions.
  var configuredRender = getRender(res, appConfig, renderOptions);
  var configuredPassError = getPassError(next);

  // TODO: Have one place this object is created.
  var projectData = {
    repoName: repoName,
    localPathRoot: appConfig.projectsPath
  };

  // Perform a clone or fetch on the repo then get the data.
  // If this switch is set then the branch will not change.
  if (projectShouldUpdate) {

    // Set the current branch name which will be used in the update.
    // If not supplied the repo default branch will be used.
    projectData.currentBranchName = sessionBranches[repoName] || false;

    // Update the repo and get the repo data.
    getProject(projectData)
      .then(configuredRender)
      .catch(configuredPassError);

  // Change the branch.
  } else if (targetBranchName && targetBranchName !== sessionBranches[repoName]) {
    getProjectData(projectData, targetBranchName)
      .then(function(projectData) {

        // The data for the target branch was retrieved succesfully,
        // Update the branch session variable. Done here rather than
        // earlier to avoid bad requests (nonsense refs) persisting.
        sessionBranches[repoName] = projectData.currentBranchName;
        return projectData;
      })
      .then(configuredRender)
      .catch(configuredPassError);

  // Else, generate the metadata and render the page.
  } else {
    getProjectData(projectData, sessionBranches[repoName])
      .then(configuredRender)
      .catch(configuredPassError);
  }
});

module.exports = router;
<|endoftext|>


<commit_before>/*
-----------------------------------------------------------------------------
Copyright (c) 2014-2016 Seth Anderson

This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the
use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software in a
product, an acknowledgment in the product documentation would be appreciated
but is not required.

2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.

3. This notice may not be removed or altered from any source distribution.
-----------------------------------------------------------------------------
*/

var mongoose = require("mongoose"),
	Lan = require("../model/lan.js"),
	Rsvp = require("../model/rsvp.js"),
	User = require("../model/user.js"),
	authorize = require("../authorization.js").authorize,
	authorizeSessionUser = require("../authorization.js").authorizeSessionUser,
	authenticate = require("../utils/common.js").authenticate,
	sanitizeBodyForDB = require("../utils/common.js").sanitizeBodyForDB,
	config = require("../utils/common.js").config,
	log = require("../utils/log.js"),
	Request = require("request");

module.exports = function(app, prefix, prefix2){
	app.get(prefix,
	function(req, res){
		Rsvp.find({})
		.populate("user lan", "email firstName lastName beginDate")
		.sort("-lan.beginDate")
		.exec(function(err, docs){
			if(err){
				res.status(500).end();
			}else{
				res.send(docs || []);
			}
		});
	});

	app.get(prefix + "/:rsvp",
	function(req, res){
		if(!mongoose.Types.ObjectId.isValid(req.params.rsvp)){
			return res.status(404).end();
		}
		Rsvp.findById(req.params.rsvp)
		.populate("user lan", "email firstName lastName beginDate")
		.exec(function(err, doc){
			if(err){
				res.status(500).end();
			}else if(!doc){
				res.status(404).end();
			}else{
				res.send(doc);
			}
		});
	});

	app.post(prefix,
		authenticate,
		authorize({hasRole: ["admin"]}),
		sanitizeBodyForDB,
	function(req, res){
		var rsvp = new Rsvp(req.body);
		rsvp.save(function(err){
			if(err){
				res.status(400).end();
			}else{
				res.status(201)
				.location(prefix2 + "/" + rsvp._id)
				.send({_id: rsvp._id});
			}
		});
	});

	app.put(prefix + "/:rsvp",
		authenticate,
		authorize({hasRoles: ["admin"]}),
		sanitizeBodyForDB,
	function(req, res){
		if(!mongoose.Types.ObjectId.isValid(req.params.rsvp)){
			return res.status(404).end();
		}
		Rsvp.findByIdAndUpdate(req.params.rsvp, req.body, function(err, doc){
			if(err){
				res.status(400).end();
			}else if(!doc){
				res.status(404).end();
			}else{
				res.status(200).end();
			}
		});
	});

	app.delete(prefix + "/:rsvp",
		authenticate,
		authorize({hasRoles: ["admin"]}),
	function(req, res){
		if(!mongoose.Types.ObjectId.isValid(req.params.rsvp)){
			return res.status(404).end();
		}
		Rsvp.findByIdAndRemove(req.params.rsvp, function(err, doc){
			if(err){
				res.status(400).end();
			}else if(!doc){
				res.status(404).end();
			}else{
				res.status(200).end();
			}
		});
	});

	app.get(prefix + "/year/:year",
	function(req, res){
		Lan.findOne({
			active: true,
			acceptingRsvps: true
		})
		.$where("this.beginDate.getFullYear() === " + req.params.year)
		.exec(function(err, lan){
			if(err){
				res.status(500).end();
			}else if(!lan){
				res.status(404).end();
			}else{
				Rsvp.find({lan: lan._id})
				.populate("user", "email firstName lastName primaryHandle")
				.exec(function(err, docs){
					if(err){
						res.status(500).end();
					}else{
						res.send(docs || []);
					}
				});
			}
		});
	});

	app.get(prefix2 + "/:year",
		authenticate,
		authorizeSessionUser(),
	function(req, res){
		if(!mongoose.Types.ObjectId.isValid(req.params.user)){
			return res.status(404).end();
		}

		Lan.findOne({
			active: true,
			acceptingRsvps: true
		})
		.$where("this.beginDate.getFullYear() === " + req.params.year)
		.exec(function(err, lan){
			if(err){
				res.status(500).end();
			}else if(!lan){
				res.status(404).end();
			}else{
				Rsvp.findOne({user: req.params.user}, function(err, doc){
					if(err){
						res.status(500).end();
					}else if(!doc){
						res.status(404).end();
					}else{
						res.send(doc);
					}
				});
			}
		});
	});

	app.put(prefix2 + "/:year",
		authenticate,
		authorizeSessionUser(),
	function(req, res){
		if(!mongoose.Types.ObjectId.isValid(req.params.user)){
			return res.status(404).end();
		}

		Lan.findOne({
			active: true,
			acceptingRsvps: true
		})
		.$where("this.beginDate.getFullYear() === " + req.params.year)
		.exec(function(err, lanDoc){
			if(err || !lanDoc){
				res.status(404).end();
			}else{
				Rsvp.findOne({user: req.params.user, lan: lanDoc._id}, function(err, rsvp){
					if(err || !rsvp){
						rsvp = new Rsvp();
						rsvp.user = req.params.user;
						rsvp.lan = lanDoc._id;
						rsvp.status = req.body.status;
						rsvp.playing = req.body.playing;
						rsvp.guests = req.body.guests;
						rsvp.cleaning = req.body.cleaning;
						rsvp.tournaments = req.body.tournaments;
						rsvp.bringingFood = req.body.bringingFood;
						rsvp.save(function(err){
							if(err){
								res.status(500).end();
							}else{
								res.status(201)
								.location(prefix + "/" + req.params.year)
								.end();
							}
						});
					}else{
						rsvp.status = req.body.status;
						rsvp.playing = req.body.playing;
						rsvp.guests = req.body.guests;
						rsvp.cleaning = req.body.cleaning;
						rsvp.tournaments = req.body.tournaments;
						rsvp.bringingFood = req.body.bringingFood;
						rsvp.save(function(err){
							if(err){
								res.status(500).end();
							}else{
								res.status(200).end();
							}
						});
					}

					// Send a notification to Slack
					if(config.slackRsvpHook.startsWith("http")){
						User.findById(req.params.user, function(err, user){
							if(!err && user){
								Request({
									method: "POST",
									uri: config.slackRsvpHook,
									json: {
										text: user.firstName + " " + user.lastName + " has RSVPed for LAN " + req.params.year + " (see the <https://www.3akm.com/appearances|full RSVP list>)"
									}
								}, function(err, res, body){
									if(err){
										log.warn("Slack notification failed with code: " + err.code + ".");
									}
								});
							}
						});
					}
				});
			}
		});
	});

	app.put(prefix2 + "/:year/attended",
		authenticate,
		authorizeSessionUser(),
	function(req, res){
		if(!mongoose.Types.ObjectId.isValid(req.params.user)){
			return res.status(404).end();
		}

		Lan.findOne({
			active: true,
			acceptingRsvps: true
		})
		.$where("this.beginDate.getFullYear() === " + req.params.year)
		.exec(function(err, lanDoc){
			if(err || !lanDoc){
				res.status(404).end();
			}else{
				Rsvp.findOne({user: req.params.user, lan: lanDoc._id}, function(err, doc){
					if(err || !doc){
						res.status(404).end();
					}else{
						doc.attended = true;
						doc.save(function(err){
							if(err){
								res.status(500).end();
							}else{
								res.status(200).end();
							}
						});
					}
				});
			}
		});
	});
}<commit_msg>Converted RSVP API<commit_after>/*
-----------------------------------------------------------------------------
Copyright (c) 2014-2016 Seth Anderson

This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the
use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software in a
product, an acknowledgment in the product documentation would be appreciated
but is not required.

2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.

3. This notice may not be removed or altered from any source distribution.
-----------------------------------------------------------------------------
*/

var mongoose = require("mongoose"),
	Lan = require("../model/lan.js"),
	Rsvp = require("../model/rsvp.js"),
	User = require("../model/user.js"),
	authorize = require("../authorization.js").authorize,
	authorizeSessionUser = require("../authorization.js").authorizeSessionUser,
	authenticate = require("../utils/common.js").authenticate,
	sanitizeBodyForDB = require("../utils/common.js").sanitizeBodyForDB,
	handleError = require("../utils/common.js").handleError,
	config = require("../utils/common.js").config,
	log = require("../utils/log.js"),
	Request = require("request");

module.exports = function(app, prefix, prefix2){
	app.get(prefix,
	function(req, res){
		Rsvp.find({})
		.populate("user lan", "email firstName lastName beginDate")
		.sort("-lan.beginDate")
		.exec()
		.then(function(rsvps){
			res.send(rsvps || []);
		}).catch(handleError(res));
	});

	app.get(prefix + "/:rsvp",
	function(req, res){
		if(!mongoose.Types.ObjectId.isValid(req.params.rsvp)){
			return res.status(404).end();
		}
		Rsvp.findById(req.params.rsvp)
		.populate("user lan", "email firstName lastName beginDate")
		.exec()
		.then(function(rsvp){
			if(!rsvp) throw 404;
			res.send(rsvp);
		}).catch(handleError(res));
	});

	app.post(prefix,
		authenticate,
		authorize({hasRole: ["admin"]}),
		sanitizeBodyForDB,
	function(req, res){
		var rsvp = new Rsvp(req.body);
		rsvp.save()
		.then(function(){
			res.status(201)
			.location(prefix2 + "/" + rsvp._id)
			.send({_id: rsvp._id});
		}).catch(function(err){
			throw 400;
		}).catch(handleError(res));
	});

	app.put(prefix + "/:rsvp",
		authenticate,
		authorize({hasRoles: ["admin"]}),
		sanitizeBodyForDB,
	function(req, res){
		if(!mongoose.Types.ObjectId.isValid(req.params.rsvp)){
			return res.status(404).end();
		}
		Rsvp.findByIdAndUpdate(req.params.rsvp, req.body)
		.then(function(rsvp){
			if(!rsvp) throw 404;
			res.status(200).end();
		}).catch(handleError(res));
	});

	app.delete(prefix + "/:rsvp",
		authenticate,
		authorize({hasRoles: ["admin"]}),
	function(req, res){
		if(!mongoose.Types.ObjectId.isValid(req.params.rsvp)){
			return res.status(404).end();
		}
		Rsvp.findByIdAndRemove(req.params.rsvp)
		.then(function(rsvp){
			if(!rsvp) throw 404;
			res.status(200).end();
		}).catch(handleError(res));
	});

	app.get(prefix + "/year/:year",
	function(req, res){
		Lan.findOne({
			active: true,
			acceptingRsvps: true
		})
		.$where("this.beginDate.getFullYear() === " + req.params.year).exec()
		.then(function(lan){
			if(!lan) throw 404;
			return Rsvp.find({lan: lan._id})
			.populate("user", "email firstName lastName primaryHandle")
			.exec();
		}).then(function(rsvps){
			res.send(rsvps || []);
		}).catch(handleError(res));
	});

	app.get(prefix2 + "/:year",
		authenticate,
		authorizeSessionUser(),
	function(req, res){
		if(!mongoose.Types.ObjectId.isValid(req.params.user)){
			return res.status(404).end();
		}

		Lan.findOne({
			active: true,
			acceptingRsvps: true
		})
		.$where("this.beginDate.getFullYear() === " + req.params.year)
		.exec()
		.then(function(lan){
			if(!lan) throw 404;
			return Rsvp.findOne({user: req.params.user});
		}).then(function(rsvp){
			if(!rsvp) throw 404;
			res.send(doc);
		}).catch(handleError(res));
	});

	app.put(prefix2 + "/:year",
		authenticate,
		authorizeSessionUser(),
	function(req, res){
		if(!mongoose.Types.ObjectId.isValid(req.params.user)){
			return res.status(404).end();
		}
		var lan, rsvp;

		Lan.findOne({
			active: true,
			acceptingRsvps: true
		})
		.$where("this.beginDate.getFullYear() === " + req.params.year)
		.exec()
		.then(function(doc){
			lan = doc;
			if(!lan) throw 404;
			return Rsvp.findOne({user: req.params.user, lan: lan._id});
		}).then(function(doc){
			rsvp = doc;
			if(!rsvp) throw 404;
			rsvp.status = req.body.status;
			rsvp.playing = req.body.playing;
			rsvp.guests = req.body.guests;
			rsvp.cleaning = req.body.cleaning;
			rsvp.tournaments = req.body.tournaments;
			rsvp.bringingFood = req.body.bringingFood;
			rsvp.save(function(err){
				if(err){
					res.status(400).end();
				}else{
					res.status(200).end();
				}
			});

			// Send a notification to Slack
			if(config.slackRsvpHook.startsWith("http")){
				User.findById(req.params.user)
				.then(function(user){
					if(user){
						Request({
							method: "POST",
							uri: config.slackRsvpHook,
							json: {
								text: user.firstName + " " + user.lastName + " has RSVPed for LAN " + req.params.year + " (see the <https://www.3akm.com/appearances|full RSVP list>)"
							}
						}, function(err, res, body){
							if(err){
								log.warn("Slack notification failed with code: " + err.code + ".");
							}
						});
					}
				});
			}
		}).catch(function(){
			rsvp = new Rsvp();
			rsvp.user = req.params.user;
			rsvp.lan = lan._id;
			rsvp.status = req.body.status;
			rsvp.playing = req.body.playing;
			rsvp.guests = req.body.guests;
			rsvp.cleaning = req.body.cleaning;
			rsvp.tournaments = req.body.tournaments;
			rsvp.bringingFood = req.body.bringingFood;
			rsvp.save(function(err){
				if(err){
					res.status(400).end();
				}else{
					res.status(201)
					.location(prefix + "/" + req.params.year)
					.end();
				}
			});
		});
	});

	app.put(prefix2 + "/:year/attended",
		authenticate,
		authorizeSessionUser(),
	function(req, res){
		if(!mongoose.Types.ObjectId.isValid(req.params.user)){
			return res.status(404).end();
		}

		Lan.findOne({
			active: true,
			acceptingRsvps: true
		})
		.$where("this.beginDate.getFullYear() === " + req.params.year)
		.exec()
		.then(function(lan){
			if(!lan) throw 404;
			return Rsvp.findOne({user: req.params.user, lan: lanDoc._id});
		}).then(function(rsvp){
			if(!rsvp) throw 404;
			rsvp.attended = true;
			return rsvp.save();
		}).then(function(){
			res.status(200).end();
		}).catch(handleError(res));
	});
}<|endoftext|>


<commit_before>var numerals = ['','I','II','III','IV','V','VI']

var armorNameLight1 = [
  "Estex",
  "Free booter",
  "Hazmat",
  "Skin",
  "Lashunta",
  "Kasatha",
  "Ysoki",
  "AbadarCorp",
  "Carbon",
  "Specialist",
  "Light",
  "Nanotube",
  "Complex",
  "Leather",
  "Aritificial",
  "Variable",
  "Reactive",
  "Ace-tech",
  "Icon",
  "Full Metal"
]

var armorNameLight2 = [
  "Armor",
  "Suit",
  "Flight Suit",
  "Microcord",
  "Stationwear",
  "Skin",
  "Travel Wear",
  "A","B","C","D",
  "Tempweave",
  "Series",
  "Microweave",
  "Night Shirt",
  "Shield",
  "Unisuit",
  "Vest",
  "Shirt",
  "Hardlight plate",
  "Jacket"
]

var armorNameHeavy1 = [
  "Re-entry",
  "Hard Weave",
  "Golemforged",
  "Vesk",
  "Voidshield",
  "Ceremonial",
  "Aegis",
  "Heavy",
  "Voidforged",
  "Reinforced",
  "Skyfire",
  "Metal",
  "Fused",
  "Temporal",
  "Energised",
  "Extra",
  "Cold Weather",
  "Armored"

]

var armorNameHeavy2 = [
  "Armor",
  "Suit",
  "Flight Suit",
  "Space Suit",
  "Series",
  "Overplate",
  "Plate",
  "Plating",
  "Monolith",
  "Ringwear",
  "Shield",
  "Breatplate",
  "Exoskeleton",
  "Super Suit",
  "Assistive Armor"
]

var indexCounter = 0;

var basePrice = [260,625,1415,2195,3230,4425,6350,9175,13300,17950,24400,35300,49600,72400,109750,170350,243850,370000,557450,832900];

var priceVariance = {
  "0.7":[-0.6,-0.4,-0.2,0,0.2,0.4,0.6,0.8],
  "0.2":[-0.2,-0.15,-0.1,-0.05,0,0.05,0.1,0.15,0.2],
  "0.15":[-0.15,-0.12,-0.1,-0.05,0,0.05,0.1,0.12,0.15],
  "0.1":[-0.1,-0.08,-0.06,-0.04,-0.02,0,0.02,0.04,0.06,0.08,0.1]
};

function getPrice(level) {
  var price;
  var variance;
  var rounding;
  var finish;
  var base = basePrice[level - 1];
  if (level == 1){
    variance = priceVariance["0.7"].selectRandom() * base;
    rounding = 10;
    finish = [0,5,-5].selectRandom();
  }
  else if (level == 2) {
    variance = priceVariance["0.2"].selectRandom() * base;
    rounding = 10;
    finish = [0,5,-5].selectRandom();
  }
  else if (level >= 3 && level <= 6) {
    variance = priceVariance["0.15"].selectRandom() * base;
    rounding = 100;
    finish = [0,50,-50].selectRandom();
  }
  else if (level >= 7 && level <= 19) {
    variance = priceVariance["0.1"].selectRandom() * base;
    rounding = 100;
    finish = [0,100,-100].selectRandom();
  }
  else if (level == 20) {
    variance = priceVariance["0.2"].selectRandom() * base;
    rounding = 100;
    finish = [0,100,-100].selectRandom();
  }
  price = (Math.floor((base + variance)/rounding)*rounding) + finish
  return price;
}

/**
 * Get the weapon's tier based on its item level.
 * @param level number
 *   An integer from 1 to 20.
 * @return number
 */
function getTier(level) {
  switch (level) {
    case 1: case 2: case 3: case 4:
      return 1;
    case 5: case 6: case 7: case 8:
      return 2;
    case 9: case 10: case 11: case 12:
      return 3;
    case 13: case 14: case 15: case 16:
      return 4;
    case 17: case 18: case 19: case 20:
      return 5;
    default:
      return NaN;
  }
}

function clearOutput() {
  var $outputArea = $(".output.area").first();
  $outputArea.empty();
  indexCounter = 0;
}

function printPanel(level,name,type,eac,kac,dex,acheck,speed,slots,bulk) {
  var $outputArea = $(".output.area").first();
  var storeOutput = $( "div.output.area" ).html();
  $outputArea.empty();

  indexCounter += 1;
  indexString = "index" + indexCounter.toString();

  var panelTitle =  "Level " + level + " " + name;
  var panelBody =   "
" + type + "
" +
                    "
Price: "+  getPrice(level) +
                    "
EAC: " + eac +
                    "
KAC: " + kac +
                    "
Max Dex Bonus: " + dex +
                    "
Armor Check Penalty: " + acheck +
                    "
Speed Adjustment: " + speed +
                    "
Upgrade Slots: " + slots +
                    "
Bulk: " + bulk + "
";

  $outputArea.append("
");
  var $panel = $(".panel."+indexString).first();
  $panel.append("

" + panelTitle + "

");
  $panel.append("
");
  var $index = $(".panel-body."+indexString).first();
  $index.append(panelBody);
  $index.append("<button type=\"button\" id=\""+indexString+"\"class=\"btn btn-default btn-sm btn-notblack pull-right\" onclick = \"removeEntry(this.id)\">Remove</button>");

  if (storeOutput != ""){
    $outputArea.append(storeOutput);
  }
}

function removeEntry(index) {
  $(".panel."+index).remove();
}

function generateArmor() {

  var level,tier,name;
  var armor,eac,kac,acheck,dex,speed,slots,bulk;

  var levelDrop = $('#levelPicker').val().trim();
  var armorDrop = $('#armorPicker').val().trim();

  //level
  if (levelDrop.includes("Any")) {
    level = getRandomInt(1, 20);
  } else if (levelDrop.includes("Tier")){
    tier = parseInt(levelDrop.replace("Tier ", ""));
    level = ((tier - 1) * 4 ) +getRandomInt(1, 4);
  } else if (levelDrop.includes("Level")){
    level = parseInt(levelDrop.replace("Level ", ""));
  } else {
    level = NaN;
    console.log('error getting level');
  }
  //tier
  tier = getTier(level);

  //level
  if (armorDrop.includes("Any")) {
    armor = ["Light armor","Heavy armor"].selectRandom();
  } else {
    armor = armorDrop;
  }

  if (armor == "Light armor") {

    //name
    name = armorNameLight1.selectRandom() + " " + armorNameLight2.selectRandom();
    name += ['',' ' + numerals[tier + [-1,0,1].selectRandom()]].selectRandom();

    //EAC
    if (level < 3) {
      eac = level + [-1,0].selectRandom();
    } else if (level < 6) {
      eac = level + [-2,-1,0,1].selectRandom();
    } else if (level < 11) {
      eac = level + [-1,0,1].selectRandom();
    } else {
      eac = level + [-1,0,1,2,3].selectRandom();
    }

    //KAC
    if (level < 4) {
      kac = eac + [1,2].selectRandom();
    } else if (level < 6) {
      kac = eac + [1].selectRandom();
    } else {
      kac = eac + [0,1,2].selectRandom();
    }

    //Max Dex
    dex = 2 + tier + [0,1,2,3].selectRandom();
    if (dex > 8){
      dex = 8;
    }

    //upgrade slots
    slots = tier + [-1,0,0,1,(-1*tier)].selectRandom();
    //armor check
    acheck = ['-','-','-','-1'].selectRandom();
    //speed adjustment
    speed = '-';
    //bulk
    bulk = ['L','L','1'].selectRandom();
  }
  else if (armor == "Heavy armor"){

    //name
    name = armorNameHeavy1.selectRandom() + " " + armorNameHeavy2.selectRandom();
    name += ['',' ' + numerals[tier + [-1,0,1].selectRandom()]].selectRandom();

    //EAC
    if (level < 3) {
      eac = level + [0,1,2].selectRandom();
    } else if (level < 6) {
      eac = level + [2,3,4,5].selectRandom();
    } else if (level < 11) {
      eac = level + [3,4,5].selectRandom();
    } else {
      eac = level + [4,5,6].selectRandom();
    }

    //KAC
    if (level < 4) {
      kac = eac + [1,2].selectRandom();
    } else {
      kac = eac + [1,2,3,1,2,3,4].selectRandom();
    }

    //Max Dex
    dex = tier + [-1,0,1].selectRandom();
    if (dex > 5){
      dex = 5;
    }

    //upgrade slots
    slots = tier + [-1,0,1,2].selectRandom();
    //armor check
    acheck = ['-','-2','-2','-3','-3','-4','-5'].selectRandom();
    //speed adjustment
    speed = ['-','-5 ft.','-5 ft.','-10 ft.','-10 ft.'].selectRandom();
    //bulk
    bulk = [1,2,2,3,3].selectRandom();

  }

  printPanel(level,name,armor,eac,kac,dex,acheck,speed,slots,bulk);
}

//runs when page is loaded
$( document ).ready(function() {
  //initialise pickers
  $('.selectpicker').selectpicker();
});
<commit_msg>more names<commit_after>var numerals = ['','I','II','III','IV','V','VI']

var armorNameLight1 = [
  "Estex",
  "Free booter",
  "Hazmat",
  "Skin",
  "Lashunta",
  "Kasatha",
  "Ysoki",
  "AbadarCorp",
  "Carbon",
  "Specialist",
  "Light",
  "Nanotube",
  "Complex",
  "Leather",
  "Aritificial",
  "Variable",
  "Reactive",
  "Ace-tech",
  "Icon",
  "Full Metal",
  "Padded",
  "Environmental"
]

var armorNameLight2 = [
  "Armor",
  "Suit",
  "Flight Suit",
  "Microcord",
  "Stationwear",
  "Skin",
  "Travel Wear",
  "A","B","C","D",
  "Tempweave",
  "Series",
  "Microweave",
  "Night Shirt",
  "Shield",
  "Unisuit",
  "Vest",
  "Shirt",
  "Hardlight plate",
  "Jacket",
  "Absorber",
  "Safeguard",
  "Undersuit"
]

var armorNameHeavy1 = [
  "Re-entry",
  "Hard Weave",
  "Golemforged",
  "Vesk",
  "Voidshield",
  "Ceremonial",
  "Aegis",
  "Heavy",
  "Voidforged",
  "Reinforced",
  "Skyfire",
  "Metal",
  "Fused",
  "Temporal",
  "Energised",
  "Extra",
  "Cold Weather",
  "Armored",
  "Nuar"

]

var armorNameHeavy2 = [
  "Armor",
  "Suit",
  "Flight Suit",
  "Space Suit",
  "Series",
  "Overplate",
  "Plate",
  "Plating",
  "Monolith",
  "Ringwear",
  "Shield",
  "Breatplate",
  "Exoskeleton",
  "Super Suit",
  "Assistive Armor",
  "Bulwark",
  "Battle Suit",
  "Assault Suit"
]

var indexCounter = 0;

var basePrice = [260,625,1415,2195,3230,4425,6350,9175,13300,17950,24400,35300,49600,72400,109750,170350,243850,370000,557450,832900];

var priceVariance = {
  "0.7":[-0.6,-0.4,-0.2,0,0.2,0.4,0.6,0.8],
  "0.2":[-0.2,-0.15,-0.1,-0.05,0,0.05,0.1,0.15,0.2],
  "0.15":[-0.15,-0.12,-0.1,-0.05,0,0.05,0.1,0.12,0.15],
  "0.1":[-0.1,-0.08,-0.06,-0.04,-0.02,0,0.02,0.04,0.06,0.08,0.1]
};

function getPrice(level) {
  var price;
  var variance;
  var rounding;
  var finish;
  var base = basePrice[level - 1];
  if (level == 1){
    variance = priceVariance["0.7"].selectRandom() * base;
    rounding = 10;
    finish = [0,5,-5].selectRandom();
  }
  else if (level == 2) {
    variance = priceVariance["0.2"].selectRandom() * base;
    rounding = 10;
    finish = [0,5,-5].selectRandom();
  }
  else if (level >= 3 && level <= 6) {
    variance = priceVariance["0.15"].selectRandom() * base;
    rounding = 100;
    finish = [0,50,-50].selectRandom();
  }
  else if (level >= 7 && level <= 19) {
    variance = priceVariance["0.1"].selectRandom() * base;
    rounding = 100;
    finish = [0,100,-100].selectRandom();
  }
  else if (level == 20) {
    variance = priceVariance["0.2"].selectRandom() * base;
    rounding = 100;
    finish = [0,100,-100].selectRandom();
  }
  price = (Math.floor((base + variance)/rounding)*rounding) + finish
  return price;
}

/**
 * Get the weapon's tier based on its item level.
 * @param level number
 *   An integer from 1 to 20.
 * @return number
 */
function getTier(level) {
  switch (level) {
    case 1: case 2: case 3: case 4:
      return 1;
    case 5: case 6: case 7: case 8:
      return 2;
    case 9: case 10: case 11: case 12:
      return 3;
    case 13: case 14: case 15: case 16:
      return 4;
    case 17: case 18: case 19: case 20:
      return 5;
    default:
      return NaN;
  }
}

function clearOutput() {
  var $outputArea = $(".output.area").first();
  $outputArea.empty();
  indexCounter = 0;
}

function printPanel(level,name,type,eac,kac,dex,acheck,speed,slots,bulk) {
  var $outputArea = $(".output.area").first();
  var storeOutput = $( "div.output.area" ).html();
  $outputArea.empty();

  indexCounter += 1;
  indexString = "index" + indexCounter.toString();

  var panelTitle =  "Level " + level + " " + name;
  var panelBody =   "
" + type + "
" +
                    "
Price: "+  getPrice(level) +
                    "
EAC: " + eac +
                    "
KAC: " + kac +
                    "
Max Dex Bonus: " + dex +
                    "
Armor Check Penalty: " + acheck +
                    "
Speed Adjustment: " + speed +
                    "
Upgrade Slots: " + slots +
                    "
Bulk: " + bulk + "
";

  $outputArea.append("
");
  var $panel = $(".panel."+indexString).first();
  $panel.append("

" + panelTitle + "

");
  $panel.append("
");
  var $index = $(".panel-body."+indexString).first();
  $index.append(panelBody);
  $index.append("<button type=\"button\" id=\""+indexString+"\"class=\"btn btn-default btn-sm btn-notblack pull-right\" onclick = \"removeEntry(this.id)\">Remove</button>");

  if (storeOutput != ""){
    $outputArea.append(storeOutput);
  }
}

function removeEntry(index) {
  $(".panel."+index).remove();
}

function generateArmor() {

  var level,tier,name;
  var armor,eac,kac,acheck,dex,speed,slots,bulk;

  var levelDrop = $('#levelPicker').val().trim();
  var armorDrop = $('#armorPicker').val().trim();

  //level
  if (levelDrop.includes("Any")) {
    level = getRandomInt(1, 20);
  } else if (levelDrop.includes("Tier")){
    tier = parseInt(levelDrop.replace("Tier ", ""));
    level = ((tier - 1) * 4 ) +getRandomInt(1, 4);
  } else if (levelDrop.includes("Level")){
    level = parseInt(levelDrop.replace("Level ", ""));
  } else {
    level = NaN;
    console.log('error getting level');
  }
  //tier
  tier = getTier(level);

  //level
  if (armorDrop.includes("Any")) {
    armor = ["Light armor","Heavy armor"].selectRandom();
  } else {
    armor = armorDrop;
  }

  if (armor == "Light armor") {

    //name
    name = armorNameLight1.selectRandom() + " " + armorNameLight2.selectRandom();
    name += ['',' ' + numerals[tier + [-1,0,1].selectRandom()]].selectRandom();

    //EAC
    if (level < 3) {
      eac = level + [-1,0].selectRandom();
    } else if (level < 6) {
      eac = level + [-2,-1,0,1].selectRandom();
    } else if (level < 11) {
      eac = level + [-1,0,1].selectRandom();
    } else {
      eac = level + [-1,0,1,2,3].selectRandom();
    }

    //KAC
    if (level < 4) {
      kac = eac + [1,2].selectRandom();
    } else if (level < 6) {
      kac = eac + [1].selectRandom();
    } else {
      kac = eac + [0,1,2].selectRandom();
    }

    //Max Dex
    dex = 2 + tier + [0,1,2,3].selectRandom();
    if (dex > 8){
      dex = 8;
    }

    //upgrade slots
    slots = tier + [-1,0,0,1,(-1*tier)].selectRandom();
    //armor check
    acheck = ['-','-','-','-1'].selectRandom();
    //speed adjustment
    speed = '-';
    //bulk
    bulk = ['L','L','1'].selectRandom();
  }
  else if (armor == "Heavy armor"){

    //name
    name = armorNameHeavy1.selectRandom() + " " + armorNameHeavy2.selectRandom();
    name += ['',' ' + numerals[tier + [-1,0,1].selectRandom()]].selectRandom();

    //EAC
    if (level < 3) {
      eac = level + [0,1,2].selectRandom();
    } else if (level < 6) {
      eac = level + [2,3,4,5].selectRandom();
    } else if (level < 11) {
      eac = level + [3,4,5].selectRandom();
    } else {
      eac = level + [4,5,6].selectRandom();
    }

    //KAC
    if (level < 4) {
      kac = eac + [1,2].selectRandom();
    } else {
      kac = eac + [1,2,3,1,2,3,4].selectRandom();
    }

    //Max Dex
    dex = tier + [-1,0,1].selectRandom();
    if (dex > 5){
      dex = 5;
    }

    //upgrade slots
    slots = tier + [-1,0,1,2].selectRandom();
    //armor check
    acheck = ['-','-2','-2','-3','-3','-4','-5'].selectRandom();
    //speed adjustment
    speed = ['-','-5 ft.','-5 ft.','-10 ft.','-10 ft.'].selectRandom();
    //bulk
    bulk = [1,2,2,3,3].selectRandom();

  }

  printPanel(level,name,armor,eac,kac,dex,acheck,speed,slots,bulk);
}

//runs when page is loaded
$( document ).ready(function() {
  //initialise pickers
  $('.selectpicker').selectpicker();
});
<|endoftext|>


<commit_before>/* eslint no-unused-vars:0 */
import React, { Component, PropTypes } from 'react';
import { build, getNext, getPrev } from './engines/carousel';
import { addListener, removeListener, globalStore } from './listener';
import { isBlocked, block } from './clock';
import { isActive } from './isActive';
import { execCb } from './funcHandler';
import { addKeyBinderToStore, _updateBinderState } from './redux/actions';
import { LEFT, RIGHT, DOWN, UP, ENTER } from './keys';

class Carousel extends Component {

  static get propTypes() {
    return {
      children: React.PropTypes.oneOfType([
        React.PropTypes.object,
        React.PropTypes.array,
      ]),
      id: PropTypes.string.isRequired,
      active: PropTypes.bool,
      index: PropTypes.number,
      size: PropTypes.number,
      speed: PropTypes.number,
      debounce: PropTypes.number,
      elWidth: PropTypes.number,
      circular: PropTypes.bool,
      className: PropTypes.string,
      childrenClassName: PropTypes.string,
      onChange: PropTypes.func,
      onDownExit: PropTypes.func,
      onUpExit: PropTypes.func,
      onEnter: PropTypes.func,
    };
  }

  static get defaultProps() {
    return {
      index: 0,
      size: 3,
      elWidth: 100,
      circular: true,
      active: true,
      speed: 100,
      debounce: 82,
      className: 'carousel',
      childrenClassName: 'carousel-child',
    };
  }

  constructor(props) {
    super(props);
    this.listenerId = addListener(this.keysHandler, this);
    this.timeout = null;
    this.sketch = [];
    this.movingCountDown = () => {
      this.timeout = setTimeout(() => _updateBinderState(props.id, { moving: false }), props.speed);
    };
    this.state = { cursor: props.index };
  }

  componentWillMount() {
    const { id, active, children } = this.props;
    addKeyBinderToStore(id, active);
    if (children.length !== 0) {
      this.initializeCarousel(children);
    }
  }

  componentWillUpdate(nextProps) {
    const { children } = nextProps;
    if (this.props.children.length === 0 && children.length !== 0) {
      this.initializeCarousel(children);
    }
  }

  initializeCarousel(children) {
    const { id, index } = this.props;
    this.selectedId = children[index].props.id;
    this.sketch = children.map(() => '');
    _updateBinderState(id, {
      selectedId: this.selectedId,
      cursor: index,
      moving: false,
    });
  }

  componentWillUnmount() {
    removeListener(this.listenerId);
  }

  performAction(cursor) {
    block(this.props.debounce);
    clearTimeout(this.timeout);
    this.selectedId = this.props.children[cursor].props.id;
    _updateBinderState(this.props.id, {
      selectedId: this.selectedId,
      cursor: cursor,
      moving: true,
    });
    this.setState({ cursor: cursor });
    this.movingCountDown();
    execCb(this.props.onChange, this.selectedId, this, this.props);
  }

  keysHandler(keyCode) {
    if (isActive(globalStore, this.props) && !isBlocked()) {
      const { cursor } = this.state;
      switch (keyCode) {
        case LEFT:
          if (!this.props.circular && cursor === 0) return;
          this.performAction(getPrev(this.sketch, cursor));
          break;
        case RIGHT:
          if (!this.props.circular && cursor === this.props.children.length - 1) return;
          this.performAction(getNext(this.sketch, cursor));
          break;
        case DOWN:
          this.performCallback(this.props.onDownExit);
          break;
        case UP:
          this.performCallback(this.props.onUpExit);
          break;
        case ENTER:
          this.performCallback(this.props.onEnter);
          break;
        default:
          break;
      }
    }
  }

  performCallback(callback) {
    if (callback) {
      block();
      execCb(callback, this.selectedId, this, this.props);
    }
  }

  render() {
    const { size, elWidth, speed, childrenClassName, circular, children, className } = this.props;
    const { cursor } = this.state;
    const ids = children.map((el, index) => index);
    const indexs = build(ids, size + 4, cursor, circular);
    return

      {children.map((el, index) => {
        if (indexs.indexOf(index) !== -1) {
          const x = (indexs.indexOf(index) - 2) * elWidth;
          return <div key={index} className={childrenClassName} style={{
            transform: `translate3d(${x}px, 0, 0)`,
            transition: (x === -(2 * elWidth) || x === (size + 1) * elWidth) ? `transform ${speed}ms` : 'none',
            willChange: "transform",
            opacity: (x === -(2 * elWidth) || x === (size + 1) * elWidth) ? 0 : 1,
          }}>{el}
;
        }
        return null;
      })}

;
  }

}

export default Carousel;
<commit_msg>fix animation issue<commit_after>/* eslint no-unused-vars:0 */
import React, { Component, PropTypes } from 'react';
import { build, getNext, getPrev } from './engines/carousel';
import { addListener, removeListener, globalStore } from './listener';
import { isBlocked, block } from './clock';
import { isActive } from './isActive';
import { execCb } from './funcHandler';
import { addKeyBinderToStore, _updateBinderState } from './redux/actions';
import { LEFT, RIGHT, DOWN, UP, ENTER } from './keys';

class Carousel extends Component {

  static get propTypes() {
    return {
      children: React.PropTypes.oneOfType([
        React.PropTypes.object,
        React.PropTypes.array,
      ]),
      id: PropTypes.string.isRequired,
      active: PropTypes.bool,
      index: PropTypes.number,
      size: PropTypes.number,
      speed: PropTypes.number,
      debounce: PropTypes.number,
      elWidth: PropTypes.number,
      circular: PropTypes.bool,
      className: PropTypes.string,
      childrenClassName: PropTypes.string,
      onChange: PropTypes.func,
      onDownExit: PropTypes.func,
      onUpExit: PropTypes.func,
      onEnter: PropTypes.func,
    };
  }

  static get defaultProps() {
    return {
      index: 0,
      size: 3,
      elWidth: 100,
      circular: true,
      active: true,
      speed: 100,
      debounce: 82,
      className: 'carousel',
      childrenClassName: 'carousel-child',
    };
  }

  constructor(props) {
    super(props);
    this.listenerId = addListener(this.keysHandler, this);
    this.timeout = null;
    this.sketch = [];
    this.movingCountDown = () => {
      this.timeout = setTimeout(() => _updateBinderState(props.id, { moving: false }), props.speed);
    };
    this.state = { cursor: props.index };
  }

  componentWillMount() {
    const { id, active, children } = this.props;
    addKeyBinderToStore(id, active);
    if (children.length !== 0) {
      this.initializeCarousel(children);
    }
  }

  componentWillUpdate(nextProps) {
    const { children } = nextProps;
    if (this.props.children.length === 0 && children.length !== 0) {
      this.initializeCarousel(children);
    }
  }

  initializeCarousel(children) {
    const { id, index } = this.props;
    this.selectedId = children[index].props.id;
    this.sketch = children.map(() => '');
    _updateBinderState(id, {
      selectedId: this.selectedId,
      cursor: index,
      moving: false,
    });
  }

  componentWillUnmount() {
    removeListener(this.listenerId);
  }

  performAction(cursor) {
    block(this.props.debounce);
    clearTimeout(this.timeout);
    this.selectedId = this.props.children[cursor].props.id;
    _updateBinderState(this.props.id, {
      selectedId: this.selectedId,
      cursor: cursor,
      moving: true,
    });
    this.setState({ cursor: cursor });
    this.movingCountDown();
    execCb(this.props.onChange, this.selectedId, this, this.props);
  }

  keysHandler(keyCode) {
    if (isActive(globalStore, this.props) && !isBlocked()) {
      const { cursor } = this.state;
      switch (keyCode) {
        case LEFT:
          if (!this.props.circular && cursor === 0) return;
          this.performAction(getPrev(this.sketch, cursor));
          break;
        case RIGHT:
          if (!this.props.circular && cursor === this.props.children.length - 1) return;
          this.performAction(getNext(this.sketch, cursor));
          break;
        case DOWN:
          this.performCallback(this.props.onDownExit);
          break;
        case UP:
          this.performCallback(this.props.onUpExit);
          break;
        case ENTER:
          this.performCallback(this.props.onEnter);
          break;
        default:
          break;
      }
    }
  }

  performCallback(callback) {
    if (callback) {
      block();
      execCb(callback, this.selectedId, this, this.props);
    }
  }

  render() {
    const { size, elWidth, speed, childrenClassName, circular, children, className } = this.props;
    const { cursor } = this.state;
    const ids = children.map((el, index) => index);
    const indexs = build(ids, size + 4, cursor, circular);
    return

      {children.map((el, index) => {
        if (indexs.indexOf(index) !== -1) {
          const x = (indexs.indexOf(index) - 2) * elWidth;
          return <div key={index} className={childrenClassName} style={{
            transform: `translate3d(${x}px, 0, 0)`,
            transition: (x === -(2 * elWidth) || x === (size + 1) * elWidth) ? 'none' : `transform ${speed}ms`,
            willChange: "transform",
            opacity: (x === -(2 * elWidth) || x === (size + 1) * elWidth) ? 0 : 1,
          }}>{el}
;
        }
        return null;
      })}

;
  }

}

export default Carousel;
<|endoftext|>


<commit_before>/**
 * Created by steve on 20/09/15.
 */
import React from 'react';
import ComposedComponent from './ComposedComponent';
import Checkbox from '@material-ui/core/Checkbox';
import FormGroup from '@material-ui/core/FormGroup';
import FormControlLabel from '@material-ui/core/FormControlLabel';

class FormCheckbox extends React.Component {

    handleChange = e => {
        this.props.onChangeValidate(e);
    };

    render() {
        // let value = selectOrSet(this.props.form.key, this.props.model);
        return (
            <FormGroup row={true}>
                <FormControlLabel
                    className={this.props.form.className}
                    label={this.props.form.title}
                    control={
                        <Checkbox
                            name={this.props.form.key.slice(-1)[0]}
                            value={this.props.form.key.slice(-1)[0]}
                            checked={this.props.value || false}
                            disabled={this.props.form.readonly}
                            onChange={this.handleChange}
                        />
                    }
                />
            </FormGroup>
        );
    }
}

export default ComposedComponent(FormCheckbox);
<commit_msg>Checkbox: fix eslint errors<commit_after>// @flow
/**
 * Created by steve on 20/09/15.
 */
import React, { Component } from "react";
import Checkbox from "@material-ui/core/Checkbox";
import FormGroup from "@material-ui/core/FormGroup";
import FormControlLabel from "@material-ui/core/FormControlLabel";
import ComposedComponent from "./ComposedComponent";

type Props = {
    onChangeValidate: any,
    form: any,
    value: any
};

class FormCheckbox extends Component<Props> {
    handleChange = e => {
        const { onChangeValidate } = this.props;
        onChangeValidate(e);
    };

    render() {
        const { form, value } = this.props;
        return (
            <FormGroup row>
                <FormControlLabel
                    className={form.className}
                    label={form.title}
                    control={
                        <Checkbox
                            name={form.key.slice(-1)[0]}
                            value={form.key.slice(-1)[0]}
                            checked={value || false}
                            disabled={form.readonly}
                            onChange={e => this.handleChange(e)}
                        />
                    }
                />
            </FormGroup>
        );
    }
}

export default ComposedComponent(FormCheckbox);
<|endoftext|>


<commit_before>import {EventEmitter} from 'events';
import Promise from 'bluebird';
import Collection from './Collection';

class Database extends EventEmitter {

  /**
   * Creates a new Database instance with the designated properties.
   * @param {Object} connectionProperties connection properties
   * @throws {TypeError} if arguments are of invalid type
   * @constructor
   */
  constructor(connectionProperties: Object) {
    // setup EventEmitter
    super();
    this.setMaxListeners(999);

    this.connectionProperties = connectionProperties;
    this.isConnected = false;
    this.Collection = Collection.bind(null, this);
  }

  /**
   * Connects to the database using the connection properties specified at construction time.
   * @param {Function<err>} [callback] an optional callback function.
   * @returns {Promise} a bluebird promise
   * @throws {TypeError} if arguments are of invalid type
   * @emits Database#connect
   */
  connect(callback: ?Function): Promise {
    // check if already connected
    if (this.isConnected) {
      return Promise.resolve().nodeify(callback);
    }

    // connect
    return Promise.resolve()
      .then(() => {
        this.isConnected = true;
        this.emit('connect');
      })
      .nodeify(callback);
  }

  /**
   * Disconnects from the database.
   * Please note: the database instance will become practically useless after calling this method.
   * @param {Function<Error>} [callback] an optional callback function.
   * @returns {Promise} a bluebird promise
   * @throws {TypeError} if arguments are of invalid type
   * @emits Database#disconnect
   */
  disconnect(callback: ?Function): Promise {
    // check if already disconnected
    if (!this.isConnected) {
      return Promise.resolve().nodeify(callback);
    }

    // disconnect
    return Promise.resolve()
      .then(() => {
        this.isConnected = false;
        this.emit('disconnect');
      })
      .nodeify(callback);
  }

  /**
   * Runs the given parameterized SQL statement.
   * @param {string} sql the SQL statement.
   * @param {Array} [params] an array of parameter values.
   * @param {Object} [options] query options.
   * @param {Function} [callback] a callback function with (err, records) arguments.
   * @returns {Promise} a bluebird promise resolving to the query results.
   * @throws {TypeError} if arguments are of invalid type
   */
  query(sql: string, params: ?Array, options: ?Object, callback: ?Function): Promise {
    return Promise.resolve([{}]).nodeify(callback);
  }

  /**
   * Awaits for the db to connect.
   * @param {number} [timeout=60000] optional maximum number of milliseconds to wait for connection - 1 min by default.
   * @return {Promise}
   * @private
   */
  _awaitConnect(timeout: ?number): Promise {
    timeout = timeout || 60000; // 1 min

    return new Promise((resolve) => {
      if (this.isConnected) {
        resolve();
      } else {
        this.once('connect', () => resolve());
      }
    });
  }

  /**
   * Creates and returns a new Collection with the specified properties.
   * @param {string} name the name of the collection.
   * @param {(Object, Schema)} [schema] optional collection schema.
   * @type {Collection}
   */
  createCollection(name: string, schema: Schema | ?Object): Collection {
    return new this.Collection(name, schema);
  }

}

export default Database;
<commit_msg>Bugfix: reference error<commit_after>import {EventEmitter} from 'events';
import Promise from 'bluebird';
import Collection from './Collection';
import Schema from './Schema';

class Database extends EventEmitter {

  /**
   * Creates a new Database instance with the designated properties.
   * @param {Object} connectionProperties connection properties
   * @throws {TypeError} if arguments are of invalid type
   * @constructor
   */
  constructor(connectionProperties: Object) {
    // setup EventEmitter
    super();
    this.setMaxListeners(999);

    this.connectionProperties = connectionProperties;
    this.isConnected = false;
    this.Collection = Collection.bind(null, this);
  }

  /**
   * Connects to the database using the connection properties specified at construction time.
   * @param {Function<err>} [callback] an optional callback function.
   * @returns {Promise} a bluebird promise
   * @throws {TypeError} if arguments are of invalid type
   * @emits Database#connect
   */
  connect(callback: ?Function): Promise {
    // check if already connected
    if (this.isConnected) {
      return Promise.resolve().nodeify(callback);
    }

    // connect
    return Promise.resolve()
      .then(() => {
        this.isConnected = true;
        this.emit('connect');
      })
      .nodeify(callback);
  }

  /**
   * Disconnects from the database.
   * Please note: the database instance will become practically useless after calling this method.
   * @param {Function<Error>} [callback] an optional callback function.
   * @returns {Promise} a bluebird promise
   * @throws {TypeError} if arguments are of invalid type
   * @emits Database#disconnect
   */
  disconnect(callback: ?Function): Promise {
    // check if already disconnected
    if (!this.isConnected) {
      return Promise.resolve().nodeify(callback);
    }

    // disconnect
    return Promise.resolve()
      .then(() => {
        this.isConnected = false;
        this.emit('disconnect');
      })
      .nodeify(callback);
  }

  /**
   * Runs the given parameterized SQL statement.
   * @param {string} sql the SQL statement.
   * @param {Array} [params] an array of parameter values.
   * @param {Object} [options] query options.
   * @param {Function} [callback] a callback function with (err, records) arguments.
   * @returns {Promise} a bluebird promise resolving to the query results.
   * @throws {TypeError} if arguments are of invalid type
   */
  query(sql: string, params: ?Array, options: ?Object, callback: ?Function): Promise {
    return Promise.resolve([{}]).nodeify(callback);
  }

  /**
   * Awaits for the db to connect.
   * @param {number} [timeout=60000] optional maximum number of milliseconds to wait for connection - 1 min by default.
   * @return {Promise}
   * @private
   */
  _awaitConnect(timeout: ?number): Promise {
    timeout = timeout || 60000; // 1 min

    return new Promise((resolve) => {
      if (this.isConnected) {
        resolve();
      } else {
        this.once('connect', () => resolve());
      }
    });
  }

  /**
   * Creates and returns a new Collection with the specified properties.
   * @param {string} name the name of the collection.
   * @param {(Object, Schema)} [schema] optional collection schema.
   * @type {Collection}
   */
  createCollection(name: string, schema: Schema | ?Object): Collection {
    return new this.Collection(name, schema);
  }

}

export default Database;
<|endoftext|>


<commit_before>//File name: app.js
//Description: the entry point to the chat app server
//Last updated: 4/28/2019

// Name of .jar file for BloomingLeaf project must be Blooming.jar
//var userPath = "/Users/<your user path here>/BloomingLeaf"
var userPath = "C:\\Users\\Katy\\Documents\\BloomingLeaf"

var http = require('http'),
    url = require('url'),
    fileServer = require('./node/fileServer.js'),
    fs = require('fs');
    qs = require('./node/query.js'),
    utils = require('./node/utils.js');
    exec = require('child_process').exec;

//TODO: If wait is not longer needed, this function can be removed.
function wait(ms){
   var start = new Date().getTime();
   var end = start;
   while(end < start + ms) {
     end = new Date().getTime();
  }
}

function processGet(path,queryObj,res) {
    // if URL includes a path to a file, call file server method
    if (path && path.length > 1) {
        // precede the given path with name of the subdirectory in which
        // the client files are stored

        fileServer.serve_static_file(userPath+"/leaf-ui"+path,res);
    }
    // check if there is a query. The query object will always be created
    // even if there is no quesry string. So check using a property that you
    // know will be part of any query sent by the client. This is application
    // specific - depends on our knowledge of what the client will serve
    // alternatively - you can check if (url.parse(req.url).search)
    // search is the query string
    /*else if (queryObj.request) {
        qs.processQuery(queryObj,res);
    } else {
        // if not file path or query were sent - read and serve default html file
        fileServer.serve_static_file("public_html/index.html",res);
        fileServed = true;
    }*/

}

function processPost(queryObj,req,res) {
    var body = '';
    req.on('data', data => {body += data;}); // get the request data
    req.on('end', () => {          // request fully received - process it
        if (body || queryObj.name) {
            queryObj.message = body; // specific to the chat application
            qs.processQuery(queryObj,res);
        }
    fs.writeFileSync(userPath+"/leaf-analysis/temp/default.json",body);
    passIntoJar(res);

    // //TODO: Can this function be written in an asynchronous call?
    // wait(1000);

    // //TODO: Can this be made asynchronous by moving the follow code down to to "HERE"
    // //read from output.out and pass the data as a string with the response
    // analysisFile = fs.readFileSync(userPath+"/leaf-analysis/temp/output.out");
    // analysisFileString = String(analysisFile);
    // res.writeHead(200, { "Content-Type" : 'text/plain'});
    // // send data
    // res.write(analysisFileString);
    // res.end();
    });

}

// server call back function
function handle_incoming_request(req, res) {
    // get the path of the file to served
    var path = url.parse(req.url).pathname;
    // get a query (true makes sure the query string is parsed into an object)
    var queryObj = url.parse(req.url,"true").query;
    if (req.method.toLowerCase() == "get")
        processGet(path,queryObj,res);
    else if (req.method.toLowerCase() == "post")
        processPost(queryObj,req,res);
    else
        utils.sendText(res,400,"Server accepts only GET ans POST requests");
}

/*
*This function executed the jar file
*/
function passIntoJar(res) {
    child = exec('java -jar '+userPath+'/leaf-analysis/bin/Blooming.jar ',
        function (error, stdout, stderr){
            if(error !== null){
                console.log('exec error: ' + error);
            }
            else{
                //Analysis return code.
                analysisFile = fs.readFileSync(userPath+"/leaf-analysis/temp/output.out");
                analysisFileString = String(analysisFile);
                res.writeHead(200, { "Content-Type" : 'text/plain'});
                // send data
                res.write(analysisFileString);
                res.end();

                return stdout;
            }
        });
    return child;
}

var server = http.createServer(handle_incoming_request);

server.listen(8080);<commit_msg>removeing my path back to default<commit_after>//File name: app.js
//Description: the entry point to the chat app server
//Last updated: 4/28/2019

// Name of .jar file for BloomingLeaf project must be Blooming.jar
//var userPath = "/Users/<your user path here>/BloomingLeaf"
var userPath = "/Users/judySmith/git/BloomingLeaf"

var http = require('http'),
    url = require('url'),
    fileServer = require('./node/fileServer.js'),
    fs = require('fs');
    qs = require('./node/query.js'),
    utils = require('./node/utils.js');
    exec = require('child_process').exec;

//TODO: If wait is not longer needed, this function can be removed.
function wait(ms){
   var start = new Date().getTime();
   var end = start;
   while(end < start + ms) {
     end = new Date().getTime();
  }
}

function processGet(path,queryObj,res) {
    // if URL includes a path to a file, call file server method
    if (path && path.length > 1) {
        // precede the given path with name of the subdirectory in which
        // the client files are stored

        fileServer.serve_static_file(userPath+"/leaf-ui"+path,res);
    }
    // check if there is a query. The query object will always be created
    // even if there is no quesry string. So check using a property that you
    // know will be part of any query sent by the client. This is application
    // specific - depends on our knowledge of what the client will serve
    // alternatively - you can check if (url.parse(req.url).search)
    // search is the query string
    /*else if (queryObj.request) {
        qs.processQuery(queryObj,res);
    } else {
        // if not file path or query were sent - read and serve default html file
        fileServer.serve_static_file("public_html/index.html",res);
        fileServed = true;
    }*/

}

function processPost(queryObj,req,res) {
    var body = '';
    req.on('data', data => {body += data;}); // get the request data
    req.on('end', () => {          // request fully received - process it
        if (body || queryObj.name) {
            queryObj.message = body; // specific to the chat application
            qs.processQuery(queryObj,res);
        }
    fs.writeFileSync(userPath+"/leaf-analysis/temp/default.json",body);
    passIntoJar(res);

    // //TODO: Can this function be written in an asynchronous call?
    // wait(1000);

    // //TODO: Can this be made asynchronous by moving the follow code down to to "HERE"
    // //read from output.out and pass the data as a string with the response
    // analysisFile = fs.readFileSync(userPath+"/leaf-analysis/temp/output.out");
    // analysisFileString = String(analysisFile);
    // res.writeHead(200, { "Content-Type" : 'text/plain'});
    // // send data
    // res.write(analysisFileString);
    // res.end();
    });

}

// server call back function
function handle_incoming_request(req, res) {
    // get the path of the file to served
    var path = url.parse(req.url).pathname;
    // get a query (true makes sure the query string is parsed into an object)
    var queryObj = url.parse(req.url,"true").query;
    if (req.method.toLowerCase() == "get")
        processGet(path,queryObj,res);
    else if (req.method.toLowerCase() == "post")
        processPost(queryObj,req,res);
    else
        utils.sendText(res,400,"Server accepts only GET ans POST requests");
}

/*
*This function executed the jar file
*/
function passIntoJar(res) {
    child = exec('java -jar '+userPath+'/leaf-analysis/bin/Blooming.jar ',
        function (error, stdout, stderr){
            if(error !== null){
                console.log('exec error: ' + error);
            }
            else{
                //Analysis return code.
                analysisFile = fs.readFileSync(userPath+"/leaf-analysis/temp/output.out");
                analysisFileString = String(analysisFile);
                res.writeHead(200, { "Content-Type" : 'text/plain'});
                // send data
                res.write(analysisFileString);
                res.end();

                return stdout;
            }
        });
    return child;
}

var server = http.createServer(handle_incoming_request);

server.listen(8080);<|endoftext|>


<commit_before>import React, { cloneElement } from 'react';
import keycode from 'keycode';
import classNames from 'classnames';
import uncontrollable from 'uncontrollable';
import ButtonGroup from './ButtonGroup';
import DropdownToggle from './DropdownToggle';
import DropdownMenu from './DropdownMenu';
import CustomPropTypes from './utils/CustomPropTypes';
import createChainedFunction from './utils/createChainedFunction';
import find from 'lodash/collection/find';
import omit from 'lodash/object/omit';

const TOGGLE_REF = 'toggle-btn';

export const TOGGLE_ROLE = DropdownToggle.defaultProps.bsRole;
export const MENU_ROLE = DropdownMenu.defaultProps.bsRole;

class Dropdown extends React.Component {

  constructor(props) {
    super(props);

    this.Toggle = DropdownToggle;

    this.toggleOpen = this.toggleOpen.bind(this);
    this.handleClick = this.handleClick.bind(this);
    this.handleKeyDown = this.handleKeyDown.bind(this);
    this.handleClose = this.handleClose.bind(this);
    this.extractChildren = this.extractChildren.bind(this);

    this.refineMenu = this.refineMenu.bind(this);
    this.refineToggle = this.refineToggle.bind(this);

    this.childExtractors = [{
      key: 'toggle',
      matches: child => child.props.bsRole === TOGGLE_ROLE,
      refine: this.refineToggle
    }, {
      key: 'menu',
      exclusive: true,
      matches: child => child.props.bsRole === MENU_ROLE,
      refine: this.refineMenu
    }];

    this.state = {};
  }

  componentDidMount() {
    let menu = this.refs.menu;
    if (this.props.open && menu.focusNext) {
      menu.focusNext();
    }
  }

  componentDidUpdate(prevProps, prevState) {
    let menu = this.refs.menu;
    if (this.props.open && !prevProps.open && menu.focusNext) {
      menu.focusNext();
    }
  }

  render() {
    let children = this.extractChildren();
    let Component = this.props.componentClass;

    let props = omit(this.props, ['id']);

    const rootClasses = {
      open: this.props.open,
      dropdown: !this.props.dropup,
      dropup: this.props.dropup
    };

    return (
      <Component
        {...props}
        className={classNames(this.props.className, rootClasses)}
      >
        { children }
      </Component>
    );
  }

  toggleOpen() {
    let open = !this.props.open;

    if (this.props.onToggle){
      this.props.onToggle(open);
    }
  }

  handleClick(event) {
    if (this.props.disabled) {
      return;
    }

    this.toggleOpen();
  }

  handleKeyDown(event) {
    let focusNext = () => {
      if (this.refs.menu.focusNext) {
        this.refs.menu.focusNext();
      }
    };

    switch(event.keyCode) {
    case keycode.codes.down:
      if (!this.props.open) {
        this.toggleOpen();
      } else {
        focusNext();
      }
      event.preventDefault();
      break;
    case keycode.codes.esc:
    case keycode.codes.tab:
      if (this.props.open) {
        this.handleClose(event);
      }
      break;
    default:
    }
  }

  handleClose(event) {
    if (!this.props.open) {
      return;
    }

    // we need to let the current event finish before closing the menu.
    // otherwise the menu may close, shifting focus to document.body, before focus has moved
    // to the next focusable input
    if (event && event.keyCode === keycode.codes.tab){
      setTimeout(this.toggleOpen);
    } else {
      this.toggleOpen();
    }

    if (event && event.type === 'keydown' && event.keyCode === keycode.codes.esc) {
      let toggle = React.findDOMNode(this.refs[TOGGLE_REF]);
      event.preventDefault();
      event.stopPropagation();
      toggle.focus();
    }
  }

  extractChildren() {
    let open = !!this.props.open;
    let seen = {};

    return React.Children.map(this.props.children, child => {
      let extractor = find(this.childExtractors, x => x.matches(child));

      if (extractor) {
        if (seen[extractor.key]){
          return false;
        }

        seen[extractor.key] = extractor.exclusive;
        child = extractor.refine(child, open);
      }

      return child;
    });
  }

  refineMenu(menu, open) {
    const menuProps = {
      ref: 'menu',
      open,
      labelledBy: this.props.id,
      pullRight: this.props.pullRight
    };

    menuProps.onClose = createChainedFunction(
      menu.props.onClose,
      this.props.onClose,
      this.handleClose
    );

    menuProps.onSelect = createChainedFunction(
      menu.props.onSelect,
      this.props.onSelect,
      this.handleClose
    );

    return cloneElement(menu, menuProps, menu.props.children);
  }

  refineToggle(toggle, open) {
    let toggleProps = {
      open,
      id: this.props.id,
      ref: TOGGLE_REF
    };

    toggleProps.onClick = createChainedFunction(
      toggle.props.onClick,
      this.handleClick
    );

    toggleProps.onKeyDown = createChainedFunction(
      toggle.props.onKeyDown,
      this.handleKeyDown
    );

    return cloneElement(toggle, toggleProps, toggle.props.children);
  }
}

Dropdown.Toggle = DropdownToggle;

Dropdown.TOGGLE_REF = TOGGLE_REF;

Dropdown.defaultProps = {
  componentClass: ButtonGroup
};

Dropdown.propTypes = {
  /**
   * The menu will open above the dropdown button, instead of below it.
   */
  dropup: React.PropTypes.bool,

  /**
   * An html id attribute, necessary for assistive technologies, such as screen readers.
   * @type {string|number}
   * @required
   */
  id: CustomPropTypes.isRequiredForA11y(
    React.PropTypes.oneOfType([
      React.PropTypes.string,
      React.PropTypes.number
    ])
  ),

  componentClass: CustomPropTypes.elementType,

  /**
   * The children of a Dropdown may be a `<Dropdown.Toggle/>` or a `<Dropdown.Menu/>`.
   * @type {node}
   */
  children: CustomPropTypes.all([
    CustomPropTypes.requiredRoles(TOGGLE_ROLE, MENU_ROLE),
    CustomPropTypes.exclusiveRoles(MENU_ROLE)
  ]),

  /**
   * Whether or not component is disabled.
   */
  disabled: React.PropTypes.bool,

  /**
   * Align the menu to the right  side of the Dropdown toggle
   */
  pullRight: React.PropTypes.bool,

  /**
   * Whether or not the Dropdown is visible.
   *
   * @controllable onToggle
   */
  open: React.PropTypes.bool,

  /**
   * A callback fired when the Dropdown closes.
   */
  onClose: React.PropTypes.func,

  /**
   * A callback fired when the Dropdown wishes to change visibility. Called with the requested
   * `open` value.
   *
   * ```js
   * function(Boolean isOpen){}
   * ```
   * @controllable open
   */
  onToggle: React.PropTypes.func,

  /**
   * A callback fired when a menu item is selected.
   *
   * ```js
   * function(Object event, Any eventKey)
   * ```
   */
  onSelect: React.PropTypes.func
};

Dropdown = uncontrollable(Dropdown, { open: 'onToggle' });

Dropdown.Toggle = DropdownToggle;
Dropdown.Menu = DropdownMenu;

export default Dropdown;
<commit_msg>[fixed] focus returns to the toggle by default onClose<commit_after>import React, { cloneElement } from 'react';
import keycode from 'keycode';
import classNames from 'classnames';
import uncontrollable from 'uncontrollable';
import ButtonGroup from './ButtonGroup';
import DropdownToggle from './DropdownToggle';
import DropdownMenu from './DropdownMenu';
import CustomPropTypes from './utils/CustomPropTypes';
import ValidComponentChildren from './utils/ValidComponentChildren';
import createChainedFunction from './utils/createChainedFunction';
import find from 'lodash/collection/find';
import omit from 'lodash/object/omit';

import activeElement from 'dom-helpers/activeElement';
import contains from 'dom-helpers/query/contains';

const TOGGLE_REF = 'toggle-btn';

export const TOGGLE_ROLE = DropdownToggle.defaultProps.bsRole;
export const MENU_ROLE = DropdownMenu.defaultProps.bsRole;

class Dropdown extends React.Component {

  constructor(props) {
    super(props);

    this.Toggle = DropdownToggle;

    this.toggleOpen = this.toggleOpen.bind(this);
    this.handleClick = this.handleClick.bind(this);
    this.handleKeyDown = this.handleKeyDown.bind(this);
    this.handleClose = this.handleClose.bind(this);
    this.extractChildren = this.extractChildren.bind(this);

    this.refineMenu = this.refineMenu.bind(this);
    this.refineToggle = this.refineToggle.bind(this);

    this.childExtractors = [{
      key: 'toggle',
      matches: child => child.props.bsRole === TOGGLE_ROLE,
      refine: this.refineToggle
    }, {
      key: 'menu',
      exclusive: true,
      matches: child => child.props.bsRole === MENU_ROLE,
      refine: this.refineMenu
    }];

    this.state = {};
  }

  componentDidMount() {
    let menu = this.refs.menu;
    if (this.props.open && menu.focusNext) {
      menu.focusNext();
    }
  }

  componentWillUpdate(nextProps) {
    if (!nextProps.open && this.props.open) {
      this._focusInDropdown = contains(
        React.findDOMNode(this.refs.menu),
        activeElement(document)
      );
    }
  }

  componentDidUpdate(prevProps) {
    let menu = this.refs.menu;

    if (this.props.open && !prevProps.open && menu.focusNext) {
      menu.focusNext();
    }

    if (!this.props.open && prevProps.open) {
      // if focus hasn't already moved from the menu lets return it
      // to the toggle
      if (this._focusInDropdown) {
        this._focusInDropdown = false;
        this.focus();
      }
    }
  }

  render() {
    let children = this.extractChildren();
    let Component = this.props.componentClass;

    let props = omit(this.props, ['id']);

    const rootClasses = {
      open: this.props.open,
      dropdown: !this.props.dropup,
      dropup: this.props.dropup
    };

    return (
      <Component
        {...props}
        tabIndex='-1'
        className={classNames(this.props.className, rootClasses)}
      >
        { children }
      </Component>
    );
  }

  toggleOpen() {
    let open = !this.props.open;

    if (this.props.onToggle) {
      this.props.onToggle(open);
    }
  }

  handleClick(event) {
    if (this.props.disabled) {
      return;
    }

    this.toggleOpen();
  }

  handleKeyDown(event) {
    let focusNext = () => {
      if (this.refs.menu.focusNext) {
        this.refs.menu.focusNext();
      }
    };

    switch(event.keyCode) {
    case keycode.codes.down:
      if (!this.props.open) {
        this.toggleOpen();
      } else {
        focusNext();
      }
      event.preventDefault();
      break;
    case keycode.codes.esc:
    case keycode.codes.tab:
      this.handleClose(event);
      break;
    default:
    }
  }

  handleClose(event) {
    if (!this.props.open) {
      return;
    }

    this.toggleOpen();
  }

  focus(){
    let toggle = React.findDOMNode(this.refs[TOGGLE_REF]);

    if (toggle && toggle.focus) {
      toggle.focus();
    }
  }

  extractChildren() {
    let open = !!this.props.open;
    let seen = {};

    return ValidComponentChildren.map(this.props.children, child => {
      let extractor = find(this.childExtractors, x => x.matches(child));

      if (extractor) {
        if (seen[extractor.key]){
          return false;
        }

        seen[extractor.key] = extractor.exclusive;
        child = extractor.refine(child, open);
      }

      return child;
    });
  }

  refineMenu(menu, open) {
    const menuProps = {
      ref: 'menu',
      open,
      labelledBy: this.props.id,
      pullRight: this.props.pullRight
    };

    menuProps.onClose = createChainedFunction(
      menu.props.onClose,
      this.props.onClose,
      this.handleClose
    );

    menuProps.onSelect = createChainedFunction(
      menu.props.onSelect,
      this.props.onSelect,
      this.handleClose
    );

    return cloneElement(menu, menuProps, menu.props.children);
  }

  refineToggle(toggle, open) {
    let toggleProps = {
      open,
      id: this.props.id,
      ref: TOGGLE_REF
    };

    toggleProps.onClick = createChainedFunction(
      toggle.props.onClick,
      this.handleClick
    );

    toggleProps.onKeyDown = createChainedFunction(
      toggle.props.onKeyDown,
      this.handleKeyDown
    );

    return cloneElement(toggle, toggleProps, toggle.props.children);
  }
}

Dropdown.Toggle = DropdownToggle;

Dropdown.TOGGLE_REF = TOGGLE_REF;

Dropdown.defaultProps = {
  componentClass: ButtonGroup
};

Dropdown.propTypes = {
  /**
   * The menu will open above the dropdown button, instead of below it.
   */
  dropup: React.PropTypes.bool,

  /**
   * An html id attribute, necessary for assistive technologies, such as screen readers.
   * @type {string|number}
   * @required
   */
  id: CustomPropTypes.isRequiredForA11y(
    React.PropTypes.oneOfType([
      React.PropTypes.string,
      React.PropTypes.number
    ])
  ),

  componentClass: CustomPropTypes.elementType,

  /**
   * The children of a Dropdown may be a `<Dropdown.Toggle/>` or a `<Dropdown.Menu/>`.
   * @type {node}
   */
  children: CustomPropTypes.all([
    CustomPropTypes.requiredRoles(TOGGLE_ROLE, MENU_ROLE),
    CustomPropTypes.exclusiveRoles(MENU_ROLE)
  ]),

  /**
   * Whether or not component is disabled.
   */
  disabled: React.PropTypes.bool,

  /**
   * Align the menu to the right  side of the Dropdown toggle
   */
  pullRight: React.PropTypes.bool,

  /**
   * Whether or not the Dropdown is visible.
   *
   * @controllable onToggle
   */
  open: React.PropTypes.bool,

  /**
   * A callback fired when the Dropdown closes.
   */
  onClose: React.PropTypes.func,

  /**
   * A callback fired when the Dropdown wishes to change visibility. Called with the requested
   * `open` value.
   *
   * ```js
   * function(Boolean isOpen){}
   * ```
   * @controllable open
   */
  onToggle: React.PropTypes.func,

  /**
   * A callback fired when a menu item is selected.
   *
   * ```js
   * function(Object event, Any eventKey)
   * ```
   */
  onSelect: React.PropTypes.func
};

Dropdown = uncontrollable(Dropdown, { open: 'onToggle' });

Dropdown.Toggle = DropdownToggle;
Dropdown.Menu = DropdownMenu;

export default Dropdown;
<|endoftext|>