├── .gitignore
├── example-code
├── 6-in.js
├── 1-in.js
├── 1-out.js
├── 2-in.js
├── 3-in.js
├── 3-out.js
├── 2-out.js
├── 5-in.js
├── 5-out.js
├── 4-in.js
├── 4-out.js
├── 7-in.js
├── 7-out.js
├── 8-in.js
└── 8-out-broken.js
├── output-checker.js
├── package.json
├── README.md
├── app.js
├── test
└── test.js
└── stopExecutionOnTimeout.js
/.gitignore:
--------------------------------------------------------------------------------
1 | **/node_modules/
--------------------------------------------------------------------------------
/example-code/6-in.js:
--------------------------------------------------------------------------------
1 | while (x {
2 |
3 | }
--------------------------------------------------------------------------------
/example-code/1-in.js:
--------------------------------------------------------------------------------
1 | const {a=1, b=2} = {a:2};
--------------------------------------------------------------------------------
/example-code/1-out.js:
--------------------------------------------------------------------------------
1 | const {a=1, b=2} = {a:2};
--------------------------------------------------------------------------------
/example-code/2-in.js:
--------------------------------------------------------------------------------
1 | for (var i; i < 10; i++) {
2 | console.log(i);
3 | }
--------------------------------------------------------------------------------
/example-code/3-in.js:
--------------------------------------------------------------------------------
1 | function returnHTML() {
2 | return `
3 |
Hello
4 | `;
5 | }
--------------------------------------------------------------------------------
/example-code/3-out.js:
--------------------------------------------------------------------------------
1 | function returnHTML() {
2 | return `
3 | Hello
4 | `;
5 | }
--------------------------------------------------------------------------------
/example-code/2-out.js:
--------------------------------------------------------------------------------
1 | for (var i; i < 10; i++) {if (window.CP.shouldStopExecution(1)){break;}
2 | console.log(i);
3 | }
4 | window.CP.exitedLoop(1);
--------------------------------------------------------------------------------
/example-code/5-in.js:
--------------------------------------------------------------------------------
1 | for (var x = 0; i < 10; x++) {
2 | for (var y = 0; y < 10; y++) {
3 | if (x === y) {
4 |
5 | } else if (x === 3) {
6 |
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/output-checker.js:
--------------------------------------------------------------------------------
1 | var fs = require("fs");
2 | var app = require("./app.js");
3 |
4 | app.handler({
5 | markup: fs.readFileSync("./example-code/8-in.js", "utf8")
6 | }, {
7 | succeed: function(result) {
8 | console.log(result.markup);
9 | }
10 | });
11 |
12 |
--------------------------------------------------------------------------------
/example-code/5-out.js:
--------------------------------------------------------------------------------
1 | for (var x = 0; i < 10; x++) {if (window.CP.shouldStopExecution(2)){break;}
2 | for (var y = 0; y < 10; y++) {if (window.CP.shouldStopExecution(1)){break;}
3 | if (x === y) {
4 |
5 | } else if (x === 3) {
6 |
7 | }
8 | }
9 | window.CP.exitedLoop(1);
10 |
11 | }
12 | window.CP.exitedLoop(2);
--------------------------------------------------------------------------------
/example-code/4-in.js:
--------------------------------------------------------------------------------
1 | function sumTo(n) {
2 | return n != 1 ? n + sumTo(n - 1) : n;
3 | }
4 |
5 | function sumToLoop(n) {
6 | var sum = 0;
7 | for (var i = n; i > 0; )
8 |
9 | var result = n;
10 | while (n > 1) {
11 | result += --n;
12 | }
13 | return result;
14 | }
15 |
16 | function sumToFormula(n) {
17 | return n * (n + 1) / 2;
18 | }
19 |
20 |
21 | document.write('sumTo: ' + sumTo(10) + '
');
22 | document.write('sumToLoop: ' + sumToLoop(10) + '
');
23 | document.write('sumToLoop: ' + sumToFormula(10) + '
');
24 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "InfiniteLoopBuster",
3 | "version": "0.0.1",
4 | "description": "Using Esprima to stop infinite loops before they happen.",
5 | "main": "app.js",
6 | "files": [
7 | "*.js"
8 | ],
9 | "scripts": {
10 | "test": "mocha",
11 | "test:ci": "mocha --watch"
12 | },
13 | "dependencies": {
14 | "esprima": "3.1.3"
15 | },
16 | "devDependencies": {
17 | "chai": "^3.5.0",
18 | "mocha": "^3.0.2"
19 | },
20 | "optionalDependencies": {
21 | "fsevents": "^1.0.14"
22 | },
23 | "author": "Team CodePen",
24 | "license": "MIT"
25 | }
26 |
--------------------------------------------------------------------------------
/example-code/4-out.js:
--------------------------------------------------------------------------------
1 | function sumTo(n) {
2 | return n != 1 ? n + sumTo(n - 1) : n;
3 | }
4 |
5 | function sumToLoop(n) {
6 | var sum = 0;
7 | for (var i = n; i > 0; )
8 |
9 | {if (window.CP.shouldStopExecution(1)){break;}var result = n;
10 | window.CP.exitedLoop(1);
11 | }
12 | while (n > 1) {if (window.CP.shouldStopExecution(2)){break;}
13 | result += --n;
14 | }
15 | window.CP.exitedLoop(2);
16 |
17 | return result;
18 | }
19 |
20 | function sumToFormula(n) {
21 | return n * (n + 1) / 2;
22 | }
23 |
24 |
25 | document.write('sumTo: ' + sumTo(10) + '
');
26 | document.write('sumToLoop: ' + sumToLoop(10) + '
');
27 | document.write('sumToLoop: ' + sumToFormula(10) + '
');
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Infinite Loop Buster!
2 |
3 | Stop infinite loops before they happen.
4 |
5 | This takes a string of JavaScript and alters it to ensure that infinite loops are broken, but otherwise doesn't affect the code. The purpose is so you can run it without fear of freezing the browser. Online code editors like CodePen are the use-case.
6 |
7 | This uses Esprima to create an abstract syntax tree out of the JavaScript and do the instrumenting. Esprima is the only dependency, it doesn't require any additional libraries to output back to a string of JavaScript.
8 |
9 | [Ariya Hidayat](https://ariya.io/) is the creator of Esprima, and largely wrote this version of the Infinite Loop Buster as well. Thanks so much, Ariya!
10 |
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | var esprima = require('esprima');
2 |
3 | function instrument(code) {
4 | var LOOP_CHECK = 'if (window.CP.shouldStopExecution(%d)){break;}';
5 | var LOOP_EXIT = "\nwindow.CP.exitedLoop(%d);\n";
6 |
7 | var loopId = 1;
8 | var patches = [];
9 |
10 | esprima.parse(code, {
11 | range: true,
12 | tolerant: false,
13 | sourceType: "script",
14 | jsx: true
15 | }, function (node) {
16 | switch (node.type) {
17 | case 'DoWhileStatement':
18 | case 'ForStatement':
19 | case 'ForInStatement':
20 | case 'ForOfStatement':
21 | case 'WhileStatement':
22 | var start = 1 + node.body.range[0];
23 | var end = node.body.range[1];
24 | var prolog = LOOP_CHECK.replace('%d', loopId);
25 | var epilog = '';
26 |
27 | if (node.body.type !== 'BlockStatement') {
28 | // `while(1) doThat()` becomes `while(1) {doThat()}`
29 | prolog = '{' + prolog;
30 | epilog = '}';
31 | --start;
32 | }
33 |
34 | patches.push({ pos: start, str: prolog });
35 | patches.push({ pos: end, str: epilog });
36 | patches.push({ pos: node.range[1], str: LOOP_EXIT.replace('%d', loopId) });
37 | ++loopId;
38 | break;
39 |
40 | default:
41 | break;
42 | }
43 | });
44 |
45 | patches.sort(function (a, b) {
46 | return b.pos - a.pos;
47 | }).forEach(function (patch) {
48 | code = code.slice(0, patch.pos) + patch.str + code.slice(patch.pos);
49 | });
50 |
51 | return code;
52 | }
53 |
54 | exports.handler = function(event, context) {
55 |
56 | try {
57 |
58 | var js = event.markup || "";
59 |
60 | if (js === "") {
61 | context.succeed({
62 | "markup": ""
63 | });
64 | } else {
65 | context.succeed({
66 | "markup": instrument(event.markup)
67 | });
68 | }
69 |
70 | } catch(e) {
71 |
72 | var line = 1;
73 |
74 | try {
75 | line = e.lineNumber;
76 | } catch(err) {
77 | // go on with line number 1
78 | }
79 |
80 | context.succeed({
81 | "error": e.description,
82 | "line": line
83 | });
84 |
85 | }
86 |
87 | };
88 |
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | var assert = require("assert");
2 | var fs = require("fs");
3 | var app = require("../app.js");
4 |
5 | /* globals beforeEach */
6 |
7 | function call(file) {
8 | return fs.readFileSync("example-code/" + file, "utf8");
9 | }
10 |
11 | function assertCompiledEqualToFileContent(compiled, file) {
12 | assert.equal(compiled.replace(/\s+$/, ''), call(file).replace(/\s+$/, ''));
13 | }
14 |
15 | function compareInputFileToOutputFile(inputFile, outputFile) {
16 | var compiled;
17 |
18 | beforeEach(function(done) {
19 | app.handler({
20 | markup: call(inputFile)
21 | }, {
22 | succeed: function(result) {
23 | compiled = result.markup;
24 | done();
25 | }
26 | });
27 | });
28 |
29 | it('Should ...', function() {
30 | assertCompiledEqualToFileContent(compiled, outputFile);
31 | });
32 | }
33 |
34 | describe('Test #1) Allows Restructuring', function() {
35 | compareInputFileToOutputFile('1-in.js', '1-out.js');
36 | });
37 |
38 | describe('Test #2) Inject Self into `for` Loop', function() {
39 | compareInputFileToOutputFile('2-in.js', '2-out.js');
40 | });
41 |
42 | describe('Test #3) Should Allow and Return Template Literals', function() {
43 | compareInputFileToOutputFile('3-in.js', '3-out.js');
44 | });
45 |
46 | describe('Test #4) Should Stop For Loop Without End Condition', function() {
47 | compareInputFileToOutputFile('4-in.js', '4-out.js');
48 | });
49 |
50 | describe('Test #5) Deal With Nested `for` loops', function() {
51 | compareInputFileToOutputFile('5-in.js', '5-out.js');
52 | });
53 |
54 | describe('Test #6) Deal With Malformed JavaScript', function() {
55 | var raw = call("6-in.js");
56 | var compiled;
57 | var expectedOutput = {
58 | "error": "Unexpected token {",
59 | "line": 1
60 | };
61 |
62 | beforeEach(function(done) {
63 | raw =
64 | app.handler({
65 | markup: raw
66 | }, {
67 | succeed: function(result) {
68 | compiled = result;
69 | done();
70 | }
71 | });
72 |
73 | });
74 |
75 | it('Should ...', function() {
76 | assert.equal(compiled.error, expectedOutput.error);
77 | });
78 |
79 | });
80 |
81 | describe('Test #7) Deal With Minified JavaScript', function() {
82 | compareInputFileToOutputFile('7-in.js', '7-out.js');
83 | });
84 |
--------------------------------------------------------------------------------
/example-code/7-in.js:
--------------------------------------------------------------------------------
1 | //----------
2 | //! glitch-canvas by snorpey - altered by Nathaniel Inman, MIT License
3 | window.glitch=function(){function t(t,s,g){if(h(t)&&c(s,"parameters","object")&&c(g,"callback","function")){for(f=u(s),e(y,t),e(I,t),m=n(t,f.quality),p=i(m),l=r(p),v=0,k=f.iterations;k>v;v++)a(p,l,f.seed,f.amount,v,f.iterations);b=new Image,b.onload=function(){j.drawImage(b,0,0),w=j.getImageData(0,0,t.width,t.height),g(w)},b.src=o(p)}}function e(t,e){t.width!==e.width&&(t.width=e.width),t.height!==e.height&&(t.height=e.height)}function a(t,e,a,n,r,i){var o=t.length-e-4,u=parseInt(o/i*r,10),h=parseInt(o/i*(r+1),10),c=h-u,s=parseInt(u+c*a,10);s>o&&(s=o);var g=Math.floor(e+s);t[g]=Math.floor(256*n)}function n(t,e){var a="number"==typeof e&&1>e&&e>0?e:.1;E.putImageData(t,0,0);var n=I.toDataURL("image/jpeg",a);switch(n.length%4){case 3:n+="=";break;case 2:n+="==";break;case 1:n+="==="}return n}function r(t){var e=417;for(v=0,k=t.length;k>v;v++)if(255===t[v]&&218===t[v+1]){e=v+2;break}return e}function i(t){var e,a,n,r=[];for(v=23,k=t.length;k>v;v++){switch(a=x[t.charAt(v)],e=(v-23)%4){case 1:r.push(n<<2|a>>4);break;case 2:r.push((15&n)<<4|a>>2);break;case 3:r.push((3&n)<<6|a)}n=a}return r}function o(t){var e,a,n,r=["data:image/jpeg;base64,"];for(v=0,k=t.length;k>v;v++){switch(a=t[v],e=v%3){case 0:r.push(q[a>>2]);break;case 1:r.push(q[(3&n)<<4|a>>4]);break;case 2:r.push(q[(15&n)<<2|a>>6]),r.push(q[63&a])}n=a}return 0===e?(r.push(q[(3&n)<<4]),r.push("==")):1===e&&(r.push(q[(15&n)<<2]),r.push("=")),r.join("")}function u(t){return{seed:(t.seed||0)/100,quality:(t.quality||0)/100,amount:(t.amount||0)/100,iterations:t.iterations||0}}function h(t){return c(t,"image_data","object")&&c(t.width,"image_data.width","number")&&c(t.height,"image_data.height","number")&&c(t.data,"image_data.data","object")&&c(t.data.length,"image_data.data.length","number")&&s(t.data.length,"image_data.data.length",g,"> 0")?!0:!1}function c(t,e,a){return typeof t===a?!0:(d(t,"typeof "+e,'"'+a+'"','"'+typeof t+'"'),!1)}function s(t,e,a,n){return a(t)===!0?!0:void d(t,e,n,"not")}function g(t){return t>0}function d(t,e,a,n){throw new Error("glitch(): Expected "+e+" to be "+a+", but it was "+n+".")}var f,m,p,l,b,w,v,k,y=document.createElement("canvas"),I=document.createElement("canvas"),j=y.getContext("2d"),E=I.getContext("2d"),_="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",q=_.split(""),x={};return q.forEach(function(t,e){x[t]=e}),t}();
4 | //----------
5 |
--------------------------------------------------------------------------------
/example-code/7-out.js:
--------------------------------------------------------------------------------
1 | //----------
2 | //! glitch-canvas by snorpey - altered by Nathaniel Inman, MIT License
3 | window.glitch=function(){function t(t,s,g){if(h(t)&&c(s,"parameters","object")&&c(g,"callback","function")){for(f=u(s),e(y,t),e(I,t),m=n(t,f.quality),p=i(m),l=r(p),v=0,k=f.iterations;k>v;v++){if (window.CP.shouldStopExecution(1)){break;}a(p,l,f.seed,f.amount,v,f.iterations);
4 | window.CP.exitedLoop(1);
5 | }b=new Image,b.onload=function(){j.drawImage(b,0,0),w=j.getImageData(0,0,t.width,t.height),g(w)},b.src=o(p)}}function e(t,e){t.width!==e.width&&(t.width=e.width),t.height!==e.height&&(t.height=e.height)}function a(t,e,a,n,r,i){var o=t.length-e-4,u=parseInt(o/i*r,10),h=parseInt(o/i*(r+1),10),c=h-u,s=parseInt(u+c*a,10);s>o&&(s=o);var g=Math.floor(e+s);t[g]=Math.floor(256*n)}function n(t,e){var a="number"==typeof e&&1>e&&e>0?e:.1;E.putImageData(t,0,0);var n=I.toDataURL("image/jpeg",a);switch(n.length%4){case 3:n+="=";break;case 2:n+="==";break;case 1:n+="==="}return n}function r(t){var e=417;for(v=0,k=t.length;k>v;v++){if (window.CP.shouldStopExecution(2)){break;}if(255===t[v]&&218===t[v+1]){e=v+2;break}}
6 | window.CP.exitedLoop(2);
7 | return e}function i(t){var e,a,n,r=[];for(v=23,k=t.length;k>v;v++){if (window.CP.shouldStopExecution(3)){break;}switch(a=x[t.charAt(v)],e=(v-23)%4){case 1:r.push(n<<2|a>>4);break;case 2:r.push((15&n)<<4|a>>2);break;case 3:r.push((3&n)<<6|a)}n=a}
8 | window.CP.exitedLoop(3);
9 | return r}function o(t){var e,a,n,r=["data:image/jpeg;base64,"];for(v=0,k=t.length;k>v;v++){if (window.CP.shouldStopExecution(4)){break;}switch(a=t[v],e=v%3){case 0:r.push(q[a>>2]);break;case 1:r.push(q[(3&n)<<4|a>>4]);break;case 2:r.push(q[(15&n)<<2|a>>6]),r.push(q[63&a])}n=a}
10 | window.CP.exitedLoop(4);
11 | return 0===e?(r.push(q[(3&n)<<4]),r.push("==")):1===e&&(r.push(q[(15&n)<<2]),r.push("=")),r.join("")}function u(t){return{seed:(t.seed||0)/100,quality:(t.quality||0)/100,amount:(t.amount||0)/100,iterations:t.iterations||0}}function h(t){return c(t,"image_data","object")&&c(t.width,"image_data.width","number")&&c(t.height,"image_data.height","number")&&c(t.data,"image_data.data","object")&&c(t.data.length,"image_data.data.length","number")&&s(t.data.length,"image_data.data.length",g,"> 0")?!0:!1}function c(t,e,a){return typeof t===a?!0:(d(t,"typeof "+e,'"'+a+'"','"'+typeof t+'"'),!1)}function s(t,e,a,n){return a(t)===!0?!0:void d(t,e,n,"not")}function g(t){return t>0}function d(t,e,a,n){throw new Error("glitch(): Expected "+e+" to be "+a+", but it was "+n+".")}var f,m,p,l,b,w,v,k,y=document.createElement("canvas"),I=document.createElement("canvas"),j=y.getContext("2d"),E=I.getContext("2d"),_="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",q=_.split(""),x={};return q.forEach(function(t,e){x[t]=e}),t}();
12 | //----------
--------------------------------------------------------------------------------
/stopExecutionOnTimeout.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | if (typeof (window.CP) !== "object") {
4 | window.CP = {};
5 | }
6 |
7 | window.CP.PenTimer = {
8 | // If we successfully run for X seconds no need to continue
9 | // to monitor because we know the program isn't locked
10 | programNoLongerBeingMonitored: false,
11 | timeOfFirstCallToShouldStopLoop: 0,
12 | _loopExits: {},
13 | // Keep track of how long program spends in single loop w/o an exit
14 | _loopTimers: {},
15 |
16 | // Give the program time to get started
17 | START_MONITORING_AFTER: 2000,
18 | // takes into account START_MONITORING_AFTER val
19 | STOP_ALL_MONITORING_TIMEOUT: 5000,
20 | // tested against pen: xbwYNm, it loops over 200k real loop
21 | MAX_TIME_IN_LOOP_WO_EXIT: 2200,
22 |
23 | exitedLoop: function(loopID) {
24 | this._loopExits[loopID] = true;
25 | },
26 |
27 | shouldStopLoop: function(loopID) {
28 | // Once we kill a loop, kill them all, we have an infinite loop and
29 | // it must be fixed prior to running again.
30 | if (this.programKilledSoStopMonitoring) {
31 | return true;
32 | }
33 |
34 | // Program exceeded monitor time, we're in the clear
35 | if (this.programNoLongerBeingMonitored) {
36 | return false;
37 | }
38 |
39 | // If the loopExit already called return
40 | // It's possible for the program to break out
41 | if (this._loopExits[loopID]) {
42 | return false;
43 | }
44 |
45 | var now = this._getTime();
46 |
47 | if (this.timeOfFirstCallToShouldStopLoop === 0) {
48 | this.timeOfFirstCallToShouldStopLoop = now;
49 | // first call to shouldStopLoop so just exit already
50 | return false;
51 | }
52 |
53 | var programRunningTime = now - this.timeOfFirstCallToShouldStopLoop;
54 |
55 | // Allow program to run unmolested (yup that's the right word)
56 | // while it starts up
57 | if (programRunningTime < this.START_MONITORING_AFTER) {
58 | return false;
59 | }
60 |
61 | // Once the program's run for a satisfactory amount of time
62 | // we assume it won't lock up and we can simply continue w/o
63 | // checking for infinite loops
64 | if (programRunningTime > this.STOP_ALL_MONITORING_TIMEOUT) {
65 | this.programNoLongerBeingMonitored = true;
66 |
67 | return false;
68 | }
69 |
70 | // Second level shit around new hotness logic
71 | try {
72 | this._checkOnInfiniteLoop(loopID, now);
73 | } catch(e) {
74 | this._sendErrorMessageToEditor();
75 | this.programKilledSoStopMonitoring = true;
76 | return true;
77 | }
78 |
79 | return false;
80 | },
81 |
82 | _sendErrorMessageToEditor: function() {
83 | try {
84 | if (this._shouldPostMessage()) {
85 | var data = {
86 | action: "infinite-loop",
87 | line: this._findAroundLineNumber()
88 | };
89 |
90 | parent.postMessage(JSON.stringify(data), "*");
91 | } else {
92 | this._throwAnErrorToStopPen();
93 | }
94 | } catch(error) {
95 | this._throwAnErrorToStopPen();
96 | }
97 | },
98 |
99 | _shouldPostMessage: function() {
100 | return document.location.href.match(/boomerang/);
101 | },
102 |
103 | _throwAnErrorToStopPen: function() {
104 | throw "We found an infinite loop in your Pen. We've stopped the Pen from running. Please correct it or contact\ support@codepen.io.";
105 | },
106 |
107 | _findAroundLineNumber: function() {
108 | var err = new Error();
109 | var lineNumber = 0;
110 |
111 | if (err.stack) {
112 | // match only against JS in boomerang
113 | var m = err.stack.match(/boomerang\S+:(\d+):\d+/);
114 |
115 | if (m) {
116 | lineNumber = m[1];
117 | }
118 | }
119 |
120 | return lineNumber;
121 | },
122 |
123 | _checkOnInfiniteLoop: function(loopID, now) {
124 | if (!this._loopTimers[loopID]) {
125 | this._loopTimers[loopID] = now;
126 | // We just started the timer for this loop. exit early
127 | return false;
128 | }
129 |
130 | var loopRunningTime = now - this._loopTimers[loopID];
131 |
132 | if (loopRunningTime > this.MAX_TIME_IN_LOOP_WO_EXIT) {
133 | throw "Infinite Loop found on loop: " + loopID;
134 | }
135 | },
136 |
137 | _getTime: function() {
138 | return +new Date();
139 | }
140 | };
141 |
142 | window.CP.shouldStopExecution = function(loopID) {
143 | var shouldStop = window.CP.PenTimer.shouldStopLoop(loopID);
144 | if( shouldStop === true ) {
145 | console.warn("[CodePen]: An infinite loop (or a loop taking too long) was detected, so we stopped its execution. Sorry!");
146 | }
147 | return shouldStop;
148 | };
149 |
150 | window.CP.exitedLoop = function(loopID) {
151 | window.CP.PenTimer.exitedLoop(loopID);
152 | };
153 |
--------------------------------------------------------------------------------
/example-code/8-in.js:
--------------------------------------------------------------------------------
1 | /**
2 | * React v15.4.2
3 | *
4 | * Copyright 2013-present, Facebook, Inc.
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree. An additional grant
9 | * of patent rights can be found in the PATENTS file in the same directory.
10 | *
11 | */
12 | !function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var e;e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,e.React=t()}}(function(){return function t(e,n,r){function o(u,a){if(!n[u]){if(!e[u]){var s="function"==typeof require&&require;if(!a&&s)return s(u,!0);if(i)return i(u,!0);var c=new Error("Cannot find module '"+u+"'");throw c.code="MODULE_NOT_FOUND",c}var l=n[u]={exports:{}};e[u][0].call(l.exports,function(t){var n=e[u][1][t];return o(n?n:t)},l,l.exports,t,e,n,r)}return n[u].exports}for(var i="function"==typeof require&&require,u=0;u1){for(var h=Array(v),m=0;m1){for(var g=Array(b),E=0;E>"),O={array:u("array"),bool:u("boolean"),func:u("function"),number:u("number"),object:u("object"),string:u("string"),symbol:u("symbol"),any:a(),arrayOf:s,element:c(),instanceOf:l,node:y(),objectOf:p,oneOf:f,oneOfType:d,shape:v};o.prototype=Error.prototype,e.exports=O},{12:12,14:14,19:19,23:23,26:26,9:9}],14:[function(t,e,n){"use strict";var r="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED";e.exports=r},{}],15:[function(t,e,n){"use strict";function r(t,e,n){this.props=t,this.context=e,this.refs=s,this.updater=n||a}function o(){}var i=t(27),u=t(6),a=t(11),s=t(24);o.prototype=u.prototype,r.prototype=new o,r.prototype.constructor=r,i(r.prototype,u.prototype),r.prototype.isPureReactComponent=!0,e.exports=r},{11:11,24:24,27:27,6:6}],16:[function(t,e,n){"use strict";var r=t(27),o=t(3),i=r({__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED:{ReactCurrentOwner:t(7)}},o);e.exports=i},{27:27,3:3,7:7}],17:[function(t,e,n){"use strict";e.exports="15.4.2"},{}],18:[function(t,e,n){"use strict";var r=!1;e.exports=r},{}],19:[function(t,e,n){"use strict";function r(t){var e=t&&(o&&t[o]||t[i]);if("function"==typeof e)return e}var o="function"==typeof Symbol&&Symbol.iterator,i="@@iterator";e.exports=r},{}],20:[function(t,e,n){"use strict";function r(t){return i.isValidElement(t)?void 0:o("143"),t}var o=t(21),i=t(9);t(25);e.exports=r},{21:21,25:25,9:9}],21:[function(t,e,n){"use strict";function r(t){for(var e=arguments.length-1,n="Minified React error #"+t+"; visit http://facebook.github.io/react/docs/error-decoder.html?invariant="+t,r=0;r1){for(var h=Array(v),m=0;m1){for(var g=Array(b),E=0;E>"),O={array:u("array"),bool:u("boolean"),func:u("function"),number:u("number"),object:u("object"),string:u("string"),symbol:u("symbol"),any:a(),arrayOf:s,element:c(),instanceOf:l,node:y(),objectOf:p,oneOf:f,oneOfType:d,shape:v};o.prototype=Error.prototype,e.exports=O},{12:12,14:14,19:19,23:23,26:26,9:9}],14:[function(t,e,n){"use strict";var r="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED";e.exports=r},{}],15:[function(t,e,n){"use strict";function r(t,e,n){this.props=t,this.context=e,this.refs=s,this.updater=n||a}function o(){}var i=t(27),u=t(6),a=t(11),s=t(24);o.prototype=u.prototype,r.prototype=new o,r.prototype.constructor=r,i(r.prototype,u.prototype),r.prototype.isPureReactComponent=!0,e.exports=r},{11:11,24:24,27:27,6:6}],16:[function(t,e,n){"use strict";var r=t(27),o=t(3),i=r({__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED:{ReactCurrentOwner:t(7)}},o);e.exports=i},{27:27,3:3,7:7}],17:[function(t,e,n){"use strict";e.exports="15.4.2"},{}],18:[function(t,e,n){"use strict";var r=!1;e.exports=r},{}],19:[function(t,e,n){"use strict";function r(t){var e=t&&(o&&t[o]||t[i]);if("function"==typeof e)return e}var o="function"==typeof Symbol&&Symbol.iterator,i="@@iterator";e.exports=r},{}],20:[function(t,e,n){"use strict";function r(t){return i.isValidElement(t)?void 0:o("143"),t}var o=t(21),i=t(9);t(25);e.exports=r},{21:21,25:25,9:9}],21:[function(t,e,n){"use strict";function r(t){for(var e=arguments.length-1,n="Minified React error #"+t+"; visit http://facebook.github.io/react/docs/error-decoder.html?invariant="+t,r=0;r