We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
from_PyCMDS should check version and system to determine if d1, d2, and d3 variables need to be scaled 
Helps to bypass legacy problems involving  wright-group/PyCMDS#210 .

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `WrightTools/data/_pycmds.py`
Content:
```
1 """PyCMDS."""
2 
3 
4 # --- import --------------------------------------------------------------------------------------
5 
6 
7 import itertools
8 import os
9 import pathlib
10 
11 import numpy as np
12 
13 import tidy_headers
14 
15 from ._data import Data
16 from .. import kit as wt_kit
17 from .. import units as wt_units
18 
19 
20 # --- define --------------------------------------------------------------------------------------
21 
22 
23 __all__ = ["from_PyCMDS"]
24 
25 
26 # --- from function -------------------------------------------------------------------------------
27 
28 
29 def from_PyCMDS(filepath, name=None, parent=None, verbose=True) -> Data:
30     """Create a data object from a single PyCMDS output file.
31 
32     Parameters
33     ----------
34     filepath : path-like
35         Path to the .data file
36         Can be either a local or remote file (http/ftp).
37         Can be compressed with gz/bz2, decompression based on file name.
38     name : str or None (optional)
39         The name to be applied to the new data object. If None, name is read
40         from file.
41     parent : WrightTools.Collection (optional)
42         Collection to place new data object within. Default is None.
43     verbose : bool (optional)
44         Toggle talkback. Default is True.
45 
46     Returns
47     -------
48     data
49         A Data instance.
50     """
51     filestr = os.fspath(filepath)
52     filepath = pathlib.Path(filepath)
53 
54     # header
55     ds = np.DataSource(None)
56     file_ = ds.open(filestr, "rt")
57     headers = tidy_headers.read(file_)
58     file_.seek(0)
59     # name
60     if name is None:  # name not given in method arguments
61         data_name = headers["data name"]
62     else:
63         data_name = name
64     if data_name == "":  # name not given in PyCMDS
65         data_name = headers["data origin"]
66     # create data object
67     kwargs = {
68         "name": data_name,
69         "kind": "PyCMDS",
70         "source": filestr,
71         "created": headers["file created"],
72     }
73     if parent is not None:
74         data = parent.create_data(**kwargs)
75     else:
76         data = Data(**kwargs)
77     # array
78     arr = np.genfromtxt(file_).T
79     file_.close()
80     # get axes and scanned variables
81     axes = []
82     for name, identity, units in zip(
83         headers["axis names"], headers["axis identities"], headers["axis units"]
84     ):
85         # points and centers
86         points = np.array(headers[name + " points"])
87         if name + " centers" in headers.keys():
88             centers = headers[name + " centers"]
89         else:
90             centers = None
91         # create
92         axis = {
93             "points": points,
94             "units": units,
95             "name": name,
96             "identity": identity,
97             "centers": centers,
98         }
99         axes.append(axis)
100     shape = tuple([a["points"].size for a in axes])
101     for i, ax in enumerate(axes):
102         sh = [1] * len(shape)
103         sh[i] = len(ax["points"])
104         data.create_variable(
105             name=ax["name"] + "_points", values=np.array(ax["points"]).reshape(sh)
106         )
107         if ax["centers"] is not None:
108             sh = list(shape)
109             sh[i] = 1
110             data.create_variable(
111                 name=ax["name"] + "_centers", values=np.array(ax["centers"]).reshape(sh)
112             )
113     # get assorted remaining things
114     # variables and channels
115     try:
116         signed = iter(headers["channel signed"])
117     except KeyError:
118         signed = itertools.repeat(False)
119     for index, kind, name in zip(range(len(arr)), headers["kind"], headers["name"]):
120         values = np.full(np.prod(shape), np.nan)
121         values[: len(arr[index])] = arr[index]
122         values.shape = shape
123         if name == "time":
124             data.create_variable(name="labtime", values=values)
125         if kind == "hardware":
126             # sadly, recorded tolerances are not reliable
127             # so a bit of hard-coded hacking is needed
128             # if this ends up being too fragile, we might have to use the points arrays
129             # ---Blaise 2018-01-09
130             units = headers["units"][index]
131             label = headers["label"][index]
132             if (
133                 "w" in name
134                 and name.startswith(tuple(data.variable_names))
135                 and name not in headers["axis names"]
136             ):
137                 inherited_shape = data[name.split("_")[0]].shape
138                 for i, s in enumerate(inherited_shape):
139                     if s == 1:
140                         values = np.mean(values, axis=i)
141                         values = np.expand_dims(values, i)
142             else:
143                 tolerance = headers["tolerance"][index]
144                 units = headers["units"][index]
145                 for i in range(len(shape)):
146                     if tolerance is None:
147                         break
148                     if "d" in name:
149                         # This is a hack because delay is particularly 
150                         # unreliable in tolerance. And 3 fs vs 3 ps is a huge
151                         # difference... KFS 2019-2-27
152                         if units == "fs":
153                             tolerance = 3.
154                         else:
155                             tolerance = 0.1
156                     if "zero" in name:
157                         tolerance = 1e-10
158                     try:
159                         assert i == headers["axis names"].index(name)
160                         tolerance = 0
161                     except (ValueError, AssertionError):
162                         if (
163                             name in headers["axis names"]
164                             and "%s_centers" % name not in data.variable_names
165                         ):
166                             tolerance = np.inf
167                     mean = np.nanmean(values, axis=i)
168                     mean = np.expand_dims(mean, i)
169                     values, meanexp = wt_kit.share_nans(values, mean)
170                     if np.allclose(meanexp, values, atol=tolerance, equal_nan=True):
171                         values = mean
172             if name in headers["axis names"]:
173                 points = np.array(headers[name + " points"])
174                 pointsshape = [1] * values.ndim
175                 for i, ax in enumerate(axes):
176                     if ax["name"] == name:
177                         pointsshape[i] = len(points)
178                         break
179                 points.shape = pointsshape
180                 points = wt_units.converter(points, headers["axis units"][i], units)
181                 for i in range(points.ndim):
182                     if points.shape[i] == 1:
183                         points = np.repeat(points, values.shape[i], axis=i)
184                 if points.size <= values.size:
185                     values[np.isnan(values)] = points[np.isnan(values)]
186             data.create_variable(name, values=values, units=units, label=label)
187         if kind == "channel":
188             data.create_channel(name=name, values=values, shape=values.shape, signed=next(signed))
189     # axes
190     for a in axes:
191         expression = a["identity"]
192         if expression.startswith("D"):
193             expression = expression[1:]
194         expression.replace("=D", "=")
195         a["expression"] = expression
196     data.transform(*[a["expression"] for a in axes])
197     for a, u in zip(data.axes, headers["axis units"]):
198         if u is not None:
199             a.convert(u)
200     # return
201     if verbose:
202         print("data created at {0}".format(data.fullpath))
203         print("  axes: {0}".format(data.axis_names))
204         print("  shape: {0}".format(data.shape))
205     return data
206
```
--- 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/WrightTools/data/_pycmds.py b/WrightTools/data/_pycmds.py
--- a/WrightTools/data/_pycmds.py
+++ b/WrightTools/data/_pycmds.py
@@ -146,7 +146,7 @@
                     if tolerance is None:
                         break
                     if "d" in name:
-                        # This is a hack because delay is particularly 
+                        # This is a hack because delay is particularly
                         # unreliable in tolerance. And 3 fs vs 3 ps is a huge
                         # difference... KFS 2019-2-27
                         if units == "fs":
@@ -197,6 +197,23 @@
     for a, u in zip(data.axes, headers["axis units"]):
         if u is not None:
             a.convert(u)
+    if (
+        headers["system name"] == "fs"
+        and int(headers["PyCMDS version"].split(".")[0]) == 0
+        and int(headers["PyCMDS version"].split(".")[1]) < 10
+    ):
+        # in versions of PyCMDS up to (and including) 0.9.0
+        # there was an incorrect hard-coded conversion factor between mm and fs
+        # this ONLY applied to Newport MFA stages
+        # we apply this correction knowing that Newport MFAs were only used on the "fs" system
+        # and knowing that the Newport MFAs were always assigned as "d1", "d2" and "d3"
+        # ---Blaise 2019-04-09
+        for delay in ("d1", "d2", "d3", "d1_points", "d2_points", "d3_points"):
+            if delay not in data.variable_names:
+                continue
+            data[delay][:] *= 6000.671281903963041 / 6671.281903963041
+            if verbose:
+                print(f"Correction factor applied to {delay}")
     # return
     if verbose:
         print("data created at {0}".format(data.fullpath))

{"golden_diff": "diff --git a/WrightTools/data/_pycmds.py b/WrightTools/data/_pycmds.py\n--- a/WrightTools/data/_pycmds.py\n+++ b/WrightTools/data/_pycmds.py\n@@ -146,7 +146,7 @@\n                     if tolerance is None:\n                         break\n                     if \"d\" in name:\n-                        # This is a hack because delay is particularly \n+                        # This is a hack because delay is particularly\n                         # unreliable in tolerance. And 3 fs vs 3 ps is a huge\n                         # difference... KFS 2019-2-27\n                         if units == \"fs\":\n@@ -197,6 +197,23 @@\n     for a, u in zip(data.axes, headers[\"axis units\"]):\n         if u is not None:\n             a.convert(u)\n+    if (\n+        headers[\"system name\"] == \"fs\"\n+        and int(headers[\"PyCMDS version\"].split(\".\")[0]) == 0\n+        and int(headers[\"PyCMDS version\"].split(\".\")[1]) < 10\n+    ):\n+        # in versions of PyCMDS up to (and including) 0.9.0\n+        # there was an incorrect hard-coded conversion factor between mm and fs\n+        # this ONLY applied to Newport MFA stages\n+        # we apply this correction knowing that Newport MFAs were only used on the \"fs\" system\n+        # and knowing that the Newport MFAs were always assigned as \"d1\", \"d2\" and \"d3\"\n+        # ---Blaise 2019-04-09\n+        for delay in (\"d1\", \"d2\", \"d3\", \"d1_points\", \"d2_points\", \"d3_points\"):\n+            if delay not in data.variable_names:\n+                continue\n+            data[delay][:] *= 6000.671281903963041 / 6671.281903963041\n+            if verbose:\n+                print(f\"Correction factor applied to {delay}\")\n     # return\n     if verbose:\n         print(\"data created at {0}\".format(data.fullpath))\n", "issue": "from_PyCMDS should check version and system to determine if d1, d2, and d3 variables need to be scaled \nHelps to bypass legacy problems involving  wright-group/PyCMDS#210 .\n", "before_files": [{"content": "\"\"\"PyCMDS.\"\"\"\n\n\n# --- import --------------------------------------------------------------------------------------\n\n\nimport itertools\nimport os\nimport pathlib\n\nimport numpy as np\n\nimport tidy_headers\n\nfrom ._data import Data\nfrom .. import kit as wt_kit\nfrom .. import units as wt_units\n\n\n# --- define --------------------------------------------------------------------------------------\n\n\n__all__ = [\"from_PyCMDS\"]\n\n\n# --- from function -------------------------------------------------------------------------------\n\n\ndef from_PyCMDS(filepath, name=None, parent=None, verbose=True) -> Data:\n    \"\"\"Create a data object from a single PyCMDS output file.\n\n    Parameters\n    ----------\n    filepath : path-like\n        Path to the .data file\n        Can be either a local or remote file (http/ftp).\n        Can be compressed with gz/bz2, decompression based on file name.\n    name : str or None (optional)\n        The name to be applied to the new data object. If None, name is read\n        from file.\n    parent : WrightTools.Collection (optional)\n        Collection to place new data object within. Default is None.\n    verbose : bool (optional)\n        Toggle talkback. Default is True.\n\n    Returns\n    -------\n    data\n        A Data instance.\n    \"\"\"\n    filestr = os.fspath(filepath)\n    filepath = pathlib.Path(filepath)\n\n    # header\n    ds = np.DataSource(None)\n    file_ = ds.open(filestr, \"rt\")\n    headers = tidy_headers.read(file_)\n    file_.seek(0)\n    # name\n    if name is None:  # name not given in method arguments\n        data_name = headers[\"data name\"]\n    else:\n        data_name = name\n    if data_name == \"\":  # name not given in PyCMDS\n        data_name = headers[\"data origin\"]\n    # create data object\n    kwargs = {\n        \"name\": data_name,\n        \"kind\": \"PyCMDS\",\n        \"source\": filestr,\n        \"created\": headers[\"file created\"],\n    }\n    if parent is not None:\n        data = parent.create_data(**kwargs)\n    else:\n        data = Data(**kwargs)\n    # array\n    arr = np.genfromtxt(file_).T\n    file_.close()\n    # get axes and scanned variables\n    axes = []\n    for name, identity, units in zip(\n        headers[\"axis names\"], headers[\"axis identities\"], headers[\"axis units\"]\n    ):\n        # points and centers\n        points = np.array(headers[name + \" points\"])\n        if name + \" centers\" in headers.keys():\n            centers = headers[name + \" centers\"]\n        else:\n            centers = None\n        # create\n        axis = {\n            \"points\": points,\n            \"units\": units,\n            \"name\": name,\n            \"identity\": identity,\n            \"centers\": centers,\n        }\n        axes.append(axis)\n    shape = tuple([a[\"points\"].size for a in axes])\n    for i, ax in enumerate(axes):\n        sh = [1] * len(shape)\n        sh[i] = len(ax[\"points\"])\n        data.create_variable(\n            name=ax[\"name\"] + \"_points\", values=np.array(ax[\"points\"]).reshape(sh)\n        )\n        if ax[\"centers\"] is not None:\n            sh = list(shape)\n            sh[i] = 1\n            data.create_variable(\n                name=ax[\"name\"] + \"_centers\", values=np.array(ax[\"centers\"]).reshape(sh)\n            )\n    # get assorted remaining things\n    # variables and channels\n    try:\n        signed = iter(headers[\"channel signed\"])\n    except KeyError:\n        signed = itertools.repeat(False)\n    for index, kind, name in zip(range(len(arr)), headers[\"kind\"], headers[\"name\"]):\n        values = np.full(np.prod(shape), np.nan)\n        values[: len(arr[index])] = arr[index]\n        values.shape = shape\n        if name == \"time\":\n            data.create_variable(name=\"labtime\", values=values)\n        if kind == \"hardware\":\n            # sadly, recorded tolerances are not reliable\n            # so a bit of hard-coded hacking is needed\n            # if this ends up being too fragile, we might have to use the points arrays\n            # ---Blaise 2018-01-09\n            units = headers[\"units\"][index]\n            label = headers[\"label\"][index]\n            if (\n                \"w\" in name\n                and name.startswith(tuple(data.variable_names))\n                and name not in headers[\"axis names\"]\n            ):\n                inherited_shape = data[name.split(\"_\")[0]].shape\n                for i, s in enumerate(inherited_shape):\n                    if s == 1:\n                        values = np.mean(values, axis=i)\n                        values = np.expand_dims(values, i)\n            else:\n                tolerance = headers[\"tolerance\"][index]\n                units = headers[\"units\"][index]\n                for i in range(len(shape)):\n                    if tolerance is None:\n                        break\n                    if \"d\" in name:\n                        # This is a hack because delay is particularly \n                        # unreliable in tolerance. And 3 fs vs 3 ps is a huge\n                        # difference... KFS 2019-2-27\n                        if units == \"fs\":\n                            tolerance = 3.\n                        else:\n                            tolerance = 0.1\n                    if \"zero\" in name:\n                        tolerance = 1e-10\n                    try:\n                        assert i == headers[\"axis names\"].index(name)\n                        tolerance = 0\n                    except (ValueError, AssertionError):\n                        if (\n                            name in headers[\"axis names\"]\n                            and \"%s_centers\" % name not in data.variable_names\n                        ):\n                            tolerance = np.inf\n                    mean = np.nanmean(values, axis=i)\n                    mean = np.expand_dims(mean, i)\n                    values, meanexp = wt_kit.share_nans(values, mean)\n                    if np.allclose(meanexp, values, atol=tolerance, equal_nan=True):\n                        values = mean\n            if name in headers[\"axis names\"]:\n                points = np.array(headers[name + \" points\"])\n                pointsshape = [1] * values.ndim\n                for i, ax in enumerate(axes):\n                    if ax[\"name\"] == name:\n                        pointsshape[i] = len(points)\n                        break\n                points.shape = pointsshape\n                points = wt_units.converter(points, headers[\"axis units\"][i], units)\n                for i in range(points.ndim):\n                    if points.shape[i] == 1:\n                        points = np.repeat(points, values.shape[i], axis=i)\n                if points.size <= values.size:\n                    values[np.isnan(values)] = points[np.isnan(values)]\n            data.create_variable(name, values=values, units=units, label=label)\n        if kind == \"channel\":\n            data.create_channel(name=name, values=values, shape=values.shape, signed=next(signed))\n    # axes\n    for a in axes:\n        expression = a[\"identity\"]\n        if expression.startswith(\"D\"):\n            expression = expression[1:]\n        expression.replace(\"=D\", \"=\")\n        a[\"expression\"] = expression\n    data.transform(*[a[\"expression\"] for a in axes])\n    for a, u in zip(data.axes, headers[\"axis units\"]):\n        if u is not None:\n            a.convert(u)\n    # return\n    if verbose:\n        print(\"data created at {0}\".format(data.fullpath))\n        print(\"  axes: {0}\".format(data.axis_names))\n        print(\"  shape: {0}\".format(data.shape))\n    return data\n", "path": "WrightTools/data/_pycmds.py"}], "after_files": [{"content": "\"\"\"PyCMDS.\"\"\"\n\n\n# --- import --------------------------------------------------------------------------------------\n\n\nimport itertools\nimport os\nimport pathlib\n\nimport numpy as np\n\nimport tidy_headers\n\nfrom ._data import Data\nfrom .. import kit as wt_kit\nfrom .. import units as wt_units\n\n\n# --- define --------------------------------------------------------------------------------------\n\n\n__all__ = [\"from_PyCMDS\"]\n\n\n# --- from function -------------------------------------------------------------------------------\n\n\ndef from_PyCMDS(filepath, name=None, parent=None, verbose=True) -> Data:\n    \"\"\"Create a data object from a single PyCMDS output file.\n\n    Parameters\n    ----------\n    filepath : path-like\n        Path to the .data file\n        Can be either a local or remote file (http/ftp).\n        Can be compressed with gz/bz2, decompression based on file name.\n    name : str or None (optional)\n        The name to be applied to the new data object. If None, name is read\n        from file.\n    parent : WrightTools.Collection (optional)\n        Collection to place new data object within. Default is None.\n    verbose : bool (optional)\n        Toggle talkback. Default is True.\n\n    Returns\n    -------\n    data\n        A Data instance.\n    \"\"\"\n    filestr = os.fspath(filepath)\n    filepath = pathlib.Path(filepath)\n\n    # header\n    ds = np.DataSource(None)\n    file_ = ds.open(filestr, \"rt\")\n    headers = tidy_headers.read(file_)\n    file_.seek(0)\n    # name\n    if name is None:  # name not given in method arguments\n        data_name = headers[\"data name\"]\n    else:\n        data_name = name\n    if data_name == \"\":  # name not given in PyCMDS\n        data_name = headers[\"data origin\"]\n    # create data object\n    kwargs = {\n        \"name\": data_name,\n        \"kind\": \"PyCMDS\",\n        \"source\": filestr,\n        \"created\": headers[\"file created\"],\n    }\n    if parent is not None:\n        data = parent.create_data(**kwargs)\n    else:\n        data = Data(**kwargs)\n    # array\n    arr = np.genfromtxt(file_).T\n    file_.close()\n    # get axes and scanned variables\n    axes = []\n    for name, identity, units in zip(\n        headers[\"axis names\"], headers[\"axis identities\"], headers[\"axis units\"]\n    ):\n        # points and centers\n        points = np.array(headers[name + \" points\"])\n        if name + \" centers\" in headers.keys():\n            centers = headers[name + \" centers\"]\n        else:\n            centers = None\n        # create\n        axis = {\n            \"points\": points,\n            \"units\": units,\n            \"name\": name,\n            \"identity\": identity,\n            \"centers\": centers,\n        }\n        axes.append(axis)\n    shape = tuple([a[\"points\"].size for a in axes])\n    for i, ax in enumerate(axes):\n        sh = [1] * len(shape)\n        sh[i] = len(ax[\"points\"])\n        data.create_variable(\n            name=ax[\"name\"] + \"_points\", values=np.array(ax[\"points\"]).reshape(sh)\n        )\n        if ax[\"centers\"] is not None:\n            sh = list(shape)\n            sh[i] = 1\n            data.create_variable(\n                name=ax[\"name\"] + \"_centers\", values=np.array(ax[\"centers\"]).reshape(sh)\n            )\n    # get assorted remaining things\n    # variables and channels\n    try:\n        signed = iter(headers[\"channel signed\"])\n    except KeyError:\n        signed = itertools.repeat(False)\n    for index, kind, name in zip(range(len(arr)), headers[\"kind\"], headers[\"name\"]):\n        values = np.full(np.prod(shape), np.nan)\n        values[: len(arr[index])] = arr[index]\n        values.shape = shape\n        if name == \"time\":\n            data.create_variable(name=\"labtime\", values=values)\n        if kind == \"hardware\":\n            # sadly, recorded tolerances are not reliable\n            # so a bit of hard-coded hacking is needed\n            # if this ends up being too fragile, we might have to use the points arrays\n            # ---Blaise 2018-01-09\n            units = headers[\"units\"][index]\n            label = headers[\"label\"][index]\n            if (\n                \"w\" in name\n                and name.startswith(tuple(data.variable_names))\n                and name not in headers[\"axis names\"]\n            ):\n                inherited_shape = data[name.split(\"_\")[0]].shape\n                for i, s in enumerate(inherited_shape):\n                    if s == 1:\n                        values = np.mean(values, axis=i)\n                        values = np.expand_dims(values, i)\n            else:\n                tolerance = headers[\"tolerance\"][index]\n                units = headers[\"units\"][index]\n                for i in range(len(shape)):\n                    if tolerance is None:\n                        break\n                    if \"d\" in name:\n                        # This is a hack because delay is particularly\n                        # unreliable in tolerance. And 3 fs vs 3 ps is a huge\n                        # difference... KFS 2019-2-27\n                        if units == \"fs\":\n                            tolerance = 3.\n                        else:\n                            tolerance = 0.1\n                    if \"zero\" in name:\n                        tolerance = 1e-10\n                    try:\n                        assert i == headers[\"axis names\"].index(name)\n                        tolerance = 0\n                    except (ValueError, AssertionError):\n                        if (\n                            name in headers[\"axis names\"]\n                            and \"%s_centers\" % name not in data.variable_names\n                        ):\n                            tolerance = np.inf\n                    mean = np.nanmean(values, axis=i)\n                    mean = np.expand_dims(mean, i)\n                    values, meanexp = wt_kit.share_nans(values, mean)\n                    if np.allclose(meanexp, values, atol=tolerance, equal_nan=True):\n                        values = mean\n            if name in headers[\"axis names\"]:\n                points = np.array(headers[name + \" points\"])\n                pointsshape = [1] * values.ndim\n                for i, ax in enumerate(axes):\n                    if ax[\"name\"] == name:\n                        pointsshape[i] = len(points)\n                        break\n                points.shape = pointsshape\n                points = wt_units.converter(points, headers[\"axis units\"][i], units)\n                for i in range(points.ndim):\n                    if points.shape[i] == 1:\n                        points = np.repeat(points, values.shape[i], axis=i)\n                if points.size <= values.size:\n                    values[np.isnan(values)] = points[np.isnan(values)]\n            data.create_variable(name, values=values, units=units, label=label)\n        if kind == \"channel\":\n            data.create_channel(name=name, values=values, shape=values.shape, signed=next(signed))\n    # axes\n    for a in axes:\n        expression = a[\"identity\"]\n        if expression.startswith(\"D\"):\n            expression = expression[1:]\n        expression.replace(\"=D\", \"=\")\n        a[\"expression\"] = expression\n    data.transform(*[a[\"expression\"] for a in axes])\n    for a, u in zip(data.axes, headers[\"axis units\"]):\n        if u is not None:\n            a.convert(u)\n    if (\n        headers[\"system name\"] == \"fs\"\n        and int(headers[\"PyCMDS version\"].split(\".\")[0]) == 0\n        and int(headers[\"PyCMDS version\"].split(\".\")[1]) < 10\n    ):\n        # in versions of PyCMDS up to (and including) 0.9.0\n        # there was an incorrect hard-coded conversion factor between mm and fs\n        # this ONLY applied to Newport MFA stages\n        # we apply this correction knowing that Newport MFAs were only used on the \"fs\" system\n        # and knowing that the Newport MFAs were always assigned as \"d1\", \"d2\" and \"d3\"\n        # ---Blaise 2019-04-09\n        for delay in (\"d1\", \"d2\", \"d3\", \"d1_points\", \"d2_points\", \"d3_points\"):\n            if delay not in data.variable_names:\n                continue\n            data[delay][:] *= 6000.671281903963041 / 6671.281903963041\n            if verbose:\n                print(f\"Correction factor applied to {delay}\")\n    # return\n    if verbose:\n        print(\"data created at {0}\".format(data.fullpath))\n        print(\"  axes: {0}\".format(data.axis_names))\n        print(\"  shape: {0}\".format(data.shape))\n    return data\n", "path": "WrightTools/data/_pycmds.py"}]}