<commit_before>import "./main";

/**
 * The game map.
 */
class Map {
    constructor(tileTypes, options = {}) {
        this.tileTypes = tileTypes;
        this.placedTiles = [];
        this.placedSprites = [];

        this.tilePixels = (options["tile_pixels"] === undefined) ? {width: 256, height: 256} : options["tile_pixels"];
        this.tilePixelDeadzone = (options["tile_pixel_deadzone"] === undefined) ? {width: 0, height: 0} : options["tile_pixel_deadzone"];

        console.log("test");
        console.log(this.tilePixels);
    }

    placeTile(tile) {
        this.placedTiles.push(tile);
    }

    /**
     * Render the map to the specified target.
     *
     * @param stage Target to render onto.
     * @param cameraPosition Camera position (offset) to render at.
     */
    render(stage, cameraPosition = {x: 0, y: 0}) {
        // Remove old tile sprites
        for (var spriteId in this.placedSprites) {
            stage.removeChild(this.placedSprites[spriteId]);
        }
        this.placedSprites = [];

        // Generate new sprites.
        for (var i in this.placedTiles) {
            var placedTile = this.placedTiles[i];

            // Create new sprite for this tile.
            var newSprite = new PIXI.Sprite(this.tileTypes[placedTile.tileType].texture);
            newSprite.x = cameraPosition.x + placedTile.position.x * this.tilePixels.width - (this.tilePixelDeadzone.width * placedTile.position.x);
            newSprite.y = cameraPosition.y + placedTile.position.y * this.tilePixels.height - (this.tilePixelDeadzone.height * placedTile.position.y);
            newSprite.width = this.tilePixels.width;
            newSprite.height = this.tilePixels.height;

            // Place sprite
            this.placedSprites.push(newSprite);
            stage.addChild(newSprite);
        }
    }
}

export default Map;
<commit_msg>Removed an accidental debug console log.<commit_after>import "./main";

/**
 * The game map.
 */
class Map {
    constructor(tileTypes, options = {}) {
        this.tileTypes = tileTypes;
        this.placedTiles = [];
        this.placedSprites = [];

        this.tilePixels = (options["tile_pixels"] === undefined) ? {width: 256, height: 256} : options["tile_pixels"];
        this.tilePixelDeadzone = (options["tile_pixel_deadzone"] === undefined) ? {width: 0, height: 0} : options["tile_pixel_deadzone"];

        console.log(this.tilePixels);
    }

    placeTile(tile) {
        this.placedTiles.push(tile);
    }

    /**
     * Render the map to the specified target.
     *
     * @param stage Target to render onto.
     * @param cameraPosition Camera position (offset) to render at.
     */
    render(stage, cameraPosition = {x: 0, y: 0}) {
        // Remove old tile sprites
        for (var spriteId in this.placedSprites) {
            stage.removeChild(this.placedSprites[spriteId]);
        }
        this.placedSprites = [];

        // Generate new sprites.
        for (var i in this.placedTiles) {
            var placedTile = this.placedTiles[i];

            // Create new sprite for this tile.
            var newSprite = new PIXI.Sprite(this.tileTypes[placedTile.tileType].texture);
            newSprite.x = cameraPosition.x + placedTile.position.x * this.tilePixels.width - (this.tilePixelDeadzone.width * placedTile.position.x);
            newSprite.y = cameraPosition.y + placedTile.position.y * this.tilePixels.height - (this.tilePixelDeadzone.height * placedTile.position.y);
            newSprite.width = this.tilePixels.width;
            newSprite.height = this.tilePixels.height;

            // Place sprite
            this.placedSprites.push(newSprite);
            stage.addChild(newSprite);
        }
    }
}

export default Map;
<|endoftext|>


<commit_before>'use strict'

var SettingActions = require('../actions/SettingActions');
var SettingStore = require('../stores/SettingStore');
var PostActions = require('../actions/PostActions');
var DraftActions = require('../actions/DraftActions');
var EditActions = require('../actions/EditActions');
var EditStore = require('../stores/EditStore');
var NavBar = require('./NavBar');
var PostButton = require('./PostButton');
var CancelButton = require('./CancelButton');

var React = require('react-native');
var KeyboardEvents = require('react-native-keyboardevents');
var KeyboardEventEmitter = KeyboardEvents.Emitter;

var {
  StyleSheet,
  Text,
  TextInput,
  ScrollView,
  View,
} = React;

class EditPage extends React.Component {
  constructor(props, context) {
    super(props, context);
    if (!this.props.route.post) {
      this.initialData = '';
      this.state = {post: {data: ''}};
      this.isEditing = false;
    } else {
      this.initialData = this.props.route.post.data;
      this.state = {post: this.props.route.post};
      this.isEditing = true;
    }
    this.saveDraft = this.saveDraft.bind(this);
    this.cancelButton = (<CancelButton onPress={this.saveDraft} />);
    this.savePost = this.savePost.bind(this);
    this.postButton = (<PostButton edit={this.isEditing} isDraft={this.state.post.isDraft} onPress={this.savePost}/>);
    this.updateKeyboardSpace = (frames) => {
      var change;
      if (frames.endCoordinates) change = frames.endCoordinates.height;
      else change = frames.end.height;
      this.setState({height: this.state.height - change});
    };
    this.resetKeyboardSpace = () => this.setState({height: this.state.fullHeight});
    this.updateWordCount = (text) => this.setState({wordCount: text.split(/\s+/).filter(w => !!w).length});
  }

  componentDidMount() {
    this.updateWordCount(this.state.post.data);
    KeyboardEventEmitter.on(KeyboardEvents.KeyboardDidShowEvent, this.updateKeyboardSpace);
    KeyboardEventEmitter.on(KeyboardEvents.KeyboardWillHideEvent, this.resetKeyboardSpace);
  }

  componentWillUnmount() {
    KeyboardEventEmitter.off(KeyboardEvents.KeyboardDidShowEvent, this.updateKeyboardSpace);
    KeyboardEventEmitter.off(KeyboardEvents.KeyboardWillHideEvent, this.resetKeyboardSpace);
  }

  savePost() {
    if (this.isEditing && this.state.post.isDraft) {
      this.state.post.isDraft = false;
      DraftActions.del(this.state.post);
      delete this.state.post.id;
      PostActions.create(this.state.post);
    } else if (this.isEditing && !this.state.post.isDraft) {
      if (this.state.post.hasUnpublishedEdits) {
        this.state.post.hasUnpublishedEdits = false;
        EditActions.del(this.state.post);
      }
      PostActions.edit(this.state.post);
    } else {
      PostActions.create(this.state.post);
    }
    this.props.navigator.pop();
  }

  saveDraft() {
    if (this.state.post.data !== this.initialData) {
      if (this.state.post.isDraft) {
        DraftActions.edit(this.state.post);
      } else {
        if (this.isEditing) {
          this.state.post.hasUnpublishedEdits = true;
          console.log(this.state.post);
          EditActions.save(this.state.post);
        } else {
          this.state.post.isDraft = true;
          DraftActions.create(this.state.post);
        }
      }
    }
    this.props.navigator.pop();
  }

  render() {
    var title = <Text style={styles.title}>{this.state.wordCount} words</Text>;
    return (
      <View style={styles.page} onLayout={(ev) => {
        // 80 is for the navbar on top
        var fullHeight = ev.nativeEvent.layout.height - 80;
        this.setState({height: fullHeight, fullHeight: fullHeight});
      }}>
        <NavBar leftButton={this.cancelButton} title={title} rightButton={this.postButton}/>
        <ScrollView keyboardDismissMode='interactive'>
          <TextInput
            multiline={true}
            onChangeText={(text) => {
              this.state.post.data = text;
              this.updateWordCount(text);
            }}
            defaultValue={this.state.post.data}
            autoFocus={true}
            style={[styles.input, {height:this.state.height}]}
          />
        </ScrollView>
      </View>
    );
  }
}

var styles = StyleSheet.create({
  page: {
    flex: 1,
    alignItems: 'stretch',
  },
  input: {
    padding: 20,
    paddingTop: 0,
    fontSize: 18,
    fontFamily: 'System',
  },
  title: {
    paddingTop: 4,
    fontSize: 18,
    fontFamily: 'System',
    color: 'grey',
    textAlign: 'center',
  },
});

module.exports = EditPage;
<commit_msg>show/hide word count based on whether keyboard is up or not<commit_after>'use strict'

var SettingActions = require('../actions/SettingActions');
var SettingStore = require('../stores/SettingStore');
var PostActions = require('../actions/PostActions');
var DraftActions = require('../actions/DraftActions');
var EditActions = require('../actions/EditActions');
var EditStore = require('../stores/EditStore');
var NavBar = require('./NavBar');
var PostButton = require('./PostButton');
var CancelButton = require('./CancelButton');

var React = require('react-native');
var KeyboardEvents = require('react-native-keyboardevents');
var KeyboardEventEmitter = KeyboardEvents.Emitter;

var {
  StyleSheet,
  Text,
  TextInput,
  ScrollView,
  View,
} = React;

class EditPage extends React.Component {
  constructor(props, context) {
    super(props, context);
    if (!this.props.route.post) {
      this.initialData = '';
      this.state = {post: {data: ''}};
      this.isEditing = false;
    } else {
      this.initialData = this.props.route.post.data;
      this.state = {post: this.props.route.post};
      this.isEditing = true;
    }
    this.saveDraft = this.saveDraft.bind(this);
    this.cancelButton = (<CancelButton onPress={this.saveDraft} />);
    this.savePost = this.savePost.bind(this);
    this.postButton = (<PostButton edit={this.isEditing} isDraft={this.state.post.isDraft} onPress={this.savePost}/>);
    this.updateKeyboardSpace = (frames) => {
      var change;
      if (frames.endCoordinates) change = frames.endCoordinates.height;
      else change = frames.end.height;
      this.setState({height: this.state.height - change});
      this.setState({isKeyboardUp: true})
    };
    this.resetKeyboardSpace = () => this.setState({height: this.state.fullHeight, isKeyboardUp: false});
    this.updateWordCount = (text) => this.setState({wordCount: text.split(/\s+/).filter(w => !!w).length});
  }

  componentDidMount() {
    this.updateWordCount(this.state.post.data);
    KeyboardEventEmitter.on(KeyboardEvents.KeyboardDidShowEvent, this.updateKeyboardSpace);
    KeyboardEventEmitter.on(KeyboardEvents.KeyboardWillHideEvent, this.resetKeyboardSpace);
  }

  componentWillUnmount() {
    KeyboardEventEmitter.off(KeyboardEvents.KeyboardDidShowEvent, this.updateKeyboardSpace);
    KeyboardEventEmitter.off(KeyboardEvents.KeyboardWillHideEvent, this.resetKeyboardSpace);
  }

  savePost() {
    if (this.isEditing && this.state.post.isDraft) {
      this.state.post.isDraft = false;
      DraftActions.del(this.state.post);
      delete this.state.post.id;
      PostActions.create(this.state.post);
    } else if (this.isEditing && !this.state.post.isDraft) {
      if (this.state.post.hasUnpublishedEdits) {
        this.state.post.hasUnpublishedEdits = false;
        EditActions.del(this.state.post);
      }
      PostActions.edit(this.state.post);
    } else {
      PostActions.create(this.state.post);
    }
    this.props.navigator.pop();
  }

  saveDraft() {
    if (this.state.post.data !== this.initialData) {
      if (this.state.post.isDraft) {
        DraftActions.edit(this.state.post);
      } else {
        if (this.isEditing) {
          this.state.post.hasUnpublishedEdits = true;
          console.log(this.state.post);
          EditActions.save(this.state.post);
        } else {
          this.state.post.isDraft = true;
          DraftActions.create(this.state.post);
        }
      }
    }
    this.props.navigator.pop();
  }

  render() {
    if (!this.state.isKeyboardUp) var title = <Text></Text>;
    else var title = <Text style={styles.title}>{this.state.wordCount} words</Text>;
    return (
      <View style={styles.page} onLayout={(ev) => {
        // 80 is for the navbar on top
        var fullHeight = ev.nativeEvent.layout.height - 80;
        this.setState({height: fullHeight, fullHeight: fullHeight});
      }}>
        <NavBar leftButton={this.cancelButton} title={title} rightButton={this.postButton}/>
        <ScrollView keyboardDismissMode='interactive'>
          <TextInput
            multiline={true}
            onChangeText={(text) => {
              this.state.post.data = text;
              this.updateWordCount(text);
            }}
            defaultValue={this.state.post.data}
            autoFocus={true}
            style={[styles.input, {height:this.state.height}]}
          />
        </ScrollView>
      </View>
    );
  }
}

var styles = StyleSheet.create({
  page: {
    flex: 1,
    alignItems: 'stretch',
  },
  input: {
    padding: 20,
    paddingTop: 0,
    fontSize: 18,
    fontFamily: 'System',
  },
  title: {
    paddingTop: 6,
    fontSize: 16,
    fontFamily: 'System',
    color: 'grey',
    textAlign: 'center',
  },
});

module.exports = EditPage;
<|endoftext|>


<commit_before>import { select, selection } from 'd3-selection';

// "Caution: avoid interpolating to or from the number zero when the interpolator is used to generate
// a string (such as with attr).
// Very small values, when stringified, may be converted to scientific notation and
// cause a temporarily invalid attribute or style property value.
// For example, the number 0.0000001 is converted to the string "1e-7".
// This is particularly noticeable when interpolating opacity values.
// To avoid scientific notation, start or end the transition at 1e-6,
// which is the smallest value that is not stringified in exponential notation."
// - https://github.com/mbostock/d3/wiki/Transitions#d3_interpolateNumber
export const effectivelyZero = 1e-6;

// Wrapper around d3's selectAll/data data-join, which allows decoration of the result.
// This is achieved by appending the element to the enter selection before exposing it.
// A default transition of fade in/out is also implicitly added but can be modified.
export default (element, className) => {
    element = element || 'g';

    let key = (_, i) => i;
    let transition = null;

    const dataJoin = function(container, data) {
        data = data || ((d) => d);

        const selected = container.selectAll((d, i, nodes) => nodes[i].children)
            .filter(className == null ? element : `${element}.${className}`);
        let update = selected.data(data, key);

        // N.B. insert() is used to create new elements, rather than append(). insert() behaves in a special manner
        // on enter selections - entering elements will be inserted immediately before the next following sibling
        // in the update selection, if any.
        // This helps order the elements in an order consistent with the data, but doesn't guarantee the ordering;
        // if the updating elements change order then selection.order() would be required to update the order.
        // (#528)
        const enter = update.enter()
            .insert(element)
            .attr('class', className);

        const exit = update.exit();

        // automatically merge in the enter selection
        update = update.merge(enter);

        // if transitions are enabled apply a default fade in/out transition
        if (selection.prototype.transition) {
            enter.style('opacity', effectivelyZero)
                .transition(transition)
                .style('opacity', 1);
            exit.transition(transition)
                .style('opacity', effectivelyZero)
                .remove();
        } else {
            exit.remove();
        }

        update.enter = () => enter;
        update.exit = () => exit;

        return update;
    };

    dataJoin.element = (...args) => {
        if (!args.length) {
            return element;
        }
        element = args[0];
        return dataJoin;
    };
    dataJoin.className = (...args) => {
        if (!args.length) {
            return className;
        }
        className = args[0];
        return dataJoin;
    };
    dataJoin.key = (...args) => {
        if (!args.length) {
            return key;
        }
        key = args[0];
        return dataJoin;
    };
    dataJoin.transition = (...args) => {
        if (!args.length) {
            return transition;
        }
        transition = args[0];
        return dataJoin;
    };

    return dataJoin;
};
<commit_msg>fix: use childNodes rather than children for compatability (#17)<commit_after>import { select, selection } from 'd3-selection';

// "Caution: avoid interpolating to or from the number zero when the interpolator is used to generate
// a string (such as with attr).
// Very small values, when stringified, may be converted to scientific notation and
// cause a temporarily invalid attribute or style property value.
// For example, the number 0.0000001 is converted to the string "1e-7".
// This is particularly noticeable when interpolating opacity values.
// To avoid scientific notation, start or end the transition at 1e-6,
// which is the smallest value that is not stringified in exponential notation."
// - https://github.com/mbostock/d3/wiki/Transitions#d3_interpolateNumber
export const effectivelyZero = 1e-6;

// Wrapper around d3's selectAll/data data-join, which allows decoration of the result.
// This is achieved by appending the element to the enter selection before exposing it.
// A default transition of fade in/out is also implicitly added but can be modified.
export default (element, className) => {
    element = element || 'g';

    let key = (_, i) => i;
    let transition = null;

    const dataJoin = function(container, data) {
        data = data || ((d) => d);

        const selected = container.selectAll((d, i, nodes) => nodes[i].childNodes)
            .filter(className == null ? element : `${element}.${className}`);
        let update = selected.data(data, key);

        // N.B. insert() is used to create new elements, rather than append(). insert() behaves in a special manner
        // on enter selections - entering elements will be inserted immediately before the next following sibling
        // in the update selection, if any.
        // This helps order the elements in an order consistent with the data, but doesn't guarantee the ordering;
        // if the updating elements change order then selection.order() would be required to update the order.
        // (#528)
        const enter = update.enter()
            .insert(element)
            .attr('class', className);

        const exit = update.exit();

        // automatically merge in the enter selection
        update = update.merge(enter);

        // if transitions are enabled apply a default fade in/out transition
        if (selection.prototype.transition) {
            enter.style('opacity', effectivelyZero)
                .transition(transition)
                .style('opacity', 1);
            exit.transition(transition)
                .style('opacity', effectivelyZero)
                .remove();
        } else {
            exit.remove();
        }

        update.enter = () => enter;
        update.exit = () => exit;

        return update;
    };

    dataJoin.element = (...args) => {
        if (!args.length) {
            return element;
        }
        element = args[0];
        return dataJoin;
    };
    dataJoin.className = (...args) => {
        if (!args.length) {
            return className;
        }
        className = args[0];
        return dataJoin;
    };
    dataJoin.key = (...args) => {
        if (!args.length) {
            return key;
        }
        key = args[0];
        return dataJoin;
    };
    dataJoin.transition = (...args) => {
        if (!args.length) {
            return transition;
        }
        transition = args[0];
        return dataJoin;
    };

    return dataJoin;
};
<|endoftext|>


<commit_before>var express = require('express');

var app = express();

app.get('/', function(request, response) {
    response.sendfile(__dirname + '/index.html');
});

app.configure(function() {
    app.use('/css', express.static(__dirname + '/css'));
    app.use('/flash', express.static(__dirname + '/flash'));
    app.use('/img', express.static(__dirname + '/img'));
    app.use('/js', express.static(__dirname + '/js'));
    app.use('/lib', express.static(__dirname + '/lib'));
    app.use('/videos', express.static(__dirname + '/videos'));
    app.use('/favicon.ico', express.static(__dirname + '/favicon.ico'));
});

var port = process.env.PORT || 8000;
app.listen(port, function() {
    console.log('Listening on ' + port);
});

<commit_msg>Fix for plugins directory not being available<commit_after>var express = require('express');

var app = express();

app.get('/', function(request, response) {
    response.sendfile(__dirname + '/index.html');
});

app.configure(function() {
    app.use('/css', express.static(__dirname + '/css'));
    app.use('/flash', express.static(__dirname + '/flash'));
    app.use('/img', express.static(__dirname + '/img'));
    app.use('/js', express.static(__dirname + '/js'));
    app.use('/lib', express.static(__dirname + '/lib'));
    app.use('/plugin', express.static(__dirname + '/plugin'));
    app.use('/videos', express.static(__dirname + '/videos'));
    app.use('/favicon.ico', express.static(__dirname + '/favicon.ico'));
});

var port = process.env.PORT || 8000;
app.listen(port, function() {
    console.log('Listening on ' + port);
});

<|endoftext|>


<commit_before>/* global jQuery, Firebase, _, db, data, params */

var taskName = 'task_img_verification_trinary';
var ticketsPool = taskName + '_tickets_pool'
var ticketsReq = taskName + '_tickets_req';
var ticketsRes = taskName + '_tickets_res';
var ticketsPool_uid = ticketsPool + '_uid';
var ticketsReq_uid = ticketsReq + '_uid';
var ticketsRes_uid = ticketsRes + '_uid';

// stub db helpers & fixtures
stub_db = {
  imgRef: db.child('img_ref'), // TODO: need to resolve this before allowing methods below to be invoked?
  taskTicketsRef: db.child(ticketsPool),
  taskTicketsReqRef: db.child(ticketsReq),
  taskTicketsResRef: db.child(ticketsRes),
  imgTickets: data.img_ref,
  taskTicketsPool: data[ticketsPool],
  taskTicketsReq: data[ticketsReq] || [],
  taskTicketsRes: data[ticketsRes] || [],
  isTicketInReqAndNotExpired: function (ticket) {
    for (var reqTicketKey in this.taskTicketsReq) {
      var reqTicket = this.taskTicketsReq[reqTicketKey];
      if ((reqTicket[ticketsPool_uid] === ticket.uid) && (!this.isReqTicketExpired(reqTicket))) return true;
    }
    return false;
  },
  isTicketInRes: function (ticket) {
    for (var resTicketKey in this.taskTicketsRes) {
      var resTicket = this.taskTicketsRes[resTicketKey];
      if (this.taskTicketsPool[this.taskTicketsReq[resTicket[ticketsReq_uid]][ticketsPool_uid]] === ticket.uid) return true;
    }
    return false;
  },
  isReqTicketExpired: function (reqTicket) {
    return (getNow() - reqTicket.timeSubmitted) > reqTicket.taskDuration; // TODO create these keys, normalize taskDuration and reference it back from jobs bucket
  },
  remainsOpen: function (ticket) {
    // if ticket is in res or (ticket is in req and is not expired ((getNow() - timeSubmitted) > taskDuration))
    if (isTicketInRes(ticket) || (isTicketInReqAndNotExpired(ticket))) return false;
    else return true;
    // var backChain = this.taskTickets[]
    // var backChain = this.taskTickets[this.taskTicketsReq[this.taskTicketsRes[ticketsReq]][ticketsPool_uid]].img_ref_uid;
    // if (ticket.img_ref_uid === backChain) return false;
  },
  // find up to first 30 open tickets from task_img_verification that are not in _req or _res
  getTickets: function (taskName, maxCount) {
    var ticketsToServe = [];
    // stub_db.imgTickets, stub_db.taskTickets, stub_db.taskTicketsReq, stub_db.taskTicketsRes
    debugger;
    for (var i = 0; i < Object.keys(this.taskTickets).length; i++) {
      var ticket = this.taskTickets[i];
      if (ticketsToServe.length === maxCount) break;
      if (this.remainsOpen(ticket)) {
        console.log('ticketsToServe.push:', ticket);
        var ticketPromise = this.taskTicketsReqRef.push(ticket)
          .then((pushedTicketRef) => {
            var newUID = pushedTicketRef.path.u[1];
            pushedTicketRef.set({task_img_verification_trinary_uid: this.uid, uid: newUID}, function(err) {
              if (err) console.log(err, 'failed to set in Firebase', this);
              else console.log('succeeded to set in Firebase', this);
            }).bind(this);
            this.task_img_verification_trinary_uid = this.uid;
            this.uid = newUID;
            return this;
          }).bind(ticket)
        ticketsToServe.push(ticketPromise);
      }
    }
    return Promise.all(ticketsToServe);
  },
};

// query db for next 30 images (server will determine these but for now on client-side)
stub_db.getTickets(taskName, 30)
  .then(function(ticketsToServe) {
    debugger;
  // iterate over server response
    console.log('succeeded to get tickets for task', ticketsToServe);
    ticketsToServe.forEach(function(ticket){
    // instantiate imgTrinary class per image (follow angular pattern)
    // event listeners on trinary
      // add response and other metadata (worker id, img_ref) to flat output obj based on trinary state change
      // enable submitBtn if all images completed
    });
  })
  .catch(function(err) {
    console.log('failed to get tickets for task');
    throw err;
  });

// event listener on submitBtn for click
  // iterate over results obj
    // push to img_sanitizer_task_worker_res
<commit_msg>Fully functional via fixing promises, add time submitted and task duration<commit_after>/* global jQuery, Firebase, _, Promise, db, data, params */

var ticketsToGet = 30;

var taskName = 'task_img_verification_trinary';
var ticketsPool = taskName + '_tickets_pool'
var ticketsReq = taskName + '_tickets_req';
var ticketsRes = taskName + '_tickets_res';
var ticketsPool_uid = ticketsPool + '_uid';
var ticketsReq_uid = ticketsReq + '_uid';
var ticketsRes_uid = ticketsRes + '_uid';

// stub db helpers & fixtures
stub_db = {
  // TODO: need to resolve these refs before allowing methods below to be invoked?
  imgRef: db.child('img_ref'),
  taskTicketsPoolRef: db.child(ticketsPool),
  taskTicketsReqRef: db.child(ticketsReq),
  taskTicketsResRef: db.child(ticketsRes),
  imgTickets: data.img_ref,
  taskTicketsPool: data[ticketsPool],
  taskTicketsReq: data[ticketsReq] || {},
  taskTicketsRes: data[ticketsRes] || {},
  isTicketInReqAndNotExpired: function (ticket) {
    for (var reqTicketKey in this.taskTicketsReq) {
      var reqTicket = this.taskTicketsReq[reqTicketKey];
      if ((reqTicket[ticketsPool_uid] === ticket.uid) && (!this.isReqTicketExpired(reqTicket))) return true;
    }
    return false;
  },
  isTicketInRes: function (ticket) {
    for (var resTicketKey in this.taskTicketsRes) {
      var resTicket = this.taskTicketsRes[resTicketKey];
      if (this.taskTicketsPool[this.taskTicketsReq[resTicket[ticketsReq_uid]][ticketsPool_uid]] === ticket.uid) return true;
    }
    return false;
  },
  isReqTicketExpired: function (reqTicket) {
    return (getNow() - reqTicket.timeSubmitted) > reqTicket.taskDuration; // TODO create these keys, normalize taskDuration and reference it back from jobs bucket
  },
  remainsOpen: function (ticket) {
    if (this.isTicketInRes(ticket) || (this.isTicketInReqAndNotExpired(ticket))) return false;
    else return true;
  },
  // retrieve up to n open tickets
  getTickets: function (taskName, maxCount) {
    var ticketsToServe = [];
    for (var uid in this.taskTicketsPool) {
      var ticket = this.taskTicketsPool[uid];
      if (ticketsToServe.length === maxCount) break;
      if (this.remainsOpen(ticket)) {
        ticketsToServe.push(this.taskTicketsReqRef.push(ticket)
        .then(function (pushedReqTicketRef) {
          this[ticketsPool_uid] = this.uid;
          this.uid = pushedReqTicketRef.path.u[1];
          this.timeSubmitted = getNow();
          this.taskDuration = minToMs(1); // TODO add this via reference to job entry
          delete this.img_ref_uid;
          pushedReqTicketRef.set({
            task_img_verification_trinary_tickets_pool_uid: this[ticketsPool_uid],
            uid: this.uid,
            timeSubmitted: this.timeSubmitted,
            taskDuration: this.taskDuration,
          });
          return this;
        }.bind(ticket))
        .catch(function (err) {
          throw err;
        }));
      }
    }
    return Promise.all(ticketsToServe);
  },
};

// query db for next 30 images (server will determine these but for now on client-side)
stub_db.getTickets(taskName, ticketsToGet)
  .then(function(ticketsToServe) {
  // iterate over server response
    console.log('succeeded to get', ticketsToServe.length, 'of', ticketsToGet, 'requested for task', taskName);
    console.log(ticketsToServe);
    ticketsToServe.forEach(function(ticket){
    // instantiate imgTrinary class per image (follow angular pattern)
    // event listeners on trinary
      // add response and other metadata (worker id, img_ref) to flat output obj based on trinary state change
      // enable submitBtn if all images completed
    });
  })
  .catch(function(err) {
    console.log('failed to get tickets for task');
    throw err;
  });

// event listener on submitBtn for click
  // iterate over results obj
    // push to img_sanitizer_task_worker_res
<|endoftext|>


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

 */
'use strict';

var React           = require('react');
var joinClasses      = require('classnames');
var Cell            = require('./Cell');
var ColumnMetrics   = require('./ColumnMetrics');
var ColumnUtilsMixin  = require('./ColumnUtils');

type RowPropsType = {
  height: number;
  idx: number;
  columns: any;
  row: any;
  cellRenderer: ?any;
  isSelected: ?boolean;
};

type cellProps = {
  props: {
    selected: {rowIdx: number};
    dragged: {complete: bool; rowIdx: number};
    copied: { rowIdx: number};
  }
};

var Row = React.createClass({

  propTypes: {
    height: React.PropTypes.number.isRequired,
    columns: React.PropTypes.oneOfType([React.PropTypes.object, React.PropTypes.array]).isRequired,
    row: React.PropTypes.object.isRequired,
    cellRenderer: React.PropTypes.func,
    isSelected: React.PropTypes.bool,
    idx : React.PropTypes.number.isRequired,
    expandedRows : React.PropTypes.arrayOf(React.PropTypes.object)
  },

  mixins: [ColumnUtilsMixin],

  render(): ?ReactElement {
    var className = joinClasses(
      'react-grid-Row',
      "react-grid-Row--${this.props.idx % 2 === 0 ? 'even' : 'odd'}"
    );

    var style = {
      height: this.getRowHeight(this.props),
      overflow: 'hidden'
    };

    var cells = this.getCells();
    return (
      <div {...this.props} className={className} style={style} onDragEnter={this.handleDragEnter}>
        {React.isValidElement(this.props.row) ?
          this.props.row : cells}
      </div>
    );
  },

  getCells(): Array<ReactElement> {
    var cells = [];
    var lockedCells = [];
    var selectedColumn = this.getSelectedColumn();

    this.props.columns.forEach((column, i) => {

      var CellRenderer = this.props.cellRenderer;
      var cell = <CellRenderer
                    ref={i}
                    key={i}
                    idx={i}
                    rowIdx={this.props.idx}
                    value={this.getCellValue(column.key || i)}
                    column={column}
                    height={this.getRowHeight()}
                    formatter={column.formatter}
                    cellMetaData={this.props.cellMetaData}
                    rowData={this.props.row}
                    selectedColumn={selectedColumn}
                    isRowSelected={this.props.isSelected} />
      if (column.locked) {
        lockedCells.push(cell);
      } else {
        cells.push(cell);
      }
    });

    return cells.concat(lockedCells);
  },

  getRowHeight(): number {
    var rows = this.props.expandedRows || null;
    if(rows && this.props.key) {
      var row = rows[this.props.key] || null;
      if(row) {
        return row.height;
      }
    }
    return this.props.height;
  },

  getCellValue(key: number | string): any {
    var val;
    if(key === 'select-row') {
      return this.props.isSelected;
    } else if (typeof this.props.row.get === 'function') {
      val = this.props.row.get(key);
    } else {
      val = this.props.row[key];
    }
    return val;
  },

  renderCell(props: any): ReactElement {
    if(typeof this.props.cellRenderer == 'function') {
      this.props.cellRenderer.call(this, props);
    }
    if (React.isValidElement(this.props.cellRenderer)) {
      return cloneWithProps(this.props.cellRenderer, props);
    } else {
      return this.props.cellRenderer(props);
    }
  },

  getDefaultProps(): {cellRenderer: Cell} {
    return {
      cellRenderer: Cell,
      isSelected: false,
      height : 35
    };
  },

  setScrollLeft(scrollLeft: number) {
    this.props.columns.forEach( (column, i) => {
      if (column.locked) {
        if(!this.refs[i]) return;
        this.refs[i].setScrollLeft(scrollLeft);
      }
    });
  },

  doesRowContainSelectedCell(props: any): boolean{
    var selected = props.cellMetaData.selected;
    if(selected && selected.rowIdx === props.idx){
      return true;
    }else{
      return false;
    }
  },

  willRowBeDraggedOver(props: any): boolean{
    var dragged = props.cellMetaData.dragged;
    return  dragged != null && (dragged.rowIdx>=0 || dragged.complete === true);
  },

  hasRowBeenCopied(): boolean{
    var copied = this.props.cellMetaData.copied;
    return copied != null && copied.rowIdx === this.props.idx;
  },

  shouldComponentUpdate(nextProps: any, nextState: any): boolean {
    return !(ColumnMetrics.sameColumns(this.props.columns, nextProps.columns, ColumnMetrics.sameColumn)) ||
    this.doesRowContainSelectedCell(this.props)          ||
    this.doesRowContainSelectedCell(nextProps)           ||
    this.willRowBeDraggedOver(nextProps)                 ||
    nextProps.row !== this.props.row                     ||
    this.hasRowBeenCopied()                              ||
    this.props.isSelected !== nextProps.isSelected       ||
    nextProps.height !== this.props.height;
  },

  handleDragEnter(){
    var handleDragEnterRow = this.props.cellMetaData.handleDragEnterRow;
    if(handleDragEnterRow){
      handleDragEnterRow(this.props.idx);
    }
  },

  getSelectedColumn(){
    var selected = this.props.cellMetaData.selected;
    if(selected && selected.idx){
      return this.getColumn(this.props.columns, selected.idx);
    }
  }

});

module.exports = Row;
<commit_msg>Support even and odd row classes.<commit_after>/* @flow  */
/**
 * @jsx React.DOM

 */
'use strict';

var React           = require('react');
var joinClasses      = require('classnames');
var Cell            = require('./Cell');
var ColumnMetrics   = require('./ColumnMetrics');
var ColumnUtilsMixin  = require('./ColumnUtils');

type RowPropsType = {
  height: number;
  idx: number;
  columns: any;
  row: any;
  cellRenderer: ?any;
  isSelected: ?boolean;
};

type cellProps = {
  props: {
    selected: {rowIdx: number};
    dragged: {complete: bool; rowIdx: number};
    copied: { rowIdx: number};
  }
};

var Row = React.createClass({

  propTypes: {
    height: React.PropTypes.number.isRequired,
    columns: React.PropTypes.oneOfType([React.PropTypes.object, React.PropTypes.array]).isRequired,
    row: React.PropTypes.object.isRequired,
    cellRenderer: React.PropTypes.func,
    isSelected: React.PropTypes.bool,
    idx : React.PropTypes.number.isRequired,
    expandedRows : React.PropTypes.arrayOf(React.PropTypes.object)
  },

  mixins: [ColumnUtilsMixin],

  render(): ?ReactElement {
    var className = joinClasses(
      'react-grid-Row',
      'react-grid-Row--' + this.props.idx % 2 === 0 ? 'even' : 'odd'
    );

    var style = {
      height: this.getRowHeight(this.props),
      overflow: 'hidden'
    };

    var cells = this.getCells();
    return (
      <div {...this.props} className={className} style={style} onDragEnter={this.handleDragEnter}>
        {React.isValidElement(this.props.row) ?
          this.props.row : cells}
      </div>
    );
  },

  getCells(): Array<ReactElement> {
    var cells = [];
    var lockedCells = [];
    var selectedColumn = this.getSelectedColumn();

    this.props.columns.forEach((column, i) => {

      var CellRenderer = this.props.cellRenderer;
      var cell = <CellRenderer
                    ref={i}
                    key={i}
                    idx={i}
                    rowIdx={this.props.idx}
                    value={this.getCellValue(column.key || i)}
                    column={column}
                    height={this.getRowHeight()}
                    formatter={column.formatter}
                    cellMetaData={this.props.cellMetaData}
                    rowData={this.props.row}
                    selectedColumn={selectedColumn}
                    isRowSelected={this.props.isSelected} />
      if (column.locked) {
        lockedCells.push(cell);
      } else {
        cells.push(cell);
      }
    });

    return cells.concat(lockedCells);
  },

  getRowHeight(): number {
    var rows = this.props.expandedRows || null;
    if(rows && this.props.key) {
      var row = rows[this.props.key] || null;
      if(row) {
        return row.height;
      }
    }
    return this.props.height;
  },

  getCellValue(key: number | string): any {
    var val;
    if(key === 'select-row') {
      return this.props.isSelected;
    } else if (typeof this.props.row.get === 'function') {
      val = this.props.row.get(key);
    } else {
      val = this.props.row[key];
    }
    return val;
  },

  renderCell(props: any): ReactElement {
    if(typeof this.props.cellRenderer == 'function') {
      this.props.cellRenderer.call(this, props);
    }
    if (React.isValidElement(this.props.cellRenderer)) {
      return cloneWithProps(this.props.cellRenderer, props);
    } else {
      return this.props.cellRenderer(props);
    }
  },

  getDefaultProps(): {cellRenderer: Cell} {
    return {
      cellRenderer: Cell,
      isSelected: false,
      height : 35
    };
  },

  setScrollLeft(scrollLeft: number) {
    this.props.columns.forEach( (column, i) => {
      if (column.locked) {
        if(!this.refs[i]) return;
        this.refs[i].setScrollLeft(scrollLeft);
      }
    });
  },

  doesRowContainSelectedCell(props: any): boolean{
    var selected = props.cellMetaData.selected;
    if(selected && selected.rowIdx === props.idx){
      return true;
    }else{
      return false;
    }
  },

  willRowBeDraggedOver(props: any): boolean{
    var dragged = props.cellMetaData.dragged;
    return  dragged != null && (dragged.rowIdx>=0 || dragged.complete === true);
  },

  hasRowBeenCopied(): boolean{
    var copied = this.props.cellMetaData.copied;
    return copied != null && copied.rowIdx === this.props.idx;
  },

  shouldComponentUpdate(nextProps: any, nextState: any): boolean {
    return !(ColumnMetrics.sameColumns(this.props.columns, nextProps.columns, ColumnMetrics.sameColumn)) ||
    this.doesRowContainSelectedCell(this.props)          ||
    this.doesRowContainSelectedCell(nextProps)           ||
    this.willRowBeDraggedOver(nextProps)                 ||
    nextProps.row !== this.props.row                     ||
    this.hasRowBeenCopied()                              ||
    this.props.isSelected !== nextProps.isSelected       ||
    nextProps.height !== this.props.height;
  },

  handleDragEnter(){
    var handleDragEnterRow = this.props.cellMetaData.handleDragEnterRow;
    if(handleDragEnterRow){
      handleDragEnterRow(this.props.idx);
    }
  },

  getSelectedColumn(){
    var selected = this.props.cellMetaData.selected;
    if(selected && selected.idx){
      return this.getColumn(this.props.columns, selected.idx);
    }
  }

});

module.exports = Row;
<|endoftext|>


<commit_before>
//-------------------------------------------------------
//-- Models

var Issue = Backbone.Model.extend({
	initialize: function(issue) {
		var this_ = this;
		this.set({
			'key': issue['key'],
			'duedate': new Date(issue['fields']['duedate']),
			'estimate': parseInt(issue['fields']['timetracking']['originalEstimateSeconds']),
			'project': {
				'name': issue['fields']['project']['name'],
				'iconUrl': issue['fields']['project']['avatarUrls']['16x16']
			},
			'summary': issue['fields']['summary'],
			'assignee': issue['fields']['assignee'],
			'reporter': issue['fields']['reporter'],
			'issuetype': issue['fields']['issuetype'],
			'priority': issue['fields']['priority'],
			'status': issue['fields']['status'],
			'progress': issue['fields']['progress'],
			'url': issue['self'].replace(/\/rest\/api\/2\/issue\/.*/, '/browse/' + issue['key'])
		});

		chrome.storage.local.get(issue['key'], function(storedAttributes) {
			if (storedAttributes) {
				this_.set(storedAttributes);
			}
		});

		this.on({
			'change:assignee': function(user) {
				app.server.api.updateIssue(this.get('self'), {
					'assignee': user
				}, function(issue) {
					this_.set({
						'assignee': issue['fields']['assignee']
					});
				});
			},
			'change:duedate': function(e) {
				app.server.api.updateIssue(this.get('self'), {
					'duedate': moment(e.start).format('YYYY-MM-DD')
				}, function(issue) {
					this_.set({
						'duedate': new Date(issue['fields']['duedate'])
					});
				});
			},
			'change:estiamte': function(e) {
				app.server.api.updateIssue(this.get('self'), {
					'timetracking': {
						'originalEstimateSeconds': (e.end - e.start)/1000
					}
				}, function(issue) {
					this_.set({
						'estimate': parseInt(issue['fields']['timetracking']['originalEstimateSeconds'])
					});
				});
			},
			'change:progress': function(started) {
				if (started) {
					this.set({'started': new Date()});
					var obj = {};
					obj[this.get('key')] = {
						'started': new Date()
					};
					chrome.storage.local.set(obj);
				} else {
					this.unset('started');
					chrome.storage.local.remove(this.get('key'));
				}
			}
		});
	},
	worklog: function(data) {
		app.server.api.worklog(this.get('self'), data);
	},
	comment: function(data) {
		app.server.api.comment(this.get('self'), data);
	}
});

var Issues = Backbone.Collection.extend({
	'model': Issue
});

var Filter = Backbone.Model.extend({
	UPDATE_INTERVAL: 1*60000, // 1min
	timeout: null,
	'issues': new Issues(),
	'initialize': function(filter) {
		var this_ = this;

		this.on('change', function() {
			this.update();
		});

		this.set({
			'name': filter['name'],
			'jql': filter['jql'],
			'type': filter['type'] || app.FILTER_TYPE_TABLE
		});
		this.update();
		this.collection.trigger('created', this);
		this.timeout = window.setInterval(function() {
			this_.update();
		}, this.UPDATE_INTERVAL);
	},
	'update': function() {
		var this_ = this;
		this.collection.server.api.executeJQL(this.get('jql'), function(issues) {
			this_['issues'] = new Issues(issues);
			this_['issues'].on('change', function() {
				this_.trigger('updated', this_);
			})
			this_.trigger('updated', this_);
		});
	}
});

var Filters = Backbone.Collection.extend({
    model: Filter
});

var ServerModel = Backbone.Model.extend({
	filters: new Filters,
	api: null,
	sync: function(cmd, server){
		var this_ = this;
		console.log(cmd);
		if (cmd === 'create') {
			this.set('filters', this.filters.toJSON());
			chrome.storage.local.set({
				'server': this_.attributes
			});
		} else if (cmd === 'read') {
			chrome.storage.local.get('server', function(data) {
				this_.set(data['server']);
				this_.trigger('load');
			});
		}
	},
	initialize: function() {
		this.filters.server = this;
		this.on('connected', function() {
			console.log(this.get('filters'));
			this.filters.add(this.get('filters'));
		});

		this.on('load', function() {
			var this_ = this;
			if (this.get('url') && this.get('token')) {
				var api = new JIRA(this.get('url'), this.get('url'));
				api.checkAuthorization(function(res, msg) {
					if (res) {
						this_.api = api;
						this_.trigger('connected');
					} else {
						this_.trigger('disconnected');
						if (msg) {
							this_.trigger('connection-error', msg);
						}
					}
				});
			} else {
				this.trigger('disconnected');
			}
		});

		this.on('login', function(e) {
			var this_ = this;
			var api = new JIRA(e.url);
			api.login(e.username, e.password, function(res, data){
				if (res) {
					this_.set({
						'url': e.url,
						'token': data,
						'username': e.username,
						'filters': this.get('filters') || app.FILTERS_DEFAULT
					});
					this_.save();
					this_.api = api;
					this_.trigger('connected');
				} else {
					app.server.trigger('login-error', data)
				}
			})
		});

		this.listenTo(this.filters, 'all', function(e) {
			if (e == 'add' || e == 'remove' || e == 'change') {
				this.save();
			}
		});

		this.fetch();
	}
});<commit_msg>resolving issues<commit_after>
//-------------------------------------------------------
//-- Models

var Issue = Backbone.Model.extend({
	initialize: function(issue) {
		var this_ = this;
		this.set({
			'key': issue['key'],
			'duedate': new Date(issue['fields']['duedate']),
			'estimate': parseInt(issue['fields']['timetracking']['originalEstimateSeconds']),
			'project': {
				'name': issue['fields']['project']['name'],
				'iconUrl': issue['fields']['project']['avatarUrls']['16x16']
			},
			'summary': issue['fields']['summary'],
			'assignee': issue['fields']['assignee'],
			'reporter': issue['fields']['reporter'],
			'issuetype': issue['fields']['issuetype'],
			'priority': issue['fields']['priority'],
			'status': issue['fields']['status'],
			'progress': issue['fields']['progress'],
			'url': issue['self'].replace(/\/rest\/api\/2\/issue\/.*/, '/browse/' + issue['key'])
		});

		chrome.storage.local.get(issue['key'], function(storedAttributes) {
			if (storedAttributes) {
				this_.set(storedAttributes);
			}
		});

		this.on({
			'change:assignee': function(user) {
				app.server.api.updateIssue(this.get('self'), {
					'assignee': user
				}, function(issue) {
					this_.set({
						'assignee': issue['fields']['assignee']
					});
				});
			},
			'change:resolution': function(resolution) {
				app.server.api.updateIssue(this.get('self'), {
					'resolution': resolution
				}, function(issue) {
					this_.set({
						'resolution': issue['fields']['resolution']
					});
				});
			},
			'change:duedate': function(e) {
				app.server.api.updateIssue(this.get('self'), {
					'duedate': moment(e.start).format('YYYY-MM-DD')
				}, function(issue) {
					this_.set({
						'duedate': new Date(issue['fields']['duedate'])
					});
				});
			},
			'change:estiamte': function(e) {
				app.server.api.updateIssue(this.get('self'), {
					'timetracking': {
						'originalEstimateSeconds': (e.end - e.start)/1000
					}
				}, function(issue) {
					this_.set({
						'estimate': parseInt(issue['fields']['timetracking']['originalEstimateSeconds'])
					});
				});
			},
			'change:progress': function(started) {
				if (started) {
					this.set({'started': new Date()});
					var obj = {};
					obj[this.get('key')] = {
						'started': new Date()
					};
					chrome.storage.local.set(obj);
				} else {
					this.unset('started');
					chrome.storage.local.remove(this.get('key'));
				}
			}
		});
	},
	worklog: function(data) {
		app.server.api.worklog(this.get('self'), data);
	},
	comment: function(data) {
		app.server.api.comment(this.get('self'), data);
	}
});

var Issues = Backbone.Collection.extend({
	'model': Issue
});

var Filter = Backbone.Model.extend({
	UPDATE_INTERVAL: 1*60000, // 1min
	timeout: null,
	'issues': new Issues(),
	'initialize': function(filter) {
		var this_ = this;

		this.on('change', function() {
			this.update();
		});

		this.set({
			'name': filter['name'],
			'jql': filter['jql'],
			'type': filter['type'] || app.FILTER_TYPE_TABLE
		});
		this.update();
		this.collection.trigger('created', this);
		this.timeout = window.setInterval(function() {
			this_.update();
		}, this.UPDATE_INTERVAL);
	},
	'update': function() {
		var this_ = this;
		this.collection.server.api.executeJQL(this.get('jql'), function(issues) {
			this_['issues'] = new Issues(issues);
			this_['issues'].on('change', function() {
				this_.trigger('updated', this_);
			})
			this_.trigger('updated', this_);
		});
	}
});

var Filters = Backbone.Collection.extend({
    model: Filter
});

var ServerModel = Backbone.Model.extend({
	filters: new Filters,
	api: null,
	sync: function(cmd, server){
		var this_ = this;
		console.log(cmd);
		if (cmd === 'create') {
			this.set('filters', this.filters.toJSON());
			chrome.storage.local.set({
				'server': this_.attributes
			});
		} else if (cmd === 'read') {
			chrome.storage.local.get('server', function(data) {
				this_.set(data['server']);
				this_.trigger('load');
			});
		}
	},
	initialize: function() {
		this.filters.server = this;
		this.on('connected', function() {
			console.log(this.get('filters'));
			this.filters.add(this.get('filters'));
		});

		this.on('load', function() {
			var this_ = this;
			if (this.get('url') && this.get('token')) {
				var api = new JIRA(this.get('url'), this.get('url'));
				api.checkAuthorization(function(res, msg) {
					if (res) {
						this_.api = api;
						this_.trigger('connected');
					} else {
						this_.trigger('disconnected');
						if (msg) {
							this_.trigger('connection-error', msg);
						}
					}
				});
			} else {
				this.trigger('disconnected');
			}
		});

		this.on('login', function(e) {
			var this_ = this;
			var api = new JIRA(e.url);
			api.login(e.username, e.password, function(res, data){
				if (res) {
					this_.set({
						'url': e.url,
						'token': data,
						'username': e.username,
						'filters': this.get('filters') || app.FILTERS_DEFAULT
					});
					this_.save();
					this_.api = api;
					this_.trigger('connected');
				} else {
					app.server.trigger('login-error', data)
				}
			})
		});

		this.listenTo(this.filters, 'all', function(e) {
			if (e == 'add' || e == 'remove' || e == 'change') {
				this.save();
			}
		});

		this.fetch();
	}
});<|endoftext|>


<commit_before>var WebSocketServer = require('ws').Server,
  MongoClient = require('mongodb').MongoClient,
  bodyParser = require('body-parser'),
  fs = require('fs'),
	http = require('http'),
	path = require('path'),
	Handlebars = require('handlebars'),
	express = require('express'),
	app = express(),
	port = process.env.PORT || 5000,
  courseUriBase = (port == 5000 ? "http://localhost:5000" : "http://www.quizhours.com"),
	mongoUri = process.env.MONGOHQ_URL || 'mongodb://localhost:27017',
	mongoCourseCollectionName = 'courses',
  mongoFeedbackCollectionName = 'feedback',
  router = express.Router();

MongoClient.connect(mongoUri, function(err, db){
  if(err) throw err;
  //db.collection(mongoCourseCollectionName).drop(); //clear collection for time being while testing
  db.collection(mongoFeedbackCollectionName).drop(); //clear collection for time being while testing
  /*var collection = db.collection(mongoCourseCollectionName);
  var filename = 'course-template1.json'; // reset the demo file on each server restart
  fs.readFile(path.join(process.cwd(), '/data/courses/'+filename), 'utf8', function(err, data){
    var initialCourse;
    if(err){
      console.log('error reading from file');
      return;
    } else {
      data = data.split("\\").join("\\\\");
      initialCourse = JSON.parse(data);
    }
    collection.insert(initialCourse, function(err, docs){
      collection.find().toArray(function(err, results){
          if(err) throw err;
          db.close();
      });
    });
  });*/
});

function compileHandlebars(inputString, context){
  var template = Handlebars.compile(inputString);
  return template(context);
}

// Every extension handled by router involves QuizHours API

// Course data (GET/CREATE/UPDATE/DELETE course)
router.route('/courses/:classcode')

  .get(function(req, res){
    //retrieve requested file from mongodb
    MongoClient.connect(mongoUri, function(conErr, db){
        if(conErr) {
        } else {
          var collection = db.collection(mongoCourseCollectionName);
          collection.find({"classcode": req.params.classcode}).toArray(function(findErr, results){
              if(findErr) {
                res.send(findErr);
              } else {
                results = results[0];
                delete results.password;
                delete results._id;
                res.json(results);
              }
              db.close();
          });
        }
    });
  })

  //create new file in mongodb
  .post(function(req, res){
      var courseData = req.body;
      res.send(courseData);
      /*MongoClient.connect(mongoUri, function(conErr, db){
          if(conErr) {
            res.send(conErr);
            throw conErr;
          }
          var collection = db.collection(mongoCourseCollectionName);
          collection.insert(courseData, function(insertErr, docs){
              if(insertErr){
                res.send(insertErr);
                throw insertErr;
              }
              res.json({"result": "success"});
              db.close();
          });
      });*/
  })

  //update file in mongodb
  .put(function(req, res){
      var courseData = req.body.data;
      MongoClient.connect(mongoUri, function(conErr, db){
          if(conErr) {
          } else {
            var collection = db.collection(mongoCourseCollectionName);
            // We use "$set" when passing in data to prevent overwriting password
            collection.findAndModify({"classcode": req.params.classcode},
                                     [['_id', 'asc']],
                                     {"$set": courseData},
                                     {},
            function(err, object){
                if(err){
                  res.send(err);
                } else {
                  res.send(object); // NOTE: passes back pre-modification file!
                }
                db.close();
            });
          }
      });
  });

router.route('/feedback')

  .get(function(req, res){
    //retrieve requested file from mongodb
    MongoClient.connect(mongoUri, function(conErr, db){
        if(conErr) {
        } else {
          var collection = db.collection(mongoFeedbackCollectionName);
          collection.find().toArray(function(findErr, results){
              if(findErr) {
                res.send(findErr);
              } else {
                for(var i = 0; i < results.length; i++){
                  delete results[i]._id;
                }
                res.json(results);
              }
              db.close();
          });
        }
    });
  })

  .post(function(req, res){
    var feedback = req.body.feedback;
    MongoClient.connect(mongoUri, function(conErr, db){
      if(conErr){
      } else {
        var collection = db.collection(mongoFeedbackCollectionName);
        collection.insert(feedback, function(insertErr, docs){
          if(insertErr){
            res.json({"success": false});
          } else {
            res.json({"success": true});
          }
          db.close();
        });
      }
    });
  });

// "1mb" is a hack to overcome Error 413 "Entity too large"
// Is there a better solution?
app.use(bodyParser.json({limit:'1mb'}));

app.use('/api', router);

// Every extension handled by app.VERB is functionality for the webapp

app.get('/course/:classcode', function(request, response){
    var classcode = request.params.classcode;
    // TODO: add code to check for classcode, return error if not present/valid
    fs.readFile('public/quiz.html', 'utf8', function(err, file){
        if(err){
        } else {
          var context = {"classcode": classcode};
          response.send(compileHandlebars(file, context));
        }
    });
});

// Hack to control api endpoint between development and production
app.get('/js/:classcode/quiz.js', function(request, response){
    //var course_uri = (port == 5000 ? "http://localhost:5000" : "http://quizhours.herokuapp.com");
    course_uri = courseUriBase + "/api/courses/" + request.params.classcode;
    fs.readFile('public/javascripts/quiz.js', 'utf8', function(err, file){
        if(err) {
        } else {
          var context = {"uriHook": course_uri};
          response.send(compileHandlebars(file, context));
        }
    });
});

app.get('/qb/course/:classcode', function(request, response){
    var classcode = request.params.classcode;
    // TODO: add code to check for classcode, return error if not present/valid
    fs.readFile('quizbuilder/quizbuilder.html', 'utf8', function(err, file){
        if(err){
        } else {
          var context = {"classcode": classcode};
          response.send(compileHandlebars(file, context));
        }
    });
});

app.get('/qb/js/:classcode', function(request, response){
    //var course_uri = (port == 5000 ? "http://localhost:5000" : "http://quizhours.herokuapp.com");
    course_uri = courseUriBase + "/api/courses/" + request.params.classcode;
    fs.readFile('quizbuilder/quizbuilder.js', 'utf8', function(err, file){
        if(err) {
        } else {
          var context = {"uriHook": course_uri};
          response.send(compileHandlebars(file, context));
        }
    });
});

app.use(express.static(__dirname + '/public'));

var server = http.createServer(app);
server.listen(port);
<commit_msg>Added input checking to api endpoints<commit_after>var WebSocketServer = require('ws').Server,
  MongoClient = require('mongodb').MongoClient,
  bodyParser = require('body-parser'),
  fs = require('fs'),
	http = require('http'),
	path = require('path'),
	Handlebars = require('handlebars'),
	express = require('express'),
	app = express(),
	port = process.env.PORT || 5000,
  courseUriBase = (port == 5000 ? "http://localhost:5000" : "http://www.quizhours.com"),
	mongoUri = process.env.MONGOHQ_URL || 'mongodb://localhost:27017',
	mongoCourseCollectionName = 'courses',
  mongoFeedbackCollectionName = 'feedback',
  router = express.Router();

MongoClient.connect(mongoUri, function(err, db){
  if(err) throw err;
  //db.collection(mongoCourseCollectionName).drop(); //clear collection for time being while testing
  db.collection(mongoFeedbackCollectionName).drop(); //clear collection for time being while testing
  /*var collection = db.collection(mongoCourseCollectionName);
  var filename = 'course-template1.json'; // reset the demo file on each server restart
  fs.readFile(path.join(process.cwd(), '/data/courses/'+filename), 'utf8', function(err, data){
    var initialCourse;
    if(err){
      console.log('error reading from file');
      return;
    } else {
      data = data.split("\\").join("\\\\");
      initialCourse = JSON.parse(data);
    }
    collection.insert(initialCourse, function(err, docs){
      collection.find().toArray(function(err, results){
          if(err) throw err;
          db.close();
      });
    });
  });*/
});

function compileHandlebars(inputString, context){
  var template = Handlebars.compile(inputString);
  return template(context);
}

// Every extension handled by router involves QuizHours API

// Course data (GET/CREATE/UPDATE/DELETE course)
router.route('/courses/:classcode')

  .get(function(req, res){
    //retrieve requested file from mongodb
    if(typeof(req.params.classcode) !== 'undefined'){
      MongoClient.connect(mongoUri, function(conErr, db){
          if(conErr) {
          } else {
            var collection = db.collection(mongoCourseCollectionName);
            collection.find({"classcode": req.params.classcode}).toArray(function(findErr, results){
                if(findErr) {
                  res.send(findErr);
                } else {
                  results = results[0];
                  delete results.password;
                  delete results._id;
                  res.json(results);
                }
                db.close();
            });
          }
      });
    }
  })

  //create new file in mongodb
  .post(function(req, res){
      var courseData = req.body;
      res.send(courseData);
      /*MongoClient.connect(mongoUri, function(conErr, db){
          if(conErr) {
            res.send(conErr);
            throw conErr;
          }
          var collection = db.collection(mongoCourseCollectionName);
          collection.insert(courseData, function(insertErr, docs){
              if(insertErr){
                res.send(insertErr);
                throw insertErr;
              }
              res.json({"result": "success"});
              db.close();
          });
      });*/
  })

  //update file in mongodb
  .put(function(req, res){
      var courseData = req.body.data;
      if(typeof(req.params.classcode) !== 'undefined' && typeof(courseData) !== 'undefined'){
        MongoClient.connect(mongoUri, function(conErr, db){
            if(conErr) {
            } else {
              var collection = db.collection(mongoCourseCollectionName);
              // We use "$set" when passing in data to prevent overwriting password
              collection.findAndModify({"classcode": req.params.classcode},
                                       [['_id', 'asc']],
                                       {"$set": courseData},
                                       {},
              function(err, object){
                  if(err){
                    res.send(err);
                  } else {
                    res.send(object); // NOTE: passes back pre-modification file!
                  }
                  db.close();
              });
            }
        });
      }
  });

router.route('/feedback')

  .get(function(req, res){
    //retrieve requested file from mongodb
    MongoClient.connect(mongoUri, function(conErr, db){
        if(conErr) {
        } else {
          var collection = db.collection(mongoFeedbackCollectionName);
          collection.find().toArray(function(findErr, results){
              if(findErr) {
                res.send(findErr);
              } else {
                for(var i = 0; i < results.length; i++){
                  delete results[i]._id;
                }
                res.json(results);
              }
              db.close();
          });
        }
    });
  })

  .post(function(req, res){
    var feedback = req.body.feedback;
    if(typeof(req.body.feedback) !== 'undefined'){
      MongoClient.connect(mongoUri, function(conErr, db){
        if(conErr){
        } else {
          var collection = db.collection(mongoFeedbackCollectionName);
          collection.insert(feedback, function(insertErr, docs){
            if(insertErr){
              res.json({"success": false});
            } else {
              res.json({"success": true});
            }
            db.close();
          });
        }
      });
    }
  });

// "1mb" is a hack to overcome Error 413 "Entity too large"
// Is there a better solution?
app.use(bodyParser.json({limit:'1mb'}));

app.use('/api', router);

// Every extension handled by app.VERB is functionality for the webapp

app.get('/course/:classcode', function(request, response){
    var classcode = request.params.classcode;
    // TODO: add code to check for classcode, return error if not present/valid
    fs.readFile('public/quiz.html', 'utf8', function(err, file){
        if(err){
        } else {
          var context = {"classcode": classcode};
          response.send(compileHandlebars(file, context));
        }
    });
});

// Hack to control api endpoint between development and production
app.get('/js/:classcode/quiz.js', function(request, response){
    //var course_uri = (port == 5000 ? "http://localhost:5000" : "http://quizhours.herokuapp.com");
    course_uri = courseUriBase + "/api/courses/" + request.params.classcode;
    fs.readFile('public/javascripts/quiz.js', 'utf8', function(err, file){
        if(err) {
        } else {
          var context = {"uriHook": course_uri};
          response.send(compileHandlebars(file, context));
        }
    });
});

app.get('/qb/course/:classcode', function(request, response){
    var classcode = request.params.classcode;
    // TODO: add code to check for classcode, return error if not present/valid
    fs.readFile('quizbuilder/quizbuilder.html', 'utf8', function(err, file){
        if(err){
        } else {
          var context = {"classcode": classcode};
          response.send(compileHandlebars(file, context));
        }
    });
});

app.get('/qb/js/:classcode', function(request, response){
    //var course_uri = (port == 5000 ? "http://localhost:5000" : "http://quizhours.herokuapp.com");
    course_uri = courseUriBase + "/api/courses/" + request.params.classcode;
    fs.readFile('quizbuilder/quizbuilder.js', 'utf8', function(err, file){
        if(err) {
        } else {
          var context = {"uriHook": course_uri};
          response.send(compileHandlebars(file, context));
        }
    });
});

app.use(express.static(__dirname + '/public'));

var server = http.createServer(app);
server.listen(port);
<|endoftext|>


<commit_before>const home = {
  url: '/',
  controller: 'HomeCtrl as homeCtrl',
  templateUrl: 'home.html',
  title: 'Home'
};

const login = {
  guest: true,

  url: '/login',
  controller: 'LoginCtrl as loginCtrl',
  templateUrl: 'auth/login.html',
  title: 'Login'
};

const register = {
  guest: true,

  url: '/register',
  controller: 'RegisterCtrl as registerCtrl',
  templateUrl: 'auth/register.html',
  title: 'Register'
};

const account = {
  url: '/account',
  controller: 'AccountCtrl as accountCtrl',
  templateUrl: 'account.html',
  title: 'Account',
  resolve: {
    me: function (AccountService) {
      return AccountService.me();
    }
  }
};

const proposals = {
  url: '/proposals',
  controller: 'ProposalsCtrl as proposalCtrl',
  templateUrl: 'proposals/index.html',
  title: 'Proposals',
  resolve: {
    proposals: function (ProposalService) {
      return ProposalService.index();
    }
  }
};

const showProposal = {
  url: '/proposals/:id',
  controller: 'ProposalCtrl as proposalCtrl',
  templateUrl: 'proposals/show.html',
  title: 'Proposal',
  resolve: {
    proposal: function (ProposalService, $stateParams) {
      return ProposalService.get($stateParams.id);
    }
  }
};

const createProposal = {
  authenticate: false, //true,

  url: '/proposals/create',
  controller: 'CreateProposalCtrl as proposalCtrl',
  templateUrl: 'proposals/create.html',
  title: 'Submit proposal'
};

const projects = {
  url: '/projects',
  controller: 'ProjectsCtrl as projectCtrl',
  templateUrl: 'projects/index.html',
  title: 'Projects',
  resolve: {
    projects: function (ProjectService) {
      return ProjectService.index();
    }
  }
};

const showProject = {
  url: '/projects/:id',
  controller: 'ProjectCtrl as projectCtrl',
  templateUrl: 'projects/show.html',
  title: 'Project',
  resolve: {
    project: function (ProjectService, $stateParams) {
      return ProjectService.get($stateParams.id);
    }
  }
};

const createProject = {
  authenticate: false, //true,
  url: '/proposals/:id/project',
  controller: 'CreateProjectCtrl as projectCtrl',
  templateUrl: 'projects/create.html',
  title: 'Submit proposal',
  resolve: {
    proposal: function (ProposalService, $stateParams) {
      return ProposalService.get($stateParams.id);
    },
    teams: function (TeamService, $stateParams) {
      return TeamService.index($stateParams.id);
    }
  }
};

export default {
  setup: function ($stateProvider) {
    $stateProvider
      .state('home', home)
      .state('login', login)
      .state('register', register)
      .state('account', account)
      .state('proposals', proposals)
      .state('createProposal', createProposal)
      .state('showProposal', showProposal)
      .state('projects', projects)
      .state('showProject', showProject)
      .state('createProject', createProject);
  }
};
<commit_msg>added route for edit proposal<commit_after>const home = {
  url: '/',
  controller: 'HomeCtrl as homeCtrl',
  templateUrl: 'home.html',
  title: 'Home'
};

const login = {
  guest: true,

  url: '/login',
  controller: 'LoginCtrl as loginCtrl',
  templateUrl: 'auth/login.html',
  title: 'Login'
};

const register = {
  guest: true,

  url: '/register',
  controller: 'RegisterCtrl as registerCtrl',
  templateUrl: 'auth/register.html',
  title: 'Register'
};

const account = {
  url: '/account',
  controller: 'AccountCtrl as accountCtrl',
  templateUrl: 'account.html',
  title: 'Account',
  resolve: {
    me: function (AccountService) {
      return AccountService.me();
    }
  }
};

const proposals = {
  url: '/proposals',
  controller: 'ProposalsCtrl as proposalCtrl',
  templateUrl: 'proposals/index.html',
  title: 'Proposals',
  resolve: {
    proposals: function (ProposalService) {
      return ProposalService.index();
    }
  }
};

const showProposal = {
  url: '/proposals/:id',
  controller: 'ProposalCtrl as proposalCtrl',
  templateUrl: 'proposals/show.html',
  title: 'Proposal',
  resolve: {
    proposal: function (ProposalService, $stateParams) {
      return ProposalService.get($stateParams.id);
    }
  }
};

const createProposal = {
  authenticate: false, //true,

  url: '/proposals/create',
  controller: 'CreateProposalCtrl as proposalCtrl',
  templateUrl: 'proposals/create.html',
  title: 'Submit proposal'
};

const editProposal = {
  authenticate: false, //true,

  url: '/proposals/:id/create',
  controller: 'EditProposalCtrl as proposalCtrl',
  templateUrl: 'proposals/edit.html',
  title: 'Edit proposal'
  resolve: {
    proposal: function (ProposalService, $stateParams) {
      return ProposalService.get($stateParams.id);
    },
};

const projects = {
  url: '/projects',
  controller: 'ProjectsCtrl as projectCtrl',
  templateUrl: 'projects/index.html',
  title: 'Projects',
  resolve: {
    projects: function (ProjectService) {
      return ProjectService.index();
    }
  }
};

const showProject = {
  url: '/projects/:id',
  controller: 'ProjectCtrl as projectCtrl',
  templateUrl: 'projects/show.html',
  title: 'Project',
  resolve: {
    project: function (ProjectService, $stateParams) {
      return ProjectService.get($stateParams.id);
    }
  }
};

const createProject = {
  authenticate: false, //true,
  url: '/proposals/:id/project',
  controller: 'CreateProjectCtrl as projectCtrl',
  templateUrl: 'projects/create.html',
  title: 'Submit proposal',
  resolve: {
    proposal: function (ProposalService, $stateParams) {
      return ProposalService.get($stateParams.id);
    },
    teams: function (TeamService, $stateParams) {
      return TeamService.index($stateParams.id);
    }
  }
};

export default {
  setup: function ($stateProvider) {
    $stateProvider
      .state('home', home)
      .state('login', login)
      .state('register', register)
      .state('account', account)
      .state('proposals', proposals)
      .state('createProposal', createProposal)
      .state('showProposal', showProposal)
      .state('projects', projects)
      .state('showProject', showProject)
      .state('createProject', createProject);
  }
};
<|endoftext|>


<commit_before>/* eslint-disable no-console */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import ObjectInspector from 'react-object-inspector';
import Command from './args';
import Bar from './Bar';
import Content from './Content';
import './Terminal.css';

(function setOldLogger() {
  console['oldLog'] = console['log']; // eslint-disable-line dot-notation
}());

function handleLogging(method, addToOutput) {
  // eslint-disable-next-line no-console
  console[method] = (...args) => {
    try {
      console.oldLog(`[${method}]`, ...args);
    } catch (e) {
      throw new Error('Terminal was loaded more than once check script tags');
    }
    const res = [...args].slice(0, 15).map((arg, i) => {
      switch (typeof arg) {
        case 'object':
          return <ObjectInspector data={arg} key={`object-${i}`} />;
        case 'function':
          return `${arg}`;
        default:
          return arg;
      }
    });
    addToOutput(res);
  };
  Object.defineProperty(console[method], 'name', { value: method, writable: false }); // eslint-disable-line no-console
}

const commandsPropType = PropTypes.objectOf(PropTypes.oneOfType([
  PropTypes.func,
  PropTypes.shape({
    options: PropTypes.arrayOf(PropTypes.shape({
      name: PropTypes.string,
      description: PropTypes.string,
      defaultValue: PropTypes.any,
    })),
    method: PropTypes.func,
  }),
]));

const descriptionsPropType = PropTypes.objectOf(PropTypes.oneOfType([
  PropTypes.string,
  PropTypes.bool,
]));

class Terminal extends Component {
  static displayName = 'Terminal';

  static propTypes = {
    msg: PropTypes.string,
    color: PropTypes.string,
    style: PropTypes.object, // eslint-disable-line
    prompt: PropTypes.string,
    barColor: PropTypes.string,
    backgroundColor: PropTypes.string,
    commands: commandsPropType,
    descriptions: descriptionsPropType,
    watchConsoleLogging: PropTypes.bool,
    commandPassThrough: PropTypes.oneOfType([
      PropTypes.func,
      PropTypes.bool,
    ]),
    promptSymbol: PropTypes.string,
    plugins: PropTypes.arrayOf(PropTypes.shape({
      name: PropTypes.string.isRequired,
      load: PropTypes.func,
      commands: commandsPropType,
      descriptions: descriptionsPropType,
    })),
  };

  static defaultProps = {
    msg: '',
    color: 'green',
    style: {},
    prompt: 'green',
    barColor: 'black',
    backgroundColor: 'black',
    commands: {},
    descriptions: {},
    watchConsoleLogging: true,
    commandPassThrough: false,
    promptSymbol: '>',
    plugins: [],
  };

  static childContextTypes = {
    symbol: PropTypes.string,
    show: PropTypes.bool,
    minimise: PropTypes.bool,
    maximise: PropTypes.bool,
    closeWindow: PropTypes.func,
    openWindow: PropTypes.func,
    minimiseWindow: PropTypes.func,
    unminimiseWindow: PropTypes.func,
    maximiseWindow: PropTypes.func,
    unmaximiseWindow: PropTypes.func,
    toggleShow: PropTypes.func,
    toggleMaximise: PropTypes.func,
    toggleMinimize: PropTypes.func,
  };

  state = {
    prompt: '>',
    promptPrefix: '',
    summary: [],
    commands: {},
    descriptions: {},
    history: [],
    historyCounter: 0,
    show: true,
    minimise: false,
    maximise: false,
  };

  getChildContext() {
    return {
      symbol: this.state.promptPrefix + this.state.prompt,
      show: this.state.show,
      minimise: this.state.minimise,
      maximise: this.state.maximise,
      openWindow: this.setTrue('show'),
      closeWindow: this.setFalse('show'),
      minimiseWindow: this.setTrue('minimise'),
      unminimiseWindow: this.setFalse('minimise'),
      maximiseWindow: this.setTrue('maximise'),
      unmaximiseWindow: this.setFalse('maximise'),
      toggleShow: this.toggleState('show'),
      toggleMaximise: this.toggleState('maximise'),
      toggleMinimize: this.toggleState('minimise'),
    };
  }

  /* Life cycle */
  componentWillMount = () => {
    this.setState({ prompt: this.props.promptSymbol });
  };

  componentDidMount = () => {
    this.loadPlugins();
    this.assembleCommands();
    this.setDescriptions();
    this.showMsg();

    if (this.props.watchConsoleLogging) {
      this.watchConsoleLogging();
    }
  };

  /* Getters */
  getAppContent = () => {
    const { show, minimise } = this.state;
    if (!show) {
      return this.showNote();
    }
    if (minimise) {
      return this.showBar();
    }
    return this.showContent();
  };

  getContent = () => {
    const { backgroundColor, color, style, barColor, prompt } = this.props;

    const inputStyles = { backgroundColor, color };
    const promptStyles = { color: prompt };
    const barColorStyles = { backgroundColor: barColor };
    const backgroundColorStyles = { backgroundColor };

    const output = this.state.summary.map((content, i) => {
      if (typeof content === 'string' && content.length === 0) {
        return

;
      }
      return
{content}
;
    });

    return (

        <Bar style={barColorStyles} />
        <Content
          output={output}
          prompt={promptStyles}
          inputStyles={inputStyles}
          handleChange={this.handleChange}
          backgroundColor={backgroundColorStyles}
          setHistoryCommand={this.setHistoryCommand}
        />

    );
  };

  getBar = () => {
    const { color, barColor, style } = this.props;
    const barColorStyles = { backgroundColor: barColor };

    return (

        <Bar style={barColorStyles} />

    );
  }

  getNote = () => (

OOPS! You closed the window.

      Click on the icon to reopen.

  );

  /* Setters */
  setDescriptions = () => {
    let descriptions = {
      show: 'show the msg',
      clear: 'clear the screen',
      help: 'list all the commands',
      echo: 'output the input',
      'edit-line': 'edit the contents of an output line',
      ...this.props.descriptions,
    };
    this.props.plugins.forEach((plugin) => {
      if (plugin.descriptions) {
        descriptions = {
          ...descriptions,
          ...plugin.descriptions,
        };
      }
    });
    this.setState({ descriptions });
  };

  setFalse = name => () => this.setState({ [name]: false });

  /**
   * Base of key code set the value of the input
   * with the history
   * 38 is key up
   * 40 is key down
   * @param {event} event of input
   */
  setHistoryCommand = (e, inputRef) => {
    const { historyCounter } = this.state;
    if (e.keyCode === 38) {
      this.setValueWithHistory(historyCounter - 1, inputRef);
    } else if (e.keyCode === 40) {
      this.setValueWithHistory(historyCounter + 1, inputRef);
    }
  };

  setPromptPrefix = (promptPrefix) => {
    this.setState({ promptPrefix });
  };

  setTrue = name => () => this.setState({ [name]: true });

  /**
   * set the input value with the possible history value
   * @param {number} next position on the history
   */
  setValueWithHistory = (position, inputRef) => {
    const { history } = this.state;
    if (history[position]) {
      this.setState({ historyCounter: position });
      inputRef.value = history[position];
    }
  };

  /* General */
  assembleCommands = () => {
    let commands = {
      show: this.showMsg,
      clear: this.clearScreen,
      help: this.showHelp,
      echo: (input) => { console.log(...input.slice(1)); },
      'edit-line': {
        method: this.editLine,
        options: [
          {
            name: 'line',
            description: 'the line you want to edit. -1 is the last line',
            init: value => parseInt(value, 10),
            defaultValue: -1,
          },
        ],
      },
      ...this.props.commands,
    };

    this.props.plugins.forEach((plugin) => {
      if (plugin.commands) {
        commands = {
          ...commands,
          ...plugin.commands,
        };
      }
    });

    Object.keys(commands).forEach((name) => {
      const definition = commands[name];
      let method = definition;
      let parse = i => i;
      if (typeof definition === 'object') {
        const cmd = new Command();
        if (typeof definition.options !== 'undefined') {
          try {
            cmd.options(definition.options);
          } catch (e) {
            throw new Error('options for command wrong format');
          }
        }
        parse = i => cmd.parse(i, {
          name,
          help: true,
          version: false,
        });
        method = definition.method;
      }

      commands[name] = {
        parse,
        method,
      };
    });
    this.setState({ commands });
  };

  clearScreen = () => {
    this.setState({ summary: [] });
  };

  editLine = (args) => {
    const { summary } = this.state;
    let index = args.line;
    if (index === -1) {
      index = summary.length === 0 ? 0 : summary.length - 1;
    }
    summary[index] = args._.join(' ');
    this.setState({ summary });
  }

  handleChange = (e) => {
    if (e.key === 'Enter') {
      this.printLine(`${this.state.promptPrefix}${this.state.prompt} ${e.target.value}`);

      const res = this.runCommand(e.target.value);

      if (typeof res !== 'undefined') {
        this.printLine(res);
      }

      const history = [...this.state.history, e.target.value];
      this.setState({
        history,
        historyCounter: history.length,
      });
      e.target.value = ''; // eslint-disable-line no-param-reassign
    }
  };

  loadPlugins = () => {
    this.props.plugins.forEach((plugin) => {
      try {
        plugin.load({
          printLine: this.printLine,
          runCommand: this.runCommand,
          setPromptPrefix: this.setPromptPrefix,
        });
      } catch (e) {
        console.error(`Error loading plugin ${plugin.name}`); // eslint-disable-line no-console
        console.dir(e);
      }
    });
  };

  printLine = (inp) => {
    const summary = this.state.summary;
    summary.push(inp);
    this.setState({ summary });
  };

  runCommand = (inputText) => {
    const inputArray = inputText.split(' ');
    const input = inputArray[0];
    const args = inputArray; // Undefined for function call
    const command = this.state.commands[input];
    let res;

    if (input === '') {
      // do nothing
    } else if (command === undefined) {
      if (typeof this.props.commandPassThrough === 'function') {
        res = this.props.commandPassThrough(inputArray, this.printLine, this.runCommand);
      } else {
        this.printLine(`-bash:${input}: command not found`);
      }
    } else {
      const parsedArgs = command.parse(args);
      if (typeof parsedArgs !== 'object' || (typeof parsedArgs === 'object' && !parsedArgs.help)) {
        res = command.method(parsedArgs, this.printLine, this.runCommand);
      }
    }
    return res;
  }

  toggleState = name => () => this.setState({ [name]: !this.state[name] });

  watchConsoleLogging = () => {
    handleLogging('log', this.printLine);
    handleLogging('info', this.printLine);
    handleLogging('warn', this.printLine);
    handleLogging('error', this.printLine);
  };

  showHelp = () => {
    const options = Object.keys(this.state.commands);
    const descriptions = this.state.descriptions;
    for (const option of options) {
      // eslint-disable-line no-restricted-syntax
      if (descriptions[option] !== false) {
        this.printLine(`${option} - ${descriptions[option]}`);
      }
    }
  };

  showMsg = () => {
    this.printLine(this.props.msg);
  };

  /* Render */
  render() {
    return (

        {this.getContent()}

    );
  }
}

export default Terminal;
<commit_msg>multi line inputs<commit_after>/* eslint-disable no-console */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import ObjectInspector from 'react-object-inspector';
import Command from './args';
import Bar from './Bar';
import Content from './Content';
import './Terminal.css';

(function setOldLogger() {
  console['oldLog'] = console['log']; // eslint-disable-line dot-notation
}());

function handleLogging(method, addToOutput) {
  // eslint-disable-next-line no-console
  console[method] = (...args) => {
    try {
      console.oldLog(`[${method}]`, ...args);
    } catch (e) {
      throw new Error('Terminal was loaded more than once check script tags');
    }
    const res = [...args].slice(0, 15).map((arg, i) => {
      switch (typeof arg) {
        case 'object':
          return <ObjectInspector data={arg} key={`object-${i}`} />;
        case 'function':
          return `${arg}`;
        default:
          return arg;
      }
    });
    addToOutput(res);
  };
  Object.defineProperty(console[method], 'name', { value: method, writable: false }); // eslint-disable-line no-console
}

const commandsPropType = PropTypes.objectOf(PropTypes.oneOfType([
  PropTypes.func,
  PropTypes.shape({
    options: PropTypes.arrayOf(PropTypes.shape({
      name: PropTypes.string,
      description: PropTypes.string,
      defaultValue: PropTypes.any,
    })),
    method: PropTypes.func,
  }),
]));

const descriptionsPropType = PropTypes.objectOf(PropTypes.oneOfType([
  PropTypes.string,
  PropTypes.bool,
]));

class Terminal extends Component {
  static displayName = 'Terminal';

  static propTypes = {
    msg: PropTypes.string,
    color: PropTypes.string,
    style: PropTypes.object, // eslint-disable-line
    prompt: PropTypes.string,
    barColor: PropTypes.string,
    backgroundColor: PropTypes.string,
    commands: commandsPropType,
    descriptions: descriptionsPropType,
    watchConsoleLogging: PropTypes.bool,
    commandPassThrough: PropTypes.oneOfType([
      PropTypes.func,
      PropTypes.bool,
    ]),
    promptSymbol: PropTypes.string,
    plugins: PropTypes.arrayOf(PropTypes.shape({
      name: PropTypes.string.isRequired,
      load: PropTypes.func,
      commands: commandsPropType,
      descriptions: descriptionsPropType,
    })),
  };

  static defaultProps = {
    msg: '',
    color: 'green',
    style: {},
    prompt: 'green',
    barColor: 'black',
    backgroundColor: 'black',
    commands: {},
    descriptions: {},
    watchConsoleLogging: true,
    commandPassThrough: false,
    promptSymbol: '>',
    plugins: [],
  };

  static childContextTypes = {
    symbol: PropTypes.string,
    show: PropTypes.bool,
    minimise: PropTypes.bool,
    maximise: PropTypes.bool,
    closeWindow: PropTypes.func,
    openWindow: PropTypes.func,
    minimiseWindow: PropTypes.func,
    unminimiseWindow: PropTypes.func,
    maximiseWindow: PropTypes.func,
    unmaximiseWindow: PropTypes.func,
    toggleShow: PropTypes.func,
    toggleMaximise: PropTypes.func,
    toggleMinimize: PropTypes.func,
  };

  state = {
    prompt: '>',
    promptPrefix: '',
    summary: [],
    commands: {},
    descriptions: {},
    history: [],
    historyCounter: 0,
    show: true,
    minimise: false,
    maximise: false,
    input: [],
  };

  getChildContext() {
    return {
      symbol: this.state.promptPrefix + this.state.prompt,
      show: this.state.show,
      minimise: this.state.minimise,
      maximise: this.state.maximise,
      openWindow: this.setTrue('show'),
      closeWindow: this.setFalse('show'),
      minimiseWindow: this.setTrue('minimise'),
      unminimiseWindow: this.setFalse('minimise'),
      maximiseWindow: this.setTrue('maximise'),
      unmaximiseWindow: this.setFalse('maximise'),
      toggleShow: this.toggleState('show'),
      toggleMaximise: this.toggleState('maximise'),
      toggleMinimize: this.toggleState('minimise'),
    };
  }

  /* Life cycle */
  componentWillMount = () => {
    this.setState({ prompt: this.props.promptSymbol });
  };

  componentDidMount = () => {
    this.loadPlugins();
    this.assembleCommands();
    this.setDescriptions();
    this.showMsg();

    if (this.props.watchConsoleLogging) {
      this.watchConsoleLogging();
    }
  };

  /* Getters */
  getAppContent = () => {
    const { show, minimise } = this.state;
    if (!show) {
      return this.showNote();
    }
    if (minimise) {
      return this.showBar();
    }
    return this.showContent();
  };

  getContent = () => {
    const { backgroundColor, color, style, barColor, prompt } = this.props;

    const inputStyles = { backgroundColor, color };
    const promptStyles = { color: prompt };
    const barColorStyles = { backgroundColor: barColor };
    const backgroundColorStyles = { backgroundColor };

    const output = this.state.summary.map((content, i) => {
      if (typeof content === 'string' && content.length === 0) {
        return

;
      }
      return
{content}
;
    });

    return (

        <Bar style={barColorStyles} />
        <Content
          output={output}
          prompt={promptStyles}
          inputStyles={inputStyles}
          handleChange={this.handleChange}
          backgroundColor={backgroundColorStyles}
          setHistoryCommand={this.setHistoryCommand}
        />

    );
  };

  getBar = () => {
    const { color, barColor, style } = this.props;
    const barColorStyles = { backgroundColor: barColor };

    return (

        <Bar style={barColorStyles} />

    );
  }

  getNote = () => (

OOPS! You closed the window.

      Click on the icon to reopen.

  );

  /* Setters */
  setDescriptions = () => {
    let descriptions = {
      show: 'show the msg',
      clear: 'clear the screen',
      help: 'list all the commands',
      echo: 'output the input',
      'edit-line': 'edit the contents of an output line',
      ...this.props.descriptions,
    };
    this.props.plugins.forEach((plugin) => {
      if (plugin.descriptions) {
        descriptions = {
          ...descriptions,
          ...plugin.descriptions,
        };
      }
    });
    this.setState({ descriptions });
  };

  setFalse = name => () => this.setState({ [name]: false });

  /**
   * Base of key code set the value of the input
   * with the history
   * 38 is key up
   * 40 is key down
   * @param {event} event of input
   */
  setHistoryCommand = (e, inputRef) => {
    const { historyCounter } = this.state;
    if (e.keyCode === 38) {
      this.setValueWithHistory(historyCounter - 1, inputRef);
    } else if (e.keyCode === 40) {
      this.setValueWithHistory(historyCounter + 1, inputRef);
    }
  };

  setPromptPrefix = (promptPrefix) => {
    this.setState({ promptPrefix });
  };

  setTrue = name => () => this.setState({ [name]: true });

  /**
   * set the input value with the possible history value
   * @param {number} next position on the history
   */
  setValueWithHistory = (position, inputRef) => {
    const { history } = this.state;
    if (history[position]) {
      this.setState({ historyCounter: position });
      inputRef.value = history[position];
    }
  };

  /* General */
  assembleCommands = () => {
    let commands = {
      show: this.showMsg,
      clear: this.clearScreen,
      help: this.showHelp,
      echo: (input) => { console.log(...input.slice(1)); },
      'edit-line': {
        method: this.editLine,
        options: [
          {
            name: 'line',
            description: 'the line you want to edit. -1 is the last line',
            init: value => parseInt(value, 10),
            defaultValue: -1,
          },
        ],
      },
      ...this.props.commands,
    };

    this.props.plugins.forEach((plugin) => {
      if (plugin.commands) {
        commands = {
          ...commands,
          ...plugin.commands,
        };
      }
    });

    Object.keys(commands).forEach((name) => {
      const definition = commands[name];
      let method = definition;
      let parse = i => i;
      if (typeof definition === 'object') {
        const cmd = new Command();
        if (typeof definition.options !== 'undefined') {
          try {
            cmd.options(definition.options);
          } catch (e) {
            throw new Error('options for command wrong format');
          }
        }
        parse = i => cmd.parse(i, {
          name,
          help: true,
          version: false,
        });
        method = definition.method;
      }

      commands[name] = {
        parse,
        method,
      };
    });
    this.setState({ commands });
  };

  clearScreen = () => {
    this.setState({ summary: [] });
  };

  editLine = (args) => {
    const { summary } = this.state;
    let index = args.line;
    if (index === -1) {
      index = summary.length === 0 ? 0 : summary.length - 1;
    }
    summary[index] = args._.join(' ');
    this.setState({ summary });
  }

  handleChange = (e) => {
    if (e.key === 'Enter' && !e.shiftKey) {
      this.printLine(`${this.state.promptPrefix}${this.state.prompt} ${e.target.value}`);
      const { input } = this.state;

      const res = this.runCommand(
        `${input.join('\n')}${input.length > 0 ? '\n' : ''}${e.target.value}`,
      );

      if (typeof res !== 'undefined') {
        this.printLine(res);
      }

      const history = [...this.state.history, e.target.value];
      this.setState({
        input: [],
        history,
        historyCounter: history.length,
      });
      e.target.value = ''; // eslint-disable-line no-param-reassign
    } else if (e.key === 'Enter' && e.shiftKey) {
      this.printLine(`${this.state.promptPrefix}${this.state.prompt} ${e.target.value}`);
      const { input } = this.state;
      const history = [...this.state.history, e.target.value];
      this.setState({
        input: [...input, e.target.value],
        history,
        historyCounter: history.length,
      });
      e.target.value = ''; // eslint-disable-line no-param-reassign
    }
  };

  loadPlugins = () => {
    this.props.plugins.forEach((plugin) => {
      try {
        plugin.load({
          printLine: this.printLine,
          runCommand: this.runCommand,
          setPromptPrefix: this.setPromptPrefix,
        });
      } catch (e) {
        console.error(`Error loading plugin ${plugin.name}`); // eslint-disable-line no-console
        console.dir(e);
      }
    });
  };

  printLine = (inp) => {
    const summary = this.state.summary;
    summary.push(inp);
    this.setState({ summary });
  };

  runCommand = (inputText) => {
    const inputArray = inputText.split(' ');
    const input = inputArray[0];
    const args = inputArray; // Undefined for function call
    const command = this.state.commands[input];
    let res;

    if (input === '') {
      // do nothing
    } else if (command === undefined) {
      if (typeof this.props.commandPassThrough === 'function') {
        res = this.props.commandPassThrough(inputArray, this.printLine, this.runCommand);
      } else {
        this.printLine(`-bash:${input}: command not found`);
      }
    } else {
      const parsedArgs = command.parse(args);
      if (typeof parsedArgs !== 'object' || (typeof parsedArgs === 'object' && !parsedArgs.help)) {
        res = command.method(parsedArgs, this.printLine, this.runCommand);
      }
    }
    return res;
  }

  toggleState = name => () => this.setState({ [name]: !this.state[name] });

  watchConsoleLogging = () => {
    handleLogging('log', this.printLine);
    handleLogging('info', this.printLine);
    // handleLogging('warn', this.printLine);
    // handleLogging('error', this.printLine);
  };

  showHelp = () => {
    const options = Object.keys(this.state.commands);
    const descriptions = this.state.descriptions;
    for (const option of options) {
      // eslint-disable-line no-restricted-syntax
      if (descriptions[option] !== false) {
        this.printLine(`${option} - ${descriptions[option]}`);
      }
    }
  };

  showMsg = () => {
    this.printLine(this.props.msg);
  };

  /* Render */
  render() {
    return (

        {this.getContent()}

    );
  }
}

export default Terminal;
<|endoftext|>