# ==============================================================================
# Boeing Navigation Display by Gijs de Rooy
# See: http://wiki.flightgear.org/Canvas_ND_Framework
# ==============================================================================
# This file makes use of the MapStructure framework, see: http://wiki.flightgear.org/Canvas_MapStructure
#
# Sooner or later, some parts will be revamped by coming up with a simple animation framework: http://wiki.flightgear.org/NavDisplay#mapping_vs._SVG_animation

##
# pseudo DSL-ish: use these as placeholders in the config hash  below
var ALWAYS = func 1;
var NOTHING = func nil;

##
# TODO: move ND-specific implementation details into this lookup hash
# so that other aircraft and ND types can be more easily supported
#
# any aircraft-specific ND behavior should be wrapped here,
# to isolate/decouple things in the generic NavDisplay class
#
# TODO: move this to an XML config file (maybe supporting SGCondition and/or SGStateMachine markup for the logic?)
#
var NDStyles = {
	##
	# this configures the 744 ND to help generalize the NavDisplay class itself
	'Boeing': {
		font_mapper: func(family, weight) {
			if( family == "Liberation Sans" and weight == "normal" )
				return "LiberationFonts/LiberationSans-Regular.ttf";
		},

		# where all the symbols are stored
		# TODO: SVG elements should be renamed to use boeing/airbus prefix
		# aircraft developers should all be editing the same ND.svg image
		# the code can deal with the differences now
		svg_filename: "Nasal/canvas/map/Images/boeingND.svg",

		initialize_elements: func(me) {

		### this is the "old" method that's less flexible, we want to use the style hash instead (see above)
		# because things are much better configurable that way
		# now look up all required SVG elements and initialize member fields using the same name  to have a convenient handle
		foreach(var element; ["dmeLDist","dmeRDist","dmeL","dmeR","vorL","vorR","vorLId","vorRId",
		                      "status.wxr","status.wpt","status.sta","status.arpt"])
			me.symbols[element] = me.nd.getElementById(element);

		# load elements from vector image, and create instance variables using identical names, and call updateCenter() on each
		# anything that needs updatecenter called, should be added to the vector here
		#
		foreach(var element; ["staArrowL2","staArrowR2","staFromL2","staToL2","staFromR2","staToR2",
		                      "hdgTrk","trkInd","hdgBug","HdgBugCRT","TrkBugLCD","HdgBugLCD","curHdgPtr",
		                      "HdgBugCRT2","TrkBugLCD2","HdgBugLCD2","hdgBug2","selHdgLine","selHdgLine2","curHdgPtr2",
		                      "staArrowL","staArrowR","staToL","staFromL","staToR","staFromR"] )
			me.symbols[element] = me.nd.getElementById(element).updateCenter();

		}, # initialize_elements

		##
		## this loads and configures existing layers (currently, *.layer files in Nasal/canvas/map)
		##


		# TODO: phase out isMapStructure flag once map.nas & *.draw files are killed
		layers: [
			# TODO: take z-indices from *.draw files -- now handled by MapStructure in the addLayer method.
			{
				name:'WXR_live',
				isMapStructure:1,
				always_update: 1,
				update_on:[ 'toggle_range','toggle_weather','toggle_display_mode','toggle_weather_live'],
				predicate: func(nd, layer) {
					var visible = nd.get_switch('toggle_weather') and
						nd.get_switch('toggle_weather_live') and
						nd.get_switch('toggle_display_mode') != "PLAN";
					layer.group.setVisible(visible);
					if (visible) {
						layer.update();
					}
				}, # end of layer update predicate
				'z-index': -100,
			},
			{ name:'FIX', isMapStructure:1, update_on:['toggle_display_mode','toggle_waypoints'],
				# FIXME: this is a really ugly place for controller code
				predicate: func(nd, layer) {
					# print("Running fix layer predicate");
					# toggle visibility here
					var visible=nd.get_switch('toggle_waypoints') and nd.in_mode('toggle_display_mode', ['MAP']) and (nd.rangeNm() <= 40);
					layer.group.setVisible( visible );
					if (visible) {
						#print("Updating MapStructure ND layer: FIX");
						# (Hopefully) smart update
						layer.update();
					}
				}, # end of layer update predicate
				options: {
					range_dependant: 1
				},
				'z-index': -3,
			}, # end of FIX layer

			# Should redraw every 10 seconds TODO: use new MapStructure/WXR here once that works properly (Gijs should check first!)
			{
				name:'WXR',
				isMapStructure:1,
				update_on:[ {rate_hz: 0.1}, 'toggle_range','toggle_weather','toggle_display_mode', 'toggle_weather_live'],
				predicate: func(nd, layer) {
					#print("Running storms predicate");
					var visible=nd.get_switch('toggle_weather') and
						!nd.get_switch('toggle_weather_live') and
						nd.get_switch('toggle_display_mode') != "PLAN";
					layer.group.setVisible(visible);
					if (visible) {
						print("storms update requested! (timer issue when closing the dialog?)");
						layer.update();
					}
				}, # end of layer update predicate
				'z-index': -4,
			}, # end of storms/WXR layer

			{ name:'APS', isMapStructure:1, always_update: 1, update_on:['toggle_display_mode'],
				predicate: func(nd, layer) {
					var visible = nd.get_switch('toggle_display_mode') == "PLAN";
					layer.group.setVisible( visible );
					if (visible) {
						layer.update();
					}
				},
			},

			{ name:'APT', isMapStructure:1, update_on:['toggle_airports','toggle_display_mode'],
				predicate: func(nd, layer) {
					# toggle visibility here
					var visible=nd.get_switch('toggle_airports') and nd.in_mode('toggle_display_mode', ['MAP']);
					layer.group.setVisible( visible );
					if (visible) {
						#print("Updating MapStructure ND layer: APT");
						layer.update();
					}
				}, # end of layer update predicate
				options: {
					range_dependant: 1
				},
				'z-index': -1,
			}, # end of APT layer

			# Should distinct between low and high altitude navaids. Hiding above 40 NM for now, to prevent clutter/lag.
			{ name:'VOR', isMapStructure:1, update_on:['toggle_stations','toggle_display_mode'],
				# FIXME: this is a really ugly place for controller code
				predicate: func(nd, layer) {
					# toggle visibility here
					var visible = nd.get_switch('toggle_stations') and nd.in_mode('toggle_display_mode', ['MAP']) and (nd.rangeNm() <= 40);
					layer.group.setVisible( visible );
					if (visible) {
						#print("Updating MapStructure ND layer: VOR");
						layer.update();
					}
				}, # end of layer update predicate
				options: {
					range_dependant: 1
				},
				'z-index': -2,
			}, # end of VOR layer

			{ name:'DME', isMapStructure:1, update_on:['toggle_display_mode','toggle_stations'],
				# FIXME: this is a really ugly place for controller code
				predicate: func(nd, layer) {
					var visible = nd.get_switch('toggle_stations') and nd.in_mode('toggle_display_mode', ['MAP']) and (nd.rangeNm() <= 40);
					# toggle visibility here
					layer.group.setVisible( visible );
					if (visible) {
						#print("Updating MapStructure ND layer: DME");
						layer.update();
					}
				}, # end of layer update predicate
				options: {
					range_dependant: 1
				},
				'z-index': -2,
			}, # end of DME layer

			{ name:'TFC', isMapStructure:1, always_update: 1, update_on:['toggle_range','toggle_traffic'],
				predicate: func(nd, layer) {
					var visible = nd.get_switch('toggle_traffic');
					layer.group.setVisible( visible );
					if (visible) {
						#print("Updating MapStructure ND layer: TFC");
						layer.update();
					}
				}, # end of layer update predicate
				'z-index': 4,
			}, # end of traffic layer

			{ name:'runway-nd', update_on:['toggle_range','toggle_display_mode'],
				predicate: func(nd, layer) {
					#print("runway-nd wants to be ported to MapStructure");
					var visible = (nd.rangeNm() <= 40) and getprop("autopilot/route-manager/active") and nd.in_mode('toggle_display_mode', ['MAP','PLAN']) ;
					if (visible)
						layer._model.init(); # clear & redraw
					layer._view.setVisible( visible );
				}, # end of layer update predicate
			}, # end of airports-nd layer

			{ name:'RTE', isMapStructure:1, update_on:['toggle_range','toggle_display_mode'],
				predicate: func(nd, layer) {
					var visible= (nd.in_mode('toggle_display_mode', ['MAP','PLAN']));
					layer.group.setVisible( visible );
					if (visible)
						layer.update();
				}, # end of layer update predicate
				'z-index': 1,
			}, # end of route layer
			{ name:'WPT', isMapStructure:1, update_on:['toggle_range','toggle_display_mode'],
				predicate: func(nd, layer) {
					var visible= (nd.in_mode('toggle_display_mode', ['MAP','PLAN']));
					layer.group.setVisible( visible );

					if (visible)
						layer.update();
				}, # end of layer update predicate
				'z-index': 2,
			}, # end of waypoint layer
			{ name:'ALT-profile', isMapStructure:1, update_on:['toggle_range','toggle_display_mode'],
				predicate: func(nd, layer) {
					var visible= (nd.in_mode('toggle_display_mode', ['MAP','PLAN']));
					layer.group.setVisible( visible );

					if (visible)
						layer.update();
				}, # end of layer update predicate
				'z-index': 3,
			}, # end of altitude profile layer

			## add other layers here, layer names must match the registered names as used in *.layer files for now
			## this will all change once we're using Philosopher's MapStructure framework

		], # end of vector with configured layers

		# This is where SVG elements are configured by providing "behavior" hashes, i.e. for animations

		# to animate each SVG symbol, specify behavior via callbacks (predicate, and true/false implementation)
		# SVG identifier, callback  etc
		# TODO: update_on([]), update_mode (update() vs. timers/listeners)
		# TODO: support putting symbols on specific layers
		features: [
			{
				# TODO: taOnly doesn't need to use getprop polling in update(), use a listener instead!
				id: 'taOnly', # the SVG ID
				impl: { # implementation hash
					init: func(nd, symbol), # for updateCenter stuff, called during initialization in the ctor
					predicate: func(nd) getprop("instrumentation/tcas/inputs/mode") == 2, # the condition
					is_true:   func(nd) nd.symbols.taOnly.show(),
					is_false:  func(nd) nd.symbols.taOnly.hide(),
				}, # end of taOnly  behavior/callbacks
			},
			{
				id: 'tcasOff',
				impl: {
					init: func(nd, symbol),
					predicate: func(nd) getprop("instrumentation/tcas/inputs/mode") == 0 and nd.get_switch('toggle_traffic') and (nd.in_mode('toggle_display_mode', ['MAP']) or (nd.in_mode('toggle_display_mode', ['APP','VOR']) and !nd.get_switch('toggle_centered'))),
					is_true:   func(nd) nd.symbols.tcasOff.show(),
					is_false:  func(nd) nd.symbols.tcasOff.hide(),
				},
			},
			{
				id: 'tcasFail',
				impl: {
					init: func(nd, symbol),
					predicate: func(nd) getprop("instrumentation/tcas/inputs/mode") != 0 and getprop("instrumentation/tcas/serviceable") != 1 and nd.get_switch('toggle_traffic') and (nd.in_mode('toggle_display_mode', ['MAP']) or (nd.in_mode('toggle_display_mode', ['APP','VOR']) and !nd.get_switch('toggle_centered'))),
					is_true:   func(nd) nd.symbols.tcasFail.show(),
					is_false:  func(nd) nd.symbols.tcasFail.hide(),
				},
			},
			{
				id: 'tcasTest',
				impl: {
					init: func(nd, symbol),
					predicate: func(nd) getprop("instrumentation/tcas/inputs/self-test") == 1 and getprop("instrumentation/tcas/serviceable") == 1,
					is_true:   func(nd) nd.symbols.tcasTest.show(),
					is_false:  func(nd) nd.symbols.tcasTest.hide(),
				},
			},
			{
				id: 'tfc',
				impl: {
					init: func(nd, symbol),
					predicate: func(nd) getprop("instrumentation/tcas/inputs/mode") != 0 and nd.get_switch('toggle_traffic') and (nd.in_mode('toggle_display_mode', ['MAP']) or (nd.in_mode('toggle_display_mode', ['APP','VOR']) and !nd.get_switch('toggle_centered'))),
					is_true:   func(nd) nd.symbols.tfc.show(),
					is_false:  func(nd) nd.symbols.tfc.hide(),
				},
			},
			{
				id: 'traffic',
				impl: {
					init: func(nd, symbol),
					predicate: func(nd) getprop("instrumentation/tcas/outputs/traffic-alert") != 0 or getprop("instrumentation/tcas/outputs/advisory-alert"),
					is_true:   func(nd) {
						nd.symbols.traffic.show();
						if (getprop("instrumentation/tcas/outputs/traffic-alert"))
							nd.symbols.traffic.setColor(1,0,0);
						else
							nd.symbols.traffic.setColor(1,0.5,0);
					},
					is_false:  func(nd) nd.symbols.traffic.hide(),
				},
			},
			{
				id: 'tas',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) nd.aircraft_source.get_spd() > 100,
					is_true: func(nd) {
						nd.symbols.tas.setText(sprintf("%3.0f",nd.aircraft_source.get_spd() ));
						nd.symbols.tas.show();
					},
					is_false: func(nd) nd.symbols.tas.hide(),
				},
			},
			{
				id: 'tasLbl',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) nd.aircraft_source.get_spd() > 100,
					is_true: func(nd) nd.symbols.tasLbl.show(),
					is_false: func(nd) nd.symbols.tasLbl.hide(),
				},
			},
			{
				id: 'ilsFreq',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP']),
					is_true: func(nd) {
						nd.symbols.ilsFreq.show();
						if(getprop("instrumentation/nav/in-range"))
							nd.symbols.ilsFreq.setText(getprop("instrumentation/nav/nav-id"));
						else
							nd.symbols.ilsFreq.setText(getprop("instrumentation/nav/frequencies/selected-mhz-fmt"));
					},
					is_false: func(nd) nd.symbols.ilsFreq.hide(),
				},
			},
			{
				id: 'ilsLbl',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP']),
					is_true: func(nd) {
						nd.symbols.ilsLbl.show();
					},
					is_false: func(nd) nd.symbols.ilsLbl.hide(),
				},
			},
			{
				id: 'wpActiveId',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) getprop("/autopilot/route-manager/wp/id") != nil and getprop("autopilot/route-manager/active")
						and nd.in_mode('toggle_display_mode', ['MAP','PLAN']),
					is_true: func(nd) {
						nd.symbols.wpActiveId.setText(getprop("/autopilot/route-manager/wp/id"));
						nd.symbols.wpActiveId.show();
					},
					is_false: func(nd) nd.symbols.wpActiveId.hide(),
				}, # of wpActiveId.impl
			}, # of wpActiveId
			{
				id: 'wpActiveDist',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) getprop("/autopilot/route-manager/wp/dist") != nil and getprop("autopilot/route-manager/active")
						and nd.in_mode('toggle_display_mode', ['MAP','PLAN']),
					is_true: func(nd) {
						nd.symbols.wpActiveDist.setText(sprintf("%3.01f",getprop("/autopilot/route-manager/wp/dist")));
						nd.symbols.wpActiveDist.show();
					},
					is_false: func(nd) nd.symbols.wpActiveDist.hide(),
				},
			},
			{
				id: 'wpActiveDistLbl',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) getprop("/autopilot/route-manager/wp/dist") != nil and getprop("autopilot/route-manager/active")
						and nd.in_mode('toggle_display_mode', ['MAP','PLAN']),
					is_true: func(nd) {
						nd.symbols.wpActiveDistLbl.show();
						if(getprop("/autopilot/route-manager/wp/dist") > 1000)
							nd.symbols.wpActiveDistLbl.setText("   NM");
					},
					is_false: func(nd) nd.symbols.wpActiveDistLbl.hide(),
				},
			},
			{
				id: 'eta',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) getprop("autopilot/route-manager/wp/eta") != nil and getprop("autopilot/route-manager/active")
						and nd.in_mode('toggle_display_mode', ['MAP','PLAN']),
					is_true: func(nd) {
						var etaSec = getprop("/sim/time/utc/day-seconds")+getprop("autopilot/route-manager/wp/eta-seconds");
						var h = math.floor(etaSec/3600);
						etaSec=etaSec-3600*h;
						var m = math.floor(etaSec/60);
						etaSec=etaSec-60*m;
						var s = etaSec/10;
						if (h>24) h=h-24;
						nd.symbols.eta.setText(sprintf("%02.0f%02.0f.%01.0fz",h,m,s));
						nd.symbols.eta.show();
					},
					is_false: func(nd) nd.symbols.eta.hide(),
				},  # of eta.impl
			}, # of eta
			{
				id: 'gsGroup',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP']),
					is_true: func(nd) {
						if(nd.get_switch('toggle_centered'))
							nd.symbols.gsGroup.setTranslation(0,0);
						else
							nd.symbols.gsGroup.setTranslation(0,150);
						nd.symbols.gsGroup.show();
					},
					is_false: func(nd) nd.symbols.gsGroup.hide(),
				},
			},
			{
				id: 'compassApp',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) (nd.get_switch('toggle_centered') and nd.in_mode('toggle_display_mode', ['APP','VOR'])),
					is_true: func(nd) {
						if(nd.get_switch('toggle_true_north'))
							var hdg = nd.aircraft_source.get_trk_tru();
						else
							var hdg = nd.aircraft_source.get_trk_mag();
						nd.symbols.compassApp.setRotation(-hdg*D2R);
						nd.symbols.compassApp.show();
					},
					is_false: func(nd) nd.symbols.compassApp.hide(),
				},
			},
			{
				id: 'compassMapCtr',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) (nd.get_switch('toggle_centered') and nd.in_mode('toggle_display_mode', ['MAP'])),
					is_true: func(nd) {
						if(nd.get_switch('toggle_true_north'))
							var hdg = nd.aircraft_source.get_trk_tru();
						else
							var hdg = nd.aircraft_source.get_trk_mag();
						nd.symbols.compassMapCtr.setRotation(-hdg*D2R);
						nd.symbols.compassMapCtr.show();
					},
					is_false: func(nd) nd.symbols.compassMapCtr.hide(),
				},
			},
			{
				id:'hdg',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP','MAP','VOR']),
					is_true: func(nd) {
						var hdgText = "";
						if((nd.in_mode('toggle_display_mode', ['MAP']) and nd.get_switch('toggle_display_type') == "CRT")
							or (nd.get_switch('toggle_track_heading') and nd.get_switch('toggle_display_type') == "LCD"))
						{
							if(nd.get_switch('toggle_true_north'))
								hdgText = nd.aircraft_source.get_trk_tru();
							else
								hdgText = nd.aircraft_source.get_trk_mag();
						} else {
							if(nd.get_switch('toggle_true_north'))
								hdgText = nd.aircraft_source.get_hdg_tru();
							else
								hdgText = nd.aircraft_source.get_hdg_mag();
						}
						if(hdgText < 0.5) hdgText = 360 + hdgText;
						elsif(hdgText >= 360.5) hdgText = hdgText - 360;
						nd.symbols.hdg.setText(sprintf("%03.0f", hdgText));
					},
					is_false: NOTHING,
				},
			},
			{
				id:'hdgGroup',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP','MAP','VOR']),
					is_true: func(nd) {
						nd.symbols.hdgGroup.show();
						if(nd.get_switch('toggle_centered'))
							nd.symbols.hdgGroup.setTranslation(0,100);
						else
							nd.symbols.hdgGroup.setTranslation(0,0);
					},
					is_false: func(nd) nd.symbols.hdgGroup.hide(),
				},
			},
			{
				id:'gs',
				impl: {
					init: func(nd,symbol),
					common: func(nd) nd.symbols.gs.setText(sprintf("%3.0f",nd.aircraft_source.get_gnd_spd() )),
					predicate: func(nd) nd.aircraft_source.get_gnd_spd() >= 30,
					is_true: func(nd) {
						nd.symbols.gs.setFontSize(36);
					},
					is_false: func(nd) nd.symbols.gs.setFontSize(52),
				},
			},
			{
				id:'compass',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) ((nd.get_switch('toggle_centered') and !nd.in_mode('toggle_display_mode', ['PLAN'])) or nd.in_mode('toggle_display_mode', ['PLAN'])),
					is_true: func(nd) nd.symbols.compass.hide(),
					is_false: func(nd) {
						nd.symbols.compass.show();
						nd.symbols.compass.setRotation(-nd.userHdgTrk*D2R);
					},
				},
			},
			{
				id:'truMag',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) nd.get_switch('toggle_true_north'),
					is_true: func(nd) nd.symbols.truMag.setText("TRU"),
					is_false: func(nd) nd.symbols.truMag.setText("MAG"),
				},
			},
			{
				id:'northUp',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) nd.in_mode('toggle_display_mode', ['PLAN']),
					is_true: func(nd) nd.symbols.northUp.show(),
					is_false: func(nd) nd.symbols.northUp.hide(),
				},
			},
			{
				id:'planArcs',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) nd.in_mode('toggle_display_mode', ['PLAN']),
					is_true: func(nd) nd.symbols.planArcs.show(),
					is_false: func(nd) nd.symbols.planArcs.hide(),
				},
			},
			{
				id:'aplSymMap',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) (nd.in_mode('toggle_display_mode', ['APP','MAP','VOR'])  and !nd.get_switch('toggle_centered')),
					is_true: func(nd) nd.symbols.aplSymMap.show(),
					is_false: func(nd) nd.symbols.aplSymMap.hide(),
				},
			},
			{
				id:'aplSymMapCtr',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) (nd.in_mode('toggle_display_mode', ['MAP'])  and nd.get_switch('toggle_centered')),
					is_true: func(nd) nd.symbols.aplSymMapCtr.show(),
					is_false: func(nd) nd.symbols.aplSymMapCtr.hide(),
				},
			},
			{
				id:'aplSymVor',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) (nd.in_mode('toggle_display_mode', ['APP','VOR'])  and nd.get_switch('toggle_centered')),
					is_true: func(nd) nd.symbols.aplSymVor.show(),
					is_false: func(nd) nd.symbols.aplSymVor.hide(),
				},
			},
			{
				id:'rangeArcs',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) !nd.get_switch('toggle_centered') and nd.get_switch('toggle_rangearc'),
					is_true: func(nd) nd.symbols.rangeArcs.show(),
					is_false: func(nd) nd.symbols.rangeArcs.hide(),
				},
			},
			{
				id:'rangePln1',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) nd.get_switch('toggle_display_mode') == "PLAN",
					is_true: func(nd) {
						nd.symbols.rangePln1.show();
						nd.symbols.rangePln1.setText(sprintf("%3.0f",nd.rangeNm()));
					},
					is_false: func(nd) nd.symbols.rangePln1.hide(),
				},
			},
			{
				id:'rangePln2',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) nd.get_switch('toggle_display_mode') == "PLAN",
					is_true: func(nd) {
						nd.symbols.rangePln2.show();
						nd.symbols.rangePln2.setText(sprintf("%3.0f",nd.rangeNm()/2));
					},
					is_false: func(nd) nd.symbols.rangePln2.hide(),
				},
			},
			{
				id:'rangePln3',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) nd.get_switch('toggle_display_mode') == "PLAN",
					is_true: func(nd) {
						nd.symbols.rangePln3.show();
						nd.symbols.rangePln3.setText(sprintf("%3.0f",nd.rangeNm()/2));
					},
					is_false: func(nd) nd.symbols.rangePln3.hide(),
				},
			},
			{
				id:'rangePln4',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) nd.get_switch('toggle_display_mode') == "PLAN",
					is_true: func(nd) {
						nd.symbols.rangePln4.show();
						nd.symbols.rangePln4.setText(sprintf("%3.0f",nd.rangeNm()));
					},
					is_false: func(nd) nd.symbols.rangePln4.hide(),
				},
			},
			{
				id:'range',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) !nd.get_switch('toggle_centered'),
					is_true: func(nd) {
						nd.symbols.range.setText(sprintf("%3.0f",nd.rangeNm()/2));
					},
					is_false: func(nd) nd.symbols.rangePln4.hide(),
				},
			},
			{
				id:'rangeCtr1',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) (nd.get_switch('toggle_centered') and nd.in_mode('toggle_display_mode', ['APP','MAP','VOR'])),
					is_true: func(nd) {
						nd.symbols.rangeCtr1.show();
						nd.symbols.rangeCtr1.setText(sprintf("%g",nd.rangeNm()/4));
					},
					is_false: func(nd) nd.symbols.rangeCtr1.hide(),
				},
			},
			{
				id:'rangeCtr2',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) (nd.get_switch('toggle_centered') and nd.in_mode('toggle_display_mode', ['APP','MAP','VOR'])),
					is_true: func(nd) {
						nd.symbols.rangeCtr2.show();
						nd.symbols.rangeCtr2.setText(sprintf("%g",nd.rangeNm()/4));
					},
					is_false: func(nd) nd.symbols.rangeCtr2.hide(),
				},
			},
			{
				id:'altArc',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) (!nd.get_switch('toggle_centered') and nd.in_mode('toggle_display_mode', ['MAP'])),
					is_true: func(nd) {
						var altDiff = (getprop("autopilot/settings/target-altitude-ft") or 0)-(getprop("instrumentation/altimeter/indicated-altitude-ft") or 0);
						if (abs(nd.aircraft_source.get_vspd()) > 1 and altDiff/nd.aircraft_source.get_vspd() > 0) {
							var altRangeNm = altDiff/nd.aircraft_source.get_vspd()*nd.aircraft_source.get_gnd_spd()*KT2MPS*M2NM;
							if(altRangeNm > 1) {
								var altRangePx = (350/nd.rangeNm())*altRangeNm;
								if (altRangePx > 700)
									altRangePx = 700;
								nd.symbols.altArc.setTranslation(0,-altRangePx);
							}
							nd.symbols.altArc.show();
						} else
							nd.symbols.altArc.hide();
					},
					is_false: func(nd) nd.symbols.altArc.hide(),
				},
			},
			{
				id:'altArcCtr',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) (nd.get_switch('toggle_centered') and nd.in_mode('toggle_display_mode', ['MAP'])),
					is_true: func(nd) {
						var altDiff = (getprop("autopilot/settings/target-altitude-ft") or 0)-(getprop("instrumentation/altimeter/indicated-altitude-ft") or 0);
						if (abs(nd.aircraft_source.get_vspd()) > 1 and altDiff/nd.aircraft_source.get_vspd() > 0) {
							var altRangeNm = altDiff/nd.aircraft_source.get_vspd()*nd.aircraft_source.get_gnd_spd()*KT2MPS*M2NM;
							if(altRangeNm > 1) {
								var altRangePx = (350/nd.rangeNm())*altRangeNm;
								if (altRangePx > 350)
									altRangePx = 350;
								nd.symbols.altArcCtr.setTranslation(0,-altRangePx);
							}
							nd.symbols.altArcCtr.show();
						} else
							nd.symbols.altArcCtr.hide();
					},
					is_false: func(nd) nd.symbols.altArcCtr.hide(),
				},
			},
			{
				id:'crsLbl',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP','VOR']),
					is_true: func(nd) nd.symbols.crsLbl.show(),
					is_false: func(nd) nd.symbols.crsLbl.hide(),
				},
			},
			{
				id:'crs',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP','VOR']),
					is_true: func(nd) {
						nd.symbols.crs.show();
						if(getprop("instrumentation/nav/radials/selected-deg") != nil)
							nd.symbols.crs.setText(sprintf("%03.0f",getprop("instrumentation/nav/radials/selected-deg")));
					},
					is_false: func(nd) nd.symbols.crs.hide(),
				},
			},
			{
				id:'dmeLbl',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP','VOR']),
					is_true: func(nd) nd.symbols.dmeLbl.show(),
					is_false: func(nd) nd.symbols.dmeLbl.hide(),
				},
			},
			{
				id:'dme',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP','VOR']),
					is_true: func(nd) {
						nd.symbols.dme.show();
						if(getprop("instrumentation/dme/in-range"))
							nd.symbols.dme.setText(sprintf("%3.1f",getprop("instrumentation/dme/indicated-distance-nm")));
					},
					is_false: func(nd) nd.symbols.dme.hide(),
				},
			},
			{
				id:'trkInd2',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) (nd.in_mode('toggle_display_mode', ['APP','VOR']) and nd.get_switch('toggle_centered')),
					is_true: func(nd) {
						if (nd.get_switch('toggle_track_heading') and nd.get_switch('toggle_display_type') == "LCD")
							nd.symbols.trkInd2.setRotation(0);
						else
							nd.symbols.trkInd2.setRotation((nd.userTrk-nd.userHdg)*D2R);
						nd.symbols.trkInd2.show();
					},
					is_false: func(nd) nd.symbols.trkInd2.hide(),
				},
			},
			{
				id:'trkIndMapCtr',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) (nd.in_mode('toggle_display_mode', ['MAP']) and nd.get_switch('toggle_centered')),
					is_true: func(nd) {
						if (nd.get_switch('toggle_display_type') == "CRT" or (nd.get_switch('toggle_track_heading') and nd.get_switch('toggle_display_type') == "LCD"))
							nd.symbols.trkIndMapCtr.setRotation(0);
						else
							nd.symbols.trkIndMapCtr.setRotation((nd.userTrk-nd.userHdg)*D2R);
						nd.symbols.trkIndMapCtr.show();
					},
					is_false: func(nd) nd.symbols.trkIndMapCtr.hide(),
				},
			},
			{
				id:'vorCrsPtr',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) (nd.in_mode('toggle_display_mode', ['APP','VOR']) and !nd.get_switch('toggle_centered')),
					is_true: func(nd) {
						nd.symbols.vorCrsPtr.show();
						if((nd.in_mode('toggle_display_mode', ['MAP']) and nd.get_switch('toggle_display_type') == "CRT")
							or (nd.get_switch('toggle_track_heading') and nd.get_switch('toggle_display_type') == "LCD"))
							nd.symbols.vorCrsPtr.setRotation((getprop("instrumentation/nav/radials/selected-deg")-nd.aircraft_source.get_trk_mag())*D2R);
						else
							nd.symbols.vorCrsPtr.setRotation((getprop("instrumentation/nav/radials/selected-deg")-nd.aircraft_source.get_hdg_mag())*D2R);
					},
					is_false: func(nd) nd.symbols.vorCrsPtr.hide(),
				},
			},
			{
				id:'vorCrsPtr2',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) (nd.in_mode('toggle_display_mode', ['APP','VOR']) and nd.get_switch('toggle_centered')),
					is_true: func(nd) {
						nd.symbols.vorCrsPtr2.show();
						if((nd.in_mode('toggle_display_mode', ['MAP']) and nd.get_switch('toggle_display_type') == "CRT")
							or (nd.get_switch('toggle_track_heading') and nd.get_switch('toggle_display_type') == "LCD"))
							nd.symbols.vorCrsPtr2.setRotation((getprop("instrumentation/nav/radials/selected-deg")-nd.aircraft_source.get_trk_mag())*D2R);
						else
							nd.symbols.vorCrsPtr2.setRotation((getprop("instrumentation/nav/radials/selected-deg")-nd.aircraft_source.get_hdg_mag())*D2R);
					},
					is_false: func(nd) nd.symbols.vorCrsPtr2.hide(),
				},
			},
			{
				id: 'gsDiamond',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP']) and getprop("instrumentation/nav/gs-in-range"),
					is_true: func(nd) {
						var gs_deflection = getprop("instrumentation/nav/gs-needle-deflection-norm");
						if(gs_deflection != nil)
							nd.symbols.gsDiamond.setTranslation(gs_deflection*150,0);
						if(abs(gs_deflection) < 0.99)
							nd.symbols.gsDiamond.setColorFill(1,0,1,1);
						else
							nd.symbols.gsDiamond.setColorFill(0,0,0,1);
					},
					is_false: func(nd) nd.symbols.gsGroup.hide(),
				},
			},
			{
				id:'locPtr',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) (nd.in_mode('toggle_display_mode', ['APP','VOR']) and !nd.get_switch('toggle_centered') and getprop("instrumentation/nav/in-range")),
					is_true: func(nd) {
						nd.symbols.locPtr.show();
						var deflection = getprop("instrumentation/nav/heading-needle-deflection-norm");
						nd.symbols.locPtr.setTranslation(deflection*150,0);
						if(abs(deflection) < 0.99)
							nd.symbols.locPtr.setColorFill(1,0,1,1);
						else
							nd.symbols.locPtr.setColorFill(0,0,0,1);
					},
					is_false: func(nd) nd.symbols.locPtr.hide(),
				},
			},
			{
				id:'locPtr2',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) (nd.in_mode('toggle_display_mode', ['APP','VOR']) and nd.get_switch('toggle_centered') and getprop("instrumentation/nav/in-range")),
					is_true: func(nd) {
						nd.symbols.locPtr2.show();
						var deflection = getprop("instrumentation/nav/heading-needle-deflection-norm");
						nd.symbols.locPtr2.setTranslation(deflection*150,0);
						if(abs(deflection) < 0.99)
							nd.symbols.locPtr2.setColorFill(1,0,1,1);
						else
							nd.symbols.locPtr2.setColorFill(0,0,0,1);
					},
					is_false: func(nd) nd.symbols.locPtr2.hide(),
				},
			},
			{
				id:'wind',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) (nd.aircraft_source.get_spd() > 100 and getprop("environment/wind-speed-kt") > 4),
					is_true: func(nd) {
						var windDir = getprop("environment/wind-from-heading-deg");
						var windSpd = getprop("environment/wind-speed-kt");
						if(!nd.get_switch('toggle_true_north'))
							windDir = windDir - getprop("environment/magnetic-variation-deg");
						while(windDir < 0.5) windDir += 360;
						while(windDir > 360.5) windDir -= 360;
						if (windSpd > 6)
							nd.windShown = 1;
						if (nd.windShown != 0) {
							nd.symbols.wind.setText(sprintf("%03.0f° / %02.0f",windDir,windSpd));
							nd.symbols.wind.show();
						} else
							nd.symbols.wind.hide();
					},
					is_false: func(nd) {
						nd.windShown = 0;
						nd.symbols.wind.hide();
					},
				},
			},
			{
				id:'windArrow',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) (!(nd.in_mode('toggle_display_mode', ['PLAN']) and (nd.get_switch('toggle_display_type') == "LCD")) and nd.aircraft_source.get_spd() > 100 and getprop("environment/wind-speed-kt") > 4),
					is_true: func(nd) {
						if (nd.windShown != 0) {
							nd.symbols.windArrow.show();
							var windArrowRot = getprop("environment/wind-from-heading-deg") - getprop("environment/magnetic-variation-deg");
							if((nd.in_mode('toggle_display_mode', ['MAP','PLAN']) and nd.get_switch('toggle_display_type') == "CRT")
								or (nd.get_switch('toggle_track_heading') and nd.get_switch('toggle_display_type') == "LCD"))
									windArrowRot = windArrowRot - nd.aircraft_source.get_trk_mag();
								else
									windArrowRot = windArrowRot - nd.aircraft_source.get_hdg_mag();
						nd.symbols.windArrow.setRotation(windArrowRot*D2R);
						} else {
							nd.symbols.windArrow.hide();
						}
					},
					is_false: func(nd) nd.symbols.windArrow.hide(),
				},
			},
			{
				id:'trendVector',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) (nd.in_mode('toggle_display_mode', ['MAP'])),
					is_true: func(nd) {
						nd.symbols.trendVector.show();
						var rollDeg = getprop("/orientation/roll-deg") or 0;
						if (abs(rollDeg) > 0.2 and nd.aircraft_source.get_gnd_spd() > 100) {
							var radius = abs(nd.aircraft_source.get_gnd_spd()*nd.aircraft_source.get_gnd_spd()/(68578.83369*math.tan(rollDeg*D2R)));
							var sec = 90;
							if (nd.rangeNm() <= 10) sec = 30;
							elsif (nd.rangeNm() == 20) sec = 60;
							var L = nd.aircraft_source.get_gnd_spd()*0.0002778*sec;
							var angle = L/radius;
							var factor = 346/(0.5*nd.rangeNm());
							radius = radius*factor;
							if (radius > 65535) radius = 65535; # prevent 16-bit overflow
							var y = radius*math.sin(angle);
							var x = (1-math.cos(angle))*radius;
							if (rollDeg < 0) {
								x = -x;
								var cmd = 21;
								if (angle > math.pi and angle < 2 * math.pi) cmd = 25;
							} else {
								var cmd = 19;
								if (angle > math.pi and angle < 2 * math.pi) cmd = 23;
							}
							var y1 = 824;
							if (nd.get_switch('toggle_centered')) y1 = 562;
							nd.symbols.trendVector.setData([2,cmd],[512,y1,radius,radius,0,x,-y]);
							var dash = L*factor;
							var dashArray = [dash/3-3, 5];
							if (nd.rangeNm() <= 10) dashArray = [dash]; 
							elsif (nd.rangeNm() == 20) dashArray = [dash/2-2, 5];
							nd.symbols.trendVector.setStrokeDashArray(dashArray);
						}
					},
					is_false: func(nd) nd.symbols.trendVector.hide(),
				},
			},
			{
				id:'vorL',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) (nd.get_switch('toggle_lh_vor_adf') != 0),
					is_true: func(nd) {
						if(nd.get_switch('toggle_lh_vor_adf') == 1) {
							nd.symbols.vorL.setText("VOR L");
							nd.symbols.vorL.setColor(0.195,0.96,0.097);
						} else {
							nd.symbols.vorL.setText("ADF L");
							nd.symbols.vorL.setColor(0,0.6,0.85);
						}
						nd.symbols.vorL.show();
					},
					is_false: func(nd) nd.symbols.vorL.hide(),
				},
			},
			{
				id:'vorLId',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) (nd.get_switch('toggle_lh_vor_adf') != 0),
					is_true: func(nd) {
						if(nd.get_switch('toggle_lh_vor_adf') == 1) {
							if(getprop("instrumentation/nav/in-range"))
								nd.symbols.vorLId.setText(getprop("instrumentation/nav/nav-id"));
							else
								nd.symbols.vorLId.setText(getprop("instrumentation/nav/frequencies/selected-mhz-fmt"));
							nd.symbols.vorLId.setColor(0.195,0.96,0.097);
						} else {
							if((var navident=getprop("instrumentation/adf/ident")) != "")
								nd.symbols.vorLId.setText(navident);
							else
								nd.symbols.vorLId.setText(sprintf("%3d",getprop("instrumentation/adf/frequencies/selected-khz")));
							nd.symbols.vorLId.setColor(0,0.6,0.85);
						}
						nd.symbols.vorLId.show();
					},
					is_false: func(nd) nd.symbols.vorLId.hide(),
				},
			},
			{
				id:'dmeLDist',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) (nd.get_switch('toggle_lh_vor_adf') != 0),
					is_true: func(nd) {
						if(nd.get_switch('toggle_lh_vor_adf') == 1) {
							if(getprop("instrumentation/dme/in-range"))
								nd.symbols.dmeLDist.setText(sprintf("%3.1f",getprop("instrumentation/dme/indicated-distance-nm")));
							else
								nd.symbols.dmeLDist.setText(" ---");
							nd.symbols.dmeLDist.setColor(0.195,0.96,0.097);
						} else {
							nd.symbols.dmeLDist.setText("");
							nd.symbols.dmeLDist.setColor(0,0.6,0.85);
						}
						nd.symbols.dmeLDist.show();
					},
					is_false: func(nd) nd.symbols.dmeLDist.hide(),
				},
			},
			{
				id:'dmeL',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) (nd.get_switch('toggle_lh_vor_adf') != 0),
					is_true: func(nd) {
						if(nd.get_switch('toggle_lh_vor_adf') == 1) {
							nd.symbols.dmeL.setText("DME");
							nd.symbols.dmeL.setColor(0.195,0.96,0.097);
						} else {
							nd.symbols.dmeL.setText("");
							nd.symbols.dmeL.setColor(0,0.6,0.85);
						}
						nd.symbols.dmeL.show();
					},
					is_false: func(nd) nd.symbols.dmeL.hide(),
				},
			},
			# TACAN added by tikibar (J. Williams)
			{
				id:'TCNArrow',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) (nd.in_mode('toggle_display_mode', ['MAP','APP','VOR']) and !nd.get_switch('toggle_centered') and nd.efis_switches['toggle_tacan'] != nil),
					is_true: func(nd) {
						if (nd.get_switch('toggle_tacan')) {
							nd.symbols.TCNArrow.show();
							nd.symbols.TCNArrow.setRotation((getprop("instrumentation/tacan/indicated-bearing-true-deg")-nd.aircraft_source.get_hdg_tru())*D2R);
						} else {
							nd.symbols.TCNArrow.hide();
						}
					},
					is_false: func(nd) nd.symbols.TCNArrow.hide(),
				},
			},
			{
				id:'TCNArrow2',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) (nd.in_mode('toggle_display_mode', ['MAP','APP','VOR']) and nd.get_switch('toggle_centered') and nd.efis_switches['toggle_tacan'] != nil),
					is_true: func(nd) {
						if (nd.get_switch('toggle_tacan')) {
							nd.symbols.TCNArrow2.show();
							nd.symbols.TCNArrow2.setRotation((getprop("instrumentation/tacan/indicated-bearing-true-deg")-nd.aircraft_source.get_hdg_tru())*D2R);
						} else {
							nd.symbols.TCNArrow2.hide();
						}
					},
					is_false: func(nd) nd.symbols.TCNArrow2.hide(),
				},
			},
			{
				id:'TACAN',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) (nd.in_mode('toggle_display_mode', ['MAP','APP','VOR']) and nd.efis_switches['toggle_tacan'] != nil),
					is_true: func(nd) {
						if (nd.get_switch('toggle_tacan')) {
							nd.symbols.TACAN.setText("TACAN");
							nd.symbols.TACAN.show();
						} else {
							nd.symbols.TACAN.hide();
						}
					},
					is_false: func(nd) nd.symbols.TACAN.hide(),
				},
			},
			{
				id:'TACANId',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) (nd.in_mode('toggle_display_mode', ['MAP','APP','VOR']) and nd.efis_switches['toggle_tacan'] != nil),
					is_true: func(nd) {
						if (nd.get_switch('toggle_tacan') and getprop("instrumentation/tacan/in-range")) {
							nd.symbols.TACANId.setText(getprop("instrumentation/tacan/ident"));
							nd.symbols.TACANId.show();
						} else {
							nd.symbols.TACANId.hide();
						}
					},
					is_false: func(nd) nd.symbols.TACANId.hide(),
				},
			},
			{
				id:'TACANdme',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) (nd.in_mode('toggle_display_mode', ['MAP','APP','VOR']) and nd.efis_switches['toggle_tacan'] != nil),
					is_true: func(nd) {
						if (nd.get_switch('toggle_tacan') and getprop("instrumentation/tacan/in-range")) {
							nd.symbols.TACANdme.setText("DIST");
							nd.symbols.TACANdme.show();
						} else {
							nd.symbols.TACANdme.hide();
						}
					},
					is_false: func(nd) nd.symbols.TACANdme.hide(),
				},
			},
			{
				id:'TACANdmeDist',
				impl: {
					init: func(nd,symbol),
					predicate: func(nd) (nd.in_mode('toggle_display_mode', ['MAP','APP','VOR']) and nd.efis_switches['toggle_tacan'] != nil),
					is_true: func(nd) {
						if (nd.get_switch('toggle_tacan') and getprop("instrumentation/tacan/in-range")) {
							nd.symbols.TACANdmeDist.setText(sprintf("%3.1f",getprop("instrumentation/tacan/indicated-distance-nm")));
							nd.symbols.TACANdmeDist.show();
						} else {
							nd.symbols.TACANdmeDist.hide();
						}
					},
					is_false: func(nd) nd.symbols.TACANdmeDist.hide(),
				},
			},

		], # end of vector with features


	}, # end of Boeing style
		"Airbus" : {
			font_mapper: func(family, weight) {
				if( family == "Liberation Sans" and weight == "normal" )
						return "LiberationFonts/LiberationSans-Regular.ttf";
			},

			# where all the symbols are stored
			# TODO: SVG elements should be renamed to use boeing/airbus prefix
			# aircraft developers should all be editing the same ND.svg image
			# the code can deal with the differences now
			svg_filename: "Nasal/canvas/map/Airbus/Images/airbusND.svg",

		initialize_elements: func(me) {

		### this is the "old" method that's less flexible, we want to use the style hash instead (see above)
		# because things are much better configurable that way
		# now look up all required SVG elements and initialize member fields using the same name  to have a convenient handle
		foreach(var element; ["dmeLDist","dmeRDist","dmeL","dmeR","vorL","vorR","vorLId","vorRId",
		                      "status.wxr","status.wpt","status.sta","status.arpt"])
			me.symbols[element] = me.nd.getElementById(element);

		# load elements from vector image, and create instance variables using identical names, and call updateCenter() on each
		# anything that needs updatecenter called, should be added to the vector here
		#
		foreach(var element; ["staArrowL2","staArrowR2","staFromL2","staToL2","staFromR2","staToR2",
		                      "hdgTrk","trkInd","hdgBug","HdgBugCRT","TrkBugLCD","HdgBugLCD","curHdgPtr",
		                      "HdgBugCRT2","TrkBugLCD2","HdgBugLCD2","hdgBug2","selHdgLine","selHdgLine2","curHdgPtr2",
		                      "staArrowL","staArrowR","staToL","staFromL","staToR","staFromR"] )
			me.symbols[element] = me.nd.getElementById(element).updateCenter();

		}, # initialize_elements



			##
			## this loads and configures existing layers (currently, *.layer files in Nasal/canvas/map)
			##
			options: {
					position_callback: func(nd, pos){
						if(nd.get_switch('toggle_centered') or
						   nd.get_switch('toggle_display_mode') == 'PLAN')
								pos.range = (nd.rangeNm() * 1.6156087432822295);
					},
					translation_callback: func(nd){
						var t = {x: 512, y: 824};
						if(nd.get_switch('toggle_centered') or
						   nd.get_switch('toggle_display_mode') == 'PLAN')
								t.y = 512;
						return t;
					},
					defaults: {
						# Configurable Global Options:
						#       - fplan_active: the boolean property used to determine if the flight plan is active
						#       - lat_ctrl: the property used to determine if lateral flight mode is managed
						#               Lateral managed mode is similar to Boeing LNAV and indicates that the
						#               aircraft should follow the current active flight plan. By default
						#               the lat_ctrl property is checked against 'fmgc' (managed) value.
						#               You can use a custom value instead on 'fmgc' by overriding 'managed_val'
						#       - managed_val: the value that the property defined by 'lat_ctrl' should have in case
						#                       that the lateral flight mode is managed.
						# You can easily override these options before creating the ND, example:
						#       canvas.NDStyles['Airbus'].options.defaults.fplan_active = 'my/autpilot/f-plan/active'
						fplan_active: 'autopilot/route-manager/active',
						lat_ctrl: 'flight-management/control/lat-ctrl',
						managed_val: 'fmgc',
						ver_ctrl: 'flight-management/control/ver-ctrl',
						spd_ctrl: '/flight-management/control/spd-ctrl',
						current_wp: '/autopilot/route-manager/current-wp',
						ap1: '/flight-management/control/ap1-master',
						ap2: '/flight-management/control/ap2-master',
						nav1_frq: 'instrumentation/nav/frequencies/selected-mhz',
						nav2_frq: 'instrumentation/nav[1]/frequencies/selected-mhz',
						adf1_frq: 'instrumentation/adf/frequencies/selected-khz',
						adf2_frq: 'instrumentation/adf[1]/frequencies/selected-khz',
						dep_rwy: '/autopilot/route-manager/departure/runway',
						dest_rwy: '/autopilot/route-manager/destination/runway',
						wp_count: 'autopilot/route-manager/route/num',
						level_off_alt: '/autopilot/route-manager/vnav/level-off-alt',
						athr: '/flight-management/control/a-thrust',
						app_mode: 'instrumentation/nd/app-mode',
						chrono_node: 'instrumentation/chrono',
						active_route_color: [0.4,0.7,0.4],
						inactive_route_color: [0.95,0.95,0.21]
					},
					map: {
						"z-index" : -1
					}
			},
			layers: [
				# Should redraw every 10 seconds TODO: use new MapStructure/WXR here once that works properly (Gijs should check first!)
				{
					name:'WXR_live',
					isMapStructure:1,
					always_update: 1,
					update_on:[ 'toggle_range','toggle_weather','toggle_display_mode','toggle_weather_live'],
					predicate: func(nd, layer) {
						var visible=nd.get_switch('toggle_weather') and
									nd.get_switch('toggle_weather_live') and
									nd.get_switch('toggle_display_mode') != "PLAN";
						layer.group.setVisible(visible);
						if (visible) {
							layer.update();
						}
					}, # end of layer update predicate
					options: {
						viewport_radius: 706
					},
					'z-index': -100,
				},
				{
					name:'WXR',
					isMapStructure:1,
					update_on:[ {rate_hz: 0.1}, 'toggle_range','toggle_weather','toggle_display_mode', 'toggle_weather_live'],
					predicate: func(nd, layer) {
						#print("Running storms predicate");
						var visible=nd.get_switch('toggle_weather') and
									!nd.get_switch('toggle_weather_live') and
									nd.get_switch('toggle_display_mode') != "PLAN";
						layer.group.setVisible(visible);
						if (visible) {
							print("storms update requested! (timer issue when closing the dialog?)");
							layer.update();
						}
					}, # end of layer update predicate
					'z-index': -4,
				}, # end of storms/WXR layer
				{
					name:'FIX',
					isMapStructure:1,
					update_on:['toggle_waypoints','toggle_display_mode'],
					predicate: func(nd, layer) {
							var visible = nd.get_switch('toggle_waypoints') and
										  nd.in_mode('toggle_display_mode', ['MAP']) and
										  (nd.rangeNm() <= 40);
							layer.group.setVisible( visible );
							if (visible)
								layer.update();
					}, # end of layer update predicate
					style: {
						color: [0.69, 0, 0.39],
						text_offset: [20,10],
						text_color: [1,1,1]
					},
					options: {
						range_dependant: 1,
						draw_function: func(group){
							group.createChild('path')
								.moveTo(-10,0)
								.lineTo(0,-17)
								.lineTo(10,0)
								.lineTo(0,17)
								.close()
								.setStrokeLineWidth(3)
								.setColor(color)
								.setScale(1);
						}
					}
				}, # end of FIX layer
				{
					name: 'ALT-profile',
					isMapStructure: 1,
					update_on: ['toggle_display_mode','toggle_range',{rate_hz: 2}],
					predicate: func(nd, layer) {
						var visible = nd.in_mode('toggle_display_mode', ['MAP', 'PLAN']);# and nd.get_switch('toggle_fplan');
						layer.group.setVisible( visible );
						if (visible) {
								layer.update();
						}
					},
					style: {
						default_color: [1,1,1],
						armed_color: [0.06,0.55,1],
						managed_color: [0.68, 0, 0.38]
					},
					options: {
						# You can overwrite these with different nodes, before creating the ND
						# Example: canvas.NDStyles['Airbus'].layers['ALT-profile'].options.vnav_node = 'my/vnav/node';
						# In order to display ALT-profile on your ND you have to create the various
						# nodes corresponding to the different ALT pseudowaypoint in your aircraft code.
						# Every node must be set into the 'vnav_node' configured here (you can override it).
						# Example: if you want to display the top-of-descent symbol you must create a 'td'
						# node into vnav_node. Something like this:
						#       /autopilot/route-manager/vnav/td/
						# Each node should have the latitude-deg and longitude-deg properties.
						# Available nodes are:
						#       tc (top of climb)
						#       td (top of descent)
						#       ec (end of climb)
						#       ed (end of descent)
						#       sc (start of climb)
						#       sd (start of descent)
						# If ec and ed are altitude constraints, their node should have the
						# boolean 'alt-cstr' property set to 1.
						vnav_node: "/autopilot/route-manager/vnav/",
						types: ["tc", "td", "ec", "ed","sc","sd"],
						svg_path: {
							tc: 'Nasal/canvas/map/Airbus/Images/airbus_tc.svg',
							td: 'Nasal/canvas/map/Airbus/Images/airbus_td.svg',
							ec: 'Nasal/canvas/map/Airbus/Images/airbus_ec.svg',
							ed: 'Nasal/canvas/map/Airbus/Images/airbus_ed.svg',
							sc: 'Nasal/canvas/map/Airbus/Images/airbus_sc.svg',
							sd: 'Nasal/canvas/map/Airbus/Images/airbus_sd.svg'
						},
						listen: [
							'fplan_active',
							'ver_ctrl',
							'ap1',
							'ap2',
							'current_wp'
						],
						draw_callback: func(){
							var name = me.model.getName();
							var grp = me.element.getElementById(name~'_symbol');
							if(grp == nil) return;
							var dfcolor = me.getStyle('default_color');
							var armed_color = me.getStyle('armed_color');
							var managed_color = me.getStyle('managed_color');
							#print('Draw: -> ' ~ name);
							if(name == 'td' or name == 'sd' or name == 'sc'){
								var vnav_armed = me.model.getValue('vnav-armed');
								if(vnav_armed)
									grp.setColor(armed_color);
								else
									grp.setColor(dfcolor);
							}
							elsif(name == 'ed' or name == 'ec'){
								var is_cstr = me.model.getValue('alt-cstr');
								if(is_cstr)
									grp.setColor(managed_color);
								else
									grp.setColor(armed_color);
							}
						},
						init_after_callback: func{
							var name = me.model.getName();
							var grp = me.element.getElementById(name~'_symbol');
							if(name != 'td' and name != 'sd' and name != 'sc'){
								grp.setTranslation(-50,0);
							}
						}
					}
				},
				{
					name:'APT',
					isMapStructure:1,
					update_on:['toggle_airports','toggle_display_mode'],
					predicate: func(nd, layer) {
							var visible = nd.get_switch('toggle_airports') and
										  nd.in_mode('toggle_display_mode', ['MAP']);
							layer.group.setVisible( visible );
							if (visible) {
								layer.update();
							}
					}, # end of layer update predicate
					options: {
						range_dependant: 1,
					},
					style: {
						svg_path: 'Nasal/canvas/map/Airbus/Images/airbus_airport.svg',
						text_offset: [45, 35],
						label_font_color: [1,1,1],
						label_font_size: 28
					}
				}, # end of APT layer
				{
					name:'VOR-airbus',
					isMapStructure:1,
					update_on:['toggle_vor','toggle_display_mode'],
					# FIXME: this is a really ugly place for controller code
					predicate: func(nd, layer) {
						# print("Running vor layer predicate");
						# toggle visibility here
						var visible = nd.get_switch('toggle_vor') and
									  nd.in_mode('toggle_display_mode', ['MAP']) and
									  (nd.rangeNm() <= 40);
						layer.group.setVisible( visible );
						if (visible) {
							layer.update();
						}
					}, # end of layer update predicate
					# You can override default colors within the style
					# Default color: 'color'
					# Tuned color: 'tuned_color'
					# Example:
					#  canvas.NDStyles['Airbus'].layers['VOR-airbus'].style.color = [1,1,1];
					#  canvas.NDStyles['Airbus'].layers['VOR-airbus'].style.tuned_color = [0,0,1];
					style: {},
					options:{
						range_dependant: 1,
						listen: [
							'nav1_frq',
							'nav2_frq'
						],
					}
				}, # end of VOR layer
				{
					name:'DME',
					isMapStructure:1,
					disabled:1,
					update_on:['toggle_display_mode','toggle_dme'],
					# FIXME: this is a really ugly place for controller code
					predicate: func(nd, layer) {
						var visible = nd.get_switch('toggle_dme') and
									  nd.in_mode('toggle_display_mode', ['MAP']) and
									  (nd.rangeNm() <= 40);
						# toggle visibility here
						layer.group.setVisible( visible );
						if (visible) {
							#print("Updating MapStructure ND layer: DME");
							layer.update();
						}
					}, # end of layer update predicate
					options: {
						range_dependant: 1,
						draw_dme: func(sym){
							return sym.createChild("path")
								.moveTo(-13, 0)
								.arcSmallCW(13,13,0,26,0)
								.arcSmallCW(13,13,0,-26,0)
								.setStrokeLineWidth(2)
								.close();
						},
						draw_text: 1
					},
					style: {
						color_default: [0.9,0,0.47],
						color_tuned: [0,0.62,0.84],
					},
					'z-index': -2,
				}, # end of DME layer
				{
					name:'NDB',
					isMapStructure:1,
					update_on:['toggle_ndb','toggle_display_mode'],
					# FIXME: this is a really ugly place for controller code
					predicate: func(nd, layer) {
						var visible = nd.get_switch('toggle_ndb') and
									  nd.in_mode('toggle_display_mode', ['MAP']) and
									  (nd.rangeNm() <= 40);
						# print("Running vor layer predicate");
						# toggle visibility here
						layer.group.setVisible( visible );
						if (visible) {
							layer.update();
						}
					}, # end of layer update predicate
					# You can override default colors within the style
					# Default color: 'color'
					# Tuned color: 'tuned_color'
					# Example:
					#  canvas.NDStyles['Airbus'].layers['VOR-airbus'].style.color = [1,1,1];
					#  canvas.NDStyles['Airbus'].layers['VOR-airbus'].style.tuned_color = [0,0,1];
					style: {
						#svg_path: 'Nasal/canvas/map/Airbus/Images/airbus_ndb.svg'
						svg_path: ''
					},
					options: {
						range_dependant: 1,
						listen: [
							'adf1_frq',
							'adf2_frq'
						],
						init_after_callback: func{
							#me.element.removeAllChildren();
							me.text_ndb = me.element.createChild("text")
								.setDrawMode( canvas.Text.TEXT )
								.setText(me.model.id)
								.setFont("LiberationFonts/LiberationSans-Regular.ttf")
								.setFontSize(28)
								.setTranslation(25,10);
							me.ndb_sym = me.element.createChild('path');
							me.ndb_sym.moveTo(-15,15)
								.lineTo(0,-15)
								.lineTo(15,15)
								.close()
								.setStrokeLineWidth(3)
								.setColor(0.69,0,0.39)
								.setScale(1,1);
						},
						draw_callback: func{
							var frq = me.model.frequency;
							if(frq != nil){
								var dfcolor = me.getStyle('color', [0.9,0,0.47]);
								var tuned_color = me.getStyle('tuned_color', [0,0.62,0.84]);
								frq = frq / 100;
								var adf1_frq = getprop(me.options.adf1_frq);
								var adf2_frq = getprop(me.options.adf2_frq);
								if(adf1_frq == frq or adf2_frq == frq){
									me.element.setColor(tuned_color, [Path]);
								} else {
									me.element.setColor(dfcolor, [Path]);
								}
							}
						},
					}
				}, # end of NDB layer
				{
					name:'TFC',
					#disabled:1,
					always_update: 1,
					isMapStructure:1,
					update_on:['toggle_range','toggle_traffic'],
					predicate: func(nd, layer) {
						var visible = nd.get_switch('toggle_traffic');
						layer.group.setVisible( visible );
						if (visible) {
							#print("Updating MapStructure ND layer: TFC");
							layer.update();
						}
					}, # end of layer update predicate
				}, # end of traffic  layer
				{
					name:'RWY-profile',
					isMapStructure:1,
					update_on:['toggle_range','toggle_display_mode'],
					predicate: func(nd, layer) {
						var visible = (nd.rangeNm() <= 40) and
										nd.in_mode('toggle_display_mode', ['MAP','PLAN']) ;
						layer.group.setVisible( visible );
						if (visible) {
							layer.update();
						}
					}, # end of layer update predicate
					options: {
						listen: [
								'fplan_active',
								'dep_rwy',
								'dest_rwy'
						]
					}
				}, # end of runway layer
				{
					name:'HOLD',
					isMapStructure: 1,
					always_update: 1,
					update_on:['toggle_range','toggle_display_mode','toggle_wpt_idx'],
					predicate: func(nd, layer) {
						var visible= nd.in_mode('toggle_display_mode', ['MAP','PLAN']);
						layer.group.setVisible( visible );
						if (visible) {
							layer.update();
						}
					},
					options: {
						hold_node: '/flight-management/hold',
						hold_init: 'flight-management/hold/init',
						points_node: '/flight-management/hold/points',
						first_point_node: '/flight-management/hold/points/point/lat',
						hold_wp: '/flight-management/hold/wp',
						hold_wp_idx: '/flight-management/hold/wp_id',
						range_dependant: 1,
						listen: [
							'first_point_node',
							'fplan_active',
							'lat_ctrl',
							'current_wp',
							'hold_wp',
							'hold_init',
							'hold_wp_idx'
						]
					}
					# end of layer update predicate
				}, # end of HOLD layer
				{
					name:'RTE',
					isMapStructure: 1,
					update_on:['toggle_range','toggle_display_mode', 'toggle_cstr',
							   'toggle_wpt_idx'],
					predicate: func(nd, layer) {
						var visible= (nd.in_mode('toggle_display_mode', ['MAP','PLAN']));
						layer.group.setVisible( visible );
						if (visible) {
								layer.update();
						}
					}, # end of layer update predicate
					options: {
						display_inactive_rte: 1,
						listen: [
							'fplan_active',
							'lat_ctrl',
							'current_wp',
							'wp_count'
						],
						draw_after_callback: func{
							me.setRouteStyle();
						}
					},
					style: {
						line_width: 5,
						#inactive_color: [0.95,0.95,0.21],
						#active_color: [0.4,0.7,0.4],
						color: func{
							if(!contains(me, 'inactive_color')){
								me.inactive_color = me.getStyle('inactive_color');
								if(me.inactive_color == nil)
									me.inactive_color = me.getOption('inactive_route_color');
							}
							if(!contains(me, 'active_color')){
								me.active_color = me.getStyle('active_color');
								if(me.active_color == nil)
									me.active_color = me.getOption('active_route_color');
							}
							var is_active = getprop(me.options.fplan_active);
							(is_active ? me.active_color : me.inactive_color);
						},
						color_alternate_current: [0,0.62,0.84],
						color_missed: [0,0.62,0.84],
						color_temporary: func me.getStyle('inactive_color', me.getOption('inactive_route_color')),
						color_secondary: [1,1,1],
						color_alternate_secondary: [1,1,1],
						line_dash: func{
							var lat_ctrl = getprop(me.options.lat_ctrl);
							var is_managed = (lat_ctrl == me.options.managed_val);
							var is_active = getprop(me.options.fplan_active);
							(is_managed and is_active ? [] : [32, 16]);
						},
						line_dash_alternate_current: [32,16],
						line_dash_temporary: [32,16]
					}
				}, # end of route layer
			{
					name:'WPT-airbus',
					isMapStructure: 1,
					update_on:['toggle_range','toggle_display_mode', 'toggle_cstr',
							   'toggle_wpt_idx'],
					style: {
						wp_color: [0.4,0.7,0.4],
						current_wp_color: [1,1,1],
						constraint_color: [1,1,1],
						active_constraint_color: [0.69,0,0.39],
						missed_constraint_color: [1,0.57,0.14]
					},
					predicate: func(nd, layer) {
						var visible= (nd.in_mode('toggle_display_mode', ['MAP','PLAN']));
						layer.group.setVisible( visible );
						if (visible) {
							layer.toggle_cstr = nd.get_switch('toggle_cstr');
							layer.update();
						}
					}, # end of layer update predicate
					options: {
						listen: [
							'fplan_active',
							'lat_ctrl',
							'ver_ctrl',
							'current_wp',
							'wp_count',
							'dep_rwy',
							'dest_rwy',
							'level_off_alt'
						],
					}
				}, # end of WPT layer
				{
					name: 'SPD-profile',
					isMapStructure: 1,
					update_on: ['toggle_display_mode','toggle_range',{rate_hz: 2}],
					predicate: func(nd, layer) {
						var visible = nd.in_mode('toggle_display_mode', ['MAP', 'PLAN']);
						layer.group.setVisible( visible );
						if (visible) {
								layer.update();
						}
					},
					style: {
						color: [0.69,0,0.39]
					},
					options: {
						spd_node: "/autopilot/route-manager/spd/",
						listen: [
								'fplan_active'
						]
					}
				},
				{
					name: 'DECEL',
					isMapStructure: 1,
					update_on: ['toggle_display_mode','toggle_range'],
					predicate: func(nd, layer) {
						var visible = nd.in_mode('toggle_display_mode', ['MAP', 'PLAN']);
						layer.group.setVisible( visible );
						if (visible) {
							layer.update();
						}
					},
					options: {
						# Overridable options:
						# decel_node: node containing latitude-deg and longitude-deg used to mark the deceleration point
						# managed_speed_node: boolean property indicating that the aircraft is flying in managed speed mode
						listen: [
							'fplan_active',
							'spd_ctrl',
							'ver_ctrl',
							'athr'
						]
					},
					style: {
						# managed_color: decelaration symbol color when the aircraft flies in managed speed mode
						# selected_color: decelaration symbol color when the aircraft flies in selected speed mode
						managed_color: [0.68, 0, 0.38],
						selected_color: [1,1,1]
					}
				},
				{
					name:'APS',
					isMapStructure:1,
					always_update: 1,
					update_on:['toggle_display_mode'],
					predicate: func(nd, layer) {
						 var visible = nd.get_switch('toggle_display_mode') == "PLAN";
						 layer.group.setVisible( visible );
						 if (visible) {
							layer.update();
						 }
					},
					style: {
						svg_path: 'Nasal/canvas/map/Airbus/Images/airbusAirplane.svg',
						#translate: [-45,-52]
					},
					options: {
						model: {
							parents: [geo.Coord],
							id: 999999,
							pos: props.globals.getNode('position'),
							type: 'position',
							latlon: func(){
								me.pos = props.globals.getNode('position');
								return [
									me.pos.getValue("latitude-deg"),
									me.pos.getValue("longitude-deg"),
									me.pos.getValue("altitude-ft")
								];
							},
							equals: func(o){me.id == o.id}
						},
						init_after_callback: func{
							var aplSymbol = me.element.getElementById("airplane");
							aplSymbol.setTranslation(-45,-52);
						}
					}
				},
				# end of storms/WXR layer
				## add other layers here, layer names must match the registered names as used in *.layer files for now
				## this will all change once we're using Philosopher's MapStructure framework

			], # end of vector with configured layers

			# This is where SVG elements are configured by providing "behavior" hashes, i.e. for animations

			# to animate each SVG symbol, specify behavior via callbacks (predicate, and true/false implementation)
			# SVG identifier, callback      etc
			# TODO: update_on([]), update_mode (update() vs. timers/listeners)
			# TODO: support putting symbols on specific layers
			features: [
				{
					id: 'compass_mask',
					impl: {
						init: func(nd, symbol),
						predicate: func(nd) !nd.get_switch('toggle_centered'),
						is_true: func(nd) nd.symbols.compass_mask.show(),
						is_false: func(nd) nd.symbols.compass_mask.hide(),
					}
				},
				{
					id: 'compass_mask_ctr',
					impl: {
						init: func(nd, symbol),
						predicate: func(nd) nd.get_switch('toggle_centered') or nd.in_mode('toggle_display_mode',['PLAN']),
						is_true: func(nd) nd.symbols.compass_mask_ctr.show(),
						is_false: func(nd) nd.symbols.compass_mask_ctr.hide(),
					}
				},
				{
					# TODO: taOnly doesn't need to use getprop polling in update(), use a listener instead!
					id: 'taOnly', # the SVG ID
					impl: { # implementation hash
						init: func(nd, symbol), # for updateCenter stuff, called during initialization in the ctor
						predicate: func(nd) getprop("instrumentation/tcas/inputs/mode") == 2, # the condition
						is_true:   func(nd) nd.symbols.taOnly.show(),                   # if true, run this
						is_false:  func(nd) nd.symbols.taOnly.hide(),                   # if false, run this
					}, # end of taOnly      behavior/callbacks
				}, # end of taOnly
				{
					id: 'tas',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) nd.aircraft_source.get_spd() > 100,
						is_true: func(nd) {
							nd.symbols.tas.setText(sprintf("%3.0f",getprop("/velocities/airspeed-kt") ));
							nd.symbols.tas.show();
						},
						is_false: func(nd) nd.symbols.tas.hide(),
					},
				},
				{
					id: 'tasLbl',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) nd.aircraft_source.get_spd() > 100,
						is_true: func(nd) nd.symbols.tasLbl.show(),
						is_false: func(nd) nd.symbols.tasLbl.hide(),
					},
				},
				{
					id: 'ilsFreq',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP', 'VOR']),
						is_true: func(nd) {
							nd.symbols.ilsFreq.show();
							nd.symbols.ilsFreq.setText(getprop("instrumentation/nav/frequencies/selected-mhz-fmt"));
							if(nd.get_switch('toggle_display_mode') == 'APP')
								nd.symbols.ilsFreq.setColor(0.69,0,0.39);
							else
								nd.symbols.ilsFreq.setColor(1,1,1);
						},
						is_false: func(nd) nd.symbols.ilsFreq.hide(),
					},
				},
				{
					id: 'ilsLbl',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP', 'VOR']),
						is_true: func(nd) {
							nd.symbols.ilsLbl.show();
							if(nd.get_switch('toggle_display_mode') == 'APP')
								nd.symbols.ilsLbl.setText('ILS');
							else
								nd.symbols.ilsLbl.setText('VOR 1');
						},
						is_false: func(nd) nd.symbols.ilsLbl.hide(),
					},
				},
				{
						id: 'wpActiveId',
						impl: {
							init: func(nd,symbol),
							predicate: func(nd) getprop("/autopilot/route-manager/wp/id") != nil and
											getprop("autopilot/route-manager/active") and
											nd.in_mode('toggle_display_mode', ['MAP', 'PLAN']),
							is_true: func(nd) {
								nd.symbols.wpActiveId.setText(getprop("/autopilot/route-manager/wp/id"));
								nd.symbols.wpActiveId.show();
							},
							is_false: func(nd) nd.symbols.wpActiveId.hide(),
						}, # of wpActiveId.impl
				}, # of wpActiveId
				{
						id: 'wpActiveCrs',
						impl: {
							init: func(nd,symbol),
							predicate: func(nd) getprop("/autopilot/route-manager/wp/id") != nil and
											getprop("autopilot/route-manager/active") and
											nd.in_mode('toggle_display_mode', ['MAP', 'PLAN']),
							is_true: func(nd) {
								#var cur_wp = getprop("autopilot/route-manager/current-wp");
								var deg = int(getprop("/autopilot/route-manager/wp/bearing-deg"));
								nd.symbols.wpActiveCrs.setText(''~deg~'°');
								nd.symbols.wpActiveCrs.show();
							},
							is_false: func(nd) nd.symbols.wpActiveCrs.hide(),
						}, # of wpActiveId.impl
				}, # of wpActiveId
				{
					id: 'wpActiveDist',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) getprop("/autopilot/route-manager/wp/dist") != nil and
										getprop("autopilot/route-manager/active") and
										nd.in_mode('toggle_display_mode', ['MAP', 'PLAN']),
						is_true: func(nd) {
							var dst = getprop("/autopilot/route-manager/wp/dist");
							nd.symbols.wpActiveDist.setText(sprintf("%3.01f",dst));
							nd.symbols.wpActiveDist.show();
						},
						is_false: func(nd) nd.symbols.wpActiveDist.hide(),
					},
				},
				{
					id: 'wpActiveDistLbl',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) getprop("/autopilot/route-manager/wp/dist") != nil and getprop("autopilot/route-manager/active")  and nd.in_mode('toggle_display_mode', ['MAP', 'PLAN']),
						is_true: func(nd) {
								nd.symbols.wpActiveDistLbl.show();
								if(getprop("/autopilot/route-manager/wp/dist") > 1000)
										nd.symbols.wpActiveDistLbl.setText("   NM");
						},
						is_false: func(nd) nd.symbols.wpActiveDistLbl.hide(),
					},
				},
				{
					id: 'eta',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) getprop("autopilot/route-manager/wp/eta") != nil and getprop("autopilot/route-manager/active")      and nd.in_mode('toggle_display_mode', ['MAP', 'PLAN']),
						is_true: func(nd) {
							var etaSec = getprop("/sim/time/utc/day-seconds")+
									getprop("autopilot/route-manager/wp/eta-seconds");
							var h = math.floor(etaSec/3600);
							etaSec = etaSec-3600*h;
							var m = math.floor(etaSec/60);
							etaSec = etaSec-60*m;
							var s = etaSec / 10;
							if (h > 24) h = h - 24;
							nd.symbols.eta.setText(sprintf("%02.0f:%02.0f",h,m));
							nd.symbols.eta.show();
						},
						is_false: func(nd) nd.symbols.eta.hide(),
					},      # of eta.impl
				}, # of eta
				{
					id: 'gsGroup',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP']),
						is_true: func(nd) {
							if(nd.get_switch('toggle_centered'))
								nd.symbols.gsGroup.setTranslation(0,0);
							else
								nd.symbols.gsGroup.setTranslation(0,150);
							nd.symbols.gsGroup.show();
						},
						is_false: func(nd) nd.symbols.gsGroup.hide(),
					},
				},
				{
					id:'hdg',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP','MAP','VOR']),
						is_true: func(nd) {
							var hdgText = "";
							if(nd.in_mode('toggle_display_mode', ['MAP'])) {
								if(nd.get_switch('toggle_true_north'))
									hdgText = nd.aircraft_source.get_trk_tru();
								else
									hdgText = nd.aircraft_source.get_trk_mag();
							} else {
								if(nd.get_switch('toggle_true_north'))
									hdgText = nd.aircraft_source.get_hdg_tru();
								else
									hdgText = nd.aircraft_source.get_hdg_mag();
							}
							nd.symbols.hdg.setText(sprintf("%03.0f", hdgText+0.5));
						},
						is_false: NOTHING,
					},
				},
				{
					id:'hdgGroup',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) {return 0},#nd.in_mode('toggle_display_mode', ['APP','MAP','VOR']),
						is_true: func(nd) {
							nd.symbols.hdgGroup.show();
							if(nd.get_switch('toggle_centered'))
								nd.symbols.hdgGroup.setTranslation(0,100);
							else
								nd.symbols.hdgGroup.setTranslation(0,0);
						},
						is_false: func(nd) nd.symbols.hdgGroup.hide(),
					},
				},
				{
					id:'altArc',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) {return 0},#nd.in_mode('toggle_display_mode', ['APP','MAP','VOR']),
						is_true: func(nd) {
							nd.symbols.altArc.show();
						},
						is_false: func(nd) nd.symbols.altArc.hide(),
					},
				},
				{
					id:'gs',
					impl: {
						init: func(nd,symbol),
						common: func(nd) nd.symbols.gs.setText(sprintf("%3.0f",nd.aircraft_source.get_gnd_spd() )),
						predicate: func(nd) nd.aircraft_source.get_gnd_spd() >= 30,
						is_true: func(nd) {
							#nd.symbols.gs.show();
							nd.symbols.gs.setFontSize(36);
						},
						is_false: func(nd) {},#nd.symbols.gs.hide(),
					},
				},
				{
					id:'compass',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) (!nd.get_switch('toggle_centered') and      nd.get_switch('toggle_display_mode') != "PLAN"),
						is_true: func(nd) {
							nd.symbols.compass.setRotation(-nd.userHdgTrk*D2R);
							nd.symbols.compass.show()
						},
						is_false: func(nd) nd.symbols.compass.hide(),
					}, # of compass.impl
				}, # of compass
				{
					id:'compassApp',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) (nd.get_switch('toggle_centered') and  nd.get_switch('toggle_display_mode') != "PLAN"),
						is_true: func(nd) {
							nd.symbols.compassApp.setRotation(-nd.userHdgTrk*D2R);
							nd.symbols.compassApp.show()
						},
						is_false: func(nd) nd.symbols.compassApp.hide(),
					}, # of compassApp.impl
				}, # of compassApp
				{
					id:'northUp',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) nd.get_switch('toggle_display_mode') == "PLAN",
						is_true: func(nd) nd.symbols.northUp.show(),
						is_false: func(nd) nd.symbols.northUp.hide(),
					}, # of northUp.impl
				}, # of northUp
				{
					id:'planArcs',
					impl: {
					init: func(nd,symbol),
						predicate: func(nd) ((nd.in_mode('toggle_display_mode', ['APP','VOR','PLAN'])) or ((nd.get_switch('toggle_display_mode') == "MAP") and (nd.get_switch('toggle_centered')))),
						is_true: func(nd) nd.symbols.planArcs.show(),
						is_false: func(nd) nd.symbols.planArcs.hide(),
					}, # of planArcs.impl
				}, # of planArcs
				{
					id:'rangeArcs',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) ((nd.get_switch('toggle_display_mode') == "MAP") and (!nd.get_switch('toggle_centered'))),
						is_true: func(nd) nd.symbols.rangeArcs.show(),
						is_false: func(nd) nd.symbols.rangeArcs.hide(),
					}, # of rangeArcs.impl
				}, # of rangeArcs
				{
					id:'rangePln1',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) {return 0},
						is_true: func(nd) {
							nd.symbols.rangePln1.show();
							nd.symbols.rangePln1.setText(sprintf("%3.0f",nd.rangeNm()));
						},
						is_false: func(nd) nd.symbols.rangePln1.hide(),
					},
				},
				{
					id:'rangePln2',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) nd.get_switch('toggle_display_mode') == "MAP" and !nd.get_switch('toggle_centered'),
						is_true: func(nd) {
							nd.symbols.rangePln2.show();
							nd.symbols.rangePln2.setText(sprintf("%3.0f",(nd.rangeNm()/2) + (nd.rangeNm()/4)));
						},
						is_false: func(nd) nd.symbols.rangePln2.hide(),
					},
				},
				{
					id:'rangePln3',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) nd.get_switch('toggle_display_mode') == "PLAN" or nd.get_switch('toggle_centered'),
						is_true: func(nd) {
							nd.symbols.rangePln3.show();
							nd.symbols.rangePln3.setText(sprintf("%3.0f",nd.rangeNm()/2));
						},
						is_false: func(nd) nd.symbols.rangePln3.hide(),
					},
				},
				{
					id:'rangePln4',
					impl: {
							init: func(nd,symbol),
							predicate: func(nd) nd.get_switch('toggle_display_mode') == "PLAN" or nd.get_switch('toggle_centered'),
							is_true: func(nd) {
								nd.symbols.rangePln4.show();
								nd.symbols.rangePln4.setText(sprintf("%3.0f",nd.rangeNm()));
							},
							is_false: func(nd) nd.symbols.rangePln4.hide(),
					},
				},
				{
					id:'rangePln5',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) nd.get_switch('toggle_display_mode') == "MAP" and !nd.get_switch('toggle_centered'),
						is_true: func(nd) {
							nd.symbols.rangePln5.show();
							nd.symbols.rangePln5.setText(sprintf("%3.0f",(nd.rangeNm()/2) + (nd.rangeNm()/4)));
						},
						is_false: func(nd) nd.symbols.rangePln5.hide(),
					},
				},
				{
					id:'range',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) !nd.get_switch('toggle_centered'),
						is_true: func(nd) {
							nd.symbols.range.show();
							nd.symbols.range.setText(sprintf("%3.0f",nd.rangeNm()/2));
						},
						is_false: func(nd) nd.symbols.range.hide(),
					},
				},
				{
					id:'range_r',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) !nd.get_switch('toggle_centered'),
						is_true: func(nd) {
							nd.symbols.range_r.show();
							nd.symbols.range_r.setText(sprintf("%3.0f",nd.rangeNm()/2));
						},
						is_false: func(nd) nd.symbols.range_r.hide(),
					},
				},
				{
					id:'aplSymMap',
					impl: {
					init: func(nd,symbol),
						predicate: func(nd) (nd.get_switch('toggle_display_mode') == "MAP" and !nd.get_switch('toggle_centered')),
						is_true: func(nd) {
							nd.symbols.aplSymMap.set('z-index', 10);
							nd.symbols.aplSymMap.show();

						},
						is_false: func(nd) nd.symbols.aplSymMap.hide(),
					},
				},
				{
					id:'aplSymMapCtr',
					impl: {
					init: func(nd,symbol),
						predicate: func(nd) ((nd.get_switch('toggle_display_mode') == "MAP" and nd.get_switch('toggle_centered')) or nd.in_mode('toggle_display_mode', ['APP','VOR'])),
						is_true: func(nd) {
							nd.symbols.aplSymMapCtr.set('z-index', 10);
							nd.symbols.aplSymMapCtr.show();

						},
						is_false: func(nd) nd.symbols.aplSymMapCtr.hide(),
					},
				},
				{
					id:'aplSymVor',
					impl: {
					init: func(nd,symbol),
							predicate: func(nd) {return 0;},
							is_true: func(nd) {
								nd.symbols.aplSymVor.show();
							},
							is_false: func(nd) nd.symbols.aplSymVor.hide(),
					},
				},
				{
					id:'crsLbl',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP','VOR']),
						is_true: func(nd) nd.symbols.crsLbl.show(),
						is_false: func(nd) nd.symbols.crsLbl.hide(),
					},
				},
				{
					id:'crs',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP','VOR']),
						is_true: func(nd) {
							nd.symbols.crs.show();
							if(getprop("instrumentation/nav/radials/selected-deg") != nil)
								nd.symbols.crs.setText(sprintf("%03.0f",getprop("instrumentation/nav/radials/selected-deg")));
						},
						is_false: func(nd) nd.symbols.crs.hide(),
					},
				},
				{
					id:'dmeLbl',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP','VOR']),
						is_true: func(nd) nd.symbols.dmeLbl.show(),
						is_false: func(nd) nd.symbols.dmeLbl.hide(),
					},
				},
				{
					id:'dme',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP','VOR']),
						is_true: func(nd) {
							nd.symbols.dme.show();
							nd.symbols.dme.setText(getprop("instrumentation/nav/nav-id"));
							if(nd.get_switch('toggle_display_mode') == 'APP')
								nd.symbols.dme.setColor(0.69,0,0.39);
							else
								nd.symbols.dme.setColor(1,1,1);
						},
						is_false: func(nd) nd.symbols.dme.hide(),
					},
				},
				{
					id:'trkline',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd){
							nd.get_switch('toggle_display_mode') == 'MAP' and
							!nd.get_switch('toggle_centered') and
							(
								getprop(nd.options.defaults.lat_ctrl) != nd.options.defaults.managed_val or
								nd.get_switch('toggle_trk_line')
							)
						},
						is_true: func(nd) {
							nd.symbols.trkline.show();
						},
						is_false: func(nd) nd.symbols.trkline.hide(),
					},
				},
				{
					id:'trkInd2',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) (nd.in_mode('toggle_display_mode', ['APP','VOR','MAP']) and
										 nd.get_switch('toggle_centered')),
						is_true: func(nd) {
							nd.symbols.trkInd2.show();
							nd.symbols.trkInd2.setRotation((nd.aircraft_source.get_trk_mag()-nd.aircraft_source.get_hdg_mag())*D2R);
						},
						is_false: func(nd) nd.symbols.trkInd2.hide(),
					},
				},
				{
					id:'trkline2',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) (nd.get_switch('toggle_display_mode') == 'MAP' and
												 nd.get_switch('toggle_centered') and
												 getprop(nd.options.defaults.lat_ctrl) != nd.options.defaults.managed_val),
						is_true: func(nd) {
							nd.symbols.trkline2.show();
						},
						is_false: func(nd) nd.symbols.trkline2.hide(),
					},
				},
				{
					id:'vorCrsPtr',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) (nd.in_mode('toggle_display_mode', ['APP','VOR']) and !nd.get_switch('toggle_centered')),
						is_true: func(nd) {
								nd.symbols.vorCrsPtr.show();
								nd.symbols.vorCrsPtr.setRotation((getprop("instrumentation/nav/radials/selected-deg")-nd.aircraft_source.get_hdg_tru())*D2R);

						},
						is_false: func(nd) nd.symbols.vorCrsPtr.hide(),
					},
				},
				{
					id:'vorCrsPtr2',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) (nd.in_mode('toggle_display_mode', ['APP','VOR']) and nd.get_switch('toggle_centered')),
						is_true: func(nd) {
								nd.symbols.vorCrsPtr2.show();
								nd.symbols.vorCrsPtr2.setRotation((getprop("instrumentation/nav/radials/selected-deg")-nd.aircraft_source.get_hdg_tru())*D2R);
								var line = nd.symbols.vorCrsPtr2.getElementById('vorCrsPtr2_line');
								if(nd.get_switch('toggle_display_mode') == 'VOR'){
									line.setColor(0,0.62,0.84);
									line.setColorFill(0,0.62,0.84);
								} else {
									line.setColor(0.9,0,0.47);
									line.setColorFill(0.9,0,0.47);
								}
						},
						is_false: func(nd) nd.symbols.vorCrsPtr2.hide(),
					},
				},
				{
					id: 'gsDiamond',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP']),
						is_true: func(nd) {
							if(getprop("instrumentation/nav/gs-needle-deflection-norm") != nil)
								nd.symbols.gsDiamond.setTranslation(getprop("instrumentation/nav/gs-needle-deflection-norm")*150,0);
						},
						is_false: func(nd) nd.symbols.gsGroup.hide(),
					},
				},
				{
					id:'locPtr',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) (nd.in_mode('toggle_display_mode', ['APP','VOR']) and !nd.get_switch('toggle_centered') and getprop("instrumentation/nav/in-range")),
						is_true: func(nd) {
							nd.symbols.locPtr.show();
							var deflection = getprop("instrumentation/nav/heading-needle-deflection-norm");
							nd.symbols.locPtr.setTranslation(deflection*150,0);
						},
						is_false: func(nd) nd.symbols.locPtr.hide(),
					},
				},
				{
					id:'locPtr2',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) (nd.in_mode('toggle_display_mode', ['APP','VOR']) and nd.get_switch('toggle_centered') and getprop("instrumentation/nav/in-range")),
						is_true: func(nd) {
							var curmode = nd.get_switch('toggle_display_mode');
							var ils_mode = getprop('/flight-management/freq/ils-mode');
							if((ils_mode and curmode == 'VOR') or (!ils_mode and curmode == 'APP')){
								nd.symbols.locPtr2.hide();
								return;
							}
							nd.symbols.locPtr2.show();
							var deflection = getprop("instrumentation/nav/heading-needle-deflection-norm");
							nd.symbols.locPtr2.setTranslation(deflection*150,0);
							var line = nd.symbols.locPtr2.getElementById('locPtr2_line');
							var arr1 = nd.symbols.locPtr2.getElementById('locPtr2_arr1');
							var arr2 = nd.symbols.locPtr2.getElementById('locPtr2_arr2');
							if(curmode == 'VOR'){
								#nd.symbols.vorCrsPtr2.setColor(0,0.62,0.84);
								line.setColor(0,0.62,0.84);
								line.setColorFill(0,0.62,0.84);
								arr1.show();
								arr2.show();
							} else {
								line.setColor(0.9,0,0.47);
								line.setColorFill(0.9,0,0.47);
								arr1.hide();
								arr2.hide();
							}
						},
						is_false: func(nd) nd.symbols.locPtr2.hide(),
					},
				},
				{
					id:'wind',
					impl: {
						init: func(nd,symbol),
						predicate: ALWAYS,
						is_true: func(nd) {
							var windDir = getprop("environment/wind-from-heading-deg");
							if(!nd.get_switch('toggle_true_north'))
									windDir = windDir + getprop("environment/magnetic-variation-deg");
							nd.symbols.wind.setText(sprintf("%03.0f / %02.0f",windDir,getprop("environment/wind-speed-kt")));
						},
						is_false: NOTHING,
					},
				},
				{
					id:'windArrow',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) (!(nd.in_mode('toggle_display_mode', ['PLAN']) and (nd.get_switch('toggle_display_type') == "LCD"))),
						is_true: func(nd) {
							nd.symbols.windArrow.show();
							var windArrowRot = getprop("environment/wind-from-heading-deg") - getprop("environment/magnetic-variation-deg");
							if(nd.in_mode('toggle_display_mode', ['MAP','PLAN'])) {
								if(nd.get_switch('toggle_true_north'))
									windArrowRot = windArrowRot - nd.aircraft_source.get_trk_tru();
								else
									windArrowRot = windArrowRot - nd.aircraft_source.get_trk_mag();
							} else {
								if(nd.get_switch('toggle_true_north'))
									windArrowRot = windArrowRot - nd.aircraft_source.get_hdg_tru();
								else
									windArrowRot = windArrowRot - nd.aircraft_source.get_hdg_mag();
							}
							nd.symbols.windArrow.setRotation(windArrowRot*D2R);
						},
						is_false: func(nd) nd.symbols.windArrow.hide(),
					},
				},
				{
					id:'staToL2',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) !(nd.in_mode('toggle_display_mode', ['PLAN'])) and nd.get_switch('toggle_centered')  and ((getprop("instrumentation/nav/in-range") and nd.get_switch('toggle_lh_vor_adf') == 1) or (getprop("instrumentation/adf/in-range") and nd.get_switch('toggle_lh_vor_adf') == -1)),
						is_true: func(nd) {
							if(nd.get_switch('toggle_lh_vor_adf') < 0){
								nd.symbols.staToL2.setColor(0.195,0.96,0.097);
								nd.symbols.staFromL2.setColor(0.195,0.96,0.097);
							} else {
								nd.symbols.staToL2.setColor(1,1,1);
								nd.symbols.staFromL2.setColor(1,1,1);
							}
							nd.symbols.staToL2.show();
							nd.symbols.staFromL2.show();
						},
						is_false: func(nd){
							nd.symbols.staToL2.hide();
							nd.symbols.staFromL2.hide();
						}
					}
				},
				{
					id:'staToR2',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) !(nd.in_mode('toggle_display_mode', ['PLAN'])) and nd.get_switch('toggle_centered') and ((getprop("instrumentation/nav[1]/in-range") and nd.get_switch('toggle_rh_vor_adf') == 1) or (getprop("instrumentation/adf[1]/in-range") and nd.get_switch('toggle_rh_vor_adf') == -1)),
						is_true: func(nd) {
							if(nd.get_switch('toggle_rh_vor_adf') < 0){
								nd.symbols.staToR2.setColor(0.195,0.96,0.097);
								nd.symbols.staFromR2.setColor(0.195,0.96,0.097);
							} else {
								nd.symbols.staToR2.setColor(1,1,1);
								nd.symbols.staFromR2.setColor(1,1,1);
							}
							nd.symbols.staToR2.show();
							nd.symbols.staFromR2.show();
						},
						is_false: func(nd){
							nd.symbols.staToR2.hide();
							nd.symbols.staFromR2.hide();
						}
					}
				},
				{
				id:'staToL',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) nd.in_mode('toggle_display_mode', ['MAP']) and !nd.get_switch('toggle_centered') and ((getprop("instrumentation/nav/in-range") and nd.get_switch('toggle_lh_vor_adf') == 1) or (getprop("instrumentation/adf/in-range") and nd.get_switch('toggle_lh_vor_adf') == -1)),
						is_true: func(nd) {
							if(nd.get_switch('toggle_lh_vor_adf') < 0){
								nd.symbols.staToL.setColor(0.195,0.96,0.097);
								nd.symbols.staFromL.setColor(0.195,0.96,0.097);
							} else {
								nd.symbols.staToL.setColor(1,1,1);
								nd.symbols.staFromL.setColor(1,1,1);
							}
							nd.symbols.staToL.show();
							nd.symbols.staFromL.show();
						},
						is_false: func(nd){
							nd.symbols.staToL.hide();
							nd.symbols.staFromL.hide();
						}
					}
				},
				{
					id:'staToR',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) nd.in_mode('toggle_display_mode', ['MAP']) and !nd.get_switch('toggle_centered') and ((getprop("instrumentation/nav[1]/in-range") and nd.get_switch('toggle_rh_vor_adf') == 1) or (getprop("instrumentation/adf[1]/in-range") and nd.get_switch('toggle_rh_vor_adf') == -1)),
						is_true: func(nd) {
							if(nd.get_switch('toggle_rh_vor_adf') < 0){
								nd.symbols.staToR.setColor(0.195,0.96,0.097);
								nd.symbols.staFromR.setColor(0.195,0.96,0.097);
							} else {
								nd.symbols.staToR.setColor(1,1,1);
								nd.symbols.staFromR.setColor(1,1,1);
							}
							nd.symbols.staToR.show();
							nd.symbols.staFromR.show();
						},
						is_false: func(nd){
							nd.symbols.staToR.hide();
							nd.symbols.staFromR.hide();
						}
					}
				},
				{
						id:'dmeL',
						impl: {
							init: func(nd,symbol),
							predicate: func(nd) (nd.get_switch('toggle_lh_vor_adf') != 0),
							is_true: func(nd) {
								nd.symbols.dmeL.show();
								if(nd.get_switch('toggle_lh_vor_adf') < 0){
									nd.symbols.vorL.setText("ADF 1");
									nd.symbols.vorL.setColor(0.195,0.96,0.097);
									nd.symbols.vorLId.setColor(0.195,0.96,0.097);
									nd.symbols.dmeLDist.setColor(0.195,0.96,0.097);
								}
								else{
									nd.symbols.vorL.setText("VOR 1");
									nd.symbols.vorL.setColor(1,1,1);
									nd.symbols.vorLId.setColor(1,1,1);
									nd.symbols.dmeLDist.setColor(1,1,1);
								}
								nd.symbols.dmeL.setText('NM');
								nd.symbols.dmeL.setColor(0,0.59,0.8);
							},
							is_false: func(nd){
								nd.symbols.dmeL.hide();
							}
					}
				},
				{
						id:'dmeR',
						impl: {
							init: func(nd,symbol),
							predicate: func(nd) (nd.get_switch('toggle_rh_vor_adf') != 0),
							is_true: func(nd) {
								nd.symbols.dmeR.show();
								if(nd.get_switch('toggle_rh_vor_adf') < 0){
									nd.symbols.vorR.setText("ADF 2");
									nd.symbols.vorR.setColor(0.195,0.96,0.097);
									nd.symbols.vorRId.setColor(0.195,0.96,0.097);
									nd.symbols.dmeRDist.setColor(0.195,0.96,0.097);
								} else {
									nd.symbols.vorR.setText("VOR 2");
									nd.symbols.vorR.setColor(1,1,1);
									nd.symbols.vorRId.setColor(1,1,1);
									nd.symbols.dmeRDist.setColor(1,1,1);
								}
								nd.symbols.dmeR.setText('NM');
								nd.symbols.dmeR.setColor(0,0.59,0.8);
							},
							is_false: func(nd){
								nd.symbols.dmeR.hide();
							}
					}
				},
				{
					id: 'vorL',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) (nd.get_switch('toggle_lh_vor_adf') != 0),
						is_true: func(nd) {
							nd.symbols.vorL.show();
							nd.symbols.vorLId.show();
							nd.symbols.dmeLDist.show();
							if(nd.get_switch('toggle_rh_vor_adf') < 0){
								var adf = 'instrumentation/adf/';
								var navident = getprop(adf~ "ident");
								var frq = getprop(adf~ "frequencies/selected-khz");
								if(navident != "")
									nd.symbols.vorLId.setText(navident);
								else
									nd.symbols.vorLId.setText(sprintf("%3d", frq));
								nd.symbols.dmeLDist.setText("");
							} else {
								var nav = 'instrumentation/nav/';
								var navID = getprop(nav~"nav-id");
								var frq = getprop(nav~"frequencies/selected-mhz-fmt");
								var dme = 'instrumentation/dme/';
								var dst = getprop(dme~ "indicated-distance-nm");
								if(getprop("instrumentation/nav/in-range"))
									nd.symbols.vorLId.setText(navID);
								else
									nd.symbols.vorLId.setText(frq);
								if(getprop("instrumentation/dme/in-range"))
									nd.symbols.dmeLDist.setText(sprintf("%3.1f",dst));
								else nd.symbols.dmeLDist.setText(" ---");
							}
						},
						is_false: func(nd){
							nd.symbols.vorL.hide();
							nd.symbols.vorLId.hide();
							nd.symbols.dmeLDist.hide();
						}
					}
				},
				{
					id:'vorLSym',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) (nd.get_switch('toggle_lh_vor_adf') != 0),
						is_true: func(nd) {
							nd.symbols.vorLSym.show();
						},
						is_false: func(nd){
							nd.symbols.vorLSym.hide();
						}
					}
				},
				{
					id:'vorRSym',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) (nd.get_switch('toggle_rh_vor_adf') != 0),
						is_true: func(nd) {
							nd.symbols.vorRSym.show();
						},
						is_false: func(nd){
							nd.symbols.vorRSym.hide();
						}
					}
				},
				{
					id:'appMode',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) {
							var mode = getprop(nd.options.defaults.app_mode);
							return (mode != '' and mode != nil);
						},
						is_true: func(nd) {
							var mode = getprop(nd.options.defaults.app_mode);
							nd.symbols.appMode.show();
							nd.symbols.appMode.setText(mode);
						},
						is_false: func(nd){
							nd.symbols.appMode.hide();
						}
					}
				},
				{
					id:'chrono_box',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) nd.get_switch('toggle_chrono'),
						is_true: func(nd) {
							var efis_node = props.globals.getNode(nd.efis_path);
							var idx = efis_node.getIndex() or 0;
							var chronoNode = nd.options.defaults.chrono_node~'['~idx~']';
							chronoNode = props.globals.getNode(chronoNode);
							var time = nil;
							if(chronoNode != nil){
								time = chronoNode.getValue('text');
							}
							nd.symbols.chrono_box.show();
							if(time != nil and time != '')
								nd.symbols.chrono_text.setText(time);
						},
						is_false: func(nd){
							nd.symbols.chrono_box.hide();
						}
					}
				},
				{
					id:'chrono_text',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) 1,
						is_true: func(nd) nd.symbols.chrono_text.show(),
						is_false: func(nd) nd.symbols.chrono_text.hide(),
					}
				},
				{
					id:'degreeArrows',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) (nd.get_switch('toggle_display_mode') != 'PLAN' and nd.get_switch('toggle_centered')),
						is_true: func(nd) {
							nd.symbols.degreeArrows.show();
						},
						is_false: func(nd){
							nd.symbols.degreeArrows.hide();
						}
					}
				},
				{
					id: 'legDistL',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) (nd.get_switch('toggle_display_mode') == 'MAP' and !nd.get_switch('toggle_centered')),
						is_true: func(nd){
							var active = getprop('autopilot/route-manager/active');
							var lat_ctrl = getprop(nd.options.defaults.lat_ctrl);
							var managed_v = nd.options.defaults.managed_val;
							var is_managed = (lat_ctrl == managed_v);
							var toggle_xtrk_err = nd.get_switch('toggle_xtrk_error');
							if((!active or is_managed) and !toggle_xtrk_err){
								nd.symbols.legDistL.hide();
							} else {
								var dist = getprop('instrumentation/gps/wp/wp[1]/course-error-nm');
								if(dist == nil or dist == '' or dist > -0.1){
									nd.symbols.legDistL.hide();
								} else {
									dist = sprintf('%.1fL', math.abs(dist));
									nd.symbols.legDistL.setText(dist);
									nd.symbols.legDistL.show();
								}
							}
						},
						is_false: func(nd){
							nd.symbols.legDistL.hide();
						}
					}
				},
				{
					id: 'legDistR',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) (nd.get_switch('toggle_display_mode') == 'MAP' and !nd.get_switch('toggle_centered')),
						is_true: func(nd){
							var active = getprop('autopilot/route-manager/active');
							var lat_ctrl = getprop(nd.options.defaults.lat_ctrl);
							var managed_v = nd.options.defaults.managed_val;
							var is_managed = (lat_ctrl == managed_v);
							var toggle_xtrk_err = nd.get_switch('toggle_xtrk_error');
							if((!active or is_managed) and !toggle_xtrk_err){
								nd.symbols.legDistR.hide();
							} else {
								var dist = getprop('instrumentation/gps/wp/wp[1]/course-error-nm');
								if(dist == nil or dist == '' or dist < 0.1){
									nd.symbols.legDistR.hide();
								} else {
									dist = sprintf('%.1fR', math.abs(dist));
									nd.symbols.legDistR.setText(dist);
									nd.symbols.legDistR.show();
								}
							}
						},
						is_false: func(nd){
							nd.symbols.legDistR.hide();
						}
					}
				},
				{
					id: 'legDistCtrL',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) (nd.get_switch('toggle_display_mode') == 'MAP' and nd.get_switch('toggle_centered')),
						is_true: func(nd){
							var active = getprop('autopilot/route-manager/active');
							var lat_ctrl = getprop(nd.options.defaults.lat_ctrl);
							var managed_v = nd.options.defaults.managed_val;
							var is_managed = (lat_ctrl == managed_v);
							var toggle_xtrk_err = nd.get_switch('toggle_xtrk_error');
							if((!active or is_managed) and !toggle_xtrk_err){
								nd.symbols.legDistCtrL.hide();
							} else {
								var dist = getprop('instrumentation/gps/wp/wp[1]/course-error-nm');
								if(dist == nil or dist == '' or dist > -0.1){
									nd.symbols.legDistCtrL.hide();
								} else {
									dist = sprintf('%.1fL', math.abs(dist));
									nd.symbols.legDistCtrL.setText(dist);
									nd.symbols.legDistCtrL.show();
								}
							}
						},
						is_false: func(nd){
							nd.symbols.legDistCtrL.hide();
						}
					}
				},
				{
					id: 'legDistCtrR',
					impl: {
						init: func(nd,symbol),
						predicate: func(nd) (nd.get_switch('toggle_display_mode') == 'MAP' and nd.get_switch('toggle_centered')),
						is_true: func(nd){
							var active = getprop('autopilot/route-manager/active');
							var lat_ctrl = getprop(nd.options.defaults.lat_ctrl);
							var managed_v = nd.options.defaults.managed_val;
							var is_managed = (lat_ctrl == managed_v);
							var toggle_xtrk_err = nd.get_switch('toggle_xtrk_error');
							if((!active or is_managed) and !toggle_xtrk_err){
								nd.symbols.legDistCtrR.hide();
							} else {
								var dist = getprop('instrumentation/gps/wp/wp[1]/course-error-nm');
								if(dist == nil or dist == '' or dist < 0.1){
									nd.symbols.legDistCtrR.hide();
								} else {
									dist = sprintf('%.1fR', math.abs(dist));
									nd.symbols.legDistCtrR.setText(dist);
									nd.symbols.legDistCtrR.show();
								}
							}
						},
						is_false: func(nd){
							nd.symbols.legDistCtrR.hide();
						}
					}
				},

			], # end of vector with features

		}
#####
##
## add support for other aircraft/ND types and styles here 
## or move to other files.
##
## see: http://wiki.flightgear.org/NavDisplay#Custom_ND_Styles
## and: http://wiki.flightgear.org/NavDisplay#Adding_new_features

}; # end of NDStyles