diff --git a/css/dev-menu.css b/css/dev-menu.css
new file mode 100644
index 000000000..21a93e78b
--- /dev/null
+++ b/css/dev-menu.css
@@ -0,0 +1,36 @@
+.add-exp-button {
+ margin-right: 0px;
+}
+
+.remove-exp-button {
+ margin-left:0px;
+}
+
+.exp-input {
+ margin-right: 0px;
+ margin-left:0px;
+
+ margin-top: 5px;
+ margin-bottom: 5px;
+
+ padding: 2px 5px;
+}
+
+.text-center {
+ margin: auto;
+ text-align: center;
+ vertical-align: middle;
+}
+
+.touch-right {
+ margin-right: 0px;
+}
+
+.touch-left {
+ margin-left: 0px;
+}
+
+.touch-sides {
+ margin-left: 0px;
+ margin-right: 0px;
+}
\ No newline at end of file
diff --git a/css/grid.min.css b/css/grid.min.css
new file mode 100644
index 000000000..d617299c5
--- /dev/null
+++ b/css/grid.min.css
@@ -0,0 +1,6 @@
+/*!
+ * Bootstrap Grid v4.1.2 (https://getbootstrap.com/)
+ * Copyright 2011-2018 The Bootstrap Authors
+ * Copyright 2011-2018 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */@-ms-viewport{width:device-width}html{-webkit-box-sizing:border-box;box-sizing:border-box;-ms-overflow-style:scrollbar}*,*::before,*::after{-webkit-box-sizing:inherit;box-sizing:inherit}.container{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width: 576px){.container{max-width:540px}}@media (min-width: 768px){.container{max-width:720px}}@media (min-width: 992px){.container{max-width:960px}}@media (min-width: 1200px){.container{max-width:1140px}}.container-fluid{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*="col-"]{padding-right:0;padding-left:0}.col-1,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-10,.col-11,.col-12,.col,.col-auto,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm,.col-sm-auto,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-md,.col-md-auto,.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg,.col-lg-auto,.col-xl-1,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl,.col-xl-auto{position:relative;width:100%;min-height:1px;padding-right:15px;padding-left:15px}.col{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-1{-webkit-box-flex:0;-ms-flex:0 0 8.3333333333%;flex:0 0 8.3333333333%;max-width:8.3333333333%}.col-2{-webkit-box-flex:0;-ms-flex:0 0 16.6666666667%;flex:0 0 16.6666666667%;max-width:16.6666666667%}.col-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-4{-webkit-box-flex:0;-ms-flex:0 0 33.3333333333%;flex:0 0 33.3333333333%;max-width:33.3333333333%}.col-5{-webkit-box-flex:0;-ms-flex:0 0 41.6666666667%;flex:0 0 41.6666666667%;max-width:41.6666666667%}.col-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-7{-webkit-box-flex:0;-ms-flex:0 0 58.3333333333%;flex:0 0 58.3333333333%;max-width:58.3333333333%}.col-8{-webkit-box-flex:0;-ms-flex:0 0 66.6666666667%;flex:0 0 66.6666666667%;max-width:66.6666666667%}.col-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-10{-webkit-box-flex:0;-ms-flex:0 0 83.3333333333%;flex:0 0 83.3333333333%;max-width:83.3333333333%}.col-11{-webkit-box-flex:0;-ms-flex:0 0 91.6666666667%;flex:0 0 91.6666666667%;max-width:91.6666666667%}.col-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-1{margin-left:8.3333333333%}.offset-2{margin-left:16.6666666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.3333333333%}.offset-5{margin-left:41.6666666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.3333333333%}.offset-8{margin-left:66.6666666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.3333333333%}.offset-11{margin-left:91.6666666667%}@media (min-width: 576px){.col-sm{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-sm-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-sm-1{-webkit-box-flex:0;-ms-flex:0 0 8.3333333333%;flex:0 0 8.3333333333%;max-width:8.3333333333%}.col-sm-2{-webkit-box-flex:0;-ms-flex:0 0 16.6666666667%;flex:0 0 16.6666666667%;max-width:16.6666666667%}.col-sm-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-sm-4{-webkit-box-flex:0;-ms-flex:0 0 33.3333333333%;flex:0 0 33.3333333333%;max-width:33.3333333333%}.col-sm-5{-webkit-box-flex:0;-ms-flex:0 0 41.6666666667%;flex:0 0 41.6666666667%;max-width:41.6666666667%}.col-sm-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-sm-7{-webkit-box-flex:0;-ms-flex:0 0 58.3333333333%;flex:0 0 58.3333333333%;max-width:58.3333333333%}.col-sm-8{-webkit-box-flex:0;-ms-flex:0 0 66.6666666667%;flex:0 0 66.6666666667%;max-width:66.6666666667%}.col-sm-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-sm-10{-webkit-box-flex:0;-ms-flex:0 0 83.3333333333%;flex:0 0 83.3333333333%;max-width:83.3333333333%}.col-sm-11{-webkit-box-flex:0;-ms-flex:0 0 91.6666666667%;flex:0 0 91.6666666667%;max-width:91.6666666667%}.col-sm-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-sm-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-sm-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-sm-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-sm-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-sm-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-sm-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-sm-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-sm-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-sm-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-sm-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-sm-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-sm-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-sm-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-sm-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-sm-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.3333333333%}.offset-sm-2{margin-left:16.6666666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.3333333333%}.offset-sm-5{margin-left:41.6666666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.3333333333%}.offset-sm-8{margin-left:66.6666666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.3333333333%}.offset-sm-11{margin-left:91.6666666667%}}@media (min-width: 768px){.col-md{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-md-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-md-1{-webkit-box-flex:0;-ms-flex:0 0 8.3333333333%;flex:0 0 8.3333333333%;max-width:8.3333333333%}.col-md-2{-webkit-box-flex:0;-ms-flex:0 0 16.6666666667%;flex:0 0 16.6666666667%;max-width:16.6666666667%}.col-md-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-md-4{-webkit-box-flex:0;-ms-flex:0 0 33.3333333333%;flex:0 0 33.3333333333%;max-width:33.3333333333%}.col-md-5{-webkit-box-flex:0;-ms-flex:0 0 41.6666666667%;flex:0 0 41.6666666667%;max-width:41.6666666667%}.col-md-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-md-7{-webkit-box-flex:0;-ms-flex:0 0 58.3333333333%;flex:0 0 58.3333333333%;max-width:58.3333333333%}.col-md-8{-webkit-box-flex:0;-ms-flex:0 0 66.6666666667%;flex:0 0 66.6666666667%;max-width:66.6666666667%}.col-md-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-md-10{-webkit-box-flex:0;-ms-flex:0 0 83.3333333333%;flex:0 0 83.3333333333%;max-width:83.3333333333%}.col-md-11{-webkit-box-flex:0;-ms-flex:0 0 91.6666666667%;flex:0 0 91.6666666667%;max-width:91.6666666667%}.col-md-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-md-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-md-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-md-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-md-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-md-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-md-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-md-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-md-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-md-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-md-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-md-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-md-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-md-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-md-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-md-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.3333333333%}.offset-md-2{margin-left:16.6666666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.3333333333%}.offset-md-5{margin-left:41.6666666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.3333333333%}.offset-md-8{margin-left:66.6666666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.3333333333%}.offset-md-11{margin-left:91.6666666667%}}@media (min-width: 992px){.col-lg{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-lg-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-lg-1{-webkit-box-flex:0;-ms-flex:0 0 8.3333333333%;flex:0 0 8.3333333333%;max-width:8.3333333333%}.col-lg-2{-webkit-box-flex:0;-ms-flex:0 0 16.6666666667%;flex:0 0 16.6666666667%;max-width:16.6666666667%}.col-lg-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-lg-4{-webkit-box-flex:0;-ms-flex:0 0 33.3333333333%;flex:0 0 33.3333333333%;max-width:33.3333333333%}.col-lg-5{-webkit-box-flex:0;-ms-flex:0 0 41.6666666667%;flex:0 0 41.6666666667%;max-width:41.6666666667%}.col-lg-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-lg-7{-webkit-box-flex:0;-ms-flex:0 0 58.3333333333%;flex:0 0 58.3333333333%;max-width:58.3333333333%}.col-lg-8{-webkit-box-flex:0;-ms-flex:0 0 66.6666666667%;flex:0 0 66.6666666667%;max-width:66.6666666667%}.col-lg-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-lg-10{-webkit-box-flex:0;-ms-flex:0 0 83.3333333333%;flex:0 0 83.3333333333%;max-width:83.3333333333%}.col-lg-11{-webkit-box-flex:0;-ms-flex:0 0 91.6666666667%;flex:0 0 91.6666666667%;max-width:91.6666666667%}.col-lg-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-lg-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-lg-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-lg-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-lg-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-lg-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-lg-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-lg-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-lg-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-lg-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-lg-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-lg-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-lg-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-lg-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-lg-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-lg-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.3333333333%}.offset-lg-2{margin-left:16.6666666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.3333333333%}.offset-lg-5{margin-left:41.6666666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.3333333333%}.offset-lg-8{margin-left:66.6666666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.3333333333%}.offset-lg-11{margin-left:91.6666666667%}}@media (min-width: 1200px){.col-xl{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-xl-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-xl-1{-webkit-box-flex:0;-ms-flex:0 0 8.3333333333%;flex:0 0 8.3333333333%;max-width:8.3333333333%}.col-xl-2{-webkit-box-flex:0;-ms-flex:0 0 16.6666666667%;flex:0 0 16.6666666667%;max-width:16.6666666667%}.col-xl-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-xl-4{-webkit-box-flex:0;-ms-flex:0 0 33.3333333333%;flex:0 0 33.3333333333%;max-width:33.3333333333%}.col-xl-5{-webkit-box-flex:0;-ms-flex:0 0 41.6666666667%;flex:0 0 41.6666666667%;max-width:41.6666666667%}.col-xl-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-xl-7{-webkit-box-flex:0;-ms-flex:0 0 58.3333333333%;flex:0 0 58.3333333333%;max-width:58.3333333333%}.col-xl-8{-webkit-box-flex:0;-ms-flex:0 0 66.6666666667%;flex:0 0 66.6666666667%;max-width:66.6666666667%}.col-xl-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-xl-10{-webkit-box-flex:0;-ms-flex:0 0 83.3333333333%;flex:0 0 83.3333333333%;max-width:83.3333333333%}.col-xl-11{-webkit-box-flex:0;-ms-flex:0 0 91.6666666667%;flex:0 0 91.6666666667%;max-width:91.6666666667%}.col-xl-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-xl-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-xl-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-xl-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-xl-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-xl-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-xl-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-xl-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-xl-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-xl-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-xl-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-xl-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-xl-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-xl-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-xl-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-xl-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.3333333333%}.offset-xl-2{margin-left:16.6666666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.3333333333%}.offset-xl-5{margin-left:41.6666666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.3333333333%}.offset-xl-8{margin-left:66.6666666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.3333333333%}.offset-xl-11{margin-left:91.6666666667%}}.d-none{display:none !important}.d-inline{display:inline !important}.d-inline-block{display:inline-block !important}.d-block{display:block !important}.d-table{display:table !important}.d-table-row{display:table-row !important}.d-table-cell{display:table-cell !important}.d-flex{display:-webkit-box !important;display:-ms-flexbox !important;display:flex !important}.d-inline-flex{display:-webkit-inline-box !important;display:-ms-inline-flexbox !important;display:inline-flex !important}@media (min-width: 576px){.d-sm-none{display:none !important}.d-sm-inline{display:inline !important}.d-sm-inline-block{display:inline-block !important}.d-sm-block{display:block !important}.d-sm-table{display:table !important}.d-sm-table-row{display:table-row !important}.d-sm-table-cell{display:table-cell !important}.d-sm-flex{display:-webkit-box !important;display:-ms-flexbox !important;display:flex !important}.d-sm-inline-flex{display:-webkit-inline-box !important;display:-ms-inline-flexbox !important;display:inline-flex !important}}@media (min-width: 768px){.d-md-none{display:none !important}.d-md-inline{display:inline !important}.d-md-inline-block{display:inline-block !important}.d-md-block{display:block !important}.d-md-table{display:table !important}.d-md-table-row{display:table-row !important}.d-md-table-cell{display:table-cell !important}.d-md-flex{display:-webkit-box !important;display:-ms-flexbox !important;display:flex !important}.d-md-inline-flex{display:-webkit-inline-box !important;display:-ms-inline-flexbox !important;display:inline-flex !important}}@media (min-width: 992px){.d-lg-none{display:none !important}.d-lg-inline{display:inline !important}.d-lg-inline-block{display:inline-block !important}.d-lg-block{display:block !important}.d-lg-table{display:table !important}.d-lg-table-row{display:table-row !important}.d-lg-table-cell{display:table-cell !important}.d-lg-flex{display:-webkit-box !important;display:-ms-flexbox !important;display:flex !important}.d-lg-inline-flex{display:-webkit-inline-box !important;display:-ms-inline-flexbox !important;display:inline-flex !important}}@media (min-width: 1200px){.d-xl-none{display:none !important}.d-xl-inline{display:inline !important}.d-xl-inline-block{display:inline-block !important}.d-xl-block{display:block !important}.d-xl-table{display:table !important}.d-xl-table-row{display:table-row !important}.d-xl-table-cell{display:table-cell !important}.d-xl-flex{display:-webkit-box !important;display:-ms-flexbox !important;display:flex !important}.d-xl-inline-flex{display:-webkit-inline-box !important;display:-ms-inline-flexbox !important;display:inline-flex !important}}@media print{.d-print-none{display:none !important}.d-print-inline{display:inline !important}.d-print-inline-block{display:inline-block !important}.d-print-block{display:block !important}.d-print-table{display:table !important}.d-print-table-row{display:table-row !important}.d-print-table-cell{display:table-cell !important}.d-print-flex{display:-webkit-box !important;display:-ms-flexbox !important;display:flex !important}.d-print-inline-flex{display:-webkit-inline-box !important;display:-ms-inline-flexbox !important;display:inline-flex !important}}.flex-row{-webkit-box-orient:horizontal !important;-webkit-box-direction:normal !important;-ms-flex-direction:row !important;flex-direction:row !important}.flex-column{-webkit-box-orient:vertical !important;-webkit-box-direction:normal !important;-ms-flex-direction:column !important;flex-direction:column !important}.flex-row-reverse{-webkit-box-orient:horizontal !important;-webkit-box-direction:reverse !important;-ms-flex-direction:row-reverse !important;flex-direction:row-reverse !important}.flex-column-reverse{-webkit-box-orient:vertical !important;-webkit-box-direction:reverse !important;-ms-flex-direction:column-reverse !important;flex-direction:column-reverse !important}.flex-wrap{-ms-flex-wrap:wrap !important;flex-wrap:wrap !important}.flex-nowrap{-ms-flex-wrap:nowrap !important;flex-wrap:nowrap !important}.flex-wrap-reverse{-ms-flex-wrap:wrap-reverse !important;flex-wrap:wrap-reverse !important}.flex-fill{-webkit-box-flex:1 !important;-ms-flex:1 1 auto !important;flex:1 1 auto !important}.flex-grow-0{-webkit-box-flex:0 !important;-ms-flex-positive:0 !important;flex-grow:0 !important}.flex-grow-1{-webkit-box-flex:1 !important;-ms-flex-positive:1 !important;flex-grow:1 !important}.flex-shrink-0{-ms-flex-negative:0 !important;flex-shrink:0 !important}.flex-shrink-1{-ms-flex-negative:1 !important;flex-shrink:1 !important}.justify-content-start{-webkit-box-pack:start !important;-ms-flex-pack:start !important;justify-content:flex-start !important}.justify-content-end{-webkit-box-pack:end !important;-ms-flex-pack:end !important;justify-content:flex-end !important}.justify-content-center{-webkit-box-pack:center !important;-ms-flex-pack:center !important;justify-content:center !important}.justify-content-between{-webkit-box-pack:justify !important;-ms-flex-pack:justify !important;justify-content:space-between !important}.justify-content-around{-ms-flex-pack:distribute !important;justify-content:space-around !important}.align-items-start{-webkit-box-align:start !important;-ms-flex-align:start !important;align-items:flex-start !important}.align-items-end{-webkit-box-align:end !important;-ms-flex-align:end !important;align-items:flex-end !important}.align-items-center{-webkit-box-align:center !important;-ms-flex-align:center !important;align-items:center !important}.align-items-baseline{-webkit-box-align:baseline !important;-ms-flex-align:baseline !important;align-items:baseline !important}.align-items-stretch{-webkit-box-align:stretch !important;-ms-flex-align:stretch !important;align-items:stretch !important}.align-content-start{-ms-flex-line-pack:start !important;align-content:flex-start !important}.align-content-end{-ms-flex-line-pack:end !important;align-content:flex-end !important}.align-content-center{-ms-flex-line-pack:center !important;align-content:center !important}.align-content-between{-ms-flex-line-pack:justify !important;align-content:space-between !important}.align-content-around{-ms-flex-line-pack:distribute !important;align-content:space-around !important}.align-content-stretch{-ms-flex-line-pack:stretch !important;align-content:stretch !important}.align-self-auto{-ms-flex-item-align:auto !important;align-self:auto !important}.align-self-start{-ms-flex-item-align:start !important;align-self:flex-start !important}.align-self-end{-ms-flex-item-align:end !important;align-self:flex-end !important}.align-self-center{-ms-flex-item-align:center !important;align-self:center !important}.align-self-baseline{-ms-flex-item-align:baseline !important;align-self:baseline !important}.align-self-stretch{-ms-flex-item-align:stretch !important;align-self:stretch !important}@media (min-width: 576px){.flex-sm-row{-webkit-box-orient:horizontal !important;-webkit-box-direction:normal !important;-ms-flex-direction:row !important;flex-direction:row !important}.flex-sm-column{-webkit-box-orient:vertical !important;-webkit-box-direction:normal !important;-ms-flex-direction:column !important;flex-direction:column !important}.flex-sm-row-reverse{-webkit-box-orient:horizontal !important;-webkit-box-direction:reverse !important;-ms-flex-direction:row-reverse !important;flex-direction:row-reverse !important}.flex-sm-column-reverse{-webkit-box-orient:vertical !important;-webkit-box-direction:reverse !important;-ms-flex-direction:column-reverse !important;flex-direction:column-reverse !important}.flex-sm-wrap{-ms-flex-wrap:wrap !important;flex-wrap:wrap !important}.flex-sm-nowrap{-ms-flex-wrap:nowrap !important;flex-wrap:nowrap !important}.flex-sm-wrap-reverse{-ms-flex-wrap:wrap-reverse !important;flex-wrap:wrap-reverse !important}.flex-sm-fill{-webkit-box-flex:1 !important;-ms-flex:1 1 auto !important;flex:1 1 auto !important}.flex-sm-grow-0{-webkit-box-flex:0 !important;-ms-flex-positive:0 !important;flex-grow:0 !important}.flex-sm-grow-1{-webkit-box-flex:1 !important;-ms-flex-positive:1 !important;flex-grow:1 !important}.flex-sm-shrink-0{-ms-flex-negative:0 !important;flex-shrink:0 !important}.flex-sm-shrink-1{-ms-flex-negative:1 !important;flex-shrink:1 !important}.justify-content-sm-start{-webkit-box-pack:start !important;-ms-flex-pack:start !important;justify-content:flex-start !important}.justify-content-sm-end{-webkit-box-pack:end !important;-ms-flex-pack:end !important;justify-content:flex-end !important}.justify-content-sm-center{-webkit-box-pack:center !important;-ms-flex-pack:center !important;justify-content:center !important}.justify-content-sm-between{-webkit-box-pack:justify !important;-ms-flex-pack:justify !important;justify-content:space-between !important}.justify-content-sm-around{-ms-flex-pack:distribute !important;justify-content:space-around !important}.align-items-sm-start{-webkit-box-align:start !important;-ms-flex-align:start !important;align-items:flex-start !important}.align-items-sm-end{-webkit-box-align:end !important;-ms-flex-align:end !important;align-items:flex-end !important}.align-items-sm-center{-webkit-box-align:center !important;-ms-flex-align:center !important;align-items:center !important}.align-items-sm-baseline{-webkit-box-align:baseline !important;-ms-flex-align:baseline !important;align-items:baseline !important}.align-items-sm-stretch{-webkit-box-align:stretch !important;-ms-flex-align:stretch !important;align-items:stretch !important}.align-content-sm-start{-ms-flex-line-pack:start !important;align-content:flex-start !important}.align-content-sm-end{-ms-flex-line-pack:end !important;align-content:flex-end !important}.align-content-sm-center{-ms-flex-line-pack:center !important;align-content:center !important}.align-content-sm-between{-ms-flex-line-pack:justify !important;align-content:space-between !important}.align-content-sm-around{-ms-flex-line-pack:distribute !important;align-content:space-around !important}.align-content-sm-stretch{-ms-flex-line-pack:stretch !important;align-content:stretch !important}.align-self-sm-auto{-ms-flex-item-align:auto !important;align-self:auto !important}.align-self-sm-start{-ms-flex-item-align:start !important;align-self:flex-start !important}.align-self-sm-end{-ms-flex-item-align:end !important;align-self:flex-end !important}.align-self-sm-center{-ms-flex-item-align:center !important;align-self:center !important}.align-self-sm-baseline{-ms-flex-item-align:baseline !important;align-self:baseline !important}.align-self-sm-stretch{-ms-flex-item-align:stretch !important;align-self:stretch !important}}@media (min-width: 768px){.flex-md-row{-webkit-box-orient:horizontal !important;-webkit-box-direction:normal !important;-ms-flex-direction:row !important;flex-direction:row !important}.flex-md-column{-webkit-box-orient:vertical !important;-webkit-box-direction:normal !important;-ms-flex-direction:column !important;flex-direction:column !important}.flex-md-row-reverse{-webkit-box-orient:horizontal !important;-webkit-box-direction:reverse !important;-ms-flex-direction:row-reverse !important;flex-direction:row-reverse !important}.flex-md-column-reverse{-webkit-box-orient:vertical !important;-webkit-box-direction:reverse !important;-ms-flex-direction:column-reverse !important;flex-direction:column-reverse !important}.flex-md-wrap{-ms-flex-wrap:wrap !important;flex-wrap:wrap !important}.flex-md-nowrap{-ms-flex-wrap:nowrap !important;flex-wrap:nowrap !important}.flex-md-wrap-reverse{-ms-flex-wrap:wrap-reverse !important;flex-wrap:wrap-reverse !important}.flex-md-fill{-webkit-box-flex:1 !important;-ms-flex:1 1 auto !important;flex:1 1 auto !important}.flex-md-grow-0{-webkit-box-flex:0 !important;-ms-flex-positive:0 !important;flex-grow:0 !important}.flex-md-grow-1{-webkit-box-flex:1 !important;-ms-flex-positive:1 !important;flex-grow:1 !important}.flex-md-shrink-0{-ms-flex-negative:0 !important;flex-shrink:0 !important}.flex-md-shrink-1{-ms-flex-negative:1 !important;flex-shrink:1 !important}.justify-content-md-start{-webkit-box-pack:start !important;-ms-flex-pack:start !important;justify-content:flex-start !important}.justify-content-md-end{-webkit-box-pack:end !important;-ms-flex-pack:end !important;justify-content:flex-end !important}.justify-content-md-center{-webkit-box-pack:center !important;-ms-flex-pack:center !important;justify-content:center !important}.justify-content-md-between{-webkit-box-pack:justify !important;-ms-flex-pack:justify !important;justify-content:space-between !important}.justify-content-md-around{-ms-flex-pack:distribute !important;justify-content:space-around !important}.align-items-md-start{-webkit-box-align:start !important;-ms-flex-align:start !important;align-items:flex-start !important}.align-items-md-end{-webkit-box-align:end !important;-ms-flex-align:end !important;align-items:flex-end !important}.align-items-md-center{-webkit-box-align:center !important;-ms-flex-align:center !important;align-items:center !important}.align-items-md-baseline{-webkit-box-align:baseline !important;-ms-flex-align:baseline !important;align-items:baseline !important}.align-items-md-stretch{-webkit-box-align:stretch !important;-ms-flex-align:stretch !important;align-items:stretch !important}.align-content-md-start{-ms-flex-line-pack:start !important;align-content:flex-start !important}.align-content-md-end{-ms-flex-line-pack:end !important;align-content:flex-end !important}.align-content-md-center{-ms-flex-line-pack:center !important;align-content:center !important}.align-content-md-between{-ms-flex-line-pack:justify !important;align-content:space-between !important}.align-content-md-around{-ms-flex-line-pack:distribute !important;align-content:space-around !important}.align-content-md-stretch{-ms-flex-line-pack:stretch !important;align-content:stretch !important}.align-self-md-auto{-ms-flex-item-align:auto !important;align-self:auto !important}.align-self-md-start{-ms-flex-item-align:start !important;align-self:flex-start !important}.align-self-md-end{-ms-flex-item-align:end !important;align-self:flex-end !important}.align-self-md-center{-ms-flex-item-align:center !important;align-self:center !important}.align-self-md-baseline{-ms-flex-item-align:baseline !important;align-self:baseline !important}.align-self-md-stretch{-ms-flex-item-align:stretch !important;align-self:stretch !important}}@media (min-width: 992px){.flex-lg-row{-webkit-box-orient:horizontal !important;-webkit-box-direction:normal !important;-ms-flex-direction:row !important;flex-direction:row !important}.flex-lg-column{-webkit-box-orient:vertical !important;-webkit-box-direction:normal !important;-ms-flex-direction:column !important;flex-direction:column !important}.flex-lg-row-reverse{-webkit-box-orient:horizontal !important;-webkit-box-direction:reverse !important;-ms-flex-direction:row-reverse !important;flex-direction:row-reverse !important}.flex-lg-column-reverse{-webkit-box-orient:vertical !important;-webkit-box-direction:reverse !important;-ms-flex-direction:column-reverse !important;flex-direction:column-reverse !important}.flex-lg-wrap{-ms-flex-wrap:wrap !important;flex-wrap:wrap !important}.flex-lg-nowrap{-ms-flex-wrap:nowrap !important;flex-wrap:nowrap !important}.flex-lg-wrap-reverse{-ms-flex-wrap:wrap-reverse !important;flex-wrap:wrap-reverse !important}.flex-lg-fill{-webkit-box-flex:1 !important;-ms-flex:1 1 auto !important;flex:1 1 auto !important}.flex-lg-grow-0{-webkit-box-flex:0 !important;-ms-flex-positive:0 !important;flex-grow:0 !important}.flex-lg-grow-1{-webkit-box-flex:1 !important;-ms-flex-positive:1 !important;flex-grow:1 !important}.flex-lg-shrink-0{-ms-flex-negative:0 !important;flex-shrink:0 !important}.flex-lg-shrink-1{-ms-flex-negative:1 !important;flex-shrink:1 !important}.justify-content-lg-start{-webkit-box-pack:start !important;-ms-flex-pack:start !important;justify-content:flex-start !important}.justify-content-lg-end{-webkit-box-pack:end !important;-ms-flex-pack:end !important;justify-content:flex-end !important}.justify-content-lg-center{-webkit-box-pack:center !important;-ms-flex-pack:center !important;justify-content:center !important}.justify-content-lg-between{-webkit-box-pack:justify !important;-ms-flex-pack:justify !important;justify-content:space-between !important}.justify-content-lg-around{-ms-flex-pack:distribute !important;justify-content:space-around !important}.align-items-lg-start{-webkit-box-align:start !important;-ms-flex-align:start !important;align-items:flex-start !important}.align-items-lg-end{-webkit-box-align:end !important;-ms-flex-align:end !important;align-items:flex-end !important}.align-items-lg-center{-webkit-box-align:center !important;-ms-flex-align:center !important;align-items:center !important}.align-items-lg-baseline{-webkit-box-align:baseline !important;-ms-flex-align:baseline !important;align-items:baseline !important}.align-items-lg-stretch{-webkit-box-align:stretch !important;-ms-flex-align:stretch !important;align-items:stretch !important}.align-content-lg-start{-ms-flex-line-pack:start !important;align-content:flex-start !important}.align-content-lg-end{-ms-flex-line-pack:end !important;align-content:flex-end !important}.align-content-lg-center{-ms-flex-line-pack:center !important;align-content:center !important}.align-content-lg-between{-ms-flex-line-pack:justify !important;align-content:space-between !important}.align-content-lg-around{-ms-flex-line-pack:distribute !important;align-content:space-around !important}.align-content-lg-stretch{-ms-flex-line-pack:stretch !important;align-content:stretch !important}.align-self-lg-auto{-ms-flex-item-align:auto !important;align-self:auto !important}.align-self-lg-start{-ms-flex-item-align:start !important;align-self:flex-start !important}.align-self-lg-end{-ms-flex-item-align:end !important;align-self:flex-end !important}.align-self-lg-center{-ms-flex-item-align:center !important;align-self:center !important}.align-self-lg-baseline{-ms-flex-item-align:baseline !important;align-self:baseline !important}.align-self-lg-stretch{-ms-flex-item-align:stretch !important;align-self:stretch !important}}@media (min-width: 1200px){.flex-xl-row{-webkit-box-orient:horizontal !important;-webkit-box-direction:normal !important;-ms-flex-direction:row !important;flex-direction:row !important}.flex-xl-column{-webkit-box-orient:vertical !important;-webkit-box-direction:normal !important;-ms-flex-direction:column !important;flex-direction:column !important}.flex-xl-row-reverse{-webkit-box-orient:horizontal !important;-webkit-box-direction:reverse !important;-ms-flex-direction:row-reverse !important;flex-direction:row-reverse !important}.flex-xl-column-reverse{-webkit-box-orient:vertical !important;-webkit-box-direction:reverse !important;-ms-flex-direction:column-reverse !important;flex-direction:column-reverse !important}.flex-xl-wrap{-ms-flex-wrap:wrap !important;flex-wrap:wrap !important}.flex-xl-nowrap{-ms-flex-wrap:nowrap !important;flex-wrap:nowrap !important}.flex-xl-wrap-reverse{-ms-flex-wrap:wrap-reverse !important;flex-wrap:wrap-reverse !important}.flex-xl-fill{-webkit-box-flex:1 !important;-ms-flex:1 1 auto !important;flex:1 1 auto !important}.flex-xl-grow-0{-webkit-box-flex:0 !important;-ms-flex-positive:0 !important;flex-grow:0 !important}.flex-xl-grow-1{-webkit-box-flex:1 !important;-ms-flex-positive:1 !important;flex-grow:1 !important}.flex-xl-shrink-0{-ms-flex-negative:0 !important;flex-shrink:0 !important}.flex-xl-shrink-1{-ms-flex-negative:1 !important;flex-shrink:1 !important}.justify-content-xl-start{-webkit-box-pack:start !important;-ms-flex-pack:start !important;justify-content:flex-start !important}.justify-content-xl-end{-webkit-box-pack:end !important;-ms-flex-pack:end !important;justify-content:flex-end !important}.justify-content-xl-center{-webkit-box-pack:center !important;-ms-flex-pack:center !important;justify-content:center !important}.justify-content-xl-between{-webkit-box-pack:justify !important;-ms-flex-pack:justify !important;justify-content:space-between !important}.justify-content-xl-around{-ms-flex-pack:distribute !important;justify-content:space-around !important}.align-items-xl-start{-webkit-box-align:start !important;-ms-flex-align:start !important;align-items:flex-start !important}.align-items-xl-end{-webkit-box-align:end !important;-ms-flex-align:end !important;align-items:flex-end !important}.align-items-xl-center{-webkit-box-align:center !important;-ms-flex-align:center !important;align-items:center !important}.align-items-xl-baseline{-webkit-box-align:baseline !important;-ms-flex-align:baseline !important;align-items:baseline !important}.align-items-xl-stretch{-webkit-box-align:stretch !important;-ms-flex-align:stretch !important;align-items:stretch !important}.align-content-xl-start{-ms-flex-line-pack:start !important;align-content:flex-start !important}.align-content-xl-end{-ms-flex-line-pack:end !important;align-content:flex-end !important}.align-content-xl-center{-ms-flex-line-pack:center !important;align-content:center !important}.align-content-xl-between{-ms-flex-line-pack:justify !important;align-content:space-between !important}.align-content-xl-around{-ms-flex-line-pack:distribute !important;align-content:space-around !important}.align-content-xl-stretch{-ms-flex-line-pack:stretch !important;align-content:stretch !important}.align-self-xl-auto{-ms-flex-item-align:auto !important;align-self:auto !important}.align-self-xl-start{-ms-flex-item-align:start !important;align-self:flex-start !important}.align-self-xl-end{-ms-flex-item-align:end !important;align-self:flex-end !important}.align-self-xl-center{-ms-flex-item-align:center !important;align-self:center !important}.align-self-xl-baseline{-ms-flex-item-align:baseline !important;align-self:baseline !important}.align-self-xl-stretch{-ms-flex-item-align:stretch !important;align-self:stretch !important}}.w-25{width:25% !important}.w-50{width:50% !important}.w-75{width:75% !important}.w-100{width:100% !important}.w-auto{width:auto !important}.h-25{height:25% !important}.h-50{height:50% !important}.h-75{height:75% !important}.h-100{height:100% !important}.h-auto{height:auto !important}.mw-100{max-width:100% !important}.mh-100{max-height:100% !important}.m-0{margin:0 !important}.mt-0,.my-0{margin-top:0 !important}.mr-0,.mx-0{margin-right:0 !important}.mb-0,.my-0{margin-bottom:0 !important}.ml-0,.mx-0{margin-left:0 !important}.m-1{margin:.25rem !important}.mt-1,.my-1{margin-top:.25rem !important}.mr-1,.mx-1{margin-right:.25rem !important}.mb-1,.my-1{margin-bottom:.25rem !important}.ml-1,.mx-1{margin-left:.25rem !important}.m-2{margin:.5rem !important}.mt-2,.my-2{margin-top:.5rem !important}.mr-2,.mx-2{margin-right:.5rem !important}.mb-2,.my-2{margin-bottom:.5rem !important}.ml-2,.mx-2{margin-left:.5rem !important}.m-3{margin:1rem !important}.mt-3,.my-3{margin-top:1rem !important}.mr-3,.mx-3{margin-right:1rem !important}.mb-3,.my-3{margin-bottom:1rem !important}.ml-3,.mx-3{margin-left:1rem !important}.m-4{margin:1.5rem !important}.mt-4,.my-4{margin-top:1.5rem !important}.mr-4,.mx-4{margin-right:1.5rem !important}.mb-4,.my-4{margin-bottom:1.5rem !important}.ml-4,.mx-4{margin-left:1.5rem !important}.m-5{margin:3rem !important}.mt-5,.my-5{margin-top:3rem !important}.mr-5,.mx-5{margin-right:3rem !important}.mb-5,.my-5{margin-bottom:3rem !important}.ml-5,.mx-5{margin-left:3rem !important}.p-0{padding:0 !important}.pt-0,.py-0{padding-top:0 !important}.pr-0,.px-0{padding-right:0 !important}.pb-0,.py-0{padding-bottom:0 !important}.pl-0,.px-0{padding-left:0 !important}.p-1{padding:.25rem !important}.pt-1,.py-1{padding-top:.25rem !important}.pr-1,.px-1{padding-right:.25rem !important}.pb-1,.py-1{padding-bottom:.25rem !important}.pl-1,.px-1{padding-left:.25rem !important}.p-2{padding:.5rem !important}.pt-2,.py-2{padding-top:.5rem !important}.pr-2,.px-2{padding-right:.5rem !important}.pb-2,.py-2{padding-bottom:.5rem !important}.pl-2,.px-2{padding-left:.5rem !important}.p-3{padding:1rem !important}.pt-3,.py-3{padding-top:1rem !important}.pr-3,.px-3{padding-right:1rem !important}.pb-3,.py-3{padding-bottom:1rem !important}.pl-3,.px-3{padding-left:1rem !important}.p-4{padding:1.5rem !important}.pt-4,.py-4{padding-top:1.5rem !important}.pr-4,.px-4{padding-right:1.5rem !important}.pb-4,.py-4{padding-bottom:1.5rem !important}.pl-4,.px-4{padding-left:1.5rem !important}.p-5{padding:3rem !important}.pt-5,.py-5{padding-top:3rem !important}.pr-5,.px-5{padding-right:3rem !important}.pb-5,.py-5{padding-bottom:3rem !important}.pl-5,.px-5{padding-left:3rem !important}.m-auto{margin:auto !important}.mt-auto,.my-auto{margin-top:auto !important}.mr-auto,.mx-auto{margin-right:auto !important}.mb-auto,.my-auto{margin-bottom:auto !important}.ml-auto,.mx-auto{margin-left:auto !important}@media (min-width: 576px){.m-sm-0{margin:0 !important}.mt-sm-0,.my-sm-0{margin-top:0 !important}.mr-sm-0,.mx-sm-0{margin-right:0 !important}.mb-sm-0,.my-sm-0{margin-bottom:0 !important}.ml-sm-0,.mx-sm-0{margin-left:0 !important}.m-sm-1{margin:.25rem !important}.mt-sm-1,.my-sm-1{margin-top:.25rem !important}.mr-sm-1,.mx-sm-1{margin-right:.25rem !important}.mb-sm-1,.my-sm-1{margin-bottom:.25rem !important}.ml-sm-1,.mx-sm-1{margin-left:.25rem !important}.m-sm-2{margin:.5rem !important}.mt-sm-2,.my-sm-2{margin-top:.5rem !important}.mr-sm-2,.mx-sm-2{margin-right:.5rem !important}.mb-sm-2,.my-sm-2{margin-bottom:.5rem !important}.ml-sm-2,.mx-sm-2{margin-left:.5rem !important}.m-sm-3{margin:1rem !important}.mt-sm-3,.my-sm-3{margin-top:1rem !important}.mr-sm-3,.mx-sm-3{margin-right:1rem !important}.mb-sm-3,.my-sm-3{margin-bottom:1rem !important}.ml-sm-3,.mx-sm-3{margin-left:1rem !important}.m-sm-4{margin:1.5rem !important}.mt-sm-4,.my-sm-4{margin-top:1.5rem !important}.mr-sm-4,.mx-sm-4{margin-right:1.5rem !important}.mb-sm-4,.my-sm-4{margin-bottom:1.5rem !important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem !important}.m-sm-5{margin:3rem !important}.mt-sm-5,.my-sm-5{margin-top:3rem !important}.mr-sm-5,.mx-sm-5{margin-right:3rem !important}.mb-sm-5,.my-sm-5{margin-bottom:3rem !important}.ml-sm-5,.mx-sm-5{margin-left:3rem !important}.p-sm-0{padding:0 !important}.pt-sm-0,.py-sm-0{padding-top:0 !important}.pr-sm-0,.px-sm-0{padding-right:0 !important}.pb-sm-0,.py-sm-0{padding-bottom:0 !important}.pl-sm-0,.px-sm-0{padding-left:0 !important}.p-sm-1{padding:.25rem !important}.pt-sm-1,.py-sm-1{padding-top:.25rem !important}.pr-sm-1,.px-sm-1{padding-right:.25rem !important}.pb-sm-1,.py-sm-1{padding-bottom:.25rem !important}.pl-sm-1,.px-sm-1{padding-left:.25rem !important}.p-sm-2{padding:.5rem !important}.pt-sm-2,.py-sm-2{padding-top:.5rem !important}.pr-sm-2,.px-sm-2{padding-right:.5rem !important}.pb-sm-2,.py-sm-2{padding-bottom:.5rem !important}.pl-sm-2,.px-sm-2{padding-left:.5rem !important}.p-sm-3{padding:1rem !important}.pt-sm-3,.py-sm-3{padding-top:1rem !important}.pr-sm-3,.px-sm-3{padding-right:1rem !important}.pb-sm-3,.py-sm-3{padding-bottom:1rem !important}.pl-sm-3,.px-sm-3{padding-left:1rem !important}.p-sm-4{padding:1.5rem !important}.pt-sm-4,.py-sm-4{padding-top:1.5rem !important}.pr-sm-4,.px-sm-4{padding-right:1.5rem !important}.pb-sm-4,.py-sm-4{padding-bottom:1.5rem !important}.pl-sm-4,.px-sm-4{padding-left:1.5rem !important}.p-sm-5{padding:3rem !important}.pt-sm-5,.py-sm-5{padding-top:3rem !important}.pr-sm-5,.px-sm-5{padding-right:3rem !important}.pb-sm-5,.py-sm-5{padding-bottom:3rem !important}.pl-sm-5,.px-sm-5{padding-left:3rem !important}.m-sm-auto{margin:auto !important}.mt-sm-auto,.my-sm-auto{margin-top:auto !important}.mr-sm-auto,.mx-sm-auto{margin-right:auto !important}.mb-sm-auto,.my-sm-auto{margin-bottom:auto !important}.ml-sm-auto,.mx-sm-auto{margin-left:auto !important}}@media (min-width: 768px){.m-md-0{margin:0 !important}.mt-md-0,.my-md-0{margin-top:0 !important}.mr-md-0,.mx-md-0{margin-right:0 !important}.mb-md-0,.my-md-0{margin-bottom:0 !important}.ml-md-0,.mx-md-0{margin-left:0 !important}.m-md-1{margin:.25rem !important}.mt-md-1,.my-md-1{margin-top:.25rem !important}.mr-md-1,.mx-md-1{margin-right:.25rem !important}.mb-md-1,.my-md-1{margin-bottom:.25rem !important}.ml-md-1,.mx-md-1{margin-left:.25rem !important}.m-md-2{margin:.5rem !important}.mt-md-2,.my-md-2{margin-top:.5rem !important}.mr-md-2,.mx-md-2{margin-right:.5rem !important}.mb-md-2,.my-md-2{margin-bottom:.5rem !important}.ml-md-2,.mx-md-2{margin-left:.5rem !important}.m-md-3{margin:1rem !important}.mt-md-3,.my-md-3{margin-top:1rem !important}.mr-md-3,.mx-md-3{margin-right:1rem !important}.mb-md-3,.my-md-3{margin-bottom:1rem !important}.ml-md-3,.mx-md-3{margin-left:1rem !important}.m-md-4{margin:1.5rem !important}.mt-md-4,.my-md-4{margin-top:1.5rem !important}.mr-md-4,.mx-md-4{margin-right:1.5rem !important}.mb-md-4,.my-md-4{margin-bottom:1.5rem !important}.ml-md-4,.mx-md-4{margin-left:1.5rem !important}.m-md-5{margin:3rem !important}.mt-md-5,.my-md-5{margin-top:3rem !important}.mr-md-5,.mx-md-5{margin-right:3rem !important}.mb-md-5,.my-md-5{margin-bottom:3rem !important}.ml-md-5,.mx-md-5{margin-left:3rem !important}.p-md-0{padding:0 !important}.pt-md-0,.py-md-0{padding-top:0 !important}.pr-md-0,.px-md-0{padding-right:0 !important}.pb-md-0,.py-md-0{padding-bottom:0 !important}.pl-md-0,.px-md-0{padding-left:0 !important}.p-md-1{padding:.25rem !important}.pt-md-1,.py-md-1{padding-top:.25rem !important}.pr-md-1,.px-md-1{padding-right:.25rem !important}.pb-md-1,.py-md-1{padding-bottom:.25rem !important}.pl-md-1,.px-md-1{padding-left:.25rem !important}.p-md-2{padding:.5rem !important}.pt-md-2,.py-md-2{padding-top:.5rem !important}.pr-md-2,.px-md-2{padding-right:.5rem !important}.pb-md-2,.py-md-2{padding-bottom:.5rem !important}.pl-md-2,.px-md-2{padding-left:.5rem !important}.p-md-3{padding:1rem !important}.pt-md-3,.py-md-3{padding-top:1rem !important}.pr-md-3,.px-md-3{padding-right:1rem !important}.pb-md-3,.py-md-3{padding-bottom:1rem !important}.pl-md-3,.px-md-3{padding-left:1rem !important}.p-md-4{padding:1.5rem !important}.pt-md-4,.py-md-4{padding-top:1.5rem !important}.pr-md-4,.px-md-4{padding-right:1.5rem !important}.pb-md-4,.py-md-4{padding-bottom:1.5rem !important}.pl-md-4,.px-md-4{padding-left:1.5rem !important}.p-md-5{padding:3rem !important}.pt-md-5,.py-md-5{padding-top:3rem !important}.pr-md-5,.px-md-5{padding-right:3rem !important}.pb-md-5,.py-md-5{padding-bottom:3rem !important}.pl-md-5,.px-md-5{padding-left:3rem !important}.m-md-auto{margin:auto !important}.mt-md-auto,.my-md-auto{margin-top:auto !important}.mr-md-auto,.mx-md-auto{margin-right:auto !important}.mb-md-auto,.my-md-auto{margin-bottom:auto !important}.ml-md-auto,.mx-md-auto{margin-left:auto !important}}@media (min-width: 992px){.m-lg-0{margin:0 !important}.mt-lg-0,.my-lg-0{margin-top:0 !important}.mr-lg-0,.mx-lg-0{margin-right:0 !important}.mb-lg-0,.my-lg-0{margin-bottom:0 !important}.ml-lg-0,.mx-lg-0{margin-left:0 !important}.m-lg-1{margin:.25rem !important}.mt-lg-1,.my-lg-1{margin-top:.25rem !important}.mr-lg-1,.mx-lg-1{margin-right:.25rem !important}.mb-lg-1,.my-lg-1{margin-bottom:.25rem !important}.ml-lg-1,.mx-lg-1{margin-left:.25rem !important}.m-lg-2{margin:.5rem !important}.mt-lg-2,.my-lg-2{margin-top:.5rem !important}.mr-lg-2,.mx-lg-2{margin-right:.5rem !important}.mb-lg-2,.my-lg-2{margin-bottom:.5rem !important}.ml-lg-2,.mx-lg-2{margin-left:.5rem !important}.m-lg-3{margin:1rem !important}.mt-lg-3,.my-lg-3{margin-top:1rem !important}.mr-lg-3,.mx-lg-3{margin-right:1rem !important}.mb-lg-3,.my-lg-3{margin-bottom:1rem !important}.ml-lg-3,.mx-lg-3{margin-left:1rem !important}.m-lg-4{margin:1.5rem !important}.mt-lg-4,.my-lg-4{margin-top:1.5rem !important}.mr-lg-4,.mx-lg-4{margin-right:1.5rem !important}.mb-lg-4,.my-lg-4{margin-bottom:1.5rem !important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem !important}.m-lg-5{margin:3rem !important}.mt-lg-5,.my-lg-5{margin-top:3rem !important}.mr-lg-5,.mx-lg-5{margin-right:3rem !important}.mb-lg-5,.my-lg-5{margin-bottom:3rem !important}.ml-lg-5,.mx-lg-5{margin-left:3rem !important}.p-lg-0{padding:0 !important}.pt-lg-0,.py-lg-0{padding-top:0 !important}.pr-lg-0,.px-lg-0{padding-right:0 !important}.pb-lg-0,.py-lg-0{padding-bottom:0 !important}.pl-lg-0,.px-lg-0{padding-left:0 !important}.p-lg-1{padding:.25rem !important}.pt-lg-1,.py-lg-1{padding-top:.25rem !important}.pr-lg-1,.px-lg-1{padding-right:.25rem !important}.pb-lg-1,.py-lg-1{padding-bottom:.25rem !important}.pl-lg-1,.px-lg-1{padding-left:.25rem !important}.p-lg-2{padding:.5rem !important}.pt-lg-2,.py-lg-2{padding-top:.5rem !important}.pr-lg-2,.px-lg-2{padding-right:.5rem !important}.pb-lg-2,.py-lg-2{padding-bottom:.5rem !important}.pl-lg-2,.px-lg-2{padding-left:.5rem !important}.p-lg-3{padding:1rem !important}.pt-lg-3,.py-lg-3{padding-top:1rem !important}.pr-lg-3,.px-lg-3{padding-right:1rem !important}.pb-lg-3,.py-lg-3{padding-bottom:1rem !important}.pl-lg-3,.px-lg-3{padding-left:1rem !important}.p-lg-4{padding:1.5rem !important}.pt-lg-4,.py-lg-4{padding-top:1.5rem !important}.pr-lg-4,.px-lg-4{padding-right:1.5rem !important}.pb-lg-4,.py-lg-4{padding-bottom:1.5rem !important}.pl-lg-4,.px-lg-4{padding-left:1.5rem !important}.p-lg-5{padding:3rem !important}.pt-lg-5,.py-lg-5{padding-top:3rem !important}.pr-lg-5,.px-lg-5{padding-right:3rem !important}.pb-lg-5,.py-lg-5{padding-bottom:3rem !important}.pl-lg-5,.px-lg-5{padding-left:3rem !important}.m-lg-auto{margin:auto !important}.mt-lg-auto,.my-lg-auto{margin-top:auto !important}.mr-lg-auto,.mx-lg-auto{margin-right:auto !important}.mb-lg-auto,.my-lg-auto{margin-bottom:auto !important}.ml-lg-auto,.mx-lg-auto{margin-left:auto !important}}@media (min-width: 1200px){.m-xl-0{margin:0 !important}.mt-xl-0,.my-xl-0{margin-top:0 !important}.mr-xl-0,.mx-xl-0{margin-right:0 !important}.mb-xl-0,.my-xl-0{margin-bottom:0 !important}.ml-xl-0,.mx-xl-0{margin-left:0 !important}.m-xl-1{margin:.25rem !important}.mt-xl-1,.my-xl-1{margin-top:.25rem !important}.mr-xl-1,.mx-xl-1{margin-right:.25rem !important}.mb-xl-1,.my-xl-1{margin-bottom:.25rem !important}.ml-xl-1,.mx-xl-1{margin-left:.25rem !important}.m-xl-2{margin:.5rem !important}.mt-xl-2,.my-xl-2{margin-top:.5rem !important}.mr-xl-2,.mx-xl-2{margin-right:.5rem !important}.mb-xl-2,.my-xl-2{margin-bottom:.5rem !important}.ml-xl-2,.mx-xl-2{margin-left:.5rem !important}.m-xl-3{margin:1rem !important}.mt-xl-3,.my-xl-3{margin-top:1rem !important}.mr-xl-3,.mx-xl-3{margin-right:1rem !important}.mb-xl-3,.my-xl-3{margin-bottom:1rem !important}.ml-xl-3,.mx-xl-3{margin-left:1rem !important}.m-xl-4{margin:1.5rem !important}.mt-xl-4,.my-xl-4{margin-top:1.5rem !important}.mr-xl-4,.mx-xl-4{margin-right:1.5rem !important}.mb-xl-4,.my-xl-4{margin-bottom:1.5rem !important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem !important}.m-xl-5{margin:3rem !important}.mt-xl-5,.my-xl-5{margin-top:3rem !important}.mr-xl-5,.mx-xl-5{margin-right:3rem !important}.mb-xl-5,.my-xl-5{margin-bottom:3rem !important}.ml-xl-5,.mx-xl-5{margin-left:3rem !important}.p-xl-0{padding:0 !important}.pt-xl-0,.py-xl-0{padding-top:0 !important}.pr-xl-0,.px-xl-0{padding-right:0 !important}.pb-xl-0,.py-xl-0{padding-bottom:0 !important}.pl-xl-0,.px-xl-0{padding-left:0 !important}.p-xl-1{padding:.25rem !important}.pt-xl-1,.py-xl-1{padding-top:.25rem !important}.pr-xl-1,.px-xl-1{padding-right:.25rem !important}.pb-xl-1,.py-xl-1{padding-bottom:.25rem !important}.pl-xl-1,.px-xl-1{padding-left:.25rem !important}.p-xl-2{padding:.5rem !important}.pt-xl-2,.py-xl-2{padding-top:.5rem !important}.pr-xl-2,.px-xl-2{padding-right:.5rem !important}.pb-xl-2,.py-xl-2{padding-bottom:.5rem !important}.pl-xl-2,.px-xl-2{padding-left:.5rem !important}.p-xl-3{padding:1rem !important}.pt-xl-3,.py-xl-3{padding-top:1rem !important}.pr-xl-3,.px-xl-3{padding-right:1rem !important}.pb-xl-3,.py-xl-3{padding-bottom:1rem !important}.pl-xl-3,.px-xl-3{padding-left:1rem !important}.p-xl-4{padding:1.5rem !important}.pt-xl-4,.py-xl-4{padding-top:1.5rem !important}.pr-xl-4,.px-xl-4{padding-right:1.5rem !important}.pb-xl-4,.py-xl-4{padding-bottom:1.5rem !important}.pl-xl-4,.px-xl-4{padding-left:1.5rem !important}.p-xl-5{padding:3rem !important}.pt-xl-5,.py-xl-5{padding-top:3rem !important}.pr-xl-5,.px-xl-5{padding-right:3rem !important}.pb-xl-5,.py-xl-5{padding-bottom:3rem !important}.pl-xl-5,.px-xl-5{padding-left:3rem !important}.m-xl-auto{margin:auto !important}.mt-xl-auto,.my-xl-auto{margin-top:auto !important}.mr-xl-auto,.mx-xl-auto{margin-right:auto !important}.mb-xl-auto,.my-xl-auto{margin-bottom:auto !important}.ml-xl-auto,.mx-xl-auto{margin-left:auto !important}}.visible{visibility:visible !important}.invisible{visibility:hidden !important}
\ No newline at end of file
diff --git a/src/DevMenu.js b/src/DevMenu.js
deleted file mode 100644
index 48a4cbee1..000000000
--- a/src/DevMenu.js
+++ /dev/null
@@ -1,740 +0,0 @@
-import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
-import { CodingContractTypes } from "./CodingContracts";
-import { generateContract,
- generateRandomContract,
- generateRandomContractOnHome } from "./CodingContractGenerator";
-import { Companies } from "./Company/Companies";
-import { Company } from "./Company/Company";
-import { Programs } from "./Programs/Programs";
-import { Factions } from "./Faction/Factions";
-import { Player } from "./Player";
-import { AllServers } from "./Server/AllServers";
-import { hackWorldDaemon } from "./RedPill";
-import { StockMarket,
- SymbolToStockMap } from "./StockMarket/StockMarket";
-import { Stock } from "./StockMarket/Stock";
-import { Terminal } from "./Terminal";
-
-import { numeralWrapper } from "./ui/numeralFormat";
-
-import { dialogBoxCreate } from "../utils/DialogBox";
-import { exceptionAlert } from "../utils/helpers/exceptionAlert";
-import { createElement } from "../utils/uiHelpers/createElement";
-import { createOptionElement } from "../utils/uiHelpers/createOptionElement";
-import { getSelectText } from "../utils/uiHelpers/getSelectData";
-import { removeElementById } from "../utils/uiHelpers/removeElementById";
-
-const devMenuContainerId = "dev-menu-container";
-
-export function createDevMenu() {
- if (process.env.NODE_ENV !== "development") {
- throw new Error("Cannot create Dev Menu because you are not in a dev build");
- }
-
- const devMenuText = createElement("h1", {
- display: "block",
- innerText: "Development Menu - Only meant to be used for testing/debugging",
- });
-
- // Generic
- const genericHeader = createElement("h2", {
- display: "block",
- innerText: "Generic"
- });
-
- const addMoney = createElement("button", {
- class: "std-button",
- clickListener: () => {
- Player.gainMoney(1e15);
- },
- display: "block",
- innerText: "Add $1000t",
- });
-
- const addMoney2 = createElement("button", {
- class: "std-button",
- clickListener: () => {
- Player.gainMoney(1e12);
- },
- display: "block",
- innerText: "Add $1t",
- })
-
- const addRam = createElement("button", {
- class: "std-button",
- clickListener: () => {
- Player.getHomeComputer().maxRam *= 2;
- },
- display: "block",
- innerText: "Double Home Computer RAM",
- });
-
- const triggerBitflume = createElement("button", {
- class: "std-button",
- clickListener: () => {
- hackWorldDaemon(Player.bitNodeN, true);
- },
- innerText: "Trigger BitFlume",
- });
-
- const destroyCurrentBitnode = createElement("button", {
- class: "std-button",
- clickListener: () => {
- hackWorldDaemon(Player.bitNodeN);
- },
- innerText: "Destroy Current BitNode",
- tooltip: "Will grant Source-File for the BitNode",
- });
-
- // Experience / stats
- const statsHeader = createElement("h2", {
- display: "block",
- innerText: "Experience/Stats"
- });
-
- const statsHackingExpInput = createElement("input", {
- class: "text-input",
- margin: "5px",
- placeholder: "+/- hacking exp",
- type: "number",
- });
- const statsHackingExpButton = createElement("button", {
- class: "std-button",
- clickListener: () => {
- const exp = parseInt(statsHackingExpInput.value);
- Player.gainHackingExp(exp);
- Player.updateSkillLevels();
- },
- innerText: "Add Hacking Exp",
- });
-
- const statsStrengthExpInput = createElement("input", {
- class: "text-input",
- margin: "5px",
- placeholder: "+/- strength exp",
- type: "number",
- });
- const statsStrengthExpButton = createElement("button", {
- class: "std-button",
- clickListener: () => {
- const exp = parseInt(statsStrengthExpInput.value);
- Player.gainStrengthExp(exp);
- Player.updateSkillLevels();
- },
- innerText: "Add Strength Exp",
- });
-
- const statsDefenseExpInput = createElement("input", {
- class: "text-input",
- margin: "5px",
- placeholder: "+/- defense exp",
- type: "number",
- });
- const statsDefenseExpButton = createElement("button", {
- class: "std-button",
- clickListener: () => {
- const exp = parseInt(statsDefenseExpInput.value);
- Player.gainDefenseExp(exp);
- Player.updateSkillLevels();
- },
- innerText: "Add Defense Exp",
- });
-
- const statsDexterityExpInput = createElement("input", {
- class: "text-input",
- margin: "5px",
- placeholder: "+/- dexterity exp",
- type: "number",
- });
- const statsDexterityExpButton = createElement("button", {
- class: "std-button",
- clickListener: () => {
- const exp = parseInt(statsDexterityExpInput.value);
- Player.gainDexterityExp(exp);
- Player.updateSkillLevels();
- },
- innerText: "Add Dexterity Exp",
- });
-
- const statsAgilityExpInput = createElement("input", {
- class: "text-input",
- margin: "5px",
- placeholder: "+/- agility exp",
- type: "number",
- });
- const statsAgilityExpButton = createElement("button", {
- class: "std-button",
- clickListener: () => {
- const exp = parseInt(statsAgilityExpInput.value);
- Player.gainAgilityExp(exp);
- Player.updateSkillLevels();
- },
- innerText: "Add Agility Exp",
- });
-
- const statsCharismaExpInput = createElement("input", {
- class: "text-input",
- margin: "5px",
- placeholder: "+/- charisma exp",
- type: "number",
- });
- const statsCharismaExpButton = createElement("button", {
- class: "std-button",
- clickListener: () => {
- const exp = parseInt(statsCharismaExpInput.value);
- Player.gainCharismaExp(exp);
- Player.updateSkillLevels();
- },
- innerText: "Add Charisma Exp",
- });
-
- const statsIntelligenceExpInput = createElement("input", {
- class: "text-input",
- margin: "5px",
- placeholder: "+/- intelligence exp",
- type: "number",
- });
- const statsIntelligenceExpButton = createElement("button", {
- class: "std-button",
- clickListener: () => {
- const exp = parseInt(statsIntelligenceExpInput.value);
- Player.gainIntelligenceExp(exp);
- Player.updateSkillLevels();
- },
- innerText: "Add Intelligence Exp",
- });
-
- const statsEnableIntelligenceButton = createElement("button", {
- class: "std-button",
- clickListener: () => {
- Player.intelligence = 1;
- },
- innerText: "Enable Intelligence"
- });
-
- const statsDisableIntelligenceButton = createElement("button", {
- class: "std-button",
- clickListener: () => {
- Player.intelligence = 0;
- },
- innerText: "Disable Intelligence"
- });
-
- // Factions
- const factionsHeader = createElement("h2", {innerText: "Factions"});
-
- const factionsDropdown = createElement("select", {
- class: "dropdown",
- margin: "5px",
- });
- for (const i in Factions) {
- factionsDropdown.options[factionsDropdown.options.length] = new Option(Factions[i].name, Factions[i].name);
- }
-
- const factionsAddButton = createElement("button", {
- class: "std-button",
- clickListener: () => {
- const facName = factionsDropdown.options[factionsDropdown.selectedIndex].value;
- Player.receiveInvite(facName);
- },
- innerText: "Receive Invite to Faction",
- });
-
- const factionsReputationInput = createElement("input", {
- placeholder: "Rep to add to faction",
- type: "number",
- });
-
- const factionsReputationButton = createElement("button", {
- class: "std-button",
- innerText: "Add rep to faction",
- clickListener: () => {
- const facName = getSelectText(factionsDropdown);
- const fac = Factions[facName];
- const rep = parseFloat(factionsReputationInput.value);
- if (fac != null && !isNaN(rep)) {
- fac.playerReputation += rep;
- }
- },
- });
-
- // Augmentations
- const augmentationsHeader = createElement("h2", {innerText: "Augmentations"});
-
- const augmentationsDropdown = createElement("select", {
- class: "dropdown",
- margin: "5px",
- });
- for (const i in AugmentationNames) {
- const augName = AugmentationNames[i];
- augmentationsDropdown.options[augmentationsDropdown.options.length] = new Option(augName, augName);
- }
-
- const augmentationsQueueButton = createElement("button", {
- class: "std-button",
- clickListener: () => {
- Player.queueAugmentation(augmentationsDropdown.options[augmentationsDropdown.selectedIndex].value);
- },
- innerText: "Queue Augmentation",
- });
-
- const giveAllAugmentationsButton = createElement("button", {
- class: "std-button",
- clickListener: () => {
- for (const i in AugmentationNames) {
- const augName = AugmentationNames[i];
- Player.queueAugmentation(augName);
- }
- },
- display: "block",
- innerText: "Queue All Augmentations",
- });
-
- // Source Files
- const sourceFilesHeader = createElement("h2", { innerText: "Source-Files" });
-
- const removeSourceFileDropdown = createElement("select", {
- class: "dropdown",
- margin: "5px",
- });
- for (let i = 0; i < 24; ++i) {
- removeSourceFileDropdown.add(createOptionElement(String(i)));
- }
-
- const removeSourceFileButton = createElement("button", {
- class: "std-button",
- clickListener: () => {
- const numToRemove = parseInt(getSelectText(removeSourceFileDropdown));
- for (let i = 0; i < Player.sourceFiles.length; ++i) {
- if (Player.sourceFiles[i].n === numToRemove) {
- Player.sourceFiles.splice(i, 1);
- hackWorldDaemon(Player.bitNodeN, true);
- return;
- }
- }
- },
- innerText: "Remove Source File and Trigger Bitflume",
- });
-
- // Programs
- const programsHeader = createElement("h2", {innerText: "Programs"});
-
- const programsAddDropdown = createElement("select", {
- class: "dropdown",
- margin: "5px",
- });
- for (const i in Programs) {
- const progName = Programs[i].name;
- programsAddDropdown.options[programsAddDropdown.options.length] = new Option(progName, progName);
- }
-
- const programsAddButton = createElement("button", {
- class: "std-button",
- clickListener: () => {
- const program = programsAddDropdown.options[programsAddDropdown.selectedIndex].value;
- if(!Player.hasProgram(program)) {
- Player.getHomeComputer().programs.push(program);
- }
- },
- innerText: "Add Program",
- })
-
- // Servers
- const serversHeader = createElement("h2", {innerText: "Servers"});
-
- const serversOpenAll = createElement("button", {
- class: "std-button",
- clickListener: () => {
- for (const i in AllServers) {
- AllServers[i].hasAdminRights = true;
- AllServers[i].sshPortOpen = true;
- AllServers[i].ftpPortOpen = true;
- AllServers[i].smtpPortOpen = true;
- AllServers[i].httpPortOpen = true;
- AllServers[i].sqlPortOpen = true;
- AllServers[i].openPortCount = 5;
- }
- },
- display: "block",
- innerText: "Get Admin Rights to all servers",
- });
-
- const serversMinSecurityAll = createElement("button", {
- class: "std-button",
- clickListener: () => {
- for (const i in AllServers) {
- AllServers[i].hackDifficulty = AllServers[i].minDifficulty;
- }
- },
- display: "block",
- innerText: "Set all servers to min security",
- });
-
- const serversMaxMoneyAll = createElement("button", {
- class: "std-button",
- clickListener: () => {
- for (const i in AllServers) {
- AllServers[i].moneyAvailable = AllServers[i].moneyMax;
- }
- },
- display: "block",
- innerText: "Set all servers to max money",
- });
-
- const serversConnectToDropdown = createElement("select", {class: "dropdown"});
- for (const i in AllServers) {
- const hn = AllServers[i].hostname;
- serversConnectToDropdown.options[serversConnectToDropdown.options.length] = new Option(hn, hn);
- }
-
- const serversConnectToButton = createElement("button", {
- class: "std-button",
- clickListener: () => {
- const host = serversConnectToDropdown.options[serversConnectToDropdown.selectedIndex].value;
- Terminal.connectToServer(host);
- },
- innerText: "Connect to server",
- });
-
- // Companies
- const companiesHeader = createElement("h2", { innerText: "Companies" });
-
- const companiesDropdown = createElement("select", {
- class: "dropdown",
- margin: "5px",
- });
- for (const c in Companies) {
- companiesDropdown.add(createOptionElement(Companies[c].name));
- }
-
- const companyReputationInput = createElement("input", {
- margin: "5px",
- placeholder: "Rep to add to company",
- type: "number",
- });
-
- const companyReputationButton = createElement("button", {
- class: "std-button",
- innerText: "Add rep to company",
- clickListener: () => {
- const compName = getSelectText(companiesDropdown);
- const company = Companies[compName];
- const rep = parseFloat(companyReputationInput.value);
- if (company != null && !isNaN(rep)) {
- company.playerReputation += rep;
- } else {
- console.warn(`Invalid input for Dev Menu Company Rep. Company Name: ${compName}. Rep: ${rep}`);
- }
- }
- });
-
- // Bladeburner
- const bladeburnerHeader = createElement("h2", {innerText: "Bladeburner"});
-
- const bladeburnerGainRankInput = createElement("input", {
- class: "text-input",
- margin: "5px",
- placeholder: "Rank to gain (or negative to lose rank)",
- type: "number",
- });
-
- const bladeburnerGainRankButton = createElement("button", {
- class: "std-button",
- clickListener: () => {
- try {
- const rank = parseInt(bladeburnerGainRankInput.value);
- Player.bladeburner.changeRank(rank);
- } catch(e) {
- exceptionAlert(`Failed to change Bladeburner Rank in dev menu: ${e}`);
- }
- },
- innerText: "Gain Bladeburner Rank",
- });
-
- const bladeburnerStoredCyclesInput = createElement("input", {
- class: "text-input",
- margin: "5px",
- placeholder: "# Cycles to Add",
- type: "number",
- });
-
- const bladeburnerStoredCyclesButton = createElement("button", {
- class: "std-button",
- clickListener: () => {
- try {
- const cycles = parseInt(bladeburnerStoredCyclesInput.value);
- Player.bladeburner.storedCycles += cycles;
- } catch(e) {
- exceptionAlert(`Failed to add cycles to Bladeburner in dev menu: ${e}`);
- }
- },
- innerText: "Add Cycles to Bladeburner mechanic",
- });
-
- // Gang
- const gangHeader = createElement("h2", {innerText: "Gang"});
-
- const gangStoredCyclesInput = createElement("input", {
- class: "text-input",
- margin: "5px",
- placeholder: "# Cycles to add",
- type: "number",
- });
-
- const gangAddStoredCycles = createElement("button", {
- class: "std-button",
- clickListener: () => {
- try {
- const cycles = parseInt(gangStoredCyclesInput.value);
- Player.gang.storedCycles += cycles;
- } catch(e) {
- exceptionAlert(`Failed to add stored cycles to gang mechanic: ${e}`);
- }
- },
- innerText: "Add cycles to Gang mechanic",
- });
-
- // Corporation
- const corpHeader = createElement("h2", { innerText: "Corporation" });
-
- const corpStoredCyclesInput = createElement("input", {
- class: "text-input",
- margin: "5px",
- placeholder: "# Cycles to Add",
- type: "number",
- });
-
- const corpStoredCyclesButton = createElement("button", {
- class: "std-button",
- clickListener: () => {
- try {
- const cycles = parseInt(bladeburnerStoredCyclesInput.value);
- Player.corporation.storeCycles(cycles);
- } catch(e) {
- exceptionAlert(`Failed to add cycles to Bladeburner in dev menu: ${e}`);
- }
- },
- innerText: "Add Cycles to Corporation mechanic",
- });
-
- // Coding Contracts
- const contractsHeader = createElement("h2", {innerText: "Coding Contracts"});
-
- const generateRandomContractBtn = createElement("button", {
- class: "std-button",
- clickListener: () => {
- generateRandomContract();
- },
- innerText: "Generate Random Contract",
- });
-
- const generateRandomContractOnHomeBtn = createElement("button", {
- class: "std-button",
- clickListener: () => {
- generateRandomContractOnHome();
- },
- innerText: "Generate Random Contract on Home Comp",
- });
-
- const generateContractWithTypeSelector = createElement("select", { margin: "5px" });
- const contractTypes = Object.keys(CodingContractTypes);
- for (let i = 0; i < contractTypes.length; ++i) {
- generateContractWithTypeSelector.add(createOptionElement(contractTypes[i]));
- }
-
- const generateContractWithTypeBtn = createElement("button", {
- class: "std-button",
- clickListener: () => {
- generateContract({
- problemType: getSelectText(generateContractWithTypeSelector),
- server: "home",
- });
- },
- innerText: "Generate Specified Contract Type on Home Comp",
- });
-
- // Stock Market
- const stockmarketHeader = createElement("h2", {innerText: "Stock Market"});
-
- const stockInput = createElement("input", {
- class: "text-input",
- display: "block",
- placeholder: "Stock symbol(s), or 'all'",
- });
-
- function processStocks(cb) {
- const input = stockInput.value.toString().replace(/\s/g, '');
-
- // Empty input, or "all", will process all stocks
- if (input === "" || input.toLowerCase() === "all") {
- for (const name in StockMarket) {
- if (StockMarket.hasOwnProperty(name)) {
- const stock = StockMarket[name];
- if (stock instanceof Stock) {
- cb(stock);
- }
- }
- }
- return;
- }
-
- const stockSymbols = input.split(",");
- for (let i = 0; i < stockSymbols.length; ++i) {
- const stock = SymbolToStockMap[stockSymbols];
- if (stock instanceof Stock) {
- cb(stock);
- }
- }
- }
-
- const stockPriceChangeInput = createElement("input", {
- class: "text-input",
- margin: "5px",
- placeholder: "Price to change stock(s) to",
- type: "number",
- });
-
- const stockPriceChangeBtn = createElement("button", {
- class: "std-button",
- clickListener: () => {
- const price = parseInt(stockPriceChangeInput.value);
- if (isNaN(price)) { return; }
-
- processStocks((stock) => {
- stock.price = price;
- });
- dialogBoxCreate(`Stock Prices changed to ${price}`);
- },
- innerText: "Change Stock Price(s)",
- });
-
- const stockViewPriceCapBtn = createElement("button", {
- class: "std-button",
- clickListener: () => {
- let text = "";
- processStocks((stock) => {
- text += `${stock.symbol}: ${numeralWrapper.format(stock.cap, '$0.000a')}
`;
- });
- dialogBoxCreate(text);
- },
- innerText: "View Stock Price Caps",
- });
-
- // Sleeves
- const sleevesHeader = createElement("h2", { innerText: "Sleeves" });
-
- const sleevesRemoveAllShockRecovery = createElement("button", {
- class: "std-button",
- display: "block",
- innerText: "Set Shock Recovery of All Sleeves to 0",
- clickListener: () => {
- for (let i = 0; i < Player.sleeves.length; ++i) {
- Player.sleeves[i].shock = 100;
- }
- }
- });
-
- // Add everything to container, then append to main menu
- const devMenuContainer = createElement("div", {
- class: "generic-menupage-container",
- id: devMenuContainerId,
- });
-
- devMenuContainer.appendChild(devMenuText);
- devMenuContainer.appendChild(genericHeader);
- devMenuContainer.appendChild(addMoney);
- devMenuContainer.appendChild(addMoney2);
- devMenuContainer.appendChild(addRam);
- devMenuContainer.appendChild(triggerBitflume);
- devMenuContainer.appendChild(destroyCurrentBitnode);
- devMenuContainer.appendChild(statsHeader);
- devMenuContainer.appendChild(statsHackingExpInput);
- devMenuContainer.appendChild(statsHackingExpButton);
- devMenuContainer.appendChild(createElement("br"));
- devMenuContainer.appendChild(statsStrengthExpInput);
- devMenuContainer.appendChild(statsStrengthExpButton);
- devMenuContainer.appendChild(createElement("br"));
- devMenuContainer.appendChild(statsDefenseExpInput);
- devMenuContainer.appendChild(statsDefenseExpButton);
- devMenuContainer.appendChild(createElement("br"));
- devMenuContainer.appendChild(statsDexterityExpInput);
- devMenuContainer.appendChild(statsDexterityExpButton);
- devMenuContainer.appendChild(createElement("br"));
- devMenuContainer.appendChild(statsAgilityExpInput);
- devMenuContainer.appendChild(statsAgilityExpButton);
- devMenuContainer.appendChild(createElement("br"));
- devMenuContainer.appendChild(statsCharismaExpInput);
- devMenuContainer.appendChild(statsCharismaExpButton);
- devMenuContainer.appendChild(createElement("br"));
- devMenuContainer.appendChild(statsIntelligenceExpInput);
- devMenuContainer.appendChild(statsIntelligenceExpButton);
- devMenuContainer.appendChild(createElement("br"));
- devMenuContainer.appendChild(statsEnableIntelligenceButton);
- devMenuContainer.appendChild(statsDisableIntelligenceButton);
- devMenuContainer.appendChild(factionsHeader);
- devMenuContainer.appendChild(factionsDropdown);
- devMenuContainer.appendChild(factionsAddButton);
- devMenuContainer.appendChild(createElement("br"));
- devMenuContainer.appendChild(factionsReputationInput);
- devMenuContainer.appendChild(factionsReputationButton);
- devMenuContainer.appendChild(augmentationsHeader);
- devMenuContainer.appendChild(augmentationsDropdown);
- devMenuContainer.appendChild(augmentationsQueueButton);
- devMenuContainer.appendChild(giveAllAugmentationsButton);
- devMenuContainer.appendChild(sourceFilesHeader);
- devMenuContainer.appendChild(removeSourceFileDropdown);
- devMenuContainer.appendChild(removeSourceFileButton);
- devMenuContainer.appendChild(programsHeader);
- devMenuContainer.appendChild(programsAddDropdown);
- devMenuContainer.appendChild(programsAddButton);
- devMenuContainer.appendChild(serversHeader);
- devMenuContainer.appendChild(serversOpenAll);
- devMenuContainer.appendChild(serversMinSecurityAll);
- devMenuContainer.appendChild(serversMaxMoneyAll);
- devMenuContainer.appendChild(serversConnectToDropdown);
- devMenuContainer.appendChild(serversConnectToButton);
- devMenuContainer.appendChild(companiesHeader);
- devMenuContainer.appendChild(companiesDropdown);
- devMenuContainer.appendChild(createElement("br"));
- devMenuContainer.appendChild(companyReputationInput);
- devMenuContainer.appendChild(companyReputationButton);
- devMenuContainer.appendChild(bladeburnerHeader);
- devMenuContainer.appendChild(bladeburnerGainRankInput);
- devMenuContainer.appendChild(bladeburnerGainRankButton);
- devMenuContainer.appendChild(createElement("br"));
- devMenuContainer.appendChild(bladeburnerStoredCyclesInput);
- devMenuContainer.appendChild(bladeburnerStoredCyclesButton);
- devMenuContainer.appendChild(createElement("br"));
- devMenuContainer.appendChild(gangHeader);
- devMenuContainer.appendChild(gangStoredCyclesInput);
- devMenuContainer.appendChild(gangAddStoredCycles);
- devMenuContainer.appendChild(createElement("br"));
- devMenuContainer.appendChild(corpHeader);
- devMenuContainer.appendChild(corpStoredCyclesInput);
- devMenuContainer.appendChild(corpStoredCyclesButton);
- devMenuContainer.appendChild(createElement("br"));
- devMenuContainer.appendChild(contractsHeader);
- devMenuContainer.appendChild(generateRandomContractBtn);
- devMenuContainer.appendChild(generateRandomContractOnHomeBtn);
- devMenuContainer.appendChild(createElement("br"));
- devMenuContainer.appendChild(generateContractWithTypeSelector);
- devMenuContainer.appendChild(generateContractWithTypeBtn);
- devMenuContainer.appendChild(stockmarketHeader);
- devMenuContainer.appendChild(stockInput);
- devMenuContainer.appendChild(stockPriceChangeInput);
- devMenuContainer.appendChild(stockPriceChangeBtn);
- devMenuContainer.appendChild(createElement("br"));
- devMenuContainer.appendChild(stockViewPriceCapBtn);
- devMenuContainer.appendChild(sleevesHeader);
- devMenuContainer.appendChild(sleevesRemoveAllShockRecovery);
-
- const entireGameContainer = document.getElementById("entire-game-container");
- if (entireGameContainer == null) {
- throw new Error("Could not find entire-game-container DOM element");
- }
- entireGameContainer.appendChild(devMenuContainer);
-}
-
-export function closeDevMenu() {
- removeElementById(devMenuContainerId);
-}
diff --git a/src/DevMenu.jsx b/src/DevMenu.jsx
new file mode 100644
index 000000000..bba6fe1ca
--- /dev/null
+++ b/src/DevMenu.jsx
@@ -0,0 +1,1875 @@
+import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
+import { CodingContractTypes } from "./CodingContracts";
+import { generateContract,
+ generateRandomContract,
+ generateRandomContractOnHome } from "./CodingContractGenerator";
+import { Companies } from "./Company/Companies";
+import { Company } from "./Company/Company";
+import { Programs } from "./Programs/Programs";
+import { Factions } from "./Faction/Factions";
+import { Player } from "./Player";
+import { PlayerOwnedSourceFile } from "./SourceFile/PlayerOwnedSourceFile";
+import { AllServers } from "./Server/AllServers";
+import { GetServerByHostname } from "./Server/ServerHelpers";
+import { hackWorldDaemon } from "./RedPill";
+import { StockMarket,
+ SymbolToStockMap } from "./StockMarket/StockMarket";
+import { Stock } from "./StockMarket/Stock";
+import { Terminal } from "./Terminal";
+
+import { numeralWrapper } from "./ui/numeralFormat";
+
+import { dialogBoxCreate } from "../utils/DialogBox";
+import { exceptionAlert } from "../utils/helpers/exceptionAlert";
+import { createElement } from "../utils/uiHelpers/createElement";
+import { createOptionElement } from "../utils/uiHelpers/createOptionElement";
+import { getSelectText } from "../utils/uiHelpers/getSelectData";
+import { removeElementById } from "../utils/uiHelpers/removeElementById";
+
+import React from "react";
+import ReactDOM from "react-dom";
+
+const Component = React.Component;
+
+const validSFN = [1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12];
+
+class DevMenuComponent extends Component {
+ constructor(props) {
+ super(props);
+ this.setSF = this.setSF.bind(this);
+ this.setAllSF = this.setAllSF.bind(this);
+ this.processStocks = this.processStocks.bind(this);
+ this.setStockPrice = this.setStockPrice.bind(this);
+ this.viewStockCaps = this.viewStockCaps.bind(this);
+ }
+
+ addMoney(n) {
+ return function() {
+ Player.gainMoney(n);
+ }
+ }
+
+ upgradeRam() {
+ Player.getHomeComputer().maxRam *= 2;
+ }
+
+ b1tflum3() {
+ hackWorldDaemon(Player.bitNodeN, true);
+ }
+
+ hackW0r1dD43m0n() {
+ hackWorldDaemon(Player.bitNodeN);
+ }
+
+ modifyExp(stat, modifier) {
+ return function() {
+ let field = null;
+ let exp = 0;
+ switch(stat) {
+ case "hacking":
+ field = document.getElementById('dev-hacking-exp');
+ exp = parseInt(field.value);
+ if(exp) {
+ Player.gainHackingExp(exp*modifier);
+ }
+ break;
+ case "strength":
+ field = document.getElementById('dev-strength-exp');
+ exp = parseInt(field.value);
+ if(exp) {
+ Player.gainStrengthExp(exp*modifier);
+ }
+ break;
+ case "defense":
+ field = document.getElementById('dev-defense-exp');
+ exp = parseInt(field.value);
+ if(exp) {
+ Player.gainDefenseExp(exp*modifier);
+ }
+ break;
+ case "dexterity":
+ field = document.getElementById('dev-dexterity-exp');
+ exp = parseInt(field.value);
+ if(exp) {
+ Player.gainDexterityExp(exp*modifier);
+ }
+ break;
+ case "agility":
+ field = document.getElementById('dev-agility-exp');
+ exp = parseInt(field.value);
+ if(exp) {
+ Player.gainAgilityExp(exp*modifier);
+ }
+ break;
+ case "charisma":
+ field = document.getElementById('dev-charisma-exp');
+ exp = parseInt(field.value);
+ if(exp) {
+ Player.gainCharismaExp(exp*modifier);
+ }
+ break;
+ case "intelligence":
+ field = document.getElementById('dev-intelligence-exp');
+ exp = parseInt(field.value);
+ if(exp) {
+ Player.gainIntelligenceExp(exp*modifier);
+ }
+ break;
+ }
+ Player.updateSkillLevels();
+ }
+ }
+
+ tonsOfExp() {
+ Player.gainHackingExp(1e27);
+ Player.gainStrengthExp(1e27);
+ Player.gainDefenseExp(1e27);
+ Player.gainDexterityExp(1e27);
+ Player.gainAgilityExp(1e27);
+ Player.gainCharismaExp(1e27);
+ Player.gainIntelligenceExp(1e27);
+ Player.updateSkillLevels();
+ }
+
+ resetAllExp() {
+ Player.hacking_exp = 0;
+ Player.strength_exp = 0;
+ Player.defense_exp = 0;
+ Player.dexterity_exp = 0;
+ Player.agility_exp = 0;
+ Player.charisma_exp = 0;
+ Player.intelligence_exp = 0;
+ Player.updateSkillLevels();
+ }
+
+ resetExperience(stat) {
+ return function() {
+ switch(stat) {
+ case "hacking":
+ Player.hacking_exp = 0;
+ break;
+ case "strength":
+ Player.strength_exp = 0;
+ break;
+ case "defense":
+ Player.defense_exp = 0;
+ break;
+ case "dexterity":
+ Player.dexterity_exp = 0;
+ break;
+ case "agility":
+ Player.agility_exp = 0;
+ break;
+ case "charisma":
+ Player.charisma_exp = 0;
+ break;
+ case "intelligence":
+ Player.intelligence_exp = 0;
+ break;
+ }
+ Player.updateSkillLevels();
+ }
+ }
+
+ enableIntelligence() {
+ if(Player.intelligence === 0) {
+ Player.intelligence = 1;
+ Player.updateSkillLevels();
+ }
+ }
+
+ disableIntelligence() {
+ Player.intelligence_exp = 0;
+ Player.intelligence = 0;
+ Player.updateSkillLevels();
+ }
+
+ factionNames() {
+ for (const i in Factions) {
+ factionsDropdown.options[factionsDropdown.options.length] = new Option(Factions[i].name, Factions[i].name);
+ }
+ return
+ }
+
+ receiveInvite() {
+ const factionsDropdown = document.getElementById('factions-dropdown');
+ const facName = factionsDropdown.options[factionsDropdown.selectedIndex].value;
+ Player.receiveInvite(facName);
+ }
+
+ receiveAllInvites() {
+ for (const i in Factions) {
+ Player.receiveInvite(Factions[i].name);
+ }
+ }
+
+ modifyRep(modifier) {
+ return function() {
+ const field = document.getElementById('dev-faction-rep');
+ const factionsDropdown = document.getElementById('factions-dropdown');
+ const facName = factionsDropdown.options[factionsDropdown.selectedIndex].value;
+ const fac = Factions[facName];
+ const rep = parseFloat(field.value);
+ if (fac != null && !isNaN(rep)) {
+ fac.playerReputation += rep*modifier;
+ }
+ }
+ }
+
+ resetRep() {
+ const factionsDropdown = document.getElementById('factions-dropdown');
+ const facName = factionsDropdown.options[factionsDropdown.selectedIndex].value;
+ const fac = Factions[facName];
+ if (fac != null) {
+ fac.playerReputation = 0;
+ }
+ }
+
+ modifyFactionFavor(modifier) {
+ return function() {
+ const field = document.getElementById('dev-faction-favor');
+ const factionsDropdown = document.getElementById('factions-dropdown');
+ const facName = factionsDropdown.options[factionsDropdown.selectedIndex].value;
+ const fac = Factions[facName];
+ const rep = parseFloat(field.value);
+ if (fac != null && !isNaN(rep)) {
+ fac.favor += rep*modifier;
+ }
+ }
+ }
+
+ resetFactionFavor() {
+ const factionsDropdown = document.getElementById('factions-dropdown');
+ const facName = factionsDropdown.options[factionsDropdown.selectedIndex].value;
+ const fac = Factions[facName];
+ if (fac != null) {
+ fac.favor = 0;
+ }
+ }
+
+ tonsOfRep() {
+ for (const i in Factions) {
+ Factions[i].playerReputation = 1e27;
+ }
+ }
+
+ resetAllRep() {
+ for (const i in Factions) {
+ Factions[i].playerReputation = 0;
+ }
+ }
+
+ tonsOfFactionFavor() {
+ for (const i in Factions) {
+ Factions[i].favor = 1e27;
+ }
+ }
+
+ resetAllFactionFavor() {
+ for (const i in Factions) {
+ Factions[i].favor = 0;
+ }
+ }
+
+ queueAug() {
+ const augsDropdown = document.getElementById('dev-augs-dropdown');
+ const augName = augsDropdown.options[augsDropdown.selectedIndex].value;
+ Player.queueAugmentation(augName);
+ }
+
+ queueAllAugs() {
+ for (const i in AugmentationNames) {
+ const augName = AugmentationNames[i];
+ Player.queueAugmentation(augName);
+ }
+ }
+
+ setSF(sfN, sfLvl) {
+ return function() {
+ if (sfLvl === 0) {
+ Player.sourceFiles = Player.sourceFiles.filter((sf) => sf.n !== sfN);
+ return;
+ }
+
+ if(!Player.sourceFiles.some((sf) => sf.n === sfN)) {
+ Player.sourceFiles.push(new PlayerOwnedSourceFile(sfN, sfLvl));
+ return;
+ }
+
+ for(let i = 0; i < Player.sourceFiles.length; i++) {
+ if (Player.sourceFiles[i].n === sfN) {
+ Player.sourceFiles[i].lvl = sfLvl;
+ }
+ }
+ }
+ }
+
+ setAllSF(sfLvl) {
+ const component = this;
+ return function(){
+ for (let i = 0; i < validSFN.length; i++) {
+ component.setSF(validSFN[i], sfLvl)();
+ }
+ }
+ }
+
+ addProgram() {
+ const programDropdown = document.getElementById('dev-programs-dropdown');
+ const program = programDropdown.options[programDropdown.selectedIndex].value;
+ if(!Player.hasProgram(program)) {
+ Player.getHomeComputer().programs.push(program);
+ }
+ }
+
+ addAllPrograms() {
+ for (const i in Programs) {
+ if(!Player.hasProgram(Programs[i].name)) {
+ Player.getHomeComputer().programs.push(Programs[i].name);
+ }
+ }
+ }
+
+ rootServer() {
+ const serverDropdown = document.getElementById('dev-servers-dropdown');
+ const serverName = serverDropdown.options[serverDropdown.selectedIndex].value;
+
+ const server = GetServerByHostname(serverName);
+
+ server.hasAdminRights = true;
+ server.sshPortOpen = true;
+ server.ftpPortOpen = true;
+ server.smtpPortOpen = true;
+ server.httpPortOpen = true;
+ server.sqlPortOpen = true;
+ server.openPortCount = 5;
+ }
+
+ rootAllServers() {
+ for (const i in AllServers) {
+ AllServers[i].hasAdminRights = true;
+ AllServers[i].sshPortOpen = true;
+ AllServers[i].ftpPortOpen = true;
+ AllServers[i].smtpPortOpen = true;
+ AllServers[i].httpPortOpen = true;
+ AllServers[i].sqlPortOpen = true;
+ AllServers[i].openPortCount = 5;
+ }
+ }
+
+ minSecurity() {
+ const serverDropdown = document.getElementById('dev-servers-dropdown');
+ const serverName = serverDropdown.options[serverDropdown.selectedIndex].value;
+
+ const server = GetServerByHostname(serverName);
+ server.hackDifficulty = server.minDifficulty;
+ }
+
+ minAllSecurity() {
+ for (const i in AllServers) {
+ AllServers[i].hackDifficulty = AllServers[i].minDifficulty;
+ }
+ }
+
+ maxMoney() {
+ const serverDropdown = document.getElementById('dev-servers-dropdown');
+ const serverName = serverDropdown.options[serverDropdown.selectedIndex].value;
+
+ const server = GetServerByHostname(serverName);
+ server.moneyAvailable = server.moneyMax;
+ }
+
+ maxAllMoney() {
+ for (const i in AllServers) {
+ AllServers[i].moneyAvailable = AllServers[i].moneyMax;
+ }
+ }
+
+ modifyCompanyRep(modifier) {
+ return function() {
+ const field = document.getElementById('dev-company-rep');
+ const companyDropdown = document.getElementById('dev-companies-dropdown');
+ const companyName = companyDropdown.options[companyDropdown.selectedIndex].value;
+ const company = Companies[companyName];
+ const rep = parseFloat(field.value);
+ if (company != null && !isNaN(rep)) {
+ company.playerReputation += rep*modifier;
+ }
+ }
+ }
+
+ resetCompanyRep() {
+ const companyDropdown = document.getElementById('dev-companies-dropdown');
+ const companyName = companyDropdown.options[companyDropdown.selectedIndex].value;
+ const company = Companies[companyName];
+ company.playerReputation = 0;
+ }
+
+ modifyCompanyFavor(modifier) {
+ return function() {
+ const field = document.getElementById('dev-company-favor');
+ const companyDropdown = document.getElementById('dev-companies-dropdown');
+ const companyName = companyDropdown.options[companyDropdown.selectedIndex].value;
+ const company = Companies[companyName];
+ const rep = parseFloat(field.value);
+ if (company != null && !isNaN(rep)) {
+ company.favor += rep*modifier;
+ console.log(company.favor);
+ }
+ }
+ }
+
+ resetCompanyFavor() {
+ const companyDropdown = document.getElementById('dev-companies-dropdown');
+ const companyName = companyDropdown.options[companyDropdown.selectedIndex].value;
+ const company = Companies[companyName];
+ company.favor = 0;
+ }
+
+ tonsOfRepCompanies() {
+ for (const c in Companies) {
+ Companies[c].playerReputation = 1e12;
+ }
+ }
+
+ resetAllRepCompanies() {
+ for (const c in Companies) {
+ Companies[c].playerReputation = 0;
+ }
+ }
+
+ tonsOfFavorCompanies() {
+ for (const c in Companies) {
+ Companies[c].favor = 1e12;
+ }
+ }
+
+ resetAllFavorCompanies() {
+ for (const c in Companies) {
+ Companies[c].favor = 0;
+ }
+ }
+
+ modifyBladeburnerRank(modify) {
+ return function() {
+ const field = document.getElementById('dev-bladeburner-rank');
+ const rank = parseInt(field.value);
+ if (!!Player.bladeburner) {
+ Player.bladeburner.changeRank(rank*modify);
+ }
+ }
+ }
+
+ resetBladeburnerRank() {
+ Player.bladeburner.rank = 0;
+ Player.bladeburner.maxRank = 0;
+ }
+
+ addTonsBladeburnerRank() {
+ if (!!Player.bladeburner) {
+ Player.bladeburner.changeRank(1e12);
+ }
+ }
+
+ modifyBladeburnerCycles(modify) {
+ return function() {
+ if (!!Player.bladeburner) {
+ const field = document.getElementById('dev-bladeburner-cycles');
+ const cycles = parseInt(field.value);
+ Player.bladeburner.storedCycles += cycles*modify;
+ }
+ }
+ }
+
+ resetBladeburnerCycles() {
+ if (!!Player.bladeburner) {
+ Player.bladeburner.storedCycles = 0;
+ }
+ }
+
+ addTonsBladeburnerCycles() {
+ if (!!Player.bladeburner) {
+ Player.bladeburner.storedCycles += 1e12;
+ }
+ }
+
+ addTonsGangCycles() {
+ if (!!Player.gang) {
+ Player.gang.storedCycles = 1e12;
+ }
+ }
+
+ modifyGangCycles(modify) {
+ return function() {
+ if (!!Player.gang) {
+ const field = document.getElementById('dev-gang-cycles');
+ const cycles = parseInt(field.value);
+ Player.gang.storedCycles += cycles*modify;
+ }
+ }
+ }
+
+ resetGangCycles() {
+ if (!!Player.gang) {
+ Player.gang.storedCycles = 0;
+ }
+ }
+
+ addTonsCorporationCycles() {
+ if (!!Player.corporation) {
+ Player.corporation.storedCycles = 1e12;
+ }
+ }
+
+ modifyCorporationCycles(modify) {
+ return function() {
+ if (!!Player.corporation) {
+ const field = document.getElementById('dev-corporation-cycles');
+ const cycles = parseInt(field.value);
+ Player.corporation.storedCycles += cycles*modify;
+ }
+ }
+ }
+
+ resetCorporationCycles() {
+ if (!!Player.corporation) {
+ Player.corporation.storedCycles = 0;
+ }
+ }
+
+ specificContract() {
+ const contractDropdown = document.getElementById('contract-types-dropdown');
+ const contractType = contractDropdown.options[contractDropdown.selectedIndex].value;
+ generateContract({
+ problemType: contractType,
+ server: "home",
+ });
+ }
+
+ processStocks(cb) {
+ const inputSymbols = document.getElementById('dev-stock-symbol').value.toString().replace(/\s/g, '');
+
+ let match = function(symbol) { return true; }
+
+ if (inputSymbols !== '' && inputSymbols !== 'all') {
+ match = function(symbol) {
+ return inputSymbols.split(',').includes(symbol);
+ };
+ }
+
+ for (const name in StockMarket) {
+ if (StockMarket.hasOwnProperty(name)) {
+ const stock = StockMarket[name];
+ if (stock instanceof Stock && match(stock.symbol)) {
+ cb(stock);
+ }
+ }
+ }
+ }
+
+ setStockPrice() {
+ const price = parseFloat(document.getElementById('dev-stock-price').value);
+
+ if (!isNaN(price)) {
+ this.processStocks((stock) => {
+ stock.price = price;
+ });
+ }
+ }
+
+ viewStockCaps() {
+ let text = "";
+ this.processStocks((stock) => {
+ text += `${stock.symbol}: ${numeralWrapper.format(stock.cap, '$0.000a')}
`;
+ });
+ dialogBoxCreate(text);
+ }
+
+ sleeveMaxAllShock() {
+ for (let i = 0; i < Player.sleeves.length; ++i) {
+ Player.sleeves[i].shock = 0;
+ }
+ }
+ sleeveClearAllShock() {
+ for (let i = 0; i < Player.sleeves.length; ++i) {
+ Player.sleeves[i].shock = 100;
+ }
+ }
+ sleeveMaxAllSync() {
+ for (let i = 0; i < Player.sleeves.length; ++i) {
+ Player.sleeves[i].sync = 100;
+ }
+ }
+ sleeveClearAllSync() {
+ for (let i = 0; i < Player.sleeves.length; ++i) {
+ Player.sleeves[i].sync = 0;
+ }
+ }
+
+ render() {
+ let factions = [];
+ for (const i in Factions) {
+ factions.push();
+ }
+
+ let augs = [];
+ for (const i in AugmentationNames) {
+ augs.push();
+ }
+
+ let programs = [];
+ for (const i in Programs) {
+ programs.push();
+ }
+
+ let sourceFiles = [];
+ validSFN.forEach( i => sourceFiles.push(
+
+ | SF-{i}: |
+
+
+
+
+
+ |
+
+));
+
+
+
+ let servers = [];
+ for (const i in AllServers) {
+ const hn = AllServers[i].hostname;
+ servers.push();
+ }
+
+ let companies = [];
+ for (const c in Companies) {
+ const name = Companies[c].name;
+ companies.push();
+ }
+
+ const contractTypes = [];
+ const contractTypeNames = Object.keys(CodingContractTypes)
+ for (let i = 0; i < contractTypeNames.length; i++) {
+ const name = contractTypeNames[i];
+ contractTypes.push();
+ }
+
+
+ return (
+
+
+
Generic
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Experience / Stats
+
+
+
+
+
+
+
+
+
Augmentations
+
+
+
+
+ | Aug: |
+ |
+
+
+ | Queue: |
+
+ |
+
+
+
+
+
+
+
+
+
Source-Files
+
+
+
+
+ | All: |
+
+
+
+
+
+ |
+
+ {sourceFiles}
+
+
+
+
+
+
+
+
Programs
+
+
+
+
+ | Program: |
+ |
+
+
+ | Add: |
+
+
+
+ |
+
+
+
+
+
+
+
+
+
Servers
+
+
+
+
+ | Server: |
+ |
+
+
+ | Root: |
+ |
+ |
+
+
+ | Security: |
+ |
+ |
+
+
+ | Money: |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Coding Contracts
+
+
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Sleeves
+
+
+
+
+ | Shock: |
+ |
+ |
+
+
+ | Sync: |
+ |
+ |
+
+
+
+
+
+
+
+ );
+ }
+}
+
+
+const devMenuContainerId = "dev-menu-container";
+
+export function createDevMenu() {
+ if (process.env.NODE_ENV !== "development") {
+ throw new Error("Cannot create Dev Menu because you are not in a dev build");
+ }
+
+ const devMenuText = createElement("h1", {
+ display: "block",
+ innerText: "Development Menu - Only meant to be used for testing/debugging",
+ });
+
+ // Generic
+ const genericHeader = createElement("h2", {
+ display: "block",
+ innerText: "Generic"
+ });
+
+ const addMoney = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ Player.gainMoney(1e15);
+ },
+ display: "block",
+ innerText: "Add $1000t",
+ });
+
+ const addMoney2 = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ Player.gainMoney(1e12);
+ },
+ display: "block",
+ innerText: "Add $1t",
+ })
+
+ const addRam = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ Player.getHomeComputer().maxRam *= 2;
+ },
+ display: "block",
+ innerText: "Double Home Computer RAM",
+ });
+
+ const triggerBitflume = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ hackWorldDaemon(Player.bitNodeN, true);
+ },
+ innerText: "Trigger BitFlume",
+ });
+
+ const destroyCurrentBitnode = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ hackWorldDaemon(Player.bitNodeN);
+ },
+ innerText: "Destroy Current BitNode",
+ tooltip: "Will grant Source-File for the BitNode",
+ });
+
+ // Experience / stats
+ const statsHeader = createElement("h2", {
+ display: "block",
+ innerText: "Experience/Stats"
+ });
+
+ const statsHackingExpInput = createElement("input", {
+ class: "text-input",
+ margin: "5px",
+ placeholder: "+/- hacking exp",
+ type: "number",
+ });
+ const statsHackingExpButton = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ const exp = parseInt(statsHackingExpInput.value);
+ Player.gainHackingExp(exp);
+ Player.updateSkillLevels();
+ },
+ innerText: "Add Hacking Exp",
+ });
+
+ const statsStrengthExpInput = createElement("input", {
+ class: "text-input",
+ margin: "5px",
+ placeholder: "+/- strength exp",
+ type: "number",
+ });
+ const statsStrengthExpButton = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ const exp = parseInt(statsStrengthExpInput.value);
+ Player.gainStrengthExp(exp);
+ Player.updateSkillLevels();
+ },
+ innerText: "Add Strength Exp",
+ });
+
+ const statsDefenseExpInput = createElement("input", {
+ class: "text-input",
+ margin: "5px",
+ placeholder: "+/- defense exp",
+ type: "number",
+ });
+ const statsDefenseExpButton = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ const exp = parseInt(statsDefenseExpInput.value);
+ Player.gainDefenseExp(exp);
+ Player.updateSkillLevels();
+ },
+ innerText: "Add Defense Exp",
+ });
+
+ const statsDexterityExpInput = createElement("input", {
+ class: "text-input",
+ margin: "5px",
+ placeholder: "+/- dexterity exp",
+ type: "number",
+ });
+ const statsDexterityExpButton = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ const exp = parseInt(statsDexterityExpInput.value);
+ Player.gainDexterityExp(exp);
+ Player.updateSkillLevels();
+ },
+ innerText: "Add Dexterity Exp",
+ });
+
+ const statsAgilityExpInput = createElement("input", {
+ class: "text-input",
+ margin: "5px",
+ placeholder: "+/- agility exp",
+ type: "number",
+ });
+ const statsAgilityExpButton = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ const exp = parseInt(statsAgilityExpInput.value);
+ Player.gainAgilityExp(exp);
+ Player.updateSkillLevels();
+ },
+ innerText: "Add Agility Exp",
+ });
+
+ const statsCharismaExpInput = createElement("input", {
+ class: "text-input",
+ margin: "5px",
+ placeholder: "+/- charisma exp",
+ type: "number",
+ });
+ const statsCharismaExpButton = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ const exp = parseInt(statsCharismaExpInput.value);
+ Player.gainCharismaExp(exp);
+ Player.updateSkillLevels();
+ },
+ innerText: "Add Charisma Exp",
+ });
+
+ const statsIntelligenceExpInput = createElement("input", {
+ class: "text-input",
+ margin: "5px",
+ placeholder: "+/- intelligence exp",
+ type: "number",
+ });
+ const statsIntelligenceExpButton = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ const exp = parseInt(statsIntelligenceExpInput.value);
+ Player.gainIntelligenceExp(exp);
+ Player.updateSkillLevels();
+ },
+ innerText: "Add Intelligence Exp",
+ });
+
+ const statsEnableIntelligenceButton = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ Player.intelligence = 1;
+ },
+ innerText: "Enable Intelligence"
+ });
+
+ const statsDisableIntelligenceButton = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ Player.intelligence = 0;
+ },
+ innerText: "Disable Intelligence"
+ });
+
+ // Factions
+ const factionsHeader = createElement("h2", {innerText: "Factions"});
+
+ const factionsDropdown = createElement("select", {
+ class: "dropdown",
+ margin: "5px",
+ });
+ for (const i in Factions) {
+ factionsDropdown.options[factionsDropdown.options.length] = new Option(Factions[i].name, Factions[i].name);
+ }
+
+ const factionsAddButton = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ const facName = factionsDropdown.options[factionsDropdown.selectedIndex].value;
+ Player.receiveInvite(facName);
+ },
+ innerText: "Receive Invite to Faction",
+ });
+
+ const factionsReputationInput = createElement("input", {
+ placeholder: "Rep to add to faction",
+ type: "number",
+ });
+
+ const factionsReputationButton = createElement("button", {
+ class: "std-button",
+ innerText: "Add rep to faction",
+ clickListener: () => {
+ const facName = getSelectText(factionsDropdown);
+ const fac = Factions[facName];
+ const rep = parseFloat(factionsReputationInput.value);
+ if (fac != null && !isNaN(rep)) {
+ fac.playerReputation += rep;
+ }
+ },
+ });
+
+ // Augmentations
+ const augmentationsHeader = createElement("h2", {innerText: "Augmentations"});
+
+ const augmentationsDropdown = createElement("select", {
+ class: "dropdown",
+ margin: "5px",
+ });
+ for (const i in AugmentationNames) {
+ const augName = AugmentationNames[i];
+ augmentationsDropdown.options[augmentationsDropdown.options.length] = new Option(augName, augName);
+ }
+
+ const augmentationsQueueButton = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ Player.queueAugmentation(augmentationsDropdown.options[augmentationsDropdown.selectedIndex].value);
+ },
+ innerText: "Queue Augmentation",
+ });
+
+ const giveAllAugmentationsButton = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ for (const i in AugmentationNames) {
+ const augName = AugmentationNames[i];
+ Player.queueAugmentation(augName);
+ }
+ },
+ display: "block",
+ innerText: "Queue All Augmentations",
+ });
+
+ // Source Files
+ const sourceFilesHeader = createElement("h2", { innerText: "Source-Files" });
+
+ const removeSourceFileDropdown = createElement("select", {
+ class: "dropdown",
+ margin: "5px",
+ });
+ for (let i = 0; i < 24; ++i) {
+ removeSourceFileDropdown.add(createOptionElement(String(i)));
+ }
+
+ const removeSourceFileButton = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ const numToRemove = parseInt(getSelectText(removeSourceFileDropdown));
+ for (let i = 0; i < Player.sourceFiles.length; ++i) {
+ if (Player.sourceFiles[i].n === numToRemove) {
+ Player.sourceFiles.splice(i, 1);
+ hackWorldDaemon(Player.bitNodeN, true);
+ return;
+ }
+ }
+ },
+ innerText: "Remove Source File and Trigger Bitflume",
+ });
+
+ // Programs
+ const programsHeader = createElement("h2", {innerText: "Programs"});
+
+ const programsAddDropdown = createElement("select", {
+ class: "dropdown",
+ margin: "5px",
+ });
+ for (const i in Programs) {
+ const progName = Programs[i].name;
+ programsAddDropdown.options[programsAddDropdown.options.length] = new Option(progName, progName);
+ }
+
+ const programsAddButton = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ const program = programsAddDropdown.options[programsAddDropdown.selectedIndex].value;
+ if(!Player.hasProgram(program)) {
+ Player.getHomeComputer().programs.push(program);
+ }
+ },
+ innerText: "Add Program",
+ })
+
+ // Servers
+ const serversHeader = createElement("h2", {innerText: "Servers"});
+
+ const serversOpenAll = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ for (const i in AllServers) {
+ AllServers[i].hasAdminRights = true;
+ AllServers[i].sshPortOpen = true;
+ AllServers[i].ftpPortOpen = true;
+ AllServers[i].smtpPortOpen = true;
+ AllServers[i].httpPortOpen = true;
+ AllServers[i].sqlPortOpen = true;
+ AllServers[i].openPortCount = 5;
+ }
+ },
+ display: "block",
+ innerText: "Get Admin Rights to all servers",
+ });
+
+ const serversMinSecurityAll = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ for (const i in AllServers) {
+ AllServers[i].hackDifficulty = AllServers[i].minDifficulty;
+ }
+ },
+ display: "block",
+ innerText: "Set all servers to min security",
+ });
+
+ const serversMaxMoneyAll = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ for (const i in AllServers) {
+ AllServers[i].moneyAvailable = AllServers[i].moneyMax;
+ }
+ },
+ display: "block",
+ innerText: "Set all servers to max money",
+ });
+
+ const serversConnectToDropdown = createElement("select", {class: "dropdown"});
+ for (const i in AllServers) {
+ const hn = AllServers[i].hostname;
+ serversConnectToDropdown.options[serversConnectToDropdown.options.length] = new Option(hn, hn);
+ }
+
+ const serversConnectToButton = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ const host = serversConnectToDropdown.options[serversConnectToDropdown.selectedIndex].value;
+ Terminal.connectToServer(host);
+ },
+ innerText: "Connect to server",
+ });
+
+ // Companies
+ const companiesHeader = createElement("h2", { innerText: "Companies" });
+
+ const companiesDropdown = createElement("select", {
+ class: "dropdown",
+ margin: "5px",
+ });
+ for (const c in Companies) {
+ companiesDropdown.add(createOptionElement(Companies[c].name));
+ }
+
+ const companyReputationInput = createElement("input", {
+ margin: "5px",
+ placeholder: "Rep to add to company",
+ type: "number",
+ });
+
+ const companyReputationButton = createElement("button", {
+ class: "std-button",
+ innerText: "Add rep to company",
+ clickListener: () => {
+ const compName = getSelectText(companiesDropdown);
+ const company = Companies[compName];
+ const rep = parseFloat(companyReputationInput.value);
+ if (company != null && !isNaN(rep)) {
+ company.playerReputation += rep;
+ } else {
+ console.warn(`Invalid input for Dev Menu Company Rep. Company Name: ${compName}. Rep: ${rep}`);
+ }
+ }
+ });
+
+ // Bladeburner
+ const bladeburnerHeader = createElement("h2", {innerText: "Bladeburner"});
+
+ const bladeburnerGainRankInput = createElement("input", {
+ class: "text-input",
+ margin: "5px",
+ placeholder: "Rank to gain (or negative to lose rank)",
+ type: "number",
+ });
+
+ const bladeburnerGainRankButton = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ try {
+ const rank = parseInt(bladeburnerGainRankInput.value);
+ Player.bladeburner.changeRank(rank);
+ } catch(e) {
+ exceptionAlert(`Failed to change Bladeburner Rank in dev menu: ${e}`);
+ }
+ },
+ innerText: "Gain Bladeburner Rank",
+ });
+
+ const bladeburnerStoredCyclesInput = createElement("input", {
+ class: "text-input",
+ margin: "5px",
+ placeholder: "# Cycles to Add",
+ type: "number",
+ });
+
+ const bladeburnerStoredCyclesButton = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ try {
+ const cycles = parseInt(bladeburnerStoredCyclesInput.value);
+ Player.bladeburner.storedCycles += cycles;
+ } catch(e) {
+ exceptionAlert(`Failed to add cycles to Bladeburner in dev menu: ${e}`);
+ }
+ },
+ innerText: "Add Cycles to Bladeburner mechanic",
+ });
+
+ // Gang
+ const gangHeader = createElement("h2", {innerText: "Gang"});
+
+ const gangStoredCyclesInput = createElement("input", {
+ class: "text-input",
+ margin: "5px",
+ placeholder: "# Cycles to add",
+ type: "number",
+ });
+
+ const gangAddStoredCycles = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ try {
+ const cycles = parseInt(gangStoredCyclesInput.value);
+ Player.gang.storedCycles += cycles;
+ } catch(e) {
+ exceptionAlert(`Failed to add stored cycles to gang mechanic: ${e}`);
+ }
+ },
+ innerText: "Add cycles to Gang mechanic",
+ });
+
+ // Corporation
+ const corpHeader = createElement("h2", { innerText: "Corporation" });
+
+ const corpStoredCyclesInput = createElement("input", {
+ class: "text-input",
+ margin: "5px",
+ placeholder: "# Cycles to Add",
+ type: "number",
+ });
+
+ const corpStoredCyclesButton = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ try {
+ const cycles = parseInt(bladeburnerStoredCyclesInput.value);
+ Player.corporation.storeCycles(cycles);
+ } catch(e) {
+ exceptionAlert(`Failed to add cycles to Bladeburner in dev menu: ${e}`);
+ }
+ },
+ innerText: "Add Cycles to Corporation mechanic",
+ });
+
+ // Coding Contracts
+ const contractsHeader = createElement("h2", {innerText: "Coding Contracts"});
+
+ const generateRandomContractBtn = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ generateRandomContract();
+ },
+ innerText: "Generate Random Contract",
+ });
+
+ const generateRandomContractOnHomeBtn = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ generateRandomContractOnHome();
+ },
+ innerText: "Generate Random Contract on Home Comp",
+ });
+
+ const generateContractWithTypeSelector = createElement("select", { margin: "5px" });
+ const contractTypes = Object.keys(CodingContractTypes);
+ for (let i = 0; i < contractTypes.length; ++i) {
+ generateContractWithTypeSelector.add(createOptionElement(contractTypes[i]));
+ }
+
+ const generateContractWithTypeBtn = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ generateContract({
+ problemType: getSelectText(generateContractWithTypeSelector),
+ server: "home",
+ });
+ },
+ innerText: "Generate Specified Contract Type on Home Comp",
+ });
+
+ // Stock Market
+ const stockmarketHeader = createElement("h2", {innerText: "Stock Market"});
+
+ const stockInput = createElement("input", {
+ class: "text-input",
+ display: "block",
+ placeholder: "Stock symbol(s), or 'all'",
+ });
+
+ function processStocks(cb) {
+ const input = stockInput.value.toString().replace(/\s/g, '');
+
+ // Empty input, or "all", will process all stocks
+ if (input === "" || input.toLowerCase() === "all") {
+ for (const name in StockMarket) {
+ if (StockMarket.hasOwnProperty(name)) {
+ const stock = StockMarket[name];
+ if (stock instanceof Stock) {
+ cb(stock);
+ }
+ }
+ }
+ return;
+ }
+
+ const stockSymbols = input.split(",");
+ for (let i = 0; i < stockSymbols.length; ++i) {
+ const stock = SymbolToStockMap[stockSymbols];
+ if (stock instanceof Stock) {
+ cb(stock);
+ }
+ }
+ }
+
+ const stockPriceChangeInput = createElement("input", {
+ class: "text-input",
+ margin: "5px",
+ placeholder: "Price to change stock(s) to",
+ type: "number",
+ });
+
+ const stockPriceChangeBtn = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ const price = parseInt(stockPriceChangeInput.value);
+ if (isNaN(price)) { return; }
+
+ processStocks((stock) => {
+ stock.price = price;
+ });
+ dialogBoxCreate(`Stock Prices changed to ${price}`);
+ },
+ innerText: "Change Stock Price(s)",
+ });
+
+ const stockViewPriceCapBtn = createElement("button", {
+ class: "std-button",
+ clickListener: () => {
+ let text = "";
+ processStocks((stock) => {
+ text += `${stock.symbol}: ${numeralWrapper.format(stock.cap, '$0.000a')}
`;
+ });
+ dialogBoxCreate(text);
+ },
+ innerText: "View Stock Price Caps",
+ });
+
+ // Sleeves
+ const sleevesHeader = createElement("h2", { innerText: "Sleeves" });
+
+ const sleevesRemoveAllShockRecovery = createElement("button", {
+ class: "std-button",
+ display: "block",
+ innerText: "Set Shock Recovery of All Sleeves to 0",
+ clickListener: () => {
+ for (let i = 0; i < Player.sleeves.length; ++i) {
+ Player.sleeves[i].shock = 100;
+ }
+ }
+ });
+
+ // Add everything to container, then append to main menu
+ const devMenuContainer = createElement("div", {
+ class: "generic-menupage-container",
+ id: devMenuContainerId,
+ });
+
+ devMenuContainer.appendChild(devMenuText);
+ /*devMenuContainer.appendChild(genericHeader);
+ devMenuContainer.appendChild(addMoney);
+ devMenuContainer.appendChild(addMoney2);
+ devMenuContainer.appendChild(addRam);
+ devMenuContainer.appendChild(triggerBitflume);
+ devMenuContainer.appendChild(destroyCurrentBitnode);
+ devMenuContainer.appendChild(statsHeader);
+ devMenuContainer.appendChild(statsHackingExpInput);
+ devMenuContainer.appendChild(statsHackingExpButton);
+ devMenuContainer.appendChild(createElement("br"));
+ devMenuContainer.appendChild(statsStrengthExpInput);
+ devMenuContainer.appendChild(statsStrengthExpButton);
+ devMenuContainer.appendChild(createElement("br"));
+ devMenuContainer.appendChild(statsDefenseExpInput);
+ devMenuContainer.appendChild(statsDefenseExpButton);
+ devMenuContainer.appendChild(createElement("br"));
+ devMenuContainer.appendChild(statsDexterityExpInput);
+ devMenuContainer.appendChild(statsDexterityExpButton);
+ devMenuContainer.appendChild(createElement("br"));
+ devMenuContainer.appendChild(statsAgilityExpInput);
+ devMenuContainer.appendChild(statsAgilityExpButton);
+ devMenuContainer.appendChild(createElement("br"));
+ devMenuContainer.appendChild(statsCharismaExpInput);
+ devMenuContainer.appendChild(statsCharismaExpButton);
+ devMenuContainer.appendChild(createElement("br"));
+ devMenuContainer.appendChild(statsIntelligenceExpInput);
+ devMenuContainer.appendChild(statsIntelligenceExpButton);
+ devMenuContainer.appendChild(createElement("br"));
+ devMenuContainer.appendChild(statsEnableIntelligenceButton);
+ devMenuContainer.appendChild(statsDisableIntelligenceButton);
+ devMenuContainer.appendChild(factionsHeader);
+ devMenuContainer.appendChild(factionsDropdown);
+ devMenuContainer.appendChild(factionsAddButton);
+ devMenuContainer.appendChild(createElement("br"));
+ devMenuContainer.appendChild(factionsReputationInput);
+ devMenuContainer.appendChild(factionsReputationButton);
+ devMenuContainer.appendChild(augmentationsHeader);
+ devMenuContainer.appendChild(augmentationsDropdown);
+ devMenuContainer.appendChild(augmentationsQueueButton);
+ devMenuContainer.appendChild(giveAllAugmentationsButton);
+ devMenuContainer.appendChild(sourceFilesHeader);
+ devMenuContainer.appendChild(removeSourceFileDropdown);
+ devMenuContainer.appendChild(removeSourceFileButton);
+ devMenuContainer.appendChild(programsHeader);
+ devMenuContainer.appendChild(programsAddDropdown);
+ devMenuContainer.appendChild(programsAddButton);
+ devMenuContainer.appendChild(serversHeader);
+ devMenuContainer.appendChild(serversOpenAll);
+ devMenuContainer.appendChild(serversMinSecurityAll);
+ devMenuContainer.appendChild(serversMaxMoneyAll);
+ devMenuContainer.appendChild(serversConnectToDropdown);
+ devMenuContainer.appendChild(serversConnectToButton);
+ devMenuContainer.appendChild(companiesHeader);
+ devMenuContainer.appendChild(companiesDropdown);
+ devMenuContainer.appendChild(createElement("br"));
+ devMenuContainer.appendChild(companyReputationInput);
+ devMenuContainer.appendChild(companyReputationButton);
+ devMenuContainer.appendChild(bladeburnerHeader);
+ devMenuContainer.appendChild(bladeburnerGainRankInput);
+ devMenuContainer.appendChild(bladeburnerGainRankButton);
+ devMenuContainer.appendChild(createElement("br"));
+ devMenuContainer.appendChild(bladeburnerStoredCyclesInput);
+ devMenuContainer.appendChild(bladeburnerStoredCyclesButton);
+ devMenuContainer.appendChild(createElement("br"));
+ devMenuContainer.appendChild(gangHeader);
+ devMenuContainer.appendChild(gangStoredCyclesInput);
+ devMenuContainer.appendChild(gangAddStoredCycles);
+ devMenuContainer.appendChild(createElement("br"));
+ devMenuContainer.appendChild(corpHeader);
+ devMenuContainer.appendChild(corpStoredCyclesInput);
+ devMenuContainer.appendChild(corpStoredCyclesButton);
+ devMenuContainer.appendChild(createElement("br"));
+ devMenuContainer.appendChild(contractsHeader);
+ devMenuContainer.appendChild(generateRandomContractBtn);
+ devMenuContainer.appendChild(generateRandomContractOnHomeBtn);
+ devMenuContainer.appendChild(createElement("br"));
+ devMenuContainer.appendChild(generateContractWithTypeSelector);
+ devMenuContainer.appendChild(generateContractWithTypeBtn);
+ devMenuContainer.appendChild(stockmarketHeader);
+ devMenuContainer.appendChild(stockInput);
+ devMenuContainer.appendChild(stockPriceChangeInput);
+ devMenuContainer.appendChild(stockPriceChangeBtn);
+ devMenuContainer.appendChild(createElement("br"));
+ devMenuContainer.appendChild(stockViewPriceCapBtn);
+ devMenuContainer.appendChild(sleevesHeader);
+ devMenuContainer.appendChild(sleevesRemoveAllShockRecovery);*/
+
+ const entireGameContainer = document.getElementById("entire-game-container");
+ if (entireGameContainer == null) {
+ throw new Error("Could not find entire-game-container DOM element");
+ }
+ entireGameContainer.appendChild(devMenuContainer);
+
+ //react
+ devMenuContainer.appendChild(createElement("div", {
+ id: "react-dev-menu",
+ }));
+ ReactDOM.render(, document.getElementById('react-dev-menu'));
+}
+
+export function closeDevMenu() {
+ removeElementById(devMenuContainerId);
+}
diff --git a/src/engine.jsx b/src/engine.jsx
index 8b0646aa8..87d8fffe4 100644
--- a/src/engine.jsx
+++ b/src/engine.jsx
@@ -124,6 +124,8 @@ import "../css/gang.scss";
import "../css/sleeves.scss";
import "../css/resleeving.scss";
import "../css/treant.css";
+import "../css/grid.min.css";
+import "../css/dev-menu.css";
/* Shortcuts to navigate through the game