We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Make opening the browser when launching the server optional
**What's the problem this feature will solve?**
When we call `server.launch()` on a `ModularServer` instance the browser always opens another tab. This is not always desired behavior. 

**Describe the solution you'd like**
We should be able to make this optional. To maintain backwards compatibility we can keep the current behavior as default but over ride it with something like `server.launch(open_browser=False)`

**Additional context**
I will make a PR with this simple change.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `mesa/visualization/ModularVisualization.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 """
3 ModularServer
4 =============
5 
6 A visualization server which renders a model via one or more elements.
7 
8 The concept for the modular visualization server as follows:
9 A visualization is composed of VisualizationElements, each of which defines how
10 to generate some visualization from a model instance and render it on the
11 client. VisualizationElements may be anything from a simple text display to
12 a multilayered HTML5 canvas.
13 
14 The actual server is launched with one or more VisualizationElements;
15 it runs the model object through each of them, generating data to be sent to
16 the client. The client page is also generated based on the JavaScript code
17 provided by each element.
18 
19 This file consists of the following classes:
20 
21 VisualizationElement: Parent class for all other visualization elements, with
22                       the minimal necessary options.
23 PageHandler: The handler for the visualization page, generated from a template
24              and built from the various visualization elements.
25 SocketHandler: Handles the websocket connection between the client page and
26                 the server.
27 ModularServer: The overall visualization application class which stores and
28                controls the model and visualization instance.
29 
30 
31 ModularServer should *not* need to be subclassed on a model-by-model basis; it
32 should be primarily a pass-through for VisualizationElement subclasses, which
33 define the actual visualization specifics.
34 
35 For example, suppose we have created two visualization elements for our model,
36 called canvasvis and graphvis; we would launch a server with:
37 
38     server = ModularServer(MyModel, [canvasvis, graphvis], name="My Model")
39     server.launch()
40 
41 The client keeps track of what step it is showing. Clicking the Step button in
42 the browser sends a message requesting the viz_state corresponding to the next
43 step position, which is then sent back to the client via the websocket.
44 
45 The websocket protocol is as follows:
46 Each message is a JSON object, with a "type" property which defines the rest of
47 the structure.
48 
49 Server -> Client:
50     Send over the model state to visualize.
51     Model state is a list, with each element corresponding to a div; each div
52     is expected to have a render function associated with it, which knows how
53     to render that particular data. The example below includes two elements:
54     the first is data for a CanvasGrid, the second for a raw text display.
55 
56     {
57     "type": "viz_state",
58     "data": [{0:[ {"Shape": "circle", "x": 0, "y": 0, "r": 0.5,
59                 "Color": "#AAAAAA", "Filled": "true", "Layer": 0,
60                 "text": 'A', "text_color": "white" }]},
61             "Shape Count: 1"]
62     }
63 
64     Informs the client that the model is over.
65     {"type": "end"}
66 
67     Informs the client of the current model's parameters
68     {
69     "type": "model_params",
70     "params": 'dict' of model params, (i.e. {arg_1: val_1, ...})
71     }
72 
73 Client -> Server:
74     Reset the model.
75     TODO: Allow this to come with parameters
76     {
77     "type": "reset"
78     }
79 
80     Get a given state.
81     {
82     "type": "get_step",
83     "step:" index of the step to get.
84     }
85 
86     Submit model parameter updates
87     {
88     "type": "submit_params",
89     "param": name of model parameter
90     "value": new value for 'param'
91     }
92 
93     Get the model's parameters
94     {
95     "type": "get_params"
96     }
97 
98 """
99 import os
100 import tornado.autoreload
101 import tornado.ioloop
102 import tornado.web
103 import tornado.websocket
104 import tornado.escape
105 import tornado.gen
106 import webbrowser
107 
108 from mesa.visualization.UserParam import UserSettableParameter
109 
110 # Suppress several pylint warnings for this file.
111 # Attributes being defined outside of init is a Tornado feature.
112 # pylint: disable=attribute-defined-outside-init
113 
114 
115 class VisualizationElement:
116     """
117     Defines an element of the visualization.
118 
119     Attributes:
120         package_includes: A list of external JavaScript files to include that
121                           are part of the Mesa packages.
122         local_includes: A list of JavaScript files that are local to the
123                         directory that the server is being run in.
124         js_code: A JavaScript code string to instantiate the element.
125 
126     Methods:
127         render: Takes a model object, and produces JSON data which can be sent
128                 to the client.
129 
130     """
131 
132     package_includes = []
133     local_includes = []
134     js_code = ''
135     render_args = {}
136 
137     def __init__(self):
138         pass
139 
140     def render(self, model):
141         """ Build visualization data from a model object.
142 
143         Args:
144             model: A model object
145 
146         Returns:
147             A JSON-ready object.
148 
149         """
150         return "<b>VisualizationElement goes here</b>."
151 
152 # =============================================================================
153 # Actual Tornado code starts here:
154 
155 
156 class PageHandler(tornado.web.RequestHandler):
157     """ Handler for the HTML template which holds the visualization. """
158 
159     def get(self):
160         elements = self.application.visualization_elements
161         for i, element in enumerate(elements):
162             element.index = i
163         self.render("modular_template.html", port=self.application.port,
164                     model_name=self.application.model_name,
165                     description=self.application.description,
166                     package_includes=self.application.package_includes,
167                     local_includes=self.application.local_includes,
168                     scripts=self.application.js_code)
169 
170 
171 class SocketHandler(tornado.websocket.WebSocketHandler):
172     """ Handler for websocket. """
173     def open(self):
174         if self.application.verbose:
175             print("Socket opened!")
176         self.write_message({
177             "type": "model_params",
178             "params": self.application.user_params
179         })
180 
181     def check_origin(self, origin):
182         return True
183 
184     @property
185     def viz_state_message(self):
186         return {
187             "type": "viz_state",
188             "data": self.application.render_model()
189         }
190 
191     def on_message(self, message):
192         """ Receiving a message from the websocket, parse, and act accordingly.
193 
194         """
195         if self.application.verbose:
196             print(message)
197         msg = tornado.escape.json_decode(message)
198 
199         if msg["type"] == "get_step":
200             if not self.application.model.running:
201                 self.write_message({"type": "end"})
202             else:
203                 self.application.model.step()
204                 self.write_message(self.viz_state_message)
205 
206         elif msg["type"] == "reset":
207             self.application.reset_model()
208             self.write_message(self.viz_state_message)
209 
210         elif msg["type"] == "submit_params":
211             param = msg["param"]
212             value = msg["value"]
213 
214             # Is the param editable?
215             if param in self.application.user_params:
216                 if isinstance(self.application.model_kwargs[param], UserSettableParameter):
217                     self.application.model_kwargs[param].value = value
218                 else:
219                     self.application.model_kwargs[param] = value
220 
221         else:
222             if self.application.verbose:
223                 print("Unexpected message!")
224 
225 
226 class ModularServer(tornado.web.Application):
227     """ Main visualization application. """
228     verbose = True
229 
230     port = 8521  # Default port to listen on
231     max_steps = 100000
232 
233     # Handlers and other globals:
234     page_handler = (r'/', PageHandler)
235     socket_handler = (r'/ws', SocketHandler)
236     static_handler = (r'/static/(.*)', tornado.web.StaticFileHandler,
237                       {"path": os.path.dirname(__file__) + "/templates"})
238     local_handler = (r'/local/(.*)', tornado.web.StaticFileHandler,
239                      {"path": ''})
240 
241     handlers = [page_handler, socket_handler, static_handler, local_handler]
242 
243     settings = {"debug": True,
244                 "autoreload": False,
245                 "template_path": os.path.dirname(__file__) + "/templates"}
246 
247     EXCLUDE_LIST = ('width', 'height',)
248 
249     def __init__(self, model_cls, visualization_elements, name="Mesa Model",
250                  model_params={}):
251         """ Create a new visualization server with the given elements. """
252         # Prep visualization elements:
253         self.visualization_elements = visualization_elements
254         self.package_includes = set()
255         self.local_includes = set()
256         self.js_code = []
257         for element in self.visualization_elements:
258             for include_file in element.package_includes:
259                 self.package_includes.add(include_file)
260             for include_file in element.local_includes:
261                 self.local_includes.add(include_file)
262             self.js_code.append(element.js_code)
263 
264         # Initializing the model
265         self.model_name = name
266         self.model_cls = model_cls
267         self.description = 'No description available'
268         if hasattr(model_cls, 'description'):
269             self.description = model_cls.description
270         elif model_cls.__doc__ is not None:
271             self.description = model_cls.__doc__
272 
273         self.model_kwargs = model_params
274         self.reset_model()
275 
276         # Initializing the application itself:
277         super().__init__(self.handlers, **self.settings)
278 
279     @property
280     def user_params(self):
281         result = {}
282         for param, val in self.model_kwargs.items():
283             if isinstance(val, UserSettableParameter):
284                 result[param] = val.json
285 
286         return result
287 
288     def reset_model(self):
289         """ Reinstantiate the model object, using the current parameters. """
290 
291         model_params = {}
292         for key, val in self.model_kwargs.items():
293             if isinstance(val, UserSettableParameter):
294                 if val.param_type == 'static_text':    # static_text is never used for setting params
295                     continue
296                 model_params[key] = val.value
297             else:
298                 model_params[key] = val
299 
300         self.model = self.model_cls(**model_params)
301 
302     def render_model(self):
303         """ Turn the current state of the model into a dictionary of
304         visualizations
305 
306         """
307         visualization_state = []
308         for element in self.visualization_elements:
309             element_state = element.render(self.model)
310             visualization_state.append(element_state)
311         return visualization_state
312 
313     def launch(self, port=None):
314         """ Run the app. """
315         if port is not None:
316             self.port = port
317         url = 'http://127.0.0.1:{PORT}'.format(PORT=self.port)
318         print('Interface starting at {url}'.format(url=url))
319         self.listen(self.port)
320         webbrowser.open(url)
321         tornado.autoreload.start()
322         tornado.ioloop.IOLoop.current().start()
323
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/mesa/visualization/ModularVisualization.py b/mesa/visualization/ModularVisualization.py
--- a/mesa/visualization/ModularVisualization.py
+++ b/mesa/visualization/ModularVisualization.py
@@ -310,13 +310,14 @@
             visualization_state.append(element_state)
         return visualization_state
 
-    def launch(self, port=None):
+    def launch(self, port=None, open_browser=True):
         """ Run the app. """
         if port is not None:
             self.port = port
         url = 'http://127.0.0.1:{PORT}'.format(PORT=self.port)
         print('Interface starting at {url}'.format(url=url))
         self.listen(self.port)
-        webbrowser.open(url)
+        if open_browser:
+            webbrowser.open(url)
         tornado.autoreload.start()
         tornado.ioloop.IOLoop.current().start()

{"golden_diff": "diff --git a/mesa/visualization/ModularVisualization.py b/mesa/visualization/ModularVisualization.py\n--- a/mesa/visualization/ModularVisualization.py\n+++ b/mesa/visualization/ModularVisualization.py\n@@ -310,13 +310,14 @@\n             visualization_state.append(element_state)\n         return visualization_state\n \n-    def launch(self, port=None):\n+    def launch(self, port=None, open_browser=True):\n         \"\"\" Run the app. \"\"\"\n         if port is not None:\n             self.port = port\n         url = 'http://127.0.0.1:{PORT}'.format(PORT=self.port)\n         print('Interface starting at {url}'.format(url=url))\n         self.listen(self.port)\n-        webbrowser.open(url)\n+        if open_browser:\n+            webbrowser.open(url)\n         tornado.autoreload.start()\n         tornado.ioloop.IOLoop.current().start()\n", "issue": "Make opening the browser when launching the server optional\n**What's the problem this feature will solve?**\r\nWhen we call `server.launch()` on a `ModularServer` instance the browser always opens another tab. This is not always desired behavior. \r\n\r\n**Describe the solution you'd like**\r\nWe should be able to make this optional. To maintain backwards compatibility we can keep the current behavior as default but over ride it with something like `server.launch(open_browser=False)`\r\n\r\n**Additional context**\r\nI will make a PR with this simple change.\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\"\"\"\nModularServer\n=============\n\nA visualization server which renders a model via one or more elements.\n\nThe concept for the modular visualization server as follows:\nA visualization is composed of VisualizationElements, each of which defines how\nto generate some visualization from a model instance and render it on the\nclient. VisualizationElements may be anything from a simple text display to\na multilayered HTML5 canvas.\n\nThe actual server is launched with one or more VisualizationElements;\nit runs the model object through each of them, generating data to be sent to\nthe client. The client page is also generated based on the JavaScript code\nprovided by each element.\n\nThis file consists of the following classes:\n\nVisualizationElement: Parent class for all other visualization elements, with\n                      the minimal necessary options.\nPageHandler: The handler for the visualization page, generated from a template\n             and built from the various visualization elements.\nSocketHandler: Handles the websocket connection between the client page and\n                the server.\nModularServer: The overall visualization application class which stores and\n               controls the model and visualization instance.\n\n\nModularServer should *not* need to be subclassed on a model-by-model basis; it\nshould be primarily a pass-through for VisualizationElement subclasses, which\ndefine the actual visualization specifics.\n\nFor example, suppose we have created two visualization elements for our model,\ncalled canvasvis and graphvis; we would launch a server with:\n\n    server = ModularServer(MyModel, [canvasvis, graphvis], name=\"My Model\")\n    server.launch()\n\nThe client keeps track of what step it is showing. Clicking the Step button in\nthe browser sends a message requesting the viz_state corresponding to the next\nstep position, which is then sent back to the client via the websocket.\n\nThe websocket protocol is as follows:\nEach message is a JSON object, with a \"type\" property which defines the rest of\nthe structure.\n\nServer -> Client:\n    Send over the model state to visualize.\n    Model state is a list, with each element corresponding to a div; each div\n    is expected to have a render function associated with it, which knows how\n    to render that particular data. The example below includes two elements:\n    the first is data for a CanvasGrid, the second for a raw text display.\n\n    {\n    \"type\": \"viz_state\",\n    \"data\": [{0:[ {\"Shape\": \"circle\", \"x\": 0, \"y\": 0, \"r\": 0.5,\n                \"Color\": \"#AAAAAA\", \"Filled\": \"true\", \"Layer\": 0,\n                \"text\": 'A', \"text_color\": \"white\" }]},\n            \"Shape Count: 1\"]\n    }\n\n    Informs the client that the model is over.\n    {\"type\": \"end\"}\n\n    Informs the client of the current model's parameters\n    {\n    \"type\": \"model_params\",\n    \"params\": 'dict' of model params, (i.e. {arg_1: val_1, ...})\n    }\n\nClient -> Server:\n    Reset the model.\n    TODO: Allow this to come with parameters\n    {\n    \"type\": \"reset\"\n    }\n\n    Get a given state.\n    {\n    \"type\": \"get_step\",\n    \"step:\" index of the step to get.\n    }\n\n    Submit model parameter updates\n    {\n    \"type\": \"submit_params\",\n    \"param\": name of model parameter\n    \"value\": new value for 'param'\n    }\n\n    Get the model's parameters\n    {\n    \"type\": \"get_params\"\n    }\n\n\"\"\"\nimport os\nimport tornado.autoreload\nimport tornado.ioloop\nimport tornado.web\nimport tornado.websocket\nimport tornado.escape\nimport tornado.gen\nimport webbrowser\n\nfrom mesa.visualization.UserParam import UserSettableParameter\n\n# Suppress several pylint warnings for this file.\n# Attributes being defined outside of init is a Tornado feature.\n# pylint: disable=attribute-defined-outside-init\n\n\nclass VisualizationElement:\n    \"\"\"\n    Defines an element of the visualization.\n\n    Attributes:\n        package_includes: A list of external JavaScript files to include that\n                          are part of the Mesa packages.\n        local_includes: A list of JavaScript files that are local to the\n                        directory that the server is being run in.\n        js_code: A JavaScript code string to instantiate the element.\n\n    Methods:\n        render: Takes a model object, and produces JSON data which can be sent\n                to the client.\n\n    \"\"\"\n\n    package_includes = []\n    local_includes = []\n    js_code = ''\n    render_args = {}\n\n    def __init__(self):\n        pass\n\n    def render(self, model):\n        \"\"\" Build visualization data from a model object.\n\n        Args:\n            model: A model object\n\n        Returns:\n            A JSON-ready object.\n\n        \"\"\"\n        return \"<b>VisualizationElement goes here</b>.\"\n\n# =============================================================================\n# Actual Tornado code starts here:\n\n\nclass PageHandler(tornado.web.RequestHandler):\n    \"\"\" Handler for the HTML template which holds the visualization. \"\"\"\n\n    def get(self):\n        elements = self.application.visualization_elements\n        for i, element in enumerate(elements):\n            element.index = i\n        self.render(\"modular_template.html\", port=self.application.port,\n                    model_name=self.application.model_name,\n                    description=self.application.description,\n                    package_includes=self.application.package_includes,\n                    local_includes=self.application.local_includes,\n                    scripts=self.application.js_code)\n\n\nclass SocketHandler(tornado.websocket.WebSocketHandler):\n    \"\"\" Handler for websocket. \"\"\"\n    def open(self):\n        if self.application.verbose:\n            print(\"Socket opened!\")\n        self.write_message({\n            \"type\": \"model_params\",\n            \"params\": self.application.user_params\n        })\n\n    def check_origin(self, origin):\n        return True\n\n    @property\n    def viz_state_message(self):\n        return {\n            \"type\": \"viz_state\",\n            \"data\": self.application.render_model()\n        }\n\n    def on_message(self, message):\n        \"\"\" Receiving a message from the websocket, parse, and act accordingly.\n\n        \"\"\"\n        if self.application.verbose:\n            print(message)\n        msg = tornado.escape.json_decode(message)\n\n        if msg[\"type\"] == \"get_step\":\n            if not self.application.model.running:\n                self.write_message({\"type\": \"end\"})\n            else:\n                self.application.model.step()\n                self.write_message(self.viz_state_message)\n\n        elif msg[\"type\"] == \"reset\":\n            self.application.reset_model()\n            self.write_message(self.viz_state_message)\n\n        elif msg[\"type\"] == \"submit_params\":\n            param = msg[\"param\"]\n            value = msg[\"value\"]\n\n            # Is the param editable?\n            if param in self.application.user_params:\n                if isinstance(self.application.model_kwargs[param], UserSettableParameter):\n                    self.application.model_kwargs[param].value = value\n                else:\n                    self.application.model_kwargs[param] = value\n\n        else:\n            if self.application.verbose:\n                print(\"Unexpected message!\")\n\n\nclass ModularServer(tornado.web.Application):\n    \"\"\" Main visualization application. \"\"\"\n    verbose = True\n\n    port = 8521  # Default port to listen on\n    max_steps = 100000\n\n    # Handlers and other globals:\n    page_handler = (r'/', PageHandler)\n    socket_handler = (r'/ws', SocketHandler)\n    static_handler = (r'/static/(.*)', tornado.web.StaticFileHandler,\n                      {\"path\": os.path.dirname(__file__) + \"/templates\"})\n    local_handler = (r'/local/(.*)', tornado.web.StaticFileHandler,\n                     {\"path\": ''})\n\n    handlers = [page_handler, socket_handler, static_handler, local_handler]\n\n    settings = {\"debug\": True,\n                \"autoreload\": False,\n                \"template_path\": os.path.dirname(__file__) + \"/templates\"}\n\n    EXCLUDE_LIST = ('width', 'height',)\n\n    def __init__(self, model_cls, visualization_elements, name=\"Mesa Model\",\n                 model_params={}):\n        \"\"\" Create a new visualization server with the given elements. \"\"\"\n        # Prep visualization elements:\n        self.visualization_elements = visualization_elements\n        self.package_includes = set()\n        self.local_includes = set()\n        self.js_code = []\n        for element in self.visualization_elements:\n            for include_file in element.package_includes:\n                self.package_includes.add(include_file)\n            for include_file in element.local_includes:\n                self.local_includes.add(include_file)\n            self.js_code.append(element.js_code)\n\n        # Initializing the model\n        self.model_name = name\n        self.model_cls = model_cls\n        self.description = 'No description available'\n        if hasattr(model_cls, 'description'):\n            self.description = model_cls.description\n        elif model_cls.__doc__ is not None:\n            self.description = model_cls.__doc__\n\n        self.model_kwargs = model_params\n        self.reset_model()\n\n        # Initializing the application itself:\n        super().__init__(self.handlers, **self.settings)\n\n    @property\n    def user_params(self):\n        result = {}\n        for param, val in self.model_kwargs.items():\n            if isinstance(val, UserSettableParameter):\n                result[param] = val.json\n\n        return result\n\n    def reset_model(self):\n        \"\"\" Reinstantiate the model object, using the current parameters. \"\"\"\n\n        model_params = {}\n        for key, val in self.model_kwargs.items():\n            if isinstance(val, UserSettableParameter):\n                if val.param_type == 'static_text':    # static_text is never used for setting params\n                    continue\n                model_params[key] = val.value\n            else:\n                model_params[key] = val\n\n        self.model = self.model_cls(**model_params)\n\n    def render_model(self):\n        \"\"\" Turn the current state of the model into a dictionary of\n        visualizations\n\n        \"\"\"\n        visualization_state = []\n        for element in self.visualization_elements:\n            element_state = element.render(self.model)\n            visualization_state.append(element_state)\n        return visualization_state\n\n    def launch(self, port=None):\n        \"\"\" Run the app. \"\"\"\n        if port is not None:\n            self.port = port\n        url = 'http://127.0.0.1:{PORT}'.format(PORT=self.port)\n        print('Interface starting at {url}'.format(url=url))\n        self.listen(self.port)\n        webbrowser.open(url)\n        tornado.autoreload.start()\n        tornado.ioloop.IOLoop.current().start()\n", "path": "mesa/visualization/ModularVisualization.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\"\"\"\nModularServer\n=============\n\nA visualization server which renders a model via one or more elements.\n\nThe concept for the modular visualization server as follows:\nA visualization is composed of VisualizationElements, each of which defines how\nto generate some visualization from a model instance and render it on the\nclient. VisualizationElements may be anything from a simple text display to\na multilayered HTML5 canvas.\n\nThe actual server is launched with one or more VisualizationElements;\nit runs the model object through each of them, generating data to be sent to\nthe client. The client page is also generated based on the JavaScript code\nprovided by each element.\n\nThis file consists of the following classes:\n\nVisualizationElement: Parent class for all other visualization elements, with\n                      the minimal necessary options.\nPageHandler: The handler for the visualization page, generated from a template\n             and built from the various visualization elements.\nSocketHandler: Handles the websocket connection between the client page and\n                the server.\nModularServer: The overall visualization application class which stores and\n               controls the model and visualization instance.\n\n\nModularServer should *not* need to be subclassed on a model-by-model basis; it\nshould be primarily a pass-through for VisualizationElement subclasses, which\ndefine the actual visualization specifics.\n\nFor example, suppose we have created two visualization elements for our model,\ncalled canvasvis and graphvis; we would launch a server with:\n\n    server = ModularServer(MyModel, [canvasvis, graphvis], name=\"My Model\")\n    server.launch()\n\nThe client keeps track of what step it is showing. Clicking the Step button in\nthe browser sends a message requesting the viz_state corresponding to the next\nstep position, which is then sent back to the client via the websocket.\n\nThe websocket protocol is as follows:\nEach message is a JSON object, with a \"type\" property which defines the rest of\nthe structure.\n\nServer -> Client:\n    Send over the model state to visualize.\n    Model state is a list, with each element corresponding to a div; each div\n    is expected to have a render function associated with it, which knows how\n    to render that particular data. The example below includes two elements:\n    the first is data for a CanvasGrid, the second for a raw text display.\n\n    {\n    \"type\": \"viz_state\",\n    \"data\": [{0:[ {\"Shape\": \"circle\", \"x\": 0, \"y\": 0, \"r\": 0.5,\n                \"Color\": \"#AAAAAA\", \"Filled\": \"true\", \"Layer\": 0,\n                \"text\": 'A', \"text_color\": \"white\" }]},\n            \"Shape Count: 1\"]\n    }\n\n    Informs the client that the model is over.\n    {\"type\": \"end\"}\n\n    Informs the client of the current model's parameters\n    {\n    \"type\": \"model_params\",\n    \"params\": 'dict' of model params, (i.e. {arg_1: val_1, ...})\n    }\n\nClient -> Server:\n    Reset the model.\n    TODO: Allow this to come with parameters\n    {\n    \"type\": \"reset\"\n    }\n\n    Get a given state.\n    {\n    \"type\": \"get_step\",\n    \"step:\" index of the step to get.\n    }\n\n    Submit model parameter updates\n    {\n    \"type\": \"submit_params\",\n    \"param\": name of model parameter\n    \"value\": new value for 'param'\n    }\n\n    Get the model's parameters\n    {\n    \"type\": \"get_params\"\n    }\n\n\"\"\"\nimport os\nimport tornado.autoreload\nimport tornado.ioloop\nimport tornado.web\nimport tornado.websocket\nimport tornado.escape\nimport tornado.gen\nimport webbrowser\n\nfrom mesa.visualization.UserParam import UserSettableParameter\n\n# Suppress several pylint warnings for this file.\n# Attributes being defined outside of init is a Tornado feature.\n# pylint: disable=attribute-defined-outside-init\n\n\nclass VisualizationElement:\n    \"\"\"\n    Defines an element of the visualization.\n\n    Attributes:\n        package_includes: A list of external JavaScript files to include that\n                          are part of the Mesa packages.\n        local_includes: A list of JavaScript files that are local to the\n                        directory that the server is being run in.\n        js_code: A JavaScript code string to instantiate the element.\n\n    Methods:\n        render: Takes a model object, and produces JSON data which can be sent\n                to the client.\n\n    \"\"\"\n\n    package_includes = []\n    local_includes = []\n    js_code = ''\n    render_args = {}\n\n    def __init__(self):\n        pass\n\n    def render(self, model):\n        \"\"\" Build visualization data from a model object.\n\n        Args:\n            model: A model object\n\n        Returns:\n            A JSON-ready object.\n\n        \"\"\"\n        return \"<b>VisualizationElement goes here</b>.\"\n\n# =============================================================================\n# Actual Tornado code starts here:\n\n\nclass PageHandler(tornado.web.RequestHandler):\n    \"\"\" Handler for the HTML template which holds the visualization. \"\"\"\n\n    def get(self):\n        elements = self.application.visualization_elements\n        for i, element in enumerate(elements):\n            element.index = i\n        self.render(\"modular_template.html\", port=self.application.port,\n                    model_name=self.application.model_name,\n                    description=self.application.description,\n                    package_includes=self.application.package_includes,\n                    local_includes=self.application.local_includes,\n                    scripts=self.application.js_code)\n\n\nclass SocketHandler(tornado.websocket.WebSocketHandler):\n    \"\"\" Handler for websocket. \"\"\"\n    def open(self):\n        if self.application.verbose:\n            print(\"Socket opened!\")\n        self.write_message({\n            \"type\": \"model_params\",\n            \"params\": self.application.user_params\n        })\n\n    def check_origin(self, origin):\n        return True\n\n    @property\n    def viz_state_message(self):\n        return {\n            \"type\": \"viz_state\",\n            \"data\": self.application.render_model()\n        }\n\n    def on_message(self, message):\n        \"\"\" Receiving a message from the websocket, parse, and act accordingly.\n\n        \"\"\"\n        if self.application.verbose:\n            print(message)\n        msg = tornado.escape.json_decode(message)\n\n        if msg[\"type\"] == \"get_step\":\n            if not self.application.model.running:\n                self.write_message({\"type\": \"end\"})\n            else:\n                self.application.model.step()\n                self.write_message(self.viz_state_message)\n\n        elif msg[\"type\"] == \"reset\":\n            self.application.reset_model()\n            self.write_message(self.viz_state_message)\n\n        elif msg[\"type\"] == \"submit_params\":\n            param = msg[\"param\"]\n            value = msg[\"value\"]\n\n            # Is the param editable?\n            if param in self.application.user_params:\n                if isinstance(self.application.model_kwargs[param], UserSettableParameter):\n                    self.application.model_kwargs[param].value = value\n                else:\n                    self.application.model_kwargs[param] = value\n\n        else:\n            if self.application.verbose:\n                print(\"Unexpected message!\")\n\n\nclass ModularServer(tornado.web.Application):\n    \"\"\" Main visualization application. \"\"\"\n    verbose = True\n\n    port = 8521  # Default port to listen on\n    max_steps = 100000\n\n    # Handlers and other globals:\n    page_handler = (r'/', PageHandler)\n    socket_handler = (r'/ws', SocketHandler)\n    static_handler = (r'/static/(.*)', tornado.web.StaticFileHandler,\n                      {\"path\": os.path.dirname(__file__) + \"/templates\"})\n    local_handler = (r'/local/(.*)', tornado.web.StaticFileHandler,\n                     {\"path\": ''})\n\n    handlers = [page_handler, socket_handler, static_handler, local_handler]\n\n    settings = {\"debug\": True,\n                \"autoreload\": False,\n                \"template_path\": os.path.dirname(__file__) + \"/templates\"}\n\n    EXCLUDE_LIST = ('width', 'height',)\n\n    def __init__(self, model_cls, visualization_elements, name=\"Mesa Model\",\n                 model_params={}):\n        \"\"\" Create a new visualization server with the given elements. \"\"\"\n        # Prep visualization elements:\n        self.visualization_elements = visualization_elements\n        self.package_includes = set()\n        self.local_includes = set()\n        self.js_code = []\n        for element in self.visualization_elements:\n            for include_file in element.package_includes:\n                self.package_includes.add(include_file)\n            for include_file in element.local_includes:\n                self.local_includes.add(include_file)\n            self.js_code.append(element.js_code)\n\n        # Initializing the model\n        self.model_name = name\n        self.model_cls = model_cls\n        self.description = 'No description available'\n        if hasattr(model_cls, 'description'):\n            self.description = model_cls.description\n        elif model_cls.__doc__ is not None:\n            self.description = model_cls.__doc__\n\n        self.model_kwargs = model_params\n        self.reset_model()\n\n        # Initializing the application itself:\n        super().__init__(self.handlers, **self.settings)\n\n    @property\n    def user_params(self):\n        result = {}\n        for param, val in self.model_kwargs.items():\n            if isinstance(val, UserSettableParameter):\n                result[param] = val.json\n\n        return result\n\n    def reset_model(self):\n        \"\"\" Reinstantiate the model object, using the current parameters. \"\"\"\n\n        model_params = {}\n        for key, val in self.model_kwargs.items():\n            if isinstance(val, UserSettableParameter):\n                if val.param_type == 'static_text':    # static_text is never used for setting params\n                    continue\n                model_params[key] = val.value\n            else:\n                model_params[key] = val\n\n        self.model = self.model_cls(**model_params)\n\n    def render_model(self):\n        \"\"\" Turn the current state of the model into a dictionary of\n        visualizations\n\n        \"\"\"\n        visualization_state = []\n        for element in self.visualization_elements:\n            element_state = element.render(self.model)\n            visualization_state.append(element_state)\n        return visualization_state\n\n    def launch(self, port=None, open_browser=True):\n        \"\"\" Run the app. \"\"\"\n        if port is not None:\n            self.port = port\n        url = 'http://127.0.0.1:{PORT}'.format(PORT=self.port)\n        print('Interface starting at {url}'.format(url=url))\n        self.listen(self.port)\n        if open_browser:\n            webbrowser.open(url)\n        tornado.autoreload.start()\n        tornado.ioloop.IOLoop.current().start()\n", "path": "mesa/visualization/ModularVisualization.py"}]}