diff --git a/Docs/README.gremlins b/Docs/README.gremlins
new file mode 100644
index 0000000..a8f7eea
--- /dev/null
+++ b/Docs/README.gremlins
@@ -0,0 +1,109 @@
+Gremlins cause things to go wrong at random times.
+
+As implemented in Nasal/gremlins.nas, there are three types of
+gremlins:
+
+-- Most gremlins are based simply on time. There will be a MTBF
+ number (i.e. mean time between failures) associated with each
+ affected feature. A zero value for the MTBF property means the
+ gremlins will leave that feature alone; this is the default.
+ Otherwise the MTBF is measured in hours. A plausible for
+ practice flights is 5 hours. Note that if you have ten gremlins
+ with a 5-hour MTBF each, that means that on average /something/
+ will go wrong every 30 minutes.
+
+ There are about 20 eligible features including nav[0]/gs,
+ nav[0]/cdi, nav[1]/gs, nav[1]/cdi, attitude-indicator,
+ heading-indicator, dme, and adf; if you really want the complete
+ current list, look at the "features" array in gremlins.nas.
+
+-- Landing gear gremlins are based on MCBF i.e. mean cycles between
+ failures. They are not based on time, i.e. not on MTBF.
+
+-- If desired, the QNH changes every time you move to a new air mass.
+ More specifically, it changes every time you use the
+ location-in-air popup. This is mediated by a listenter attached to
+ the /position/attention property. The listener is in gremlins.nas;
+ the property is set by the location-in-air popup menu. This
+ happens on a per-relocation-event basis (not MTBF or MCBF).
+
+ The instructional purpose here is to encourage you (the pilot) to
+ pay attention to the altimeter setting. Every time you use
+ location-in-air, you should listen to the AWOS and set your altimeter
+ before practicing landings and/or instrument approaches.
+
+ The amount of change in the QNH is random, on a scale set by the
+ /environment/pressure-sea-level-inhg-step property. The default is
+ zero, and a reasonably instructive value is 0.2.
+
+ Also BTW, going the other way, note that anybody who changes the
+ QNH should set the /environment/attention property, not to be
+ confused with the /position/attention property. The former has
+ listeners in atis.cxx and perhaps elsewhere.
+
+==============================
+Notes and hints:
+
+Note that failing the vacuum system gives a more gradual -- and
+therefore more realistic -- gyro failure (as compared to failing the
+attitude indicator directly, which causes an unrealistically sudden
+failure). Both failure modes are supported; take your choice when you
+set the MTBF values.
+
+======
+
+There are three ways to check and/or change the status of a particular
+feature:
+ A) The Equipment::Instrument-failures popup or the
+ Equipment::System-failures popup.
+
+ B) The web interface. This is simpler than it initially appears;
+ for details see below.
+
+ C) The File::browse-internal-properties popup. This has the
+ advantage that it shows properties changing in real time,
+ whereas the web interface and the Equipment popups don't
+ show updated values unless/until you hit the reset or
+ reload button.
+
+Using the web interface is simpler than it looks, because you can use
+hyperlinks and/or bookmarks to quickly get access to the features you
+want.
+
+Here are some examples of checking properties:
+
+ lynx -dump 'http://localhost:5400/instrumentation/dme'
+ lynx -dump 'http://localhost:5400/gear'
+
+On such a page, both the "serviceable" property and the "mtbf" (or
+"mcbf") property may be of interest.
+
+You can also use the web page to restore functionality. For
+example:
+ lynx -dump 'http://localhost:5400/instrumentation/dme/serviceable?value=1&submit=update'
+ lynx -dump 'http://localhost:5400/gear/serviceable?value=1&submit=update'
+ lynx -dump 'http://localhost:5400/instrumentation/nav/gs/serviceable?value=1&submit=update'
+
+======
+
+In order to make the gremlins active, you have to set a nonzero MTBF
+(or MCBF, as appropriate) for each item of interest. This is
+typically done via the .fgfsrc file or the preferences.xml file. To
+save you some typing, here is an example of the setup you could put in
+your .fgfsrc file:
+
+ --prop:/gear/mcbf=5
+ --prop:/instrumentation/nav[0]/gs/mtbf=5
+ --prop:/instrumentation/nav[0]/cdi/mtbf=5
+ --prop:/instrumentation/nav[1]/gs/mtbf=5
+ --prop:/instrumentation/nav[1]/cdi/mtbf=5
+ ###--prop:/instrumentation/attitude-indicator/mtbf=5
+ --prop:/systems/vacuum/mtbf=5
+ --prop:/instrumentation/heading-indicator/mtbf=5
+ --prop:/instrumentation/dme/mtbf=5
+ --prop:/instrumentation/adf/mtbf=5
+
+ --prop:/environment/pressure-sea-level-inhg-step=0.2
+
+Also don't forget to start the web interface if you want it:
+ --httpd=5400
diff --git a/Nasal/gremlins.nas b/Nasal/gremlins.nas
new file mode 100644
index 0000000..a098329
--- /dev/null
+++ b/Nasal/gremlins.nas
@@ -0,0 +1,122 @@
+#! nasal
+
+# For design notes and usage instructions, see Docs/README.gremlins
+
+var last_gear = 0;
+var dt = 10; ## time between updates
+
+# Each of the following has an MTBF property:
+features = [
+ "/instrumentation/nav[0]/gs",
+ "/instrumentation/nav[0]/cdi",
+ "/instrumentation/nav[1]/gs",
+ "/instrumentation/nav[1]/cdi",
+ "/instrumentation/attitude-indicator", ## unrealistically sudden
+ "/systems/vacuum", ## more realistically gradual
+ "/instrumentation/heading-indicator",
+ "/instrumentation/dme",
+ "/instrumentation/adf",
+ "/instrumentation/airspeed-indicator",
+ "/instrumentation/attitude-indicator",
+ "/instrumentation/altimeter",
+ "/instrumentation/turn-indicator",
+ "/instrumentation/slip-skid-ball",
+ "/instrumentation/vertical-speed-indicator",
+ "/instrumentation/magnetic-compass",
+ "/systems/vacuum",
+ "/systems/static",
+ "/systems/pitot",
+ "/systems/electrical"
+ ];
+
+# For the given feature,
+# assign types and default values to the two properties of interest
+set1 = func(feat, interval) {
+ nnn = props.globals.getNode(feat ~ "/serviceable", 1);
+ if (nnn.getValue() == nil) {
+ nnn.setBoolValue(1);
+ }
+ if (nnn.getType() == "UNSPECIFIED") {
+ nnn.setBoolValue(nnn.getValue());
+ }
+
+ nnn = props.globals.getNode(feat ~ interval, 1);
+ if (nnn.getValue() == nil) {
+ nnn.setDoubleValue(0);
+ }
+ if (nnn.getType() == "UNSPECIFIED") {
+ nnn.setDoubleValue(nnn.getValue());
+ }
+}
+
+var gearcheck = func {
+ gear = getprop("/controls/gear/gear-down");
+
+ if (gear != last_gear) {
+ last_gear = gear;
+# mcbf == mean cycles between failures
+# hence 2*mcbf is the number of _half-cycles_ between failures,
+# which is relevant because we do this check on each half-cycle:
+ mcbf = getprop("/gear/mcbf");
+ if (mcbf and !int(2 * mcbf * rand())) {
+ setprop("/gear/serviceable", 0);
+ }
+ }
+}
+
+var gremulate = func{
+ foreach (feat ; features) {
+ mtbf = getprop(feat, "mtbf");
+ if (mtbf and !int(rand() * mtbf * 3600.0 / dt)) {
+ setprop(feat, "serviceable", 0);
+ }
+ }
+ settimer(gremulate, dt);
+}
+
+##########################
+# Listener; responds when we have moved to a new position
+var newpos = func{
+ Psl = getprop("/environment/pressure-sea-level-inhg");
+ step = getprop("/environment/pressure-sea-level-inhg-step");
+ delta = step * (2*rand() - 1);
+ Psl += delta;
+ lat = getprop("/position/latitude-deg");
+ lon = getprop("/position/longitude-deg");
+ # print("Gremlins.nas noticed new location: ", lon, " ", lat);
+ # print("... and sets Psl, delta: ", delta, " new: ", Psl);
+ for (ii = 0; ii < 5; ii+=1){
+ fmt = "/environment/config/%s/entry[%d]/pressure-sea-level-inhg";
+ setprop(sprintf(fmt, "boundary", ii), Psl);
+ setprop(sprintf(fmt, "aloft", ii), Psl);
+ }
+# Propagate it from the aforementioned entry[] items
+# to the internal variable of the FGenvironment class,
+# from whence it will propagate to the
+# /environment/pressure-sea-level-inhg property:
+ fgcommand("reinit", props.Node.new({"subsystem" : "environment"}));
+# Notify the ATIS generator that things have changed:
+ setprop("/environment/attention", 1);
+}
+
+# Initialization, called once Nasal loaded properly.
+_setlistener("/sim/signals/nasal-dir-initialized", func {
+ srand();
+
+ foreach (feat ; features) {
+ set1(feat, "/mtbf");
+ }
+
+ # Do the same for the gear,
+ # which is a special case (mcbf instead of mtbf).
+ set1("/gear", "/mcbf");
+
+ last_gear = getprop("/controls/gear/gear-down");
+
+ #####################
+ # Now the variables are set up; implement the listeners
+ setlistener("/controls/gear/gear-down", gearcheck);
+ setlistener("/position/attention", newpos);
+
+ gremulate(); # start the chain
+});
diff --git a/gui/dialogs/instrument-failures.xml b/gui/dialogs/instrument-failures.xml
index a0214dc..3b0f130 100644
--- a/gui/dialogs/instrument-failures.xml
+++ b/gui/dialogs/instrument-failures.xml
@@ -2,173 +2,362 @@
-
-
- instrument-failures
- 500
- 240
- false
-
-
- 10
- 210
-
-
+ instrument-failures
+ 620
+ 420
+ false
+ vbox
+
+
+
-
- 180
+
- 100
-
+ 10
+
-
-
-
- 150
-
-
- 10
- 0
- 20
- 20
-
- /instrumentation/airspeed-indicator/serviceable
-
-
-
- 240
- 0
- 20
- 20
-
- /instrumentation/attitude-indicator/serviceable
-
-
-
-
-
-
- 120
-
-
- 10
- 0
- 20
- 20
-
- /instrumentation/altimeter/serviceable
-
-
-
- 240
- 0
- 20
- 20
-
- /instrumentation/turn-indicator/serviceable
-
-
-
-
-
-
- 90
-
-
- 10
- 0
- 20
- 20
-
- /instrumentation/slip-skid-ball/serviceable
-
-
-
- 240
- 0
- 20
- 20
-
- /instrumentation/heading-indicator/serviceable
-
-
-
-
-
-
- 60
-
-
- 10
- 0
- 20
- 20
-
- /instrumentation/vertical-speed-indicator/serviceable
-
-
-
- 240
- 0
- 20
- 20
-
- /instrumentation/magnetic-compass/serviceable
-
-
-
-
-
-
- 10
-
-
-
-
-
-
-
-
-
-
+
+ table
+ center
+
+ 0
+