(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

function EventEmitter() {
  this._events = this._events || {};
  this._maxListeners = this._maxListeners || undefined;
}
module.exports = EventEmitter;

// Backwards-compat with node 0.10.x
EventEmitter.EventEmitter = EventEmitter;

EventEmitter.prototype._events = undefined;
EventEmitter.prototype._maxListeners = undefined;

// By default EventEmitters will print a warning if more than 10 listeners are
// added to it. This is a useful default which helps finding memory leaks.
EventEmitter.defaultMaxListeners = 10;

// Obviously not all Emitters should be limited to 10. This function allows
// that to be increased. Set to zero for unlimited.
EventEmitter.prototype.setMaxListeners = function(n) {
  if (!isNumber(n) || n < 0 || isNaN(n))
    throw TypeError('n must be a positive number');
  this._maxListeners = n;
  return this;
};

EventEmitter.prototype.emit = function(type) {
  var er, handler, len, args, i, listeners;

  if (!this._events)
    this._events = {};

  // If there is no 'error' event listener then throw.
  if (type === 'error') {
    if (!this._events.error ||
        (isObject(this._events.error) && !this._events.error.length)) {
      er = arguments[1];
      if (er instanceof Error) {
        throw er; // Unhandled 'error' event
      }
      throw TypeError('Uncaught, unspecified "error" event.');
    }
  }

  handler = this._events[type];

  if (isUndefined(handler))
    return false;

  if (isFunction(handler)) {
    switch (arguments.length) {
      // fast cases
      case 1:
        handler.call(this);
        break;
      case 2:
        handler.call(this, arguments[1]);
        break;
      case 3:
        handler.call(this, arguments[1], arguments[2]);
        break;
      // slower
      default:
        len = arguments.length;
        args = new Array(len - 1);
        for (i = 1; i < len; i++)
          args[i - 1] = arguments[i];
        handler.apply(this, args);
    }
  } else if (isObject(handler)) {
    len = arguments.length;
    args = new Array(len - 1);
    for (i = 1; i < len; i++)
      args[i - 1] = arguments[i];

    listeners = handler.slice();
    len = listeners.length;
    for (i = 0; i < len; i++)
      listeners[i].apply(this, args);
  }

  return true;
};

EventEmitter.prototype.addListener = function(type, listener) {
  var m;

  if (!isFunction(listener))
    throw TypeError('listener must be a function');

  if (!this._events)
    this._events = {};

  // To avoid recursion in the case that type === "newListener"! Before
  // adding it to the listeners, first emit "newListener".
  if (this._events.newListener)
    this.emit('newListener', type,
              isFunction(listener.listener) ?
              listener.listener : listener);

  if (!this._events[type])
    // Optimize the case of one listener. Don't need the extra array object.
    this._events[type] = listener;
  else if (isObject(this._events[type]))
    // If we've already got an array, just append.
    this._events[type].push(listener);
  else
    // Adding the second element, need to change to array.
    this._events[type] = [this._events[type], listener];

  // Check for listener leak
  if (isObject(this._events[type]) && !this._events[type].warned) {
    var m;
    if (!isUndefined(this._maxListeners)) {
      m = this._maxListeners;
    } else {
      m = EventEmitter.defaultMaxListeners;
    }

    if (m && m > 0 && this._events[type].length > m) {
      this._events[type].warned = true;
      console.error('(node) warning: possible EventEmitter memory ' +
                    'leak detected. %d listeners added. ' +
                    'Use emitter.setMaxListeners() to increase limit.',
                    this._events[type].length);
      if (typeof console.trace === 'function') {
        // not supported in IE 10
        console.trace();
      }
    }
  }

  return this;
};

EventEmitter.prototype.on = EventEmitter.prototype.addListener;

EventEmitter.prototype.once = function(type, listener) {
  if (!isFunction(listener))
    throw TypeError('listener must be a function');

  var fired = false;

  function g() {
    this.removeListener(type, g);

    if (!fired) {
      fired = true;
      listener.apply(this, arguments);
    }
  }

  g.listener = listener;
  this.on(type, g);

  return this;
};

// emits a 'removeListener' event iff the listener was removed
EventEmitter.prototype.removeListener = function(type, listener) {
  var list, position, length, i;

  if (!isFunction(listener))
    throw TypeError('listener must be a function');

  if (!this._events || !this._events[type])
    return this;

  list = this._events[type];
  length = list.length;
  position = -1;

  if (list === listener ||
      (isFunction(list.listener) && list.listener === listener)) {
    delete this._events[type];
    if (this._events.removeListener)
      this.emit('removeListener', type, listener);

  } else if (isObject(list)) {
    for (i = length; i-- > 0;) {
      if (list[i] === listener ||
          (list[i].listener && list[i].listener === listener)) {
        position = i;
        break;
      }
    }

    if (position < 0)
      return this;

    if (list.length === 1) {
      list.length = 0;
      delete this._events[type];
    } else {
      list.splice(position, 1);
    }

    if (this._events.removeListener)
      this.emit('removeListener', type, listener);
  }

  return this;
};

EventEmitter.prototype.removeAllListeners = function(type) {
  var key, listeners;

  if (!this._events)
    return this;

  // not listening for removeListener, no need to emit
  if (!this._events.removeListener) {
    if (arguments.length === 0)
      this._events = {};
    else if (this._events[type])
      delete this._events[type];
    return this;
  }

  // emit removeListener for all listeners on all events
  if (arguments.length === 0) {
    for (key in this._events) {
      if (key === 'removeListener') continue;
      this.removeAllListeners(key);
    }
    this.removeAllListeners('removeListener');
    this._events = {};
    return this;
  }

  listeners = this._events[type];

  if (isFunction(listeners)) {
    this.removeListener(type, listeners);
  } else {
    // LIFO order
    while (listeners.length)
      this.removeListener(type, listeners[listeners.length - 1]);
  }
  delete this._events[type];

  return this;
};

EventEmitter.prototype.listeners = function(type) {
  var ret;
  if (!this._events || !this._events[type])
    ret = [];
  else if (isFunction(this._events[type]))
    ret = [this._events[type]];
  else
    ret = this._events[type].slice();
  return ret;
};

EventEmitter.listenerCount = function(emitter, type) {
  var ret;
  if (!emitter._events || !emitter._events[type])
    ret = 0;
  else if (isFunction(emitter._events[type]))
    ret = 1;
  else
    ret = emitter._events[type].length;
  return ret;
};

function isFunction(arg) {
  return typeof arg === 'function';
}

function isNumber(arg) {
  return typeof arg === 'number';
}

function isObject(arg) {
  return typeof arg === 'object' && arg !== null;
}

function isUndefined(arg) {
  return arg === void 0;
}

},{}],2:[function(require,module,exports){
"use strict";

var $ = require("jquery");
var _ = require("lodash");
var AppDispatcher = require("./dispatcher.js").AppDispatcher;

var ActionTypes = {
    // Connection
    CONNECTION_OPEN: "connection_open",
    CONNECTION_CLOSE: "connection_close",
    CONNECTION_ERROR: "connection_error",

    // Stores
    SETTINGS_STORE: "settings",
    EVENT_STORE: "events",
    FLOW_STORE: "flows"
};

var StoreCmds = {
    ADD: "add",
    UPDATE: "update",
    REMOVE: "remove",
    RESET: "reset"
};

var ConnectionActions = {
    open: function open() {
        AppDispatcher.dispatchViewAction({
            type: ActionTypes.CONNECTION_OPEN
        });
    },
    close: function close() {
        AppDispatcher.dispatchViewAction({
            type: ActionTypes.CONNECTION_CLOSE
        });
    },
    error: function error() {
        AppDispatcher.dispatchViewAction({
            type: ActionTypes.CONNECTION_ERROR
        });
    }
};

var SettingsActions = {
    update: function update(settings) {

        $.ajax({
            type: "PUT",
            url: "/settings",
            contentType: 'application/json',
            data: JSON.stringify(settings)
        });

        /*
        //Facebook Flux: We do an optimistic update on the client already.
        AppDispatcher.dispatchViewAction({
            type: ActionTypes.SETTINGS_STORE,
            cmd: StoreCmds.UPDATE,
            data: settings
        });
        */
    }
};

var EventLogActions_event_id = 0;
var EventLogActions = {
    add_event: function add_event(message) {
        AppDispatcher.dispatchViewAction({
            type: ActionTypes.EVENT_STORE,
            cmd: StoreCmds.ADD,
            data: {
                message: message,
                level: "web",
                id: "viewAction-" + EventLogActions_event_id++
            }
        });
    }
};

var FlowActions = {
    accept: function accept(flow) {
        $.post("/flows/" + flow.id + "/accept");
    },
    accept_all: function accept_all() {
        $.post("/flows/accept");
    },
    "delete": function _delete(flow) {
        $.ajax({
            type: "DELETE",
            url: "/flows/" + flow.id
        });
    },
    duplicate: function duplicate(flow) {
        $.post("/flows/" + flow.id + "/duplicate");
    },
    replay: function replay(flow) {
        $.post("/flows/" + flow.id + "/replay");
    },
    revert: function revert(flow) {
        $.post("/flows/" + flow.id + "/revert");
    },
    update: function update(flow, nextProps) {
        /*
        //Facebook Flux: We do an optimistic update on the client already.
        var nextFlow = _.cloneDeep(flow);
        _.merge(nextFlow, nextProps);
        AppDispatcher.dispatchViewAction({
            type: ActionTypes.FLOW_STORE,
            cmd: StoreCmds.UPDATE,
            data: nextFlow
        });
        */
        $.ajax({
            type: "PUT",
            url: "/flows/" + flow.id,
            contentType: 'application/json',
            data: JSON.stringify(nextProps)
        });
    },
    clear: function clear() {
        $.post("/clear");
    }
};

var Query = {
    SEARCH: "s",
    HIGHLIGHT: "h",
    SHOW_EVENTLOG: "e"
};

module.exports = {
    ActionTypes: ActionTypes,
    ConnectionActions: ConnectionActions,
    FlowActions: FlowActions,
    StoreCmds: StoreCmds,
    SettingsActions: SettingsActions,
    EventLogActions: EventLogActions,
    Query: Query
};


},{"./dispatcher.js":21,"jquery":"jquery","lodash":"lodash"}],3:[function(require,module,exports){
"use strict";

var React = require("react");
var ReactRouter = require("react-router");
var $ = require("jquery");
var Connection = require("./connection");
var proxyapp = require("./components/proxyapp.js");
var EventLogActions = require("./actions.js").EventLogActions;

$(function () {
    window.ws = new Connection("/updates");

    window.onerror = function (msg) {
        EventLogActions.add_event(msg);
    };

    ReactRouter.run(proxyapp.routes, function (Handler, state) {
        React.render(React.createElement(Handler, null), document.body);
    });
});


},{"./actions.js":2,"./components/proxyapp.js":18,"./connection":20,"jquery":"jquery","react":"react","react-router":"react-router"}],4:[function(require,module,exports){
"use strict";

var React = require("react");
var ReactRouter = require("react-router");
var _ = require("lodash");

// http://blog.vjeux.com/2013/javascript/scroll-position-with-react.html (also contains inverse example)
var AutoScrollMixin = {
    componentWillUpdate: function componentWillUpdate() {
        var node = this.getDOMNode();
        this._shouldScrollBottom = node.scrollTop !== 0 && node.scrollTop + node.clientHeight === node.scrollHeight;
    },
    componentDidUpdate: function componentDidUpdate() {
        if (this._shouldScrollBottom) {
            var node = this.getDOMNode();
            node.scrollTop = node.scrollHeight;
        }
    }
};

var StickyHeadMixin = {
    adjustHead: function adjustHead() {
        // Abusing CSS transforms to set the element
        // referenced as head into some kind of position:sticky.
        var head = this.refs.head.getDOMNode();
        head.style.transform = "translate(0," + this.getDOMNode().scrollTop + "px)";
    }
};

var SettingsState = {
    contextTypes: {
        settingsStore: React.PropTypes.object.isRequired
    },
    getInitialState: function getInitialState() {
        return {
            settings: this.context.settingsStore.dict
        };
    },
    componentDidMount: function componentDidMount() {
        this.context.settingsStore.addListener("recalculate", this.onSettingsChange);
    },
    componentWillUnmount: function componentWillUnmount() {
        this.context.settingsStore.removeListener("recalculate", this.onSettingsChange);
    },
    onSettingsChange: function onSettingsChange() {
        this.setState({
            settings: this.context.settingsStore.dict
        });
    }
};

var ChildFocus = {
    contextTypes: {
        returnFocus: React.PropTypes.func
    },
    returnFocus: function returnFocus() {
        React.findDOMNode(this).blur();
        window.getSelection().removeAllRanges();
        this.context.returnFocus();
    }
};

var Navigation = _.extend({}, ReactRouter.Navigation, {
    setQuery: function setQuery(dict) {
        var q = this.context.router.getCurrentQuery();
        for (var i in dict) {
            if (dict.hasOwnProperty(i)) {
                q[i] = dict[i] || undefined; //falsey values shall be removed.
            }
        }
        this.replaceWith(this.context.router.getCurrentPath(), this.context.router.getCurrentParams(), q);
    },
    replaceWith: function replaceWith(routeNameOrPath, params, query) {
        if (routeNameOrPath === undefined) {
            routeNameOrPath = this.context.router.getCurrentPath();
        }
        if (params === undefined) {
            params = this.context.router.getCurrentParams();
        }
        if (query === undefined) {
            query = this.context.router.getCurrentQuery();
        }

        this.context.router.replaceWith(routeNameOrPath, params, query);
    }
});

// react-router is fairly good at changing its API regularly.
// We keep the old method for now - if it should turn out that their changes are permanent,
// we may remove this mixin and access react-router directly again.
var RouterState = _.extend({}, ReactRouter.State, {
    getQuery: function getQuery() {
        // For whatever reason, react-router always returns the same object, which makes comparing
        // the current props with nextProps impossible. As a workaround, we just clone the query object.
        return _.clone(this.context.router.getCurrentQuery());
    },
    getParams: function getParams() {
        return _.clone(this.context.router.getCurrentParams());
    }
});

var Splitter = React.createClass({
    displayName: "Splitter",

    getDefaultProps: function getDefaultProps() {
        return {
            axis: "x"
        };
    },
    getInitialState: function getInitialState() {
        return {
            applied: false,
            startX: false,
            startY: false
        };
    },
    onMouseDown: function onMouseDown(e) {
        this.setState({
            startX: e.pageX,
            startY: e.pageY
        });
        window.addEventListener("mousemove", this.onMouseMove);
        window.addEventListener("mouseup", this.onMouseUp);
        // Occasionally, only a dragEnd event is triggered, but no mouseUp.
        window.addEventListener("dragend", this.onDragEnd);
    },
    onDragEnd: function onDragEnd() {
        this.getDOMNode().style.transform = "";
        window.removeEventListener("dragend", this.onDragEnd);
        window.removeEventListener("mouseup", this.onMouseUp);
        window.removeEventListener("mousemove", this.onMouseMove);
    },
    onMouseUp: function onMouseUp(e) {
        this.onDragEnd();

        var node = this.getDOMNode();
        var prev = node.previousElementSibling;
        var next = node.nextElementSibling;

        var dX = e.pageX - this.state.startX;
        var dY = e.pageY - this.state.startY;
        var flexBasis;
        if (this.props.axis === "x") {
            flexBasis = prev.offsetWidth + dX;
        } else {
            flexBasis = prev.offsetHeight + dY;
        }

        prev.style.flex = "0 0 " + Math.max(0, flexBasis) + "px";
        next.style.flex = "1 1 auto";

        this.setState({
            applied: true
        });
        this.onResize();
    },
    onMouseMove: function onMouseMove(e) {
        var dX = 0,
            dY = 0;
        if (this.props.axis === "x") {
            dX = e.pageX - this.state.startX;
        } else {
            dY = e.pageY - this.state.startY;
        }
        this.getDOMNode().style.transform = "translate(" + dX + "px," + dY + "px)";
    },
    onResize: function onResize() {
        // Trigger a global resize event. This notifies components that employ virtual scrolling
        // that their viewport may have changed.
        window.setTimeout(function () {
            window.dispatchEvent(new CustomEvent("resize"));
        }, 1);
    },
    reset: function reset(willUnmount) {
        if (!this.state.applied) {
            return;
        }
        var node = this.getDOMNode();
        var prev = node.previousElementSibling;
        var next = node.nextElementSibling;

        prev.style.flex = "";
        next.style.flex = "";

        if (!willUnmount) {
            this.setState({
                applied: false
            });
        }
        this.onResize();
    },
    componentWillUnmount: function componentWillUnmount() {
        this.reset(true);
    },
    render: function render() {
        var className = "splitter";
        if (this.props.axis === "x") {
            className += " splitter-x";
        } else {
            className += " splitter-y";
        }
        return React.createElement(
            "div",
            { className: className },
            React.createElement("div", { onMouseDown: this.onMouseDown, draggable: "true" })
        );
    }
});

module.exports = {
    ChildFocus: ChildFocus,
    RouterState: RouterState,
    Navigation: Navigation,
    StickyHeadMixin: StickyHeadMixin,
    AutoScrollMixin: AutoScrollMixin,
    Splitter: Splitter,
    SettingsState: SettingsState
};


},{"lodash":"lodash","react":"react","react-router":"react-router"}],5:[function(require,module,exports){
"use strict";

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

var React = require("react");
var common = require("./common.js");
var utils = require("../utils.js");

var contentToHtml = function contentToHtml(content) {
    return _.escape(content);
};
var nodeToContent = function nodeToContent(node) {
    return node.textContent;
};

/*
 Basic Editor Functionality
 */
var EditorBase = React.createClass({
    displayName: "EditorBase",

    propTypes: {
        content: React.PropTypes.string.isRequired,
        onDone: React.PropTypes.func.isRequired,
        contentToHtml: React.PropTypes.func,
        nodeToContent: React.PropTypes.func, // content === nodeToContent( Node<innerHTML=contentToHtml(content)> )
        onStop: React.PropTypes.func,
        submitOnEnter: React.PropTypes.bool,
        className: React.PropTypes.string,
        tag: React.PropTypes.string
    },
    getDefaultProps: function getDefaultProps() {
        return {
            contentToHtml: contentToHtml,
            nodeToContent: nodeToContent,
            submitOnEnter: true,
            className: "",
            tag: "div"
        };
    },
    getInitialState: function getInitialState() {
        return {
            editable: false
        };
    },
    render: function render() {
        var className = "inline-input " + this.props.className;
        var html = { __html: this.props.contentToHtml(this.props.content) };
        var Tag = this.props.tag;
        return React.createElement(Tag, _extends({}, this.props, {
            tabIndex: "0",
            className: className,
            contentEditable: this.state.editable || undefined, // workaround: use undef instead of false to remove attr
            onFocus: this.onFocus,
            onMouseDown: this.onMouseDown,
            onClick: this.onClick,
            onBlur: this._stop,
            onKeyDown: this.onKeyDown,
            onInput: this.onInput,
            onPaste: this.onPaste,
            dangerouslySetInnerHTML: html
        }));
    },
    onPaste: function onPaste(e) {
        e.preventDefault();
        var content = e.clipboardData.getData("text/plain");
        document.execCommand("insertHTML", false, content);
    },
    onMouseDown: function onMouseDown(e) {
        this._mouseDown = true;
        window.addEventListener("mouseup", this.onMouseUp);
        this.props.onMouseDown && this.props.onMouseDown(e);
    },
    onMouseUp: function onMouseUp() {
        if (this._mouseDown) {
            this._mouseDown = false;
            window.removeEventListener("mouseup", this.onMouseUp);
        }
    },
    onClick: function onClick(e) {
        this.onMouseUp();
        this.onFocus(e);
    },
    onFocus: function onFocus(e) {
        console.log("onFocus", this._mouseDown, this._ignore_events, this.state.editable);
        if (this._mouseDown || this._ignore_events || this.state.editable) {
            return;
        }

        //contenteditable in FireFox is more or less broken.
        // - we need to blur() and then focus(), otherwise the caret is not shown.
        // - blur() + focus() == we need to save the caret position before
        //   Firefox sometimes just doesn't set a caret position => use caretPositionFromPoint
        var sel = window.getSelection();
        var range;
        if (sel.rangeCount > 0) {
            range = sel.getRangeAt(0);
        } else if (document.caretPositionFromPoint && e.clientX && e.clientY) {
            var pos = document.caretPositionFromPoint(e.clientX, e.clientY);
            range = document.createRange();
            range.setStart(pos.offsetNode, pos.offset);
        } else if (document.caretRangeFromPoint && e.clientX && e.clientY) {
            range = document.caretRangeFromPoint(e.clientX, e.clientY);
        } else {
            range = document.createRange();
            range.selectNodeContents(React.findDOMNode(this));
        }

        this._ignore_events = true;
        this.setState({ editable: true }, function () {
            var node = React.findDOMNode(this);
            node.blur();
            node.focus();
            this._ignore_events = false;
            //sel.removeAllRanges();
            //sel.addRange(range);
        });
    },
    stop: function stop() {
        // a stop would cause a blur as a side-effect.
        // but a blur event must trigger a stop as well.
        // to fix this, make stop = blur and do the actual stop in the onBlur handler.
        React.findDOMNode(this).blur();
        this.props.onStop && this.props.onStop();
    },
    _stop: function _stop(e) {
        if (this._ignore_events) {
            return;
        }
        console.log("_stop", _.extend({}, e));
        window.getSelection().removeAllRanges(); //make sure that selection is cleared on blur
        var node = React.findDOMNode(this);
        var content = this.props.nodeToContent(node);
        this.setState({ editable: false });
        this.props.onDone(content);
        this.props.onBlur && this.props.onBlur(e);
    },
    reset: function reset() {
        React.findDOMNode(this).innerHTML = this.props.contentToHtml(this.props.content);
    },
    onKeyDown: function onKeyDown(e) {
        e.stopPropagation();
        switch (e.keyCode) {
            case utils.Key.ESC:
                e.preventDefault();
                this.reset();
                this.stop();
                break;
            case utils.Key.ENTER:
                if (this.props.submitOnEnter && !e.shiftKey) {
                    e.preventDefault();
                    this.stop();
                }
                break;
            default:
                break;
        }
    },
    onInput: function onInput() {
        var node = React.findDOMNode(this);
        var content = this.props.nodeToContent(node);
        this.props.onInput && this.props.onInput(content);
    }
});

/*
 Add Validation to EditorBase
 */
var ValidateEditor = React.createClass({
    displayName: "ValidateEditor",

    propTypes: {
        content: React.PropTypes.string.isRequired,
        onDone: React.PropTypes.func.isRequired,
        onInput: React.PropTypes.func,
        isValid: React.PropTypes.func,
        className: React.PropTypes.string
    },
    getInitialState: function getInitialState() {
        return {
            currentContent: this.props.content
        };
    },
    componentWillReceiveProps: function componentWillReceiveProps() {
        this.setState({ currentContent: this.props.content });
    },
    onInput: function onInput(content) {
        this.setState({ currentContent: content });
        this.props.onInput && this.props.onInput(content);
    },
    render: function render() {
        var className = this.props.className || "";
        if (this.props.isValid) {
            if (this.props.isValid(this.state.currentContent)) {
                className += " has-success";
            } else {
                className += " has-warning";
            }
        }
        return React.createElement(EditorBase, _extends({}, this.props, {
            ref: "editor",
            className: className,
            onDone: this.onDone,
            onInput: this.onInput
        }));
    },
    onDone: function onDone(content) {
        if (this.props.isValid && !this.props.isValid(content)) {
            this.refs.editor.reset();
            content = this.props.content;
        }
        this.props.onDone(content);
    }
});

/*
 Text Editor with mitmweb-specific convenience features
 */
var ValueEditor = React.createClass({
    displayName: "ValueEditor",

    mixins: [common.ChildFocus],
    propTypes: {
        content: React.PropTypes.string.isRequired,
        onDone: React.PropTypes.func.isRequired,
        inline: React.PropTypes.bool
    },
    render: function render() {
        var tag = this.props.inline ? "span" : "div";
        return React.createElement(ValidateEditor, _extends({}, this.props, {
            onStop: this.onStop,
            tag: tag
        }));
    },
    focus: function focus() {
        React.findDOMNode(this).focus();
    },
    onStop: function onStop() {
        this.returnFocus();
    }
});

module.exports = {
    ValueEditor: ValueEditor
};


},{"../utils.js":26,"./common.js":4,"react":"react"}],6:[function(require,module,exports){
"use strict";

var React = require("react");
var common = require("./common.js");
var Query = require("../actions.js").Query;
var VirtualScrollMixin = require("./virtualscroll.js");
var views = require("../store/view.js");
var _ = require("lodash");

var LogMessage = React.createClass({
    displayName: "LogMessage",

    render: function render() {
        var entry = this.props.entry;
        var indicator;
        switch (entry.level) {
            case "web":
                indicator = React.createElement("i", { className: "fa fa-fw fa-html5" });
                break;
            case "debug":
                indicator = React.createElement("i", { className: "fa fa-fw fa-bug" });
                break;
            default:
                indicator = React.createElement("i", { className: "fa fa-fw fa-info" });
        }
        return React.createElement(
            "div",
            null,
            indicator,
            " ",
            entry.message
        );
    },
    shouldComponentUpdate: function shouldComponentUpdate() {
        return false; // log entries are immutable.
    }
});

var EventLogContents = React.createClass({
    displayName: "EventLogContents",

    contextTypes: {
        eventStore: React.PropTypes.object.isRequired
    },
    mixins: [common.AutoScrollMixin, VirtualScrollMixin],
    getInitialState: function getInitialState() {
        var filterFn = function filterFn(entry) {
            return this.props.filter[entry.level];
        };
        var view = new views.StoreView(this.context.eventStore, filterFn.bind(this));
        view.addListener("add", this.onEventLogChange);
        view.addListener("recalculate", this.onEventLogChange);

        return {
            view: view
        };
    },
    componentWillUnmount: function componentWillUnmount() {
        this.state.view.close();
    },
    filter: function filter(entry) {
        return this.props.filter[entry.level];
    },
    onEventLogChange: function onEventLogChange() {
        this.forceUpdate();
    },
    componentWillReceiveProps: function componentWillReceiveProps(nextProps) {
        if (nextProps.filter !== this.props.filter) {
            this.props.filter = nextProps.filter; // Dirty: Make sure that view filter sees the update.
            this.state.view.recalculate();
        }
    },
    getDefaultProps: function getDefaultProps() {
        return {
            rowHeight: 45,
            rowHeightMin: 15,
            placeholderTagName: "div"
        };
    },
    renderRow: function renderRow(elem) {
        return React.createElement(LogMessage, { key: elem.id, entry: elem });
    },
    render: function render() {
        var entries = this.state.view.list;
        var rows = this.renderRows(entries);

        return React.createElement(
            "pre",
            { onScroll: this.onScroll },
            this.getPlaceholderTop(entries.length),
            rows,
            this.getPlaceholderBottom(entries.length)
        );
    }
});

var ToggleFilter = React.createClass({
    displayName: "ToggleFilter",

    toggle: function toggle(e) {
        e.preventDefault();
        return this.props.toggleLevel(this.props.name);
    },
    render: function render() {
        var className = "label ";
        if (this.props.active) {
            className += "label-primary";
        } else {
            className += "label-default";
        }
        return React.createElement(
            "a",
            {
                href: "#",
                className: className,
                onClick: this.toggle },
            this.props.name
        );
    }
});

var EventLog = React.createClass({
    displayName: "EventLog",

    mixins: [common.Navigation],
    getInitialState: function getInitialState() {
        return {
            filter: {
                "debug": false,
                "info": true,
                "web": true
            }
        };
    },
    close: function close() {
        var d = {};
        d[Query.SHOW_EVENTLOG] = undefined;
        this.setQuery(d);
    },
    toggleLevel: function toggleLevel(level) {
        var filter = _.extend({}, this.state.filter);
        filter[level] = !filter[level];
        this.setState({ filter: filter });
    },
    render: function render() {
        return React.createElement(
            "div",
            { className: "eventlog" },
            React.createElement(
                "div",
                null,
                "Eventlog",
                React.createElement(
                    "div",
                    { className: "pull-right" },
                    React.createElement(ToggleFilter, { name: "debug", active: this.state.filter.debug, toggleLevel: this.toggleLevel }),
                    React.createElement(ToggleFilter, { name: "info", active: this.state.filter.info, toggleLevel: this.toggleLevel }),
                    React.createElement(ToggleFilter, { name: "web", active: this.state.filter.web, toggleLevel: this.toggleLevel }),
                    React.createElement("i", { onClick: this.close, className: "fa fa-close" })
                )
            ),
            React.createElement(EventLogContents, { filter: this.state.filter })
        );
    }
});

module.exports = EventLog;


},{"../actions.js":2,"../store/view.js":25,"./common.js":4,"./virtualscroll.js":19,"lodash":"lodash","react":"react"}],7:[function(require,module,exports){
"use strict";

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

var React = require("react");
var RequestUtils = require("../flow/utils.js").RequestUtils;
var ResponseUtils = require("../flow/utils.js").ResponseUtils;
var utils = require("../utils.js");

var TLSColumn = React.createClass({
    displayName: "TLSColumn",

    statics: {
        Title: React.createClass({
            displayName: "Title",

            render: function render() {
                return React.createElement("th", _extends({}, this.props, { className: "col-tls " + (this.props.className || "") }));
            }
        }),
        sortKeyFun: function sortKeyFun(flow) {
            return flow.request.scheme;
        }
    },
    render: function render() {
        var flow = this.props.flow;
        var ssl = flow.request.scheme === "https";
        var classes;
        if (ssl) {
            classes = "col-tls col-tls-https";
        } else {
            classes = "col-tls col-tls-http";
        }
        return React.createElement("td", { className: classes });
    }
});

var IconColumn = React.createClass({
    displayName: "IconColumn",

    statics: {
        Title: React.createClass({
            displayName: "Title",

            render: function render() {
                return React.createElement("th", _extends({}, this.props, { className: "col-icon " + (this.props.className || "") }));
            }
        })
    },
    render: function render() {
        var flow = this.props.flow;

        var icon;
        if (flow.response) {
            var contentType = ResponseUtils.getContentType(flow.response);

            //TODO: We should assign a type to the flow somewhere else.
            if (flow.response.status_code === 304) {
                icon = "resource-icon-not-modified";
            } else if (300 <= flow.response.status_code && flow.response.status_code < 400) {
                icon = "resource-icon-redirect";
            } else if (contentType && contentType.indexOf("image") >= 0) {
                icon = "resource-icon-image";
            } else if (contentType && contentType.indexOf("javascript") >= 0) {
                icon = "resource-icon-js";
            } else if (contentType && contentType.indexOf("css") >= 0) {
                icon = "resource-icon-css";
            } else if (contentType && contentType.indexOf("html") >= 0) {
                icon = "resource-icon-document";
            }
        }
        if (!icon) {
            icon = "resource-icon-plain";
        }

        icon += " resource-icon";
        return React.createElement(
            "td",
            { className: "col-icon" },
            React.createElement("div", { className: icon })
        );
    }
});

var PathColumn = React.createClass({
    displayName: "PathColumn",

    statics: {
        Title: React.createClass({
            displayName: "Title",

            render: function render() {
                return React.createElement(
                    "th",
                    _extends({}, this.props, { className: "col-path " + (this.props.className || "") }),
                    "Path"
                );
            }
        }),
        sortKeyFun: function sortKeyFun(flow) {
            return RequestUtils.pretty_url(flow.request);
        }
    },
    render: function render() {
        var flow = this.props.flow;
        return React.createElement(
            "td",
            { className: "col-path" },
            flow.request.is_replay ? React.createElement("i", { className: "fa fa-fw fa-repeat pull-right" }) : null,
            flow.intercepted ? React.createElement("i", { className: "fa fa-fw fa-pause pull-right" }) : null,
            RequestUtils.pretty_url(flow.request)
        );
    }
});

var MethodColumn = React.createClass({
    displayName: "MethodColumn",

    statics: {
        Title: React.createClass({
            displayName: "Title",

            render: function render() {
                return React.createElement(
                    "th",
                    _extends({}, this.props, { className: "col-method " + (this.props.className || "") }),
                    "Method"
                );
            }
        }),
        sortKeyFun: function sortKeyFun(flow) {
            return flow.request.method;
        }
    },
    render: function render() {
        var flow = this.props.flow;
        return React.createElement(
            "td",
            { className: "col-method" },
            flow.request.method
        );
    }
});

var StatusColumn = React.createClass({
    displayName: "StatusColumn",

    statics: {
        Title: React.createClass({
            displayName: "Title",

            render: function render() {
                return React.createElement(
                    "th",
                    _extends({}, this.props, { className: "col-status " + (this.props.className || "") }),
                    "Status"
                );
            }
        }),
        sortKeyFun: function sortKeyFun(flow) {
            return flow.response ? flow.response.status_code : undefined;
        }
    },
    render: function render() {
        var flow = this.props.flow;
        var status;
        if (flow.response) {
            status = flow.response.status_code;
        } else {
            status = null;
        }
        return React.createElement(
            "td",
            { className: "col-status" },
            status
        );
    }
});

var SizeColumn = React.createClass({
    displayName: "SizeColumn",

    statics: {
        Title: React.createClass({
            displayName: "Title",

            render: function render() {
                return React.createElement(
                    "th",
                    _extends({}, this.props, { className: "col-size " + (this.props.className || "") }),
                    "Size"
                );
            }
        }),
        sortKeyFun: function sortKeyFun(flow) {
            var total = flow.request.contentLength;
            if (flow.response) {
                total += flow.response.contentLength || 0;
            }
            return total;
        }
    },
    render: function render() {
        var flow = this.props.flow;

        var total = flow.request.contentLength;
        if (flow.response) {
            total += flow.response.contentLength || 0;
        }
        var size = utils.formatSize(total);
        return React.createElement(
            "td",
            { className: "col-size" },
            size
        );
    }
});

var TimeColumn = React.createClass({
    displayName: "TimeColumn",

    statics: {
        Title: React.createClass({
            displayName: "Title",

            render: function render() {
                return React.createElement(
                    "th",
                    _extends({}, this.props, { className: "col-time " + (this.props.className || "") }),
                    "Time"
                );
            }
        }),
        sortKeyFun: function sortKeyFun(flow) {
            if (flow.response) {
                return flow.response.timestamp_end - flow.request.timestamp_start;
            }
        }
    },
    render: function render() {
        var flow = this.props.flow;
        var time;
        if (flow.response) {
            time = utils.formatTimeDelta(1000 * (flow.response.timestamp_end - flow.request.timestamp_start));
        } else {
            time = "...";
        }
        return React.createElement(
            "td",
            { className: "col-time" },
            time
        );
    }
});

var all_columns = [TLSColumn, IconColumn, PathColumn, MethodColumn, StatusColumn, SizeColumn, TimeColumn];

module.exports = all_columns;


},{"../flow/utils.js":23,"../utils.js":26,"react":"react"}],8:[function(require,module,exports){
"use strict";

var React = require("react");
var common = require("./common.js");
var utils = require("../utils.js");
var _ = require("lodash");

var VirtualScrollMixin = require("./virtualscroll.js");
var flowtable_columns = require("./flowtable-columns.js");

var FlowRow = React.createClass({
    displayName: "FlowRow",

    render: function render() {
        var flow = this.props.flow;
        var columns = this.props.columns.map((function (Column) {
            return React.createElement(Column, { key: Column.displayName, flow: flow });
        }).bind(this));
        var className = "";
        if (this.props.selected) {
            className += " selected";
        }
        if (this.props.highlighted) {
            className += " highlighted";
        }
        if (flow.intercepted) {
            className += " intercepted";
        }
        if (flow.request) {
            className += " has-request";
        }
        if (flow.response) {
            className += " has-response";
        }

        return React.createElement(
            "tr",
            { className: className, onClick: this.props.selectFlow.bind(null, flow) },
            columns
        );
    },
    shouldComponentUpdate: function shouldComponentUpdate(nextProps) {
        return true;
        // Further optimization could be done here
        // by calling forceUpdate on flow updates, selection changes and column changes.
        //return (
        //(this.props.columns.length !== nextProps.columns.length) ||
        //(this.props.selected !== nextProps.selected)
        //);
    }
});

var FlowTableHead = React.createClass({
    displayName: "FlowTableHead",

    getInitialState: function getInitialState() {
        return {
            sortColumn: undefined,
            sortDesc: false
        };
    },
    onClick: function onClick(Column) {
        var sortDesc = this.state.sortDesc;
        var hasSort = Column.sortKeyFun;
        if (Column === this.state.sortColumn) {
            sortDesc = !sortDesc;
            this.setState({
                sortDesc: sortDesc
            });
        } else {
            this.setState({
                sortColumn: hasSort && Column,
                sortDesc: false
            });
        }
        var sortKeyFun;
        if (!sortDesc) {
            sortKeyFun = Column.sortKeyFun;
        } else {
            sortKeyFun = hasSort && function () {
                var k = Column.sortKeyFun.apply(this, arguments);
                if (_.isString(k)) {
                    return utils.reverseString("" + k);
                } else {
                    return -k;
                }
            };
        }
        this.props.setSortKeyFun(sortKeyFun);
    },
    render: function render() {
        var columns = this.props.columns.map((function (Column) {
            var onClick = this.onClick.bind(this, Column);
            var className;
            if (this.state.sortColumn === Column) {
                if (this.state.sortDesc) {
                    className = "sort-desc";
                } else {
                    className = "sort-asc";
                }
            }
            return React.createElement(Column.Title, {
                key: Column.displayName,
                onClick: onClick,
                className: className });
        }).bind(this));
        return React.createElement(
            "thead",
            null,
            React.createElement(
                "tr",
                null,
                columns
            )
        );
    }
});

var ROW_HEIGHT = 32;

var FlowTable = React.createClass({
    displayName: "FlowTable",

    mixins: [common.StickyHeadMixin, common.AutoScrollMixin, VirtualScrollMixin],
    contextTypes: {
        view: React.PropTypes.object.isRequired
    },
    getInitialState: function getInitialState() {
        return {
            columns: flowtable_columns
        };
    },
    componentWillMount: function componentWillMount() {
        this.context.view.addListener("add", this.onChange);
        this.context.view.addListener("update", this.onChange);
        this.context.view.addListener("remove", this.onChange);
        this.context.view.addListener("recalculate", this.onChange);
    },
    componentWillUnmount: function componentWillUnmount() {
        this.context.view.removeListener("add", this.onChange);
        this.context.view.removeListener("update", this.onChange);
        this.context.view.removeListener("remove", this.onChange);
        this.context.view.removeListener("recalculate", this.onChange);
    },
    getDefaultProps: function getDefaultProps() {
        return {
            rowHeight: ROW_HEIGHT
        };
    },
    onScrollFlowTable: function onScrollFlowTable() {
        this.adjustHead();
        this.onScroll();
    },
    onChange: function onChange() {
        this.forceUpdate();
    },
    scrollIntoView: function scrollIntoView(flow) {
        this.scrollRowIntoView(this.context.view.index(flow), this.refs.body.getDOMNode().offsetTop);
    },
    renderRow: function renderRow(flow) {
        var selected = flow === this.props.selected;
        var highlighted = this.context.view._highlight && this.context.view._highlight[flow.id];

        return React.createElement(FlowRow, { key: flow.id,
            ref: flow.id,
            flow: flow,
            columns: this.state.columns,
            selected: selected,
            highlighted: highlighted,
            selectFlow: this.props.selectFlow
        });
    },
    render: function render() {
        var flows = this.context.view.list;
        var rows = this.renderRows(flows);

        return React.createElement(
            "div",
            { className: "flow-table", onScroll: this.onScrollFlowTable },
            React.createElement(
                "table",
                null,
                React.createElement(FlowTableHead, { ref: "head",
                    columns: this.state.columns,
                    setSortKeyFun: this.props.setSortKeyFun }),
                React.createElement(
                    "tbody",
                    { ref: "body" },
                    this.getPlaceholderTop(flows.length),
                    rows,
                    this.getPlaceholderBottom(flows.length)
                )
            )
        );
    }
});

module.exports = FlowTable;


},{"../utils.js":26,"./common.js":4,"./flowtable-columns.js":7,"./virtualscroll.js":19,"lodash":"lodash","react":"react"}],9:[function(require,module,exports){
"use strict";

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

var React = require("react");
var _ = require("lodash");

var MessageUtils = require("../../flow/utils.js").MessageUtils;
var utils = require("../../utils.js");

var image_regex = /^image\/(png|jpe?g|gif|vnc.microsoft.icon|x-icon)$/i;
var ViewImage = React.createClass({
    displayName: "ViewImage",

    statics: {
        matches: function matches(message) {
            return image_regex.test(MessageUtils.getContentType(message));
        }
    },
    render: function render() {
        var url = MessageUtils.getContentURL(this.props.flow, this.props.message);
        return React.createElement(
            "div",
            { className: "flowview-image" },
            React.createElement("img", { src: url, alt: "preview", className: "img-thumbnail" })
        );
    }
});

var RawMixin = {
    getInitialState: function getInitialState() {
        return {
            content: undefined,
            request: undefined
        };
    },
    requestContent: function requestContent(nextProps) {
        if (this.state.request) {
            this.state.request.abort();
        }
        var request = MessageUtils.getContent(nextProps.flow, nextProps.message);
        this.setState({
            content: undefined,
            request: request
        });
        request.done((function (data) {
            this.setState({ content: data });
        }).bind(this)).fail((function (jqXHR, textStatus, errorThrown) {
            if (textStatus === "abort") {
                return;
            }
            this.setState({ content: "AJAX Error: " + textStatus + "\r\n" + errorThrown });
        }).bind(this)).always((function () {
            this.setState({ request: undefined });
        }).bind(this));
    },
    componentWillMount: function componentWillMount() {
        this.requestContent(this.props);
    },
    componentWillReceiveProps: function componentWillReceiveProps(nextProps) {
        if (nextProps.message !== this.props.message) {
            this.requestContent(nextProps);
        }
    },
    componentWillUnmount: function componentWillUnmount() {
        if (this.state.request) {
            this.state.request.abort();
        }
    },
    render: function render() {
        if (!this.state.content) {
            return React.createElement(
                "div",
                { className: "text-center" },
                React.createElement("i", { className: "fa fa-spinner fa-spin" })
            );
        }
        return this.renderContent();
    }
};

var ViewRaw = React.createClass({
    displayName: "ViewRaw",

    mixins: [RawMixin],
    statics: {
        matches: function matches(message) {
            return true;
        }
    },
    renderContent: function renderContent() {
        return React.createElement(
            "pre",
            null,
            this.state.content
        );
    }
});

var json_regex = /^application\/json$/i;
var ViewJSON = React.createClass({
    displayName: "ViewJSON",

    mixins: [RawMixin],
    statics: {
        matches: function matches(message) {
            return json_regex.test(MessageUtils.getContentType(message));
        }
    },
    renderContent: function renderContent() {
        var json = this.state.content;
        try {
            json = JSON.stringify(JSON.parse(json), null, 2);
        } catch (e) {}
        return React.createElement(
            "pre",
            null,
            json
        );
    }
});

var ViewAuto = React.createClass({
    displayName: "ViewAuto",

    statics: {
        matches: function matches() {
            return false; // don't match itself
        },
        findView: function findView(message) {
            for (var i = 0; i < all.length; i++) {
                if (all[i].matches(message)) {
                    return all[i];
                }
            }
            return all[all.length - 1];
        }
    },
    render: function render() {
        var View = ViewAuto.findView(this.props.message);
        return React.createElement(View, this.props);
    }
});

var all = [ViewAuto, ViewImage, ViewJSON, ViewRaw];

var ContentEmpty = React.createClass({
    displayName: "ContentEmpty",

    render: function render() {
        var message_name = this.props.flow.request === this.props.message ? "request" : "response";
        return React.createElement(
            "div",
            { className: "alert alert-info" },
            "No ",
            message_name,
            " content."
        );
    }
});

var ContentMissing = React.createClass({
    displayName: "ContentMissing",

    render: function render() {
        var message_name = this.props.flow.request === this.props.message ? "Request" : "Response";
        return React.createElement(
            "div",
            { className: "alert alert-info" },
            message_name,
            " content missing."
        );
    }
});

var TooLarge = React.createClass({
    displayName: "TooLarge",

    statics: {
        isTooLarge: function isTooLarge(message) {
            var max_mb = ViewImage.matches(message) ? 10 : 0.2;
            return message.contentLength > 1024 * 1024 * max_mb;
        }
    },
    render: function render() {
        var size = utils.formatSize(this.props.message.contentLength);
        return React.createElement(
            "div",
            { className: "alert alert-warning" },
            React.createElement(
                "button",
                { onClick: this.props.onClick, className: "btn btn-xs btn-warning pull-right" },
                "Display anyway"
            ),
            size,
            " content size."
        );
    }
});

var ViewSelector = React.createClass({
    displayName: "ViewSelector",

    render: function render() {
        var views = [];
        for (var i = 0; i < all.length; i++) {
            var view = all[i];
            var className = "btn btn-default";
            if (view === this.props.active) {
                className += " active";
            }
            var text;
            if (view === ViewAuto) {
                text = "auto: " + ViewAuto.findView(this.props.message).displayName.toLowerCase().replace("view", "");
            } else {
                text = view.displayName.toLowerCase().replace("view", "");
            }
            views.push(React.createElement(
                "button",
                {
                    key: view.displayName,
                    onClick: this.props.selectView.bind(null, view),
                    className: className },
                text
            ));
        }

        return React.createElement(
            "div",
            { className: "view-selector btn-group btn-group-xs" },
            views
        );
    }
});

var ContentView = React.createClass({
    displayName: "ContentView",

    getInitialState: function getInitialState() {
        return {
            displayLarge: false,
            View: ViewAuto
        };
    },
    propTypes: {
        // It may seem a bit weird at the first glance:
        // Every view takes the flow and the message as props, e.g.
        // <Auto flow={flow} message={flow.request}/>
        flow: React.PropTypes.object.isRequired,
        message: React.PropTypes.object.isRequired
    },
    selectView: function selectView(view) {
        this.setState({
            View: view
        });
    },
    displayLarge: function displayLarge() {
        this.setState({ displayLarge: true });
    },
    componentWillReceiveProps: function componentWillReceiveProps(nextProps) {
        if (nextProps.message !== this.props.message) {
            this.setState(this.getInitialState());
        }
    },
    render: function render() {
        var message = this.props.message;
        if (message.contentLength === 0) {
            return React.createElement(ContentEmpty, this.props);
        } else if (message.contentLength === null) {
            return React.createElement(ContentMissing, this.props);
        } else if (!this.state.displayLarge && TooLarge.isTooLarge(message)) {
            return React.createElement(TooLarge, _extends({}, this.props, { onClick: this.displayLarge }));
        }

        var downloadUrl = MessageUtils.getContentURL(this.props.flow, message);

        return React.createElement(
            "div",
            null,
            React.createElement(this.state.View, this.props),
            React.createElement(
                "div",
                { className: "view-options text-center" },
                React.createElement(ViewSelector, { selectView: this.selectView, active: this.state.View, message: message }),
                " ",
                React.createElement(
                    "a",
                    { className: "btn btn-default btn-xs", href: downloadUrl },
                    React.createElement("i", { className: "fa fa-download" })
                )
            )
        );
    }
});

module.exports = ContentView;


},{"../../flow/utils.js":23,"../../utils.js":26,"lodash":"lodash","react":"react"}],10:[function(require,module,exports){
"use strict";

var React = require("react");
var _ = require("lodash");

var utils = require("../../utils.js");

var TimeStamp = React.createClass({
    displayName: "TimeStamp",

    render: function render() {

        if (!this.props.t) {
            //should be return null, but that triggers a React bug.
            return React.createElement("tr", null);
        }

        var ts = utils.formatTimeStamp(this.props.t);

        var delta;
        if (this.props.deltaTo) {
            delta = utils.formatTimeDelta(1000 * (this.props.t - this.props.deltaTo));
            delta = React.createElement(
                "span",
                { className: "text-muted" },
                "(" + delta + ")"
            );
        } else {
            delta = null;
        }

        return React.createElement(
            "tr",
            null,
            React.createElement(
                "td",
                null,
                this.props.title + ":"
            ),
            React.createElement(
                "td",
                null,
                ts,
                " ",
                delta
            )
        );
    }
});

var ConnectionInfo = React.createClass({
    displayName: "ConnectionInfo",

    render: function render() {
        var conn = this.props.conn;
        var address = conn.address.address.join(":");

        var sni = React.createElement("tr", { key: "sni" }); //should be null, but that triggers a React bug.
        if (conn.sni) {
            sni = React.createElement(
                "tr",
                { key: "sni" },
                React.createElement(
                    "td",
                    null,
                    React.createElement(
                        "abbr",
                        { title: "TLS Server Name Indication" },
                        "TLS SNI:"
                    )
                ),
                React.createElement(
                    "td",
                    null,
                    conn.sni
                )
            );
        }
        return React.createElement(
            "table",
            { className: "connection-table" },
            React.createElement(
                "tbody",
                null,
                React.createElement(
                    "tr",
                    { key: "address" },
                    React.createElement(
                        "td",
                        null,
                        "Address:"
                    ),
                    React.createElement(
                        "td",
                        null,
                        address
                    )
                ),
                sni
            )
        );
    }
});

var CertificateInfo = React.createClass({
    displayName: "CertificateInfo",

    render: function render() {
        //TODO: We should fetch human-readable certificate representation
        // from the server
        var flow = this.props.flow;
        var client_conn = flow.client_conn;
        var server_conn = flow.server_conn;

        var preStyle = { maxHeight: 100 };
        return React.createElement(
            "div",
            null,
            client_conn.cert ? React.createElement(
                "h4",
                null,
                "Client Certificate"
            ) : null,
            client_conn.cert ? React.createElement(
                "pre",
                { style: preStyle },
                client_conn.cert
            ) : null,
            server_conn.cert ? React.createElement(
                "h4",
                null,
                "Server Certificate"
            ) : null,
            server_conn.cert ? React.createElement(
                "pre",
                { style: preStyle },
                server_conn.cert
            ) : null
        );
    }
});

var Timing = React.createClass({
    displayName: "Timing",

    render: function render() {
        var flow = this.props.flow;
        var sc = flow.server_conn;
        var cc = flow.client_conn;
        var req = flow.request;
        var resp = flow.response;

        var timestamps = [{
            title: "Server conn. initiated",
            t: sc.timestamp_start,
            deltaTo: req.timestamp_start
        }, {
            title: "Server conn. TCP handshake",
            t: sc.timestamp_tcp_setup,
            deltaTo: req.timestamp_start
        }, {
            title: "Server conn. SSL handshake",
            t: sc.timestamp_ssl_setup,
            deltaTo: req.timestamp_start
        }, {
            title: "Client conn. established",
            t: cc.timestamp_start,
            deltaTo: req.timestamp_start
        }, {
            title: "Client conn. SSL handshake",
            t: cc.timestamp_ssl_setup,
            deltaTo: req.timestamp_start
        }, {
            title: "First request byte",
            t: req.timestamp_start
        }, {
            title: "Request complete",
            t: req.timestamp_end,
            deltaTo: req.timestamp_start
        }];

        if (flow.response) {
            timestamps.push({
                title: "First response byte",
                t: resp.timestamp_start,
                deltaTo: req.timestamp_start
            }, {
                title: "Response complete",
                t: resp.timestamp_end,
                deltaTo: req.timestamp_start
            });
        }

        //Add unique key for each row.
        timestamps.forEach(function (e) {
            e.key = e.title;
        });

        timestamps = _.sortBy(timestamps, 't');

        var rows = timestamps.map(function (e) {
            return React.createElement(TimeStamp, e);
        });

        return React.createElement(
            "div",
            null,
            React.createElement(
                "h4",
                null,
                "Timing"
            ),
            React.createElement(
                "table",
                { className: "timing-table" },
                React.createElement(
                    "tbody",
                    null,
                    rows
                )
            )
        );
    }
});

var Details = React.createClass({
    displayName: "Details",

    render: function render() {
        var flow = this.props.flow;
        var client_conn = flow.client_conn;
        var server_conn = flow.server_conn;
        return React.createElement(
            "section",
            null,
            React.createElement(
                "h4",
                null,
                "Client Connection"
            ),
            React.createElement(ConnectionInfo, { conn: client_conn }),
            React.createElement(
                "h4",
                null,
                "Server Connection"
            ),
            React.createElement(ConnectionInfo, { conn: server_conn }),
            React.createElement(CertificateInfo, { flow: flow }),
            React.createElement(Timing, { flow: flow })
        );
    }
});

module.exports = Details;


},{"../../utils.js":26,"lodash":"lodash","react":"react"}],11:[function(require,module,exports){
"use strict";

var React = require("react");
var _ = require("lodash");

var common = require("../common.js");
var Nav = require("./nav.js");
var Messages = require("./messages.js");
var Details = require("./details.js");
var Prompt = require("../prompt.js");

var allTabs = {
    request: Messages.Request,
    response: Messages.Response,
    error: Messages.Error,
    details: Details
};

var FlowView = React.createClass({
    displayName: "FlowView",

    mixins: [common.StickyHeadMixin, common.Navigation, common.RouterState],
    getInitialState: function getInitialState() {
        return {
            prompt: false
        };
    },
    getTabs: function getTabs(flow) {
        var tabs = [];
        ["request", "response", "error"].forEach(function (e) {
            if (flow[e]) {
                tabs.push(e);
            }
        });
        tabs.push("details");
        return tabs;
    },
    nextTab: function nextTab(i) {
        var tabs = this.getTabs(this.props.flow);
        var currentIndex = tabs.indexOf(this.getActive());
        // JS modulo operator doesn't correct negative numbers, make sure that we are positive.
        var nextIndex = (currentIndex + i + tabs.length) % tabs.length;
        this.selectTab(tabs[nextIndex]);
    },
    selectTab: function selectTab(panel) {
        this.replaceWith("flow", {
            flowId: this.getParams().flowId,
            detailTab: panel
        });
    },
    getActive: function getActive() {
        return this.getParams().detailTab;
    },
    promptEdit: function promptEdit() {
        var options;
        switch (this.getActive()) {
            case "request":
                options = ["method", "url", { text: "http version", key: "v" }, "header"
                /*, "content"*/];
                break;
            case "response":
                options = [{ text: "http version", key: "v" }, "code", "message", "header"
                /*, "content"*/];
                break;
            case "details":
                return;
            default:
                throw "Unknown tab for edit: " + this.getActive();
        }

        this.setState({
            prompt: {
                done: (function (k) {
                    this.setState({ prompt: false });
                    if (k) {
                        this.refs.tab.edit(k);
                    }
                }).bind(this),
                options: options
            }
        });
    },
    render: function render() {
        var flow = this.props.flow;
        var tabs = this.getTabs(flow);
        var active = this.getActive();

        if (!_.contains(tabs, active)) {
            if (active === "response" && flow.error) {
                active = "error";
            } else if (active === "error" && flow.response) {
                active = "response";
            } else {
                active = tabs[0];
            }
            this.selectTab(active);
        }

        var prompt = null;
        if (this.state.prompt) {
            prompt = React.createElement(Prompt, this.state.prompt);
        }

        var Tab = allTabs[active];
        return React.createElement(
            "div",
            { className: "flow-detail", onScroll: this.adjustHead },
            React.createElement(Nav, { ref: "head",
                flow: flow,
                tabs: tabs,
                active: active,
                selectTab: this.selectTab }),
            React.createElement(Tab, { ref: "tab", flow: flow }),
            prompt
        );
    }
});

module.exports = FlowView;


},{"../common.js":4,"../prompt.js":17,"./details.js":10,"./messages.js":12,"./nav.js":13,"lodash":"lodash","react":"react"}],12:[function(require,module,exports){
"use strict";

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

var React = require("react");
var _ = require("lodash");

var common = require("../common.js");
var actions = require("../../actions.js");
var flowutils = require("../../flow/utils.js");
var utils = require("../../utils.js");
var ContentView = require("./contentview.js");
var ValueEditor = require("../editor.js").ValueEditor;

var Headers = React.createClass({
    displayName: "Headers",

    propTypes: {
        onChange: React.PropTypes.func.isRequired,
        message: React.PropTypes.object.isRequired
    },
    onChange: function onChange(row, col, val) {
        var nextHeaders = _.cloneDeep(this.props.message.headers);
        nextHeaders[row][col] = val;
        if (!nextHeaders[row][0] && !nextHeaders[row][1]) {
            // do not delete last row
            if (nextHeaders.length === 1) {
                nextHeaders[0][0] = "Name";
                nextHeaders[0][1] = "Value";
            } else {
                nextHeaders.splice(row, 1);
                // manually move selection target if this has been the last row.
                if (row === nextHeaders.length) {
                    this._nextSel = row - 1 + "-value";
                }
            }
        }
        this.props.onChange(nextHeaders);
    },
    edit: function edit() {
        this.refs["0-key"].focus();
    },
    onTab: function onTab(row, col, e) {
        var headers = this.props.message.headers;
        if (row === headers.length - 1 && col === 1) {
            e.preventDefault();

            var nextHeaders = _.cloneDeep(this.props.message.headers);
            nextHeaders.push(["Name", "Value"]);
            this.props.onChange(nextHeaders);
            this._nextSel = row + 1 + "-key";
        }
    },
    componentDidUpdate: function componentDidUpdate() {
        if (this._nextSel && this.refs[this._nextSel]) {
            this.refs[this._nextSel].focus();
            this._nextSel = undefined;
        }
    },
    onRemove: function onRemove(row, col, e) {
        if (col === 1) {
            e.preventDefault();
            this.refs[row + "-key"].focus();
        } else if (row > 0) {
            e.preventDefault();
            this.refs[row - 1 + "-value"].focus();
        }
    },
    render: function render() {

        var rows = this.props.message.headers.map((function (header, i) {

            var kEdit = React.createElement(HeaderEditor, {
                ref: i + "-key",
                content: header[0],
                onDone: this.onChange.bind(null, i, 0),
                onRemove: this.onRemove.bind(null, i, 0),
                onTab: this.onTab.bind(null, i, 0) });
            var vEdit = React.createElement(HeaderEditor, {
                ref: i + "-value",
                content: header[1],
                onDone: this.onChange.bind(null, i, 1),
                onRemove: this.onRemove.bind(null, i, 1),
                onTab: this.onTab.bind(null, i, 1) });
            return React.createElement(
                "tr",
                { key: i },
                React.createElement(
                    "td",
                    { className: "header-name" },
                    kEdit,
                    ":"
                ),
                React.createElement(
                    "td",
                    { className: "header-value" },
                    vEdit
                )
            );
        }).bind(this));
        return React.createElement(
            "table",
            { className: "header-table" },
            React.createElement(
                "tbody",
                null,
                rows
            )
        );
    }
});

var HeaderEditor = React.createClass({
    displayName: "HeaderEditor",

    render: function render() {
        return React.createElement(ValueEditor, _extends({ ref: "input" }, this.props, { onKeyDown: this.onKeyDown, inline: true }));
    },
    focus: function focus() {
        this.getDOMNode().focus();
    },
    onKeyDown: function onKeyDown(e) {
        switch (e.keyCode) {
            case utils.Key.BACKSPACE:
                var s = window.getSelection().getRangeAt(0);
                if (s.startOffset === 0 && s.endOffset === 0) {
                    this.props.onRemove(e);
                }
                break;
            case utils.Key.TAB:
                if (!e.shiftKey) {
                    this.props.onTab(e);
                }
                break;
        }
    }
});

var RequestLine = React.createClass({
    displayName: "RequestLine",

    render: function render() {
        var flow = this.props.flow;
        var url = flowutils.RequestUtils.pretty_url(flow.request);
        var httpver = flow.request.http_version;

        return React.createElement(
            "div",
            { className: "first-line request-line" },
            React.createElement(ValueEditor, {
                ref: "method",
                content: flow.request.method,
                onDone: this.onMethodChange,
                inline: true }),
            " ",
            React.createElement(ValueEditor, {
                ref: "url",
                content: url,
                onDone: this.onUrlChange,
                isValid: this.isValidUrl,
                inline: true }),
            " ",
            React.createElement(ValueEditor, {
                ref: "httpVersion",
                content: httpver,
                onDone: this.onHttpVersionChange,
                isValid: flowutils.isValidHttpVersion,
                inline: true })
        );
    },
    isValidUrl: function isValidUrl(url) {
        var u = flowutils.parseUrl(url);
        return !!u.host;
    },
    onMethodChange: function onMethodChange(nextMethod) {
        actions.FlowActions.update(this.props.flow, { request: { method: nextMethod } });
    },
    onUrlChange: function onUrlChange(nextUrl) {
        var props = flowutils.parseUrl(nextUrl);
        props.path = props.path || "";
        actions.FlowActions.update(this.props.flow, { request: props });
    },
    onHttpVersionChange: function onHttpVersionChange(nextVer) {
        var ver = flowutils.parseHttpVersion(nextVer);
        actions.FlowActions.update(this.props.flow, { request: { http_version: ver } });
    }
});

var ResponseLine = React.createClass({
    displayName: "ResponseLine",

    render: function render() {
        var flow = this.props.flow;
        var httpver = flow.response.http_version;
        return React.createElement(
            "div",
            { className: "first-line response-line" },
            React.createElement(ValueEditor, {
                ref: "httpVersion",
                content: httpver,
                onDone: this.onHttpVersionChange,
                isValid: flowutils.isValidHttpVersion,
                inline: true }),
            " ",
            React.createElement(ValueEditor, {
                ref: "code",
                content: flow.response.status_code + "",
                onDone: this.onCodeChange,
                isValid: this.isValidCode,
                inline: true }),
            " ",
            React.createElement(ValueEditor, {
                ref: "msg",
                content: flow.response.msg,
                onDone: this.onMsgChange,
                inline: true })
        );
    },
    isValidCode: function isValidCode(code) {
        return (/^\d+$/.test(code)
        );
    },
    onHttpVersionChange: function onHttpVersionChange(nextVer) {
        var ver = flowutils.parseHttpVersion(nextVer);
        actions.FlowActions.update(this.props.flow, { response: { http_version: ver } });
    },
    onMsgChange: function onMsgChange(nextMsg) {
        actions.FlowActions.update(this.props.flow, { response: { msg: nextMsg } });
    },
    onCodeChange: function onCodeChange(nextCode) {
        nextCode = parseInt(nextCode);
        actions.FlowActions.update(this.props.flow, { response: { code: nextCode } });
    }
});

var Request = React.createClass({
    displayName: "Request",

    render: function render() {
        var flow = this.props.flow;
        return React.createElement(
            "section",
            { className: "request" },
            React.createElement(RequestLine, { ref: "requestLine", flow: flow }),
            React.createElement(Headers, { ref: "headers", message: flow.request, onChange: this.onHeaderChange }),
            React.createElement("hr", null),
            React.createElement(ContentView, { flow: flow, message: flow.request })
        );
    },
    edit: function edit(k) {
        switch (k) {
            case "m":
                this.refs.requestLine.refs.method.focus();
                break;
            case "u":
                this.refs.requestLine.refs.url.focus();
                break;
            case "v":
                this.refs.requestLine.refs.httpVersion.focus();
                break;
            case "h":
                this.refs.headers.edit();
                break;
            default:
                throw "Unimplemented: " + k;
        }
    },
    onHeaderChange: function onHeaderChange(nextHeaders) {
        actions.FlowActions.update(this.props.flow, {
            request: {
                headers: nextHeaders
            }
        });
    }
});

var Response = React.createClass({
    displayName: "Response",

    render: function render() {
        var flow = this.props.flow;
        return React.createElement(
            "section",
            { className: "response" },
            React.createElement(ResponseLine, { ref: "responseLine", flow: flow }),
            React.createElement(Headers, { ref: "headers", message: flow.response, onChange: this.onHeaderChange }),
            React.createElement("hr", null),
            React.createElement(ContentView, { flow: flow, message: flow.response })
        );
    },
    edit: function edit(k) {
        switch (k) {
            case "c":
                this.refs.responseLine.refs.status_code.focus();
                break;
            case "m":
                this.refs.responseLine.refs.msg.focus();
                break;
            case "v":
                this.refs.responseLine.refs.httpVersion.focus();
                break;
            case "h":
                this.refs.headers.edit();
                break;
            default:
                throw "Unimplemented: " + k;
        }
    },
    onHeaderChange: function onHeaderChange(nextHeaders) {
        actions.FlowActions.update(this.props.flow, {
            response: {
                headers: nextHeaders
            }
        });
    }
});

var Error = React.createClass({
    displayName: "Error",

    render: function render() {
        var flow = this.props.flow;
        return React.createElement(
            "section",
            null,
            React.createElement(
                "div",
                { className: "alert alert-warning" },
                flow.error.msg,
                React.createElement(
                    "div",
                    null,
                    React.createElement(
                        "small",
                        null,
                        utils.formatTimeStamp(flow.error.timestamp)
                    )
                )
            )
        );
    }
});

module.exports = {
    Request: Request,
    Response: Response,
    Error: Error
};
/*<ResponseLine flow={flow}/>*/ /*<RequestLine flow={flow}/>*/


},{"../../actions.js":2,"../../flow/utils.js":23,"../../utils.js":26,"../common.js":4,"../editor.js":5,"./contentview.js":9,"lodash":"lodash","react":"react"}],13:[function(require,module,exports){
"use strict";

var React = require("react");

var actions = require("../../actions.js");

var NavAction = React.createClass({
    displayName: "NavAction",

    onClick: function onClick(e) {
        e.preventDefault();
        this.props.onClick();
    },
    render: function render() {
        return React.createElement(
            "a",
            { title: this.props.title,
                href: "#",
                className: "nav-action",
                onClick: this.onClick },
            React.createElement("i", { className: "fa fa-fw " + this.props.icon })
        );
    }
});

var Nav = React.createClass({
    displayName: "Nav",

    render: function render() {
        var flow = this.props.flow;

        var tabs = this.props.tabs.map((function (e) {
            var str = e.charAt(0).toUpperCase() + e.slice(1);
            var className = this.props.active === e ? "active" : "";
            var onClick = (function (event) {
                this.props.selectTab(e);
                event.preventDefault();
            }).bind(this);
            return React.createElement(
                "a",
                { key: e,
                    href: "#",
                    className: className,
                    onClick: onClick },
                str
            );
        }).bind(this));

        var acceptButton = null;
        if (flow.intercepted) {
            acceptButton = React.createElement(NavAction, { title: "[a]ccept intercepted flow", icon: "fa-play", onClick: actions.FlowActions.accept.bind(null, flow) });
        }
        var revertButton = null;
        if (flow.modified) {
            revertButton = React.createElement(NavAction, { title: "revert changes to flow [V]", icon: "fa-history", onClick: actions.FlowActions.revert.bind(null, flow) });
        }

        return React.createElement(
            "nav",
            { ref: "head", className: "nav-tabs nav-tabs-sm" },
            tabs,
            React.createElement(NavAction, { title: "[d]elete flow", icon: "fa-trash", onClick: actions.FlowActions["delete"].bind(null, flow) }),
            React.createElement(NavAction, { title: "[D]uplicate flow", icon: "fa-copy", onClick: actions.FlowActions.duplicate.bind(null, flow) }),
            React.createElement(NavAction, { disabled: true, title: "[r]eplay flow", icon: "fa-repeat", onClick: actions.FlowActions.replay.bind(null, flow) }),
            acceptButton,
            revertButton
        );
    }
});

module.exports = Nav;


},{"../../actions.js":2,"react":"react"}],14:[function(require,module,exports){
"use strict";

var React = require("react");
var common = require("./common.js");

var Footer = React.createClass({
    displayName: "Footer",

    mixins: [common.SettingsState],
    render: function render() {
        var mode = this.state.settings.mode;
        var intercept = this.state.settings.intercept;
        return React.createElement(
            "footer",
            null,
            mode && mode != "regular" ? React.createElement(
                "span",
                { className: "label label-success" },
                mode,
                " mode"
            ) : null,
            " ",
            intercept ? React.createElement(
                "span",
                { className: "label label-success" },
                "Intercept: ",
                intercept
            ) : null
        );
    }
});

module.exports = Footer;


},{"./common.js":4,"react":"react"}],15:[function(require,module,exports){
"use strict";

var React = require("react");
var $ = require("jquery");

var Filt = require("../filt/filt.js");
var utils = require("../utils.js");
var common = require("./common.js");
var actions = require("../actions.js");
var Query = require("../actions.js").Query;

var FilterDocs = React.createClass({
    displayName: "FilterDocs",

    statics: {
        xhr: false,
        doc: false
    },
    componentWillMount: function componentWillMount() {
        if (!FilterDocs.doc) {
            FilterDocs.xhr = $.getJSON("/filter-help").done(function (doc) {
                FilterDocs.doc = doc;
                FilterDocs.xhr = false;
            });
        }
        if (FilterDocs.xhr) {
            FilterDocs.xhr.done((function () {
                this.forceUpdate();
            }).bind(this));
        }
    },
    render: function render() {
        if (!FilterDocs.doc) {
            return React.createElement("i", { className: "fa fa-spinner fa-spin" });
        } else {
            var commands = FilterDocs.doc.commands.map(function (c) {
                return React.createElement(
                    "tr",
                    { key: c[1] },
                    React.createElement(
                        "td",
                        null,
                        c[0].replace(" ", " ")
                    ),
                    React.createElement(
                        "td",
                        null,
                        c[1]
                    )
                );
            });
            commands.push(React.createElement(
                "tr",
                { key: "docs-link" },
                React.createElement(
                    "td",
                    { colSpan: "2" },
                    React.createElement(
                        "a",
                        { href: "https://mitmproxy.org/doc/features/filters.html",
                            target: "_blank" },
                        React.createElement("i", { className: "fa fa-external-link" }),
                        "  mitmproxy docs"
                    )
                )
            ));
            return React.createElement(
                "table",
                { className: "table table-condensed" },
                React.createElement(
                    "tbody",
                    null,
                    commands
                )
            );
        }
    }
});
var FilterInput = React.createClass({
    displayName: "FilterInput",

    mixins: [common.ChildFocus],
    getInitialState: function getInitialState() {
        // Consider both focus and mouseover for showing/hiding the tooltip,
        // because onBlur of the input is triggered before the click on the tooltip
        // finalized, hiding the tooltip just as the user clicks on it.
        return {
            value: this.props.value,
            focus: false,
            mousefocus: false
        };
    },
    componentWillReceiveProps: function componentWillReceiveProps(nextProps) {
        this.setState({ value: nextProps.value });
    },
    onChange: function onChange(e) {
        var nextValue = e.target.value;
        this.setState({
            value: nextValue
        });
        // Only propagate valid filters upwards.
        if (this.isValid(nextValue)) {
            this.props.onChange(nextValue);
        }
    },
    isValid: function isValid(filt) {
        try {
            Filt.parse(filt || this.state.value);
            return true;
        } catch (e) {
            return false;
        }
    },
    getDesc: function getDesc() {
        var desc;
        try {
            desc = Filt.parse(this.state.value).desc;
        } catch (e) {
            desc = "" + e;
        }
        if (desc !== "true") {
            return desc;
        } else {
            return React.createElement(FilterDocs, null);
        }
    },
    onFocus: function onFocus() {
        this.setState({ focus: true });
    },
    onBlur: function onBlur() {
        this.setState({ focus: false });
    },
    onMouseEnter: function onMouseEnter() {
        this.setState({ mousefocus: true });
    },
    onMouseLeave: function onMouseLeave() {
        this.setState({ mousefocus: false });
    },
    onKeyDown: function onKeyDown(e) {
        if (e.keyCode === utils.Key.ESC || e.keyCode === utils.Key.ENTER) {
            this.blur();
            // If closed using ESC/ENTER, hide the tooltip.
            this.setState({ mousefocus: false });
        }
        e.stopPropagation();
    },
    blur: function blur() {
        this.refs.input.getDOMNode().blur();
        this.returnFocus();
    },
    select: function select() {
        this.refs.input.getDOMNode().select();
    },
    render: function render() {
        var isValid = this.isValid();
        var icon = "fa fa-fw fa-" + this.props.type;
        var groupClassName = "filter-input input-group" + (isValid ? "" : " has-error");

        var popover;
        if (this.state.focus || this.state.mousefocus) {
            popover = React.createElement(
                "div",
                { className: "popover bottom", onMouseEnter: this.onMouseEnter, onMouseLeave: this.onMouseLeave },
                React.createElement("div", { className: "arrow" }),
                React.createElement(
                    "div",
                    { className: "popover-content" },
                    this.getDesc()
                )
            );
        }

        return React.createElement(
            "div",
            { className: groupClassName },
            React.createElement(
                "span",
                { className: "input-group-addon" },
                React.createElement("i", { className: icon, style: { color: this.props.color } })
            ),
            React.createElement("input", { type: "text", placeholder: this.props.placeholder, className: "form-control",
                ref: "input",
                onChange: this.onChange,
                onFocus: this.onFocus,
                onBlur: this.onBlur,
                onKeyDown: this.onKeyDown,
                value: this.state.value }),
            popover
        );
    }
});

var MainMenu = React.createClass({
    displayName: "MainMenu",

    mixins: [common.Navigation, common.RouterState, common.SettingsState],
    statics: {
        title: "Start",
        route: "flows"
    },
    onSearchChange: function onSearchChange(val) {
        var d = {};
        d[Query.SEARCH] = val;
        this.setQuery(d);
    },
    onHighlightChange: function onHighlightChange(val) {
        var d = {};
        d[Query.HIGHLIGHT] = val;
        this.setQuery(d);
    },
    onInterceptChange: function onInterceptChange(val) {
        actions.SettingsActions.update({ intercept: val });
    },
    render: function render() {
        var search = this.getQuery()[Query.SEARCH] || "";
        var highlight = this.getQuery()[Query.HIGHLIGHT] || "";
        var intercept = this.state.settings.intercept || "";

        return React.createElement(
            "div",
            null,
            React.createElement(
                "div",
                { className: "menu-row" },
                React.createElement(FilterInput, {
                    ref: "search",
                    placeholder: "Search",
                    type: "search",
                    color: "black",
                    value: search,
                    onChange: this.onSearchChange }),
                React.createElement(FilterInput, {
                    ref: "highlight",
                    placeholder: "Highlight",
                    type: "tag",
                    color: "hsl(48, 100%, 50%)",
                    value: highlight,
                    onChange: this.onHighlightChange }),
                React.createElement(FilterInput, {
                    ref: "intercept",
                    placeholder: "Intercept",
                    type: "pause",
                    color: "hsl(208, 56%, 53%)",
                    value: intercept,
                    onChange: this.onInterceptChange })
            ),
            React.createElement("div", { className: "clearfix" })
        );
    }
});

var ViewMenu = React.createClass({
    displayName: "ViewMenu",

    statics: {
        title: "View",
        route: "flows"
    },
    mixins: [common.Navigation, common.RouterState],
    toggleEventLog: function toggleEventLog() {
        var d = {};

        if (this.getQuery()[Query.SHOW_EVENTLOG]) {
            d[Query.SHOW_EVENTLOG] = undefined;
        } else {
            d[Query.SHOW_EVENTLOG] = "t"; // any non-false value will do it, keep it short
        }

        this.setQuery(d);
    },
    render: function render() {
        var showEventLog = this.getQuery()[Query.SHOW_EVENTLOG];
        return React.createElement(
            "div",
            null,
            React.createElement(
                "button",
                {
                    className: "btn " + (showEventLog ? "btn-primary" : "btn-default"),
                    onClick: this.toggleEventLog },
                React.createElement("i", { className: "fa fa-database" }),
                " Show Eventlog"
            ),
            React.createElement(
                "span",
                null,
                " "
            )
        );
    }
});

var ReportsMenu = React.createClass({
    displayName: "ReportsMenu",

    statics: {
        title: "Visualization",
        route: "reports"
    },
    render: function render() {
        return React.createElement(
            "div",
            null,
            "Reports Menu"
        );
    }
});

var FileMenu = React.createClass({
    displayName: "FileMenu",

    getInitialState: function getInitialState() {
        return {
            showFileMenu: false
        };
    },
    handleFileClick: function handleFileClick(e) {
        e.preventDefault();
        if (!this.state.showFileMenu) {
            var close = (function () {
                this.setState({ showFileMenu: false });
                document.removeEventListener("click", close);
            }).bind(this);
            document.addEventListener("click", close);

            this.setState({
                showFileMenu: true
            });
        }
    },
    handleNewClick: function handleNewClick(e) {
        e.preventDefault();
        if (confirm("Delete all flows?")) {
            actions.FlowActions.clear();
        }
    },
    handleOpenClick: function handleOpenClick(e) {
        e.preventDefault();
        console.error("unimplemented: handleOpenClick");
    },
    handleSaveClick: function handleSaveClick(e) {
        e.preventDefault();
        console.error("unimplemented: handleSaveClick");
    },
    handleShutdownClick: function handleShutdownClick(e) {
        e.preventDefault();
        console.error("unimplemented: handleShutdownClick");
    },
    render: function render() {
        var fileMenuClass = "dropdown pull-left" + (this.state.showFileMenu ? " open" : "");

        return React.createElement(
            "div",
            { className: fileMenuClass },
            React.createElement(
                "a",
                { href: "#", className: "special", onClick: this.handleFileClick },
                " mitmproxy "
            ),
            React.createElement(
                "ul",
                { className: "dropdown-menu", role: "menu" },
                React.createElement(
                    "li",
                    null,
                    React.createElement(
                        "a",
                        { href: "#", onClick: this.handleNewClick },
                        React.createElement("i", { className: "fa fa-fw fa-file" }),
                        "New"
                    )
                ),
                React.createElement("li", { role: "presentation", className: "divider" }),
                React.createElement(
                    "li",
                    null,
                    React.createElement(
                        "a",
                        { href: "http://mitm.it/", target: "_blank" },
                        React.createElement("i", { className: "fa fa-fw fa-external-link" }),
                        "Install Certificates..."
                    )
                )
            )
        );
    }
});

var header_entries = [MainMenu, ViewMenu /*, ReportsMenu */];

var Header = React.createClass({
    displayName: "Header",

    mixins: [common.Navigation],
    getInitialState: function getInitialState() {
        return {
            active: header_entries[0]
        };
    },
    handleClick: function handleClick(active, e) {
        e.preventDefault();
        this.replaceWith(active.route);
        this.setState({ active: active });
    },
    render: function render() {
        var header = header_entries.map((function (entry, i) {
            var className;
            if (entry === this.state.active) {
                className = "active";
            } else {
                className = "";
            }
            return React.createElement(
                "a",
                { key: i,
                    href: "#",
                    className: className,
                    onClick: this.handleClick.bind(this, entry) },
                entry.title
            );
        }).bind(this));

        return React.createElement(
            "header",
            null,
            React.createElement(
                "nav",
                { className: "nav-tabs nav-tabs-lg" },
                React.createElement(FileMenu, null),
                header
            ),
            React.createElement(
                "div",
                { className: "menu" },
                React.createElement(this.state.active, { ref: "active" })
            )
        );
    }
});

module.exports = {
    Header: Header,
    MainMenu: MainMenu
};
/*
<li>
<a href="#" onClick={this.handleOpenClick}>
<i className="fa fa-fw fa-folder-open"></i>
Open
</a>
</li>
<li>
<a href="#" onClick={this.handleSaveClick}>
<i className="fa fa-fw fa-save"></i>
Save
</a>
</li>
<li role="presentation" className="divider"></li>
<li>
<a href="#" onClick={this.handleShutdownClick}>
<i className="fa fa-fw fa-plug"></i>
Shutdown
</a>
</li>
*/


},{"../actions.js":2,"../filt/filt.js":22,"../utils.js":26,"./common.js":4,"jquery":"jquery","react":"react"}],16:[function(require,module,exports){
"use strict";

var React = require("react");

var actions = require("../actions.js");
var Query = require("../actions.js").Query;
var utils = require("../utils.js");
var views = require("../store/view.js");
var Filt = require("../filt/filt.js");

var common = require("./common.js");
var FlowTable = require("./flowtable.js");
var FlowView = require("./flowview/index.js");

var MainView = React.createClass({
    displayName: "MainView",

    mixins: [common.Navigation, common.RouterState],
    contextTypes: {
        flowStore: React.PropTypes.object.isRequired
    },
    childContextTypes: {
        view: React.PropTypes.object.isRequired
    },
    getChildContext: function getChildContext() {
        return {
            view: this.state.view
        };
    },
    getInitialState: function getInitialState() {
        var sortKeyFun = false;
        var view = new views.StoreView(this.context.flowStore, this.getViewFilt(), sortKeyFun);
        view.addListener("recalculate", this.onRecalculate);
        view.addListener("add", this.onUpdate);
        view.addListener("update", this.onUpdate);
        view.addListener("remove", this.onUpdate);
        view.addListener("remove", this.onRemove);

        return {
            view: view,
            sortKeyFun: sortKeyFun
        };
    },
    componentWillUnmount: function componentWillUnmount() {
        this.state.view.close();
    },
    getViewFilt: function getViewFilt() {
        try {
            var filt = Filt.parse(this.getQuery()[Query.SEARCH] || "");
            var highlightStr = this.getQuery()[Query.HIGHLIGHT];
            var highlight = highlightStr ? Filt.parse(highlightStr) : false;
        } catch (e) {
            console.error("Error when processing filter: " + e);
        }

        return function filter_and_highlight(flow) {
            if (!this._highlight) {
                this._highlight = {};
            }
            this._highlight[flow.id] = highlight && highlight(flow);
            return filt(flow);
        };
    },
    componentWillReceiveProps: function componentWillReceiveProps(nextProps) {
        var filterChanged = this.props.query[Query.SEARCH] !== nextProps.query[Query.SEARCH];
        var highlightChanged = this.props.query[Query.HIGHLIGHT] !== nextProps.query[Query.HIGHLIGHT];
        if (filterChanged || highlightChanged) {
            this.state.view.recalculate(this.getViewFilt(), this.state.sortKeyFun);
        }
    },
    onRecalculate: function onRecalculate() {
        this.forceUpdate();
        var selected = this.getSelected();
        if (selected) {
            this.refs.flowTable.scrollIntoView(selected);
        }
    },
    onUpdate: function onUpdate(flow) {
        if (flow.id === this.getParams().flowId) {
            this.forceUpdate();
        }
    },
    onRemove: function onRemove(flow_id, index) {
        if (flow_id === this.getParams().flowId) {
            var flow_to_select = this.state.view.list[Math.min(index, this.state.view.list.length - 1)];
            this.selectFlow(flow_to_select);
        }
    },
    setSortKeyFun: function setSortKeyFun(sortKeyFun) {
        this.setState({
            sortKeyFun: sortKeyFun
        });
        this.state.view.recalculate(this.getViewFilt(), sortKeyFun);
    },
    selectFlow: function selectFlow(flow) {
        if (flow) {
            this.replaceWith("flow", {
                flowId: flow.id,
                detailTab: this.getParams().detailTab || "request"
            });
            this.refs.flowTable.scrollIntoView(flow);
        } else {
            this.replaceWith("flows", {});
        }
    },
    selectFlowRelative: function selectFlowRelative(shift) {
        var flows = this.state.view.list;
        var index;
        if (!this.getParams().flowId) {
            if (shift < 0) {
                index = flows.length - 1;
            } else {
                index = 0;
            }
        } else {
            var currFlowId = this.getParams().flowId;
            var i = flows.length;
            while (i--) {
                if (flows[i].id === currFlowId) {
                    index = i;
                    break;
                }
            }
            index = Math.min(Math.max(0, index + shift), flows.length - 1);
        }
        this.selectFlow(flows[index]);
    },
    onMainKeyDown: function onMainKeyDown(e) {
        var flow = this.getSelected();
        if (e.ctrlKey) {
            return;
        }
        switch (e.keyCode) {
            case utils.Key.K:
            case utils.Key.UP:
                this.selectFlowRelative(-1);
                break;
            case utils.Key.J:
            case utils.Key.DOWN:
                this.selectFlowRelative(+1);
                break;
            case utils.Key.SPACE:
            case utils.Key.PAGE_DOWN:
                this.selectFlowRelative(+10);
                break;
            case utils.Key.PAGE_UP:
                this.selectFlowRelative(-10);
                break;
            case utils.Key.END:
                this.selectFlowRelative(+1e10);
                break;
            case utils.Key.HOME:
                this.selectFlowRelative(-1e10);
                break;
            case utils.Key.ESC:
                this.selectFlow(null);
                break;
            case utils.Key.H:
            case utils.Key.LEFT:
                if (this.refs.flowDetails) {
                    this.refs.flowDetails.nextTab(-1);
                }
                break;
            case utils.Key.L:
            case utils.Key.TAB:
            case utils.Key.RIGHT:
                if (this.refs.flowDetails) {
                    this.refs.flowDetails.nextTab(+1);
                }
                break;
            case utils.Key.C:
                if (e.shiftKey) {
                    actions.FlowActions.clear();
                }
                break;
            case utils.Key.D:
                if (flow) {
                    if (e.shiftKey) {
                        actions.FlowActions.duplicate(flow);
                    } else {
                        actions.FlowActions["delete"](flow);
                    }
                }
                break;
            case utils.Key.A:
                if (e.shiftKey) {
                    actions.FlowActions.accept_all();
                } else if (flow && flow.intercepted) {
                    actions.FlowActions.accept(flow);
                }
                break;
            case utils.Key.R:
                if (!e.shiftKey && flow) {
                    actions.FlowActions.replay(flow);
                }
                break;
            case utils.Key.V:
                if (e.shiftKey && flow && flow.modified) {
                    actions.FlowActions.revert(flow);
                }
                break;
            case utils.Key.E:
                if (this.refs.flowDetails) {
                    this.refs.flowDetails.promptEdit();
                }
                break;
            case utils.Key.SHIFT:
                break;
            default:
                console.debug("keydown", e.keyCode);
                return;
        }
        e.preventDefault();
    },
    getSelected: function getSelected() {
        return this.context.flowStore.get(this.getParams().flowId);
    },
    render: function render() {
        var selected = this.getSelected();

        var details;
        if (selected) {
            details = [React.createElement(common.Splitter, { key: "splitter" }), React.createElement(FlowView, { key: "flowDetails", ref: "flowDetails", flow: selected })];
        } else {
            details = null;
        }

        return React.createElement(
            "div",
            { className: "main-view" },
            React.createElement(FlowTable, { ref: "flowTable",
                selectFlow: this.selectFlow,
                setSortKeyFun: this.setSortKeyFun,
                selected: selected }),
            details
        );
    }
});

module.exports = MainView;


},{"../actions.js":2,"../filt/filt.js":22,"../store/view.js":25,"../utils.js":26,"./common.js":4,"./flowtable.js":8,"./flowview/index.js":11,"react":"react"}],17:[function(require,module,exports){
"use strict";

var React = require("react");
var _ = require("lodash");

var utils = require("../utils.js");
var common = require("./common.js");

var Prompt = React.createClass({
    displayName: "Prompt",

    mixins: [common.ChildFocus],
    propTypes: {
        options: React.PropTypes.array.isRequired,
        done: React.PropTypes.func.isRequired,
        prompt: React.PropTypes.string
    },
    componentDidMount: function componentDidMount() {
        React.findDOMNode(this).focus();
    },
    onKeyDown: function onKeyDown(e) {
        e.stopPropagation();
        e.preventDefault();
        var opts = this.getOptions();
        for (var i = 0; i < opts.length; i++) {
            var k = opts[i].key;
            if (utils.Key[k.toUpperCase()] === e.keyCode) {
                this.done(k);
                return;
            }
        }
        if (e.keyCode === utils.Key.ESC || e.keyCode === utils.Key.ENTER) {
            this.done(false);
        }
    },
    onClick: function onClick(e) {
        this.done(false);
    },
    done: function done(ret) {
        this.props.done(ret);
        this.returnFocus();
    },
    getOptions: function getOptions() {
        var opts = [];

        var keyTaken = function keyTaken(k) {
            return _.includes(_.pluck(opts, "key"), k);
        };

        for (var i = 0; i < this.props.options.length; i++) {
            var opt = this.props.options[i];
            if (_.isString(opt)) {
                var str = opt;
                while (str.length > 0 && keyTaken(str[0])) {
                    str = str.substr(1);
                }
                opt = {
                    text: opt,
                    key: str[0]
                };
            }
            if (!opt.text || !opt.key || keyTaken(opt.key)) {
                throw "invalid options";
            } else {
                opts.push(opt);
            }
        }
        return opts;
    },
    render: function render() {
        var opts = this.getOptions();
        opts = _.map(opts, (function (o) {
            var prefix, suffix;
            var idx = o.text.indexOf(o.key);
            if (idx !== -1) {
                prefix = o.text.substring(0, idx);
                suffix = o.text.substring(idx + 1);
            } else {
                prefix = o.text + " (";
                suffix = ")";
            }
            var onClick = (function (e) {
                this.done(o.key);
                e.stopPropagation();
            }).bind(this);
            return React.createElement(
                "span",
                {
                    key: o.key,
                    className: "option",
                    onClick: onClick },
                prefix,
                React.createElement(
                    "strong",
                    { className: "text-primary" },
                    o.key
                ),
                suffix
            );
        }).bind(this));
        return React.createElement(
            "div",
            { tabIndex: "0", onKeyDown: this.onKeyDown, onClick: this.onClick, className: "prompt-dialog" },
            React.createElement(
                "div",
                { className: "prompt-content" },
                this.props.prompt || React.createElement(
                    "strong",
                    null,
                    "Select: "
                ),
                opts
            )
        );
    }
});

module.exports = Prompt;


},{"../utils.js":26,"./common.js":4,"lodash":"lodash","react":"react"}],18:[function(require,module,exports){
"use strict";

var React = require("react");
var ReactRouter = require("react-router");
var _ = require("lodash");

var common = require("./common.js");
var MainView = require("./mainview.js");
var Footer = require("./footer.js");
var header = require("./header.js");
var EventLog = require("./eventlog.js");
var store = require("../store/store.js");
var Query = require("../actions.js").Query;
var Key = require("../utils.js").Key;

//TODO: Move out of here, just a stub.
var Reports = React.createClass({
    displayName: "Reports",

    render: function render() {
        return React.createElement(
            "div",
            null,
            "ReportEditor"
        );
    }
});

var ProxyAppMain = React.createClass({
    displayName: "ProxyAppMain",

    mixins: [common.RouterState],
    childContextTypes: {
        settingsStore: React.PropTypes.object.isRequired,
        flowStore: React.PropTypes.object.isRequired,
        eventStore: React.PropTypes.object.isRequired,
        returnFocus: React.PropTypes.func.isRequired
    },
    componentDidMount: function componentDidMount() {
        this.focus();
    },
    getChildContext: function getChildContext() {
        return {
            settingsStore: this.state.settingsStore,
            flowStore: this.state.flowStore,
            eventStore: this.state.eventStore,
            returnFocus: this.focus
        };
    },
    getInitialState: function getInitialState() {
        var eventStore = new store.EventLogStore();
        var flowStore = new store.FlowStore();
        var settingsStore = new store.SettingsStore();

        // Default Settings before fetch
        _.extend(settingsStore.dict, {});
        return {
            settingsStore: settingsStore,
            flowStore: flowStore,
            eventStore: eventStore
        };
    },
    focus: function focus() {
        React.findDOMNode(this).focus();
    },
    getMainComponent: function getMainComponent() {
        return this.refs.view.refs.__routeHandler__;
    },
    onKeydown: function onKeydown(e) {

        var selectFilterInput = (function (name) {
            var headerComponent = this.refs.header;
            headerComponent.setState({ active: header.MainMenu }, function () {
                headerComponent.refs.active.refs[name].select();
            });
        }).bind(this);

        switch (e.keyCode) {
            case Key.I:
                selectFilterInput("intercept");
                break;
            case Key.L:
                selectFilterInput("search");
                break;
            case Key.H:
                selectFilterInput("highlight");
                break;
            default:
                var main = this.getMainComponent();
                if (main.onMainKeyDown) {
                    main.onMainKeyDown(e);
                }
                return; // don't prevent default then
        }
        e.preventDefault();
    },
    render: function render() {
        var eventlog;
        if (this.getQuery()[Query.SHOW_EVENTLOG]) {
            eventlog = [React.createElement(common.Splitter, { key: "splitter", axis: "y" }), React.createElement(EventLog, { key: "eventlog" })];
        } else {
            eventlog = null;
        }
        return React.createElement(
            "div",
            { id: "container", tabIndex: "0", onKeyDown: this.onKeydown },
            React.createElement(header.Header, { ref: "header" }),
            React.createElement(RouteHandler, { ref: "view", query: this.getQuery() }),
            eventlog,
            React.createElement(Footer, null)
        );
    }
});

var Route = ReactRouter.Route;
var RouteHandler = ReactRouter.RouteHandler;
var Redirect = ReactRouter.Redirect;
var DefaultRoute = ReactRouter.DefaultRoute;
var NotFoundRoute = ReactRouter.NotFoundRoute;

var routes = React.createElement(
    Route,
    { path: "/", handler: ProxyAppMain },
    React.createElement(Route, { name: "flows", path: "flows", handler: MainView }),
    React.createElement(Route, { name: "flow", path: "flows/:flowId/:detailTab", handler: MainView }),
    React.createElement(Route, { name: "reports", handler: Reports }),
    React.createElement(Redirect, { path: "/", to: "flows" })
);

module.exports = {
    routes: routes
};


},{"../actions.js":2,"../store/store.js":24,"../utils.js":26,"./common.js":4,"./eventlog.js":6,"./footer.js":14,"./header.js":15,"./mainview.js":16,"lodash":"lodash","react":"react","react-router":"react-router"}],19:[function(require,module,exports){
"use strict";

var React = require("react");

var VirtualScrollMixin = {
    getInitialState: function getInitialState() {
        return {
            start: 0,
            stop: 0
        };
    },
    componentWillMount: function componentWillMount() {
        if (!this.props.rowHeight) {
            console.warn("VirtualScrollMixin: No rowHeight specified", this);
        }
    },
    getPlaceholderTop: function getPlaceholderTop(total) {
        var Tag = this.props.placeholderTagName || "tr";
        // When a large trunk of elements is removed from the button, start may be far off the viewport.
        // To make this issue less severe, limit the top placeholder to the total number of rows.
        var style = {
            height: Math.min(this.state.start, total) * this.props.rowHeight
        };
        var spacer = React.createElement(Tag, { key: "placeholder-top", style: style });

        if (this.state.start % 2 === 1) {
            // fix even/odd rows
            return [spacer, React.createElement(Tag, { key: "placeholder-top-2" })];
        } else {
            return spacer;
        }
    },
    getPlaceholderBottom: function getPlaceholderBottom(total) {
        var Tag = this.props.placeholderTagName || "tr";
        var style = {
            height: Math.max(0, total - this.state.stop) * this.props.rowHeight
        };
        return React.createElement(Tag, { key: "placeholder-bottom", style: style });
    },
    componentDidMount: function componentDidMount() {
        this.onScroll();
        window.addEventListener('resize', this.onScroll);
    },
    componentWillUnmount: function componentWillUnmount() {
        window.removeEventListener('resize', this.onScroll);
    },
    onScroll: function onScroll() {
        var viewport = this.getDOMNode();
        var top = viewport.scrollTop;
        var height = viewport.offsetHeight;
        var start = Math.floor(top / this.props.rowHeight);
        var stop = start + Math.ceil(height / (this.props.rowHeightMin || this.props.rowHeight));

        this.setState({
            start: start,
            stop: stop
        });
    },
    renderRows: function renderRows(elems) {
        var rows = [];
        var max = Math.min(elems.length, this.state.stop);

        for (var i = this.state.start; i < max; i++) {
            var elem = elems[i];
            rows.push(this.renderRow(elem));
        }
        return rows;
    },
    scrollRowIntoView: function scrollRowIntoView(index, head_height) {

        var row_top = index * this.props.rowHeight + head_height;
        var row_bottom = row_top + this.props.rowHeight;

        var viewport = this.getDOMNode();
        var viewport_top = viewport.scrollTop;
        var viewport_bottom = viewport_top + viewport.offsetHeight;

        // Account for pinned thead
        if (row_top - head_height < viewport_top) {
            viewport.scrollTop = row_top - head_height;
        } else if (row_bottom > viewport_bottom) {
            viewport.scrollTop = row_bottom - viewport.offsetHeight;
        }
    }
};

module.exports = VirtualScrollMixin;


},{"react":"react"}],20:[function(require,module,exports){
"use strict";

var actions = require("./actions.js");
var AppDispatcher = require("./dispatcher.js").AppDispatcher;

function Connection(url) {
    if (url[0] === "/") {
        url = location.origin.replace("http", "ws") + url;
    }

    var ws = new WebSocket(url);
    ws.onopen = function () {
        actions.ConnectionActions.open();
    };
    ws.onmessage = function (message) {
        var m = JSON.parse(message.data);
        AppDispatcher.dispatchServerAction(m);
    };
    ws.onerror = function () {
        actions.ConnectionActions.error();
        actions.EventLogActions.add_event("WebSocket connection error.");
    };
    ws.onclose = function () {
        actions.ConnectionActions.close();
        actions.EventLogActions.add_event("WebSocket connection closed.");
    };
    return ws;
}

module.exports = Connection;


},{"./actions.js":2,"./dispatcher.js":21}],21:[function(require,module,exports){
"use strict";

var flux = require("flux");

var PayloadSources = {
    VIEW: "view",
    SERVER: "server"
};

var AppDispatcher = new flux.Dispatcher();
AppDispatcher.dispatchViewAction = function (action) {
    action.source = PayloadSources.VIEW;
    this.dispatch(action);
};
AppDispatcher.dispatchServerAction = function (action) {
    action.source = PayloadSources.SERVER;
    this.dispatch(action);
};

module.exports = {
    AppDispatcher: AppDispatcher
};


},{"flux":"flux"}],22:[function(require,module,exports){
"use strict";

module.exports = (function () {
  /*
   * Generated by PEG.js 0.8.0.
   *
   * http://pegjs.majda.cz/
   */

  function peg$subclass(child, parent) {
    function ctor() {
      this.constructor = child;
    }
    ctor.prototype = parent.prototype;
    child.prototype = new ctor();
  }

  function SyntaxError(message, expected, found, offset, line, column) {
    this.message = message;
    this.expected = expected;
    this.found = found;
    this.offset = offset;
    this.line = line;
    this.column = column;

    this.name = "SyntaxError";
  }

  peg$subclass(SyntaxError, Error);

  function parse(input) {
    var options = arguments.length > 1 ? arguments[1] : {},
        peg$FAILED = {},
        peg$startRuleFunctions = { start: peg$parsestart },
        peg$startRuleFunction = peg$parsestart,
        peg$c0 = { type: "other", description: "filter expression" },
        peg$c1 = peg$FAILED,
        peg$c2 = function peg$c2(orExpr) {
      return orExpr;
    },
        peg$c3 = [],
        peg$c4 = function peg$c4() {
      return trueFilter;
    },
        peg$c5 = { type: "other", description: "whitespace" },
        peg$c6 = /^[ \t\n\r]/,
        peg$c7 = { type: "class", value: "[ \\t\\n\\r]", description: "[ \\t\\n\\r]" },
        peg$c8 = { type: "other", description: "control character" },
        peg$c9 = /^[|&!()~"]/,
        peg$c10 = { type: "class", value: "[|&!()~\"]", description: "[|&!()~\"]" },
        peg$c11 = { type: "other", description: "optional whitespace" },
        peg$c12 = "|",
        peg$c13 = { type: "literal", value: "|", description: "\"|\"" },
        peg$c14 = function peg$c14(first, second) {
      return or(first, second);
    },
        peg$c15 = "&",
        peg$c16 = { type: "literal", value: "&", description: "\"&\"" },
        peg$c17 = function peg$c17(first, second) {
      return and(first, second);
    },
        peg$c18 = "!",
        peg$c19 = { type: "literal", value: "!", description: "\"!\"" },
        peg$c20 = function peg$c20(expr) {
      return not(expr);
    },
        peg$c21 = "(",
        peg$c22 = { type: "literal", value: "(", description: "\"(\"" },
        peg$c23 = ")",
        peg$c24 = { type: "literal", value: ")", description: "\")\"" },
        peg$c25 = function peg$c25(expr) {
      return binding(expr);
    },
        peg$c26 = "~a",
        peg$c27 = { type: "literal", value: "~a", description: "\"~a\"" },
        peg$c28 = function peg$c28() {
      return assetFilter;
    },
        peg$c29 = "~e",
        peg$c30 = { type: "literal", value: "~e", description: "\"~e\"" },
        peg$c31 = function peg$c31() {
      return errorFilter;
    },
        peg$c32 = "~q",
        peg$c33 = { type: "literal", value: "~q", description: "\"~q\"" },
        peg$c34 = function peg$c34() {
      return noResponseFilter;
    },
        peg$c35 = "~s",
        peg$c36 = { type: "literal", value: "~s", description: "\"~s\"" },
        peg$c37 = function peg$c37() {
      return responseFilter;
    },
        peg$c38 = "true",
        peg$c39 = { type: "literal", value: "true", description: "\"true\"" },
        peg$c40 = function peg$c40() {
      return trueFilter;
    },
        peg$c41 = "false",
        peg$c42 = { type: "literal", value: "false", description: "\"false\"" },
        peg$c43 = function peg$c43() {
      return falseFilter;
    },
        peg$c44 = "~c",
        peg$c45 = { type: "literal", value: "~c", description: "\"~c\"" },
        peg$c46 = function peg$c46(s) {
      return responseCode(s);
    },
        peg$c47 = "~d",
        peg$c48 = { type: "literal", value: "~d", description: "\"~d\"" },
        peg$c49 = function peg$c49(s) {
      return domain(s);
    },
        peg$c50 = "~h",
        peg$c51 = { type: "literal", value: "~h", description: "\"~h\"" },
        peg$c52 = function peg$c52(s) {
      return header(s);
    },
        peg$c53 = "~hq",
        peg$c54 = { type: "literal", value: "~hq", description: "\"~hq\"" },
        peg$c55 = function peg$c55(s) {
      return requestHeader(s);
    },
        peg$c56 = "~hs",
        peg$c57 = { type: "literal", value: "~hs", description: "\"~hs\"" },
        peg$c58 = function peg$c58(s) {
      return responseHeader(s);
    },
        peg$c59 = "~m",
        peg$c60 = { type: "literal", value: "~m", description: "\"~m\"" },
        peg$c61 = function peg$c61(s) {
      return method(s);
    },
        peg$c62 = "~t",
        peg$c63 = { type: "literal", value: "~t", description: "\"~t\"" },
        peg$c64 = function peg$c64(s) {
      return contentType(s);
    },
        peg$c65 = "~tq",
        peg$c66 = { type: "literal", value: "~tq", description: "\"~tq\"" },
        peg$c67 = function peg$c67(s) {
      return requestContentType(s);
    },
        peg$c68 = "~ts",
        peg$c69 = { type: "literal", value: "~ts", description: "\"~ts\"" },
        peg$c70 = function peg$c70(s) {
      return responseContentType(s);
    },
        peg$c71 = "~u",
        peg$c72 = { type: "literal", value: "~u", description: "\"~u\"" },
        peg$c73 = function peg$c73(s) {
      return url(s);
    },
        peg$c74 = { type: "other", description: "integer" },
        peg$c75 = null,
        peg$c76 = /^['"]/,
        peg$c77 = { type: "class", value: "['\"]", description: "['\"]" },
        peg$c78 = /^[0-9]/,
        peg$c79 = { type: "class", value: "[0-9]", description: "[0-9]" },
        peg$c80 = function peg$c80(digits) {
      return parseInt(digits.join(""), 10);
    },
        peg$c81 = { type: "other", description: "string" },
        peg$c82 = "\"",
        peg$c83 = { type: "literal", value: "\"", description: "\"\\\"\"" },
        peg$c84 = function peg$c84(chars) {
      return chars.join("");
    },
        peg$c85 = "'",
        peg$c86 = { type: "literal", value: "'", description: "\"'\"" },
        peg$c87 = void 0,
        peg$c88 = /^["\\]/,
        peg$c89 = { type: "class", value: "[\"\\\\]", description: "[\"\\\\]" },
        peg$c90 = { type: "any", description: "any character" },
        peg$c91 = function peg$c91(char) {
      return char;
    },
        peg$c92 = "\\",
        peg$c93 = { type: "literal", value: "\\", description: "\"\\\\\"" },
        peg$c94 = /^['\\]/,
        peg$c95 = { type: "class", value: "['\\\\]", description: "['\\\\]" },
        peg$c96 = /^['"\\]/,
        peg$c97 = { type: "class", value: "['\"\\\\]", description: "['\"\\\\]" },
        peg$c98 = "n",
        peg$c99 = { type: "literal", value: "n", description: "\"n\"" },
        peg$c100 = function peg$c100() {
      return "\n";
    },
        peg$c101 = "r",
        peg$c102 = { type: "literal", value: "r", description: "\"r\"" },
        peg$c103 = function peg$c103() {
      return "\r";
    },
        peg$c104 = "t",
        peg$c105 = { type: "literal", value: "t", description: "\"t\"" },
        peg$c106 = function peg$c106() {
      return "\t";
    },
        peg$currPos = 0,
        peg$reportedPos = 0,
        peg$cachedPos = 0,
        peg$cachedPosDetails = { line: 1, column: 1, seenCR: false },
        peg$maxFailPos = 0,
        peg$maxFailExpected = [],
        peg$silentFails = 0,
        peg$result;

    if ("startRule" in options) {
      if (!(options.startRule in peg$startRuleFunctions)) {
        throw new Error("Can't start parsing from rule \"" + options.startRule + "\".");
      }

      peg$startRuleFunction = peg$startRuleFunctions[options.startRule];
    }

    function text() {
      return input.substring(peg$reportedPos, peg$currPos);
    }

    function offset() {
      return peg$reportedPos;
    }

    function line() {
      return peg$computePosDetails(peg$reportedPos).line;
    }

    function column() {
      return peg$computePosDetails(peg$reportedPos).column;
    }

    function expected(description) {
      throw peg$buildException(null, [{ type: "other", description: description }], peg$reportedPos);
    }

    function error(message) {
      throw peg$buildException(message, null, peg$reportedPos);
    }

    function peg$computePosDetails(pos) {
      function advance(details, startPos, endPos) {
        var p, ch;

        for (p = startPos; p < endPos; p++) {
          ch = input.charAt(p);
          if (ch === "\n") {
            if (!details.seenCR) {
              details.line++;
            }
            details.column = 1;
            details.seenCR = false;
          } else if (ch === "\r" || ch === "\u2028" || ch === "\u2029") {
            details.line++;
            details.column = 1;
            details.seenCR = true;
          } else {
            details.column++;
            details.seenCR = false;
          }
        }
      }

      if (peg$cachedPos !== pos) {
        if (peg$cachedPos > pos) {
          peg$cachedPos = 0;
          peg$cachedPosDetails = { line: 1, column: 1, seenCR: false };
        }
        advance(peg$cachedPosDetails, peg$cachedPos, pos);
        peg$cachedPos = pos;
      }

      return peg$cachedPosDetails;
    }

    function peg$fail(expected) {
      if (peg$currPos < peg$maxFailPos) {
        return;
      }

      if (peg$currPos > peg$maxFailPos) {
        peg$maxFailPos = peg$currPos;
        peg$maxFailExpected = [];
      }

      peg$maxFailExpected.push(expected);
    }

    function peg$buildException(message, expected, pos) {
      function cleanupExpected(expected) {
        var i = 1;

        expected.sort(function (a, b) {
          if (a.description < b.description) {
            return -1;
          } else if (a.description > b.description) {
            return 1;
          } else {
            return 0;
          }
        });

        while (i < expected.length) {
          if (expected[i - 1] === expected[i]) {
            expected.splice(i, 1);
          } else {
            i++;
          }
        }
      }

      function buildMessage(expected, found) {
        function stringEscape(s) {
          function hex(ch) {
            return ch.charCodeAt(0).toString(16).toUpperCase();
          }

          return s.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\x08/g, '\\b').replace(/\t/g, '\\t').replace(/\n/g, '\\n').replace(/\f/g, '\\f').replace(/\r/g, '\\r').replace(/[\x00-\x07\x0B\x0E\x0F]/g, function (ch) {
            return '\\x0' + hex(ch);
          }).replace(/[\x10-\x1F\x80-\xFF]/g, function (ch) {
            return '\\x' + hex(ch);
          }).replace(/[\u0180-\u0FFF]/g, function (ch) {
            return "\\u0" + hex(ch);
          }).replace(/[\u1080-\uFFFF]/g, function (ch) {
            return "\\u" + hex(ch);
          });
        }

        var expectedDescs = new Array(expected.length),
            expectedDesc,
            foundDesc,
            i;

        for (i = 0; i < expected.length; i++) {
          expectedDescs[i] = expected[i].description;
        }

        expectedDesc = expected.length > 1 ? expectedDescs.slice(0, -1).join(", ") + " or " + expectedDescs[expected.length - 1] : expectedDescs[0];

        foundDesc = found ? "\"" + stringEscape(found) + "\"" : "end of input";

        return "Expected " + expectedDesc + " but " + foundDesc + " found.";
      }

      var posDetails = peg$computePosDetails(pos),
          found = pos < input.length ? input.charAt(pos) : null;

      if (expected !== null) {
        cleanupExpected(expected);
      }

      return new SyntaxError(message !== null ? message : buildMessage(expected, found), expected, found, pos, posDetails.line, posDetails.column);
    }

    function peg$parsestart() {
      var s0, s1, s2, s3;

      peg$silentFails++;
      s0 = peg$currPos;
      s1 = peg$parse__();
      if (s1 !== peg$FAILED) {
        s2 = peg$parseOrExpr();
        if (s2 !== peg$FAILED) {
          s3 = peg$parse__();
          if (s3 !== peg$FAILED) {
            peg$reportedPos = s0;
            s1 = peg$c2(s2);
            s0 = s1;
          } else {
            peg$currPos = s0;
            s0 = peg$c1;
          }
        } else {
          peg$currPos = s0;
          s0 = peg$c1;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$c1;
      }
      if (s0 === peg$FAILED) {
        s0 = peg$currPos;
        s1 = [];
        if (s1 !== peg$FAILED) {
          peg$reportedPos = s0;
          s1 = peg$c4();
        }
        s0 = s1;
      }
      peg$silentFails--;
      if (s0 === peg$FAILED) {
        s1 = peg$FAILED;
        if (peg$silentFails === 0) {
          peg$fail(peg$c0);
        }
      }

      return s0;
    }

    function peg$parsews() {
      var s0, s1;

      peg$silentFails++;
      if (peg$c6.test(input.charAt(peg$currPos))) {
        s0 = input.charAt(peg$currPos);
        peg$currPos++;
      } else {
        s0 = peg$FAILED;
        if (peg$silentFails === 0) {
          peg$fail(peg$c7);
        }
      }
      peg$silentFails--;
      if (s0 === peg$FAILED) {
        s1 = peg$FAILED;
        if (peg$silentFails === 0) {
          peg$fail(peg$c5);
        }
      }

      return s0;
    }

    function peg$parsecc() {
      var s0, s1;

      peg$silentFails++;
      if (peg$c9.test(input.charAt(peg$currPos))) {
        s0 = input.charAt(peg$currPos);
        peg$currPos++;
      } else {
        s0 = peg$FAILED;
        if (peg$silentFails === 0) {
          peg$fail(peg$c10);
        }
      }
      peg$silentFails--;
      if (s0 === peg$FAILED) {
        s1 = peg$FAILED;
        if (peg$silentFails === 0) {
          peg$fail(peg$c8);
        }
      }

      return s0;
    }

    function peg$parse__() {
      var s0, s1;

      peg$silentFails++;
      s0 = [];
      s1 = peg$parsews();
      while (s1 !== peg$FAILED) {
        s0.push(s1);
        s1 = peg$parsews();
      }
      peg$silentFails--;
      if (s0 === peg$FAILED) {
        s1 = peg$FAILED;
        if (peg$silentFails === 0) {
          peg$fail(peg$c11);
        }
      }

      return s0;
    }

    function peg$parseOrExpr() {
      var s0, s1, s2, s3, s4, s5;

      s0 = peg$currPos;
      s1 = peg$parseAndExpr();
      if (s1 !== peg$FAILED) {
        s2 = peg$parse__();
        if (s2 !== peg$FAILED) {
          if (input.charCodeAt(peg$currPos) === 124) {
            s3 = peg$c12;
            peg$currPos++;
          } else {
            s3 = peg$FAILED;
            if (peg$silentFails === 0) {
              peg$fail(peg$c13);
            }
          }
          if (s3 !== peg$FAILED) {
            s4 = peg$parse__();
            if (s4 !== peg$FAILED) {
              s5 = peg$parseOrExpr();
              if (s5 !== peg$FAILED) {
                peg$reportedPos = s0;
                s1 = peg$c14(s1, s5);
                s0 = s1;
              } else {
                peg$currPos = s0;
                s0 = peg$c1;
              }
            } else {
              peg$currPos = s0;
              s0 = peg$c1;
            }
          } else {
            peg$currPos = s0;
            s0 = peg$c1;
          }
        } else {
          peg$currPos = s0;
          s0 = peg$c1;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$c1;
      }
      if (s0 === peg$FAILED) {
        s0 = peg$parseAndExpr();
      }

      return s0;
    }

    function peg$parseAndExpr() {
      var s0, s1, s2, s3, s4, s5;

      s0 = peg$currPos;
      s1 = peg$parseNotExpr();
      if (s1 !== peg$FAILED) {
        s2 = peg$parse__();
        if (s2 !== peg$FAILED) {
          if (input.charCodeAt(peg$currPos) === 38) {
            s3 = peg$c15;
            peg$currPos++;
          } else {
            s3 = peg$FAILED;
            if (peg$silentFails === 0) {
              peg$fail(peg$c16);
            }
          }
          if (s3 !== peg$FAILED) {
            s4 = peg$parse__();
            if (s4 !== peg$FAILED) {
              s5 = peg$parseAndExpr();
              if (s5 !== peg$FAILED) {
                peg$reportedPos = s0;
                s1 = peg$c17(s1, s5);
                s0 = s1;
              } else {
                peg$currPos = s0;
                s0 = peg$c1;
              }
            } else {
              peg$currPos = s0;
              s0 = peg$c1;
            }
          } else {
            peg$currPos = s0;
            s0 = peg$c1;
          }
        } else {
          peg$currPos = s0;
          s0 = peg$c1;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$c1;
      }
      if (s0 === peg$FAILED) {
        s0 = peg$currPos;
        s1 = peg$parseNotExpr();
        if (s1 !== peg$FAILED) {
          s2 = [];
          s3 = peg$parsews();
          if (s3 !== peg$FAILED) {
            while (s3 !== peg$FAILED) {
              s2.push(s3);
              s3 = peg$parsews();
            }
          } else {
            s2 = peg$c1;
          }
          if (s2 !== peg$FAILED) {
            s3 = peg$parseAndExpr();
            if (s3 !== peg$FAILED) {
              peg$reportedPos = s0;
              s1 = peg$c17(s1, s3);
              s0 = s1;
            } else {
              peg$currPos = s0;
              s0 = peg$c1;
            }
          } else {
            peg$currPos = s0;
            s0 = peg$c1;
          }
        } else {
          peg$currPos = s0;
          s0 = peg$c1;
        }
        if (s0 === peg$FAILED) {
          s0 = peg$parseNotExpr();
        }
      }

      return s0;
    }

    function peg$parseNotExpr() {
      var s0, s1, s2, s3;

      s0 = peg$currPos;
      if (input.charCodeAt(peg$currPos) === 33) {
        s1 = peg$c18;
        peg$currPos++;
      } else {
        s1 = peg$FAILED;
        if (peg$silentFails === 0) {
          peg$fail(peg$c19);
        }
      }
      if (s1 !== peg$FAILED) {
        s2 = peg$parse__();
        if (s2 !== peg$FAILED) {
          s3 = peg$parseNotExpr();
          if (s3 !== peg$FAILED) {
            peg$reportedPos = s0;
            s1 = peg$c20(s3);
            s0 = s1;
          } else {
            peg$currPos = s0;
            s0 = peg$c1;
          }
        } else {
          peg$currPos = s0;
          s0 = peg$c1;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$c1;
      }
      if (s0 === peg$FAILED) {
        s0 = peg$parseBindingExpr();
      }

      return s0;
    }

    function peg$parseBindingExpr() {
      var s0, s1, s2, s3, s4, s5;

      s0 = peg$currPos;
      if (input.charCodeAt(peg$currPos) === 40) {
        s1 = peg$c21;
        peg$currPos++;
      } else {
        s1 = peg$FAILED;
        if (peg$silentFails === 0) {
          peg$fail(peg$c22);
        }
      }
      if (s1 !== peg$FAILED) {
        s2 = peg$parse__();
        if (s2 !== peg$FAILED) {
          s3 = peg$parseOrExpr();
          if (s3 !== peg$FAILED) {
            s4 = peg$parse__();
            if (s4 !== peg$FAILED) {
              if (input.charCodeAt(peg$currPos) === 41) {
                s5 = peg$c23;
                peg$currPos++;
              } else {
                s5 = peg$FAILED;
                if (peg$silentFails === 0) {
                  peg$fail(peg$c24);
                }
              }
              if (s5 !== peg$FAILED) {
                peg$reportedPos = s0;
                s1 = peg$c25(s3);
                s0 = s1;
              } else {
                peg$currPos = s0;
                s0 = peg$c1;
              }
            } else {
              peg$currPos = s0;
              s0 = peg$c1;
            }
          } else {
            peg$currPos = s0;
            s0 = peg$c1;
          }
        } else {
          peg$currPos = s0;
          s0 = peg$c1;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$c1;
      }
      if (s0 === peg$FAILED) {
        s0 = peg$parseExpr();
      }

      return s0;
    }

    function peg$parseExpr() {
      var s0;

      s0 = peg$parseNullaryExpr();
      if (s0 === peg$FAILED) {
        s0 = peg$parseUnaryExpr();
      }

      return s0;
    }

    function peg$parseNullaryExpr() {
      var s0, s1;

      s0 = peg$parseBooleanLiteral();
      if (s0 === peg$FAILED) {
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 2) === peg$c26) {
          s1 = peg$c26;
          peg$currPos += 2;
        } else {
          s1 = peg$FAILED;
          if (peg$silentFails === 0) {
            peg$fail(peg$c27);
          }
        }
        if (s1 !== peg$FAILED) {
          peg$reportedPos = s0;
          s1 = peg$c28();
        }
        s0 = s1;
        if (s0 === peg$FAILED) {
          s0 = peg$currPos;
          if (input.substr(peg$currPos, 2) === peg$c29) {
            s1 = peg$c29;
            peg$currPos += 2;
          } else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
              peg$fail(peg$c30);
            }
          }
          if (s1 !== peg$FAILED) {
            peg$reportedPos = s0;
            s1 = peg$c31();
          }
          s0 = s1;
          if (s0 === peg$FAILED) {
            s0 = peg$currPos;
            if (input.substr(peg$currPos, 2) === peg$c32) {
              s1 = peg$c32;
              peg$currPos += 2;
            } else {
              s1 = peg$FAILED;
              if (peg$silentFails === 0) {
                peg$fail(peg$c33);
              }
            }
            if (s1 !== peg$FAILED) {
              peg$reportedPos = s0;
              s1 = peg$c34();
            }
            s0 = s1;
            if (s0 === peg$FAILED) {
              s0 = peg$currPos;
              if (input.substr(peg$currPos, 2) === peg$c35) {
                s1 = peg$c35;
                peg$currPos += 2;
              } else {
                s1 = peg$FAILED;
                if (peg$silentFails === 0) {
                  peg$fail(peg$c36);
                }
              }
              if (s1 !== peg$FAILED) {
                peg$reportedPos = s0;
                s1 = peg$c37();
              }
              s0 = s1;
            }
          }
        }
      }

      return s0;
    }

    function peg$parseBooleanLiteral() {
      var s0, s1;

      s0 = peg$currPos;
      if (input.substr(peg$currPos, 4) === peg$c38) {
        s1 = peg$c38;
        peg$currPos += 4;
      } else {
        s1 = peg$FAILED;
        if (peg$silentFails === 0) {
          peg$fail(peg$c39);
        }
      }
      if (s1 !== peg$FAILED) {
        peg$reportedPos = s0;
        s1 = peg$c40();
      }
      s0 = s1;
      if (s0 === peg$FAILED) {
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 5) === peg$c41) {
          s1 = peg$c41;
          peg$currPos += 5;
        } else {
          s1 = peg$FAILED;
          if (peg$silentFails === 0) {
            peg$fail(peg$c42);
          }
        }
        if (s1 !== peg$FAILED) {
          peg$reportedPos = s0;
          s1 = peg$c43();
        }
        s0 = s1;
      }

      return s0;
    }

    function peg$parseUnaryExpr() {
      var s0, s1, s2, s3;

      s0 = peg$currPos;
      if (input.substr(peg$currPos, 2) === peg$c44) {
        s1 = peg$c44;
        peg$currPos += 2;
      } else {
        s1 = peg$FAILED;
        if (peg$silentFails === 0) {
          peg$fail(peg$c45);
        }
      }
      if (s1 !== peg$FAILED) {
        s2 = [];
        s3 = peg$parsews();
        if (s3 !== peg$FAILED) {
          while (s3 !== peg$FAILED) {
            s2.push(s3);
            s3 = peg$parsews();
          }
        } else {
          s2 = peg$c1;
        }
        if (s2 !== peg$FAILED) {
          s3 = peg$parseIntegerLiteral();
          if (s3 !== peg$FAILED) {
            peg$reportedPos = s0;
            s1 = peg$c46(s3);
            s0 = s1;
          } else {
            peg$currPos = s0;
            s0 = peg$c1;
          }
        } else {
          peg$currPos = s0;
          s0 = peg$c1;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$c1;
      }
      if (s0 === peg$FAILED) {
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 2) === peg$c47) {
          s1 = peg$c47;
          peg$currPos += 2;
        } else {
          s1 = peg$FAILED;
          if (peg$silentFails === 0) {
            peg$fail(peg$c48);
          }
        }
        if (s1 !== peg$FAILED) {
          s2 = [];
          s3 = peg$parsews();
          if (s3 !== peg$FAILED) {
            while (s3 !== peg$FAILED) {
              s2.push(s3);
              s3 = peg$parsews();
            }
          } else {
            s2 = peg$c1;
          }
          if (s2 !== peg$FAILED) {
            s3 = peg$parseStringLiteral();
            if (s3 !== peg$FAILED) {
              peg$reportedPos = s0;
              s1 = peg$c49(s3);
              s0 = s1;
            } else {
              peg$currPos = s0;
              s0 = peg$c1;
            }
          } else {
            peg$currPos = s0;
            s0 = peg$c1;
          }
        } else {
          peg$currPos = s0;
          s0 = peg$c1;
        }
        if (s0 === peg$FAILED) {
          s0 = peg$currPos;
          if (input.substr(peg$currPos, 2) === peg$c50) {
            s1 = peg$c50;
            peg$currPos += 2;
          } else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
              peg$fail(peg$c51);
            }
          }
          if (s1 !== peg$FAILED) {
            s2 = [];
            s3 = peg$parsews();
            if (s3 !== peg$FAILED) {
              while (s3 !== peg$FAILED) {
                s2.push(s3);
                s3 = peg$parsews();
              }
            } else {
              s2 = peg$c1;
            }
            if (s2 !== peg$FAILED) {
              s3 = peg$parseStringLiteral();
              if (s3 !== peg$FAILED) {
                peg$reportedPos = s0;
                s1 = peg$c52(s3);
                s0 = s1;
              } else {
                peg$currPos = s0;
                s0 = peg$c1;
              }
            } else {
              peg$currPos = s0;
              s0 = peg$c1;
            }
          } else {
            peg$currPos = s0;
            s0 = peg$c1;
          }
          if (s0 === peg$FAILED) {
            s0 = peg$currPos;
            if (input.substr(peg$currPos, 3) === peg$c53) {
              s1 = peg$c53;
              peg$currPos += 3;
            } else {
              s1 = peg$FAILED;
              if (peg$silentFails === 0) {
                peg$fail(peg$c54);
              }
            }
            if (s1 !== peg$FAILED) {
              s2 = [];
              s3 = peg$parsews();
              if (s3 !== peg$FAILED) {
                while (s3 !== peg$FAILED) {
                  s2.push(s3);
                  s3 = peg$parsews();
                }
              } else {
                s2 = peg$c1;
              }
              if (s2 !== peg$FAILED) {
                s3 = peg$parseStringLiteral();
                if (s3 !== peg$FAILED) {
                  peg$reportedPos = s0;
                  s1 = peg$c55(s3);
                  s0 = s1;
                } else {
                  peg$currPos = s0;
                  s0 = peg$c1;
                }
              } else {
                peg$currPos = s0;
                s0 = peg$c1;
              }
            } else {
              peg$currPos = s0;
              s0 = peg$c1;
            }
            if (s0 === peg$FAILED) {
              s0 = peg$currPos;
              if (input.substr(peg$currPos, 3) === peg$c56) {
                s1 = peg$c56;
                peg$currPos += 3;
              } else {
                s1 = peg$FAILED;
                if (peg$silentFails === 0) {
                  peg$fail(peg$c57);
                }
              }
              if (s1 !== peg$FAILED) {
                s2 = [];
                s3 = peg$parsews();
                if (s3 !== peg$FAILED) {
                  while (s3 !== peg$FAILED) {
                    s2.push(s3);
                    s3 = peg$parsews();
                  }
                } else {
                  s2 = peg$c1;
                }
                if (s2 !== peg$FAILED) {
                  s3 = peg$parseStringLiteral();
                  if (s3 !== peg$FAILED) {
                    peg$reportedPos = s0;
                    s1 = peg$c58(s3);
                    s0 = s1;
                  } else {
                    peg$currPos = s0;
                    s0 = peg$c1;
                  }
                } else {
                  peg$currPos = s0;
                  s0 = peg$c1;
                }
              } else {
                peg$currPos = s0;
                s0 = peg$c1;
              }
              if (s0 === peg$FAILED) {
                s0 = peg$currPos;
                if (input.substr(peg$currPos, 2) === peg$c59) {
                  s1 = peg$c59;
                  peg$currPos += 2;
                } else {
                  s1 = peg$FAILED;
                  if (peg$silentFails === 0) {
                    peg$fail(peg$c60);
                  }
                }
                if (s1 !== peg$FAILED) {
                  s2 = [];
                  s3 = peg$parsews();
                  if (s3 !== peg$FAILED) {
                    while (s3 !== peg$FAILED) {
                      s2.push(s3);
                      s3 = peg$parsews();
                    }
                  } else {
                    s2 = peg$c1;
                  }
                  if (s2 !== peg$FAILED) {
                    s3 = peg$parseStringLiteral();
                    if (s3 !== peg$FAILED) {
                      peg$reportedPos = s0;
                      s1 = peg$c61(s3);
                      s0 = s1;
                    } else {
                      peg$currPos = s0;
                      s0 = peg$c1;
                    }
                  } else {
                    peg$currPos = s0;
                    s0 = peg$c1;
                  }
                } else {
                  peg$currPos = s0;
                  s0 = peg$c1;
                }
                if (s0 === peg$FAILED) {
                  s0 = peg$currPos;
                  if (input.substr(peg$currPos, 2) === peg$c62) {
                    s1 = peg$c62;
                    peg$currPos += 2;
                  } else {
                    s1 = peg$FAILED;
                    if (peg$silentFails === 0) {
                      peg$fail(peg$c63);
                    }
                  }
                  if (s1 !== peg$FAILED) {
                    s2 = [];
                    s3 = peg$parsews();
                    if (s3 !== peg$FAILED) {
                      while (s3 !== peg$FAILED) {
                        s2.push(s3);
                        s3 = peg$parsews();
                      }
                    } else {
                      s2 = peg$c1;
                    }
                    if (s2 !== peg$FAILED) {
                      s3 = peg$parseStringLiteral();
                      if (s3 !== peg$FAILED) {
                        peg$reportedPos = s0;
                        s1 = peg$c64(s3);
                        s0 = s1;
                      } else {
                        peg$currPos = s0;
                        s0 = peg$c1;
                      }
                    } else {
                      peg$currPos = s0;
                      s0 = peg$c1;
                    }
                  } else {
                    peg$currPos = s0;
                    s0 = peg$c1;
                  }
                  if (s0 === peg$FAILED) {
                    s0 = peg$currPos;
                    if (input.substr(peg$currPos, 3) === peg$c65) {
                      s1 = peg$c65;
                      peg$currPos += 3;
                    } else {
                      s1 = peg$FAILED;
                      if (peg$silentFails === 0) {
                        peg$fail(peg$c66);
                      }
                    }
                    if (s1 !== peg$FAILED) {
                      s2 = [];
                      s3 = peg$parsews();
                      if (s3 !== peg$FAILED) {
                        while (s3 !== peg$FAILED) {
                          s2.push(s3);
                          s3 = peg$parsews();
                        }
                      } else {
                        s2 = peg$c1;
                      }
                      if (s2 !== peg$FAILED) {
                        s3 = peg$parseStringLiteral();
                        if (s3 !== peg$FAILED) {
                          peg$reportedPos = s0;
                          s1 = peg$c67(s3);
                          s0 = s1;
                        } else {
                          peg$currPos = s0;
                          s0 = peg$c1;
                        }
                      } else {
                        peg$currPos = s0;
                        s0 = peg$c1;
                      }
                    } else {
                      peg$currPos = s0;
                      s0 = peg$c1;
                    }
                    if (s0 === peg$FAILED) {
                      s0 = peg$currPos;
                      if (input.substr(peg$currPos, 3) === peg$c68) {
                        s1 = peg$c68;
                        peg$currPos += 3;
                      } else {
                        s1 = peg$FAILED;
                        if (peg$silentFails === 0) {
                          peg$fail(peg$c69);
                        }
                      }
                      if (s1 !== peg$FAILED) {
                        s2 = [];
                        s3 = peg$parsews();
                        if (s3 !== peg$FAILED) {
                          while (s3 !== peg$FAILED) {
                            s2.push(s3);
                            s3 = peg$parsews();
                          }
                        } else {
                          s2 = peg$c1;
                        }
                        if (s2 !== peg$FAILED) {
                          s3 = peg$parseStringLiteral();
                          if (s3 !== peg$FAILED) {
                            peg$reportedPos = s0;
                            s1 = peg$c70(s3);
                            s0 = s1;
                          } else {
                            peg$currPos = s0;
                            s0 = peg$c1;
                          }
                        } else {
                          peg$currPos = s0;
                          s0 = peg$c1;
                        }
                      } else {
                        peg$currPos = s0;
                        s0 = peg$c1;
                      }
                      if (s0 === peg$FAILED) {
                        s0 = peg$currPos;
                        if (input.substr(peg$currPos, 2) === peg$c71) {
                          s1 = peg$c71;
                          peg$currPos += 2;
                        } else {
                          s1 = peg$FAILED;
                          if (peg$silentFails === 0) {
                            peg$fail(peg$c72);
                          }
                        }
                        if (s1 !== peg$FAILED) {
                          s2 = [];
                          s3 = peg$parsews();
                          if (s3 !== peg$FAILED) {
                            while (s3 !== peg$FAILED) {
                              s2.push(s3);
                              s3 = peg$parsews();
                            }
                          } else {
                            s2 = peg$c1;
                          }
                          if (s2 !== peg$FAILED) {
                            s3 = peg$parseStringLiteral();
                            if (s3 !== peg$FAILED) {
                              peg$reportedPos = s0;
                              s1 = peg$c73(s3);
                              s0 = s1;
                            } else {
                              peg$currPos = s0;
                              s0 = peg$c1;
                            }
                          } else {
                            peg$currPos = s0;
                            s0 = peg$c1;
                          }
                        } else {
                          peg$currPos = s0;
                          s0 = peg$c1;
                        }
                        if (s0 === peg$FAILED) {
                          s0 = peg$currPos;
                          s1 = peg$parseStringLiteral();
                          if (s1 !== peg$FAILED) {
                            peg$reportedPos = s0;
                            s1 = peg$c73(s1);
                          }
                          s0 = s1;
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }

      return s0;
    }

    function peg$parseIntegerLiteral() {
      var s0, s1, s2, s3;

      peg$silentFails++;
      s0 = peg$currPos;
      if (peg$c76.test(input.charAt(peg$currPos))) {
        s1 = input.charAt(peg$currPos);
        peg$currPos++;
      } else {
        s1 = peg$FAILED;
        if (peg$silentFails === 0) {
          peg$fail(peg$c77);
        }
      }
      if (s1 === peg$FAILED) {
        s1 = peg$c75;
      }
      if (s1 !== peg$FAILED) {
        s2 = [];
        if (peg$c78.test(input.charAt(peg$currPos))) {
          s3 = input.charAt(peg$currPos);
          peg$currPos++;
        } else {
          s3 = peg$FAILED;
          if (peg$silentFails === 0) {
            peg$fail(peg$c79);
          }
        }
        if (s3 !== peg$FAILED) {
          while (s3 !== peg$FAILED) {
            s2.push(s3);
            if (peg$c78.test(input.charAt(peg$currPos))) {
              s3 = input.charAt(peg$currPos);
              peg$currPos++;
            } else {
              s3 = peg$FAILED;
              if (peg$silentFails === 0) {
                peg$fail(peg$c79);
              }
            }
          }
        } else {
          s2 = peg$c1;
        }
        if (s2 !== peg$FAILED) {
          if (peg$c76.test(input.charAt(peg$currPos))) {
            s3 = input.charAt(peg$currPos);
            peg$currPos++;
          } else {
            s3 = peg$FAILED;
            if (peg$silentFails === 0) {
              peg$fail(peg$c77);
            }
          }
          if (s3 === peg$FAILED) {
            s3 = peg$c75;
          }
          if (s3 !== peg$FAILED) {
            peg$reportedPos = s0;
            s1 = peg$c80(s2);
            s0 = s1;
          } else {
            peg$currPos = s0;
            s0 = peg$c1;
          }
        } else {
          peg$currPos = s0;
          s0 = peg$c1;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$c1;
      }
      peg$silentFails--;
      if (s0 === peg$FAILED) {
        s1 = peg$FAILED;
        if (peg$silentFails === 0) {
          peg$fail(peg$c74);
        }
      }

      return s0;
    }

    function peg$parseStringLiteral() {
      var s0, s1, s2, s3;

      peg$silentFails++;
      s0 = peg$currPos;
      if (input.charCodeAt(peg$currPos) === 34) {
        s1 = peg$c82;
        peg$currPos++;
      } else {
        s1 = peg$FAILED;
        if (peg$silentFails === 0) {
          peg$fail(peg$c83);
        }
      }
      if (s1 !== peg$FAILED) {
        s2 = [];
        s3 = peg$parseDoubleStringChar();
        while (s3 !== peg$FAILED) {
          s2.push(s3);
          s3 = peg$parseDoubleStringChar();
        }
        if (s2 !== peg$FAILED) {
          if (input.charCodeAt(peg$currPos) === 34) {
            s3 = peg$c82;
            peg$currPos++;
          } else {
            s3 = peg$FAILED;
            if (peg$silentFails === 0) {
              peg$fail(peg$c83);
            }
          }
          if (s3 !== peg$FAILED) {
            peg$reportedPos = s0;
            s1 = peg$c84(s2);
            s0 = s1;
          } else {
            peg$currPos = s0;
            s0 = peg$c1;
          }
        } else {
          peg$currPos = s0;
          s0 = peg$c1;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$c1;
      }
      if (s0 === peg$FAILED) {
        s0 = peg$currPos;
        if (input.charCodeAt(peg$currPos) === 39) {
          s1 = peg$c85;
          peg$currPos++;
        } else {
          s1 = peg$FAILED;
          if (peg$silentFails === 0) {
            peg$fail(peg$c86);
          }
        }
        if (s1 !== peg$FAILED) {
          s2 = [];
          s3 = peg$parseSingleStringChar();
          while (s3 !== peg$FAILED) {
            s2.push(s3);
            s3 = peg$parseSingleStringChar();
          }
          if (s2 !== peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 39) {
              s3 = peg$c85;
              peg$currPos++;
            } else {
              s3 = peg$FAILED;
              if (peg$silentFails === 0) {
                peg$fail(peg$c86);
              }
            }
            if (s3 !== peg$FAILED) {
              peg$reportedPos = s0;
              s1 = peg$c84(s2);
              s0 = s1;
            } else {
              peg$currPos = s0;
              s0 = peg$c1;
            }
          } else {
            peg$currPos = s0;
            s0 = peg$c1;
          }
        } else {
          peg$currPos = s0;
          s0 = peg$c1;
        }
        if (s0 === peg$FAILED) {
          s0 = peg$currPos;
          s1 = peg$currPos;
          peg$silentFails++;
          s2 = peg$parsecc();
          peg$silentFails--;
          if (s2 === peg$FAILED) {
            s1 = peg$c87;
          } else {
            peg$currPos = s1;
            s1 = peg$c1;
          }
          if (s1 !== peg$FAILED) {
            s2 = [];
            s3 = peg$parseUnquotedStringChar();
            if (s3 !== peg$FAILED) {
              while (s3 !== peg$FAILED) {
                s2.push(s3);
                s3 = peg$parseUnquotedStringChar();
              }
            } else {
              s2 = peg$c1;
            }
            if (s2 !== peg$FAILED) {
              peg$reportedPos = s0;
              s1 = peg$c84(s2);
              s0 = s1;
            } else {
              peg$currPos = s0;
              s0 = peg$c1;
            }
          } else {
            peg$currPos = s0;
            s0 = peg$c1;
          }
        }
      }
      peg$silentFails--;
      if (s0 === peg$FAILED) {
        s1 = peg$FAILED;
        if (peg$silentFails === 0) {
          peg$fail(peg$c81);
        }
      }

      return s0;
    }

    function peg$parseDoubleStringChar() {
      var s0, s1, s2;

      s0 = peg$currPos;
      s1 = peg$currPos;
      peg$silentFails++;
      if (peg$c88.test(input.charAt(peg$currPos))) {
        s2 = input.charAt(peg$currPos);
        peg$currPos++;
      } else {
        s2 = peg$FAILED;
        if (peg$silentFails === 0) {
          peg$fail(peg$c89);
        }
      }
      peg$silentFails--;
      if (s2 === peg$FAILED) {
        s1 = peg$c87;
      } else {
        peg$currPos = s1;
        s1 = peg$c1;
      }
      if (s1 !== peg$FAILED) {
        if (input.length > peg$currPos) {
          s2 = input.charAt(peg$currPos);
          peg$currPos++;
        } else {
          s2 = peg$FAILED;
          if (peg$silentFails === 0) {
            peg$fail(peg$c90);
          }
        }
        if (s2 !== peg$FAILED) {
          peg$reportedPos = s0;
          s1 = peg$c91(s2);
          s0 = s1;
        } else {
          peg$currPos = s0;
          s0 = peg$c1;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$c1;
      }
      if (s0 === peg$FAILED) {
        s0 = peg$currPos;
        if (input.charCodeAt(peg$currPos) === 92) {
          s1 = peg$c92;
          peg$currPos++;
        } else {
          s1 = peg$FAILED;
          if (peg$silentFails === 0) {
            peg$fail(peg$c93);
          }
        }
        if (s1 !== peg$FAILED) {
          s2 = peg$parseEscapeSequence();
          if (s2 !== peg$FAILED) {
            peg$reportedPos = s0;
            s1 = peg$c91(s2);
            s0 = s1;
          } else {
            peg$currPos = s0;
            s0 = peg$c1;
          }
        } else {
          peg$currPos = s0;
          s0 = peg$c1;
        }
      }

      return s0;
    }

    function peg$parseSingleStringChar() {
      var s0, s1, s2;

      s0 = peg$currPos;
      s1 = peg$currPos;
      peg$silentFails++;
      if (peg$c94.test(input.charAt(peg$currPos))) {
        s2 = input.charAt(peg$currPos);
        peg$currPos++;
      } else {
        s2 = peg$FAILED;
        if (peg$silentFails === 0) {
          peg$fail(peg$c95);
        }
      }
      peg$silentFails--;
      if (s2 === peg$FAILED) {
        s1 = peg$c87;
      } else {
        peg$currPos = s1;
        s1 = peg$c1;
      }
      if (s1 !== peg$FAILED) {
        if (input.length > peg$currPos) {
          s2 = input.charAt(peg$currPos);
          peg$currPos++;
        } else {
          s2 = peg$FAILED;
          if (peg$silentFails === 0) {
            peg$fail(peg$c90);
          }
        }
        if (s2 !== peg$FAILED) {
          peg$reportedPos = s0;
          s1 = peg$c91(s2);
          s0 = s1;
        } else {
          peg$currPos = s0;
          s0 = peg$c1;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$c1;
      }
      if (s0 === peg$FAILED) {
        s0 = peg$currPos;
        if (input.charCodeAt(peg$currPos) === 92) {
          s1 = peg$c92;
          peg$currPos++;
        } else {
          s1 = peg$FAILED;
          if (peg$silentFails === 0) {
            peg$fail(peg$c93);
          }
        }
        if (s1 !== peg$FAILED) {
          s2 = peg$parseEscapeSequence();
          if (s2 !== peg$FAILED) {
            peg$reportedPos = s0;
            s1 = peg$c91(s2);
            s0 = s1;
          } else {
            peg$currPos = s0;
            s0 = peg$c1;
          }
        } else {
          peg$currPos = s0;
          s0 = peg$c1;
        }
      }

      return s0;
    }

    function peg$parseUnquotedStringChar() {
      var s0, s1, s2;

      s0 = peg$currPos;
      s1 = peg$currPos;
      peg$silentFails++;
      s2 = peg$parsews();
      peg$silentFails--;
      if (s2 === peg$FAILED) {
        s1 = peg$c87;
      } else {
        peg$currPos = s1;
        s1 = peg$c1;
      }
      if (s1 !== peg$FAILED) {
        if (input.length > peg$currPos) {
          s2 = input.charAt(peg$currPos);
          peg$currPos++;
        } else {
          s2 = peg$FAILED;
          if (peg$silentFails === 0) {
            peg$fail(peg$c90);
          }
        }
        if (s2 !== peg$FAILED) {
          peg$reportedPos = s0;
          s1 = peg$c91(s2);
          s0 = s1;
        } else {
          peg$currPos = s0;
          s0 = peg$c1;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$c1;
      }

      return s0;
    }

    function peg$parseEscapeSequence() {
      var s0, s1;

      if (peg$c96.test(input.charAt(peg$currPos))) {
        s0 = input.charAt(peg$currPos);
        peg$currPos++;
      } else {
        s0 = peg$FAILED;
        if (peg$silentFails === 0) {
          peg$fail(peg$c97);
        }
      }
      if (s0 === peg$FAILED) {
        s0 = peg$currPos;
        if (input.charCodeAt(peg$currPos) === 110) {
          s1 = peg$c98;
          peg$currPos++;
        } else {
          s1 = peg$FAILED;
          if (peg$silentFails === 0) {
            peg$fail(peg$c99);
          }
        }
        if (s1 !== peg$FAILED) {
          peg$reportedPos = s0;
          s1 = peg$c100();
        }
        s0 = s1;
        if (s0 === peg$FAILED) {
          s0 = peg$currPos;
          if (input.charCodeAt(peg$currPos) === 114) {
            s1 = peg$c101;
            peg$currPos++;
          } else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
              peg$fail(peg$c102);
            }
          }
          if (s1 !== peg$FAILED) {
            peg$reportedPos = s0;
            s1 = peg$c103();
          }
          s0 = s1;
          if (s0 === peg$FAILED) {
            s0 = peg$currPos;
            if (input.charCodeAt(peg$currPos) === 116) {
              s1 = peg$c104;
              peg$currPos++;
            } else {
              s1 = peg$FAILED;
              if (peg$silentFails === 0) {
                peg$fail(peg$c105);
              }
            }
            if (s1 !== peg$FAILED) {
              peg$reportedPos = s0;
              s1 = peg$c106();
            }
            s0 = s1;
          }
        }
      }

      return s0;
    }

    var flowutils = require("../flow/utils.js");

    function or(first, second) {
      // Add explicit function names to ease debugging.
      function orFilter() {
        return first.apply(this, arguments) || second.apply(this, arguments);
      }
      orFilter.desc = first.desc + " or " + second.desc;
      return orFilter;
    }
    function and(first, second) {
      function andFilter() {
        return first.apply(this, arguments) && second.apply(this, arguments);
      }
      andFilter.desc = first.desc + " and " + second.desc;
      return andFilter;
    }
    function not(expr) {
      function notFilter() {
        return !expr.apply(this, arguments);
      }
      notFilter.desc = "not " + expr.desc;
      return notFilter;
    }
    function binding(expr) {
      function bindingFilter() {
        return expr.apply(this, arguments);
      }
      bindingFilter.desc = "(" + expr.desc + ")";
      return bindingFilter;
    }
    function trueFilter(flow) {
      return true;
    }
    trueFilter.desc = "true";
    function falseFilter(flow) {
      return false;
    }
    falseFilter.desc = "false";

    var ASSET_TYPES = [new RegExp("text/javascript"), new RegExp("application/x-javascript"), new RegExp("application/javascript"), new RegExp("text/css"), new RegExp("image/.*"), new RegExp("application/x-shockwave-flash")];
    function assetFilter(flow) {
      if (flow.response) {
        var ct = flowutils.ResponseUtils.getContentType(flow.response);
        var i = ASSET_TYPES.length;
        while (i--) {
          if (ASSET_TYPES[i].test(ct)) {
            return true;
          }
        }
      }
      return false;
    }
    assetFilter.desc = "is asset";
    function responseCode(code) {
      function responseCodeFilter(flow) {
        return flow.response && flow.response.status_code === code;
      }
      responseCodeFilter.desc = "resp. code is " + code;
      return responseCodeFilter;
    }
    function domain(regex) {
      regex = new RegExp(regex, "i");
      function domainFilter(flow) {
        return flow.request && regex.test(flow.request.host);
      }
      domainFilter.desc = "domain matches " + regex;
      return domainFilter;
    }
    function errorFilter(flow) {
      return !!flow.error;
    }
    errorFilter.desc = "has error";
    function header(regex) {
      regex = new RegExp(regex, "i");
      function headerFilter(flow) {
        return flow.request && flowutils.RequestUtils.match_header(flow.request, regex) || flow.response && flowutils.ResponseUtils.match_header(flow.response, regex);
      }
      headerFilter.desc = "header matches " + regex;
      return headerFilter;
    }
    function requestHeader(regex) {
      regex = new RegExp(regex, "i");
      function requestHeaderFilter(flow) {
        return flow.request && flowutils.RequestUtils.match_header(flow.request, regex);
      }
      requestHeaderFilter.desc = "req. header matches " + regex;
      return requestHeaderFilter;
    }
    function responseHeader(regex) {
      regex = new RegExp(regex, "i");
      function responseHeaderFilter(flow) {
        return flow.response && flowutils.ResponseUtils.match_header(flow.response, regex);
      }
      responseHeaderFilter.desc = "resp. header matches " + regex;
      return responseHeaderFilter;
    }
    function method(regex) {
      regex = new RegExp(regex, "i");
      function methodFilter(flow) {
        return flow.request && regex.test(flow.request.method);
      }
      methodFilter.desc = "method matches " + regex;
      return methodFilter;
    }
    function noResponseFilter(flow) {
      return flow.request && !flow.response;
    }
    noResponseFilter.desc = "has no response";
    function responseFilter(flow) {
      return !!flow.response;
    }
    responseFilter.desc = "has response";

    function contentType(regex) {
      regex = new RegExp(regex, "i");
      function contentTypeFilter(flow) {
        return flow.request && regex.test(flowutils.RequestUtils.getContentType(flow.request)) || flow.response && regex.test(flowutils.ResponseUtils.getContentType(flow.response));
      }
      contentTypeFilter.desc = "content type matches " + regex;
      return contentTypeFilter;
    }
    function requestContentType(regex) {
      regex = new RegExp(regex, "i");
      function requestContentTypeFilter(flow) {
        return flow.request && regex.test(flowutils.RequestUtils.getContentType(flow.request));
      }
      requestContentTypeFilter.desc = "req. content type matches " + regex;
      return requestContentTypeFilter;
    }
    function responseContentType(regex) {
      regex = new RegExp(regex, "i");
      function responseContentTypeFilter(flow) {
        return flow.response && regex.test(flowutils.ResponseUtils.getContentType(flow.response));
      }
      responseContentTypeFilter.desc = "resp. content type matches " + regex;
      return responseContentTypeFilter;
    }
    function url(regex) {
      regex = new RegExp(regex, "i");
      function urlFilter(flow) {
        return flow.request && regex.test(flowutils.RequestUtils.pretty_url(flow.request));
      }
      urlFilter.desc = "url matches " + regex;
      return urlFilter;
    }

    peg$result = peg$startRuleFunction();

    if (peg$result !== peg$FAILED && peg$currPos === input.length) {
      return peg$result;
    } else {
      if (peg$result !== peg$FAILED && peg$currPos < input.length) {
        peg$fail({ type: "end", description: "end of input" });
      }

      throw peg$buildException(null, peg$maxFailExpected, peg$maxFailPos);
    }
  }

  return {
    SyntaxError: SyntaxError,
    parse: parse
  };
})();


},{"../flow/utils.js":23}],23:[function(require,module,exports){
"use strict";

var _ = require("lodash");
var $ = require("jquery");

var defaultPorts = {
    "http": 80,
    "https": 443
};

var MessageUtils = {
    getContentType: function getContentType(message) {
        var ct = this.get_first_header(message, /^Content-Type$/i);
        if (ct) {
            return ct.split(";")[0].trim();
        }
    },
    get_first_header: function get_first_header(message, regex) {
        //FIXME: Cache Invalidation.
        if (!message._headerLookups) Object.defineProperty(message, "_headerLookups", {
            value: {},
            configurable: false,
            enumerable: false,
            writable: false
        });
        if (!(regex in message._headerLookups)) {
            var header;
            for (var i = 0; i < message.headers.length; i++) {
                if (!!message.headers[i][0].match(regex)) {
                    header = message.headers[i];
                    break;
                }
            }
            message._headerLookups[regex] = header ? header[1] : undefined;
        }
        return message._headerLookups[regex];
    },
    match_header: function match_header(message, regex) {
        var headers = message.headers;
        var i = headers.length;
        while (i--) {
            if (regex.test(headers[i].join(" "))) {
                return headers[i];
            }
        }
        return false;
    },
    getContentURL: function getContentURL(flow, message) {
        if (message === flow.request) {
            message = "request";
        } else if (message === flow.response) {
            message = "response";
        }
        return "/flows/" + flow.id + "/" + message + "/content";
    },
    getContent: function getContent(flow, message) {
        var url = MessageUtils.getContentURL(flow, message);
        return $.get(url);
    }
};

var RequestUtils = _.extend(MessageUtils, {
    pretty_host: function pretty_host(request) {
        //FIXME: Add hostheader
        return request.host;
    },
    pretty_url: function pretty_url(request) {
        var port = "";
        if (defaultPorts[request.scheme] !== request.port) {
            port = ":" + request.port;
        }
        return request.scheme + "://" + this.pretty_host(request) + port + request.path;
    }
});

var ResponseUtils = _.extend(MessageUtils, {});

var parseUrl_regex = /^(?:(https?):\/\/)?([^\/:]+)?(?::(\d+))?(\/.*)?$/i;
var parseUrl = function parseUrl(url) {
    //there are many correct ways to parse a URL,
    //however, a mitmproxy user may also wish to generate a not-so-correct URL. ;-)
    var parts = parseUrl_regex.exec(url);
    if (!parts) {
        return false;
    }

    var scheme = parts[1],
        host = parts[2],
        port = parseInt(parts[3]),
        path = parts[4];
    if (scheme) {
        port = port || defaultPorts[scheme];
    }
    var ret = {};
    if (scheme) {
        ret.scheme = scheme;
    }
    if (host) {
        ret.host = host;
    }
    if (port) {
        ret.port = port;
    }
    if (path) {
        ret.path = path;
    }
    return ret;
};

var isValidHttpVersion_regex = /^HTTP\/\d+(\.\d+)*$/i;
var isValidHttpVersion = function isValidHttpVersion(httpVersion) {
    return isValidHttpVersion_regex.test(httpVersion);
};

var parseHttpVersion = function parseHttpVersion(httpVersion) {
    httpVersion = httpVersion.replace("HTTP/", "").split(".");
    return _.map(httpVersion, function (x) {
        return parseInt(x);
    });
};

module.exports = {
    ResponseUtils: ResponseUtils,
    RequestUtils: RequestUtils,
    MessageUtils: MessageUtils,
    parseUrl: parseUrl,
    parseHttpVersion: parseHttpVersion,
    isValidHttpVersion: isValidHttpVersion
};


},{"jquery":"jquery","lodash":"lodash"}],24:[function(require,module,exports){
"use strict";

var _ = require("lodash");
var $ = require("jquery");
var EventEmitter = require('events').EventEmitter;

var utils = require("../utils.js");
var actions = require("../actions.js");
var dispatcher = require("../dispatcher.js");

function ListStore() {
    EventEmitter.call(this);
    this.reset();
}
_.extend(ListStore.prototype, EventEmitter.prototype, {
    add: function add(elem) {
        if (elem.id in this._pos_map) {
            return;
        }
        this._pos_map[elem.id] = this.list.length;
        this.list.push(elem);
        this.emit("add", elem);
    },
    update: function update(elem) {
        if (!(elem.id in this._pos_map)) {
            return;
        }
        this.list[this._pos_map[elem.id]] = elem;
        this.emit("update", elem);
    },
    remove: function remove(elem_id) {
        if (!(elem_id in this._pos_map)) {
            return;
        }
        this.list.splice(this._pos_map[elem_id], 1);
        this._build_map();
        this.emit("remove", elem_id);
    },
    reset: function reset(elems) {
        this.list = elems || [];
        this._build_map();
        this.emit("recalculate");
    },
    _build_map: function _build_map() {
        this._pos_map = {};
        for (var i = 0; i < this.list.length; i++) {
            var elem = this.list[i];
            this._pos_map[elem.id] = i;
        }
    },
    get: function get(elem_id) {
        return this.list[this._pos_map[elem_id]];
    },
    index: function index(elem_id) {
        return this._pos_map[elem_id];
    }
});

function DictStore() {
    EventEmitter.call(this);
    this.reset();
}
_.extend(DictStore.prototype, EventEmitter.prototype, {
    update: function update(dict) {
        _.merge(this.dict, dict);
        this.emit("recalculate");
    },
    reset: function reset(dict) {
        this.dict = dict || {};
        this.emit("recalculate");
    }
});

function LiveStoreMixin(type) {
    this.type = type;

    this._updates_before_fetch = undefined;
    this._fetchxhr = false;

    this.handle = this.handle.bind(this);
    dispatcher.AppDispatcher.register(this.handle);

    // Avoid double-fetch on startup.
    if (!(window.ws && window.ws.readyState === WebSocket.CONNECTING)) {
        this.fetch();
    }
}
_.extend(LiveStoreMixin.prototype, {
    handle: function handle(event) {
        if (event.type === actions.ActionTypes.CONNECTION_OPEN) {
            return this.fetch();
        }
        if (event.type === this.type) {
            if (event.cmd === actions.StoreCmds.RESET) {
                this.fetch(event.data);
            } else if (this._updates_before_fetch) {
                console.log("defer update", event);
                this._updates_before_fetch.push(event);
            } else {
                this[event.cmd](event.data);
            }
        }
    },
    close: function close() {
        dispatcher.AppDispatcher.unregister(this.handle);
    },
    fetch: function fetch(data) {
        console.log("fetch " + this.type);
        if (this._fetchxhr) {
            this._fetchxhr.abort();
        }
        this._updates_before_fetch = []; // (JS: empty array is true)
        if (data) {
            this.handle_fetch(data);
        } else {
            this._fetchxhr = $.getJSON("/" + this.type).done((function (message) {
                this.handle_fetch(message.data);
            }).bind(this)).fail((function () {
                EventLogActions.add_event("Could not fetch " + this.type);
            }).bind(this));
        }
    },
    handle_fetch: function handle_fetch(data) {
        this._fetchxhr = false;
        console.log(this.type + " fetched.", this._updates_before_fetch);
        this.reset(data);
        var updates = this._updates_before_fetch;
        this._updates_before_fetch = false;
        for (var i = 0; i < updates.length; i++) {
            this.handle(updates[i]);
        }
    }
});

function LiveListStore(type) {
    ListStore.call(this);
    LiveStoreMixin.call(this, type);
}
_.extend(LiveListStore.prototype, ListStore.prototype, LiveStoreMixin.prototype);

function LiveDictStore(type) {
    DictStore.call(this);
    LiveStoreMixin.call(this, type);
}
_.extend(LiveDictStore.prototype, DictStore.prototype, LiveStoreMixin.prototype);

function FlowStore() {
    return new LiveListStore(actions.ActionTypes.FLOW_STORE);
}

function SettingsStore() {
    return new LiveDictStore(actions.ActionTypes.SETTINGS_STORE);
}

function EventLogStore() {
    LiveListStore.call(this, actions.ActionTypes.EVENT_STORE);
}
_.extend(EventLogStore.prototype, LiveListStore.prototype, {
    fetch: function fetch() {
        LiveListStore.prototype.fetch.apply(this, arguments);

        // Make sure to display updates even if fetching all events failed.
        // This way, we can send "fetch failed" log messages to the log.
        if (this._fetchxhr) {
            this._fetchxhr.fail((function () {
                this.handle_fetch(null);
            }).bind(this));
        }
    }
});

module.exports = {
    EventLogStore: EventLogStore,
    SettingsStore: SettingsStore,
    FlowStore: FlowStore
};


},{"../actions.js":2,"../dispatcher.js":21,"../utils.js":26,"events":1,"jquery":"jquery","lodash":"lodash"}],25:[function(require,module,exports){
"use strict";

var EventEmitter = require('events').EventEmitter;
var _ = require("lodash");

var utils = require("../utils.js");

function SortByStoreOrder(elem) {
    return this.store.index(elem.id);
}

var default_sort = SortByStoreOrder;
var default_filt = function default_filt(elem) {
    return true;
};

function StoreView(store, filt, sortfun) {
    EventEmitter.call(this);

    this.store = store;

    this.add = this.add.bind(this);
    this.update = this.update.bind(this);
    this.remove = this.remove.bind(this);
    this.recalculate = this.recalculate.bind(this);
    this.store.addListener("add", this.add);
    this.store.addListener("update", this.update);
    this.store.addListener("remove", this.remove);
    this.store.addListener("recalculate", this.recalculate);

    this.recalculate(filt, sortfun);
}

_.extend(StoreView.prototype, EventEmitter.prototype, {
    close: function close() {
        this.store.removeListener("add", this.add);
        this.store.removeListener("update", this.update);
        this.store.removeListener("remove", this.remove);
        this.store.removeListener("recalculate", this.recalculate);
        this.removeAllListeners();
    },
    recalculate: function recalculate(filt, sortfun) {
        filt = filt || this.filt || default_filt;
        sortfun = sortfun || this.sortfun || default_sort;
        filt = filt.bind(this);
        sortfun = sortfun.bind(this);
        this.filt = filt;
        this.sortfun = sortfun;

        this.list = this.store.list.filter(filt);
        this.list.sort(function (a, b) {
            var akey = sortfun(a);
            var bkey = sortfun(b);
            if (akey < bkey) {
                return -1;
            } else if (akey > bkey) {
                return 1;
            } else {
                return 0;
            }
        });
        this.emit("recalculate");
    },
    index: function index(elem) {
        return _.sortedIndex(this.list, elem, this.sortfun);
    },
    add: function add(elem) {
        if (this.filt(elem)) {
            var idx = this.index(elem);
            if (idx === this.list.length) {
                //happens often, .push is way faster.
                this.list.push(elem);
            } else {
                this.list.splice(idx, 0, elem);
            }
            this.emit("add", elem, idx);
        }
    },
    update: function update(elem) {
        var idx;
        var i = this.list.length;
        // Search from the back, we usually update the latest entries.
        while (i--) {
            if (this.list[i].id === elem.id) {
                idx = i;
                break;
            }
        }

        if (idx === -1) {
            //not contained in list
            this.add(elem);
        } else if (!this.filt(elem)) {
            this.remove(elem.id);
        } else {
            if (this.sortfun(this.list[idx]) !== this.sortfun(elem)) {
                //sortpos has changed
                this.remove(this.list[idx]);
                this.add(elem);
            } else {
                this.list[idx] = elem;
                this.emit("update", elem, idx);
            }
        }
    },
    remove: function remove(elem_id) {
        var idx = this.list.length;
        while (idx--) {
            if (this.list[idx].id === elem_id) {
                this.list.splice(idx, 1);
                this.emit("remove", elem_id, idx);
                break;
            }
        }
    }
});

module.exports = {
    StoreView: StoreView
};


},{"../utils.js":26,"events":1,"lodash":"lodash"}],26:[function(require,module,exports){
"use strict";

var $ = require("jquery");
var _ = require("lodash");
var actions = require("./actions.js");

window.$ = $;
window._ = _;
window.React = require("react");

var Key = {
    UP: 38,
    DOWN: 40,
    PAGE_UP: 33,
    PAGE_DOWN: 34,
    HOME: 36,
    END: 35,
    LEFT: 37,
    RIGHT: 39,
    ENTER: 13,
    ESC: 27,
    TAB: 9,
    SPACE: 32,
    BACKSPACE: 8,
    SHIFT: 16
};
// Add A-Z
for (var i = 65; i <= 90; i++) {
    Key[String.fromCharCode(i)] = i;
}

var formatSize = function formatSize(bytes) {
    if (bytes === 0) return "0";
    var prefix = ["b", "kb", "mb", "gb", "tb"];
    for (var i = 0; i < prefix.length; i++) {
        if (Math.pow(1024, i + 1) > bytes) {
            break;
        }
    }
    var precision;
    if (bytes % Math.pow(1024, i) === 0) precision = 0;else precision = 1;
    return (bytes / Math.pow(1024, i)).toFixed(precision) + prefix[i];
};

var formatTimeDelta = function formatTimeDelta(milliseconds) {
    var time = milliseconds;
    var prefix = ["ms", "s", "min", "h"];
    var div = [1000, 60, 60];
    var i = 0;
    while (Math.abs(time) >= div[i] && i < div.length) {
        time = time / div[i];
        i++;
    }
    return Math.round(time) + prefix[i];
};

var formatTimeStamp = function formatTimeStamp(seconds) {
    var ts = new Date(seconds * 1000).toISOString();
    return ts.replace("T", " ").replace("Z", "");
};

// At some places, we need to sort strings alphabetically descending,
// but we can only provide a key function.
// This beauty "reverses" a JS string.
var end = String.fromCharCode(0xffff);
function reverseString(s) {
    return String.fromCharCode.apply(String, _.map(s.split(""), function (c) {
        return 0xffff - c.charCodeAt(0);
    })) + end;
}

function getCookie(name) {
    var r = document.cookie.match(new RegExp("\\b" + name + "=([^;]*)\\b"));
    return r ? r[1] : undefined;
}
var xsrf = $.param({ _xsrf: getCookie("_xsrf") });

//Tornado XSRF Protection.
$.ajaxPrefilter(function (options) {
    if (["post", "put", "delete"].indexOf(options.type.toLowerCase()) >= 0 && options.url[0] === "/") {
        if (options.url.indexOf("?") === -1) {
            options.url += "?" + xsrf;
        } else {
            options.url += "&" + xsrf;
        }
    }
});
// Log AJAX Errors
$(document).ajaxError(function (event, jqXHR, ajaxSettings, thrownError) {
    if (thrownError === "abort") {
        return;
    }
    var message = jqXHR.responseText;
    console.error(thrownError, message, arguments);
    actions.EventLogActions.add_event(thrownError + ": " + message);
    alert(message);
});

module.exports = {
    formatSize: formatSize,
    formatTimeDelta: formatTimeDelta,
    formatTimeStamp: formatTimeStamp,
    reverseString: reverseString,
    Key: Key
};


},{"./actions.js":2,"jquery":"jquery","lodash":"lodash","react":"react"}]},{},[3])


//# sourceMappingURL=app.js.map
