diff --git a/app.js b/app.js
index 437bd19fe27ca8df1e8778a0e5afe9d571519e02..b56d788dfb67e8597eb7559f9c21dfb2dfe68034 100644
--- a/app.js
+++ b/app.js
@@ -86,7 +86,8 @@ ipc.config.silent = true;
 ipc.serve(() => ipc.server.on('rundynarematlab', (data, socket) => {
   global.mysocket=socket;
   console.log('received ipc message from router');
-  mymessage={'messageid': 'rundynarematlab'};
+  console.log(data)
+  mymessage={'messageid': 'rundynarematlab','messagetype': data};
   child.send(mymessage);
 })
 
@@ -120,6 +121,11 @@ child.on('message', message => {
       
     }
 
+    if (message.message==2){
+      console.log('-=perfect foresight computation completed=-');
+      finishperfect();
+    }
+
   }
 
   if (message.messageid=='stdoutmessage'){
@@ -153,7 +159,7 @@ async function finishstochastic() {
   try {
     stomatlabdata = await loadjsonfile('stochsimout.JSON');
   } catch (error) {
-    return popthis('Error', 'Unable to open stochsimout.JSON to process:' + error);
+    return console.log('Unable to open stochsimout.JSON to process:' + error);
   }
 
   sockIO.emit('stochasticsimfinish', stomatlabdata);
@@ -164,6 +170,23 @@ async function finishstochastic() {
 
 }
 
+async function finishperfect() {
+
+  // loading JSON output from Matlab
+  try {
+    permatlabdata = await loadjsonfile('perforout.JSON');
+  } catch (error) {
+    return console.log('Unable to open perforout.JSON to process:' + error);
+  }
+
+  sockIO.emit('perfectsimfinish', permatlabdata);
+
+  console.log(permatlabdata);
+
+  return false;
+
+}
+
 
 
 
diff --git a/appModules.js b/appModules.js
index 3e1654de0eb2eb918b9301acf4fe4e786c2a4148..05a9b1047adcb282c7ddf0545ace3c4e6bdab4ad 100644
--- a/appModules.js
+++ b/appModules.js
@@ -812,6 +812,7 @@ module.exports = {
 
       // removing old JSON files and writing the correct file
       if (runtype == 1) {
+        //writes JSON file for perfect foresight
         try {
           await module.exports.removeoldfile('perforout.JSON');
         } catch (error) {
@@ -839,6 +840,7 @@ module.exports = {
       }
 
       if (runtype == 2) {
+        //writes JSON file for stochastic simulations
         try {
           await module.exports.removeoldfile('stochsimout.JSON');
         } catch (error) {
diff --git a/background.js b/background.js
index 9deef193ac71a96619f4ccfb22a48895fc761103..99b45734b5f40d95e749edc724d5c855da777ee4 100644
--- a/background.js
+++ b/background.js
@@ -47,13 +47,22 @@ async function main() {
           'messageid': 'matlabready',
           'message': 0
         };
-      } else {
+      } 
+      if (origincalltype == 1) {
+        //this is the return from a stochastic simulation
         mymessage = {
           'messageid': 'matlabready',
           'message': 1
         };
-        // origincalltype = 0;
       }
+      if (origincalltype == 2) {
+        //this is the return from a perfect foresight computation
+        mymessage = {
+          'messageid': 'matlabready',
+          'message': 2
+        };
+      }
+
       // process.send('matlabready', origincalltype);
       process.send(mymessage);
       // }
@@ -82,14 +91,25 @@ async function main() {
   process.on('message', (pmessage) => {
     // var messageprocess=0;
 
+
+
     if (pmessage.messageid == 'rundynarematlab') {
-      // child.stdin.write('15+15\n');
-      origincalltype = 1;
-      child.stdin.write('run temp.m;run di_stochastic_simulations.m;\n');
-      // child.stdin.write('15+15\n');
-      child.stdin.on('drain', () => {});
-      // ready()
-      // messageprocess=1;
+
+
+      if (pmessage.messagetype=='stochastic'){
+        origincalltype = 1;
+        child.stdin.write('run temp.m;run di_stochastic_simulations.m;\n');
+        child.stdin.on('drain', () => {});
+      }
+
+      if (pmessage.messagetype=='perfect'){
+        origincalltype = 2;
+        child.stdin.write('run temp.m;run di_perfect_foresight.m;\n');
+        child.stdin.on('drain', () => {});
+      }
+
+
+
     }
 
     // mymessage={'messageid': 'stdoutmessage','message': 'received rundynarematlab in background' };
diff --git a/middleware/runpreprocess.js b/middleware/runpreprocess.js
deleted file mode 100644
index 8b7558f7a46f4c0358602c3e12b76c845a3cb81f..0000000000000000000000000000000000000000
--- a/middleware/runpreprocess.js
+++ /dev/null
@@ -1,87 +0,0 @@
-const savetodb = require('../appModules').savetodb;
-const removeoldfile = require('../appModules').removeoldfile;
-const createnewfile = require('../appModules').createnewfile;
-const preprocess = require('../appModules').preprocess;
-
-
-module.exports = {
-
-    // async function setpreprocess(modelcode) {
-    setpreprocess: (modelcode) => {
-        // will save and preprocess the model
-
-        return new Promise(async function (resolve, reject) {
-
-            var dynaremodel = '';
-            // saving to database and retrieving the model from database
-            try {
-                dynaremodel = await savetodb(modelcode);
-            } catch (error) {
-                return reject({
-                    'status': 200,
-                    'message': error.toString()
-                });
-            }
-
-            // removing old files
-            try {
-                await removeoldfile(dynaremodel['modelhash'] + '_ini_steady_state_model.json');
-            } catch (error) {
-                return reject({
-                    'status': 200,
-                    'message': error.toString()
-                });
-            }
-            try {
-                await removeoldfile(dynaremodel['modelhash'] + '_ini.json');
-            } catch (error) {
-                return reject({
-                    'status': 200,
-                    'message': error.toString()
-                });
-            }
-            try {
-                await removeoldfile(dynaremodel['modelhash'] + '_ini.mod');
-            } catch (error) {
-                return reject({
-                    'status': 200,
-                    'message': error.toString()
-                });
-            }
-
-            // creating a modfile from editor input. Flag 'w' truncates if file already exits
-            try {
-                await createnewfile(dynaremodel['modelhash'] + '_ini.mod', dynaremodel['modelcode']);
-            } catch (error) {
-                return reject({
-                    'status': 200,
-                    'message': error.toString()
-                });
-            }
-
-            // calling dynare preprocessor on modfile
-            var dynarestdout = '';
-            var preprocok = 1;
-            try {
-                dynarestdout += await preprocess(dynaremodel['modelhash'] + '_ini.mod', 3);
-            } catch (error) {
-                dynarestdout += error.toString();
-                preprocok = 0;
-            }
-
-            if (preprocok == 0) {
-                return reject({
-                    'status': 100,
-                    'message': dynarestdout
-                });
-            } else {
-                return resolve({
-                    'status': 1,
-                    'message': dynarestdout
-                });
-            }
-
-        }); //end of main promise
-    }
-
-}
diff --git a/middleware/runstochastic.js b/middleware/runprocesses.js
similarity index 60%
rename from middleware/runstochastic.js
rename to middleware/runprocesses.js
index 03e42e016313025e6fa02096fcd556eb9a3027e2..e0e077684f56f40d27f261b0fa0d2dc3438cec18 100644
--- a/middleware/runstochastic.js
+++ b/middleware/runprocesses.js
@@ -10,7 +10,85 @@ const ipc = require('node-ipc');
 
 module.exports = {
 
-    setstochasticnode: (modelcode) => {
+    // async function setpreprocess(modelcode) {
+    setpreprocess: (modelcode) => {
+        // will save and preprocess the model
+
+        return new Promise(async function (resolve, reject) {
+
+            var dynaremodel = '';
+            // saving to database and retrieving the model from database
+            try {
+                dynaremodel = await savetodb(modelcode);
+            } catch (error) {
+                return reject({
+                    'status': 200,
+                    'message': error.toString()
+                });
+            }
+
+            // removing old files
+            try {
+                await removeoldfile(dynaremodel['modelhash'] + '_ini_steady_state_model.json');
+            } catch (error) {
+                return reject({
+                    'status': 200,
+                    'message': error.toString()
+                });
+            }
+            try {
+                await removeoldfile(dynaremodel['modelhash'] + '_ini.json');
+            } catch (error) {
+                return reject({
+                    'status': 200,
+                    'message': error.toString()
+                });
+            }
+            try {
+                await removeoldfile(dynaremodel['modelhash'] + '_ini.mod');
+            } catch (error) {
+                return reject({
+                    'status': 200,
+                    'message': error.toString()
+                });
+            }
+
+            // creating a modfile from editor input. Flag 'w' truncates if file already exits
+            try {
+                await createnewfile(dynaremodel['modelhash'] + '_ini.mod', dynaremodel['modelcode']);
+            } catch (error) {
+                return reject({
+                    'status': 200,
+                    'message': error.toString()
+                });
+            }
+
+            // calling dynare preprocessor on modfile
+            var dynarestdout = '';
+            var preprocok = 1;
+            try {
+                dynarestdout += await preprocess(dynaremodel['modelhash'] + '_ini.mod', 3);
+            } catch (error) {
+                dynarestdout += error.toString();
+                preprocok = 0;
+            }
+
+            if (preprocok == 0) {
+                return reject({
+                    'status': 100,
+                    'message': dynarestdout
+                });
+            } else {
+                return resolve({
+                    'status': 1,
+                    'message': dynarestdout
+                });
+            }
+
+        }); //end of main promise
+    },
+
+    setpreprocessmore: (modelcode) => {
         // will save and run a stochastic simulation step
 
         return new Promise(async function (resolve, reject) {
@@ -143,7 +221,6 @@ module.exports = {
         }); //end of main promise
     },
 
-
     runstochasticnode: (stosimval) => {
 
         return new Promise(async function (resolve, reject) {
@@ -176,7 +253,79 @@ module.exports = {
 
             ipc.connectTo('appIPC', () => {
                 ipc.of.appIPC.on('connect', () => {
-                    ipc.of.appIPC.emit('rundynarematlab', "hello");
+                    ipc.of.appIPC.emit('rundynarematlab', "stochastic");
+                    ipc.disconnect('appIPC');
+                });
+
+                // ipc.of.appIPC.on('message', (data) => {
+                //     console.log('back in runstochastic')
+                //     console.log(data);
+                // });
+
+            });
+
+
+
+
+
+
+
+            // this code will get the local user directory (do not erase until used)
+            // console.log(app.getPath('userData'));
+
+
+
+
+            // console.log('runstochasticnode last');
+            return resolve('Done runstochasticnode !');
+
+
+        }); //end of main promise
+
+
+    },
+
+
+    runperfectnode: (perfectval) => {
+
+        return new Promise(async function (resolve, reject) {
+
+
+            console.log('inside runperfectnode');
+
+            var modelhash = perfectval['modelhash'];
+            // preparing only the standardized JSON in data
+            var perfectindata = {
+                'exonum': perfectval['exonum'],
+                'simperiods': perfectval['simperiods'],
+                'permanentshockexist': perfectval['permanentshockexist'],
+                'transitoryshockexist': perfectval['transitoryshockexist'],
+                'nonanticipatedshockexist': perfectval['nonanticipatedshockexist'],
+                'delayexist': perfectval['delayexist'],
+                'permanentshocksdescription': perfectval['permanentshocksdescription'],
+                'shocksdescription': perfectval['shocksdescription'],
+                'nonanticipmatrix': perfectval['nonanticipmatrix']
+            };
+
+
+            try {
+                await preparejsonfiles(modelhash, 1, perfectval, perfectindata);
+            } catch (error) {
+                return reject(error);
+            }
+
+            // const reply = ipc.sendSync('performMatlab', 111);
+            // cl(reply);
+
+            console.log('before IPC')
+
+            ipc.config.id = 'routerIPC';
+            ipc.config.retry = 1500;
+            // ipc.config.silent = true;
+
+            ipc.connectTo('appIPC', () => {
+                ipc.of.appIPC.on('connect', () => {
+                    ipc.of.appIPC.emit('rundynarematlab', "perfect");
                     ipc.disconnect('appIPC');
                 });
 
@@ -200,12 +349,16 @@ module.exports = {
 
 
             // console.log('runstochasticnode last');
-            return resolve('hello');
+            return resolve('Done runperfectnode !');
 
 
         }); //end of main promise
 
 
+
+
+
+
     }
 
 
@@ -213,4 +366,7 @@ module.exports = {
 
 
 
-}
\ No newline at end of file
+
+
+
+}
diff --git a/public/static/js/perfectforesight.js b/public/static/js/perfectforesight.js
new file mode 100644
index 0000000000000000000000000000000000000000..3e5ad80bfc99420bb07e6ed497fd835c58e93c8f
--- /dev/null
+++ b/public/static/js/perfectforesight.js
@@ -0,0 +1,943 @@
+var matlabdata;
+var numshocks = [];
+for (i = 0; i < 1000; i++) {
+  numshocks[i] = 0;
+}
+
+//------------------------------------------------------------@@@button set perfect
+$('#setperfect').click(function () {
+
+  var modelname = $('#codename').val();
+  if (modelname == null || modelname == "") {
+    $.alert({
+      title: 'Project name is empty.',
+      content: 'Please choose a name for this project...',
+    });
+    return false;
+  }
+
+
+  var modelcode = {
+    'modelcode': window.editor_dynare.getValue(),
+    'modelhash': $('#codehash').val(),
+    'modelname': $('#codename').val(),
+    'accesstype': 'setperfect'
+  };
+
+  console.log(modelcode)
+
+  $.ajax({
+    url: $(editorform).attr('action'),
+    headers: {
+      'x-csrf-token': $('#_csrf').val()
+    },
+    type: "POST",
+    data: modelcode,
+    success: function (resp) {
+
+      if (resp.status == 200) {
+        console.log("200")
+        return popthis('Error', resp.message);
+      } else if (resp.status == 100) {
+        console.log("100")
+        showconsolealert(resp.message, 1);
+        console.log('console error');
+        return false;
+      }
+
+      showconsolealert(resp.message, 1);
+
+      var currentdate = new Date();
+      $('#classlist-form-messages').text('Last saved at: ' + currentdate);
+
+      // sucess handling
+
+      //if (((resp.data.status == 1) || (resp.data.status == 2)) || (resp.data.status == 201)) {
+
+        //the model has exo shocks: we make a table
+        // if a steady state has not been provided if ask extra info on that
+        dynaremodel = resp.modeljson;
+
+        // steady-state compute table
+        document.getElementById("perforssinittable").innerHTML = "";
+        if (resp.status == 201) {
+          var extrassinfo = "";
+          var extrasshelp = "";
+          if (resp.extrassinfo !== null) {
+            extrassinfo = resp.extrassinfo;
+            extrasshelp = " (the last known steady-state info have been loaded below)"
+          }
+          var extrasstype = "";
+          if (resp.extrasstype == 1) {
+            extrasstype = 'checked';
+          }
+
+          sscomputeeendo = `
+            <h4>Steady state</h4>
+            <p style="color:#3399CC">You did not provide any way to compute the steady-state. Please specify a way to compute the steady-state` + extrasshelp + `.</p>
+            <div class="form-group no-margin"> <textarea class="form-control" id="perforSSblock" name="perforSSblock" placeholder="Steady-state equations;" rows="7">` + extrassinfo + `</textarea> </div>
+            <div class="form-group no-margin"><label><input type="checkbox" name="issteadystatelock" id="issteadystateblock"` + extrasstype + `/> Check if the above will compute the exact steady-state (will be interpreted as a <span style="font-style: italic;">steady_state_model</span> block). Leave unchecked if the above should be used as a starting point to compute the steady-state (will be interpreted as an <span style="font-style: italic;">initval</span> block).</label></div>
+            <input id="modelsteadystatestatus" name="modelsteadystatestatus" value="99" type="hidden">
+            `;
+        } else if (resp.status == 2) {
+          sscomputeeendo = `
+            <input id="modelsteadystatestatus" name="modelsteadystatestatus" value="55" type="hidden">
+            `;
+        } else {
+          sscomputeeendo = `
+            <input id="modelsteadystatestatus" name="modelsteadystatestatus" value="0" type="hidden">
+            `;
+        }
+        document.getElementById("perforssinittable").innerHTML = sscomputeeendo;
+        document.getElementById("model_endonum").value = (dynaremodel.endogenous).length;
+        document.getElementById("model_exonum").value = (dynaremodel.exogenous).length;
+        $('#perforModal').modal('show');
+      //}
+
+    },
+    error: function () {
+      console.log('there was a problem checking the fields');
+    }
+  });
+  return false;
+});
+
+
+
+//--------------------------------------------@@@button add sequence of shocks code
+$('#addshock').click(function() {
+  var rowindex;
+  var xcond = 0;
+  var iter = 0;
+  while (xcond == 0) {
+    if (numshocks[iter] == 0) {
+      xcond = 1;
+      rowindex = iter;
+      numshocks[iter] = 1;
+    }
+    iter = iter + 1;
+  }
+
+
+  expectedshockstable = '';
+  expectedshockstable += '<tr><td><select id="shockname' + rowindex + '" class="form-control input-sm" name="shocks">';
+  for (x in dynaremodel.exogenous) {
+    expectedshockstable += '<option value="' + x + '">' + dynaremodel.exogenous[x]["longName"] + '</option>';
+  }
+  expectedshockstable += "</select></td>";
+  expectedshockstable += '<td><input type="text" class="form-control no-border input-sm" name="shockstart' + rowindex + '" id="shockstart' + rowindex + '" placeholder="Start"></td>';
+  expectedshockstable += '<td><input type="text" class="form-control no-border input-sm" name="shockend' + rowindex + '" id="shockend' + rowindex + '" placeholder="End"></td>';
+  expectedshockstable += '<td><input type="text" class="form-control no-border input-sm" name="shockvalues' + rowindex + '" id="shockvalues' + rowindex + '" placeholder="Value(s)"></td>';
+  expectedshockstable += '<td><input type="text" class="form-control no-border input-sm" name="shockanticipdate' + rowindex + '" id="shockanticipdate' + rowindex + '" placeholder="0"></td>';
+  expectedshockstable += '<td><input type="checkbox" class="form-control no-border input-sm" name="shockanticip' + rowindex + '" id="shockanticip' + rowindex + '"></td>';
+  expectedshockstable += '<td><input type="checkbox" class="form-control no-border input-sm" onclick="activateunactivateperiod(' + rowindex + ')" name="shockpermanent' + rowindex + '" id="shockpermanent' + rowindex + '"></td>';
+  expectedshockstable += '<td><input type="button" value="X" onclick="SomeDeleteRowFunction(this,' + rowindex + ')" class="form-control no-border input-sm" name="removeshock' + rowindex + '" id="removeshock' + rowindex + '"></td></tr>';
+
+  $('#perforseqexptable tbody').append(expectedshockstable);
+
+  return false;
+});
+
+//----------------------------------------------------@@@disable/unable periods when permanent shock is clicked
+function activateunactivateperiod(thisnum) {
+
+  if ($('#shockend' + thisnum.toString()).is(':disabled')) {
+    //textbox is disabled
+    $('#shockend' + thisnum.toString()).removeAttr('disabled');
+    $('#shockstart' + thisnum.toString()).val('');
+  } else {
+    $('#shockend' + thisnum.toString()).attr({
+      'disabled': 'disabled'
+    });
+    $('#shockend' + thisnum.toString()).val('');
+    $('#shockstart' + thisnum.toString()).val('1');
+  }
+}
+
+//----------------------------------------------------@@@removes a shock line in Shocks table
+function SomeDeleteRowFunction(o, rowindex) {
+  var p = o.parentNode.parentNode;
+  p.parentNode.removeChild(p);
+  numshocks[rowindex] = 0;
+}
+
+
+//----------------------------------------------------@@@button run perfect: verifies input then runs perfect foresight simulation
+$('#runperfect').click(function() {
+  //getting all the necessary info from the forms
+  var endonum = $('#model_endonum').val();
+  var exonum = $('#model_exonum').val();
+  var simperiods = $('#simperiods').val();
+  var ssstatus = $('#modelsteadystatestatus').val();
+  var globalvaluescount = 0;
+  // checking the shocks tab
+  var shockindex;
+  var shockvaluearray = [];
+  var shocksdescription = [];
+  var permanentshocksdescription = [];
+  var ssdescription = [];
+  var permanentshockexist = 0;
+  var nonanticipatedshockexist = 0;
+  var transitoryshockexist = 0;
+  var delayexist = 0;
+  var permanentflag = [];
+  var transitoryflag = [];
+  var shocksflag = [];
+  var nonanticipmatrix = [];
+  var trackrow = 0;
+  var sstype = 0;
+
+  var ispermanent;
+  var isnonanticipated;
+  var isdelayed;
+
+  for (i = 0; i < exonum; i++) {
+    permanentflag[i] = 0;
+    shocksflag[i] = 0;
+    transitoryflag[i] = 0;
+  }
+
+  // setup tab checks
+
+  // simulation periods check
+  if (simperiods == null || simperiods == "") {
+    $('.nav-tabs a[href="#perforsetuptable"]').tab('show');
+    popthis('Setup error.', 'You did not specify the number of simulation periods.');
+    return (0);
+  } else {
+    if (!(Number.isInteger(Number(simperiods)))) {
+      $('.nav-tabs a[href="#perforsetuptable"]').tab('show');
+      popthis('Setup error.', 'The number of simulation periods is not an integer number.');
+      return (0);
+    }
+    if (Number(simperiods) < 1) {
+      $('.nav-tabs a[href="#perforsetuptable"]').tab('show');
+      popthis('Setup error.', 'The number of simulation periods can not be lower than 1.');
+      return (0);
+    }
+  }
+
+  // steady-state info check
+  if (ssstatus == 99) {
+    sstext = $('#perforSSblock').val();
+    if (sstext.length == 0) {
+      $('.nav-tabs a[href="#perforsetuptable"]').tab('show');
+      popthis('Steady state error.', 'Please provide a way to compute the steady-state.');
+      return (0);
+    }
+    if ($('#issteadystateblock').is(":checked") == true) {
+      var sstype = 1;
+    } else {
+      var sstype = 2;
+    }
+    ssdescription.push({
+      'sstext': sstext,
+      'sstype': parseInt(sstype, 10)
+    });
+  }
+
+
+
+  // Shocks tab checks
+  $('.nav-tabs a[href="#perforseqexp"]').tab('show');
+
+  var rowCount = $('#perforseqexptable tr').length - 1; // careful this counts the th row as a row, thus the -1
+
+  if (rowCount > 0) {
+    // there are shocks in the table
+    globalvaluescount = 1;
+    var xcond = 0;
+    var iter = 0;
+    var countshocks = 0;
+
+    while (xcond == 0) {
+      // we iterate over global numshocks that kept track of shock indexes in any order they were entered
+      if (numshocks[iter] == 1) {
+        // if numshocks identifies a valid row in the table, we start further checks
+        countshocks = countshocks + 1;
+        shockvaluearray = [];
+
+        // we fetch periods and values and anticipation dates
+        shockstart = $('#shockstart' + iter.toString()).val();
+        shockstart = shockstart.trim();
+        shockend = $('#shockend' + iter.toString()).val();
+        shockend = shockend.trim();
+        shockvalue = $('#shockvalues' + iter.toString()).val();
+        shockvalue = shockvalue.trim();
+        shockanticipdate = $('#shockanticipdate' + iter.toString()).val();
+        shockanticipdate = shockanticipdate.trim();
+
+        ispermanent = 0;
+        isnonanticipated = 0;
+        isdelayed = 0;
+        previousdelay = 0
+        previousnonanticip = 0;
+
+        // we fetch the index of the shock given by the Dynare preprocessor
+        shockindex = $('#shockname' + iter.toString()).val();
+
+        // we verify if shock has been flagged as permanent or non anticipated
+        if ($("#shockpermanent" + iter.toString()).is(':checked')) {
+          permanentflag[shockindex] = permanentflag[shockindex] + 1;
+          permanentshockexist = 1;
+          ispermanent = 1;
+          if (nonanticipatedshockexist == 1) {
+            previousnonanticip = 1;
+          }
+          if (delayexist == 1) {
+            previousdelay = 1;
+          }
+        }
+
+        if ($("#shockanticip" + iter.toString()).is(':checked')) {
+          nonanticipatedshockexist = 1;
+          isnonanticipated = 1;
+        }
+
+        // we validate the anticipation date
+        if (shockanticipdate == null || shockanticipdate == "") {
+          shockanticipdate = 0;
+        } else {
+          if (!(Number.isInteger(Number(shockanticipdate)))) {
+            popthis('Shocks error.', 'The shock expectation date on row ' + countshocks + ' is not an integer number.');
+            return (0);
+          }
+          if (Number(shockanticipdate) < 1) {
+            popthis('Shocks error.', 'The shock expectation date on row ' + countshocks + ' can not be lower than 1.');
+            return (0);
+          }
+          delayexist = 1;
+          isdelayed = 1;
+        }
+
+        if (permanentflag[shockindex] > 1) {
+          popthis('Shocks error.', 'You requested that shock ' + dynaremodel.exogenous[shockindex]["longName"] + ' is permanent in two or more instances. This is not supported, please specify only one permanent status per shock.');
+        }
+
+
+        if (((ispermanent == 0) && (isnonanticipated == 0)) && (isdelayed == 0)) {
+          // the shock is not permanent or non anticipated or know with delay, user is supposed to enter periods
+          transitoryflag[shockindex] = 1;
+          // we validate the starting period
+          if (shockstart == null || shockstart == "") {
+            popthis('Shocks error.', 'You did not specify any starting period for shock on row ' + countshocks + '.');
+            return (0);
+          } else {
+            if (!(Number.isInteger(Number(shockstart)))) {
+              popthis('Shocks error.', 'The shock starting period on row ' + countshocks + ' is not an integer number.');
+              return (0);
+            }
+            if (Number(shockstart) < 1) {
+              popthis('Shocks error.', 'The shock starting period on row ' + countshocks + ' can not be lower than 1.');
+              return (0);
+            }
+            shockstart = parseInt(shockstart, 10);
+          }
+
+          // we validate the shock value
+          if (shockvalue == null || shockvalue == "") {
+            popthis('Shocks error.', 'You did not specify any value for shock on row ' + countshocks + '.');
+            return (0);
+          } else {
+            if (!(IsNumeric(shockvalue))) {
+              // the user can enter several values separated by semicolon, we validate that
+              if (shockvalue.indexOf(';') > -1) {
+                columnsplit = shockvalue.split(';');
+                columnsplitlength = columnsplit.length;
+                if ((columnsplit[columnsplitlength - 1] == null) || (columnsplit[columnsplitlength - 1] == "")) {
+                  // we let the user end such an entry with a semicolon, but then reduce the length
+                  columnsplitlength--;
+                }
+                if (columnsplitlength > 1) {
+                  // if we are sure there should be at least 2 periods, we check the end period
+                  if (shockend == null || shockend == "") {
+                    popthis('Shocks error.', 'You did not specify any ending period for shock on row ' + countshocks + '.');
+                    return (0);
+                  } else {
+                    if (!(Number.isInteger(Number(shockend)))) {
+                      popthis('Shocks error.', 'The shock ending period on row ' + countshocks + ' is not an integer number.');
+                      return (0);
+                    }
+                    if (Number(shockend) > Number(simperiods)) {
+                      popthis('Shocks error.', 'The shock ending period on row ' + countshocks + ' can not be larger than the number of simulation periods.');
+                      return (0);
+                    }
+                    if (Number(shockend) < Number(shockstart)) {
+                      popthis('Shocks error.', 'The shock ending period on row ' + countshocks + ' cannot be before the shock starting period.');
+                      return (0);
+                    }
+                    shockend = parseInt(shockend, 10);
+                  }
+
+                  // we verify if the number of periods and values match
+                  if (!(columnsplitlength == (shockend - shockstart + 1))) {
+                    popthis('Shocks error.', 'The number of periods and the number of shock values does not match on row ' + countshocks + '.');
+                    return (0);
+                  }
+
+                  // we define a values array
+                  for (i = 0; i < columnsplitlength; i++) {
+                    if (!(IsNumeric(columnsplit[i]))) {
+                      popthis('Shocks error.', 'At least one shock vector value on row ' + countshocks + ' is not a number.');
+                      return (0);
+                    }
+                    shockvaluearray.push(Number(columnsplit[i]));
+                  }
+                } else {
+                  // this is a single shock with just a start period
+                  if (!(IsNumeric(columnsplit[0]))) {
+                    popthis('Shocks error.', 'The shock value on row ' + countshocks + ' is not a number.');
+                    return (0);
+                  }
+                  shockvaluearray.push(Number(columnsplit[0]));
+                  shockend = parseInt(shockstart, 10);
+                }
+              } else {
+                popthis('Shocks error.', 'The shock value on row ' + countshocks + ' is not a number.');
+                return (0);
+              }
+            } else {
+              // the user did provide a single numeric value for the shock value
+              // the user can provide a single value and a start and end period, in that case the value is the same for this whole range, or just a start period
+              if (shockend == null || shockend == "") {
+                // this is a single shock with just a start period
+                if (!(IsNumeric(shockvalue))) {
+                  popthis('Shocks error.', 'The shock value on row ' + countshocks + ' is not a number.');
+                  return (0);
+                }
+                shockend = parseInt(shockstart, 10);
+                shockvaluearray.push(Number(shockvalue));
+              } else {
+                // this is a single value but with a range, we repeat the value over the range
+                if (!(Number.isInteger(Number(shockend)))) {
+                  popthis('Shocks error.', 'The shock ending period on row ' + countshocks + ' is not an integer number.');
+                  return (0);
+                }
+                if (Number(shockend) > Number(simperiods)) {
+                  popthis('Shocks error.', 'The shock ending period on row ' + countshocks + ' can not be larger than the number of simulation periods.');
+                  return (0);
+                }
+                shockend = parseInt(shockend, 10);
+
+                // we define a values array
+                for (i = Number(shockstart); i < (Number(shockend) + 1); i++) {
+                  shockvaluearray.push(Number(shockvalue));
+                }
+              }
+            }
+          }
+          transitoryshockexist = 1;
+          // collecting the description of the shocks in an object
+          shocksdescription.push({
+            'shockindex': parseInt(shockindex, 10),
+            'shockname': dynaremodel.exogenous[shockindex]["longName"],
+            'shockstartperiod': shockstart,
+            'shockendperiod': shockend,
+            'shockvalue': shockvaluearray,
+            'shocknonanticipated': isnonanticipated,
+            'shockpermanent': ispermanent,
+            'shockdelayed': isdelayed
+          });
+        }
+
+        // we want to rule out permanent shocks anticipated at date 1 or delayed permanent shocks with anticipation date 1, because basically it's the same thing as a permanent shock at date 1
+        if ((ispermanent == 1) && ((isnonanticipated == 1) || (isdelayed == 1))) {
+          if (shockstart == null || shockstart == "") {
+            shockstart = 1;
+          } else {
+            if (!(Number.isInteger(Number(shockstart)))) {
+              popthis('Shocks error.', 'The shock starting period on row ' + countshocks + ' is not an integer number.');
+              return (0);
+            }
+            if (Number(shockstart) < 1) {
+              popthis('Shocks error.', 'The shock starting period on row ' + countshocks + ' can not be lower than 1.');
+              return (0);
+            }
+            shockstart = parseInt(shockstart, 10);
+          }
+
+          // we validate the anticipation date
+          if (shockanticipdate == null || shockanticipdate == "") {
+            shockanticipdate = 0;
+          } else {
+            if (Number(shockanticipdate) > Number(shockstart)) {
+              popthis('Shocks error.', 'The shock expectation date on row ' + countshocks + ' can not be after the start date.');
+              return (0);
+            }
+            // if ((nonanticipatedshockexist==1)&&(delayexist==1)){popthis('Shocks error.','Please either choose a non anticipated shock or a delayed anticipation shock with anticipation date for shock on row '+countshocks+', but not both.');return(0);}
+          }
+
+          if ((isnonanticipated == 1) && (shockstart == 1)) {
+            isnonanticipated = 0;
+            if (previousnonanticip == 0) {
+              nonanticipatedshockexist = 0;
+            }
+          }
+          if ((isdelayed == 1) && (shockanticipdate == 1)) {
+            isdelayed = 0;
+            if (previousdelay == 0) {
+              delayexist = 0;
+            }
+          }
+        }
+        if (((ispermanent == 1) && (isnonanticipated == 0)) && (isdelayed == 0)) {
+          // the shock is permanent and anticipated, we allow only one value and ignore the ending period
+
+          // we validate the starting period
+          if (shockstart == null || shockstart == "") {
+            shockstart = 1;
+          } else {
+            if (!(Number.isInteger(Number(shockstart)))) {
+              popthis('Shocks error.', 'The shock starting period on row ' + countshocks + ' is not an integer number.');
+              return (0);
+            }
+            if (Number(shockstart) < 1) {
+              popthis('Shocks error.', 'The shock starting period on row ' + countshocks + ' can not be lower than 1.');
+              return (0);
+            }
+            shockstart = parseInt(shockstart, 10);
+          }
+
+          // we validate the shock value
+          if (shockvalue == null || shockvalue == "") {
+            popthis('Shocks error.', 'You did not specify any value for shock on row ' + countshocks + '.');
+            return (0);
+          } else {
+            if (!(IsNumeric(shockvalue))) {
+              popthis('Shocks error.', 'The shock value on row ' + countshocks + ' is not numeric. A permanent shock can only have a single numeric value, no comma or semi-colon is authorized.');
+              return (0);
+            } else {
+              // we collect the value
+              shockvaluearray.push(Number(shockvalue));
+            }
+          }
+
+          permanentshocksdescription.push({
+            'shockindex': parseInt(shockindex, 10),
+            'shockname': dynaremodel.exogenous[shockindex]["longName"],
+            'shockstartperiod': shockstart,
+            'shockendperiod': shockend,
+            'shockvalue': shockvaluearray,
+            'shocknonanticipated': isnonanticipated,
+            'shockpermanent': ispermanent,
+            'shockdelayed': isdelayed
+          });
+        }
+
+        if ((isnonanticipated == 1) || (isdelayed == 1)) {
+          // the shock is either non anticipated or delayed
+
+          // we validate the starting period
+          if (shockstart == null || shockstart == "") {
+            popthis('Shocks error.', 'You did not specify any starting period for shock on row ' + countshocks + '.');
+            return (0);
+          } else {
+            if (!(Number.isInteger(Number(shockstart)))) {
+              popthis('Shocks error.', 'The shock starting period on row ' + countshocks + ' is not an integer number.');
+              return (0);
+            }
+            if (Number(shockstart) < 1) {
+              popthis('Shocks error.', 'The shock starting period on row ' + countshocks + ' can not be lower than 1.');
+              return (0);
+            }
+            shockstart = parseInt(shockstart, 10);
+          }
+
+          // we validate the anticipation date
+          if (shockanticipdate == null || shockanticipdate == "") {
+            shockanticipdate = 0;
+          } else {
+            if (Number(shockanticipdate) > Number(shockstart)) {
+              popthis('Shocks error.', 'The shock expectation date on row ' + countshocks + ' can not be after the start date.');
+              return (0);
+            }
+          }
+
+          // we validate the shock value
+          if (shockvalue == null || shockvalue == "") {
+            popthis('Shocks error.', 'You did not specify any value for shock on row ' + countshocks + '.');
+            return (0);
+          } else {
+            if (!(IsNumeric(shockvalue))) {
+              // the user can enter several values separated by semicolon, we validate that
+              if (shockvalue.indexOf(';') > -1) {
+                columnsplit = shockvalue.split(';');
+                columnsplitlength = columnsplit.length;
+                if ((columnsplit[columnsplitlength - 1] == null) || (columnsplit[columnsplitlength - 1] == "")) {
+                  // we let the user end such an entry with a semicolon, but then reduce the length
+                  columnsplitlength--;
+                }
+                if (columnsplitlength > 1) {
+                  // if we are sure there should be at least 2 periods, we check the end period
+                  if (shockend == null || shockend == "") {
+                    popthis('Shocks error.', 'You did not specify any ending period for shock on row ' + countshocks + '.');
+                    return (0);
+                  } else {
+                    if (!(Number.isInteger(Number(shockend)))) {
+                      popthis('Shocks error.', 'The shock ending period on row ' + countshocks + ' is not an integer number.');
+                      return (0);
+                    }
+                    if (Number(shockend) > Number(simperiods)) {
+                      popthis('Shocks error.', 'The shock ending period on row ' + countshocks + ' can not be larger than the number of simulation periods.');
+                      return (0);
+                    }
+                    if (Number(shockend) < Number(shockstart)) {
+                      popthis('Shocks error.', 'The shock ending period on row ' + countshocks + ' can before the shock starting period.');
+                      return (0);
+                    }
+                    shockend = parseInt(shockend, 10);
+                  }
+
+                  // we verify if the number of periods and values match
+                  if (!(columnsplitlength == (shockend - shockstart + 1))) {
+                    popthis('Shocks error.', 'The number of periods and the number of shock values does not match on row ' + countshocks + '.');
+                    return (0);
+                  }
+
+                  // we define a values array
+                  for (i = 0; i < columnsplitlength; i++) {
+                    if (!(IsNumeric(columnsplit[i]))) {
+                      popthis('Shocks error.', 'At least one shock vector value on row ' + countshocks + ' is not a number.');
+                      return (0);
+                    }
+                    shockvaluearray.push(Number(columnsplit[i]));
+                  }
+                } else {
+                  // this is a single shock with just a start period
+                  if (!(IsNumeric(columnsplit[0]))) {
+                    popthis('Shocks error.', 'The shock value on row ' + countshocks + ' is not a number.');
+                    return (0);
+                  }
+                  shockvaluearray.push(Number(columnsplit[0]));
+                  shockend = parseInt(shockstart, 10);
+                }
+              } else {
+                popthis('Shocks error.', 'The shock value on row ' + countshocks + ' is not a number.');
+                return (0);
+              }
+            } else {
+              // the user did provide a single numeric value for the shock value
+              // the user can provide a single value and a start and end period, in that case the value is the same for this whole range, or just a start period
+              if (shockend == null || shockend == "") {
+                // this is a single shock with just a start period
+                if (!(IsNumeric(shockvalue))) {
+                  popthis('Shocks error.', 'The shock value on row ' + countshocks + ' is not a number.');
+                  return (0);
+                }
+                shockend = parseInt(shockstart, 10);
+                shockvaluearray.push(Number(shockvalue));
+              } else {
+                // this is a single value but with a range, we repeat the value over the range
+                if (!(Number.isInteger(Number(shockend)))) {
+                  popthis('Shocks error.', 'The shock ending period on row ' + countshocks + ' is not an integer number.');
+                  return (0);
+                }
+                if (Number(shockend) > Number(simperiods)) {
+                  popthis('Shocks error.', 'The shock ending period on row ' + countshocks + ' can not be larger than the number of simulation periods.');
+                  return (0);
+                }
+                shockend = parseInt(shockend, 10);
+
+                // we define a values array
+                for (i = Number(shockstart); i < (Number(shockend) + 1); i++) {
+                  shockvaluearray.push(Number(shockvalue));
+                }
+              }
+            }
+          }
+
+          // defining special anticipation tracking
+          if (isdelayed == 1) {
+            nonanticipmatrix[trackrow] = new Array(9);
+            nonanticipmatrix[trackrow][0] = parseInt(shockanticipdate, 10);
+            nonanticipmatrix[trackrow][1] = parseInt(shockindex, 10);
+            if (ispermanent == 1) {
+              nonanticipmatrix[trackrow][2] = 1;
+            } else {
+              nonanticipmatrix[trackrow][2] = 0;
+            }
+            nonanticipmatrix[trackrow][3] = 1;
+            nonanticipmatrix[trackrow][4] = shockstart;
+            nonanticipmatrix[trackrow][5] = shockend;
+            nonanticipmatrix[trackrow][6] = shockvaluearray;
+            nonanticipmatrix[trackrow][8] = "";
+            trackrow++;
+          } else {
+            cl("shockstart:" + shockstart);
+            cl("shockend:" + shockend);
+            icurrentloop = 0;
+            for (ixloop = shockstart; ixloop <= shockend; ixloop++) {
+              cl("ixloop:" + ixloop)
+              nonanticipmatrix[trackrow] = new Array(9);
+              nonanticipmatrix[trackrow][0] = ixloop;
+              nonanticipmatrix[trackrow][1] = parseInt(shockindex, 10);
+              if (ispermanent == 1) {
+                nonanticipmatrix[trackrow][2] = 1;
+              } else {
+                nonanticipmatrix[trackrow][2] = 0;
+              }
+              nonanticipmatrix[trackrow][3] = 0;
+              nonanticipmatrix[trackrow][6] = shockvaluearray[icurrentloop];
+              nonanticipmatrix[trackrow][8] = "";
+              icurrentloop++;
+              trackrow++;
+            }
+          }
+
+        }
+
+
+        //we count the number of this specific shock
+        shocksflag[shockindex] = shocksflag[shockindex] + 1;
+      }
+      if (countshocks == rowCount) {
+        xcond = 1;
+      }
+      iter = iter + 1;
+    }
+
+
+  }
+
+
+
+  if (globalvaluescount == 0) {
+    popthis('Simulation input error.', 'You have submitted no input to perform the simulation. Please input value(s) and retry.');
+    return (0);
+  } else {
+    { //we post to the server
+
+      nonanticipmatrix.sort(sortbyfirst);
+      nonanticipmatrix[trackrow] = new Array(9);
+      nonanticipmatrix[trackrow][0] = -1;
+
+      if ((delayexist == 1) && (nonanticipatedshockexist == 1)) {
+        popthis('Warning.', 'You have specified that a shock is non-expected while providing an expectation date. Only the effect of the expectation date will be taken into account.');
+      }
+
+      var perforval = {
+        'modelhash': $('#codehash').val(),
+        'simperiods': parseInt(simperiods, 10),
+        'ssstatus': parseInt(ssstatus, 10),
+        'endonum': parseInt(endonum, 10),
+        'exonum': parseInt(exonum, 10),
+        'ssdescription': ssdescription,
+        'shocksdescription': shocksdescription,
+        'permanentshocksdescription': permanentshocksdescription,
+        'transitoryshockexist': transitoryshockexist,
+        'permanentshockexist': permanentshockexist,
+        'nonanticipatedshockexist': nonanticipatedshockexist,
+        'delayexist': delayexist,
+        'nonanticipmatrix': nonanticipmatrix,
+        'accesstype': 'runperfect',
+        'jsontest': ["12"]
+      };
+
+      var perforvaldata = JSON.stringify(perforval);
+      $("#outputtable").empty();
+      $("#plotbtn").empty();
+      $("#plotbox").empty();
+      $('#perforModal').modal('hide');
+      var div = document.createElement('div');
+      div.className = 'loader';
+      div.innerHTML = '';
+      document.getElementById('inner').appendChild(div);
+      $('.nav-tabs a[href="#output"]').tab('show');
+
+      // ajaxing content
+
+      $.ajax({
+        url: $(editorform).attr('action'),
+        headers: {'x-csrf-token': $('#_csrf').val()},
+        type: "PUT",
+        contentType: "application/json",
+        dataType: 'json',
+        data: perforvaldata,
+        success: function(resp) {
+
+          // var currentout = $("textarea#preprocessorout").val();
+          // currentout = currentout + resp.data.message;
+          // $("textarea#preprocessorout").val(currentout);
+
+        //  else if (resp.data.status == 2) { //there were matlab errors
+        //     $('.nav-tabs a[href="#console"]').tab('show');
+        //     $("#inner").empty();
+        //     document.getElementById("inner").innerHTML = '<p style="color:red;">Matlab errors found. See console.</p>';
+        //   } else if (resp.data.status == 3) {
+        //     currentout = currentout + resp.data.message;
+        //     $("textarea#preprocessorout").val(currentout + '\n \n The preprocessor could nor process your input. Please check the extra steady-state information you provided.');
+        //     $('.nav-tabs a[href="#console"]').tab('show');
+        //     $("#inner").empty();
+        //     document.getElementById("inner").innerHTML = '<p style="color:red;">Preprocessor errors found. See console.</p>';
+        //   }
+
+
+        if (resp.status == 200) {
+          console.log("200")
+          return popthis('Error', resp.message);
+        } else if (resp.status == 100) {
+          console.log("100")
+          showconsolealert(resp.message, 1);
+          console.log('console error');
+          return false;
+        }
+
+        console.log('All done here !')
+
+
+
+        },
+        error: function() {
+          console.log('there was a problem checking the fields');
+        }
+      });
+      return false;
+    }
+  }
+
+});
+
+
+
+$(function () {
+  socket.on('perfectsimfinish', function(msg){
+    // $('#messages').append($('<li>').text(msg));
+      console.log(msg);
+
+
+        matlabdata = msg;
+        var endovarname;
+
+        // creating output content
+        var sstbl1 = `
+            <section>
+            <h2>Steady state results</h2>
+            <table class="table table-striped table-hover">
+            <thead>
+            <tr>
+            <th>#</th>
+            <th>Endogenous variable</th>
+            <th>Initial Steady state</th>
+            <th>Final Steady state</th>
+            </tr>
+            </thead>
+            <tbody>
+            `;
+
+        var plotdropdown = `
+            <section>
+            <h2>Plots</h2>
+            <div class="btn-group" role="group" aria-label="...">
+            <div class="btn-group" role="group">
+              <button id="plotbtn" class="btn btn-primary btn-lg dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+                Select graph <span class="caret"></span><span class="sr-only">Toggle Dropdown</span>
+              </button>
+              <ul class="dropdown-menu" aria-labelledby="plotbtn">
+              <li class="dropdown-header">Endogenous variables:</li>
+              `;
+        y = 0;
+        for (x in matlabdata.endo_names) {
+          endovarname = matlabdata.endo_names[x].trim();
+          plotdropdown += '<li onclick="plotmethis(&quot;' + endovarname + '&quot;)"><a href="#stophere">' + endovarname + '</a></li>';
+          y = y + 1;
+          sstbl1 += '<tr><th scope="row">' + y + '</th>';
+          sstbl1 += "<td>" + endovarname + "</td>";
+          sstbl1 += "<td>" + matlabdata.steady_state1[x] + "</td>";
+          sstbl1 += "<td>" + matlabdata.steady_state2[x] + "</td>";
+        }
+        plotdropdown +='</ul></div>';
+        plotdropdown +=`
+        <div class="btn-group" role="group">
+        <button id="exportbtn" class="btn btn-primary btn-lg dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+          Export data <span class="caret"></span><span class="sr-only">Toggle Dropdown</span>
+        </button>
+        <ul class="dropdown-menu" aria-labelledby="exportbtn">
+        <li class="dropdown-header">Select file type:</li>
+        <li onclick="exportfile(&quot;json&quot;)"><a href="#stophere">Export to JSON</a></li>
+        <li onclick="exportfile(&quot;csv&quot;)"><a href="#stophere">Export to CSV</a></li>
+        </ul>
+        </div>`;
+
+        plotdropdown += `
+        </div>
+            </section>
+            `;
+        sstbl1 += "</tbody></table></section>";
+        $("#inner").empty();
+        document.getElementById("outputtable").innerHTML = sstbl1;
+        document.getElementById("plotbtn").innerHTML = plotdropdown;
+
+
+        plotmethis(matlabdata.endo_names[0].trim());
+
+      
+
+
+
+
+    });
+  });
+
+
+
+
+// $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ output
+
+// graph plotter
+function plotmethis(plotvar) {
+
+  var trace1 = {
+    x: matlabdata.endo_simul.plotx,
+    y: matlabdata.endo_simul[plotvar]
+  };
+  var data = [trace1];
+
+  var layout = {
+    title: plotvar,
+    xaxis: {
+      title: 'Periods'
+    },
+    yaxis: {
+      title: plotvar
+    }
+  };
+
+  Plotly.newPlot('plotbox', data, layout);
+}
+
+// files exporter
+function exportfile(exporttype) {
+
+  var filename = $('#codename').val();
+
+  if (exporttype == 'json') {
+    var exportjson = {
+      'simulation': [],
+      'steadystate1': matlabdata.steady_state1,
+      'steadystate2': matlabdata.steady_state2
+    };
+    for (var key in matlabdata.endo_simul) {
+      if (key != "plotx") {
+        exportjson.simulation.push({
+          [key]: matlabdata.endo_simul[key]
+        });
+      }
+    }
+    var exportjsontext = JSON.stringify(exportjson);
+    download(filename + ".JSON", exportjsontext);
+  }
+
+  if (exporttype == 'csv') {
+    var exportcsv = matlabdata.endo_names + "\r\n";
+    var csvarray = [];
+    for (var mykey in matlabdata.endo_names) {
+      csvarray.push(matlabdata.endo_simul[matlabdata.endo_names[mykey]]);
+      cl(mykey);
+    }
+    var transpose = csvarray[0].map((col, i) => csvarray.map(row => row[i]));
+    for (itr = 0; itr < transpose.length; itr++) {
+      exportcsv += transpose[itr] + "\r\n";
+    }
+    download(filename + ".csv", exportcsv);
+  }
+}
diff --git a/public/static/js/stochastic.js b/public/static/js/stochastic.js
index cb653eafe83685061a3c34a133fda4156e8689f1..aa8d9ea03e15d75d298d2d85077b095758d66b9c 100644
--- a/public/static/js/stochastic.js
+++ b/public/static/js/stochastic.js
@@ -28,7 +28,7 @@ for (i = 0; i < 1000; i++) {
 
 
 //------------------------------------------------------------@@@button set perfect
-$('#setstochastic').click(function() {
+$('#setstochastic').click(function () {
 
   // let basedir = path.resolve(__dirname, './assets/modfiles/');
 
@@ -50,10 +50,12 @@ $('#setstochastic').click(function() {
 
   $.ajax({
     url: $(editorform).attr('action'),
-    headers: {'x-csrf-token': $('#_csrf').val()},
+    headers: {
+      'x-csrf-token': $('#_csrf').val()
+    },
     type: "POST",
     data: modelcode,
-    success: function(resp) {
+    success: function (resp) {
 
       if (resp.status == 200) {
         console.log("200")
@@ -65,52 +67,53 @@ $('#setstochastic').click(function() {
         return false;
       }
 
+      showconsolealert(resp.message, 1);
 
+      var currentdate = new Date();
+      $('#classlist-form-messages').text('Last saved at: ' + currentdate);
 
-  showconsolealert(resp.message, 1);
-
-  //the model has exo shocks: we make a table
-  // if a steady state has not been provided if ask extra info on that
-  dynaremodel = resp.modeljson;
+      //the model has exo shocks: we make a table
+      // if a steady state has not been provided if ask extra info on that
+      dynaremodel = resp.modeljson;
 
-  // steady-state compute table
-  document.getElementById("stosimssinittable").innerHTML = "";
-  if (resp.status == 201) {
-    var extrassinfo = "";
-    var extrasshelp = "";
-    if (resp.extrassinfo !== null) {
-      extrassinfo = resp.extrassinfo;
-      extrasshelp = " (the last known steady-state info have been loaded below)"
-    }
-    var extrasstype = "";
-    if (resp.extrasstype == 1) {
-      extrasstype = 'checked';
-    }
+      // steady-state compute table
+      document.getElementById("stosimssinittable").innerHTML = "";
+      if (resp.status == 201) {
+        var extrassinfo = "";
+        var extrasshelp = "";
+        if (resp.extrassinfo !== null) {
+          extrassinfo = resp.extrassinfo;
+          extrasshelp = " (the last known steady-state info have been loaded below)"
+        }
+        var extrasstype = "";
+        if (resp.extrasstype == 1) {
+          extrasstype = 'checked';
+        }
 
-    sscomputeeendo = `
+        sscomputeeendo = `
       <h4>Steady state</h4>
       <p style="color:#3399CC">You did not provide any way to compute the steady-state. Please specify a way to compute the steady-state` + extrasshelp + `.</p>
       <div class="form-group no-margin"> <textarea class="form-control" id="stoSSblock" name="stoSSblock" placeholder="Steady-state equations;" rows="7">` + extrassinfo + `</textarea> </div>
       <div class="form-group no-margin"><label><input type="checkbox" name="stoissteadystateblock" id="stoissteadystateblock"` + extrasstype + `/> Check if the above will compute the exact steady-state (will be interpreted as a <span style="font-style: italic;">steady_state_model</span> block). Leave unchecked if the above should be used as a starting point to compute the steady-state (will be interpreted as an <span style="font-style: italic;">initval</span> block).</label></div>
       <input id="stomodelsteadystatestatus" name="stomodelsteadystatestatus" value="99" type="hidden">
       `;
-  } else if (resp.status == 2) {
-    sscomputeeendo = `
+      } else if (resp.status == 2) {
+        sscomputeeendo = `
       <input id="stomodelsteadystatestatus" name="stomodelsteadystatestatus" value="55" type="hidden">
       `;
-  } else {
-    sscomputeeendo = `
+      } else {
+        sscomputeeendo = `
       <input id="stomodelsteadystatestatus" name="stomodelsteadystatestatus" value="0" type="hidden">
       `;
-  }
-  document.getElementById("stosimssinittable").innerHTML = sscomputeeendo;
-  document.getElementById("stomodel_endonum").value = (dynaremodel.endogenous).length;
-  document.getElementById("stomodel_exonum").value = (dynaremodel.exogenous).length;
-  $('#stosimModal').modal('show');
+      }
+      document.getElementById("stosimssinittable").innerHTML = sscomputeeendo;
+      document.getElementById("stomodel_endonum").value = (dynaremodel.endogenous).length;
+      document.getElementById("stomodel_exonum").value = (dynaremodel.exogenous).length;
+      $('#stosimModal').modal('show');
 
 
     },
-    error: function() {
+    error: function () {
       console.log('there was a problem checking the fields');
     }
   });
@@ -447,23 +450,7 @@ $('#runstochastic').click(async function () {
         return false;
 
 
-      // // calling the 'node side'
-      // try {
-      //   var resp = await runstochasticnode(stosimval);
-      // } catch (error) {
-      //   console.log(error)
-      //   if (error.status == 200) {
-      //     console.log("200")
-      //     return popthis('Error', error.message);
-      //   } else if (error.status == 100) {
-      //     console.log("100")
-      //     showconsolealert(error.message, 1);
-      //     console.log('console error');
-      //     return false;
-      //   }
-      // }
-
-      // return false;
+
     }
   }
 
diff --git a/routes/index.js b/routes/index.js
index e067387de8f66c70900d41675ce93071fcd61351..f0372378101182629b3e89cd69e10897db99c4db 100644
--- a/routes/index.js
+++ b/routes/index.js
@@ -7,9 +7,10 @@ var cookieParser = require('cookie-parser');
 const getmodelfromdb = require('../appModules').getmodelfromdb;
 const savetodb = require('../appModules').savetodb;
 const newmodelindb = require('../appModules').newmodelindb;
-const setpreprocess = require('../middleware/runpreprocess').setpreprocess;
-const setstochasticnode = require('../middleware/runstochastic').setstochasticnode;
-const runstochasticnode = require('../middleware/runstochastic').runstochasticnode;
+const setpreprocess = require('../middleware/runprocesses').setpreprocess;
+const setpreprocessmore = require('../middleware/runprocesses').setpreprocessmore;
+const runstochasticnode = require('../middleware/runprocesses').runstochasticnode;
+const runperfectnode = require('../middleware/runprocesses').runperfectnode;
 // const ipc = require('node-ipc');
 
 const csrfProtection = csrf({
@@ -132,7 +133,7 @@ router.post('/', function (req, res) {
 
     case 'setstochastic':
 
-      setstochasticnode(req.body)
+      setpreprocessmore(req.body)
         .then(function (data) {
           console.log(data);
           res.json(data);
@@ -145,6 +146,22 @@ router.post('/', function (req, res) {
 
       break;
 
+
+    case 'setperfect':
+
+      console.log('Got setperfect');
+
+      setpreprocessmore(req.body)
+        .then(function (data) {
+          console.log(data);
+          res.json(data);
+        })
+        .catch(function (e) {
+          res.json(data);
+        });
+
+      break;
+
     default:
       res.json({
         'status': 999,
@@ -176,6 +193,22 @@ router.put('/', function (req, res) {
     break;
 
 
+    case 'runperfect':
+
+      console.log('Got runperfect');
+
+      runperfectnode(req.body)
+      .then(function (data) {
+        console.log(data);
+        res.json(data);
+      })
+      .catch(function (e) {
+        res.json(data);
+      });
+
+    break;
+
+
     default:
       res.json({
         'status': 999,
diff --git a/views/index.handlebars b/views/index.handlebars
index 9bb444c5930132f1ba57cd62ec3e3fbba374f92b..025495a7786ed2077dc4e1bd2f0792a43a8b94a8 100644
--- a/views/index.handlebars
+++ b/views/index.handlebars
@@ -401,7 +401,7 @@
 
         <script src="./static/js/dynareinterface.js"></script>
         <script src="./static/js/editor.js"></script>
-        <!-- <script src="./static/js/perfectforesight.js"></script> -->
+        <script src="./static/js/perfectforesight.js"></script>
         <script src="./static/js/stochastic.js"></script>
 
         <script>