diff --git a/env_data/tests/test_env_loop.pkl b/env_data/tests/test_env_loop.pkl
new file mode 100644
index 0000000000000000000000000000000000000000..dd1df2a1b9982587b45a5bd802168e0820401f79
Binary files /dev/null and b/env_data/tests/test_env_loop.pkl differ
diff --git a/flatland/envs/malfunction_generators.py b/flatland/envs/malfunction_generators.py
index f8d1bc66b4f9a66c9657902aaa67ae42c9fd8c71..99082ddd764c62e16ad6b71bef7901333732cc4b 100644
--- a/flatland/envs/malfunction_generators.py
+++ b/flatland/envs/malfunction_generators.py
@@ -6,7 +6,7 @@ import numpy as np
 from numpy.random.mtrand import RandomState
 
 from flatland.envs.agent_utils import EnvAgent, RailAgentStatus
-from flatland.envs import persistence 
+from flatland.envs import persistence
 
 Malfunction = NamedTuple('Malfunction', [('num_broken_steps', int)])
 MalfunctionParameters = NamedTuple('MalfunctionParameters',
@@ -25,7 +25,7 @@ def _malfunction_prob(rate: float) -> float:
     if rate <= 0:
         return 0.
     else:
-        return 1 - np.exp(- (1 / rate))
+        return 1 - np.exp(-rate)
 
 
 def malfunction_from_file(filename: str, load_from_package=None) -> Tuple[MalfunctionGenerator, MalfunctionProcessData]:
@@ -42,7 +42,7 @@ def malfunction_from_file(filename: str, load_from_package=None) -> Tuple[Malfun
     """
     # with open(filename, "rb") as file_in:
     #     load_data = file_in.read()
-    
+
     # if filename.endswith("mpk"):
     #     data = msgpack.unpackb(load_data, use_list=False, encoding='utf-8')
     # elif filename.endswith("pkl"):
@@ -52,7 +52,7 @@ def malfunction_from_file(filename: str, load_from_package=None) -> Tuple[Malfun
     if "malfunction" in env_dict:
         env_dict['malfunction'] = oMPD = MalfunctionProcessData._make(env_dict['malfunction'])
     else:
-        oMPD=None
+        oMPD = None
     if oMPD is not None:
         # Mean malfunction in number of time steps
         mean_malfunction_rate = oMPD.malfunction_rate
diff --git a/flatland/utils/editor.py b/flatland/utils/editor.py
index d0f36a0deefb502017df1704a515ff4fda436a92..ff99ec08a35c26f6fc2b4bd54f9349c3963840ef 100644
--- a/flatland/utils/editor.py
+++ b/flatland/utils/editor.py
@@ -14,13 +14,13 @@ from flatland.envs.agent_utils import EnvAgent
 from flatland.envs.observations import TreeObsForRailEnv
 from flatland.envs.rail_env import RailEnv
 from flatland.envs.rail_generators import complex_rail_generator, empty_rail_generator, random_rail_generator
-
+from flatland.envs.persistence import RailEnvPersister
 
 class EditorMVC(object):
     """ EditorMVC - a class to encompass and assemble the Jupyter Editor Model-View-Controller.
     """
 
-    def __init__(self, env=None, sGL="PIL", env_filename="temp.mpk"):
+    def __init__(self, env=None, sGL="PIL", env_filename="temp.pkl"):
         """ Create an Editor MVC assembly around a railenv, or create one if None.
         """
         if env is None:
@@ -383,7 +383,7 @@ class Controller(object):
 
 
 class EditorModel(object):
-    def __init__(self, env, env_filename="temp.mpk"):
+    def __init__(self, env, env_filename="temp.pkl"):
         self.view = None
         self.env = env
         self.regen_size_width = 10
@@ -624,12 +624,13 @@ class EditorModel(object):
     def load(self):
         if os.path.exists(self.env_filename):
             self.log("load file: ", self.env_filename)
-            self.env.load(self.env_filename)
+            #self.env.load(self.env_filename)
+            RailEnvPersister.load(self.env, self.env_filename)
             if not self.regen_size_height == self.env.height or not self.regen_size_width == self.env.width:
                 self.regen_size_height = self.env.height
                 self.regen_size_width = self.env.width
                 self.regenerate(None, 0, self.env)
-                self.env.load(self.env_filename)
+                RailEnvPersister.load(self.env, self.env_filename)
 
             self.env.reset_agents()
             self.env.reset(False, False)
@@ -642,7 +643,8 @@ class EditorModel(object):
 
     def save(self):
         self.log("save to ", self.env_filename, " working dir: ", os.getcwd())
-        self.env.save(self.env_filename)
+        #self.env.save(self.env_filename)
+        RailEnvPersister.save(self.env, self.env_filename)
 
     def save_image(self):
         self.view.oRT.gl.save_image('frame_{:04d}.bmp'.format(self.save_image_count))
diff --git a/tests/test_flatland_envs_rail_env.py b/tests/test_flatland_envs_rail_env.py
index 68f0e089a82934278397b4d637e0ae42a9b61b58..0c865502f94b624ca9712a20cb83af72b0310357 100644
--- a/tests/test_flatland_envs_rail_env.py
+++ b/tests/test_flatland_envs_rail_env.py
@@ -8,7 +8,7 @@ from flatland.core.transition_map import GridTransitionMap
 from flatland.envs.agent_utils import EnvAgent
 from flatland.envs.observations import GlobalObsForRailEnv, TreeObsForRailEnv
 from flatland.envs.predictions import ShortestPathPredictorForRailEnv
-from flatland.envs.rail_env import RailEnv
+from flatland.envs.rail_env import RailEnv, RailEnvActions
 from flatland.envs.rail_generators import complex_rail_generator, rail_from_file
 from flatland.envs.rail_generators import rail_from_grid_transition_map
 from flatland.envs.schedule_generators import random_schedule_generator, complex_schedule_generator, schedule_from_file
@@ -87,8 +87,8 @@ def test_save_load_mpk():
         assert(agent1.target == agent2.target)
 
 
-@pytest.mark.skip(reason="Some unfortunate behaviour here - agent gets stuck at corners.")
-def test_rail_environment_single_agent():
+#@pytest.mark.skip(reason="Some unfortunate behaviour here - agent gets stuck at corners.")
+def test_rail_environment_single_agent(show=False):
     # We instantiate the following map on a 3x3 grid
     #  _  _
     # / \/ \
@@ -96,34 +96,50 @@ def test_rail_environment_single_agent():
     # \_/\_/
 
     transitions = RailEnvTransitions()
-    cells = transitions.transition_list
-    vertical_line = cells[1]
-    south_symmetrical_switch = cells[6]
-    north_symmetrical_switch = transitions.rotate_transition(south_symmetrical_switch, 180)
-    south_east_turn = int('0100000000000010', 2)
-    south_west_turn = transitions.rotate_transition(south_east_turn, 90)
-    north_east_turn = transitions.rotate_transition(south_east_turn, 270)
-    north_west_turn = transitions.rotate_transition(south_east_turn, 180)
-
-    rail_map = np.array([[south_east_turn, south_symmetrical_switch,
-                          south_west_turn],
-                         [vertical_line, vertical_line, vertical_line],
-                         [north_east_turn, north_symmetrical_switch,
-                          north_west_turn]],
-                        dtype=np.uint16)
-
-    rail = GridTransitionMap(width=3, height=3, transitions=transitions)
-    rail.grid = rail_map
-    rail_env = RailEnv(width=3, height=3, rail_generator=rail_from_grid_transition_map(rail),
-                       schedule_generator=random_schedule_generator(), number_of_agents=1,
-                       obs_builder_object=GlobalObsForRailEnv())
+    
+    
+    
+    if False:
+        # This env creation doesn't quite work right.
+        cells = transitions.transition_list
+        vertical_line = cells[1]
+        south_symmetrical_switch = cells[6]
+        north_symmetrical_switch = transitions.rotate_transition(south_symmetrical_switch, 180)
+        south_east_turn = int('0100000000000010', 2)
+        south_west_turn = transitions.rotate_transition(south_east_turn, 90)
+        north_east_turn = transitions.rotate_transition(south_east_turn, 270)
+        north_west_turn = transitions.rotate_transition(south_east_turn, 180)
+
+        rail_map = np.array([[south_east_turn, south_symmetrical_switch,
+                            south_west_turn],
+                            [vertical_line, vertical_line, vertical_line],
+                            [north_east_turn, north_symmetrical_switch,
+                            north_west_turn]],
+                            dtype=np.uint16)
+
+        rail = GridTransitionMap(width=3, height=3, transitions=transitions)
+        rail.grid = rail_map
+        rail_env = RailEnv(width=3, height=3, rail_generator=rail_from_grid_transition_map(rail),
+                        schedule_generator=random_schedule_generator(), number_of_agents=1,
+                        obs_builder_object=GlobalObsForRailEnv())
+    else:
+        rail_env, env_dict = RailEnvPersister.load_new("test_env_loop.pkl", "env_data.tests")
+        rail_map = rail_env.rail.grid
+    
+    rail_env._max_episode_steps = 1000
+
+    _ = rail_env.reset(False, False, True)
+
+    liActions = [int(a) for a in RailEnvActions]
 
     env_renderer = RenderTool(rail_env)
+
+    #RailEnvPersister.save(rail_env, "test_env_figure8.pkl")
     
-    for _ in range(50):
-        _ = rail_env.reset(False, False, True)
+    for _ in range(5):
 
-        
+        #rail_env.agents[0].initial_position = (1,2)
+        _ = rail_env.reset(False, False, True)
 
         # We do not care about target for the moment
         agent = rail_env.agents[0]
@@ -132,57 +148,68 @@ def test_rail_environment_single_agent():
         # Check that trains are always initialized at a consistent position
         # or direction.
         # They should always be able to go somewhere.
-        assert (transitions.get_transitions(
-            rail_map[agent.position],
-            agent.direction) != (0, 0, 0, 0))
+        if show:
+            print("After reset - agent pos:", agent.position, "dir: ", agent.direction)
+            print(transitions.get_transitions(rail_map[agent.position], agent.direction))
 
-        # HACK - force it to appear somwhere we know is good.
-        agent.position = (1,2)
-        agent.direction = 0
+        #assert (transitions.get_transitions(
+        #    rail_map[agent.position],
+        #    agent.direction) != (0, 0, 0, 0))
 
-        agent.initial_position = initial_pos = agent.position
+        # HACK - force the direction to one we know is good.
+        #agent.initial_position = agent.position = (2,3)
+        agent.initial_direction = agent.direction = 0
 
-        valid_active_actions_done = 0
-        pos = initial_pos
+        if show:
+            print ("handle:", agent.handle)
+        #agent.initial_position = initial_pos = agent.position
 
+        valid_active_actions_done = 0
+        pos = agent.position
 
-        env_renderer.render_env(show=False)
+        if show:
+            env_renderer.render_env(show=show, show_agents=True)
+            time.sleep(0.01)
 
         iStep = 0
         while valid_active_actions_done < 6:
             # We randomly select an action
-            action = np.random.randint(4)
+            action = np.random.choice(liActions)
+            #action = RailEnvActions.MOVE_FORWARD
 
-            _, _, _, _ = rail_env.step({0: action})
+            _, _, dict_done, _ = rail_env.step({0: action})
 
             prev_pos = pos
             pos = agent.position  # rail_env.agents_position[0]
 
-            #print("action:", action, "pos:", pos, "prev:", prev_pos)
+            print("action:", action, "pos:", agent.position, "prev:", prev_pos, agent.direction)
+            print(dict_done)
             if prev_pos != pos:
                 valid_active_actions_done += 1
             iStep += 1
-            env_renderer.render_env(show=False)
-            #time.sleep(0.1)
+            
+            if show:
+                env_renderer.render_env(show=show, show_agents=True, step=iStep)
+                time.sleep(0.01)
             assert iStep < 100, "valid actions should have been performed by now - hung agent"
 
         # After 6 movements on this railway network, the train should be back
         # to its original height on the map.
-        assert (initial_pos[0] == agent.position[0])
+        #assert (initial_pos[0] == agent.position[0])
 
         # We check that the train always attains its target after some time
         for _ in range(10):
             _ = rail_env.reset()
 
-            # JW - to avoid problem with random_schedule_generator.
-            rail_env.agents[0].position = (1,2)
+            rail_env.agents[0].direction = 0
 
-            done = False
+            # JW - to avoid problem with random_schedule_generator.
+            #rail_env.agents[0].position = (1,2)
 
             iStep = 0
             while iStep < 100:
                 # We randomly select an action
-                action = np.random.randint(4)
+                action = np.random.choice(liActions)
 
                 _, _, dones, _ = rail_env.step({0: action})
                 done = dones['__all__']
@@ -190,6 +217,7 @@ def test_rail_environment_single_agent():
                     break
                 iStep +=1
                 assert iStep < 100, "agent should have finished by now"
+                env_renderer.render_env(show=show)
 
 
 def test_dead_end():
@@ -336,7 +364,7 @@ def test_rail_env_reset():
 
 
 def main():
-    test_rail_environment_single_agent()
+    test_rail_environment_single_agent(show=True)
 
 if __name__=="__main__":
     main()
\ No newline at end of file
diff --git a/tests/test_flatland_malfunction.py b/tests/test_flatland_malfunction.py
index 464e7523db805bd1a45441c0666f5d37245439c1..eaa3112708f3f0e5d255b7e454078d9a59e7ca22 100644
--- a/tests/test_flatland_malfunction.py
+++ b/tests/test_flatland_malfunction.py
@@ -119,9 +119,9 @@ def test_malfunction_process():
 
 
 def test_malfunction_process_statistically():
-    """Tests hat malfunctions are produced by stochastic_data!"""
+    """Tests that malfunctions are produced by stochastic_data!"""
     # Set fixed malfunction duration for this test
-    stochastic_data = MalfunctionParameters(malfunction_rate=5,  # Rate of malfunction occurence
+    stochastic_data = MalfunctionParameters(malfunction_rate=1/5,  # Rate of malfunction occurence
                                             min_duration=5,  # Minimal duration of malfunction
                                             max_duration=5  # Max duration of malfunction
                                             )
@@ -168,7 +168,7 @@ def test_malfunction_process_statistically():
 def test_malfunction_before_entry():
     """Tests that malfunctions are working properly for agents before entering the environment!"""
     # Set fixed malfunction duration for this test
-    stochastic_data = MalfunctionParameters(malfunction_rate=2,  # Rate of malfunction occurence
+    stochastic_data = MalfunctionParameters(malfunction_rate=1/2,  # Rate of malfunction occurrence
                                             min_duration=10,  # Minimal duration of malfunction
                                             max_duration=10  # Max duration of malfunction
                                             )
@@ -215,7 +215,7 @@ def test_malfunction_values_and_behavior():
 
     rail, rail_map = make_simple_rail2()
     action_dict: Dict[int, RailEnvActions] = {}
-    stochastic_data = MalfunctionParameters(malfunction_rate=0.001,  # Rate of malfunction occurence
+    stochastic_data = MalfunctionParameters(malfunction_rate=1/0.001,  # Rate of malfunction occurence
                                             min_duration=10,  # Minimal duration of malfunction
                                             max_duration=10  # Max duration of malfunction
                                             )
@@ -241,7 +241,7 @@ def test_malfunction_values_and_behavior():
 
 
 def test_initial_malfunction():
-    stochastic_data = MalfunctionParameters(malfunction_rate=1000,  # Rate of malfunction occurence
+    stochastic_data = MalfunctionParameters(malfunction_rate=1/1000,  # Rate of malfunction occurence
                                             min_duration=2,  # Minimal duration of malfunction
                                             max_duration=5  # Max duration of malfunction
                                             )
@@ -390,7 +390,7 @@ def test_initial_malfunction_stop_moving():
 
 
 def test_initial_malfunction_do_nothing():
-    stochastic_data = MalfunctionParameters(malfunction_rate=70,  # Rate of malfunction occurence
+    stochastic_data = MalfunctionParameters(malfunction_rate=1/70,  # Rate of malfunction occurence
                                             min_duration=2,  # Minimal duration of malfunction
                                             max_duration=5  # Max duration of malfunction
                                             )