mitmproxy/libmproxy/web/static/js/app.js
2014-12-25 02:03:55 +01:00

4144 lines
125 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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,
};
// Add A-Z
for (var i = 65; i <= 90; i++) {
Key[String.fromCharCode(i)] = i;
}
var formatSize = function (bytes) {
var size = bytes;
var prefix = ["B", "KB", "MB", "GB", "TB"];
var i = 0;
while (Math.abs(size) >= 1024 && i < prefix.length - 1) {
i++;
size = size / 1024;
}
return (Math.floor(size * 100) / 100.0).toFixed(2) + prefix[i];
};
var formatTimeDelta = function (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 (seconds) {
var ts = (new Date(seconds * 1000)).toISOString();
return ts.replace("T", " ").replace("Z", "");
};
function EventEmitter() {
this.listeners = {};
}
EventEmitter.prototype.emit = function (event) {
if (!(event in this.listeners)) {
return;
}
var args = Array.prototype.slice.call(arguments, 1);
this.listeners[event].forEach(function (listener) {
listener.apply(this, args);
}.bind(this));
};
EventEmitter.prototype.addListener = function (events, f) {
events.split(" ").forEach(function (event) {
this.listeners[event] = this.listeners[event] || [];
this.listeners[event].push(f);
}.bind(this));
};
EventEmitter.prototype.removeListener = function (events, f) {
if (!(events in this.listeners)) {
return false;
}
events.split(" ").forEach(function (event) {
var index = this.listeners[event].indexOf(f);
if (index >= 0) {
this.listeners[event].splice(index, 1);
}
}.bind(this));
};
function getCookie(name) {
var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
return r ? r[1] : undefined;
}
var xsrf = $.param({_xsrf: getCookie("_xsrf")});
//Tornado XSRF Protection.
jQuery.ajaxPrefilter(function (options) {
if (["post", "put", "delete"].indexOf(options.type.toLowerCase()) >= 0 && options.url[0] === "/") {
if (options.data) {
options.data += ("&" + xsrf);
} else {
options.data = xsrf;
}
}
});
// Log AJAX Errors
$(document).ajaxError(function (event, jqXHR, ajaxSettings, thrownError) {
var message = jqXHR.responseText;
console.error(message, arguments);
EventLogActions.add_event(thrownError + ": " + message);
window.alert(message);
});
const PayloadSources = {
VIEW: "view",
SERVER: "server"
};
function Dispatcher() {
this.callbacks = [];
}
Dispatcher.prototype.register = function (callback) {
this.callbacks.push(callback);
};
Dispatcher.prototype.unregister = function (callback) {
var index = this.callbacks.indexOf(callback);
if (index >= 0) {
this.callbacks.splice(index, 1);
}
};
Dispatcher.prototype.dispatch = function (payload) {
console.debug("dispatch", payload);
for (var i = 0; i < this.callbacks.length; i++) {
this.callbacks[i](payload);
}
};
AppDispatcher = new Dispatcher();
AppDispatcher.dispatchViewAction = function (action) {
action.source = PayloadSources.VIEW;
this.dispatch(action);
};
AppDispatcher.dispatchServerAction = function (action) {
action.source = PayloadSources.SERVER;
this.dispatch(action);
};
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 () {
AppDispatcher.dispatchViewAction({
type: ActionTypes.CONNECTION_OPEN
});
},
close: function () {
AppDispatcher.dispatchViewAction({
type: ActionTypes.CONNECTION_CLOSE
});
},
error: function () {
AppDispatcher.dispatchViewAction({
type: ActionTypes.CONNECTION_ERROR
});
}
};
var SettingsActions = {
update: function (settings) {
jQuery.ajax({
type: "PUT",
url: "/settings",
data: 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 (message) {
AppDispatcher.dispatchViewAction({
type: ActionTypes.EVENT_STORE,
cmd: StoreCmds.ADD,
data: {
message: message,
level: "web",
id: "viewAction-" + EventLogActions_event_id++
}
});
}
};
var FlowActions = {
accept: function (flow) {
jQuery.post("/flows/" + flow.id + "/accept");
},
accept_all: function(){
jQuery.post("/flows/accept");
},
"delete": function(flow){
jQuery.ajax({
type:"DELETE",
url: "/flows/" + flow.id
});
},
duplicate: function(flow){
jQuery.post("/flows/" + flow.id + "/duplicate");
},
replay: function(flow){
jQuery.post("/flows/" + flow.id + "/replay");
},
update: function (flow) {
AppDispatcher.dispatchViewAction({
type: ActionTypes.FLOW_STORE,
cmd: StoreCmds.UPDATE,
data: flow
});
},
clear: function(){
jQuery.post("/clear");
}
};
Query = {
FILTER: "f",
HIGHLIGHT: "h",
SHOW_EVENTLOG: "e"
};
Filt = (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(orExpr) { return orExpr; },
peg$c3 = [],
peg$c4 = function() {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(first, second) { return or(first, second); },
peg$c15 = "&",
peg$c16 = { type: "literal", value: "&", description: "\"&\"" },
peg$c17 = function(first, second) { return and(first, second); },
peg$c18 = "!",
peg$c19 = { type: "literal", value: "!", description: "\"!\"" },
peg$c20 = function(expr) { return not(expr); },
peg$c21 = "(",
peg$c22 = { type: "literal", value: "(", description: "\"(\"" },
peg$c23 = ")",
peg$c24 = { type: "literal", value: ")", description: "\")\"" },
peg$c25 = function(expr) { return binding(expr); },
peg$c26 = "~a",
peg$c27 = { type: "literal", value: "~a", description: "\"~a\"" },
peg$c28 = function() { return assetFilter; },
peg$c29 = "~e",
peg$c30 = { type: "literal", value: "~e", description: "\"~e\"" },
peg$c31 = function() { return errorFilter; },
peg$c32 = "~q",
peg$c33 = { type: "literal", value: "~q", description: "\"~q\"" },
peg$c34 = function() { return noResponseFilter; },
peg$c35 = "~s",
peg$c36 = { type: "literal", value: "~s", description: "\"~s\"" },
peg$c37 = function() { return responseFilter; },
peg$c38 = "true",
peg$c39 = { type: "literal", value: "true", description: "\"true\"" },
peg$c40 = function() { return trueFilter; },
peg$c41 = "false",
peg$c42 = { type: "literal", value: "false", description: "\"false\"" },
peg$c43 = function() { return falseFilter; },
peg$c44 = "~c",
peg$c45 = { type: "literal", value: "~c", description: "\"~c\"" },
peg$c46 = function(s) { return responseCode(s); },
peg$c47 = "~d",
peg$c48 = { type: "literal", value: "~d", description: "\"~d\"" },
peg$c49 = function(s) { return domain(s); },
peg$c50 = "~h",
peg$c51 = { type: "literal", value: "~h", description: "\"~h\"" },
peg$c52 = function(s) { return header(s); },
peg$c53 = "~hq",
peg$c54 = { type: "literal", value: "~hq", description: "\"~hq\"" },
peg$c55 = function(s) { return requestHeader(s); },
peg$c56 = "~hs",
peg$c57 = { type: "literal", value: "~hs", description: "\"~hs\"" },
peg$c58 = function(s) { return responseHeader(s); },
peg$c59 = "~m",
peg$c60 = { type: "literal", value: "~m", description: "\"~m\"" },
peg$c61 = function(s) { return method(s); },
peg$c62 = "~t",
peg$c63 = { type: "literal", value: "~t", description: "\"~t\"" },
peg$c64 = function(s) { return contentType(s); },
peg$c65 = "~tq",
peg$c66 = { type: "literal", value: "~tq", description: "\"~tq\"" },
peg$c67 = function(s) { return requestContentType(s); },
peg$c68 = "~ts",
peg$c69 = { type: "literal", value: "~ts", description: "\"~ts\"" },
peg$c70 = function(s) { return responseContentType(s); },
peg$c71 = "~u",
peg$c72 = { type: "literal", value: "~u", description: "\"~u\"" },
peg$c73 = function(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(digits) { return parseInt(digits.join(""), 10); },
peg$c81 = { type: "other", description: "string" },
peg$c82 = "\"",
peg$c83 = { type: "literal", value: "\"", description: "\"\\\"\"" },
peg$c84 = function(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(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() { return "\n"; },
peg$c101 = "r",
peg$c102 = { type: "literal", value: "r", description: "\"r\"" },
peg$c103 = function() { return "\r"; },
peg$c104 = "t",
peg$c105 = { type: "literal", value: "t", description: "\"t\"" },
peg$c106 = function() { 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;
}
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 = 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.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 && RequestUtils.match_header(flow.request, regex))
||
(flow.response && 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 && 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 && 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(RequestUtils.getContentType(flow.request)))
||
(flow.response && regex.test(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(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(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(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
};
})();
var _MessageUtils = {
getContentType: function (message) {
return this.get_first_header(message, /^Content-Type$/i);
},
get_first_header: function (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 (message, regex) {
var headers = message.headers;
var i = headers.length;
while (i--) {
if (regex.test(headers[i].join(" "))) {
return headers[i];
}
}
return false;
}
};
var defaultPorts = {
"http": 80,
"https": 443
};
var RequestUtils = _.extend(_MessageUtils, {
pretty_host: function (request) {
//FIXME: Add hostheader
return request.host;
},
pretty_url: function (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, {});
function ListStore() {
EventEmitter.call(this);
this.reset();
}
_.extend(ListStore.prototype, EventEmitter.prototype, {
add: function (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 (elem) {
if (!(elem.id in this._pos_map)) {
return;
}
this.list[this._pos_map[elem.id]] = elem;
this.emit("update", elem);
},
remove: function (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 (elems) {
this.list = elems || [];
this._build_map();
this.emit("recalculate");
},
_build_map: function () {
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 (elem_id) {
return this.list[this._pos_map[elem_id]];
},
index: function (elem_id) {
return this._pos_map[elem_id];
}
});
function DictStore() {
EventEmitter.call(this);
this.reset();
}
_.extend(DictStore.prototype, EventEmitter.prototype, {
update: function (dict) {
_.merge(this.dict, dict);
this.emit("recalculate");
},
reset: function (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);
AppDispatcher.register(this.handle);
// Avoid double-fetch on startup.
if (!(window.ws && window.ws.readyState === WebSocket.CONNECTING)) {
this.fetch();
}
}
_.extend(LiveStoreMixin.prototype, {
handle: function (event) {
if (event.type === ActionTypes.CONNECTION_OPEN) {
return this.fetch();
}
if (event.type === this.type) {
if (event.cmd === 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 () {
AppDispatcher.unregister(this.handle);
},
fetch: function (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 (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(ActionTypes.FLOW_STORE);
}
function SettingsStore() {
return new LiveDictStore(ActionTypes.SETTINGS_STORE);
}
function EventLogStore() {
LiveListStore.call(this, ActionTypes.EVENT_STORE);
}
_.extend(EventLogStore.prototype, LiveListStore.prototype, {
fetch: function(){
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));
}
}
});
function SortByStoreOrder(elem) {
return this.store.index(elem.id);
}
var default_sort = SortByStoreOrder;
var default_filt = function(elem){
return true;
};
function StoreView(store, filt, sortfun) {
EventEmitter.call(this);
filt = filt || default_filt;
sortfun = sortfun || default_sort;
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 () {
this.store.removeListener("add", this.add);
this.store.removeListener("update", this.update);
this.store.removeListener("remove", this.remove);
this.store.removeListener("recalculate", this.recalculate);
},
recalculate: function (filt, sortfun) {
if (filt) {
this.filt = filt.bind(this);
}
if (sortfun) {
this.sortfun = sortfun.bind(this);
}
this.list = this.store.list.filter(this.filt);
this.list.sort(function (a, b) {
return this.sortfun(a) - this.sortfun(b);
}.bind(this));
this.emit("recalculate");
},
index: function (elem) {
return _.sortedIndex(this.list, elem, this.sortfun);
},
add: function (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 (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 (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;
}
}
}
});
function Connection(url) {
if (url[0] === "/") {
url = location.origin.replace("http", "ws") + url;
}
var ws = new WebSocket(url);
ws.onopen = function () {
ConnectionActions.open();
};
ws.onmessage = function (message) {
var m = JSON.parse(message.data);
AppDispatcher.dispatchServerAction(m);
};
ws.onerror = function () {
ConnectionActions.error();
EventLogActions.add_event("WebSocket connection error.");
};
ws.onclose = function () {
ConnectionActions.close();
EventLogActions.add_event("WebSocket connection closed.");
};
return ws;
}
//React utils. For other utilities, see ../utils.js
// http://blog.vjeux.com/2013/javascript/scroll-position-with-react.html (also contains inverse example)
var AutoScrollMixin = {
componentWillUpdate: function () {
var node = this.getDOMNode();
this._shouldScrollBottom = (
node.scrollTop !== 0 &&
node.scrollTop + node.clientHeight === node.scrollHeight
);
},
componentDidUpdate: function () {
if (this._shouldScrollBottom) {
var node = this.getDOMNode();
node.scrollTop = node.scrollHeight;
}
},
};
var StickyHeadMixin = {
adjustHead: function () {
// 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 Navigation = _.extend({}, ReactRouter.Navigation, {
setQuery: function (dict) {
var q = this.context.getCurrentQuery();
for(var i in dict){
if(dict.hasOwnProperty(i)){
q[i] = dict[i] || undefined; //falsey values shall be removed.
}
}
q._ = "_"; // workaround for https://github.com/rackt/react-router/pull/599
this.replaceWith(this.context.getCurrentPath(), this.context.getCurrentParams(), q);
},
replaceWith: function(routeNameOrPath, params, query) {
if(routeNameOrPath === undefined){
routeNameOrPath = this.context.getCurrentPath();
}
if(params === undefined){
params = this.context.getCurrentParams();
}
if(query === undefined){
query = this.context.getCurrentQuery();
}
ReactRouter.Navigation.replaceWith.call(this, routeNameOrPath, params, query);
}
});
_.extend(Navigation.contextTypes, ReactRouter.State.contextTypes);
var State = _.extend({}, ReactRouter.State, {
getInitialState: function () {
this._query = this.context.getCurrentQuery();
this._queryWatches = [];
return null;
},
onQueryChange: function (key, callback) {
this._queryWatches.push({
key: key,
callback: callback
});
},
componentWillReceiveProps: function (nextProps, nextState) {
var q = this.context.getCurrentQuery();
for (var i = 0; i < this._queryWatches.length; i++) {
var watch = this._queryWatches[i];
if (this._query[watch.key] !== q[watch.key]) {
watch.callback(this._query[watch.key], q[watch.key], watch.key);
}
}
this._query = q;
}
});
var Splitter = React.createClass({displayName: 'Splitter',
getDefaultProps: function () {
return {
axis: "x"
};
},
getInitialState: function () {
return {
applied: false,
startX: false,
startY: false
};
},
onMouseDown: function (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 () {
this.getDOMNode().style.transform = "";
window.removeEventListener("dragend", this.onDragEnd);
window.removeEventListener("mouseup", this.onMouseUp);
window.removeEventListener("mousemove", this.onMouseMove);
},
onMouseUp: function (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 (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 () {
// 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 (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 () {
this.reset(true);
},
render: function () {
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"})
)
);
}
});
var VirtualScrollMixin = {
getInitialState: function () {
return {
start: 0,
stop: 0
};
},
componentWillMount: function () {
if (!this.props.rowHeight) {
console.warn("VirtualScrollMixin: No rowHeight specified", this);
}
},
getPlaceholderTop: function (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 (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 () {
this.onScroll();
window.addEventListener('resize', this.onScroll);
},
componentWillUnmount: function(){
window.removeEventListener('resize', this.onScroll);
},
onScroll: function () {
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 (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 (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;
}
},
};
var FilterInput = React.createClass({displayName: 'FilterInput',
getInitialState: function () {
// 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 (nextProps) {
this.setState({value: nextProps.value});
},
onChange: function (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 (filt) {
try {
Filt.parse(filt || this.state.value);
return true;
} catch (e) {
return false;
}
},
getDesc: function () {
var desc;
try {
desc = Filt.parse(this.state.value).desc;
} catch (e) {
desc = "" + e;
}
if (desc !== "true") {
return desc;
} else {
return (
React.createElement("a", {href: "https://mitmproxy.org/doc/features/filters.html", target: "_blank"},
React.createElement("i", {className: "fa fa-external-link"}),
"Filter Documentation"
)
);
}
},
onFocus: function () {
this.setState({focus: true});
},
onBlur: function () {
this.setState({focus: false});
},
onMouseEnter: function () {
this.setState({mousefocus: true});
},
onMouseLeave: function () {
this.setState({mousefocus: false});
},
onKeyDown: function (e) {
if (e.keyCode === Key.ESC || e.keyCode === Key.ENTER) {
this.blur();
// If closed using ESC/ENTER, hide the tooltip.
this.setState({mousefocus: false});
}
},
blur: function () {
this.refs.input.getDOMNode().blur();
},
focus: function () {
this.refs.input.getDOMNode().select();
},
render: function () {
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: [Navigation, State],
statics: {
title: "Start",
route: "flows"
},
onFilterChange: function (val) {
var d = {};
d[Query.FILTER] = val;
this.setQuery(d);
},
onHighlightChange: function (val) {
var d = {};
d[Query.HIGHLIGHT] = val;
this.setQuery(d);
},
onInterceptChange: function (val) {
SettingsActions.update({intercept: val});
},
render: function () {
var filter = this.getQuery()[Query.FILTER] || "";
var highlight = this.getQuery()[Query.HIGHLIGHT] || "";
var intercept = this.props.settings.intercept || "";
return (
React.createElement("div", null,
React.createElement("form", {className: "form-inline", style: {display: "inline"}},
React.createElement(FilterInput, {
placeholder: "Filter",
type: "filter",
color: "black",
value: filter,
onChange: this.onFilterChange}),
React.createElement("span", null, " "),
React.createElement(FilterInput, {
placeholder: "Highlight",
type: "tag",
color: "hsl(48, 100%, 50%)",
value: highlight,
onChange: this.onHighlightChange}),
React.createElement("span", null, " "),
React.createElement(FilterInput, {
placeholder: "Intercept",
type: "pause",
color: "hsl(208, 56%, 53%)",
value: intercept,
onChange: this.onInterceptChange})
)
)
);
}
});
var ViewMenu = React.createClass({displayName: 'ViewMenu',
statics: {
title: "View",
route: "flows"
},
mixins: [Navigation, State],
toggleEventLog: function () {
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 () {
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 () {
return React.createElement("div", null, "Reports Menu");
}
});
var FileMenu = React.createClass({displayName: 'FileMenu',
getInitialState: function () {
return {
showFileMenu: false
};
},
handleFileClick: function (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 (e) {
e.preventDefault();
if (confirm("Delete all flows?")) {
FlowActions.clear();
}
},
handleOpenClick: function (e) {
e.preventDefault();
console.error("unimplemented: handleOpenClick");
},
handleSaveClick: function (e) {
e.preventDefault();
console.error("unimplemented: handleSaveClick");
},
handleShutdownClick: function (e) {
e.preventDefault();
console.error("unimplemented: handleShutdownClick");
},
render: function () {
var fileMenuClass = "dropdown pull-left" + (this.state.showFileMenu ? " open" : "");
return (
React.createElement("div", {className: fileMenuClass},
React.createElement("a", {href: "#", className: "special", onClick: this.handleFileClick}, " File "),
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-lock"}),
"Install Certificates..."
)
)
/*
<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>
*/
)
)
);
}
});
var header_entries = [MainMenu, ViewMenu /*, ReportsMenu */];
var Header = React.createClass({displayName: 'Header',
mixins: [Navigation],
getInitialState: function () {
return {
active: header_entries[0]
};
},
handleClick: function (active, e) {
e.preventDefault();
this.replaceWith(active.route);
this.setState({active: active});
},
render: function () {
var header = header_entries.map(function (entry, i) {
var classes = React.addons.classSet({
active: entry == this.state.active
});
return (
React.createElement("a", {key: i,
href: "#",
className: classes,
onClick: this.handleClick.bind(this, entry)
},
entry.title
)
);
}.bind(this));
return (
React.createElement("header", null,
React.createElement("div", {className: "title-bar"},
"mitmproxy ", this.props.settings.version
),
React.createElement("nav", {className: "nav-tabs nav-tabs-lg"},
React.createElement(FileMenu, null),
header
),
React.createElement("div", {className: "menu"},
React.createElement(this.state.active, {settings: this.props.settings})
)
)
);
}
});
var TLSColumn = React.createClass({displayName: 'TLSColumn',
statics: {
renderTitle: function () {
return React.createElement("th", {key: "tls", className: "col-tls"});
}
},
render: function () {
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: {
renderTitle: function () {
return React.createElement("th", {key: "icon", className: "col-icon"});
}
},
render: function () {
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.code == 304) {
icon = "resource-icon-not-modified";
} else if (300 <= flow.response.code && flow.response.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: {
renderTitle: function () {
return React.createElement("th", {key: "path", className: "col-path"}, "Path");
}
},
render: function () {
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,
flow.request.scheme + "://" + flow.request.host + flow.request.path
);
}
});
var MethodColumn = React.createClass({displayName: 'MethodColumn',
statics: {
renderTitle: function () {
return React.createElement("th", {key: "method", className: "col-method"}, "Method");
}
},
render: function () {
var flow = this.props.flow;
return React.createElement("td", {className: "col-method"}, flow.request.method);
}
});
var StatusColumn = React.createClass({displayName: 'StatusColumn',
statics: {
renderTitle: function () {
return React.createElement("th", {key: "status", className: "col-status"}, "Status");
}
},
render: function () {
var flow = this.props.flow;
var status;
if (flow.response) {
status = flow.response.code;
} else {
status = null;
}
return React.createElement("td", {className: "col-status"}, status);
}
});
var SizeColumn = React.createClass({displayName: 'SizeColumn',
statics: {
renderTitle: function () {
return React.createElement("th", {key: "size", className: "col-size"}, "Size");
}
},
render: function () {
var flow = this.props.flow;
var total = flow.request.contentLength;
if (flow.response) {
total += flow.response.contentLength || 0;
}
var size = formatSize(total);
return React.createElement("td", {className: "col-size"}, size);
}
});
var TimeColumn = React.createClass({displayName: 'TimeColumn',
statics: {
renderTitle: function () {
return React.createElement("th", {key: "time", className: "col-time"}, "Time");
}
},
render: function () {
var flow = this.props.flow;
var time;
if (flow.response) {
time = 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];
var FlowRow = React.createClass({displayName: 'FlowRow',
render: function () {
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 (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',
render: function () {
var columns = this.props.columns.map(function (column) {
return column.renderTitle();
}.bind(this));
return React.createElement("thead", null,
React.createElement("tr", null, columns)
);
}
});
var ROW_HEIGHT = 32;
var FlowTable = React.createClass({displayName: 'FlowTable',
mixins: [StickyHeadMixin, AutoScrollMixin, VirtualScrollMixin],
getInitialState: function () {
return {
columns: all_columns
};
},
componentWillMount: function () {
if (this.props.view) {
this.props.view.addListener("add update remove recalculate", this.onChange);
}
},
componentWillReceiveProps: function (nextProps) {
if (nextProps.view !== this.props.view) {
if (this.props.view) {
this.props.view.removeListener("add update remove recalculate");
}
nextProps.view.addListener("add update remove recalculate", this.onChange);
}
},
getDefaultProps: function () {
return {
rowHeight: ROW_HEIGHT
};
},
onScrollFlowTable: function () {
this.adjustHead();
this.onScroll();
},
onChange: function () {
this.forceUpdate();
},
scrollIntoView: function (flow) {
this.scrollRowIntoView(
this.props.view.index(flow),
this.refs.body.getDOMNode().offsetTop
);
},
renderRow: function (flow) {
var selected = (flow === this.props.selected);
var highlighted =
(
this.props.view._highlight &&
this.props.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 () {
//console.log("render flowtable", this.state.start, this.state.stop, this.props.selected);
var flows = this.props.view ? this.props.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}),
React.createElement("tbody", {ref: "body"},
this.getPlaceholderTop(flows.length),
rows,
this.getPlaceholderBottom(flows.length)
)
)
)
);
}
});
var DeleteButton = React.createClass({displayName: 'DeleteButton',
onClick: function (e) {
e.preventDefault();
FlowActions.delete(this.props.flow);
},
render: function () {
return (
React.createElement("a", {title: "[d]elete Flow",
href: "#",
className: "nav-action",
onClick: this.onClick},
React.createElement("i", {className: "fa fa-fw fa-trash"})
)
);
}
});
var DuplicateButton = React.createClass({displayName: 'DuplicateButton',
onClick: function (e) {
e.preventDefault();
FlowActions.duplicate(this.props.flow);
},
render: function () {
return (
React.createElement("a", {title: "[D]uplicate Flow",
href: "#",
className: "nav-action",
onClick: this.onClick},
React.createElement("i", {className: "fa fa-fw fa-edit"})
)
);
}
});
var ReplayButton = React.createClass({displayName: 'ReplayButton',
onClick: function (e) {
e.preventDefault();
FlowActions.replay(this.props.flow);
},
render: function () {
return (
React.createElement("a", {title: "[r]eplay Flow",
href: "#",
className: "nav-action",
onClick: this.onClick},
React.createElement("i", {className: "fa fa-fw fa-close"})
)
);
}
});
var AcceptButton = React.createClass({displayName: 'AcceptButton',
onClick: function (e) {
e.preventDefault();
FlowActions.accept(this.props.flow);
},
render: function () {
return (
React.createElement("a", {title: "[a]ccept (resume) Flow",
href: "#",
className: "nav-action",
onClick: this.onClick},
React.createElement("i", {className: "fa fa-fw fa-play"})
)
);
}
});
var FlowDetailNav = React.createClass({displayName: 'FlowDetailNav',
render: function () {
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));
return (
React.createElement("nav", {ref: "head", className: "nav-tabs nav-tabs-sm"},
tabs,
React.createElement(DeleteButton, {flow: flow}),
React.createElement(DuplicateButton, {flow: flow}),
React.createElement(ReplayButton, {flow: flow}),
flow.intercepted ? React.createElement(AcceptButton, {flow: this.props.flow}) : null
)
);
}
});
var Headers = React.createClass({displayName: 'Headers',
render: function () {
var rows = this.props.message.headers.map(function (header, i) {
return (
React.createElement("tr", {key: i},
React.createElement("td", {className: "header-name"}, header[0] + ":"),
React.createElement("td", {className: "header-value"}, header[1])
)
);
});
return (
React.createElement("table", {className: "header-table"},
React.createElement("tbody", null,
rows
)
)
);
}
});
var FlowDetailRequest = React.createClass({displayName: 'FlowDetailRequest',
render: function () {
var flow = this.props.flow;
var first_line = [
flow.request.method,
RequestUtils.pretty_url(flow.request),
"HTTP/" + flow.request.httpversion.join(".")
].join(" ");
var content = null;
if (flow.request.contentLength > 0) {
content = "Request Content Size: " + formatSize(flow.request.contentLength);
} else {
content = React.createElement("div", {className: "alert alert-info"}, "No Content");
}
//TODO: Styling
return (
React.createElement("section", null,
React.createElement("div", {className: "first-line"}, first_line ),
React.createElement(Headers, {message: flow.request}),
React.createElement("hr", null),
content
)
);
}
});
var FlowDetailResponse = React.createClass({displayName: 'FlowDetailResponse',
render: function () {
var flow = this.props.flow;
var first_line = [
"HTTP/" + flow.response.httpversion.join("."),
flow.response.code,
flow.response.msg
].join(" ");
var content = null;
if (flow.response.contentLength > 0) {
content = "Response Content Size: " + formatSize(flow.response.contentLength);
} else {
content = React.createElement("div", {className: "alert alert-info"}, "No Content");
}
//TODO: Styling
return (
React.createElement("section", null,
React.createElement("div", {className: "first-line"}, first_line ),
React.createElement(Headers, {message: flow.response}),
React.createElement("hr", null),
content
)
);
}
});
var FlowDetailError = React.createClass({displayName: 'FlowDetailError',
render: function () {
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, formatTimeStamp(flow.error.timestamp) )
)
)
)
);
}
});
var TimeStamp = React.createClass({displayName: 'TimeStamp',
render: function () {
if (!this.props.t) {
//should be return null, but that triggers a React bug.
return React.createElement("tr", null);
}
var ts = formatTimeStamp(this.props.t);
var delta;
if (this.props.deltaTo) {
delta = 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 () {
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 () {
//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 () {
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, React.__spread({}, e));
});
return (
React.createElement("div", null,
React.createElement("h4", null, "Timing"),
React.createElement("table", {className: "timing-table"},
React.createElement("tbody", null,
rows
)
)
)
);
}
});
var FlowDetailConnectionInfo = React.createClass({displayName: 'FlowDetailConnectionInfo',
render: function () {
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})
)
);
}
});
var allTabs = {
request: FlowDetailRequest,
response: FlowDetailResponse,
error: FlowDetailError,
details: FlowDetailConnectionInfo
};
var FlowDetail = React.createClass({displayName: 'FlowDetail',
mixins: [StickyHeadMixin, Navigation, State],
getTabs: function (flow) {
var tabs = [];
["request", "response", "error"].forEach(function (e) {
if (flow[e]) {
tabs.push(e);
}
});
tabs.push("details");
return tabs;
},
nextTab: function (i) {
var tabs = this.getTabs(this.props.flow);
var currentIndex = tabs.indexOf(this.getParams().detailTab);
// 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 (panel) {
this.replaceWith(
"flow",
{
flowId: this.getParams().flowId,
detailTab: panel
}
);
},
render: function () {
var flow = this.props.flow;
var tabs = this.getTabs(flow);
var active = this.getParams().detailTab;
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 Tab = allTabs[active];
return (
React.createElement("div", {className: "flow-detail", onScroll: this.adjustHead},
React.createElement(FlowDetailNav, {ref: "head",
flow: flow,
tabs: tabs,
active: active,
selectTab: this.selectTab}),
React.createElement(Tab, {flow: flow})
)
);
}
});
var MainView = React.createClass({displayName: 'MainView',
mixins: [Navigation, State],
getInitialState: function () {
this.onQueryChange(Query.FILTER, function () {
this.state.view.recalculate(this.getViewFilt(), this.getViewSort());
}.bind(this));
this.onQueryChange(Query.HIGHLIGHT, function () {
this.state.view.recalculate(this.getViewFilt(), this.getViewSort());
}.bind(this));
return {
flows: []
};
},
getViewFilt: function () {
try {
var filt = Filt.parse(this.getQuery()[Query.FILTER] || "");
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);
};
},
getViewSort: function () {
},
componentWillReceiveProps: function (nextProps) {
if (nextProps.flowStore !== this.props.flowStore) {
this.closeView();
this.openView(nextProps.flowStore);
}
},
openView: function (store) {
var view = new StoreView(store, this.getViewFilt(), this.getViewSort());
this.setState({
view: view
});
view.addListener("recalculate", this.onRecalculate);
view.addListener("add update remove", this.onUpdate);
view.addListener("remove", this.onRemove);
},
onRecalculate: function () {
this.forceUpdate();
var selected = this.getSelected();
if (selected) {
this.refs.flowTable.scrollIntoView(selected);
}
},
onUpdate: function (flow) {
if (flow.id === this.getParams().flowId) {
this.forceUpdate();
}
},
onRemove: function (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);
}
},
closeView: function () {
this.state.view.close();
},
componentWillMount: function () {
this.openView(this.props.flowStore);
},
componentWillUnmount: function () {
this.closeView();
},
selectFlow: function (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 (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]);
},
onKeyDown: function (e) {
var flow = this.getSelected();
if (e.ctrlKey) {
return;
}
switch (e.keyCode) {
case Key.K:
case Key.UP:
this.selectFlowRelative(-1);
break;
case Key.J:
case Key.DOWN:
this.selectFlowRelative(+1);
break;
case Key.SPACE:
case Key.PAGE_DOWN:
this.selectFlowRelative(+10);
break;
case Key.PAGE_UP:
this.selectFlowRelative(-10);
break;
case Key.END:
this.selectFlowRelative(+1e10);
break;
case Key.HOME:
this.selectFlowRelative(-1e10);
break;
case Key.ESC:
this.selectFlow(null);
break;
case Key.H:
case Key.LEFT:
if (this.refs.flowDetails) {
this.refs.flowDetails.nextTab(-1);
}
break;
case Key.L:
case Key.TAB:
case Key.RIGHT:
if (this.refs.flowDetails) {
this.refs.flowDetails.nextTab(+1);
}
break;
case Key.C:
if (e.shiftKey) {
FlowActions.clear();
}
break;
case Key.D:
if (flow) {
if (e.shiftKey) {
FlowActions.duplicate(flow);
} else {
FlowActions.delete(flow);
}
}
break;
case Key.A:
if (e.shiftKey) {
FlowActions.accept_all();
} else if (flow) {
FlowActions.accept(flow);
}
break;
case Key.R:
if (!e.shiftKey && flow) {
FlowActions.replay(flow);
}
break;
default:
console.debug("keydown", e.keyCode);
return;
}
e.preventDefault();
},
getSelected: function () {
return this.props.flowStore.get(this.getParams().flowId);
},
render: function () {
var selected = this.getSelected();
var details;
if (selected) {
details = [
React.createElement(Splitter, {key: "splitter"}),
React.createElement(FlowDetail, {key: "flowDetails", ref: "flowDetails", flow: selected})
];
} else {
details = null;
}
return (
React.createElement("div", {className: "main-view", onKeyDown: this.onKeyDown, tabIndex: "0"},
React.createElement(FlowTable, {ref: "flowTable",
view: this.state.view,
selectFlow: this.selectFlow,
selected: selected}),
details
)
);
}
});
var LogMessage = React.createClass({displayName: 'LogMessage',
render: function () {
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 () {
return false; // log entries are immutable.
}
});
var EventLogContents = React.createClass({displayName: 'EventLogContents',
mixins: [AutoScrollMixin, VirtualScrollMixin],
getInitialState: function () {
return {
log: []
};
},
componentWillMount: function () {
this.openView(this.props.eventStore);
},
componentWillUnmount: function () {
this.closeView();
},
openView: function (store) {
var view = new StoreView(store, function (entry) {
return this.props.filter[entry.level];
}.bind(this));
this.setState({
view: view
});
view.addListener("add recalculate", this.onEventLogChange);
},
closeView: function () {
this.state.view.close();
},
onEventLogChange: function () {
this.setState({
log: this.state.view.list
});
},
componentWillReceiveProps: function (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();
}
if (nextProps.eventStore !== this.props.eventStore) {
this.closeView();
this.openView(nextProps.eventStore);
}
},
getDefaultProps: function () {
return {
rowHeight: 45,
rowHeightMin: 15,
placeholderTagName: "div"
};
},
renderRow: function (elem) {
return React.createElement(LogMessage, {key: elem.id, entry: elem});
},
render: function () {
var rows = this.renderRows(this.state.log);
return React.createElement("pre", {onScroll: this.onScroll},
this.getPlaceholderTop(this.state.log.length),
rows,
this.getPlaceholderBottom(this.state.log.length)
);
}
});
var ToggleFilter = React.createClass({displayName: 'ToggleFilter',
toggle: function (e) {
e.preventDefault();
return this.props.toggleLevel(this.props.name);
},
render: function () {
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',
getInitialState: function () {
return {
filter: {
"debug": false,
"info": true,
"web": true
}
};
},
close: function () {
var d = {};
d[Query.SHOW_EVENTLOG] = undefined;
this.setQuery(d);
},
toggleLevel: function (level) {
var filter = _.extend({}, this.state.filter);
filter[level] = !filter[level];
this.setState({filter: filter});
},
render: function () {
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, eventStore: this.props.eventStore})
)
);
}
});
var Footer = React.createClass({displayName: 'Footer',
render: function () {
var mode = this.props.settings.mode;
var intercept = this.props.settings.intercept;
return (
React.createElement("footer", null,
mode != "regular" ? React.createElement("span", {className: "label label-success"}, mode, " mode") : null,
" ",
intercept ? React.createElement("span", {className: "label label-success"}, "Intercept: ", intercept) : null
)
);
}
});
//TODO: Move out of here, just a stub.
var Reports = React.createClass({displayName: 'Reports',
render: function () {
return React.createElement("div", null, "ReportEditor");
}
});
var ProxyAppMain = React.createClass({displayName: 'ProxyAppMain',
mixins: [State],
getInitialState: function () {
var eventStore = new EventLogStore();
var flowStore = new FlowStore();
var settings = new SettingsStore();
// Default Settings before fetch
_.extend(settings.dict,{
});
return {
settings: settings,
flowStore: flowStore,
eventStore: eventStore
};
},
componentDidMount: function () {
this.state.settings.addListener("recalculate", this.onSettingsChange);
window.app = this;
},
componentWillUnmount: function () {
this.state.settings.removeListener("recalculate", this.onSettingsChange);
},
onSettingsChange: function(){
this.setState({
settings: this.state.settings
});
},
render: function () {
var eventlog;
if (this.getQuery()[Query.SHOW_EVENTLOG]) {
eventlog = [
React.createElement(Splitter, {key: "splitter", axis: "y"}),
React.createElement(EventLog, {key: "eventlog", eventStore: this.state.eventStore})
];
} else {
eventlog = null;
}
return (
React.createElement("div", {id: "container"},
React.createElement(Header, {settings: this.state.settings.dict}),
React.createElement(RouteHandler, {settings: this.state.settings.dict, flowStore: this.state.flowStore}),
eventlog,
React.createElement(Footer, {settings: this.state.settings.dict})
)
);
}
});
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"})
)
);
$(function () {
window.ws = new Connection("/updates");
ReactRouter.run(routes, function (Handler) {
React.render(React.createElement(Handler, null), document.body);
});
});
//# sourceMappingURL=app.js.map