<commit_before>var _ = require('lodash'),
    debug = require('debug')('freecc:cntr:courseware'),
    Courseware = require('./../models/Courseware'),
    User = require('./../models/User'),
    resources = require('./resources');

/**
 * Courseware controller
 */

exports.coursewareNames = function(req, res) {
    res.render('coursewares/showList', {
        coursewareList: resources.allCoursewareNames()
    });
};

exports.returnNextCourseware = function(req, res) {
    if (!req.user) {
        return res.redirect('../coursewares/start-our-challenges');
    }
    var completed = req.user.completedCoursewares.map(function (elem) {
        return elem._id;
    });

    req.user.uncompletedCoursewares = resources.allCoursewareIds().filter(function (elem) {
        if (completed.indexOf(elem) === -1) {
            return elem;
        }
    });
    req.user.save();

    var uncompletedCoursewares = req.user.uncompletedCoursewares;

    var displayedCoursewares =  Courseware.find({'_id': uncompletedCoursewares[0]});
    displayedCoursewares.exec(function(err, courseware) {
        if (err) {
            next(err);
        }
        courseware = courseware.pop();
        if (courseware === undefined) {
            req.flash('errors', {
                msg: "It looks like you've completed all the courses we have available. Good job!"
            })
            return res.redirect('../coursewares/start-our-challenges');
        }
        nameString = courseware.name.toLowerCase().replace(/\s/g, '-');
        return res.redirect('../coursewares/' + nameString);
    });
};

exports.returnIndividualCourseware = function(req, res, next) {
    var dashedName = req.params.coursewareName;

    coursewareName = dashedName.replace(/\-/g, ' ');

    Courseware.find({"name" : new RegExp(coursewareName, 'i')}, function(err, courseware) {
        if (err) {
            next(err);
        }
        // Handle not found
        if (courseware.length < 1) {
            req.flash('errors', {
            msg: "404: We couldn't find a challenge with that name. Please double check the name."
        });
            return res.redirect('/coursewares')
        }
        courseware = courseware.pop();

        // Redirect to full name if the user only entered a partial
        var dashedNameFull = courseware.name.toLowerCase().replace(/\s/g, '-');
        if (dashedNameFull != dashedName) {
            return res.redirect('../coursewares/' + dashedNameFull);
        }

        var challengeType = {
            0 : function() {
                res.render('coursewares/showHTML', {
                    title: courseware.name,
                    dashedName: dashedName,
                    name: courseware.name,
                    brief: courseware.description[0],
                    details: courseware.description.slice(1),
                    tests: courseware.tests,
                    challengeSeed: courseware.challengeSeed,
                    cc: !!req.user,
                    points: req.user ? req.user.points : undefined,
                    verb: resources.randomVerb(),
                    phrase: resources.randomPhrase(),
                    compliment: resources.randomCompliment(),
                    coursewareHash: courseware._id,
                    environment: resources.whichEnvironment()
                });
            },

            1 : function() {
                res.render('coursewares/showJS', {
                    title: courseware.name,
                    dashedName: dashedName,
                    name: courseware.name,
                    brief: courseware.description[0],
                    details: courseware.description.slice(1),
                    tests: courseware.tests,
                    challengeSeed: courseware.challengeSeed,
                    cc: !!req.user,
                    points: req.user ? req.user.points : undefined,
                    verb: resources.randomVerb(),
                    phrase: resources.randomPhrase(),
                    compliment: resources.randomCompliment(),
                    coursewareHash: courseware._id,
                    environment: resources.whichEnvironment()

                });
            },

            2: function() {
                res.render('coursewares/showVideo', {
                    title: courseware.name,
                    dashedName: dashedName,
                    name: courseware.name,
                    details: courseware.description,
                    tests: courseware.tests,
                    video: courseware.challengeSeed[0],
                    cc: !!req.user,
                    points: req.user ? req.user.points : undefined,
                    verb: resources.randomVerb(),
                    phrase: resources.randomPhrase(),
                    compliment: resources.randomCompliment(),
                    coursewareHash: courseware._id,
                    environment: resources.whichEnvironment()
                });
            }
        };

        return challengeType[courseware.challengeType]();

    });
};

exports.testCourseware = function(req, res) {
    var coursewareName = req.body.name,
        coursewareTests = req.body.tests,
        coursewareDifficulty = req.body.difficulty,
        coursewareDescription = req.body.description,
        coursewareEntryPoint = req.body.challengeEntryPoint,
        coursewareChallengeSeed = req.body.challengeSeed;
    coursewareTests = coursewareTests.split('\r\n');
    coursewareDescription = coursewareDescription.split('\r\n');
    coursewareTests.filter(getRidOfEmpties);
    coursewareDescription.filter(getRidOfEmpties);
    coursewareChallengeSeed = coursewareChallengeSeed.replace('\r', '');
    res.render('courseware/show', {
        completedWith: null,
        title: coursewareName,
        name: coursewareName,
        difficulty: +coursewareDifficulty,
        brief: coursewareDescription[0],
        details: coursewareDescription.slice(1),
        tests:  coursewareTests,
        challengeSeed:  coursewareChallengeSeed,
        challengeEntryPoint: coursewareEntryPoint,
        cc: req.user ? req.user.coursewaresHash : undefined,
        points: req.user ? req.user.points : undefined,
        verb: resources.randomVerb(),
        phrase: resources.randomPhrase(),
        compliment: resources.randomCompliment(),
        coursewares: [],
        coursewareHash: "test"
    });
};

function getRidOfEmpties(elem) {
    if (elem.length > 0) {
        return elem;
    }
};

exports.publicGenerator = function(req, res) {
    res.render('courseware/public-generator');
};

exports.generateChallenge = function(req, res) {
    var coursewareName = req.body.name,
        coursewareTests = req.body.tests,
        coursewareDifficulty = req.body.difficulty,
        coursewareDescription = req.body.description,
        coursewareEntryPoint = req.body.challengeEntryPoint,
        coursewareChallengeSeed = req.body.challengeSeed;
    coursewareTests = coursewareTests.split('\r\n');
    coursewareDescription = coursewareDescription.split('\r\n');
    coursewareTests.filter(getRidOfEmpties);
    coursewareDescription.filter(getRidOfEmpties);
    coursewareChallengeSeed = coursewareChallengeSeed.replace('\r', '');

    var response = {
        _id: randomString(),
        name: coursewareName,
        difficulty: coursewareDifficulty,
        description: coursewareDescription,
        challengeEntryPoint: coursewareEntryPoint,
        challengeSeed: coursewareChallengeSeed,
        tests: coursewareTests
    };
    res.send(response);
};

exports.completedCourseware = function (req, res) {

    var isCompletedDate = Math.round(+new Date() / 1000);
    var coursewareHash = req.body.coursewareInfo.coursewareHash;

    req.user.completedCoursewares.push({
        _id: coursewareHash,
        completedDate: isCompletedDate
    });

    var index = req.user.uncompletedCoursewares.indexOf(coursewareHash);
    if (index > -1) {
        req.user.points++;
        req.user.uncompletedCoursewares.splice(index, 1)
    }

    req.user.save(function (err, user) {
        if (err) {
            throw err;
        }
        if (user) {
            res.send(true)
        }
    });
};<commit_msg>fixed obvious error handlers<commit_after>var _ = require('lodash'),
    debug = require('debug')('freecc:cntr:courseware'),
    Courseware = require('./../models/Courseware'),
    User = require('./../models/User'),
    resources = require('./resources');

/**
 * Courseware controller
 */

exports.coursewareNames = function(req, res) {
    res.render('coursewares/showList', {
        coursewareList: resources.allCoursewareNames()
    });
};

exports.returnNextCourseware = function(req, res, next) {
    if (!req.user) {
        return res.redirect('../coursewares/start-our-challenges');
    }
    var completed = req.user.completedCoursewares.map(function (elem) {
        return elem._id;
    });

    req.user.uncompletedCoursewares = resources.allCoursewareIds().filter(function (elem) {
        if (completed.indexOf(elem) === -1) {
            return elem;
        }
    });

    // *****CALLBACK
    req.user.save();

    var uncompletedCoursewares = req.user.uncompletedCoursewares;

    var displayedCoursewares =  Courseware.find({'_id': uncompletedCoursewares[0]});
    displayedCoursewares.exec(function(err, courseware) {
        if (err) {
            return next(err);
        }
        courseware = courseware.pop();
        if (courseware === undefined) {
            req.flash('errors', {
                msg: "It looks like you've completed all the courses we have available. Good job!"
            })
            return res.redirect('../coursewares/start-our-challenges');
        }
        nameString = courseware.name.toLowerCase().replace(/\s/g, '-');
        return res.redirect('../coursewares/' + nameString);
    });
};

exports.returnIndividualCourseware = function(req, res, next) {
    var dashedName = req.params.coursewareName;

    coursewareName = dashedName.replace(/\-/g, ' ');

    Courseware.find({"name" : new RegExp(coursewareName, 'i')}, function(err, courseware) {
        if (err) {
            return next(err);
        }
        // Handle not found
        if (courseware.length < 1) {
            req.flash('errors', {
            msg: "404: We couldn't find a challenge with that name. Please double check the name."
        });
            return res.redirect('/coursewares')
        }
        courseware = courseware.pop();

        // Redirect to full name if the user only entered a partial
        var dashedNameFull = courseware.name.toLowerCase().replace(/\s/g, '-');
        if (dashedNameFull != dashedName) {
            return res.redirect('../coursewares/' + dashedNameFull);
        }

        var challengeType = {
            0 : function() {
                res.render('coursewares/showHTML', {
                    title: courseware.name,
                    dashedName: dashedName,
                    name: courseware.name,
                    brief: courseware.description[0],
                    details: courseware.description.slice(1),
                    tests: courseware.tests,
                    challengeSeed: courseware.challengeSeed,
                    cc: !!req.user,
                    points: req.user ? req.user.points : undefined,
                    verb: resources.randomVerb(),
                    phrase: resources.randomPhrase(),
                    compliment: resources.randomCompliment(),
                    coursewareHash: courseware._id,
                    environment: resources.whichEnvironment()
                });
            },

            1 : function() {
                res.render('coursewares/showJS', {
                    title: courseware.name,
                    dashedName: dashedName,
                    name: courseware.name,
                    brief: courseware.description[0],
                    details: courseware.description.slice(1),
                    tests: courseware.tests,
                    challengeSeed: courseware.challengeSeed,
                    cc: !!req.user,
                    points: req.user ? req.user.points : undefined,
                    verb: resources.randomVerb(),
                    phrase: resources.randomPhrase(),
                    compliment: resources.randomCompliment(),
                    coursewareHash: courseware._id,
                    environment: resources.whichEnvironment()

                });
            },

            2: function() {
                res.render('coursewares/showVideo', {
                    title: courseware.name,
                    dashedName: dashedName,
                    name: courseware.name,
                    details: courseware.description,
                    tests: courseware.tests,
                    video: courseware.challengeSeed[0],
                    cc: !!req.user,
                    points: req.user ? req.user.points : undefined,
                    verb: resources.randomVerb(),
                    phrase: resources.randomPhrase(),
                    compliment: resources.randomCompliment(),
                    coursewareHash: courseware._id,
                    environment: resources.whichEnvironment()
                });
            }
        };

        return challengeType[courseware.challengeType]();

    });
};

exports.testCourseware = function(req, res) {
    var coursewareName = req.body.name,
        coursewareTests = req.body.tests,
        coursewareDifficulty = req.body.difficulty,
        coursewareDescription = req.body.description,
        coursewareEntryPoint = req.body.challengeEntryPoint,
        coursewareChallengeSeed = req.body.challengeSeed;
    coursewareTests = coursewareTests.split('\r\n');
    coursewareDescription = coursewareDescription.split('\r\n');
    coursewareTests.filter(getRidOfEmpties);
    coursewareDescription.filter(getRidOfEmpties);
    coursewareChallengeSeed = coursewareChallengeSeed.replace('\r', '');
    res.render('courseware/show', {
        completedWith: null,
        title: coursewareName,
        name: coursewareName,
        difficulty: +coursewareDifficulty,
        brief: coursewareDescription[0],
        details: coursewareDescription.slice(1),
        tests:  coursewareTests,
        challengeSeed:  coursewareChallengeSeed,
        challengeEntryPoint: coursewareEntryPoint,
        cc: req.user ? req.user.coursewaresHash : undefined,
        points: req.user ? req.user.points : undefined,
        verb: resources.randomVerb(),
        phrase: resources.randomPhrase(),
        compliment: resources.randomCompliment(),
        coursewares: [],
        coursewareHash: "test"
    });
};

function getRidOfEmpties(elem) {
    if (elem.length > 0) {
        return elem;
    }
};

exports.publicGenerator = function(req, res) {
    res.render('courseware/public-generator');
};

exports.generateChallenge = function(req, res) {
    var coursewareName = req.body.name,
        coursewareTests = req.body.tests,
        coursewareDifficulty = req.body.difficulty,
        coursewareDescription = req.body.description,
        coursewareEntryPoint = req.body.challengeEntryPoint,
        coursewareChallengeSeed = req.body.challengeSeed;
    coursewareTests = coursewareTests.split('\r\n');
    coursewareDescription = coursewareDescription.split('\r\n');
    coursewareTests.filter(getRidOfEmpties);
    coursewareDescription.filter(getRidOfEmpties);
    coursewareChallengeSeed = coursewareChallengeSeed.replace('\r', '');

    var response = {
        _id: randomString(),
        name: coursewareName,
        difficulty: coursewareDifficulty,
        description: coursewareDescription,
        challengeEntryPoint: coursewareEntryPoint,
        challengeSeed: coursewareChallengeSeed,
        tests: coursewareTests
    };
    res.send(response);
};

exports.completedCourseware = function (req, res, next) {

    var isCompletedDate = Math.round(+new Date() / 1000);
    var coursewareHash = req.body.coursewareInfo.coursewareHash;

    req.user.completedCoursewares.push({
        _id: coursewareHash,
        completedDate: isCompletedDate
    });

    var index = req.user.uncompletedCoursewares.indexOf(coursewareHash);
    if (index > -1) {
        req.user.points++;
        req.user.uncompletedCoursewares.splice(index, 1)
    }

    req.user.save(function (err, user) {
        if (err) {
            return next(err);
        }
        if (user) {
            res.send(true)
        }
    });
};<|endoftext|>


<commit_before>/** @jsx React.DOM */

"use strict";
"use babel";

const async = require("async");
const _ = require("lodash");
const path = require("path");
const React = require('react-atom-fork');
const open_url = require("open");
const $ = require('atom-space-pen-views').$;
const utils = require("../utils");
const floorc = require("../common/floorc");
const api = require("../common/api");
const constants = require("../common/constants");
const mixins = require("./mixins");

module.exports = React.createClass({
  mixins: [mixins.ReactUnwrapper, mixins.FormMixin],
  getInitialState: function () {
    return {
      error: "",
      name: "",
      create: true,
      hosts: {},
      host: "",
      disabled_hosts: {},
      owner: "",
      // perms
      view: true,
      edit: false,
      needsMonies: false
    };
  },
  componentDidMount: function () {
    const d = utils.getRootDirectory();
    if (!d) {
      console.error("can't create a workspace without an open directory in atom");
      return this.destroy();
    }
    const state = this.state;
    state.name = d.getBaseName();
    if (_.has(floorc.auth, constants.HOST)) {
      state.host = constants.HOST;
      state.owner = floorc.auth[constants.HOST].username;
    } else {
      state.host = _.keys(floorc.auth)[0];
      state.owner = floorc.auth[state.host].username;
    }

    _.each(floorc.auth, function (auth, host) {
      state.hosts[host] = [auth.username];
    });

    this.setState(state);

    const that = this;
    async.each(_.keys(floorc.auth), function (host, cb) {
      const auth =  floorc.auth[host];
      api.get_orgs_can_admin(host, function (err, res, body) {
        const hosts = that.state.hosts;
        if (err) {
          that.state.disabled_hosts[host] = true;
          that.setState(that.state);
          console.error(err);
        } else {
          _.each(body, function (org) {
            hosts[host].push(org.name);
          });
          that.setState(hosts);
        }
        return cb();
      });
    }, function (err) {
      if (err) {
        console.error(err);
      }

      const name = that.refs.name.getDOMNode();
      const length = name.value.length;
      name.setSelectionRange(length, length);
      name.focus();
    });
  },
  join: function (url, created) {
    setTimeout(function () {
      // TODO: give the user the option of picking the directory if many are open
      // also can explode
      const d = utils.getRootDirectory().getPath();
      require("../floobits").join_workspace_(d, url, created);
    }, 0);
    this.destroy();
  },
  onSubmit: function (event) {
    event.preventDefault();
    const create = this.refs.create ? this.refs.create.getDOMNode().checked : true;
    if (!create) {
      this.join(this.props.url);
      return;
    }
    const edit = this.refs.edit.getDOMNode().checked;
    const view = this.refs.view.getDOMNode().checked;
    const perms = [];
    if (edit) {
      perms.push("edit_room");
      perms.push("view_room");
    }
    if (view) {
      perms.push("view_room");
    }
    const name = this.refs.name.getDOMNode().value;
    const host = this.state.host;
    const owner = this.state.owner;
    const room_perms = {AnonymousUser: perms};
    api.create_workspace(host, name, owner, room_perms, function (err, res, body) {
      console.log(err, res, body);
      const code = res.statusCode;

      if (code < 400) {
        const workspace = `http://${host}/${owner}/${name}`;
        console.log("created workspace", workspace);
        this.join(workspace, true);
        return;
      }
      console.error('Unable to create workspace: ', code, body);

      switch (code) {
        case 400:
          this.setState({
            needsMonies: false,
            name: name.replace(/[^A-Za-z0-9_\-\.]/g, "-"),
            error: "Workspace names may only contain [A-Za-z0-9_\-\.]."
          });
          return;
        case 402:
          this.setState({needsMonies: true, error: false});
          return;
        case 409:
          this.setState({
            error: "A workspace with that name already exists.",
            needsMonies: false,
            name: this.state.name+"1"}
          );
          return;
        default:
          this.setState({
            needsMonies: false,
            error: `Could not create workspace ${code}: ${body}`
          });
          return;
      }
    }.bind(this));
  },
  toggleCreate: function (event) {
    this.setState({create: event.target.checked});
  },
  onNameChange: function (event) {
    this.setState({name: event.target.value});
  },
  onSelectAuth: function (event) {
    this.setState({host: event.target.value});
  },
  render_auth: function () {
    const auths = _.keys(this.state.hosts);
    if (auths.length <= 1) {
      return;
    }
    auths.sort(function (a, b) {
      if (a === constants.HOST) {
        return -1;
      }
      if (b === constants.HOST) {
        return 1;
      }
      if (a === b) {
        return 0;
      } else if (a < b) {
        return -1;
      } else {
        return 1;
      }
    });
    const that = this;
    return (

        Host

          {auths.map(function (host) {
            const disabled = that.state.disabled_hosts[host];
            return (

                <input onChange={that.onSelectAuth} type="radio" name="host" value={host} tabIndex="3"
                  disabled={disabled} checked={host === that.state.host} className="native-key-bindings" /> {host}

            );
          })}

    );
  },
  onChangedOwner: function (event) {
    this.setState({owner: event.target.value});
  },
  onChangeView: function (event) {
    const state = {view: event.target.checked};
    if (!state.view) {
      state.edit = false;
    }
    this.setState(state);
  },
  onChangeEdit: function (event) {
    const state = {edit: event.target.checked};
    if (state.edit) {
      state.view = true;
    }
    this.setState(state);
  },
  render_create: function () {
    const owners = this.state.hosts[this.state.host];

    let username = floorc.auth[this.state.host];
    username = username && username.username;

    owners.sort(function (a, b) {
      if (a === username) {
        return -1;
      }
      if (b === username) {
        return 1;
      }
      if (a === b) {
        return 0;
      } else if (a < b) {
        return -1;
      } else {
        return 1;
      }
    });
    const that = this;
    const labels = owners.map(function (o) {
      return (

          <input type="radio" onChange={that.onChangedOwner} name="owner" tabIndex="5"
            value={o} className="native-key-bindings" checked={o===that.state.owner}/> {o}

      );
    });
    return (

        {this.render_auth()}

          Owner

            {labels}

          Name

            <input tabIndex="7" id="floobits-name" ref="name" className="native-key-bindings form-control" type="text" value={this.state.name} onChange={this.onNameChange}/>

          Description

            <textarea tabIndex="9" id="floobits-description" ref="description" className="native-key-bindings form-control" type="text" rows="3" />

          Global Permissions

              <input tabIndex="11" checked={this.state.view} onChange={this.onChangeView} type="checkbox" ref="view" value="view" className="native-key-bindings" /> Viewable

              <input tabIndex="13" checked={this.state.edit} type="checkbox" ref="edit" value="edit" onChange={this.onChangeEdit} className="native-key-bindings" /> Editable

    );
  },
  render_create_new_workspace_option: function () {
    const url = this.props.url;
    if (!url) {
      return;
    }
    return (

              The workspace {url} already exists.  Do you want to create a new workspace?

                <input id="floobits-create" ref="create" type="checkbox" tabIndex="1"
                  onChange={this.toggleCreate} checked={this.state.create} className="native-key-bindings" /> Create New Workspace

    );
  },
  openBilling: function (event) {
    event.preventDefault();
    open_url(`https://${this.state.host}/${this.state.owner}/settings#billing`);
  },
  render: function () {
    return (

Create Workspace

          <form id="join-workspace" className="form-horizontal native-key-bindings" onSubmit={this.onSubmit}>
            {this.render_create_new_workspace_option()}
            {this.state.create && this.render_create()}
            {!this.state.error ? "" :

                {this.state.error}

            }
            {!this.state.needsMonies ? "" :

                You reached the limit for workspaces for {this.state.host}/{this.state.owner}.

            }

              <input tabIndex="14" type="submit" value={this.state.create ? "Create Workspace" : "Join Workspace"} className="floobits-submit" />
              <input tabIndex="15" type="submit" value="Cancel" className="floobits-submit" onClick={this.destroy} />

          </form>

    );
  }
});<commit_msg>fixes race condition<commit_after>/** @jsx React.DOM */

"use strict";
"use babel";

const async = require("async");
const _ = require("lodash");
const path = require("path");
const React = require('react-atom-fork');
const open_url = require("open");
const $ = require('atom-space-pen-views').$;
const utils = require("../utils");
const floorc = require("../common/floorc");
const api = require("../common/api");
const constants = require("../common/constants");
const mixins = require("./mixins");

module.exports = React.createClass({
  mixins: [mixins.ReactUnwrapper, mixins.FormMixin],
  getInitialState: function () {
    return {
      error: "",
      name: "",
      create: true,
      hosts: {},
      host: "",
      disabled_hosts: {},
      owner: "",
      // perms
      view: true,
      edit: false,
      needsMonies: false
    };
  },
  componentWillMount: function () {
    const d = utils.getRootDirectory();
    if (!d) {
      console.error("can't create a workspace without an open directory in atom");
      return this.destroy();
    }
    const state = this.state;
    state.name = d.getBaseName();
    if (_.has(floorc.auth, constants.HOST)) {
      state.host = constants.HOST;
      state.owner = floorc.auth[constants.HOST].username;
    } else {
      state.host = _.keys(floorc.auth)[0];
      state.owner = floorc.auth[state.host].username;
    }

    _.each(floorc.auth, function (auth, host) {
      state.hosts[host] = [auth.username];
    });

    this.setState(state);

    const that = this;
    async.each(_.keys(floorc.auth), function (host, cb) {
      const auth =  floorc.auth[host];
      api.get_orgs_can_admin(host, function (err, res, body) {
        const hosts = that.state.hosts;
        if (err) {
          that.state.disabled_hosts[host] = true;
          that.setState(that.state);
          console.error(err);
        } else {
          _.each(body, function (org) {
            hosts[host].push(org.name);
          });
          that.setState(hosts);
        }
        return cb();
      });
    }, function (err) {
      if (err) {
        console.error(err);
      }

      const name = that.refs.name.getDOMNode();
      const length = name.value.length;
      name.setSelectionRange(length, length);
      name.focus();
    });
  },
  join: function (url, created) {
    setTimeout(function () {
      // TODO: give the user the option of picking the directory if many are open
      // also can explode
      const d = utils.getRootDirectory().getPath();
      require("../floobits").join_workspace_(d, url, created);
    }, 0);
    this.destroy();
  },
  onSubmit: function (event) {
    event.preventDefault();
    const create = this.refs.create ? this.refs.create.getDOMNode().checked : true;
    if (!create) {
      this.join(this.props.url);
      return;
    }
    const edit = this.refs.edit.getDOMNode().checked;
    const view = this.refs.view.getDOMNode().checked;
    const perms = [];
    if (edit) {
      perms.push("edit_room");
      perms.push("view_room");
    }
    if (view) {
      perms.push("view_room");
    }
    const name = this.refs.name.getDOMNode().value;
    const host = this.state.host;
    const owner = this.state.owner;
    const room_perms = {AnonymousUser: perms};
    api.create_workspace(host, name, owner, room_perms, function (err, res, body) {
      console.log(err, res, body);
      const code = res.statusCode;

      if (code < 400) {
        const workspace = `http://${host}/${owner}/${name}`;
        console.log("created workspace", workspace);
        this.join(workspace, true);
        return;
      }
      console.error('Unable to create workspace: ', code, body);

      switch (code) {
        case 400:
          this.setState({
            needsMonies: false,
            name: name.replace(/[^A-Za-z0-9_\-\.]/g, "-"),
            error: "Workspace names may only contain [A-Za-z0-9_\-\.]."
          });
          return;
        case 402:
          this.setState({needsMonies: true, error: false});
          return;
        case 409:
          this.setState({
            error: "A workspace with that name already exists.",
            needsMonies: false,
            name: this.state.name+"1"}
          );
          return;
        default:
          this.setState({
            needsMonies: false,
            error: `Could not create workspace ${code}: ${body}`
          });
          return;
      }
    }.bind(this));
  },
  toggleCreate: function (event) {
    this.setState({create: event.target.checked});
  },
  onNameChange: function (event) {
    this.setState({name: event.target.value});
  },
  onSelectAuth: function (event) {
    this.setState({host: event.target.value});
  },
  render_auth: function () {
    const auths = _.keys(this.state.hosts);
    if (auths.length <= 1) {
      return;
    }
    auths.sort(function (a, b) {
      if (a === constants.HOST) {
        return -1;
      }
      if (b === constants.HOST) {
        return 1;
      }
      if (a === b) {
        return 0;
      } else if (a < b) {
        return -1;
      } else {
        return 1;
      }
    });
    const that = this;
    return (

        Host

          {auths.map(function (host) {
            const disabled = that.state.disabled_hosts[host];
            return (

                <input onChange={that.onSelectAuth} type="radio" name="host" value={host} tabIndex="3"
                  disabled={disabled} checked={host === that.state.host} className="native-key-bindings" /> {host}

            );
          })}

    );
  },
  onChangedOwner: function (event) {
    this.setState({owner: event.target.value});
  },
  onChangeView: function (event) {
    const state = {view: event.target.checked};
    if (!state.view) {
      state.edit = false;
    }
    this.setState(state);
  },
  onChangeEdit: function (event) {
    const state = {edit: event.target.checked};
    if (state.edit) {
      state.view = true;
    }
    this.setState(state);
  },
  render_create: function () {
    const owners = this.state.hosts[this.state.host];

    let username = floorc.auth[this.state.host];
    username = username && username.username;

    owners.sort(function (a, b) {
      if (a === username) {
        return -1;
      }
      if (b === username) {
        return 1;
      }
      if (a === b) {
        return 0;
      } else if (a < b) {
        return -1;
      } else {
        return 1;
      }
    });
    const that = this;
    const labels = owners.map(function (o) {
      return (

          <input type="radio" onChange={that.onChangedOwner} name="owner" tabIndex="5"
            value={o} className="native-key-bindings" checked={o===that.state.owner}/> {o}

      );
    });
    return (

        {this.render_auth()}

          Owner

            {labels}

          Name

            <input tabIndex="7" id="floobits-name" ref="name" className="native-key-bindings form-control" type="text" value={this.state.name} onChange={this.onNameChange}/>

          Description

            <textarea tabIndex="9" id="floobits-description" ref="description" className="native-key-bindings form-control" type="text" rows="3" />

          Global Permissions

              <input tabIndex="11" checked={this.state.view} onChange={this.onChangeView} type="checkbox" ref="view" value="view" className="native-key-bindings" /> Viewable

              <input tabIndex="13" checked={this.state.edit} type="checkbox" ref="edit" value="edit" onChange={this.onChangeEdit} className="native-key-bindings" /> Editable

    );
  },
  render_create_new_workspace_option: function () {
    const url = this.props.url;
    if (!url) {
      return;
    }
    return (

              The workspace {url} already exists.  Do you want to create a new workspace?

                <input id="floobits-create" ref="create" type="checkbox" tabIndex="1"
                  onChange={this.toggleCreate} checked={this.state.create} className="native-key-bindings" /> Create New Workspace

    );
  },
  openBilling: function (event) {
    event.preventDefault();
    open_url(`https://${this.state.host}/${this.state.owner}/settings#billing`);
  },
  render: function () {
    return (

Create Workspace

          <form id="join-workspace" className="form-horizontal native-key-bindings" onSubmit={this.onSubmit}>
            {this.render_create_new_workspace_option()}
            {this.state.create && this.render_create()}
            {!this.state.error ? "" :

                {this.state.error}

            }
            {!this.state.needsMonies ? "" :

                You reached the limit for workspaces for {this.state.host}/{this.state.owner}.

            }

              <input tabIndex="14" type="submit" value={this.state.create ? "Create Workspace" : "Join Workspace"} className="floobits-submit" />
              <input tabIndex="15" type="submit" value="Cancel" className="floobits-submit" onClick={this.destroy} />

          </form>

    );
  }
});<|endoftext|>


<commit_before>module.exports = function(app){
  app.get('/pagamentos', function(req, res){
    console.log('Recebida requisicao de teste na porta 3000.')
    res.send('OK.');
  });

  app.post('/pagamentos/pagamento', function(req, res){

    req.assert("forma_de_pagamento",
        "Forma de pagamento eh obrigatorio").notEmpty();
    req.assert("valor",
      "Valor eh obrigatorio e deve ser um decimal")
        .notEmpty().isFloat();

    var erros = req.validationErrors();

    if (erros){
      console.log('Erros de validacao encontrados');
      res.status(400).send(erros);
      return;
    }

    var pagamento = req.body;
    console.log('processando uma requisicao de um novo pagamento');

    pagamento.status = 'CRIADO';
    pagamento.data = new Date;

    var connection = app.persistencia.connectionFactory();
    var pagamentoDao = new app.persistencia.PagamentoDao(connection);

    pagamentoDao.salva(pagamento, function(erro, resultado){
      if(erro){
        console.log('Erro ao inserir no banco:' + erro);
        res.status(500).send(erro);
      } else {
      console.log('pagamento criado');
      res.location('/pagamentos/pagamento/' +
            resultado.insertId);

      res.status(201).json(pagamento);
    }
    });

  });
}
<commit_msg>add inserts teste<commit_after>module.exports = function(app){
  app.get('/pagamentos', function(req, res){
    console.log('Recebida requisicao de teste na porta 3000.')
    res.send('OK.');
  });

  app.post('/pagamentos/pagamento', function(req, res){

    req.assert("forma_de_pagamento",
        "Forma de pagamento eh obrigatorio").notEmpty();
    req.assert("valor",
      "Valor eh obrigatorio e deve ser um decimal")
        .notEmpty().isFloat();

    var erros = req.validationErrors();

    if (erros){
      console.log('Erros de validacao encontrados');
      res.status(400).send(erros);
      return;
    }

    var pagamento = req.body;
    console.log('processando uma requisicao de um novo pagamento');

    pagamento.status = 'CRIADO';
    pagamento.data = new Date;

    var connection = app.persistencia.connectionFactory();
    var pagamentoDao = new app.persistencia.PagamentoDao(connection);

    pagamentoDao.salva(pagamento, function(erro, resultado){
      if(erro){
        console.log('Erro ao inserir no banco:' + erro);
        res.status(500).send(erro);
      } else {
      console.log('pagamento criado');
      res.location('/pagamentos/pagamento/' +
            resultado.insertId);

      res.status(201).json(pagamento);
    }
    });

  });

  app.get('/pagamentos/pagamento/:id', function(req, res){
    var id = req.params.id;
    console.log('consultando pagamento: ' + id);

    var connection = app.persistencia.connectionFactory();
    var pagamentoDao = new app.persistencia.PagamentoDao(connection);

    pagamentoDao.buscaPorId(id, function(erro, resultado){
      if(erro){
        console.log('erro ao consultar no banco: ' + erro);
        res.status(500).send(erro);
        return;
      }
      console.log('pagamento encontrado: ' + JSON.stringify(resultado));
      res.json(resultado);
      return;
    });

  });
}
<|endoftext|>


<commit_before>// @flow

import path from 'path';
import {
  Compiler
} from 'webpack';
import {
  SourceMapConsumer
} from 'source-map';
import createDebug from 'debug';
import type {
  UserIsomorphicWebpackConfigurationType
} from '../types';
import evalCodeInBrowser from '../utilities/evalCodeInBrowser';
import getEntryScriptPath from '../utilities/getEntryScriptPath';
import createCompiler from './createCompiler';
import createCompilerCallback from './createCompilerCallback';
import createCompilerConfiguration from './createCompilerConfiguration';
import createIsomorphicWebpackConfiguration from './createIsomorphicWebpackConfiguration';

const debug = createDebug('isomorphic-webpack');

type IsomorphicWebpackType = {|

  /**
   * @see https://webpack.github.io/docs/node.js-api.html#compiler
   */
  compiler: Compiler,
  createCompilationPromise: Function,
  evalBundleCode: Function,
  formatErrorStack: Function
|};

type ErrorPositionType = {|
  +column: number,
  +line: number,
  +source: string
|};

export default (webpackConfiguration: Object, userIsomorphicWebpackConfiguration?: UserIsomorphicWebpackConfigurationType): IsomorphicWebpackType => {
  const isomorphicWebpackConfiguration = createIsomorphicWebpackConfiguration(userIsomorphicWebpackConfiguration);
  const compilerConfiguration = createCompilerConfiguration(webpackConfiguration, isomorphicWebpackConfiguration.nodeExternalsWhitelist);
  const compiler = createCompiler(compilerConfiguration);

  let createCompilationPromise;

  /**
   * @see https://github.com/gajus/isomorphic-webpack#isomorphic-webpack-faq-how-to-delay-request-handling-while-compilation-is-in-progress
   */
  if (isomorphicWebpackConfiguration.useCompilationPromise) {
    let compilationPromise;
    let compilationPromiseResolve;
    let compilationPromiseIsResolved = true;

    createCompilationPromise = () => {
      return compilationPromise;
    };

    compiler.plugin('compile', () => {
      debug('compiler event: compile (compilationPromiseIsResolved: %s)', compilationPromiseIsResolved);

      if (!compilationPromiseIsResolved) {
        return;
      }

      compilationPromiseIsResolved = false;

      compilationPromise = new Promise((resolve) => {
        compilationPromiseResolve = resolve;
      });
    });

    compiler.plugin('done', () => {
      debug('compiler event: done');

      compilationPromiseIsResolved = true;

      compilationPromiseResolve();
    });
  } else {
    createCompilationPromise = () => {
      throw new Error('"createCompilationPromise" feature has not been enabled.');
    };
  }

  let bundleSourceMapConsumer;

  let currentBundleCode;
  let currentRequestMap;

  const evalBundleCode = (windowUrl?: string) => {
    const requireModule = evalCodeInBrowser(currentBundleCode, {}, windowUrl);

    const entryScriptPath = getEntryScriptPath(compiler.options.entry);

    debug('entryScriptPath', entryScriptPath);

    // @todo Make it work in Windows.
    const relativeEntryScriptPath = './' + path.relative(webpackConfiguration.context, require.resolve(entryScriptPath));

    const moduleId = currentRequestMap[relativeEntryScriptPath];

    if (typeof moduleId !== 'number') {
      throw new Error('Cannot determine entry module ID.');
    }

    debug('evaluating module ID %i', moduleId);

    return requireModule(moduleId);
  };

  const compilerCallback = createCompilerCallback(compiler, ({
    bundleCode,
    bundleSourceMap,
    requestMap
  }) => {
    bundleSourceMapConsumer = new SourceMapConsumer(bundleSourceMap);
    currentBundleCode = bundleCode;
    currentRequestMap = requestMap;
  });

  compiler.watch({}, compilerCallback);

  const isOriginalPositionDiscoverable = (lineNumber: number, columnNumber: number): boolean => {
    const originalPosition = bundleSourceMapConsumer.originalPositionFor({
      column: columnNumber,
      line: lineNumber
    });

    return originalPosition.source !== null && originalPosition.line !== null && originalPosition.column !== null;
  };

  const getOriginalPosition = (lineNumber: number, columnNumber: number): ErrorPositionType => {
    const originalPosition = bundleSourceMapConsumer.originalPositionFor({
      column: columnNumber,
      line: lineNumber
    });

    return {
      column: originalPosition.column,
      line: originalPosition.line,
      source: originalPosition.source.replace('webpack://', webpackConfiguration.context)
    };
  };

  const formatErrorStack = (errorStack: string): string => {
    return errorStack.replace(/isomorphic-webpack:(\d+):(\d+)/g, (match, lineNumber, columnNumber) => {
      const targetLineNumber = Number(lineNumber);
      const targetColumnNumber = Number(columnNumber);

      if (!isOriginalPositionDiscoverable(targetLineNumber, targetColumnNumber)) {
        return match;
      }

      const originalPosition = getOriginalPosition(targetLineNumber, targetColumnNumber);

      return originalPosition.source + ':' + originalPosition.line + ':' + originalPosition.column;
    });
  };

  return {
    compiler,
    createCompilationPromise,
    evalBundleCode,
    formatErrorStack
  };
};
<commit_msg>Adding custom context for evalBundleCode<commit_after>// @flow

import path from 'path';
import {
  Compiler
} from 'webpack';
import {
  SourceMapConsumer
} from 'source-map';
import createDebug from 'debug';
import type {
  UserIsomorphicWebpackConfigurationType
} from '../types';
import evalCodeInBrowser from '../utilities/evalCodeInBrowser';
import getEntryScriptPath from '../utilities/getEntryScriptPath';
import createCompiler from './createCompiler';
import createCompilerCallback from './createCompilerCallback';
import createCompilerConfiguration from './createCompilerConfiguration';
import createIsomorphicWebpackConfiguration from './createIsomorphicWebpackConfiguration';

const debug = createDebug('isomorphic-webpack');

type IsomorphicWebpackType = {|

  /**
   * @see https://webpack.github.io/docs/node.js-api.html#compiler
   */
  compiler: Compiler,
  createCompilationPromise: Function,
  evalBundleCode: Function,
  formatErrorStack: Function
|};

type ErrorPositionType = {|
  +column: number,
  +line: number,
  +source: string
|};

export default (webpackConfiguration: Object, userIsomorphicWebpackConfiguration?: UserIsomorphicWebpackConfigurationType): IsomorphicWebpackType => {
  const isomorphicWebpackConfiguration = createIsomorphicWebpackConfiguration(userIsomorphicWebpackConfiguration);
  const compilerConfiguration = createCompilerConfiguration(webpackConfiguration, isomorphicWebpackConfiguration.nodeExternalsWhitelist);
  const compiler = createCompiler(compilerConfiguration);

  let createCompilationPromise;

  /**
   * @see https://github.com/gajus/isomorphic-webpack#isomorphic-webpack-faq-how-to-delay-request-handling-while-compilation-is-in-progress
   */
  if (isomorphicWebpackConfiguration.useCompilationPromise) {
    let compilationPromise;
    let compilationPromiseResolve;
    let compilationPromiseIsResolved = true;

    createCompilationPromise = () => {
      return compilationPromise;
    };

    compiler.plugin('compile', () => {
      debug('compiler event: compile (compilationPromiseIsResolved: %s)', compilationPromiseIsResolved);

      if (!compilationPromiseIsResolved) {
        return;
      }

      compilationPromiseIsResolved = false;

      compilationPromise = new Promise((resolve) => {
        compilationPromiseResolve = resolve;
      });
    });

    compiler.plugin('done', () => {
      debug('compiler event: done');

      compilationPromiseIsResolved = true;

      compilationPromiseResolve();
    });
  } else {
    createCompilationPromise = () => {
      throw new Error('"createCompilationPromise" feature has not been enabled.');
    };
  }

  let bundleSourceMapConsumer;

  let currentBundleCode;
  let currentRequestMap;

  const evalBundleCode = (windowUrl?: string, customContext?: object) => {
    const requireModule = evalCodeInBrowser(currentBundleCode, {}, windowUrl, customContext);

    const entryScriptPath = getEntryScriptPath(compiler.options.entry);

    debug('entryScriptPath', entryScriptPath);

    // @todo Make it work in Windows.
    const relativeEntryScriptPath = './' + path.relative(webpackConfiguration.context, require.resolve(entryScriptPath));

    const moduleId = currentRequestMap[relativeEntryScriptPath];

    if (typeof moduleId !== 'number') {
      throw new Error('Cannot determine entry module ID.');
    }

    debug('evaluating module ID %i', moduleId);

    return requireModule(moduleId);
  };

  const compilerCallback = createCompilerCallback(compiler, ({
    bundleCode,
    bundleSourceMap,
    requestMap
  }) => {
    bundleSourceMapConsumer = new SourceMapConsumer(bundleSourceMap);
    currentBundleCode = bundleCode;
    currentRequestMap = requestMap;
  });

  compiler.watch({}, compilerCallback);

  const isOriginalPositionDiscoverable = (lineNumber: number, columnNumber: number): boolean => {
    const originalPosition = bundleSourceMapConsumer.originalPositionFor({
      column: columnNumber,
      line: lineNumber
    });

    return originalPosition.source !== null && originalPosition.line !== null && originalPosition.column !== null;
  };

  const getOriginalPosition = (lineNumber: number, columnNumber: number): ErrorPositionType => {
    const originalPosition = bundleSourceMapConsumer.originalPositionFor({
      column: columnNumber,
      line: lineNumber
    });

    return {
      column: originalPosition.column,
      line: originalPosition.line,
      source: originalPosition.source.replace('webpack://', webpackConfiguration.context)
    };
  };

  const formatErrorStack = (errorStack: string): string => {
    return errorStack.replace(/isomorphic-webpack:(\d+):(\d+)/g, (match, lineNumber, columnNumber) => {
      const targetLineNumber = Number(lineNumber);
      const targetColumnNumber = Number(columnNumber);

      if (!isOriginalPositionDiscoverable(targetLineNumber, targetColumnNumber)) {
        return match;
      }

      const originalPosition = getOriginalPosition(targetLineNumber, targetColumnNumber);

      return originalPosition.source + ':' + originalPosition.line + ':' + originalPosition.column;
    });
  };

  return {
    compiler,
    createCompilationPromise,
    evalBundleCode,
    formatErrorStack
  };
};
<|endoftext|>


<commit_before>/**
 * Ripple Client Configuration
 *
 * Copy this file to config.js and edit to suit your preferences.
 */
var Options = {
  server: {
    trace :         true,
    trusted:        true,
    local_signing:  true,

    servers: [
      { host: 's_west.ripple.com', port: 443, secure: true },
      { host: 's_east.ripple.com', port: 443, secure: true }
    ],

    connection_offset: 1
  },

  blobvault : 'https://blobvault.payward.com',

  // If set, login will persist across sessions (page reload). This is mostly
  // intended for developers, be careful about using this in a real setting.
  persistent_auth : false,

  // Number of transactions each page has in balance tab notifications
  transactions_per_page: 50,

  // Configure bridges
  bridge: {
    out: {
//    'bitcoin': 'localhost:3000'
//    'bitcoin': 'https://www.bitstamp.net/ripple/bridge/out/bitcoin/'
    }
  }
};

// Load client-side overrides
if (store.enabled) {
  $.extend(true, Options, JSON.parse(store.get('ripple_settings') || '{}'));
}

<commit_msg>Set default connection_offset to 0 seconds<commit_after>/**
 * Ripple Client Configuration
 *
 * Copy this file to config.js and edit to suit your preferences.
 */
var Options = {
  server: {
    trace :         true,
    trusted:        true,
    local_signing:  true,

    servers: [
      { host: 's_west.ripple.com', port: 443, secure: true },
      { host: 's_east.ripple.com', port: 443, secure: true }
    ],

    connection_offset: 0
  },

  blobvault : 'https://blobvault.payward.com',

  // If set, login will persist across sessions (page reload). This is mostly
  // intended for developers, be careful about using this in a real setting.
  persistent_auth : false,

  // Number of transactions each page has in balance tab notifications
  transactions_per_page: 50,

  // Configure bridges
  bridge: {
    out: {
//    'bitcoin': 'localhost:3000'
//    'bitcoin': 'https://www.bitstamp.net/ripple/bridge/out/bitcoin/'
    }
  }
};

// Load client-side overrides
if (store.enabled) {
  $.extend(true, Options, JSON.parse(store.get('ripple_settings') || '{}'));
}

<|endoftext|>


<commit_before>'use strict';
var uuid, Service, Characteristic, StreamController;

var fs = require('fs');
var request = require('request').defaults({ encoding: null });
var spawn = require('child_process').spawn;

function SensrCamera(hap, sensrCameraOptions) {
    uuid = hap.uuid;
    Service = hap.Service;
    Characteristic = hap.Characteristic;
    StreamController = hap.StreamController;

    this.options = sensrCameraOptions;

    this.services = [];
    this.streamControllers = [];

    this.pendingSessions = {};
    this.ongoingSessions = {};

    // TODO: These should be dynamic to some degree
    var numberOfStreams = 1;
    var maxWidth = 640;
    var maxHeight = 480;
    var maxFPS = 15;

    this.createCameraControlService();
    this._createStreamControllers(numberOfStreams);
}

SensrCamera.prototype.handleCloseConnection = function (connectionID) {
    this.streamControllers.forEach(function (controller) {
        controller.handleCloseConnection(connectionID);
    });
}

SensrCamera.prototype.createCameraControlService = function () {
    var controlService = new Service.CameraControl();

    this.services.push(controlService);
}

SensrCamera.prototype._createStreamControllers = function (maxStreams, options) {
    let self = this;
    options = options || {
        video: {
            codec: {
                profiles: [0, 1, 2], // Enum, please refer StreamController.VideoCodecParamProfileIDTypes
                levels: [0, 1, 2] // Enum, please refer StreamController.VideoCodecParamLevelTypes
            },
            resolutions: [
                [640, 480, 15]
            ]
        },
        audio: {
            codecs: [
                {
                    type: "OPUS", // Audio Codec
                    samplerate: 24 // 8, 16, 24 KHz
                },
                {
                    type: "AAC-eld",
                    samplerate: 16
                }
            ]
        }
    };

    for (var i = 0; i < maxStreams; i++) {
        var streamController = new StreamController(i, options, self);

        self.services.push(streamController.service);
        self.streamControllers.push(streamController);
    }
}

module.exports = SensrCamera;<commit_msg>Adding snapshot requests<commit_after>'use strict';
var uuid, Service, Characteristic, StreamController;

var fs = require('fs');
var request = require('request').defaults({ encoding: null });
var spawn = require('child_process').spawn;

function SensrCamera(hap, sensrCameraOptions) {
    uuid = hap.uuid;
    Service = hap.Service;
    Characteristic = hap.Characteristic;
    StreamController = hap.StreamController;

    this.options = sensrCameraOptions;

    this.services = [];
    this.streamControllers = [];

    this.pendingSessions = {};
    this.ongoingSessions = {};

    // TODO: These should be dynamic to some degree
    var numberOfStreams = 1;
    var maxWidth = 640;
    var maxHeight = 480;
    var maxFPS = 15;

    this.createCameraControlService();
    this._createStreamControllers(numberOfStreams);
}

SensrCamera.prototype.handleCloseConnection = function (connectionID) {
    this.streamControllers.forEach(function (controller) {
        controller.handleCloseConnection(connectionID);
    });
}

SensrCamera.prototype.handleSnapshotRequest = function (request, callback) {
    let resolution = request.width + 'x' + request.height;

    request(this.options.live, function (err, response, buffer) {
        callback(undefined, buffer);
    });
}

SensrCamera.prototype.createCameraControlService = function () {
    var controlService = new Service.CameraControl();

    this.services.push(controlService);
}

SensrCamera.prototype._createStreamControllers = function (maxStreams, options) {
    let self = this;
    options = options || {
        video: {
            codec: {
                profiles: [0, 1, 2], // Enum, please refer StreamController.VideoCodecParamProfileIDTypes
                levels: [0, 1, 2] // Enum, please refer StreamController.VideoCodecParamLevelTypes
            },
            resolutions: [
                [640, 480, 15]
            ]
        },
        audio: {
            codecs: [
                {
                    type: "OPUS", // Audio Codec
                    samplerate: 24 // 8, 16, 24 KHz
                },
                {
                    type: "AAC-eld",
                    samplerate: 16
                }
            ]
        }
    };

    for (var i = 0; i < maxStreams; i++) {
        var streamController = new StreamController(i, options, self);

        self.services.push(streamController.service);
        self.streamControllers.push(streamController);
    }
}

module.exports = SensrCamera;<|endoftext|>


<commit_before>import { $each, $setRef, $sel } from 'core/dom';
import { $extend, $isObject, $isString, $toArray } from 'core/types';
import { $exec } from 'core/core';
import { _doc } from 'core/variables';

let custom = {};
let bound = [];

function _bind(els, obj, options) {
	// Redefine variables when delegating
	if (options && options.delegate) {
		options.targ = els;
		els = options.delegate;
	}

	// For each element attach events
	$each(els, el => {
		// Loop through object events
		for (let key in obj) {
			if (obj.hasOwnProperty(key)) {
				let evts = key.split(' ');
				let	i = 0;

				for (; i < evts.length; i++) {
					let conf = $extend({
						args: [],
						once: false,
						scope: el
					}, options);
					let	fn = obj[key];
					let	evt = evts[i];
					let	ev = evt;
					let	parts = ev.split('.');
					let	f = fn;
					evt = parts[0];

					if (parts.length == 1 && conf.namespace) {
						ev += '.' + conf.namespace;
					}

					// Prepend element to callback arguments if necessary
					if (conf.args[1] !== el) {
						conf.args.unshift(0, el);
					}

					(function(el, evt, fn, f, conf) {
						let cb = e => {
							let cont = true;
							conf.args[0] = e;

							// If watch within ancestor make sure the target
							// matches the selector
							if (conf.targ) {
								let targ = conf.targ;
								let	sel = targ._$ ? targ.sel : targ;

								// Update refs when targeting ref
								if ($isString(sel) &&
									sel.indexOf('ref:') > -1) {
									$setRef(el);
								}

								cont = $toArray($sel(sel)).some(el => el.contains(e.target) && (targ = el));

								// Ensure element argument is the target
								conf.args[1] = conf.scope = targ;
							}

							if (cont) {
								$exec(fn, conf);

								// Unbind after first execution
								if (conf.once) {
									_off(el, evt, f);
								}
							}
						};

						// Ensure the specified element, event, and function
						// combination hasn't already been bound
						if (evt != 'init' && ! _bound(el, ev, f, conf.targ).length) {
							// Determine if the event is native or custom
							if ('on' + evt in el) {
								el.addEventListener(evt, cb, false);
							} else if (custom[evt]) {
								custom[evt][0](el, fn, conf);
							}

							bound.push({
								el: el,
								ev: ev,
								evt: evt,
								cb: cb,
								fn: f,
								targ: conf.targ
							});
						}

						if (evt == 'init' || conf.init === true) {
							cb();
						}
					})(el, evt, fn, f, conf);
				}
			}
		}
	}, options);
}

/**
 * Detach event(s) from element
 *
 * @private
 * @param {(HTMLElement|string)} [sel]
 * @param {string} [evt]
 * @param {function} [fn]
 */
function _off(sel, evt, fn) {
	$each(_bound(sel, evt, fn), e => {
		if ('on' + e.evt in _doc) {
			e.el.removeEventListener(e.evt, e.cb);
		} else if (custom[e.evt]) {
			custom[e.evt][1](e.el, e.cb);
		}

		bound.splice(bound.indexOf(e), 1);
	});
}

function _bound(target, event = '', fn = null, delegateTarg = null) {
	let segs = event.split('.');
	let	matches = [];
	target = target || [0];

	$each(target, el => {
		Object.keys(bound).forEach(e => {
			let binding = bound[e];
			let	parts = binding.ev.split('.');
			let	match = true;

			if (el && el !== binding.el) {
				match = false;
			}

			if (event && (segs[0] !== '' && segs[0] != parts[0]) || (segs[1] && segs[1] != parts[1])) {
				match = false;
			}

			if (fn && String(fn) !== String(binding.fn)) {
				match = false;
			}

			// If delegated event, check against target element
			if ((delegateTarg && binding.targ) && delegateTarg.sel !== binding.targ.sel) {
				match = false;
			}

			if (match) {
				matches.push(binding);
			}
		});
	});

	return matches;
}

export default {
	/**
	 * Bind event function to element
	 *
	 * @param {(HTMLElement|object|string)} target
	 * @param {(object|string)} a - event name or object of events
	 * @param {(function|object)} [b] - event callback or options object
	 * @param {(object|string)} [c] - event options
	 * @param {Array} [c.args] - callback arguments
	 * @param {(HTMLElement|string)} [c.context=document]
	 * @param {(HTMLElement|string)} [c.delegate]
	 * @param {boolean} [c.once=false] - remove event after first execution
	 * @param {object} [c.scope]
	 */
	on(target, a, b, c) {
		let evts = [];

		if ($isObject(target) && ! target._$) {
			let keys = Object.keys(target);
			let	i = 0;

			for (; i < keys.length; i++) {
				let key = keys[i];
				evts = target[key];

				_bind(key, evts, a);
			}
		} else {
			if ($isString(a)) {
				evts[a] = b;
			} else {
				evts = a;
				c = b;
			}

			_bind(target, evts, c);
		}
	},

	/**
	 * Remove specified event from specified element
	 *
	 * @param {(HTMLElement|string)} [target]
	 * @param {(object|string)} a - event name or object of events
	 * @param {function} [b] - specific function to remove
	 */
	off(target, a, b) {
		let obj = a;

		if (! target && ! a) {
			bound = [];
			custom = {};
			return;
		}

		if (a) {
			if ($isString(a)) {
				obj = [];
				obj[a] = b;
			}

			for (let key in obj) {
				if (obj.hasOwnProperty(key)) {
					let evts = key.split(' ');
					let	i = 0;

					for (; i < evts.length; i++) {
						let evt = evts[i];
						let fn = obj[evt];

						_off(target, evt, fn);
					}
				}
			}
		} else {
			_off(target);
		}
	},

	/**
	 * Get currently bound events to optional specified element and event|function
	 *
	 * @param {(boolean|HTMLElement|string)} [target]
	 * @param {string} [event] - event name to match
	 * @param {function} [fn] - specific function to match
	 * @param {HTMLElement} [delegateTarg] - targets of delegated event
	 * @returns {Array} matches
	 */
	bound(target, event, fn, delegateTarg) {
		return _bound(target, event, fn, delegateTarg);
	},

	/**
	 * Execute bound event for each matching selection
	 *
	 * @param {(HTMLElement|string)} target
	 * @param {string} name
	 */
	trigger(target, name) {
		let fn = function() {};

		_bound(target, name).forEach(e => {
			e.cb({
				target: e.el,
				preventDefault: fn,
				stopPropagation: fn
			});
		});
	},

	/**
	 * Add a custom event
	 *
	 * @param {string} name
	 * @param {function} on
	 * @param {function} off
	 */
	addEvent(name, on, off) {
		custom[name] = [on, off];
	}
}<commit_msg>Refactor lets to const<commit_after>import { $each, $setRef, $sel } from 'core/dom';
import { $extend, $isObject, $isString, $toArray } from 'core/types';
import { $exec } from 'core/core';
import { _doc } from 'core/variables';

let custom = {};
let bound = [];

function _bind(els, obj, options) {
	// Redefine variables when delegating
	if (options && options.delegate) {
		options.targ = els;
		els = options.delegate;
	}

	// For each element attach events
	$each(els, el => {
		// Loop through object events
		for (const key in obj) {
			if (obj.hasOwnProperty(key)) {
				let evts = key.split(' ');
				let	i = 0;

				for (; i < evts.length; i++) {
					const conf = $extend({
						args: [],
						once: false,
						scope: el
					}, options);
					const fn = obj[key];
					const f = fn;
					let	evt = evts[i];
					let	ev = evt;
					let parts = ev.split('.');
					evt = parts[0];

					if (parts.length == 1 && conf.namespace) {
						ev += '.' + conf.namespace;
					}

					// Prepend element to callback arguments if necessary
					if (conf.args[1] !== el) {
						conf.args.unshift(0, el);
					}

					(function(el, evt, fn, f, conf) {
						const cb = e => {
							let cont = true;
							conf.args[0] = e;

							// If watch within ancestor make sure the target
							// matches the selector
							if (conf.targ) {
								let targ = conf.targ;
								const sel = targ._$ ? targ.sel : targ;

								// Update refs when targeting ref
								if ($isString(sel) &&
									sel.indexOf('ref:') > -1) {
									$setRef(el);
								}

								cont = $toArray($sel(sel)).some(el => el.contains(e.target) && (targ = el));

								// Ensure element argument is the target
								conf.args[1] = conf.scope = targ;
							}

							if (cont) {
								$exec(fn, conf);

								// Unbind after first execution
								if (conf.once) {
									_off(el, evt, f);
								}
							}
						};

						// Ensure the specified element, event, and function
						// combination hasn't already been bound
						if (evt != 'init' && ! _bound(el, ev, f, conf.targ).length) {

							// Determine if the event is native or custom
							if ('on' + evt in el) {
								el.addEventListener(evt, cb, false);
							} else if (custom[evt]) {
								custom[evt][0](el, fn, conf);
							}

							bound.push({
								el,
								ev,
								evt,
								cb,
								fn: f,
								targ: conf.targ
							});
						}

						if (evt == 'init' || conf.init === true) {
							cb();
						}
					})(el, evt, fn, f, conf);
				}
			}
		}
	}, options);
}

/**
 * Detach event(s) from element
 *
 * @private
 * @param {(HTMLElement|string)} [sel]
 * @param {string} [evt]
 * @param {function} [fn]
 */
function _off(sel, evt, fn) {
	$each(_bound(sel, evt, fn), e => {
		if ('on' + e.evt in _doc) {
			e.el.removeEventListener(e.evt, e.cb);
		} else if (custom[e.evt]) {
			custom[e.evt][1](e.el, e.cb);
		}

		bound.splice(bound.indexOf(e), 1);
	});
}

function _bound(target, event = '', fn = null, delegateTarg = null) {
	let segs = event.split('.');
	let	matches = [];
	target = target || [0];

	$each(target, el => {
		Object.keys(bound).forEach(e => {
			let binding = bound[e];
			let	parts = binding.ev.split('.');
			let	match = true;

			if (el && el !== binding.el) {
				match = false;
			}

			if (event && (segs[0] !== '' && segs[0] != parts[0]) || (segs[1] && segs[1] != parts[1])) {
				match = false;
			}

			if (fn && String(fn) !== String(binding.fn)) {
				match = false;
			}

			// If delegated event, check against target element
			if ((delegateTarg && binding.targ) && delegateTarg.sel !== binding.targ.sel) {
				match = false;
			}

			if (match) {
				matches.push(binding);
			}
		});
	});

	return matches;
}

export default {
	/**
	 * Bind event function to element
	 *
	 * @param {(HTMLElement|object|string)} target
	 * @param {(object|string)} a - event name or object of events
	 * @param {(function|object)} [b] - event callback or options object
	 * @param {(object|string)} [c] - event options
	 * @param {Array} [c.args] - callback arguments
	 * @param {(HTMLElement|string)} [c.context=document]
	 * @param {(HTMLElement|string)} [c.delegate]
	 * @param {boolean} [c.once=false] - remove event after first execution
	 * @param {object} [c.scope]
	 */
	on(target, a, b, c) {
		let evts = [];

		if ($isObject(target) && ! target._$) {
			const keys = Object.keys(target);
			let	i = 0;

			for (; i < keys.length; i++) {
				const key = keys[i];
				evts = target[key];

				_bind(key, evts, a);
			}
		} else {
			if ($isString(a)) {
				evts[a] = b;
			} else {
				evts = a;
				c = b;
			}

			_bind(target, evts, c);
		}
	},

	/**
	 * Remove specified event from specified element
	 *
	 * @param {(HTMLElement|string)} [target]
	 * @param {(object|string)} a - event name or object of events
	 * @param {function} [b] - specific function to remove
	 */
	off(target, a, b) {
		let obj = a;

		if (! target && ! a) {
			bound = [];
			custom = {};
			return;
		}

		if (a) {
			if ($isString(a)) {
				obj = [];
				obj[a] = b;
			}

			for (let key in obj) {
				if (obj.hasOwnProperty(key)) {
					const evts = key.split(' ');
					let	i = 0;

					for (; i < evts.length; i++) {
						const evt = evts[i];
						const fn = obj[evt];

						_off(target, evt, fn);
					}
				}
			}
		} else {
			_off(target);
		}
	},

	/**
	 * Get currently bound events to optional specified element and event|function
	 *
	 * @param {(boolean|HTMLElement|string)} [target]
	 * @param {string} [event] - event name to match
	 * @param {function} [fn] - specific function to match
	 * @param {HTMLElement} [delegateTarg] - targets of delegated event
	 * @returns {Array} matches
	 */
	bound(target, event, fn, delegateTarg) {
		return _bound(target, event, fn, delegateTarg);
	},

	/**
	 * Execute bound event for each matching selection
	 *
	 * @param {(HTMLElement|string)} target
	 * @param {string} name
	 */
	trigger(target, name) {
		const fn = function() {};

		_bound(target, name).forEach(e => {
			e.cb({
				target: e.el,
				preventDefault: fn,
				stopPropagation: fn
			});
		});
	},

	/**
	 * Add a custom event
	 *
	 * @param {string} name
	 * @param {function} on
	 * @param {function} off
	 */
	addEvent(name, on, off) {
		custom[name] = [on, off];
	}
}<|endoftext|>


<commit_before>const layergroupToken = require('../middlewares/layergroup-token');
const cleanUpQueryParams = require('../middlewares/clean-up-query-params');
const credentials = require('../middlewares/credentials');
const dbConnSetup = require('../middlewares/db-conn-setup');
const authorize = require('../middlewares/authorize');
const rateLimit = require('../middlewares/rate-limit');
const { RATE_LIMIT_ENDPOINTS_GROUPS } = rateLimit;
const createMapStoreMapConfigProvider = require('../middlewares/map-store-map-config-provider');
const cacheControlHeader = require('../middlewares/cache-control-header');
const cacheChannelHeader = require('../middlewares/cache-channel-header');
const surrogateKeyHeader = require('../middlewares/surrogate-key-header');
const lastModifiedHeader = require('../middlewares/last-modified-header');

module.exports = class AttributesLayergroupController {
    constructor (
        attributesBackend,
        pgConnection,
        mapStore,
        userLimitsBackend,
        layergroupAffectedTablesCache,
        authBackend,
        surrogateKeysCache
    ) {
        this.attributesBackend = attributesBackend;
        this.pgConnection = pgConnection;
        this.mapStore = mapStore;
        this.userLimitsBackend = userLimitsBackend;
        this.layergroupAffectedTablesCache = layergroupAffectedTablesCache;
        this.authBackend = authBackend;
        this.surrogateKeysCache = surrogateKeysCache;
    }

    register (mapRouter) {
        mapRouter.get(
            `/:token/:layer/attributes/:fid`,
            layergroupToken(),
            credentials(),
            authorize(this.authBackend),
            dbConnSetup(this.pgConnection),
            rateLimit(this.userLimitsBackend, RATE_LIMIT_ENDPOINTS_GROUPS.ATTRIBUTES),
            cleanUpQueryParams(),
            createMapStoreMapConfigProvider(
                this.mapStore,
                this.userLimitsBackend,
                this.pgConnection,
                this.layergroupAffectedTablesCache
            ),
            getFeatureAttributes(this.attributesBackend),
            cacheControlHeader(),
            cacheChannelHeader(),
            surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
            lastModifiedHeader()
        );
    }
};

function getFeatureAttributes (attributesBackend) {
    return function getFeatureAttributesMiddleware (req, res, next) {
        req.profiler.start('windshaft.maplayer_attribute');

        const { mapConfigProvider } = res.locals;
        const { token } = res.locals;
        const { dbuser, dbname, dbpassword, dbhost, dbport } = res.locals;
        const { layer, fid } = req.params;

        const params = {
            token,
            dbuser, dbname, dbpassword, dbhost, dbport,
            layer, fid
        };

        attributesBackend.getFeatureAttributes(mapConfigProvider, params, false, (err, tile, stats = {}) => {
            req.profiler.add(stats);

            if (err) {
                err.label = 'GET ATTRIBUTES';
                return next(err);
            }

            res.statusCode = 200;
            res.body = tile;

            next();
        });
    };
}
<commit_msg>Create .middlewares() method to mount corresponding set of middlewares<commit_after>const layergroupToken = require('../middlewares/layergroup-token');
const cleanUpQueryParams = require('../middlewares/clean-up-query-params');
const credentials = require('../middlewares/credentials');
const dbConnSetup = require('../middlewares/db-conn-setup');
const authorize = require('../middlewares/authorize');
const rateLimit = require('../middlewares/rate-limit');
const { RATE_LIMIT_ENDPOINTS_GROUPS } = rateLimit;
const createMapStoreMapConfigProvider = require('../middlewares/map-store-map-config-provider');
const cacheControlHeader = require('../middlewares/cache-control-header');
const cacheChannelHeader = require('../middlewares/cache-channel-header');
const surrogateKeyHeader = require('../middlewares/surrogate-key-header');
const lastModifiedHeader = require('../middlewares/last-modified-header');

module.exports = class AttributesLayergroupController {
    constructor (
        attributesBackend,
        pgConnection,
        mapStore,
        userLimitsBackend,
        layergroupAffectedTablesCache,
        authBackend,
        surrogateKeysCache
    ) {
        this.attributesBackend = attributesBackend;
        this.pgConnection = pgConnection;
        this.mapStore = mapStore;
        this.userLimitsBackend = userLimitsBackend;
        this.layergroupAffectedTablesCache = layergroupAffectedTablesCache;
        this.authBackend = authBackend;
        this.surrogateKeysCache = surrogateKeysCache;
    }

    register (mapRouter) {
        mapRouter.get('/:token/:layer/attributes/:fid', this.middlewares());
    }

    middlewares () {
        return [
            layergroupToken(),
            credentials(),
            authorize(this.authBackend),
            dbConnSetup(this.pgConnection),
            rateLimit(this.userLimitsBackend, RATE_LIMIT_ENDPOINTS_GROUPS.ATTRIBUTES),
            cleanUpQueryParams(),
            createMapStoreMapConfigProvider(
                this.mapStore,
                this.userLimitsBackend,
                this.pgConnection,
                this.layergroupAffectedTablesCache
            ),
            getFeatureAttributes(this.attributesBackend),
            cacheControlHeader(),
            cacheChannelHeader(),
            surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
            lastModifiedHeader()
        ];
    }
};

function getFeatureAttributes (attributesBackend) {
    return function getFeatureAttributesMiddleware (req, res, next) {
        req.profiler.start('windshaft.maplayer_attribute');

        const { mapConfigProvider } = res.locals;
        const { token } = res.locals;
        const { dbuser, dbname, dbpassword, dbhost, dbport } = res.locals;
        const { layer, fid } = req.params;

        const params = {
            token,
            dbuser, dbname, dbpassword, dbhost, dbport,
            layer, fid
        };

        attributesBackend.getFeatureAttributes(mapConfigProvider, params, false, (err, tile, stats = {}) => {
            req.profiler.add(stats);

            if (err) {
                err.label = 'GET ATTRIBUTES';
                return next(err);
            }

            res.statusCode = 200;
            res.body = tile;

            next();
        });
    };
}
<|endoftext|>


<commit_before>// export default [
//   {
//     // Months are zero-indexed for whatever reason
//     // This is a historical artifact from the Java (yes, Java) APIs
//     date: new Date(2018, 9, 13),
//     events: [
//       {
//         time: '9:00AM - 10:45AM',
//         name: 'Check-In',
//         locations: ['Schiciano Atrium']
//       },
//       {
//         time: '11:00AM - 12:30PM',
//         name: 'Opening Ceremony',
//         locations: ['Reynolds Theatre']
//       },
//       {
//         time: '1:00PM - 2:00PM',
//         name: 'Lunch',
//         locations: ['Schiciano Atrium']
//       },
//       { time: '2:00PM', name: 'Hacking Commences' },
//       {
//         time: '2:00PM - 2:30PM',
//         name: 'Team Formation Mixer',
//         locations: ['Schiciano Lobby']
//       },
//       {
//         time: '2:00PM - 8:00PM',
//         name: 'Frisbee, Football, Volleyball',
//         locations: ['Harrington Quad']
//       },
//       {
//         time: '2:30PM - 3:30PM',
//         name: 'Intro to Hardware Hacking by August Ning',
//         locations: ['Hudson 201']
//       },
//       {
//         time: '2:30PM - 3:30PM',
//         name: 'VR Workshop by Mark Steelman',
//         locations: ['Hudson 232']
//       },
//       {
//         time: '3:00PM - 3:30PM',
//         name: 'Health Track Kickoff with Jason Liu',
//         locations: ['Hudson 222']
//       },
//       {
//         time: '3:00PM - 4:30PM',
//         name: 'Javascript Workshop by Co-Lab',
//         locations: ['Hudson 216']
//       },
//       {
//         time: '3:30PM - 5:00PM',
//         name: 'Puppies!!!!!',
//         locations: ['Harrington Quad']
//       },
//       {
//         time: '4:30PM - 5:30PM',
//         name: 'API Workshop by Archana Ahlawat',
//         locations: ['Hudson 115A']
//       },
//       {
//         time: '4:45PM - 6:15PM',
//         name: 'Mobile Workshop by Co-Lab',
//         locations: ['Hudson 216']
//       },
//       {
//         time: '6:30PM - 8:00PM',
//         name: 'Dinner',
//         locations: ['Schiciano Atrium']
//       },
//       {
//         time: '8:00PM - 9:00PM',
//         name: 'MLH Werewolf',
//         locations: ['Schiciano Lobby']
//       },
//       {
//         time: '9:00PM - 10:00PM',
//         name: 'Mixer for Female-Identifying and Non-Binary Hackers',
//         locations: ['Innovation Co-Lab']
//       },
//       {
//         time: '10:00PM - 11:00PM',
//         name: 'Nerf War',
//         locations: ["Twinnie's 2nd Floor"]
//       },
//       {
//         time: '11:00PM - 11:45PM',
//         name: 'Spicy Noodle Challenge',
//         locations: ['Schiciano Atrium']
//       }
//     ]
//   },
//   {
//     date: new Date(2018, 9, 14),
//     events: [
//       {
//         time: '12:00AM - 8:00AM',
//         name: 'Midnight Snacks',
//         locations: ["Twinnie's"]
//       },
//       {
//         time: '12:00AM - 8:00AM',
//         name: 'Nap Time',
//         locations: ['Hudson (222, 224, 232)']
//       },
//       {
//         time: '9:00AM - 9:45AM',
//         name: 'Breakfast',
//         locations: ['Schiciano Atrium']
//       },
//       {
//         time: '11:00AM - 11:30PM',
//         name:
//           'The Future of Healthcare Technology by Dr. Michael Kerzner (Duke Hospital)',
//         locations: ['Hudson 216']
//       },
//       {
//         time: '11:00AM - 12:00PM',
//         name: 'Turning Hack into Startup by Kasper Kubica',
//         locations: ['Hudson 222']
//       },
//
//       {
//         time: '12:00PM - 1:30PM',
//         name: 'Lunch',
//         locations: ['Schiciano Atrium']
//       },
//       { time: '1:30PM', name: 'Hacking Ends' },
//       {
//         time: '2:00PM - 4:00PM',
//         name: 'Judging and Demos',
//         locations: ['Schiciano Lobby']
//       },
//       {
//         time: '4:00PM',
//         name: 'HackDuke Ends'
//       },
//       {
//         time: '4:30PM - 5:30PM',
//         name: 'Closing Ceremony',
//         locations: ['Reynolds Theatre']
//       },
//       {
//         time: '6:00PM',
//         name: 'VTech Bus Leaves',
//         locations: ['Science Drive']
//       }
//     ]
//   }
// ];
export default [
  {
    // Months are zero-indexed for whatever reason
    // This is a historical artifact from the Java (yes, Java) APIs
    // Correct month data is one index less --> month later fixed in Schedule.js
    date: new Date(2019, 10, 2),
    events: [
      {
        time: '9:00AM - 10:45AM',
        name: 'Check-In',
        locations: ['Schiciano Foyer'],
        type: 'important'
      },
      {
        time: '11:00AM - 12:15PM',
        name: 'Opening Ceremony',
        locations: ['Page Auditorium'],
        type: 'important'
      },
      {
        time: '12:30PM - 1:00PM',
        name: 'Track Talks',
        locations: [
          'Scichiano A - Education, Scichiano B - Health, Hudson 207 - Energy, Hudson 208 - InequalityHudson 208 - Nonprofit'
        ],
        type: 'event'
      },
      {
        time: '1:00PM - 2:00PM',
        name: 'Lunch',
        locations: ['CIEMAS 1st Floor'],
        type: 'meal'
      },
      { time: '2:00PM',
        name: 'Hacking Commences',
        type: 'important'
      },
      {
        time: '2:00PM - 2:30PM',
        name: 'Team Formation Mixer',
        locations: ['Schiciano Foyer'],
        type: 'event'
      },
      {
        time: '2:00PM',
        name: 'Workshop Session 1',
        locations: ['Hudson Hall, Room TBD'],
        type: 'event'
      },
      {
        time: '3:00PM',
        name: 'Workshop Session 2',
        locations: ['Hudson Hall, Room TBD'],
        type: 'event'
      },
      {
        time: '3:00PM - 5:00PM',
        name: 'Puppies!!!!!',
        locations: ['Harrington Quad']
      },
      {
        time: '3:00PM - 7:00PM',
        name: 'Spikeball & Frisbee',
        locations: ['Harrington Quad']
      },
      {
        time: '4:00PM',
        name: 'Workshop Session 3',
        locations: ['Hudson Hall, Room TBD'],
        type: 'event'
      },
      {
        time: '6:00PM - 7:00PM',
        name: 'Mixer for Female-Identifying and Non-Binary Hackers',
        locations: ['Innovation Co-Lab'],
        type: 'event'
      },
      {
        time: '6:30PM - 8:00PM',
        name: 'Dinner',
        locations: ['Schiciano Foyer'],
        type: 'meal'
      },
      {
        time: '7:30PM - 8:00PM',
        name: 'Pie an Organizer',
        locations: ['CIEMAS 1st Floor']
      },
      {
        time: '8:00PM - 9:00PM',
        name: 'MLH Minigame',
        locations: ['CIEMAS 1st Floor']
      },
      {
        time: '9:00PM - 10:00PM',
        name: 'WIT Mixer',
        locations: ['Location TBA'],
        type: 'event'
      },
      {
        time: '10:00PM - 10:45PM',
        name: 'Nerf War',
        locations: ["Twinnie's 2nd Floor"]
      },
      {
        time: '11:00PM - 11:45PM',
        name: 'Spicy Noodle Challenge',
        locations: ['Schiciano Foyer']
      }
    ]
  },
  {
    date: new Date(2019, 10, 3),
    events: [
      {
        time: '12:00AM - 8:00AM',
        name: 'Midnight Snacks',
        locations: ["Twinnie's"],
        type: 'meal'
      },
      {
        time: '12:00AM - 8:00AM',
        name: 'Nap Time',
        locations: ['–'],
        type: 'important'
      },
      {
        time: '9:00AM - 9:45AM',
        name: 'Breakfast',
        locations: ['Schiciano Foyer'],
        type: 'meal'
      },
      {
        time: '10:00AM - 12:00PM',
        name: 'Workshops',
        locations: ['Locations TBA'],
        type: 'event'
      },
      {
        time: '12:00PM - 1:30PM',
        name: 'Lunch',
        locations: ['Schiciano Foyer'],
        type: 'meal'
      },
      { time: '1:30PM',
        name: 'Hacking Ends',
        type: 'important'
      },
      { time: '2:00PM',
        name: 'Judging Begins',
        type: 'important'
      },
      {
        time: '2:00PM - 2:45PM',
        name: 'First Round Judging',
        locations: ['CIEMAS Lobby'],
        type: 'event'
      },
      {
        time: '2:45PM - 3:30PM',
        name: 'Finalist Demos',
        locations: ['CIEMAS Lobby'],
        type: 'event'
      },
      {
        time: '3:30PM - 4:00PM',
        name: 'Final Judging',
        locations: ['CIEMAS Lobby'],
        type: 'event'
      },
      {
        time: '4:00PM',
        name: 'Judging Ends',
        type: 'important'
      },
      {
        time: '4:30PM - 5:30PM',
        name: 'Closing Ceremony',
        locations: ['Page Auditorium'],
        type: 'important'
      },
      {
        time: '6:00PM',
        name: 'Buses Leave',
        locations: ['Science Drive'],
        type: 'important'
      }
    ]
  }
]
<commit_msg>small schedule updates<commit_after>// export default [
//   {
//     // Months are zero-indexed for whatever reason
//     // This is a historical artifact from the Java (yes, Java) APIs
//     date: new Date(2018, 9, 13),
//     events: [
//       {
//         time: '9:00AM - 10:45AM',
//         name: 'Check-In',
//         locations: ['Schiciano Atrium']
//       },
//       {
//         time: '11:00AM - 12:30PM',
//         name: 'Opening Ceremony',
//         locations: ['Reynolds Theatre']
//       },
//       {
//         time: '1:00PM - 2:00PM',
//         name: 'Lunch',
//         locations: ['Schiciano Atrium']
//       },
//       { time: '2:00PM', name: 'Hacking Commences' },
//       {
//         time: '2:00PM - 2:30PM',
//         name: 'Team Formation Mixer',
//         locations: ['Schiciano Lobby']
//       },
//       {
//         time: '2:00PM - 8:00PM',
//         name: 'Frisbee, Football, Volleyball',
//         locations: ['Harrington Quad']
//       },
//       {
//         time: '2:30PM - 3:30PM',
//         name: 'Intro to Hardware Hacking by August Ning',
//         locations: ['Hudson 201']
//       },
//       {
//         time: '2:30PM - 3:30PM',
//         name: 'VR Workshop by Mark Steelman',
//         locations: ['Hudson 232']
//       },
//       {
//         time: '3:00PM - 3:30PM',
//         name: 'Health Track Kickoff with Jason Liu',
//         locations: ['Hudson 222']
//       },
//       {
//         time: '3:00PM - 4:30PM',
//         name: 'Javascript Workshop by Co-Lab',
//         locations: ['Hudson 216']
//       },
//       {
//         time: '3:30PM - 5:00PM',
//         name: 'Puppies!!!!!',
//         locations: ['Harrington Quad']
//       },
//       {
//         time: '4:30PM - 5:30PM',
//         name: 'API Workshop by Archana Ahlawat',
//         locations: ['Hudson 115A']
//       },
//       {
//         time: '4:45PM - 6:15PM',
//         name: 'Mobile Workshop by Co-Lab',
//         locations: ['Hudson 216']
//       },
//       {
//         time: '6:30PM - 8:00PM',
//         name: 'Dinner',
//         locations: ['Schiciano Atrium']
//       },
//       {
//         time: '8:00PM - 9:00PM',
//         name: 'MLH Werewolf',
//         locations: ['Schiciano Lobby']
//       },
//       {
//         time: '9:00PM - 10:00PM',
//         name: 'Mixer for Female-Identifying and Non-Binary Hackers',
//         locations: ['Innovation Co-Lab']
//       },
//       {
//         time: '10:00PM - 11:00PM',
//         name: 'Nerf War',
//         locations: ["Twinnie's 2nd Floor"]
//       },
//       {
//         time: '11:00PM - 11:45PM',
//         name: 'Spicy Noodle Challenge',
//         locations: ['Schiciano Atrium']
//       }
//     ]
//   },
//   {
//     date: new Date(2018, 9, 14),
//     events: [
//       {
//         time: '12:00AM - 8:00AM',
//         name: 'Midnight Snacks',
//         locations: ["Twinnie's"]
//       },
//       {
//         time: '12:00AM - 8:00AM',
//         name: 'Nap Time',
//         locations: ['Hudson (222, 224, 232)']
//       },
//       {
//         time: '9:00AM - 9:45AM',
//         name: 'Breakfast',
//         locations: ['Schiciano Atrium']
//       },
//       {
//         time: '11:00AM - 11:30PM',
//         name:
//           'The Future of Healthcare Technology by Dr. Michael Kerzner (Duke Hospital)',
//         locations: ['Hudson 216']
//       },
//       {
//         time: '11:00AM - 12:00PM',
//         name: 'Turning Hack into Startup by Kasper Kubica',
//         locations: ['Hudson 222']
//       },
//
//       {
//         time: '12:00PM - 1:30PM',
//         name: 'Lunch',
//         locations: ['Schiciano Atrium']
//       },
//       { time: '1:30PM', name: 'Hacking Ends' },
//       {
//         time: '2:00PM - 4:00PM',
//         name: 'Judging and Demos',
//         locations: ['Schiciano Lobby']
//       },
//       {
//         time: '4:00PM',
//         name: 'HackDuke Ends'
//       },
//       {
//         time: '4:30PM - 5:30PM',
//         name: 'Closing Ceremony',
//         locations: ['Reynolds Theatre']
//       },
//       {
//         time: '6:00PM',
//         name: 'VTech Bus Leaves',
//         locations: ['Science Drive']
//       }
//     ]
//   }
// ];
export default [
  {
    // Months are zero-indexed for whatever reason
    // This is a historical artifact from the Java (yes, Java) APIs
    // Correct month data is one index less --> month later fixed in Schedule.js
    date: new Date(2019, 10, 2),
    events: [
      {
        time: '9:00AM - 10:45AM',
        name: 'Check-In',
        locations: ['Schiciano Foyer'],
        type: 'important'
      },
      {
        time: '11:00AM - 12:15PM',
        name: 'Opening Ceremony',
        locations: ['Page Auditorium'],
        type: 'important'
      },
      {
        time: '12:30PM - 1:00PM',
        name: 'Track Talks',
        locations: [
          'Scichiano A - Education, Scichiano B - Health, Hudson 207 - Energy, Hudson 208 - InequalityHudson 208 - Nonprofit'
        ],
        type: 'event'
      },
      {
        time: '1:00PM - 2:00PM',
        name: 'Lunch',
        locations: ['CIEMAS 1st Floor'],
        type: 'meal'
      },
      { time: '2:00PM',
        name: 'Hacking Commences',
        type: 'important'
      },
      {
        time: '2:00PM - 2:30PM',
        name: 'Team Formation Mixer',
        locations: ['Schiciano Foyer'],
        type: 'event'
      },
      {
        time: '2:00PM - 8:00PM',
        name: 'Workshops',
        locations: ['Hudson Hall, Various Rooms'],
        type: 'event'
      },
      {
        time: '3:00PM - 5:00PM',
        name: 'Puppies!!!!!',
        locations: ['Harrington Quad']
      },
      {
        time: '3:00PM - 7:00PM',
        name: 'Spikeball & Frisbee',
        locations: ['Harrington Quad']
      },
      {
        time: '6:00PM - 7:00PM',
        name: 'Mixer for Female-Identifying and Non-Binary Hackers with Houzz',
        locations: ['Innovation Co-Lab'],
        type: 'event'
      },
      {
        time: '6:30PM - 8:00PM',
        name: 'Dinner',
        locations: ['Schiciano Foyer'],
        type: 'meal'
      },
      {
        time: '7:30PM - 8:00PM',
        name: 'Pie an Organizer',
        locations: ['CIEMAS 1st Floor']
      },
      {
        time: '8:00PM - 9:00PM',
        name: 'MLH Minigame',
        locations: ['CIEMAS 1st Floor']
      },
      {
        time: '10:00PM - 10:45PM',
        name: 'Nerf War',
        locations: ["Twinnie's 2nd Floor"]
      },
      {
        time: '11:00PM - 11:45PM',
        name: 'Spicy Noodle Challenge',
        locations: ['Schiciano Foyer']
      }
    ]
  },
  {
    date: new Date(2019, 10, 3),
    events: [
      {
        time: '12:00AM - 8:00AM',
        name: 'Midnight Snacks',
        locations: ["Twinnie's"],
        type: 'meal'
      },
      {
        time: '12:00AM - 8:00AM',
        name: 'Nap Time',
        locations: ['–'],
        type: 'important'
      },
      {
        time: '9:00AM - 9:45AM',
        name: 'Breakfast',
        locations: ['Schiciano Foyer'],
        type: 'meal'
      },
      {
        time: '10:00AM - 12:00PM',
        name: 'Workshops',
        locations: ['Locations TBA'],
        type: 'event'
      },
      {
        time: '12:00PM - 1:30PM',
        name: 'Lunch',
        locations: ['Schiciano Foyer'],
        type: 'meal'
      },
      { time: '1:30PM',
        name: 'Hacking Ends',
        type: 'important'
      },
      { time: '2:00PM - 4:00PM',
        name: 'Judging',
        locations: ['CIEMAS 1st Floor & Schiciano Foyer'],
        type: 'event'
      },
      {
        time: '4:30PM - 5:30PM',
        name: 'Closing Ceremony',
        locations: ['Page Auditorium'],
        type: 'important'
      },
      {
        time: '6:00PM',
        name: 'Buses Leave',
        locations: ['Science Drive'],
        type: 'important'
      }
    ]
  }
]
<|endoftext|>