<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.flightgear.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Legoboyvdlp</id>
	<title>FlightGear wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.flightgear.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Legoboyvdlp"/>
	<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/Special:Contributions/Legoboyvdlp"/>
	<updated>2026-05-29T23:57:05Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.6</generator>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Changelog_2020.3&amp;diff=137482</id>
		<title>Changelog 2020.3</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Changelog_2020.3&amp;diff=137482"/>
		<updated>2023-04-03T12:31:02Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: /* 2020.3.18 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{changelogs|prev=2020.1|next=2022.1}}&lt;br /&gt;
&lt;br /&gt;
Available in: [[Changelog_2020.3|English]], [[Pl/Changelog_2020.3|Polish]], [[Zh/2020.3|Chinese]]&lt;br /&gt;
&lt;br /&gt;
Please help us translate into other languages!&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
The FlightGear development team is delighted to announce the v2020.3 LTS release of FlightGear, the free, open-source flight simulator. This is the second Long Term Support release for FlightGear, since the project changed to offering both Long Term Support releases, and more cutting-edge Preview releases.  This release represents the culmination of two years of development effort by a worldwide group of volunteers, brought together by a shared ambition to create the most realistic flight simulator possible that is free to use, modify and distribute. FlightGear is used all over the world by desktop flight simulator enthusiasts, for research in universities and for interactive exhibits in museums.&lt;br /&gt;
&lt;br /&gt;
Major enhancements since the v2020.3 LTS include: &lt;br /&gt;
* a developer preview of the upcoming Compositor graphical rendering framework as a separate pre-built binary, &lt;br /&gt;
* enhancements to both the JSBSim and YASim flight dynamics models&lt;br /&gt;
* DDS texture caching to reduce load times&lt;br /&gt;
* faster loading and more memory efficient buildings&lt;br /&gt;
* improved aircraft carrier support&lt;br /&gt;
&lt;br /&gt;
Additionally 30 completely new aircraft have been added to the official hangar, and a further 71 have received major updates.&lt;br /&gt;
&lt;br /&gt;
{{Disclaimer|id=final-fixed-function-release}}&lt;br /&gt;
&lt;br /&gt;
Founded in 1997, FlightGear features more than 700 aircraft, a worldwide scenery database, a multiplayer environment, detailed sky modelling, a flexible and open aircraft modelling system, varied networking options, multiple display support, a powerful scripting language, and an open architecture. Best of all, being open-source, the simulator is owned by the community and everyone is encouraged to contribute.&lt;br /&gt;
&lt;br /&gt;
FlightGear - Fly Free! &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Launcher ==&lt;br /&gt;
* Addition of a welcome screen on first launch, providing helpful information to first time users.&lt;br /&gt;
* Aircraft can now be marked as Favourites, and filtered, making it easier to see find your favourite aircraft out of the hundreds available.&lt;br /&gt;
* The launcher now supports aircraft carriers, including selecting a carrier and setting a start position.&lt;br /&gt;
* {{key press|Ctrl|F}} shortcut for when you just want to Fly!&lt;br /&gt;
* Improved support for helipads and seaports, including detection of current aircraft type.&lt;br /&gt;
* Numerous bugfixes and stability improvements, in particular for the aircraft and addons tabs.&lt;br /&gt;
&lt;br /&gt;
== Graphics ==&lt;br /&gt;
* To provide a developer preview, the [[Compositor]] renderer is included as part of this release.  It provides a fully XML-configurable multi-pass rendering pipeline that is compatible with ALS and includes clustered shading.&lt;br /&gt;
* Support for DDS Texture Cache, improving loading times for texture files.&lt;br /&gt;
* Star visibility is configurable based on magnitude of star and atmospheric conditions.&lt;br /&gt;
* Use of non-directional point sprites as a fallback for drivers that do not support triangles of point sprites is now supported by setting &amp;lt;code&amp;gt;/rendering/triangle-directional-lights=false&amp;lt;/code&amp;gt;.&lt;br /&gt;
* A new Tower AGL view has been added.  This is similar to Tower View, except that it keeps both the aircraft and the ground immediately below the aircraft in view, zooming and panning smoothly as the aircraft moves. Good for viewing landings.&lt;br /&gt;
* Improved airport grass textures&lt;br /&gt;
* Implemented tidal movement for littoral areas.&lt;br /&gt;
* Updated regional material definitions for California, Asia, Northern Brazil, Iceland, Jan Mayen island.&lt;br /&gt;
* Active volcanoes - Katla, Eyjafjallajokull, Surtsey.  &lt;br /&gt;
* Instanced-based random and OpenStreetMap buildings, improving performance and graphical quality significantly.&lt;br /&gt;
* Improvements to the Wingflex Shader.&lt;br /&gt;
* Users may enable/disable the pilot model from the View Options dialog.&lt;br /&gt;
&lt;br /&gt;
== JSBSim ==&lt;br /&gt;
* Added the ability to set up the starter and acceleration times of a turbine (parameters &amp;lt;code&amp;gt;&amp;lt;n1spinup&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;lt;n2spinup&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;lt;n1startrate&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;lt;n2startrate&amp;gt;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* The &amp;lt;code&amp;gt;&amp;lt;integrator&amp;gt;&amp;lt;/code&amp;gt; filter can now be reset to 0.0 by setting its &amp;lt;code&amp;gt;&amp;lt;trigger&amp;gt;&amp;lt;/code&amp;gt; property to a negative value.&lt;br /&gt;
* The integration scheme of the &amp;lt;code&amp;gt;&amp;lt;integrator&amp;gt;&amp;lt;/code&amp;gt; filter can now be chosen among &amp;lt;code&amp;gt;rect&amp;lt;/code&amp;gt; (Euler), &amp;lt;code&amp;gt;trap&amp;lt;/code&amp;gt; (Trapezoidal), &amp;lt;code&amp;gt;ab2&amp;lt;/code&amp;gt; (2nd order Adams-BashForth) and &amp;lt;code&amp;gt;ab3&amp;lt;/code&amp;gt; (3rd order Adams-Bashforth)&lt;br /&gt;
* The following functions can now be used in &amp;lt;code&amp;gt;&amp;lt;function&amp;gt;&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;floor&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ceil&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;fmod&amp;lt;/code&amp;gt;. Their functionalities are the same than the corresponding C/C++ functions.&lt;br /&gt;
* &amp;lt;code&amp;gt;&amp;lt;function&amp;gt;&amp;lt;/code&amp;gt; now checks the number of its arguments.&lt;br /&gt;
* New system component linear_actuator&lt;br /&gt;
* Export the fuel density to the property tree&lt;br /&gt;
* Added cyclic clipping for FCS components&lt;br /&gt;
* Added the ability to control the turbine engines spin down factor&lt;br /&gt;
* [Backward compatibility breakage] Gyros are now measuring rotation rates instead of rotational accelerations. Gyros that measure rotational accelerations do not exist in the real world.&lt;br /&gt;
* Output properties of flight control elements are no longer tied. This saves a lot of spurious warning messages and allows direct references of the same properties among several flight controls.&lt;br /&gt;
* Water vapor in the atmosphere is now managed through its mass fraction rather than its partial pressure. The former being the physical quantity that is conserved when pressure and temperature vary.&lt;br /&gt;
* Check that there are at least 3 contacts before trying to trim on ground.&lt;br /&gt;
* Added optional transmission of the simulation time for FG UDP interface&lt;br /&gt;
* The existence of the property that is used for table independent vars is now checked during execution rather than when the XML definition is parsed. This relaxes the order in which filters, table and more generally flight controls need to be declared in the XML definition files.&lt;br /&gt;
* Electric engines RPM is now exported in UDP sockets.&lt;br /&gt;
* The parameter &amp;lt;code&amp;gt;&amp;lt;ignitionn2&amp;gt;&amp;lt;/code&amp;gt; now affects N2 rather than N1. &lt;br /&gt;
* A warning is now given when max &amp;lt; min in a &amp;lt;code&amp;gt;&amp;lt;clipto&amp;gt;&amp;lt;/code&amp;gt; rather than throwing an exception&lt;br /&gt;
* Added the ability to log properties in a CSV file with the new fgfs executable argument &amp;lt;code&amp;gt;--jsbsim-output-directive-file&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== YASim ==&lt;br /&gt;
* Ground friction (stiction) changes&lt;br /&gt;
* Support for transonic flow effects.&lt;br /&gt;
* Control initial gear state directly by setting &amp;lt;code&amp;gt;/fdm/yasim/respect-external-gear-state=true&amp;lt;/code&amp;gt;, rather then YASim settings this depending on whether the aircraft is in the air or on the ground.&lt;br /&gt;
* Electric engines are now supported.&lt;br /&gt;
&lt;br /&gt;
== Weather and Environment ==&lt;br /&gt;
* Increased turbulence will be encountered near active volcanoes.&lt;br /&gt;
* Configurable METAR URL.&lt;br /&gt;
* METAR strings are decoded and displayed in a human-readable form in the weather dialog.&lt;br /&gt;
&lt;br /&gt;
== Carriers ==&lt;br /&gt;
* Two new carrier-specific starting options are supported in the launcher: &amp;lt;code&amp;gt;carrier-takeoff&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;carrier-approach&amp;lt;/code&amp;gt;.&lt;br /&gt;
* A new &amp;lt;code&amp;gt;--carrier-position&amp;lt;/code&amp;gt; command-line argument has been added.  This can be used to select the aircraft start position on an aircraft carrier.  Either a catapult (e.g. &amp;lt;code&amp;gt;cat-1&amp;lt;/code&amp;gt;), a parking position (e.g. &amp;lt;code&amp;gt;park-1&amp;lt;/code&amp;gt;), on final approach on the FLOLS (&amp;lt;code&amp;gt;flols&amp;lt;/code&amp;gt;) or abeam the carrier (&amp;lt;code&amp;gt;abeam&amp;lt;/code&amp;gt;).&lt;br /&gt;
* MPCarrier can now be detected by the GUI even if not available on startup.  To enable this feature set &amp;lt;code&amp;gt;/sim/mp-carriers/auto-attach=true&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== AI ==&lt;br /&gt;
* New fgcommands &amp;lt;code&amp;gt;add-aiobject&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;remove-aiobject&amp;lt;/code&amp;gt; for adding/removing objects to the AI subsystem.&lt;br /&gt;
* New AI aircraft, including 747 Freighter, CRJ900, SR-71, Saab 340.&lt;br /&gt;
* Numerous updates to AI traffic schedules and airline liveries.&lt;br /&gt;
* Space Shuttle TAEM and approach at KEDW scenario.&lt;br /&gt;
* Accurate Britten-Norman Islander performance data, from an Islander pilot.&lt;br /&gt;
&lt;br /&gt;
== Multiplayer ==&lt;br /&gt;
* Connection to VATSIM via swift is now available via the GUI.&lt;br /&gt;
* FGCom now supports both COM1 and COM2, as well as volume settings.&lt;br /&gt;
* The views defined by the user's aircraft (Pilot view, Helicopter view, Tower view etc) can now be used with multiplayer aircraft.  Viewing a particular multiplayer aircraft is done by clicking in the Pilot List dialogue's &amp;quot;view' column (see the &amp;quot;Multiplayer/Pilot List&amp;quot; menu).&lt;br /&gt;
* &amp;lt;code&amp;gt;--disable-hold-short&amp;lt;/code&amp;gt; option which allows the user to force a start on the runway when multiplayer is enabled.  This option should be used with caution - it can give other pilots and ATC a nasty fright to find an aircraft materialize on the runway!&lt;br /&gt;
* Support for recording multiplayer data&lt;br /&gt;
&lt;br /&gt;
== Nasal Scripting ==&lt;br /&gt;
* Configurable load order for core Nasal modules.&lt;br /&gt;
* Improvements and bug fixes to Emesary, the messaging interface.&lt;br /&gt;
* Improvements to the core libraries.&lt;br /&gt;
* Garbage collection improvements to reduce frame stuttering&lt;br /&gt;
* Re-loadable Nasal modules&lt;br /&gt;
* Canvas EFIS framework&lt;br /&gt;
* New methods in Canvas Image to set colors of pixels in the image.&lt;br /&gt;
&lt;br /&gt;
== Aircraft == &lt;br /&gt;
* FG1000 Glass Panel improvements include user-configurable VFR transponder codes, volume controls, new fascia, UI is now resizeable, support for custom SVG files (e.g. for a G500).  The FG1000 is now available on the Cessna 182T, J3 Cub, Diamond DA40.&lt;br /&gt;
* Improved glider vario instrument.&lt;br /&gt;
* New Aircraft: &lt;br /&gt;
** Airbus A320 - airliner&lt;br /&gt;
** Alisport Silent2Electro - glider with electric sustainer motor&lt;br /&gt;
** Bombardier Q400 DHC8-402 - shorthaul turboprop airliner&lt;br /&gt;
** Breguet Atlantic BR 1150 - long-range maritime patrol aircraft&lt;br /&gt;
** Cessna 140 - GA aircraft&lt;br /&gt;
** Cessna 208B Caravan - short range passenger, freighter and utility aircraft&lt;br /&gt;
** Cirrus SR22T - GA aircraft&lt;br /&gt;
** Diamond DA40 NG - GA aircraft, including FG1000 glass panel cockpit&lt;br /&gt;
** Diamond DA62 Twinstar- Twin engine GA aircraft&lt;br /&gt;
** Diamond HK36 Super Dimona - motorglider&lt;br /&gt;
** Dornier DO 28 Skyservant - Twin engine STOL utility aircraft&lt;br /&gt;
** Douglas TBD Devastator - WWII Torpedo bomber&lt;br /&gt;
** Draco Wilga - turboprop taildragger bush plane&lt;br /&gt;
** Fokker T.V - twin engine bomber&lt;br /&gt;
** Glasfluegel H201B Standard Libelle - glider&lt;br /&gt;
** Grumman F11-Tiger - carrier-based fighter&lt;br /&gt;
** Grumman HU-16A Albatross - twin engine amphibian&lt;br /&gt;
** Petliakov PE-8 (Ant-42/TB-7) - WWII bomber&lt;br /&gt;
** Piper PA28-161 Warrior II - GA aircraft&lt;br /&gt;
** Pipistrel Alpha Electro - electric training aircraft&lt;br /&gt;
** Pipistrel Taurus Electro G2.5 - glider with electric sustainer motor&lt;br /&gt;
** Rolladen Schneider LS8sc neo - standard glider with electric sustainer motor&lt;br /&gt;
** Robin DR400 Ecoflyer - GA Aircraft&lt;br /&gt;
** Scheibe Bergfalke II/55 - training glider&lt;br /&gt;
** Schempp-Hirth Arcus S - high performance glider&lt;br /&gt;
** Schleicher Ka6(CR) &amp;quot;Rhoensegler&amp;quot; - training glider&lt;br /&gt;
** SEPECAT Jaguar GR.1 - jet attack aircraft&lt;br /&gt;
** SUMPAC - Human powered airplane&lt;br /&gt;
** Supermarine Swift - jet fighter&lt;br /&gt;
** Yak 52 - training aircraft&lt;br /&gt;
* Major updates to over 70 aircraft.  Including 737-100, 737-300, 777, A-26-Invader, AR-234, ASG29, ASK13, ASK21, Aero-Commander, Aichi-D3A, B-17, B-24-Liberator, B-25, Bombardier-415, CH750STOL, CRJ700-family, Cessna-208-Caravan, Cessna Citation II, Cessna-L19, Cirrus-SR22, Concorde, DO-228, DO-335, Diamond-Da40, Diamond-Da42, Dragonfly, Embraer-ERJ-145, F-15, Fairchild-Metroliner, Falcon-50, Fokker-S-11, Fw200, H4-Hercules, Harrier-GR3, Horten-Ho-IX, Hughes-XF11, J3Cub, JA37, JAS39-Gripen, Jaguar, LS4, Lancair-235, Lionceau, Lockheed-NF104A, Lockheed-P38, ME-262, Mirage-2000, MirageIV, Northrop-xb35, PC-12, Piaggio-P166, Piper-PA-28, Potez-630, R44, Ryan-Navion, SIAI-Marchetti-SF.260, Socata-ST10, SpaceShuttle, Starship, Tecnam-P2006T, UH-1, Yak-18T, Zlin-50lx, an24b, bluebird, c182s, dhc1, f-14b, f16.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous ==&lt;br /&gt;
* Updated Chinese, Dutch, French, German, Italian, Polish and Slovak translations.&lt;br /&gt;
* Map dialog displays heliports and allows configurable cursor key panning&lt;br /&gt;
* Faster Terrasync:  Download a tarball of airport information on first start and only check for updates every 24 hours rather than every simulator run.&lt;br /&gt;
* GPS fly-by mode&lt;br /&gt;
* Sentry.io integration to provide centralized crash reporting.&lt;br /&gt;
* Change screenshot filename to have date and time&lt;br /&gt;
* New thread safe particle manager -- should reduce random crashes around particles.&lt;br /&gt;
&lt;br /&gt;
=Updates since 2020.1=&lt;br /&gt;
Changes since the 2020.1 preview release include:&lt;br /&gt;
* Various launcher improvements including a Welcome screen and a keyboard shortcut ({{key press|Ctrl|F}}) to Fly!&lt;br /&gt;
* Improved regional definitions for California, Iceland and Northern Brazil and better grass textures.&lt;br /&gt;
* Implemented tidal movement for littoral areas.&lt;br /&gt;
* New AI model for the 747 Freighter, and numerous AI livery and traffic updates.&lt;br /&gt;
* Updates to the FG1000 glass panel display including configurable VFR transponder codes, volume controls, a new fascia, resizeable UI and support for custom SVG files.&lt;br /&gt;
* A hangar full of new aircraft: HU-16A-Albatross, LS8, Embraer-ERJ-145, Cessna 208B Caravan, PZL 104 wilga 2000 Draco, Scheibe Bergfalke, Taurus, f16, Dornier Do 28 Skyservant, Petliakov Pe 8 (Ant 42/DB 7), Grumman F.11 Tiger&lt;br /&gt;
* Updates to a large number of aircraft including CRJ700, Dragonfly, Mirage 2000, Jaguar GR1, H4 Hercules, JA37, Supermarine Swift, A320, Cirrus-SR22, Cessna Citation, J3Cub&lt;br /&gt;
* Updated Chinese, Dutch, French, German, Italian, Polish and Slovak translations.&lt;br /&gt;
* Faster Terrasync:  Download a tarball of airport information on first start and only check for updates every 24 hours rather than every simulator run.&lt;br /&gt;
* GPS fly-by mode&lt;br /&gt;
* Sentry.io integration to provide centralized crash reporting.&lt;br /&gt;
* New thread safe particle manager -- should reduce random crashes around particles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Updates since 2020.3.0=&lt;br /&gt;
&lt;br /&gt;
As 2020.3 is a long term supported release, there are ongoing bug-fixes and small improvements happening, based on user feedback and automatic reporting of crashes and issues. Significant fixes are listed below:&lt;br /&gt;
&lt;br /&gt;
==2020.3.1==&lt;br /&gt;
* Add help page to the launcher&lt;br /&gt;
* Fix handling of helipads at heliports&lt;br /&gt;
* Migrate installed aircraft packages, when migrating to the new stable catalog&lt;br /&gt;
* TerraSync: improve startup performance on Windows&lt;br /&gt;
&lt;br /&gt;
==2020.3.2==&lt;br /&gt;
* TerraSync waits for Models to be completely sync-ed, to avoid missing models when starting&lt;br /&gt;
* First-run screen: add a 'scroll to the bottom' hint icon&lt;br /&gt;
* Tides fixes from Erik Hofman&lt;br /&gt;
* Use nicer scrollbar for the launcher, fixes some issue with long aircraft lists&lt;br /&gt;
* Support Apt.dat v1000 comm frequencies&lt;br /&gt;
* Fix an ATC crash when repositioning&lt;br /&gt;
* Many translations fixes identified by Michael Danilov&lt;br /&gt;
* Greatly improve the Brazilian cerradio areas (near SBMQ)&lt;br /&gt;
* Russian translation updates&lt;br /&gt;
* Iceland materials fixes&lt;br /&gt;
&lt;br /&gt;
==2020.3.3==&lt;br /&gt;
* Fix accidental mouse picks while using a right-mouse-drag to look around&lt;br /&gt;
* Fix the download location we recommend in the 'setup root' dialog&lt;br /&gt;
&lt;br /&gt;
==2020.3.4==&lt;br /&gt;
* Handle more METAR strings correctly, including wind sensor failures&lt;br /&gt;
* Fix airmass velocity being applied to sub-models twice (eg, when dropping payloads in a cross-wind)&lt;br /&gt;
* Fix crash on shutdown in the properties code&lt;br /&gt;
* Spanish translation updates &lt;br /&gt;
* Disable flights to EGEL to avoid crashes in traffic code&lt;br /&gt;
&lt;br /&gt;
==2020.3.5==&lt;br /&gt;
* Change default Windows download location to %USERS%\FlightGear\Downloads, to avoid problems with Windows Defender blocking un-trusted applications from writing to Documents, which was the previous location.&lt;br /&gt;
* Fix a crash when returning to FlightGear from another application and scrolling or clicking&lt;br /&gt;
* Avoid crashing with UIUC-based aircraft such as the Wright Flyer&lt;br /&gt;
* Fix a crash on macOS when a joystick failed to open&lt;br /&gt;
* Update the macOS application icon&lt;br /&gt;
* Fix Nasal crash on reset&lt;br /&gt;
* Canvas: allow anisotropic filtering&lt;br /&gt;
* Larger, improved moon texture&lt;br /&gt;
* UFO speed goes to 11&lt;br /&gt;
* Fix taxiway markings disappearing in specific graphics settings&lt;br /&gt;
&lt;br /&gt;
==2020.3.6==&lt;br /&gt;
* Fixed crash downloading the default aircraft catalog&lt;br /&gt;
* Fix a hang starting at scenery in the ocean&lt;br /&gt;
* Fix incorrect sky &amp;amp; cockpit rendering with certain METAR values&lt;br /&gt;
* Add getting-started hints to the launcher (English only for now)&lt;br /&gt;
* Fix Shuttle AI scenarios&lt;br /&gt;
* Improvements to flight-planning mode&lt;br /&gt;
* Sun / moon scaling fixes&lt;br /&gt;
* Fix initial position of submodels&lt;br /&gt;
* macOS: warn if running with app translocation&lt;br /&gt;
* Windows: detect missing OpenGL drivers&lt;br /&gt;
* Fix UIUC FDM crashes&lt;br /&gt;
* Fix crash with invalid view numbers&lt;br /&gt;
* Catch FDM NaN errors more gracefully&lt;br /&gt;
* KAP-140 approach mode improvements&lt;br /&gt;
* Traffic+AI livery updates&lt;br /&gt;
&lt;br /&gt;
== 2020.3.7 ==&lt;br /&gt;
* Enable OSM2City buildings via TerraSync for the whole planet&lt;br /&gt;
* C172 bug-fixes and updates&lt;br /&gt;
* Improved regional material definitions for Europe, California&lt;br /&gt;
* Allow chat box to be re-positioned&lt;br /&gt;
* Fix crashes related to particle systems&lt;br /&gt;
* Fix selection of time-zone around Beijing&lt;br /&gt;
* Fix display of non-Latin1 strings in Canvas displays&lt;br /&gt;
* Fix Multi-player mode runway-start logic to select hold-short position correctly&lt;br /&gt;
* macOS: fix crash on text with certain fonts&lt;br /&gt;
* Fix launcher language selection when the UI language include a script specifier (eg zh-Hans-CN)&lt;br /&gt;
* Fix aircraft-id property when loading from a hangar ( https://sourceforge.net/p/flightgear/codetickets/2502/ )&lt;br /&gt;
* Improve checks for out-of-date Intel Graphics drivers on Windows&lt;br /&gt;
&lt;br /&gt;
== 2020.3.8 ==&lt;br /&gt;
* Fix behaviour of &amp;lt;code&amp;gt;&amp;lt;local&amp;gt;&amp;lt;/code&amp;gt; particle systems &lt;br /&gt;
* Fix autumn tree appearance&lt;br /&gt;
&lt;br /&gt;
== 2020.3.9 ==&lt;br /&gt;
* Fix crash in Swift&lt;br /&gt;
* Corrections to MP protocol timing&lt;br /&gt;
* Correct URL to FGData&lt;br /&gt;
* Fix bug in cache reload dialog&lt;br /&gt;
* Improvements to ATC dialog to display frequencies with 3 decimal places correctly&lt;br /&gt;
* Improve material definitions for Africa, Mediterranean regions&lt;br /&gt;
* Add updated ocean and water visual effects&lt;br /&gt;
&lt;br /&gt;
== 2020.3.10 ==&lt;br /&gt;
* Transponder: make standby mode work&lt;br /&gt;
* Launcher: pick up scenery and aircraft paths from the command line&lt;br /&gt;
* Launcher: store locations differently, to avoid problems when running multiple FlightGear versions and switching between them.&lt;br /&gt;
* Launcher: add 'restart on quit' option&lt;br /&gt;
* Fix NavCache errors loading ShapeFile data&lt;br /&gt;
* Fix NavCache errors when running multiple copies of FlightGear&lt;br /&gt;
&lt;br /&gt;
== 2020.3.11 ==&lt;br /&gt;
* Fix a crash introduced in 2020.3.10&lt;br /&gt;
* Improve error message when no aircraft search paths are available&lt;br /&gt;
* Fix a crash with misconfigured traffic taxi routes&lt;br /&gt;
* Update AI traffic schedules&lt;br /&gt;
&lt;br /&gt;
== 2020.3.12 ==&lt;br /&gt;
* Add aircraft directory name validation &lt;br /&gt;
* Add an extra step of antialiasing (8x)&lt;br /&gt;
* Add feature allowing aircraft to define custom fonts for osg::Text&lt;br /&gt;
* Add generic combined ALS procedural lights and Compositor lights&lt;br /&gt;
* Add new regional materials for Australia&lt;br /&gt;
* Fix Basic Weather producing invalid pressure altitudes&lt;br /&gt;
* Fix bug in path searching for previews&lt;br /&gt;
* Fix bug in sound system when approaching max-dist range&lt;br /&gt;
* Fix crashes after reset&lt;br /&gt;
* Fix crash when AI aircraft has invalid destination runway&lt;br /&gt;
* Fix Mapstructure error in RTE layer&lt;br /&gt;
* Fix &amp;lt;code&amp;gt;--view-offset&amp;lt;/code&amp;gt; to use the correct property&lt;br /&gt;
* HUD: make vertical gauges look the same as horizontal ones&lt;br /&gt;
* Improved Russian and Spanish translations&lt;br /&gt;
* Miscellaneous improvements to weather dialog&lt;br /&gt;
* Property browser: display values for folders in verbose mode &lt;br /&gt;
* Route manager: select correct waypoint when duplicate waypoints exist&lt;br /&gt;
* Update AI traffic schedules and add new AI models&lt;br /&gt;
&lt;br /&gt;
== 2020.3.13 ==&lt;br /&gt;
* Fix for the disappearing MP pilot list&lt;br /&gt;
* Fix JSBsim linear actuators behaving badly in certain conditions&lt;br /&gt;
&lt;br /&gt;
== 2020.3.14 ==&lt;br /&gt;
* Support for add-on paths&lt;br /&gt;
* Instant audio queue&lt;br /&gt;
* Allow canvas dialogs to not grab focus away from FG (more like how focus in PUI dialogs behaves)&lt;br /&gt;
&lt;br /&gt;
== 2020.3.15 ==&lt;br /&gt;
* Fix radio audio morse issue.&lt;br /&gt;
&lt;br /&gt;
== 2020.3.16 ==&lt;br /&gt;
* Fix audio indent issue.&lt;br /&gt;
&lt;br /&gt;
== 2020.3.17 ==&lt;br /&gt;
* Navradio: disable low-pass filter when changing selected freq or leaving GPS slave mode. When the selected frequency is changed or when leaving GPS slave mode, disable the low-pass filter applied to signal quality.&lt;br /&gt;
* Navradio: fix regression and optimize older code. Fix a little regression introduced in previous commit. Add: changing the standby frequency disabled the low-pass filter for the next call to updateReceiver(); this must happen when the selected frequency is changed but not when the standby frequency is changed.&lt;br /&gt;
* AP input: add property-path support to Inputs. Allow making the AP source indirect (via a string property), so that the actual source property can be configured or adjusted from a -set.xml, or at runtime.&lt;br /&gt;
* Replace displaying in Launcher `--on-ground=false` to `--in-air` for on final. The option`--on-ground=false` doesn't exist which can be misleading.&lt;br /&gt;
&lt;br /&gt;
== 2020.3.18 == &lt;br /&gt;
&amp;lt;!-- Just for placeholder, someone will need to fix this --&amp;gt;&lt;br /&gt;
* Added photoscenery capability.&lt;br /&gt;
* New basic autopilot system.&lt;br /&gt;
* Fix crash with a 'between' type constraint in Navigraph procedure files&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- == 2020.3.19 == &lt;br /&gt;
* Add AI submodel collision&lt;br /&gt;
* Fix crash with invalid METAR strings&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
{{Appendix}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:FlightGear changelogs‎]]&lt;br /&gt;
[[pl:Changelog_2020.3]]&lt;br /&gt;
[[Zh:2020.3]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Changelog_2020.3&amp;diff=137481</id>
		<title>Changelog 2020.3</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Changelog_2020.3&amp;diff=137481"/>
		<updated>2023-04-03T12:28:07Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: /* 2020.3.18 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{changelogs|prev=2020.1|next=2022.1}}&lt;br /&gt;
&lt;br /&gt;
Available in: [[Changelog_2020.3|English]], [[Pl/Changelog_2020.3|Polish]], [[Zh/2020.3|Chinese]]&lt;br /&gt;
&lt;br /&gt;
Please help us translate into other languages!&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
The FlightGear development team is delighted to announce the v2020.3 LTS release of FlightGear, the free, open-source flight simulator. This is the second Long Term Support release for FlightGear, since the project changed to offering both Long Term Support releases, and more cutting-edge Preview releases.  This release represents the culmination of two years of development effort by a worldwide group of volunteers, brought together by a shared ambition to create the most realistic flight simulator possible that is free to use, modify and distribute. FlightGear is used all over the world by desktop flight simulator enthusiasts, for research in universities and for interactive exhibits in museums.&lt;br /&gt;
&lt;br /&gt;
Major enhancements since the v2020.3 LTS include: &lt;br /&gt;
* a developer preview of the upcoming Compositor graphical rendering framework as a separate pre-built binary, &lt;br /&gt;
* enhancements to both the JSBSim and YASim flight dynamics models&lt;br /&gt;
* DDS texture caching to reduce load times&lt;br /&gt;
* faster loading and more memory efficient buildings&lt;br /&gt;
* improved aircraft carrier support&lt;br /&gt;
&lt;br /&gt;
Additionally 30 completely new aircraft have been added to the official hangar, and a further 71 have received major updates.&lt;br /&gt;
&lt;br /&gt;
{{Disclaimer|id=final-fixed-function-release}}&lt;br /&gt;
&lt;br /&gt;
Founded in 1997, FlightGear features more than 700 aircraft, a worldwide scenery database, a multiplayer environment, detailed sky modelling, a flexible and open aircraft modelling system, varied networking options, multiple display support, a powerful scripting language, and an open architecture. Best of all, being open-source, the simulator is owned by the community and everyone is encouraged to contribute.&lt;br /&gt;
&lt;br /&gt;
FlightGear - Fly Free! &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Launcher ==&lt;br /&gt;
* Addition of a welcome screen on first launch, providing helpful information to first time users.&lt;br /&gt;
* Aircraft can now be marked as Favourites, and filtered, making it easier to see find your favourite aircraft out of the hundreds available.&lt;br /&gt;
* The launcher now supports aircraft carriers, including selecting a carrier and setting a start position.&lt;br /&gt;
* {{key press|Ctrl|F}} shortcut for when you just want to Fly!&lt;br /&gt;
* Improved support for helipads and seaports, including detection of current aircraft type.&lt;br /&gt;
* Numerous bugfixes and stability improvements, in particular for the aircraft and addons tabs.&lt;br /&gt;
&lt;br /&gt;
== Graphics ==&lt;br /&gt;
* To provide a developer preview, the [[Compositor]] renderer is included as part of this release.  It provides a fully XML-configurable multi-pass rendering pipeline that is compatible with ALS and includes clustered shading.&lt;br /&gt;
* Support for DDS Texture Cache, improving loading times for texture files.&lt;br /&gt;
* Star visibility is configurable based on magnitude of star and atmospheric conditions.&lt;br /&gt;
* Use of non-directional point sprites as a fallback for drivers that do not support triangles of point sprites is now supported by setting &amp;lt;code&amp;gt;/rendering/triangle-directional-lights=false&amp;lt;/code&amp;gt;.&lt;br /&gt;
* A new Tower AGL view has been added.  This is similar to Tower View, except that it keeps both the aircraft and the ground immediately below the aircraft in view, zooming and panning smoothly as the aircraft moves. Good for viewing landings.&lt;br /&gt;
* Improved airport grass textures&lt;br /&gt;
* Implemented tidal movement for littoral areas.&lt;br /&gt;
* Updated regional material definitions for California, Asia, Northern Brazil, Iceland, Jan Mayen island.&lt;br /&gt;
* Active volcanoes - Katla, Eyjafjallajokull, Surtsey.  &lt;br /&gt;
* Instanced-based random and OpenStreetMap buildings, improving performance and graphical quality significantly.&lt;br /&gt;
* Improvements to the Wingflex Shader.&lt;br /&gt;
* Users may enable/disable the pilot model from the View Options dialog.&lt;br /&gt;
&lt;br /&gt;
== JSBSim ==&lt;br /&gt;
* Added the ability to set up the starter and acceleration times of a turbine (parameters &amp;lt;code&amp;gt;&amp;lt;n1spinup&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;lt;n2spinup&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;lt;n1startrate&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;lt;n2startrate&amp;gt;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* The &amp;lt;code&amp;gt;&amp;lt;integrator&amp;gt;&amp;lt;/code&amp;gt; filter can now be reset to 0.0 by setting its &amp;lt;code&amp;gt;&amp;lt;trigger&amp;gt;&amp;lt;/code&amp;gt; property to a negative value.&lt;br /&gt;
* The integration scheme of the &amp;lt;code&amp;gt;&amp;lt;integrator&amp;gt;&amp;lt;/code&amp;gt; filter can now be chosen among &amp;lt;code&amp;gt;rect&amp;lt;/code&amp;gt; (Euler), &amp;lt;code&amp;gt;trap&amp;lt;/code&amp;gt; (Trapezoidal), &amp;lt;code&amp;gt;ab2&amp;lt;/code&amp;gt; (2nd order Adams-BashForth) and &amp;lt;code&amp;gt;ab3&amp;lt;/code&amp;gt; (3rd order Adams-Bashforth)&lt;br /&gt;
* The following functions can now be used in &amp;lt;code&amp;gt;&amp;lt;function&amp;gt;&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;floor&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ceil&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;fmod&amp;lt;/code&amp;gt;. Their functionalities are the same than the corresponding C/C++ functions.&lt;br /&gt;
* &amp;lt;code&amp;gt;&amp;lt;function&amp;gt;&amp;lt;/code&amp;gt; now checks the number of its arguments.&lt;br /&gt;
* New system component linear_actuator&lt;br /&gt;
* Export the fuel density to the property tree&lt;br /&gt;
* Added cyclic clipping for FCS components&lt;br /&gt;
* Added the ability to control the turbine engines spin down factor&lt;br /&gt;
* [Backward compatibility breakage] Gyros are now measuring rotation rates instead of rotational accelerations. Gyros that measure rotational accelerations do not exist in the real world.&lt;br /&gt;
* Output properties of flight control elements are no longer tied. This saves a lot of spurious warning messages and allows direct references of the same properties among several flight controls.&lt;br /&gt;
* Water vapor in the atmosphere is now managed through its mass fraction rather than its partial pressure. The former being the physical quantity that is conserved when pressure and temperature vary.&lt;br /&gt;
* Check that there are at least 3 contacts before trying to trim on ground.&lt;br /&gt;
* Added optional transmission of the simulation time for FG UDP interface&lt;br /&gt;
* The existence of the property that is used for table independent vars is now checked during execution rather than when the XML definition is parsed. This relaxes the order in which filters, table and more generally flight controls need to be declared in the XML definition files.&lt;br /&gt;
* Electric engines RPM is now exported in UDP sockets.&lt;br /&gt;
* The parameter &amp;lt;code&amp;gt;&amp;lt;ignitionn2&amp;gt;&amp;lt;/code&amp;gt; now affects N2 rather than N1. &lt;br /&gt;
* A warning is now given when max &amp;lt; min in a &amp;lt;code&amp;gt;&amp;lt;clipto&amp;gt;&amp;lt;/code&amp;gt; rather than throwing an exception&lt;br /&gt;
* Added the ability to log properties in a CSV file with the new fgfs executable argument &amp;lt;code&amp;gt;--jsbsim-output-directive-file&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== YASim ==&lt;br /&gt;
* Ground friction (stiction) changes&lt;br /&gt;
* Support for transonic flow effects.&lt;br /&gt;
* Control initial gear state directly by setting &amp;lt;code&amp;gt;/fdm/yasim/respect-external-gear-state=true&amp;lt;/code&amp;gt;, rather then YASim settings this depending on whether the aircraft is in the air or on the ground.&lt;br /&gt;
* Electric engines are now supported.&lt;br /&gt;
&lt;br /&gt;
== Weather and Environment ==&lt;br /&gt;
* Increased turbulence will be encountered near active volcanoes.&lt;br /&gt;
* Configurable METAR URL.&lt;br /&gt;
* METAR strings are decoded and displayed in a human-readable form in the weather dialog.&lt;br /&gt;
&lt;br /&gt;
== Carriers ==&lt;br /&gt;
* Two new carrier-specific starting options are supported in the launcher: &amp;lt;code&amp;gt;carrier-takeoff&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;carrier-approach&amp;lt;/code&amp;gt;.&lt;br /&gt;
* A new &amp;lt;code&amp;gt;--carrier-position&amp;lt;/code&amp;gt; command-line argument has been added.  This can be used to select the aircraft start position on an aircraft carrier.  Either a catapult (e.g. &amp;lt;code&amp;gt;cat-1&amp;lt;/code&amp;gt;), a parking position (e.g. &amp;lt;code&amp;gt;park-1&amp;lt;/code&amp;gt;), on final approach on the FLOLS (&amp;lt;code&amp;gt;flols&amp;lt;/code&amp;gt;) or abeam the carrier (&amp;lt;code&amp;gt;abeam&amp;lt;/code&amp;gt;).&lt;br /&gt;
* MPCarrier can now be detected by the GUI even if not available on startup.  To enable this feature set &amp;lt;code&amp;gt;/sim/mp-carriers/auto-attach=true&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== AI ==&lt;br /&gt;
* New fgcommands &amp;lt;code&amp;gt;add-aiobject&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;remove-aiobject&amp;lt;/code&amp;gt; for adding/removing objects to the AI subsystem.&lt;br /&gt;
* New AI aircraft, including 747 Freighter, CRJ900, SR-71, Saab 340.&lt;br /&gt;
* Numerous updates to AI traffic schedules and airline liveries.&lt;br /&gt;
* Space Shuttle TAEM and approach at KEDW scenario.&lt;br /&gt;
* Accurate Britten-Norman Islander performance data, from an Islander pilot.&lt;br /&gt;
&lt;br /&gt;
== Multiplayer ==&lt;br /&gt;
* Connection to VATSIM via swift is now available via the GUI.&lt;br /&gt;
* FGCom now supports both COM1 and COM2, as well as volume settings.&lt;br /&gt;
* The views defined by the user's aircraft (Pilot view, Helicopter view, Tower view etc) can now be used with multiplayer aircraft.  Viewing a particular multiplayer aircraft is done by clicking in the Pilot List dialogue's &amp;quot;view' column (see the &amp;quot;Multiplayer/Pilot List&amp;quot; menu).&lt;br /&gt;
* &amp;lt;code&amp;gt;--disable-hold-short&amp;lt;/code&amp;gt; option which allows the user to force a start on the runway when multiplayer is enabled.  This option should be used with caution - it can give other pilots and ATC a nasty fright to find an aircraft materialize on the runway!&lt;br /&gt;
* Support for recording multiplayer data&lt;br /&gt;
&lt;br /&gt;
== Nasal Scripting ==&lt;br /&gt;
* Configurable load order for core Nasal modules.&lt;br /&gt;
* Improvements and bug fixes to Emesary, the messaging interface.&lt;br /&gt;
* Improvements to the core libraries.&lt;br /&gt;
* Garbage collection improvements to reduce frame stuttering&lt;br /&gt;
* Re-loadable Nasal modules&lt;br /&gt;
* Canvas EFIS framework&lt;br /&gt;
* New methods in Canvas Image to set colors of pixels in the image.&lt;br /&gt;
&lt;br /&gt;
== Aircraft == &lt;br /&gt;
* FG1000 Glass Panel improvements include user-configurable VFR transponder codes, volume controls, new fascia, UI is now resizeable, support for custom SVG files (e.g. for a G500).  The FG1000 is now available on the Cessna 182T, J3 Cub, Diamond DA40.&lt;br /&gt;
* Improved glider vario instrument.&lt;br /&gt;
* New Aircraft: &lt;br /&gt;
** Airbus A320 - airliner&lt;br /&gt;
** Alisport Silent2Electro - glider with electric sustainer motor&lt;br /&gt;
** Bombardier Q400 DHC8-402 - shorthaul turboprop airliner&lt;br /&gt;
** Breguet Atlantic BR 1150 - long-range maritime patrol aircraft&lt;br /&gt;
** Cessna 140 - GA aircraft&lt;br /&gt;
** Cessna 208B Caravan - short range passenger, freighter and utility aircraft&lt;br /&gt;
** Cirrus SR22T - GA aircraft&lt;br /&gt;
** Diamond DA40 NG - GA aircraft, including FG1000 glass panel cockpit&lt;br /&gt;
** Diamond DA62 Twinstar- Twin engine GA aircraft&lt;br /&gt;
** Diamond HK36 Super Dimona - motorglider&lt;br /&gt;
** Dornier DO 28 Skyservant - Twin engine STOL utility aircraft&lt;br /&gt;
** Douglas TBD Devastator - WWII Torpedo bomber&lt;br /&gt;
** Draco Wilga - turboprop taildragger bush plane&lt;br /&gt;
** Fokker T.V - twin engine bomber&lt;br /&gt;
** Glasfluegel H201B Standard Libelle - glider&lt;br /&gt;
** Grumman F11-Tiger - carrier-based fighter&lt;br /&gt;
** Grumman HU-16A Albatross - twin engine amphibian&lt;br /&gt;
** Petliakov PE-8 (Ant-42/TB-7) - WWII bomber&lt;br /&gt;
** Piper PA28-161 Warrior II - GA aircraft&lt;br /&gt;
** Pipistrel Alpha Electro - electric training aircraft&lt;br /&gt;
** Pipistrel Taurus Electro G2.5 - glider with electric sustainer motor&lt;br /&gt;
** Rolladen Schneider LS8sc neo - standard glider with electric sustainer motor&lt;br /&gt;
** Robin DR400 Ecoflyer - GA Aircraft&lt;br /&gt;
** Scheibe Bergfalke II/55 - training glider&lt;br /&gt;
** Schempp-Hirth Arcus S - high performance glider&lt;br /&gt;
** Schleicher Ka6(CR) &amp;quot;Rhoensegler&amp;quot; - training glider&lt;br /&gt;
** SEPECAT Jaguar GR.1 - jet attack aircraft&lt;br /&gt;
** SUMPAC - Human powered airplane&lt;br /&gt;
** Supermarine Swift - jet fighter&lt;br /&gt;
** Yak 52 - training aircraft&lt;br /&gt;
* Major updates to over 70 aircraft.  Including 737-100, 737-300, 777, A-26-Invader, AR-234, ASG29, ASK13, ASK21, Aero-Commander, Aichi-D3A, B-17, B-24-Liberator, B-25, Bombardier-415, CH750STOL, CRJ700-family, Cessna-208-Caravan, Cessna Citation II, Cessna-L19, Cirrus-SR22, Concorde, DO-228, DO-335, Diamond-Da40, Diamond-Da42, Dragonfly, Embraer-ERJ-145, F-15, Fairchild-Metroliner, Falcon-50, Fokker-S-11, Fw200, H4-Hercules, Harrier-GR3, Horten-Ho-IX, Hughes-XF11, J3Cub, JA37, JAS39-Gripen, Jaguar, LS4, Lancair-235, Lionceau, Lockheed-NF104A, Lockheed-P38, ME-262, Mirage-2000, MirageIV, Northrop-xb35, PC-12, Piaggio-P166, Piper-PA-28, Potez-630, R44, Ryan-Navion, SIAI-Marchetti-SF.260, Socata-ST10, SpaceShuttle, Starship, Tecnam-P2006T, UH-1, Yak-18T, Zlin-50lx, an24b, bluebird, c182s, dhc1, f-14b, f16.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous ==&lt;br /&gt;
* Updated Chinese, Dutch, French, German, Italian, Polish and Slovak translations.&lt;br /&gt;
* Map dialog displays heliports and allows configurable cursor key panning&lt;br /&gt;
* Faster Terrasync:  Download a tarball of airport information on first start and only check for updates every 24 hours rather than every simulator run.&lt;br /&gt;
* GPS fly-by mode&lt;br /&gt;
* Sentry.io integration to provide centralized crash reporting.&lt;br /&gt;
* Change screenshot filename to have date and time&lt;br /&gt;
* New thread safe particle manager -- should reduce random crashes around particles.&lt;br /&gt;
&lt;br /&gt;
=Updates since 2020.1=&lt;br /&gt;
Changes since the 2020.1 preview release include:&lt;br /&gt;
* Various launcher improvements including a Welcome screen and a keyboard shortcut ({{key press|Ctrl|F}}) to Fly!&lt;br /&gt;
* Improved regional definitions for California, Iceland and Northern Brazil and better grass textures.&lt;br /&gt;
* Implemented tidal movement for littoral areas.&lt;br /&gt;
* New AI model for the 747 Freighter, and numerous AI livery and traffic updates.&lt;br /&gt;
* Updates to the FG1000 glass panel display including configurable VFR transponder codes, volume controls, a new fascia, resizeable UI and support for custom SVG files.&lt;br /&gt;
* A hangar full of new aircraft: HU-16A-Albatross, LS8, Embraer-ERJ-145, Cessna 208B Caravan, PZL 104 wilga 2000 Draco, Scheibe Bergfalke, Taurus, f16, Dornier Do 28 Skyservant, Petliakov Pe 8 (Ant 42/DB 7), Grumman F.11 Tiger&lt;br /&gt;
* Updates to a large number of aircraft including CRJ700, Dragonfly, Mirage 2000, Jaguar GR1, H4 Hercules, JA37, Supermarine Swift, A320, Cirrus-SR22, Cessna Citation, J3Cub&lt;br /&gt;
* Updated Chinese, Dutch, French, German, Italian, Polish and Slovak translations.&lt;br /&gt;
* Faster Terrasync:  Download a tarball of airport information on first start and only check for updates every 24 hours rather than every simulator run.&lt;br /&gt;
* GPS fly-by mode&lt;br /&gt;
* Sentry.io integration to provide centralized crash reporting.&lt;br /&gt;
* New thread safe particle manager -- should reduce random crashes around particles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Updates since 2020.3.0=&lt;br /&gt;
&lt;br /&gt;
As 2020.3 is a long term supported release, there are ongoing bug-fixes and small improvements happening, based on user feedback and automatic reporting of crashes and issues. Significant fixes are listed below:&lt;br /&gt;
&lt;br /&gt;
==2020.3.1==&lt;br /&gt;
* Add help page to the launcher&lt;br /&gt;
* Fix handling of helipads at heliports&lt;br /&gt;
* Migrate installed aircraft packages, when migrating to the new stable catalog&lt;br /&gt;
* TerraSync: improve startup performance on Windows&lt;br /&gt;
&lt;br /&gt;
==2020.3.2==&lt;br /&gt;
* TerraSync waits for Models to be completely sync-ed, to avoid missing models when starting&lt;br /&gt;
* First-run screen: add a 'scroll to the bottom' hint icon&lt;br /&gt;
* Tides fixes from Erik Hofman&lt;br /&gt;
* Use nicer scrollbar for the launcher, fixes some issue with long aircraft lists&lt;br /&gt;
* Support Apt.dat v1000 comm frequencies&lt;br /&gt;
* Fix an ATC crash when repositioning&lt;br /&gt;
* Many translations fixes identified by Michael Danilov&lt;br /&gt;
* Greatly improve the Brazilian cerradio areas (near SBMQ)&lt;br /&gt;
* Russian translation updates&lt;br /&gt;
* Iceland materials fixes&lt;br /&gt;
&lt;br /&gt;
==2020.3.3==&lt;br /&gt;
* Fix accidental mouse picks while using a right-mouse-drag to look around&lt;br /&gt;
* Fix the download location we recommend in the 'setup root' dialog&lt;br /&gt;
&lt;br /&gt;
==2020.3.4==&lt;br /&gt;
* Handle more METAR strings correctly, including wind sensor failures&lt;br /&gt;
* Fix airmass velocity being applied to sub-models twice (eg, when dropping payloads in a cross-wind)&lt;br /&gt;
* Fix crash on shutdown in the properties code&lt;br /&gt;
* Spanish translation updates &lt;br /&gt;
* Disable flights to EGEL to avoid crashes in traffic code&lt;br /&gt;
&lt;br /&gt;
==2020.3.5==&lt;br /&gt;
* Change default Windows download location to %USERS%\FlightGear\Downloads, to avoid problems with Windows Defender blocking un-trusted applications from writing to Documents, which was the previous location.&lt;br /&gt;
* Fix a crash when returning to FlightGear from another application and scrolling or clicking&lt;br /&gt;
* Avoid crashing with UIUC-based aircraft such as the Wright Flyer&lt;br /&gt;
* Fix a crash on macOS when a joystick failed to open&lt;br /&gt;
* Update the macOS application icon&lt;br /&gt;
* Fix Nasal crash on reset&lt;br /&gt;
* Canvas: allow anisotropic filtering&lt;br /&gt;
* Larger, improved moon texture&lt;br /&gt;
* UFO speed goes to 11&lt;br /&gt;
* Fix taxiway markings disappearing in specific graphics settings&lt;br /&gt;
&lt;br /&gt;
==2020.3.6==&lt;br /&gt;
* Fixed crash downloading the default aircraft catalog&lt;br /&gt;
* Fix a hang starting at scenery in the ocean&lt;br /&gt;
* Fix incorrect sky &amp;amp; cockpit rendering with certain METAR values&lt;br /&gt;
* Add getting-started hints to the launcher (English only for now)&lt;br /&gt;
* Fix Shuttle AI scenarios&lt;br /&gt;
* Improvements to flight-planning mode&lt;br /&gt;
* Sun / moon scaling fixes&lt;br /&gt;
* Fix initial position of submodels&lt;br /&gt;
* macOS: warn if running with app translocation&lt;br /&gt;
* Windows: detect missing OpenGL drivers&lt;br /&gt;
* Fix UIUC FDM crashes&lt;br /&gt;
* Fix crash with invalid view numbers&lt;br /&gt;
* Catch FDM NaN errors more gracefully&lt;br /&gt;
* KAP-140 approach mode improvements&lt;br /&gt;
* Traffic+AI livery updates&lt;br /&gt;
&lt;br /&gt;
== 2020.3.7 ==&lt;br /&gt;
* Enable OSM2City buildings via TerraSync for the whole planet&lt;br /&gt;
* C172 bug-fixes and updates&lt;br /&gt;
* Improved regional material definitions for Europe, California&lt;br /&gt;
* Allow chat box to be re-positioned&lt;br /&gt;
* Fix crashes related to particle systems&lt;br /&gt;
* Fix selection of time-zone around Beijing&lt;br /&gt;
* Fix display of non-Latin1 strings in Canvas displays&lt;br /&gt;
* Fix Multi-player mode runway-start logic to select hold-short position correctly&lt;br /&gt;
* macOS: fix crash on text with certain fonts&lt;br /&gt;
* Fix launcher language selection when the UI language include a script specifier (eg zh-Hans-CN)&lt;br /&gt;
* Fix aircraft-id property when loading from a hangar ( https://sourceforge.net/p/flightgear/codetickets/2502/ )&lt;br /&gt;
* Improve checks for out-of-date Intel Graphics drivers on Windows&lt;br /&gt;
&lt;br /&gt;
== 2020.3.8 ==&lt;br /&gt;
* Fix behaviour of &amp;lt;code&amp;gt;&amp;lt;local&amp;gt;&amp;lt;/code&amp;gt; particle systems &lt;br /&gt;
* Fix autumn tree appearance&lt;br /&gt;
&lt;br /&gt;
== 2020.3.9 ==&lt;br /&gt;
* Fix crash in Swift&lt;br /&gt;
* Corrections to MP protocol timing&lt;br /&gt;
* Correct URL to FGData&lt;br /&gt;
* Fix bug in cache reload dialog&lt;br /&gt;
* Improvements to ATC dialog to display frequencies with 3 decimal places correctly&lt;br /&gt;
* Improve material definitions for Africa, Mediterranean regions&lt;br /&gt;
* Add updated ocean and water visual effects&lt;br /&gt;
&lt;br /&gt;
== 2020.3.10 ==&lt;br /&gt;
* Transponder: make standby mode work&lt;br /&gt;
* Launcher: pick up scenery and aircraft paths from the command line&lt;br /&gt;
* Launcher: store locations differently, to avoid problems when running multiple FlightGear versions and switching between them.&lt;br /&gt;
* Launcher: add 'restart on quit' option&lt;br /&gt;
* Fix NavCache errors loading ShapeFile data&lt;br /&gt;
* Fix NavCache errors when running multiple copies of FlightGear&lt;br /&gt;
&lt;br /&gt;
== 2020.3.11 ==&lt;br /&gt;
* Fix a crash introduced in 2020.3.10&lt;br /&gt;
* Improve error message when no aircraft search paths are available&lt;br /&gt;
* Fix a crash with misconfigured traffic taxi routes&lt;br /&gt;
* Update AI traffic schedules&lt;br /&gt;
&lt;br /&gt;
== 2020.3.12 ==&lt;br /&gt;
* Add aircraft directory name validation &lt;br /&gt;
* Add an extra step of antialiasing (8x)&lt;br /&gt;
* Add feature allowing aircraft to define custom fonts for osg::Text&lt;br /&gt;
* Add generic combined ALS procedural lights and Compositor lights&lt;br /&gt;
* Add new regional materials for Australia&lt;br /&gt;
* Fix Basic Weather producing invalid pressure altitudes&lt;br /&gt;
* Fix bug in path searching for previews&lt;br /&gt;
* Fix bug in sound system when approaching max-dist range&lt;br /&gt;
* Fix crashes after reset&lt;br /&gt;
* Fix crash when AI aircraft has invalid destination runway&lt;br /&gt;
* Fix Mapstructure error in RTE layer&lt;br /&gt;
* Fix &amp;lt;code&amp;gt;--view-offset&amp;lt;/code&amp;gt; to use the correct property&lt;br /&gt;
* HUD: make vertical gauges look the same as horizontal ones&lt;br /&gt;
* Improved Russian and Spanish translations&lt;br /&gt;
* Miscellaneous improvements to weather dialog&lt;br /&gt;
* Property browser: display values for folders in verbose mode &lt;br /&gt;
* Route manager: select correct waypoint when duplicate waypoints exist&lt;br /&gt;
* Update AI traffic schedules and add new AI models&lt;br /&gt;
&lt;br /&gt;
== 2020.3.13 ==&lt;br /&gt;
* Fix for the disappearing MP pilot list&lt;br /&gt;
* Fix JSBsim linear actuators behaving badly in certain conditions&lt;br /&gt;
&lt;br /&gt;
== 2020.3.14 ==&lt;br /&gt;
* Support for add-on paths&lt;br /&gt;
* Instant audio queue&lt;br /&gt;
* Allow canvas dialogs to not grab focus away from FG (more like how focus in PUI dialogs behaves)&lt;br /&gt;
&lt;br /&gt;
== 2020.3.15 ==&lt;br /&gt;
* Fix radio audio morse issue.&lt;br /&gt;
&lt;br /&gt;
== 2020.3.16 ==&lt;br /&gt;
* Fix audio indent issue.&lt;br /&gt;
&lt;br /&gt;
== 2020.3.17 ==&lt;br /&gt;
* Navradio: disable low-pass filter when changing selected freq or leaving GPS slave mode. When the selected frequency is changed or when leaving GPS slave mode, disable the low-pass filter applied to signal quality.&lt;br /&gt;
* Navradio: fix regression and optimize older code. Fix a little regression introduced in previous commit. Add: changing the standby frequency disabled the low-pass filter for the next call to updateReceiver(); this must happen when the selected frequency is changed but not when the standby frequency is changed.&lt;br /&gt;
* AP input: add property-path support to Inputs. Allow making the AP source indirect (via a string property), so that the actual source property can be configured or adjusted from a -set.xml, or at runtime.&lt;br /&gt;
* Replace displaying in Launcher `--on-ground=false` to `--in-air` for on final. The option`--on-ground=false` doesn't exist which can be misleading.&lt;br /&gt;
&lt;br /&gt;
== 2020.3.18 == &lt;br /&gt;
&amp;lt;!-- Just for placeholder, someone will need to fix this --&amp;gt;&lt;br /&gt;
* Added photoscenery capability.&lt;br /&gt;
* New basic autopilot system.&lt;br /&gt;
* Add AI submodel collision&lt;br /&gt;
* Fix crash with a 'between' type constraint in Navigraph procedure files&lt;br /&gt;
* Fix crash with invalid METAR strings&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
{{Appendix}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:FlightGear changelogs‎]]&lt;br /&gt;
[[pl:Changelog_2020.3]]&lt;br /&gt;
[[Zh:2020.3]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=User:D-ECHO&amp;diff=135471</id>
		<title>User:D-ECHO</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=User:D-ECHO&amp;diff=135471"/>
		<updated>2022-09-05T11:05:28Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: /* Zenith Air */ Remove real name&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== List of aircraft ==&lt;br /&gt;
This is a list of all aircraft in FGAddon which I either currently maintain or started:&lt;br /&gt;
&lt;br /&gt;
==== Alexander Schleicher Segelflugzeugbau ====&lt;br /&gt;
&lt;br /&gt;
* [[Schleicher Ka 6|Ka6]]&lt;br /&gt;
* [[ASK13]], originally created by Patrice Poly, who doesn't seem to be around anymore, so I took over maintaining the fgaddon version as well as improving the aircraft.&lt;br /&gt;
*[[ASK21]], originally created by Heiko Schulz and AJ MacLeod, from 2017 on developed by Viktor Radnai, Gilberto Agostinho as well as Herbert Wagner, Thomas Polzer and me.&lt;br /&gt;
&lt;br /&gt;
*[[ASG 29|ASG29]]&lt;br /&gt;
&lt;br /&gt;
==== Diamond Aircraft ====&lt;br /&gt;
&lt;br /&gt;
*[[Diamond HK36]]&lt;br /&gt;
*[[Diamond_DA40|Diamond DA40NG]], not to be confused with the (other) FGAddon DA40 found under [https://sourceforge.net/p/flightgear/fgaddon/HEAD/tree/trunk/Aircraft/Diamond-Da40/ this link].&lt;br /&gt;
&lt;br /&gt;
==== Zenith Air ====&lt;br /&gt;
*[[Zenith Air CH650]], converted from an X-Plane addon by hydroz (with his kind permission) with help by legoboyvdlp&lt;br /&gt;
*[[CH750|Zenith Air CH750 STOL]], same as with the CH650&lt;br /&gt;
&lt;br /&gt;
==== Other ====&lt;br /&gt;
&lt;br /&gt;
*[https://sourceforge.net/p/flightgear/fgaddon/HEAD/tree/trunk/Aircraft/Silent2Electro/ Alisport Silent2Electro]&lt;br /&gt;
*[https://sourceforge.net/p/flightgear/fgaddon/HEAD/tree/trunk/Aircraft/c140/ Cessna 140]&lt;br /&gt;
*[[Dornier 228NG]]&lt;br /&gt;
*[https://sourceforge.net/p/flightgear/fgaddon/HEAD/tree/trunk/Aircraft/Libelle/ Glasflügel Libelle]&lt;br /&gt;
*[https://sourceforge.net/p/flightgear/fgaddon/HEAD/tree/trunk/Aircraft/Dragonfly Moyes Dragonfly]&lt;br /&gt;
&lt;br /&gt;
*[[Pipistrel Alpha Electro|Pipistrel Alpha Electro / Pipistrel Velis Electro]]&lt;br /&gt;
*[[QSeries]]&lt;br /&gt;
&lt;br /&gt;
*[https://sourceforge.net/p/flightgear/fgaddon/HEAD/tree/trunk/Aircraft/LS4 Rolladen-Schneider LS4]&lt;br /&gt;
&lt;br /&gt;
*[https://sourceforge.net/p/flightgear/fgaddon/HEAD/tree/trunk/Aircraft/LS8 Rolladen-Schneider LS8]&lt;br /&gt;
&lt;br /&gt;
*[https://sourceforge.net/p/flightgear/fgaddon/HEAD/tree/trunk/Aircraft/SG38 SG38]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Template:Nasal_Navigation&amp;diff=135260</id>
		<title>Template:Nasal Navigation</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Template:Nasal_Navigation&amp;diff=135260"/>
		<updated>2022-06-28T16:57:00Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;{{Informative template|1=&lt;br /&gt;
Navigation box for core [[Nasal]] articles.&lt;br /&gt;
&lt;br /&gt;
== Usage ==&lt;br /&gt;
Put this at the top of the article:&lt;br /&gt;
 {{obr}}'''Nasal Navigation'''{{cbr}}&lt;br /&gt;
&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Navigation templates]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&amp;lt;includeonly&amp;gt;{{nocat|{{{nocat|}}}|Nasal}}&amp;lt;/includeonly&amp;gt;{{forum|30|Nasal Scripting}}&lt;br /&gt;
&lt;br /&gt;
{{Sidebar with collapsible lists&lt;br /&gt;
| name     = Nasal Navigation&lt;br /&gt;
| pretitle = [[File:Nasallogo3.png|link=Nasal]]&lt;br /&gt;
| title    = [[Nasal|Nasal scripting]]&lt;br /&gt;
| expanded = {{{expanded|}}}&lt;br /&gt;
&lt;br /&gt;
| content1   = &lt;br /&gt;
* [[What is Nasal]]?&lt;br /&gt;
* [[Nasal success stories|Success stories]]&lt;br /&gt;
* [[Nasal FAQ]]&lt;br /&gt;
* [[Nasal Snippets]]&lt;br /&gt;
* [[Howto:Syntax highlighting for Nasal]]&lt;br /&gt;
&lt;br /&gt;
| list2title = Tools and utilities&lt;br /&gt;
| list2      = [[Nasal Console|Console]] &amp;amp;bull; [[Interactive Nasal Console|REPL Console]] &amp;amp;bull; [[Nasal Browser|Browser]]&lt;br /&gt;
&lt;br /&gt;
| list3title = Getting started&lt;br /&gt;
| list3      =&lt;br /&gt;
* [[Nasal Best Practices]]&lt;br /&gt;
* [[Nasal for C++ programmers]]&lt;br /&gt;
* [[Creating new Nasal scripts]]&lt;br /&gt;
* [[Nasal Hello World]]&lt;br /&gt;
* [[Howto:Create a new Nasal module]]&lt;br /&gt;
* [[Using Nasal functions]]&lt;br /&gt;
* [[Nasal Variables]]&lt;br /&gt;
* [[Nasal Namespaces]]&lt;br /&gt;
* [[Howto:Understand Namespaces and Methods|Namespace and Methods]]&lt;br /&gt;
* [[Nasal Namespaces in-depth]]&lt;br /&gt;
* [[Nasal Conditionals]]&lt;br /&gt;
* [[Nasal Loops]]&lt;br /&gt;
* [[Numbers in Nasal]]&lt;br /&gt;
* [[Nasal Operators]]&lt;br /&gt;
* [[Howto:Use vectors and foreach loops to write shorter code]]&lt;br /&gt;
* [[Howto:Start using vectors and hashes in Nasal]]&lt;br /&gt;
* [[Nasal library]] ([[Nasal library#Core library functions|core]]/[[Nasal library#Extension functions|extension]] functions)&lt;br /&gt;
** [[Nasal library/clipboard|&amp;lt;code&amp;gt;clipboard&amp;lt;/code&amp;gt; namespace]]&lt;br /&gt;
** [[Nasal library/debug|&amp;lt;code&amp;gt;debug&amp;lt;/code&amp;gt; namespace]]&lt;br /&gt;
** [[Nasal library/geo|&amp;lt;code&amp;gt;geo&amp;lt;/code&amp;gt; namespace]]&lt;br /&gt;
** [[Nasal library/io|&amp;lt;code&amp;gt;io&amp;lt;/code&amp;gt; namespace]]&lt;br /&gt;
** [[Nasal library/math|&amp;lt;code&amp;gt;math&amp;lt;/code&amp;gt; namespace]]&lt;br /&gt;
** [[Nasal library/os.path|&amp;lt;code&amp;gt;os.path&amp;lt;/code&amp;gt; namespace]]&lt;br /&gt;
** [[Nasal library/props|&amp;lt;code&amp;gt;props&amp;lt;/code&amp;gt; namespace]]&lt;br /&gt;
** [[Nasal String Manipulation|&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt; namespace]]&lt;br /&gt;
** [[Nasal library/flightplan|flightplan library]]&lt;br /&gt;
* [[Howto:Write a parser in Nasal]]&lt;br /&gt;
* [[Nasal Flightplan]]&lt;br /&gt;
* [[Object oriented programming in Nasal|OOP Introduction]]&lt;br /&gt;
* [[Object Oriented Programming with Nasal]]&lt;br /&gt;
* [[Nasal Callbacks Explained]]&lt;br /&gt;
* [[Exception handling with Nasal]]&lt;br /&gt;
* [[Using listeners and signals with Nasal]]&lt;br /&gt;
* [[Developing and debugging Nasal code]]&lt;br /&gt;
&lt;br /&gt;
| list4title = Advanced Tutorials&lt;br /&gt;
| list4      =&lt;br /&gt;
* [[Caching Nasal function calls]]&lt;br /&gt;
* [[Nasal Unit Testing Framework]] (WIP)&lt;br /&gt;
* [[Nasal Meta-Programming]]&lt;br /&gt;
* [[A GPX flight logger in Nasal]]&lt;br /&gt;
* [[Multiplayer scripting in Nasal]]&lt;br /&gt;
* [[Howto:Making HTTP Requests from Nasal]]&lt;br /&gt;
* [[Howto:Transmit properties over MP]]&lt;br /&gt;
* [[Howto:Terrain sampling in Nasal]]&lt;br /&gt;
* [[Howto:Create a new system in Nasal]]&lt;br /&gt;
* [[Howto:Load a Nasal file at runtime]]&lt;br /&gt;
* [[Howto:Control the route manager in Nasal]]&lt;br /&gt;
* [[Howto:Get a number of elevation offsets for a number of objects]]&lt;br /&gt;
* [[Howto:Nasal in scenery object XML files]]&lt;br /&gt;
* [[Howto:Create animation XML files from Nasal]]&lt;br /&gt;
* [[Howto:Port I/O from Nasal]]&lt;br /&gt;
* [[Howto:Continuation-passing style programming in Nasal]]&lt;br /&gt;
* [[Howto:Start worker threads using listeners in Nasal]]&lt;br /&gt;
* [[Howto:Developing a DSL interpreter in Nasal]]&lt;br /&gt;
* [[Howto:Nasal Metaprogramming]]&lt;br /&gt;
* [[Nasal/JavaScript Subset]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Nasal Internals}}&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_library/flightplan&amp;diff=135259</id>
		<title>Nasal library/flightplan</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_library/flightplan&amp;diff=135259"/>
		<updated>2022-06-28T16:55:51Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: Add redirect under Nasal library for flightplan&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#redirect[[Nasal_Flightplan]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Software_testing&amp;diff=135078</id>
		<title>Software testing</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Software_testing&amp;diff=135078"/>
		<updated>2022-05-16T11:35:40Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: /* Running the test suite */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Note|There’s already the test_suite in {{fg src file|path=test_suite}} using [[Cppunit effort|CppUnit]], thanks to some hard work by [[User:Bugman|Edward]]. We need more tests written for it, submissions welcome. (Pick an area of interest)&amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/36972720/&amp;lt;/ref&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
{{See also|Cppunit effort}}&lt;br /&gt;
&lt;br /&gt;
The FlightGear source code and data are tested by the FlightGear developers using a number of tools.  This includes automated testing via unit tests in [[SimGear]] and a full test suite with multiple test categories in the [[FlightGear Git|flightgear repository]], as well as manual in-sim testing.  Writing tests is one of the best ways to jump into FlightGear development.&lt;br /&gt;
&lt;br /&gt;
One improving area is unit-testing: because of which, certain areas and features (eg, carrier start) now ‘can’t break’. As we add more such areas (eg Multi-player, AI, protocols and replay are all possible), we increase the baseline quality, and also have a clearer idea when we make incompatible changes. (The idea being we capture the ‘supported API’ in the tests: when an aircraft deviates from that, we can decide to add another test case, fix the aircraft, etc). Of course, there’s some pretty major areas where Automated Testing Is Hard (TM).&amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/37078825/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== SimGear ==&lt;br /&gt;
&lt;br /&gt;
The [[SimGear]] sources are checked via unit testing.  This is implemented using the CMake CTest unit testing infrastructure.  A number of tests are currently implemented using the BOOST unit testing infrastructure tied to the build system using CTest, however this should be avoided when writing tests as there is a shift towards eliminating BOOST by the FlightGear developers.&lt;br /&gt;
&lt;br /&gt;
=== Building and running the SimGear tests ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ make&lt;br /&gt;
$ ctest&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== FlightGear ==&lt;br /&gt;
&lt;br /&gt;
Testing of the [[FlightGear Git|flightgear sources]] is via a comprehensive test suite implemented using [https://www.freedesktop.org/wiki/Software/cppunit/ CppUnit], a port of the famous JUnit framework.&lt;br /&gt;
&lt;br /&gt;
=== Building the test suite ===&lt;br /&gt;
&lt;br /&gt;
To run the tests you will need to build FlightGear from source using cmake.  See [[Building FlightGear]] for details.&lt;br /&gt;
&lt;br /&gt;
Once you have your cmake build environment do the following:&lt;br /&gt;
# Change to your FlightGear build directory&lt;br /&gt;
# Enable building the tests by setting a cmake variable:  &amp;lt;code&amp;gt;cmake -LBUILD_TESTING=ON .&amp;lt;/code&amp;gt;&lt;br /&gt;
# Ensure the &amp;lt;code&amp;gt;[[$FG ROOT|$FG_ROOT]]&amp;lt;/code&amp;gt; environment variable points to fgdata e.g. &amp;lt;code&amp;gt;$FG_INSTALL_DIR/share/fgdata&amp;lt;/code&amp;gt;&lt;br /&gt;
# Build the test suite:  &amp;lt;code&amp;gt;make test_suite&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will also run the full test suite (see below), because you will typically want to write a test and then immediately compile and run it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On a Windows MSVC-based build environment, after generating files with cmake, run the following code:&lt;br /&gt;
# cmake --build . --config RelWithDebInfo --target test_suite/test_suite&lt;br /&gt;
&lt;br /&gt;
=== Running the test suite ===&lt;br /&gt;
&lt;br /&gt;
To run the test suite, simply run &amp;lt;code&amp;gt;./test_suite/fgfs_test_suite&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will run the full test suite and print a Synopsis of results similar to the following:&lt;br /&gt;
&lt;br /&gt;
 Synopsis&lt;br /&gt;
 ========&lt;br /&gt;
 &lt;br /&gt;
 System/functional tests ....................................... [ OK ]&lt;br /&gt;
 Unit tests .................................................... [ OK ]&lt;br /&gt;
 Simgear unit tests ............................................ [ OK ]&lt;br /&gt;
 FGData tests .................................................. [ OK ]&lt;br /&gt;
 Synopsis ...................................................... [ OK ]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You can also run individual test cases.  Run &amp;lt;code&amp;gt;./test_suite/fgfs_test_suite -h&amp;lt;/code&amp;gt; to see the various options&lt;br /&gt;
&lt;br /&gt;
For example, fgfs_test_suite --log-level=alert -d -u GPSTests will run the GPS unit tests while displaying the output.&lt;br /&gt;
&lt;br /&gt;
=== Why write unit tests? ===&lt;br /&gt;
&lt;br /&gt;
A well tested piece of software will have a much lower bug count/load.  An extensive test suite with '''unit tests''', system/functional tests, GUI tests, installer tests, and other categories of tests can significantly help in this regard.&lt;br /&gt;
&lt;br /&gt;
The benefits of not just chasing clear &amp;quot;wins&amp;quot; are great:  An awesome learning experience for new developers; the ability to catch latent, unreported bugs; making it easier to refactor current code by creating a safety net; making it easier for current developers to accept new contributions (when accompanied with passing tests); helping other test writers by contributing to the common test suite infrastructure; and being able to easily check for memory leaks or other issues via Valgrind.&amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/36977686/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you are a new developer, just jump in and write any test!  It does not need to catch a bug. Do whatever how ever you wish! Just dive in this shallow end and you'll see that the water is not cold.&lt;br /&gt;
&lt;br /&gt;
Writing a test as a safety net. You write the test to pass, make your changes, then make sure that the test still passes.  Then you push both the test and core changes.&amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/36977465/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It'd be better jumping into a specific area of interest to you, and submitting merge-requests. That would naturally trigger some C++ feedback when reviewed but we aren’t looking for perfection here, more to increase the overall pool of knowledge of what best-practice looks like, even if a given commit is less than perfect.&lt;br /&gt;
&lt;br /&gt;
I,e It’s more important to have 10 or 20 people actively contributing correct-and-reasonable code than three people contributing absolutely perfect, micro-optimised C++. &amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/36951247/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Benefits of unit testing ===&lt;br /&gt;
There are lots of benefits to writing tests that pass.&lt;br /&gt;
&lt;br /&gt;
Benefits include :&lt;br /&gt;
&lt;br /&gt;
* Learning!  New developers can learn a ton from writing a number of passing tests in the area they are interested in. This is one of the quickest ways to learn about a pre-existing and mature code base.  You have zero worries about breaking things.  This is diving in the shallow end.&lt;br /&gt;
&lt;br /&gt;
* Latent bug uncovering.  For every ten tests you write expecting them to pass, one will probably fail.  Or at least uncover unexpected behavior that can be improved.&lt;br /&gt;
&lt;br /&gt;
* Refactoring.  If we had 10,000 passing tests (assuming universal test coverage), large scale refactoring of the entire code base would be quick and reliable.  It would enable refactoring on a scale currently unimaginable. I cannot emphasize enough how much of a benefit this would be.&lt;br /&gt;
&lt;br /&gt;
* Developer turnover.  Again if we had 10,000 passing tests (assuming universal test coverage), it would encourage new developers.  This is because the fear of breaking something is removed.  It is a total safety net.  It also would give existing developers peace of mind when a new developer is touching one of the dark parts of FlightGear that no current developer understands (there are plenty of those) .&lt;br /&gt;
&lt;br /&gt;
* Test suite infrastructure.  The more passing tests written, the better the test suite infrastructure will become.  We can already do a lot.  But the addition of more passing tests will help other test writers.&lt;br /&gt;
&lt;br /&gt;
* Memory checking.  Running a single test through Valgrind is amazing.  Running FlightGear through Valgrind is close to impossible.  Passing tests can be written to catch memory leaks!&lt;br /&gt;
&lt;br /&gt;
* Low code quality and standards.  This is related to the learning point.  As long as a test compiles on all OSes without warning, it passes, and Valgrind gives you an ok, it is good enough.  You dont need to be a C++ expert to dive into this shallow end of the pool.&lt;br /&gt;
&lt;br /&gt;
=== Bootstrapping completely new tests ===&lt;br /&gt;
To start diving straight into the test suite code, firstly copy what has been done in this commit:  {{repo link&lt;br /&gt;
| site   = sf&lt;br /&gt;
| user = edauvergne&lt;br /&gt;
| repo   = flightgear&lt;br /&gt;
| commit = 8474df&lt;br /&gt;
| view   = commit&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Just modify all names for a JSBSim test (or any other test fixture you&lt;br /&gt;
want to code).  You should then be able to compile and check that your&lt;br /&gt;
new testDummy() test passes as expected.  You can then slowly build up&lt;br /&gt;
from this basic infrastructure as you learn the fgfs internals, c++,&lt;br /&gt;
and git skills required for implementing your test on your fork's new&lt;br /&gt;
development branch :)&lt;br /&gt;
&lt;br /&gt;
=== Headless testing ===&lt;br /&gt;
{{Main article|FlightGear Headless}}&lt;br /&gt;
&lt;br /&gt;
For an FDM+systems test, we should run FG without a renderer (which is what the test_suite does), to benchmark the pure C++ performance of whatever system it is we care about (FDM or whatever). But this is not really worth doing anyway, since a few hours playing with ‘perf’ on Linux / Instruments on macOS will show you that 80% of our CPU time is spent in OSG + the GL drivers, and hence Amdhal’s law will always get you.&amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/36977666/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Graphics testing ===&lt;br /&gt;
{{See also|FlightGear Benchmark}}&lt;br /&gt;
&lt;br /&gt;
The other thing is to setup some test-case scenes where you can quickly measure differences and compare via screenshots. The brain/eye/memory are very bad at this stuff, setup something you can load from the command line via a script to test old/new versions, if possible. &amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/36959002/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, a test would would be a .[[fgfsrc]] that makes:&lt;br /&gt;
* c172p at some parking in a detailed airport;&lt;br /&gt;
* camera looking at it in specific direction with specific FOV;&lt;br /&gt;
* AW with specific METARs around (if not possible, BW with specific METAR);&lt;br /&gt;
* fixed rendering settings (several variants may be needed for renderers and threading modes) &amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/36975122/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can already load a [[Instant Replay|replay tape]] on startup, however, which is good for testing rendering (scenery, loading) performance, since the FDM is not involved, nor is the user-interface.&lt;br /&gt;
&lt;br /&gt;
But essentially any and all of the methods proposed can be done here with small amounts of shell-script + Nasal hacking I think, and any of them would be welcome additions. For lower-level tests run by developers, the unit-test framework is great (i.e ‘does the API call produce the right results in the system’), but a smoke-test that regular users can run would be ideal. &lt;br /&gt;
&lt;br /&gt;
A rendering performance would likely do:&lt;br /&gt;
&lt;br /&gt;
* select some particular rendering settings (clouds, draw distance, etc)&lt;br /&gt;
* run a saved fgtape recording&lt;br /&gt;
* record the mean/min/max FPS during this and save it in some text file / copy to the clipboard&lt;br /&gt;
&lt;br /&gt;
So yes, if anyone wants to work on the above, the code is all there, please jump in and start hacking - I don’t think it needs any more from the core code, but as ever, please just ask if it does.&amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/36975213/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, describing a /rendering/ test (to establish FPS) - the advantage of a replay tape is the actual position (and therefore what is rendered) will be 100% consistent acorss different computers.&lt;br /&gt;
&lt;br /&gt;
Keep in mind that the CPU use of the FDM+systems is typically &amp;lt; 10% of our total CPU use, even when running OSG single-threaded, so for a rendering performance test, whether the FD is run or not is probably noise compared to other things that do run (Nasal, Canvas for example)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Also, Multi-monitor setup is not tested so commonly unfortunately. &amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/36904782/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Fgdata ==&lt;br /&gt;
=== Nasal scripting (comments) ===&lt;br /&gt;
{{WIP}}&lt;br /&gt;
&lt;br /&gt;
The now builtin CppUnit framework can obviously solve all the issues&lt;br /&gt;
identified in the old [[Nasal Unit Testing Framework]] wiki article and the discussions it points to&lt;br /&gt;
and provide the full framework required.&amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/36990615/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
have some very simple tests running now for the route-manager, which rely on Nasal. we're skipping a few of the bigger Nasal modules (local-weather, jetways) and have a few lingering issues in some other modules but the basic concept is working. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A very interesting further step, which you might wish to discuss with Edward, is writing test checks *in* Nasal, since this could be quite a fast way to test some area of the code. There’s several ways that could work, and I don’t know if Edward has always planned something around this, so I won’t preempt that conversation.&lt;br /&gt;
&amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/36764781/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
we have route-manager tests which validate route_manager.nas is working correctly, and we have Canavs tests ({{fg src file|path=test_suite/simgear_tests/canvas|}}) which poke the Nasal API. &amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/36991200/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We need more FGData testing via the test suite.&lt;br /&gt;
&lt;br /&gt;
Adding the CppUnit assertions to Nasal, is the task James has been suggesting he would do, so others can write tests in pure Nasal.&lt;br /&gt;
&lt;br /&gt;
The other piece is some C++ code to scan a directory for files matching a pattern, eg test_XYZ.nas, and to run each of those automatically.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The idea for testing Nasal would be that you write a small CppUnit&lt;br /&gt;
interface in c++ in $FG_SRC/test_suite/*_tests/ (the FGData Nasal&lt;br /&gt;
testing would be in a fgdata_tests/ directory).  This would register&lt;br /&gt;
each test which points to the script in&lt;br /&gt;
$FG_SRC/test_suite/shared_data/nasal/, and the setUp() and tearDown()&lt;br /&gt;
functions would use helper functions in the fgtest namespace to start&lt;br /&gt;
and stop Nasal.  The Nasal scripts could then call the CppUnit&lt;br /&gt;
assertion macros wrapped up as Nasal functions for communicating&lt;br /&gt;
failures and errors to the test suite. &amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/36991150/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Scanning for scripts is a great idea.  Then developers (core and content) could write tests in pure Nasal.&lt;br /&gt;
&lt;br /&gt;
However all scripts found and executed will be seen as a single test within the test suite.  So maybe we should have a $FG_SRC/test_suite/nasal_staging/ directory for initial development of such auto-scanned scripts.  But then we have someone shift them into $FG_SRC/test_suite/system_tests/, $FG_SRC/test_suite/unit_tests/, or $FG_SRC/test_suite/fgdata_tests/ later on?  That would give better diagnostics and would avoid long-term clutter.&amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/36991198/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* First we should probably hard code tests into the C++ framework. The CppUnit assertion macros will have to be wrapped up as Nasal functions for this.&lt;br /&gt;
* Then implement the scanning code as we need some CMake magic (probably using file(COPY, ...)).&lt;br /&gt;
* Finally work out if and how we need to improve the Nasal debugging output.&lt;br /&gt;
&lt;br /&gt;
the code could go into a subdirectory in $FG_SRC/test_suite/fgdata_tests/, and the Nasal script in $FG_SRC/test_suite/shared_data/nasal/.&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
{{Appendix}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Core development]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Software_testing&amp;diff=135077</id>
		<title>Software testing</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Software_testing&amp;diff=135077"/>
		<updated>2022-05-16T10:53:06Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: /* Building the test suite */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Note|There’s already the test_suite in {{fg src file|path=test_suite}} using [[Cppunit effort|CppUnit]], thanks to some hard work by [[User:Bugman|Edward]]. We need more tests written for it, submissions welcome. (Pick an area of interest)&amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/36972720/&amp;lt;/ref&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
{{See also|Cppunit effort}}&lt;br /&gt;
&lt;br /&gt;
The FlightGear source code and data are tested by the FlightGear developers using a number of tools.  This includes automated testing via unit tests in [[SimGear]] and a full test suite with multiple test categories in the [[FlightGear Git|flightgear repository]], as well as manual in-sim testing.  Writing tests is one of the best ways to jump into FlightGear development.&lt;br /&gt;
&lt;br /&gt;
One improving area is unit-testing: because of which, certain areas and features (eg, carrier start) now ‘can’t break’. As we add more such areas (eg Multi-player, AI, protocols and replay are all possible), we increase the baseline quality, and also have a clearer idea when we make incompatible changes. (The idea being we capture the ‘supported API’ in the tests: when an aircraft deviates from that, we can decide to add another test case, fix the aircraft, etc). Of course, there’s some pretty major areas where Automated Testing Is Hard (TM).&amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/37078825/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== SimGear ==&lt;br /&gt;
&lt;br /&gt;
The [[SimGear]] sources are checked via unit testing.  This is implemented using the CMake CTest unit testing infrastructure.  A number of tests are currently implemented using the BOOST unit testing infrastructure tied to the build system using CTest, however this should be avoided when writing tests as there is a shift towards eliminating BOOST by the FlightGear developers.&lt;br /&gt;
&lt;br /&gt;
=== Building and running the SimGear tests ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ make&lt;br /&gt;
$ ctest&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== FlightGear ==&lt;br /&gt;
&lt;br /&gt;
Testing of the [[FlightGear Git|flightgear sources]] is via a comprehensive test suite implemented using [https://www.freedesktop.org/wiki/Software/cppunit/ CppUnit], a port of the famous JUnit framework.&lt;br /&gt;
&lt;br /&gt;
=== Building the test suite ===&lt;br /&gt;
&lt;br /&gt;
To run the tests you will need to build FlightGear from source using cmake.  See [[Building FlightGear]] for details.&lt;br /&gt;
&lt;br /&gt;
Once you have your cmake build environment do the following:&lt;br /&gt;
# Change to your FlightGear build directory&lt;br /&gt;
# Enable building the tests by setting a cmake variable:  &amp;lt;code&amp;gt;cmake -LBUILD_TESTING=ON .&amp;lt;/code&amp;gt;&lt;br /&gt;
# Ensure the &amp;lt;code&amp;gt;[[$FG ROOT|$FG_ROOT]]&amp;lt;/code&amp;gt; environment variable points to fgdata e.g. &amp;lt;code&amp;gt;$FG_INSTALL_DIR/share/fgdata&amp;lt;/code&amp;gt;&lt;br /&gt;
# Build the test suite:  &amp;lt;code&amp;gt;make test_suite&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will also run the full test suite (see below), because you will typically want to write a test and then immediately compile and run it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On a Windows MSVC-based build environment, after generating files with cmake, run the following code:&lt;br /&gt;
# cmake --build . --config RelWithDebInfo --target test_suite/test_suite&lt;br /&gt;
&lt;br /&gt;
=== Running the test suite ===&lt;br /&gt;
&lt;br /&gt;
To run the test suite, simply run &amp;lt;code&amp;gt;./test_suite/fgfs_test_suite&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will run the full test suite and print a Synopsis of results similar to the following:&lt;br /&gt;
&lt;br /&gt;
 Synopsis&lt;br /&gt;
 ========&lt;br /&gt;
 &lt;br /&gt;
 System/functional tests ....................................... [ OK ]&lt;br /&gt;
 Unit tests .................................................... [ OK ]&lt;br /&gt;
 Simgear unit tests ............................................ [ OK ]&lt;br /&gt;
 FGData tests .................................................. [ OK ]&lt;br /&gt;
 Synopsis ...................................................... [ OK ]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You can also run individual test cases.  Run &amp;lt;code&amp;gt;./test_suite/fgfs_test_suite -h&amp;lt;/code&amp;gt; to see the various options&lt;br /&gt;
&lt;br /&gt;
=== Why write unit tests? ===&lt;br /&gt;
&lt;br /&gt;
A well tested piece of software will have a much lower bug count/load.  An extensive test suite with '''unit tests''', system/functional tests, GUI tests, installer tests, and other categories of tests can significantly help in this regard.&lt;br /&gt;
&lt;br /&gt;
The benefits of not just chasing clear &amp;quot;wins&amp;quot; are great:  An awesome learning experience for new developers; the ability to catch latent, unreported bugs; making it easier to refactor current code by creating a safety net; making it easier for current developers to accept new contributions (when accompanied with passing tests); helping other test writers by contributing to the common test suite infrastructure; and being able to easily check for memory leaks or other issues via Valgrind.&amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/36977686/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you are a new developer, just jump in and write any test!  It does not need to catch a bug. Do whatever how ever you wish! Just dive in this shallow end and you'll see that the water is not cold.&lt;br /&gt;
&lt;br /&gt;
Writing a test as a safety net. You write the test to pass, make your changes, then make sure that the test still passes.  Then you push both the test and core changes.&amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/36977465/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It'd be better jumping into a specific area of interest to you, and submitting merge-requests. That would naturally trigger some C++ feedback when reviewed but we aren’t looking for perfection here, more to increase the overall pool of knowledge of what best-practice looks like, even if a given commit is less than perfect.&lt;br /&gt;
&lt;br /&gt;
I,e It’s more important to have 10 or 20 people actively contributing correct-and-reasonable code than three people contributing absolutely perfect, micro-optimised C++. &amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/36951247/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Benefits of unit testing ===&lt;br /&gt;
There are lots of benefits to writing tests that pass.&lt;br /&gt;
&lt;br /&gt;
Benefits include :&lt;br /&gt;
&lt;br /&gt;
* Learning!  New developers can learn a ton from writing a number of passing tests in the area they are interested in. This is one of the quickest ways to learn about a pre-existing and mature code base.  You have zero worries about breaking things.  This is diving in the shallow end.&lt;br /&gt;
&lt;br /&gt;
* Latent bug uncovering.  For every ten tests you write expecting them to pass, one will probably fail.  Or at least uncover unexpected behavior that can be improved.&lt;br /&gt;
&lt;br /&gt;
* Refactoring.  If we had 10,000 passing tests (assuming universal test coverage), large scale refactoring of the entire code base would be quick and reliable.  It would enable refactoring on a scale currently unimaginable. I cannot emphasize enough how much of a benefit this would be.&lt;br /&gt;
&lt;br /&gt;
* Developer turnover.  Again if we had 10,000 passing tests (assuming universal test coverage), it would encourage new developers.  This is because the fear of breaking something is removed.  It is a total safety net.  It also would give existing developers peace of mind when a new developer is touching one of the dark parts of FlightGear that no current developer understands (there are plenty of those) .&lt;br /&gt;
&lt;br /&gt;
* Test suite infrastructure.  The more passing tests written, the better the test suite infrastructure will become.  We can already do a lot.  But the addition of more passing tests will help other test writers.&lt;br /&gt;
&lt;br /&gt;
* Memory checking.  Running a single test through Valgrind is amazing.  Running FlightGear through Valgrind is close to impossible.  Passing tests can be written to catch memory leaks!&lt;br /&gt;
&lt;br /&gt;
* Low code quality and standards.  This is related to the learning point.  As long as a test compiles on all OSes without warning, it passes, and Valgrind gives you an ok, it is good enough.  You dont need to be a C++ expert to dive into this shallow end of the pool.&lt;br /&gt;
&lt;br /&gt;
=== Bootstrapping completely new tests ===&lt;br /&gt;
To start diving straight into the test suite code, firstly copy what has been done in this commit:  {{repo link&lt;br /&gt;
| site   = sf&lt;br /&gt;
| user = edauvergne&lt;br /&gt;
| repo   = flightgear&lt;br /&gt;
| commit = 8474df&lt;br /&gt;
| view   = commit&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Just modify all names for a JSBSim test (or any other test fixture you&lt;br /&gt;
want to code).  You should then be able to compile and check that your&lt;br /&gt;
new testDummy() test passes as expected.  You can then slowly build up&lt;br /&gt;
from this basic infrastructure as you learn the fgfs internals, c++,&lt;br /&gt;
and git skills required for implementing your test on your fork's new&lt;br /&gt;
development branch :)&lt;br /&gt;
&lt;br /&gt;
=== Headless testing ===&lt;br /&gt;
{{Main article|FlightGear Headless}}&lt;br /&gt;
&lt;br /&gt;
For an FDM+systems test, we should run FG without a renderer (which is what the test_suite does), to benchmark the pure C++ performance of whatever system it is we care about (FDM or whatever). But this is not really worth doing anyway, since a few hours playing with ‘perf’ on Linux / Instruments on macOS will show you that 80% of our CPU time is spent in OSG + the GL drivers, and hence Amdhal’s law will always get you.&amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/36977666/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Graphics testing ===&lt;br /&gt;
{{See also|FlightGear Benchmark}}&lt;br /&gt;
&lt;br /&gt;
The other thing is to setup some test-case scenes where you can quickly measure differences and compare via screenshots. The brain/eye/memory are very bad at this stuff, setup something you can load from the command line via a script to test old/new versions, if possible. &amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/36959002/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, a test would would be a .[[fgfsrc]] that makes:&lt;br /&gt;
* c172p at some parking in a detailed airport;&lt;br /&gt;
* camera looking at it in specific direction with specific FOV;&lt;br /&gt;
* AW with specific METARs around (if not possible, BW with specific METAR);&lt;br /&gt;
* fixed rendering settings (several variants may be needed for renderers and threading modes) &amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/36975122/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can already load a [[Instant Replay|replay tape]] on startup, however, which is good for testing rendering (scenery, loading) performance, since the FDM is not involved, nor is the user-interface.&lt;br /&gt;
&lt;br /&gt;
But essentially any and all of the methods proposed can be done here with small amounts of shell-script + Nasal hacking I think, and any of them would be welcome additions. For lower-level tests run by developers, the unit-test framework is great (i.e ‘does the API call produce the right results in the system’), but a smoke-test that regular users can run would be ideal. &lt;br /&gt;
&lt;br /&gt;
A rendering performance would likely do:&lt;br /&gt;
&lt;br /&gt;
* select some particular rendering settings (clouds, draw distance, etc)&lt;br /&gt;
* run a saved fgtape recording&lt;br /&gt;
* record the mean/min/max FPS during this and save it in some text file / copy to the clipboard&lt;br /&gt;
&lt;br /&gt;
So yes, if anyone wants to work on the above, the code is all there, please jump in and start hacking - I don’t think it needs any more from the core code, but as ever, please just ask if it does.&amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/36975213/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, describing a /rendering/ test (to establish FPS) - the advantage of a replay tape is the actual position (and therefore what is rendered) will be 100% consistent acorss different computers.&lt;br /&gt;
&lt;br /&gt;
Keep in mind that the CPU use of the FDM+systems is typically &amp;lt; 10% of our total CPU use, even when running OSG single-threaded, so for a rendering performance test, whether the FD is run or not is probably noise compared to other things that do run (Nasal, Canvas for example)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Also, Multi-monitor setup is not tested so commonly unfortunately. &amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/36904782/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Fgdata ==&lt;br /&gt;
=== Nasal scripting (comments) ===&lt;br /&gt;
{{WIP}}&lt;br /&gt;
&lt;br /&gt;
The now builtin CppUnit framework can obviously solve all the issues&lt;br /&gt;
identified in the old [[Nasal Unit Testing Framework]] wiki article and the discussions it points to&lt;br /&gt;
and provide the full framework required.&amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/36990615/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
have some very simple tests running now for the route-manager, which rely on Nasal. we're skipping a few of the bigger Nasal modules (local-weather, jetways) and have a few lingering issues in some other modules but the basic concept is working. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A very interesting further step, which you might wish to discuss with Edward, is writing test checks *in* Nasal, since this could be quite a fast way to test some area of the code. There’s several ways that could work, and I don’t know if Edward has always planned something around this, so I won’t preempt that conversation.&lt;br /&gt;
&amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/36764781/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
we have route-manager tests which validate route_manager.nas is working correctly, and we have Canavs tests ({{fg src file|path=test_suite/simgear_tests/canvas|}}) which poke the Nasal API. &amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/36991200/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We need more FGData testing via the test suite.&lt;br /&gt;
&lt;br /&gt;
Adding the CppUnit assertions to Nasal, is the task James has been suggesting he would do, so others can write tests in pure Nasal.&lt;br /&gt;
&lt;br /&gt;
The other piece is some C++ code to scan a directory for files matching a pattern, eg test_XYZ.nas, and to run each of those automatically.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The idea for testing Nasal would be that you write a small CppUnit&lt;br /&gt;
interface in c++ in $FG_SRC/test_suite/*_tests/ (the FGData Nasal&lt;br /&gt;
testing would be in a fgdata_tests/ directory).  This would register&lt;br /&gt;
each test which points to the script in&lt;br /&gt;
$FG_SRC/test_suite/shared_data/nasal/, and the setUp() and tearDown()&lt;br /&gt;
functions would use helper functions in the fgtest namespace to start&lt;br /&gt;
and stop Nasal.  The Nasal scripts could then call the CppUnit&lt;br /&gt;
assertion macros wrapped up as Nasal functions for communicating&lt;br /&gt;
failures and errors to the test suite. &amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/36991150/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Scanning for scripts is a great idea.  Then developers (core and content) could write tests in pure Nasal.&lt;br /&gt;
&lt;br /&gt;
However all scripts found and executed will be seen as a single test within the test suite.  So maybe we should have a $FG_SRC/test_suite/nasal_staging/ directory for initial development of such auto-scanned scripts.  But then we have someone shift them into $FG_SRC/test_suite/system_tests/, $FG_SRC/test_suite/unit_tests/, or $FG_SRC/test_suite/fgdata_tests/ later on?  That would give better diagnostics and would avoid long-term clutter.&amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/36991198/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* First we should probably hard code tests into the C++ framework. The CppUnit assertion macros will have to be wrapped up as Nasal functions for this.&lt;br /&gt;
* Then implement the scanning code as we need some CMake magic (probably using file(COPY, ...)).&lt;br /&gt;
* Finally work out if and how we need to improve the Nasal debugging output.&lt;br /&gt;
&lt;br /&gt;
the code could go into a subdirectory in $FG_SRC/test_suite/fgdata_tests/, and the Nasal script in $FG_SRC/test_suite/shared_data/nasal/.&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
{{Appendix}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Core development]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_optimisation&amp;diff=135018</id>
		<title>Nasal optimisation</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_optimisation&amp;diff=135018"/>
		<updated>2022-04-29T19:36:00Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: /* PartitionProcessor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Nasal Navigation}}&lt;br /&gt;
&lt;br /&gt;
= Introduction to writing Nasal for optimum performance =&lt;br /&gt;
&lt;br /&gt;
Writing optimal performing code in a real time system (in any language) is usually related to minmising the per frame impact of any given set of code; which may end up with slightly slower code but the point is to ensure that the real time frame rate does not degrade.&lt;br /&gt;
&lt;br /&gt;
The basic techniques are as follows;&lt;br /&gt;
&lt;br /&gt;
# Measure and locate (profile) code.&lt;br /&gt;
# Do less&lt;br /&gt;
# Cache more&lt;br /&gt;
# Spread out workload&lt;br /&gt;
# Avoid garbage collection&lt;br /&gt;
&lt;br /&gt;
Inside each [[Nasal]] frame the programmer needs to ensure that the minimum necessary work is performed; ideally a predictable workload to ensure that Nasal processing per frame is constant - because otherwise there can be frame pauses - which is where an occasional frame will take much longer than usual.&lt;br /&gt;
&lt;br /&gt;
Splitting any given task across frames is the normal way of ensuring that performance remains good; unfortunately a lot of Nasal doesn't do this and instead will process everything each frame. This is what the PartitionProcessor is designed to help with&lt;br /&gt;
&lt;br /&gt;
Do not use getprop or setprop - these are very slow; instead use the props.nas module to refer to the property tree. &lt;br /&gt;
&lt;br /&gt;
All property tree access is much slower than using native Nasal variables; and it is therefore wise to only read each property from the tree once per frame. This is what the FrameNotification is designed to help with.&lt;br /&gt;
&lt;br /&gt;
Writing data to Canvas displays can be considered to be a slow operation; so only write values that are changed. props.UpdateManager can help with this.&lt;br /&gt;
&lt;br /&gt;
Generally using props.UpdateManager (with the FrameNotification hash) can be generally used to perform OnChange processing that is more efficient than the property listeners - however property listeners should still be used to perform occasional actions (rather than per frame actions)&lt;br /&gt;
&lt;br /&gt;
== fdm-initialized listener == &lt;br /&gt;
It is important to realise that sim/fdm-initialized will be set to true every time the model is repositioned; i.e. it does not fire just once. When sim/fdm-initialized is set to false the model should clean up all previously initialised listeners, threads, timers etc.&lt;br /&gt;
&lt;br /&gt;
Generally it is much better to set timers, listeners (etc) at module level scope inside any Nasal file; as these will be executed only once. Using the Emesary FrameNotification can further simplify per frame processing because there is no need to use a timer per module and instead any modules can register themselves for frame processing simply by using GlobalNotifier.Register and all of the details are abstracted away and all that needs to happen is to handle the received notifications.&lt;br /&gt;
&lt;br /&gt;
This is an example of acquiring and releasing listeners and timers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var l1 = nil;&lt;br /&gt;
var timer_loopTimer  = nil;&lt;br /&gt;
var fdm_init = func(v) {&lt;br /&gt;
&lt;br /&gt;
# always clean up values that aren't nil - this is safe&lt;br /&gt;
    if (l1 != nil)&lt;br /&gt;
      removelistener(l1);&lt;br /&gt;
    l1 = nil;&lt;br /&gt;
&lt;br /&gt;
    if (timer_loopTimer != nil)&lt;br /&gt;
        timer_loopTimer.stop();&lt;br /&gt;
    timer_loopTimer = nil;&lt;br /&gt;
&lt;br /&gt;
# then acquire new values&lt;br /&gt;
    if (v.getValue()){&lt;br /&gt;
        print(&amp;quot;Initializing Systems&amp;quot;);&lt;br /&gt;
        l1 = setlistener(&amp;quot;/some-prop&amp;quot;, listener_func);&lt;br /&gt;
        timer_loopTimer = maketimer(0.25, timer_loop);&lt;br /&gt;
        timer_loopTimer.start();&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        # now perform any other cleanup.&lt;br /&gt;
        print(&amp;quot;Cleaning up&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
setlistener(&amp;quot;sim/signals/fdm-initialized&amp;quot;, fdm_init);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
However the above can be better written as follows;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var l1 = setlistener(&amp;quot;/some-prop&amp;quot;, listener_func);&lt;br /&gt;
var timer_loopTimer = maketimer(0.25, timer_loop);&lt;br /&gt;
&lt;br /&gt;
var fdm_init = func(v) {&lt;br /&gt;
    if (v.getValue()){&lt;br /&gt;
        timer_loopTimer.start();&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        timer_loopTimer.stop();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
setlistener(&amp;quot;sim/signals/fdm-initialized&amp;quot;, fdm_init);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Nasal threads ==&lt;br /&gt;
&lt;br /&gt;
Nasal threads are of limited use because most of the time it is property tree access and other API calls that are slow and a lot of the API library (including properties) are not thread safe and should not be called from outside the main loop.&lt;br /&gt;
&lt;br /&gt;
= Optimisation techniques = &lt;br /&gt;
&lt;br /&gt;
The F-15 I think is the reference implementation of my three main Nasal optimisation techniques;  &lt;br /&gt;
&lt;br /&gt;
== Nasal Profiling ==&lt;br /&gt;
&lt;br /&gt;
As yet there isn't a profiler available so instead there is an OperationTimer that is ships as part of emexec (2020.3 or later released after Aprial 2022).&lt;br /&gt;
&lt;br /&gt;
This makes it easy to output (via logprint) information about how much time a module is taking. &lt;br /&gt;
&lt;br /&gt;
To create an instance of a timer there are two parameters, the first is the ident and the second the log level (3=info, 2=debug)&lt;br /&gt;
 &amp;lt;code&amp;gt;var ot = emexec.OperationTimer.new(&amp;quot;VSD&amp;quot;,2);&amp;lt;/code&amp;gt;&lt;br /&gt;
The output is a cumulative number of milliseconds since the OperationTimer was reset.&lt;br /&gt;
 &amp;lt;code&amp;gt;ot.reset();&lt;br /&gt;
 ot.log(&amp;quot;Start&amp;quot;);&lt;br /&gt;
 &amp;lt;some code to time&amp;gt;&lt;br /&gt;
 ot.log(&amp;quot;1&amp;quot;);&lt;br /&gt;
 &amp;lt;more code&amp;gt;&lt;br /&gt;
 ot.log(&amp;quot;ed&amp;quot;);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Emesary real time executive ==&lt;br /&gt;
&lt;br /&gt;
Starting from 2020.3 released after April 2022 FGdata includes the emexec module which provides an easy to use object scheduler that uses Emesary to do most of the work. &lt;br /&gt;
&lt;br /&gt;
By default it is recommended to use the built in scheduler &amp;lt;code&amp;gt;emexec.ExecModule&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The scheduler will adjust the frequency from 50hz right down to 4hz. &lt;br /&gt;
&lt;br /&gt;
Any object that wishes to be invoked simply needs to provide an &amp;lt;code&amp;gt;update(notification)&amp;lt;/code&amp;gt; method and register itself via ExecModule.register method.&lt;br /&gt;
&lt;br /&gt;
The register method takes the following arguments&lt;br /&gt;
&lt;br /&gt;
# ident - text to identify this object registration&lt;br /&gt;
# properties_to_monitor : a key value pair hash of properties to include in the notification. This helps to optimise property tree access (see FrameNotification below for the format)&lt;br /&gt;
# object : an instance of an objec that has an update(notification) method&lt;br /&gt;
# rate : frame skip rate (1/rate is the effective rate)&lt;br /&gt;
# frame_offset : frame skip offset. Must be less than rate and when used with rate it can allow interleaving of modules (usually for performance)&lt;br /&gt;
&lt;br /&gt;
During development it would be usual to set the overrun detection active emexec.ExecModule.transmitter.OverrunDetection(9) for a warning (log leve info) of any frame that exceeds 9 ms&lt;br /&gt;
&lt;br /&gt;
== FrameNotification ==&lt;br /&gt;
&lt;br /&gt;
The FrameNotification is a notification sent out at defined intervals that contains a hash with property values.&lt;br /&gt;
&lt;br /&gt;
Use the FrameNotificationAddProperty to request that certain properties are contained within the FrameNotification.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
notifications.FrameNotificationAddProperty.new(&amp;quot;F15-HUD&amp;quot;, **[HASH-Name]**, **[property-string]**)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
emesary.GlobalTransmitter.NotifyAll(notifications.FrameNotificationAddProperty.new(&amp;quot;F15-HUD&amp;quot;, &amp;quot;AirspeedIndicatorIndicatedMach&amp;quot;, &amp;quot;instrumentation/airspeed-indicator/indicated-mach&amp;quot;));`&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
although more typically used by having a hash that contains the keys and properties that you want to monitor and then using a loop to send out the FrameNotificationAddProperty; e.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
input = {&lt;br /&gt;
        AirspeedIndicatorIndicatedMach          : &amp;quot;instrumentation/airspeed-indicator/indicated-mach&amp;quot;,&lt;br /&gt;
        Alpha                                   : &amp;quot;orientation/alpha-indicated-deg&amp;quot;,&lt;br /&gt;
        AltimeterIndicatedAltitudeFt            : &amp;quot;instrumentation/altimeter/indicated-altitude-ft&amp;quot;,&lt;br /&gt;
        ArmamentAgmCount                        : &amp;quot;sim/model/f15/systems/armament/agm/count&amp;quot;,&lt;br /&gt;
        ArmamentAim120Count                     : &amp;quot;sim/model/f15/systems/armament/aim120/count&amp;quot;,&lt;br /&gt;
        ArmamentAim7Count                       : &amp;quot;sim/model/f15/systems/armament/aim7/count&amp;quot;,&lt;br /&gt;
        ArmamentAim9Count                       : &amp;quot;sim/model/f15/systems/armament/aim9/count&amp;quot;,&lt;br /&gt;
        ArmamentRounds                          : &amp;quot;sim/model/f15/systems/gun/rounds&amp;quot;,&lt;br /&gt;
        AutopilotRouteManagerActive             : &amp;quot;autopilot/route-manager/active&amp;quot;,&lt;br /&gt;
        AutopilotRouteManagerWpDist             : &amp;quot;autopilot/route-manager/wp/dist&amp;quot;,&lt;br /&gt;
        AutopilotRouteManagerWpEtaSeconds       : &amp;quot;autopilot/route-manager/wp/eta-seconds&amp;quot;,&lt;br /&gt;
        CadcOwsMaximumG                         : &amp;quot;fdm/jsbsim/systems/cadc/ows-maximum-g&amp;quot;,&lt;br /&gt;
        ControlsArmamentMasterArmSwitch         : &amp;quot;sim/model/f15/controls/armament/master-arm-switch&amp;quot;,&lt;br /&gt;
        ControlsArmamentWeaponSelector          : &amp;quot;sim/model/f15/controls/armament/weapon-selector&amp;quot;,&lt;br /&gt;
        ControlsGearBrakeParking                : &amp;quot;controls/gear/brake-parking&amp;quot;,&lt;br /&gt;
        ControlsGearGearDown                    : &amp;quot;controls/gear/gear-down&amp;quot;,&lt;br /&gt;
        ControlsHudBrightness                   : &amp;quot;sim/model/f15/controls/HUD/brightness&amp;quot;,&lt;br /&gt;
        ControlsHudSymRej                       : &amp;quot;sim/model/f15/controls/HUD/sym-rej&amp;quot;,&lt;br /&gt;
        ElectricsAcLeftMainBus                  : &amp;quot;fdm/jsbsim/systems/electrics/ac-left-main-bus&amp;quot;,&lt;br /&gt;
        HudNavRangeDisplay                      : &amp;quot;sim/model/f15/instrumentation/hud/nav-range-display&amp;quot;,&lt;br /&gt;
        HudNavRangeETA                          : &amp;quot;sim/model/f15/instrumentation/hud/nav-range-eta&amp;quot;,&lt;br /&gt;
        OrientationHeadingDeg                   : &amp;quot;orientation/heading-deg&amp;quot;,&lt;br /&gt;
        OrientationPitchDeg                     : &amp;quot;orientation/pitch-deg&amp;quot;,&lt;br /&gt;
        OrientationRollDeg                      : &amp;quot;orientation/roll-deg&amp;quot;,&lt;br /&gt;
        OrientationSideSlipDeg                  : &amp;quot;orientation/side-slip-deg&amp;quot;,&lt;br /&gt;
        RadarActiveTargetAvailable              : &amp;quot;sim/model/f15/instrumentation/radar-awg-9/active-target-available&amp;quot;,&lt;br /&gt;
        RadarActiveTargetCallsign               : &amp;quot;sim/model/f15/instrumentation/radar-awg-9/active-target-callsign&amp;quot;,&lt;br /&gt;
        RadarActiveTargetClosure                : &amp;quot;sim/model/f15/instrumentation/radar-awg-9/active-target-closure&amp;quot;,&lt;br /&gt;
        RadarActiveTargetDisplay                : &amp;quot;sim/model/f15/instrumentation/radar-awg-9/active-target-display&amp;quot;,&lt;br /&gt;
        RadarActiveTargetRange                  : &amp;quot;sim/model/f15/instrumentation/radar-awg-9/active-target-range&amp;quot;,&lt;br /&gt;
        RadarActiveTargetType                   : &amp;quot;sim/model/f15/instrumentation/radar-awg-9/active-target-type&amp;quot;,&lt;br /&gt;
        InstrumentedG                           : &amp;quot;instrumentation/g-meter/instrumented-g&amp;quot;,&lt;br /&gt;
        VelocitiesAirspeedKt                    : &amp;quot;velocities/airspeed-kt&amp;quot;,&lt;br /&gt;
};&lt;br /&gt;
foreach (var name; keys(input)) {&lt;br /&gt;
    emesary.GlobalTransmitter.NotifyAll(notifications.FrameNotificationAddProperty.new(&amp;quot;F15-HUD&amp;quot;, name, input[name]));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The idea of the FrameNotification is that it provides an easy way to run your update logic; simply by registering with the GlobalTransmitter and then processing the FrameNotification you can call your update logic in an efficient manner;&lt;br /&gt;
&lt;br /&gt;
e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var HUDRecipient =&lt;br /&gt;
{&lt;br /&gt;
    new: func(_ident)&lt;br /&gt;
    {&lt;br /&gt;
        var new_class = emesary.Recipient.new(_ident);&lt;br /&gt;
        new_class.MainHUD = nil;&lt;br /&gt;
        new_class.Receive = func(notification)&lt;br /&gt;
        {&lt;br /&gt;
            if (notification.NotificationType == &amp;quot;FrameNotification&amp;quot;)&lt;br /&gt;
            {&lt;br /&gt;
                if (new_class.MainHUD == nil)&lt;br /&gt;
                  new_class.MainHUD = F15HUD.new(&amp;quot;Nasal/HUD/HUD.svg&amp;quot;, &amp;quot;HUDImage1&amp;quot;);&lt;br /&gt;
                if (!math.mod(notifications.frameNotification.FrameCount,2)){&lt;br /&gt;
                    new_class.MainHUD.update(notification);&lt;br /&gt;
                }&lt;br /&gt;
                return emesary.Transmitter.ReceiptStatus_OK;&lt;br /&gt;
            }&lt;br /&gt;
            return emesary.Transmitter.ReceiptStatus_NotProcessed;&lt;br /&gt;
        };&lt;br /&gt;
        return new_class;&lt;br /&gt;
    },&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
and then register that function with the Emesary Global transmitter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
emesary.GlobalTransmitter.Register(HUDRecipient.new(&amp;quot;F15-HUD&amp;quot;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
------&lt;br /&gt;
&lt;br /&gt;
== props.UpdateManager ==&lt;br /&gt;
&lt;br /&gt;
This will monitor one or more property, or values from a hash and call a function (or inline function) when the value or a value changes more than a defined amount.&lt;br /&gt;
&lt;br /&gt;
e.g. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
       obj.update_items = [&lt;br /&gt;
            props.UpdateManager.FromHashList([&amp;quot;ElectricsAcLeftMainBus&amp;quot;,&amp;quot;ControlsHudBrightness&amp;quot;] , 0.01, func(val)&lt;br /&gt;
                                      {&lt;br /&gt;
                                          if (val.ElectricsAcLeftMainBus &amp;lt;= 0 &lt;br /&gt;
                                              or val.ControlsHudBrightness &amp;lt;= 0) {&lt;br /&gt;
                                              obj.svg.setVisible(0);&lt;br /&gt;
                                          } else {&lt;br /&gt;
                                              obj.svg.setVisible(1);&lt;br /&gt;
                                          }&lt;br /&gt;
                                      }),&lt;br /&gt;
            props.UpdateManager.FromHashValue(&amp;quot;AltimeterIndicatedAltitudeFt&amp;quot;, 1, func(val)&lt;br /&gt;
                                             {&lt;br /&gt;
                                                 obj.alt_range.setTranslation(0, val * alt_range_factor);&lt;br /&gt;
                                             }),&lt;br /&gt;
&lt;br /&gt;
            props.UpdateManager.FromHashValue(&amp;quot;VelocitiesAirspeedKt&amp;quot;, 0.1, func(val)&lt;br /&gt;
                                      {&lt;br /&gt;
                                          obj.ias_range.setTranslation(0, val * ias_range_factor);&lt;br /&gt;
                                      }),&lt;br /&gt;
            props.UpdateManager.FromHashValue(&amp;quot;ControlsHudSymRej&amp;quot;, 0.1, func(val)&lt;br /&gt;
                                             {&lt;br /&gt;
                                                 obj.symbol_reject = val;&lt;br /&gt;
                                             }),&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
and then in the update method &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
       foreach(var update_item; me.update_items)&lt;br /&gt;
        {&lt;br /&gt;
            update_item.update(notification);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
As you can see above the update method is called from the recipient of the frame notification.&lt;br /&gt;
&lt;br /&gt;
== PartitionProcessor ==&lt;br /&gt;
&lt;br /&gt;
When working with lists (arrays) of data that can get quite long (e.g. targets from radar) the partition processor is an easy way to only process a part of that list each frame.&lt;br /&gt;
&lt;br /&gt;
What it does is to manage the processing of data in a manner suitable for real time operations.  Given a data array [0..size] this will process a number of array elements each time it is called This allows for a simple way    to split up intensive processing across multiple frames.&lt;br /&gt;
   &lt;br /&gt;
The limit is the number of elements to process per frame (invocation of .process method) or to limit the processing to a specified amount of time using a Nasal timestamp to measure the amount (in usec)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
example usage (object);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var VSD_Device =&lt;br /&gt;
{&lt;br /&gt;
    new : func(designation, model_element, target_module_id, root_node)&lt;br /&gt;
    {&lt;br /&gt;
...&lt;br /&gt;
       # new : func(_name, _size, _timestamp=nil)&lt;br /&gt;
       obj.process_targets = PartitionProcessor.new(&amp;quot;VSD-targets&amp;quot;, 20, nil);&lt;br /&gt;
       obj.process_targets.set_max_time_usec(500);&lt;br /&gt;
...&lt;br /&gt;
     me.process_targets.set_timestamp(notification.Timestamp);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
then invoke.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
     # process : func (object, data, init_method, process_method, complete_method)&lt;br /&gt;
&lt;br /&gt;
     me.process_targets.process(me, awg_9.tgts_list, &lt;br /&gt;
                                func(pp, obj, data){&lt;br /&gt;
                                    initialisation; called before processing element[0]&lt;br /&gt;
                                    params&lt;br /&gt;
                                     pp is the partition processor that called this&lt;br /&gt;
                                     obj is the reference object (first argument in the .process)&lt;br /&gt;
                                     data is the entire data array.&lt;br /&gt;
                                }&lt;br /&gt;
                                ,&lt;br /&gt;
                                func(pp, obj, element){&lt;br /&gt;
                                    process individual element; &lt;br /&gt;
                                    params&lt;br /&gt;
                                     pp is the partition processor that called this&lt;br /&gt;
                                     obj is the reference object (first argument in the .process)&lt;br /&gt;
                                     element is the element data[pp.data_index]&lt;br /&gt;
                                    return 0 to stop processing any more elements and call the completed method&lt;br /&gt;
                                    return 1 to continue processing.&lt;br /&gt;
                                },&lt;br /&gt;
                                func(pp, obj, data)&lt;br /&gt;
                                {&lt;br /&gt;
                                    completed; called after the last element processed&lt;br /&gt;
                                    params&lt;br /&gt;
                                     pp is the partition processor that called this&lt;br /&gt;
                                     obj is the reference object (first argument in the .process)&lt;br /&gt;
                                     data is the entire data array.&lt;br /&gt;
                                });&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Changelog_2020.3&amp;diff=134567</id>
		<title>Changelog 2020.3</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Changelog_2020.3&amp;diff=134567"/>
		<updated>2022-02-03T11:35:31Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: /* 2020.3.12 */ New changelog&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{changelogs|prev=2020.1|next=2022.1}}&lt;br /&gt;
&lt;br /&gt;
Available in: [[Changelog_2020.3|English]], [[Zh/2020.3|Chinese]]&lt;br /&gt;
&lt;br /&gt;
Please help us translate into other languages!&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
The FlightGear development team is delighted to announce the v2020.3 LTS release of FlightGear, the free, open-source flight simulator. This is the second Long Term Support release for FlightGear, since the project changed to offering both Long Term Support releases, and more cutting-edge Preview releases.  This release represents the culmination of two years of development effort by a worldwide group of volunteers, brought together by a shared ambition to create the most realistic flight simulator possible that is free to use, modify and distribute. FlightGear is used all over the world by desktop flight simulator enthusiasts, for research in universities and for interactive exhibits in museums.&lt;br /&gt;
&lt;br /&gt;
Major enhancements since the v2020.3 LTS include: &lt;br /&gt;
* a developer preview of the upcoming Compositor graphical rendering framework as a separate pre-built binary, &lt;br /&gt;
* enhancements to both the JSBSim and YASim flight dynamics models&lt;br /&gt;
* DDS texture caching to reduce load times&lt;br /&gt;
* faster loading and more memory efficient buildings&lt;br /&gt;
* improved aircraft carrier support&lt;br /&gt;
&lt;br /&gt;
Additionally 30 completely new aircraft have been added to the official hangar, and a further 71 have received major updates.&lt;br /&gt;
&lt;br /&gt;
{{Disclaimer|id=final-fixed-function-release}}&lt;br /&gt;
&lt;br /&gt;
Founded in 1997, FlightGear features more than 700 aircraft, a worldwide scenery database, a multiplayer environment, detailed sky modelling, a flexible and open aircraft modelling system, varied networking options, multiple display support, a powerful scripting language, and an open architecture. Best of all, being open-source, the simulator is owned by the community and everyone is encouraged to contribute.&lt;br /&gt;
&lt;br /&gt;
FlightGear - Fly Free! &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Launcher ==&lt;br /&gt;
* Addition of a welcome screen on first launch, providing helpful information to first time users.&lt;br /&gt;
* Aircraft can now be marked as Favourites, and filtered, making it easier to see find your favourite aircraft out of the hundreds available.&lt;br /&gt;
* The launcher now supports aircraft carriers, including selecting a carrier and setting a start position.&lt;br /&gt;
* {{key press|Ctrl|F}} shortcut for when you just want to Fly!&lt;br /&gt;
* Improved support for helipads and seaports, including detection of current aircraft type.&lt;br /&gt;
* Numerous bugfixes and stability improvements, in particular for the aircraft and addons tabs.&lt;br /&gt;
&lt;br /&gt;
== Graphics ==&lt;br /&gt;
* To provide a developer preview, the [[Compositor]] renderer is included as part of this release.  It provides a fully XML-configurable multi-pass rendering pipeline that is compatible with ALS and includes clustered shading.&lt;br /&gt;
* Support for DDS Texture Cache, improving loading times for texture files.&lt;br /&gt;
* Star visibility is configurable based on magnitude of star and atmospheric conditions.&lt;br /&gt;
* Use of non-directional point sprites as a fallback for drivers that do not support triangles of point sprites is now supported by setting &amp;lt;code&amp;gt;/rendering/triangle-directional-lights=false&amp;lt;/code&amp;gt;.&lt;br /&gt;
* A new Tower AGL view has been added.  This is similar to Tower View, except that it keeps both the aircraft and the ground immediately below the aircraft in view, zooming and panning smoothly as the aircraft moves. Good for viewing landings.&lt;br /&gt;
* Improved airport grass textures&lt;br /&gt;
* Implemented tidal movement for littoral areas.&lt;br /&gt;
* Updated regional material definitions for California, Asia, Northern Brazil, Iceland, Jan Mayen island.&lt;br /&gt;
* Active volcanoes - Katla, Eyjafjallajokull, Surtsey.  &lt;br /&gt;
* Instanced-based random and OpenStreetMap buildings, improving performance and graphical quality significantly.&lt;br /&gt;
* Improvements to the Wingflex Shader.&lt;br /&gt;
* Users may enable/disable the pilot model from the View Options dialog.&lt;br /&gt;
&lt;br /&gt;
== JSBSim ==&lt;br /&gt;
* Added the ability to set up the starter and acceleration times of a turbine (parameters &amp;lt;code&amp;gt;&amp;lt;n1spinup&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;lt;n2spinup&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;lt;n1startrate&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;lt;n2startrate&amp;gt;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* The &amp;lt;code&amp;gt;&amp;lt;integrator&amp;gt;&amp;lt;/code&amp;gt; filter can now be reset to 0.0 by setting its &amp;lt;code&amp;gt;&amp;lt;trigger&amp;gt;&amp;lt;/code&amp;gt; property to a negative value.&lt;br /&gt;
* The integration scheme of the &amp;lt;code&amp;gt;&amp;lt;integrator&amp;gt;&amp;lt;/code&amp;gt; filter can now be chosen among &amp;lt;code&amp;gt;rect&amp;lt;/code&amp;gt; (Euler), &amp;lt;code&amp;gt;trap&amp;lt;/code&amp;gt; (Trapezoidal), &amp;lt;code&amp;gt;ab2&amp;lt;/code&amp;gt; (2nd order Adams-BashForth) and &amp;lt;code&amp;gt;ab3&amp;lt;/code&amp;gt; (3rd order Adams-Bashforth)&lt;br /&gt;
* The following functions can now be used in &amp;lt;code&amp;gt;&amp;lt;function&amp;gt;&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;floor&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ceil&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;fmod&amp;lt;/code&amp;gt;. Their functionalities are the same than the corresponding C/C++ functions.&lt;br /&gt;
* &amp;lt;code&amp;gt;&amp;lt;function&amp;gt;&amp;lt;/code&amp;gt; now checks the number of its arguments.&lt;br /&gt;
* New system component linear_actuator&lt;br /&gt;
* Export the fuel density to the property tree&lt;br /&gt;
* Added cyclic clipping for FCS components&lt;br /&gt;
* Added the ability to control the turbine engines spin down factor&lt;br /&gt;
* [Backward compatibility breakage] Gyros are now measuring rotation rates instead of rotational accelerations. Gyros that measure rotational accelerations do not exist in the real world.&lt;br /&gt;
* Output properties of flight control elements are no longer tied. This saves a lot of spurious warning messages and allows direct references of the same properties among several flight controls.&lt;br /&gt;
* Water vapor in the atmosphere is now managed through its mass fraction rather than its partial pressure. The former being the physical quantity that is conserved when pressure and temperature vary.&lt;br /&gt;
* Check that there are at least 3 contacts before trying to trim on ground.&lt;br /&gt;
* Added optional transmission of the simulation time for FG UDP interface&lt;br /&gt;
* The existence of the property that is used for table independent vars is now checked during execution rather than when the XML definition is parsed. This relaxes the order in which filters, table and more generally flight controls need to be declared in the XML definition files.&lt;br /&gt;
* Electric engines RPM is now exported in UDP sockets.&lt;br /&gt;
* The parameter &amp;lt;code&amp;gt;&amp;lt;ignitionn2&amp;gt;&amp;lt;/code&amp;gt; now affects N2 rather than N1. &lt;br /&gt;
* A warning is now given when max &amp;lt; min in a &amp;lt;code&amp;gt;&amp;lt;clipto&amp;gt;&amp;lt;/code&amp;gt; rather than throwing an exception&lt;br /&gt;
* Added the ability to log properties in a CSV file with the new fgfs executable argument &amp;lt;code&amp;gt;--jsbsim-output-directive-file&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== YASim ==&lt;br /&gt;
* Ground friction (stiction) changes&lt;br /&gt;
* Support for transonic flow effects.&lt;br /&gt;
* Control initial gear state directly by setting &amp;lt;code&amp;gt;/fdm/yasim/respect-external-gear-state=true&amp;lt;/code&amp;gt;, rather then YASim settings this depending on whether the aircraft is in the air or on the ground.&lt;br /&gt;
* Electric engines are now supported.&lt;br /&gt;
&lt;br /&gt;
== Weather and Environment ==&lt;br /&gt;
* Increased turbulence will be encountered near active volcanoes.&lt;br /&gt;
* Configurable METAR URL.&lt;br /&gt;
* METAR strings are decoded and displayed in a human-readable form in the weather dialog.&lt;br /&gt;
&lt;br /&gt;
== Carriers ==&lt;br /&gt;
* Two new carrier-specific starting options are supported in the launcher: &amp;lt;code&amp;gt;carrier-takeoff&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;carrier-approach&amp;lt;/code&amp;gt;.&lt;br /&gt;
* A new &amp;lt;code&amp;gt;--carrier-position&amp;lt;/code&amp;gt; command-line argument has been added.  This can be used to select the aircraft start position on an aircraft carrier.  Either a catapult (e.g. &amp;lt;code&amp;gt;cat-1&amp;lt;/code&amp;gt;), a parking position (e.g. &amp;lt;code&amp;gt;park-1&amp;lt;/code&amp;gt;), on final approach on the FLOLS (&amp;lt;code&amp;gt;flols&amp;lt;/code&amp;gt;) or abeam the carrier (&amp;lt;code&amp;gt;abeam&amp;lt;/code&amp;gt;).&lt;br /&gt;
* MPCarrier can now be detected by the GUI even if not available on startup.  To enable this feature set &amp;lt;code&amp;gt;/sim/mp-carriers/auto-attach=true&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== AI ==&lt;br /&gt;
* New fgcommands &amp;lt;code&amp;gt;add-aiobject&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;remove-aiobject&amp;lt;/code&amp;gt; for adding/removing objects to the AI subsystem.&lt;br /&gt;
* New AI aircraft, including 747 Freighter, CRJ900, SR-71, Saab 340.&lt;br /&gt;
* Numerous updates to AI traffic schedules and airline liveries.&lt;br /&gt;
* Space Shuttle TAEM and approach at KEDW scenario.&lt;br /&gt;
* Accurate Britten-Norman Islander performance data, from an Islander pilot.&lt;br /&gt;
&lt;br /&gt;
== Multiplayer ==&lt;br /&gt;
* Connection to VATSIM via swift is now available via the GUI.&lt;br /&gt;
* FGCom now supports both COM1 and COM2, as well as volume settings.&lt;br /&gt;
* The views defined by the user's aircraft (Pilot view, Helicopter view, Tower view etc) can now be used with multiplayer aircraft.  Viewing a particular multiplayer aircraft is done by clicking in the Pilot List dialogue's &amp;quot;view' column (see the &amp;quot;Multiplayer/Pilot List&amp;quot; menu).&lt;br /&gt;
* &amp;lt;code&amp;gt;--disable-hold-short&amp;lt;/code&amp;gt; option which allows the user to force a start on the runway when multiplayer is enabled.  This option should be used with caution - it can give other pilots and ATC a nasty fright to find an aircraft materialize on the runway!&lt;br /&gt;
* Support for recording multiplayer data&lt;br /&gt;
&lt;br /&gt;
== Nasal Scripting ==&lt;br /&gt;
* Configurable load order for core Nasal modules.&lt;br /&gt;
* Improvements and bug fixes to Emesary, the messaging interface.&lt;br /&gt;
* Improvements to the core libraries.&lt;br /&gt;
* Garbage collection improvements to reduce frame stuttering&lt;br /&gt;
* Re-loadable Nasal modules&lt;br /&gt;
* Canvas EFIS framework&lt;br /&gt;
* New methods in Canvas Image to set colors of pixels in the image.&lt;br /&gt;
&lt;br /&gt;
== Aircraft == &lt;br /&gt;
* FG1000 Glass Panel improvements include user-configurable VFR transponder codes, volume controls, new fascia, UI is now resizeable, support for custom SVG files (e.g. for a G500).  The FG1000 is now available on the Cessna 182T, J3 Cub, Diamond DA40.&lt;br /&gt;
* Improved glider vario instrument.&lt;br /&gt;
* New Aircraft: &lt;br /&gt;
** Airbus A320 - airliner&lt;br /&gt;
** Alisport Silent2Electro - glider with electric sustainer motor&lt;br /&gt;
** Bombardier Q400 DHC8-402 - shorthaul turboprop airliner&lt;br /&gt;
** Breguet Atlantic BR 1150 - long-range maritime patrol aircraft&lt;br /&gt;
** Cessna 140 - GA aircraft&lt;br /&gt;
** Cessna 208B Caravan - short range passenger, freighter and utility aircraft&lt;br /&gt;
** Cirrus SR22T - GA aircraft&lt;br /&gt;
** Diamond DA40 NG - GA aircraft, including FG1000 glass panel cockpit&lt;br /&gt;
** Diamond DA62 Twinstar- Twin engine GA aircraft&lt;br /&gt;
** Diamond HK36 Super Dimona - motorglider&lt;br /&gt;
** Dornier DO 28 Skyservant - Twin engine STOL utility aircraft&lt;br /&gt;
** Douglas TBD Devastator - WWII Torpedo bomber&lt;br /&gt;
** Draco Wilga - turboprop taildragger bush plane&lt;br /&gt;
** Fokker T.V - twin engine bomber&lt;br /&gt;
** Glasfluegel H201B Standard Libelle - glider&lt;br /&gt;
** Grumman F11-Tiger - carrier-based fighter&lt;br /&gt;
** Grumman HU-16A Albatross - twin engine amphibian&lt;br /&gt;
** Petliakov PE-8 (Ant-42/TB-7) - WWII bomber&lt;br /&gt;
** Piper PA28-161 Warrior II - GA aircraft&lt;br /&gt;
** Pipistrel Alpha Electro - electric training aircraft&lt;br /&gt;
** Pipistrel Taurus Electro G2.5 - glider with electric sustainer motor&lt;br /&gt;
** Rolladen Schneider LS8sc neo - standard glider with electric sustainer motor&lt;br /&gt;
** Robin DR400 Ecoflyer - GA Aircraft&lt;br /&gt;
** Scheibe Bergfalke II/55 - training glider&lt;br /&gt;
** Schempp-Hirth Arcus S - high performance glider&lt;br /&gt;
** Schleicher Ka6(CR) &amp;quot;Rhoensegler&amp;quot; - training glider&lt;br /&gt;
** SEPECAT Jaguar GR.1 - jet attack aircraft&lt;br /&gt;
** SUMPAC - Human powered airplane&lt;br /&gt;
** Supermarine Swift - jet fighter&lt;br /&gt;
** Yak 52 - training aircraft&lt;br /&gt;
* Major updates to over 70 aircraft.  Including 737-100, 737-300, 777, A-26-Invader, AR-234, ASG29, ASK13, ASK21, Aero-Commander, Aichi-D3A, B-17, B-24-Liberator, B-25, Bombardier-415, CH750STOL, CRJ700-family, Cessna-208-Caravan, Cessna Citation II, Cessna-L19, Cirrus-SR22, Concorde, DO-228, DO-335, Diamond-Da40, Diamond-Da42, Dragonfly, Embraer-ERJ-145, F-15, Fairchild-Metroliner, Falcon-50, Fokker-S-11, Fw200, H4-Hercules, Harrier-GR3, Horten-Ho-IX, Hughes-XF11, J3Cub, JA37, JAS39-Gripen, Jaguar, LS4, Lancair-235, Lionceau, Lockheed-NF104A, Lockheed-P38, ME-262, Mirage-2000, MirageIV, Northrop-xb35, PC-12, Piaggio-P166, Piper-PA-28, Potez-630, R44, Ryan-Navion, SIAI-Marchetti-SF.260, Socata-ST10, SpaceShuttle, Starship, Tecnam-P2006T, UH-1, Yak-18T, Zlin-50lx, an24b, bluebird, c182s, dhc1, f-14b, f16.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous ==&lt;br /&gt;
* Updated Chinese, Dutch, French, German, Italian, Polish and Slovak translations.&lt;br /&gt;
* Map dialog displays heliports and allows configurable cursor key panning&lt;br /&gt;
* Faster Terrasync:  Download a tarball of airport information on first start and only check for updates every 24 hours rather than every simulator run.&lt;br /&gt;
* GPS fly-by mode&lt;br /&gt;
* Sentry.io integration to provide centralized crash reporting.&lt;br /&gt;
* Change screenshot filename to have date and time&lt;br /&gt;
* New thread safe particle manager -- should reduce random crashes around particles.&lt;br /&gt;
&lt;br /&gt;
=Updates since 2020.1=&lt;br /&gt;
Changes since the 2020.1 preview release include:&lt;br /&gt;
* Various launcher improvements including a Welcome screen and a keyboard shortcut (Ctrl+F) to Fly!&lt;br /&gt;
* Improved regional definitions for California, Iceland and Northern Brazil and better grass textures.&lt;br /&gt;
* Implemented tidal movement for littoral areas.&lt;br /&gt;
* New AI model for the 747 Freighter, and numerous AI livery and traffic updates.&lt;br /&gt;
* Updates to the FG1000 glass panel display including configurable VFR transponder codes, volume controls, a new fascia, resizeable UI and support for custom SVG files.&lt;br /&gt;
* A hangar full of new aircraft: HU-16A-Albatross, LS8, Embraer-ERJ-145, Cessna 208B Caravan, PZL 104 wilga 2000 Draco, Scheibe Bergfalke, Taurus, f16, Dornier Do 28 Skyservant, Petliakov Pe 8 (Ant 42/DB 7), Grumman F.11 Tiger&lt;br /&gt;
* Updates to a large number of aircraft including CRJ700, Dragonfly, Mirage 2000, Jaguar GR1, H4 Hercules, JA37, Supermarine Swift, A320, Cirrus-SR22, Cessna Citation, J3Cub&lt;br /&gt;
* Updated Chinese, Dutch, French, German, Italian, Polish and Slovak translations.&lt;br /&gt;
* Faster Terrasync:  Download a tarball of airport information on first start and only check for updates every 24 hours rather than every simulator run.&lt;br /&gt;
* GPS fly-by mode&lt;br /&gt;
* Sentry.io integration to provide centralized crash reporting.&lt;br /&gt;
* New thread safe particle manager -- should reduce random crashes around particles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Updates since 2020.3.0=&lt;br /&gt;
&lt;br /&gt;
As 2020.3 is a long term supported release, there are ongoing bug-fixes and small improvements happening, based on user feedback and automatic reporting of crashes and issues. Significant fixes are listed below:&lt;br /&gt;
&lt;br /&gt;
==2020.3.1==&lt;br /&gt;
* Add help page to the launcher&lt;br /&gt;
* Fix handling of helipads at heliports&lt;br /&gt;
* Migrate installed aircraft packages, when migrating to the new stable catalog&lt;br /&gt;
* TerraSync: improve startup performance on Windows&lt;br /&gt;
&lt;br /&gt;
==2020.3.2==&lt;br /&gt;
* TerraSync waits for Models to be completely sync-ed, to avoid missing models when starting&lt;br /&gt;
* First-run screen: add a 'scroll to the bottom' hint icon&lt;br /&gt;
* Tides fixes from Erik Hofman&lt;br /&gt;
* Use nicer scrollbar for the launcher, fixes some issue with long aircraft lists&lt;br /&gt;
* Support Apt.dat v1000 comm frequencies&lt;br /&gt;
* Fix an ATC crash when repositioning&lt;br /&gt;
* Many translations fixes identified by Michael Danilov&lt;br /&gt;
* Greatly improve the Brazilian cerradio areas (near SBMQ)&lt;br /&gt;
* Russian translation updates&lt;br /&gt;
* Iceland materials fixes&lt;br /&gt;
&lt;br /&gt;
==2020.3.3==&lt;br /&gt;
* Fix accidental mouse picks while using a right-mouse-drag to look around&lt;br /&gt;
* Fix the download location we recommend in the 'setup root' dialog&lt;br /&gt;
&lt;br /&gt;
==2020.3.4==&lt;br /&gt;
* Handle more METAR strings correctly, including wind sensor failures&lt;br /&gt;
* Fix airmass velocity being applied to sub-models twice (eg, when dropping payloads in a cross-wind)&lt;br /&gt;
* Fix crash on shutdown in the properties code&lt;br /&gt;
* Spanish translation updates &lt;br /&gt;
* Disable flights to EGEL to avoid crashes in traffic code&lt;br /&gt;
&lt;br /&gt;
==2020.3.5==&lt;br /&gt;
* Change default Windows download location to %USERS%\FlightGear\Downloads, to avoid problems with Windows Defender blocking un-trusted applications from writing to Documents, which was the previous location.&lt;br /&gt;
* Fix a crash when returning to FlightGear from another application and scrolling or clicking&lt;br /&gt;
* Avoid crashing with UIUC-based aircraft such as the Wright Flyer&lt;br /&gt;
* Fix a crash on macOS when a joystick failed to open&lt;br /&gt;
* Update the macOS application icon&lt;br /&gt;
* Fix Nasal crash on reset&lt;br /&gt;
* Canvas: allow anisotropic filtering&lt;br /&gt;
* Larger, improved moon texture&lt;br /&gt;
* UFO speed goes to 11&lt;br /&gt;
* Fix taxiway markings disappearing in specific graphics settings&lt;br /&gt;
&lt;br /&gt;
==2020.3.6==&lt;br /&gt;
* Fixed crash downloading the default aircraft catalog&lt;br /&gt;
* Fix a hang starting at scenery in the ocean&lt;br /&gt;
* Fix incorrect sky &amp;amp; cockpit rendering with certain METAR values&lt;br /&gt;
* Add getting-started hints to the launcher (English only for now)&lt;br /&gt;
* Fix Shuttle AI scenarios&lt;br /&gt;
* Improvements to flight-planning mode&lt;br /&gt;
* Sun / moon scaling fixes&lt;br /&gt;
* Fix initial position of submodels&lt;br /&gt;
* macOS: warn if running with app translocation&lt;br /&gt;
* Windows: detect missing OpenGL drivers&lt;br /&gt;
* Fix UIUC FDM crashes&lt;br /&gt;
* Fix crash with invalid view numbers&lt;br /&gt;
* Catch FDM NaN errors more gracefully&lt;br /&gt;
* KAP-140 approach mode improvements&lt;br /&gt;
* Traffic+AI livery updates&lt;br /&gt;
&lt;br /&gt;
== 2020.3.7 ==&lt;br /&gt;
&lt;br /&gt;
* Enable OSM2City buildings via TerraSync for the whole planet&lt;br /&gt;
* C172 bug-fixes and updates&lt;br /&gt;
* Improved regional material definitions for Europe, California&lt;br /&gt;
* Allow chat box to be re-positioned&lt;br /&gt;
* Fix crashes related to particle systems&lt;br /&gt;
* Fix selection of time-zone around Beijing&lt;br /&gt;
* Fix display of non-Latin1 strings in Canvas displays&lt;br /&gt;
* Fix Multi-player mode runway-start logic to select hold-short position correctly&lt;br /&gt;
* macOS: fix crash on text with certain fonts&lt;br /&gt;
* Fix launcher language selection when the UI language include a script specifier (eg zh-Hans-CN)&lt;br /&gt;
* Fix aircraft-id property when loading from a hangar ( https://sourceforge.net/p/flightgear/codetickets/2502/ )&lt;br /&gt;
* Improve checks for out-of-date Intel Graphics drivers on Windows&lt;br /&gt;
&lt;br /&gt;
== 2020.3.8 ==&lt;br /&gt;
&lt;br /&gt;
* Fix behaviour of &amp;lt;code&amp;gt;&amp;lt;local&amp;gt;&amp;lt;/code&amp;gt; particle systems &lt;br /&gt;
* Fix autumn tree appearance&lt;br /&gt;
&lt;br /&gt;
== 2020.3.9 ==&lt;br /&gt;
&lt;br /&gt;
* Fix crash in Swift&lt;br /&gt;
* Corrections to MP protocol timing&lt;br /&gt;
* Correct URL to FGData&lt;br /&gt;
* Fix bug in cache reload dialog&lt;br /&gt;
* Improvements to ATC dialog to display frequencies with 3 decimal places correctly&lt;br /&gt;
* Improve material definitions for Africa, Mediterranean regions&lt;br /&gt;
* Add updated ocean and water visual effects&lt;br /&gt;
&lt;br /&gt;
== 2020.3.10 ==&lt;br /&gt;
&lt;br /&gt;
* Transponder: make standby mode work&lt;br /&gt;
* Launcher: pick up scenery and aircraft paths from the command line&lt;br /&gt;
* Launcher: store locations differently, to avoid problems when running multiple FlightGear versions and switching between them.&lt;br /&gt;
* Launcher: add 'restart on quit' option&lt;br /&gt;
* Fix NavCache errors loading ShapeFile data&lt;br /&gt;
* Fix NavCache errors when running multiple copies of FlightGear&lt;br /&gt;
&lt;br /&gt;
== 2020.3.11 ==&lt;br /&gt;
&lt;br /&gt;
* Fix a crash introduced in 2020.3.10&lt;br /&gt;
* Improve error message when no aircraft search paths are available&lt;br /&gt;
* Fix a crash with misconfigured traffic taxi routes&lt;br /&gt;
* Update AI traffic schedules&lt;br /&gt;
&lt;br /&gt;
== 2020.3.12 ==&lt;br /&gt;
&lt;br /&gt;
* Add aircraft directory name validation &lt;br /&gt;
* Add an extra step of antialiasing (8x)&lt;br /&gt;
* Add feature allowing aircraft to define custom fonts for osg::Text&lt;br /&gt;
* Add generic combined ALS procedural lights and Compositor lights&lt;br /&gt;
* Add new regional materials for Australia&lt;br /&gt;
* Fix Basic Weather producing invalid pressure altitudes&lt;br /&gt;
* Fix bug in path searching for previews&lt;br /&gt;
* Fix bug in sound system when approaching max-dist range&lt;br /&gt;
* Fix crashes after reset&lt;br /&gt;
* Fix crash when AI aircraft has invalid destination runway&lt;br /&gt;
* Fix Mapstructure error in RTE layer&lt;br /&gt;
* Fix --view-offset to use the correct property&lt;br /&gt;
* HUD: make vertical gauges look the same as horizontal ones&lt;br /&gt;
* Improved Russian and Spanish translations&lt;br /&gt;
* Miscellaneous improvements to weather dialog&lt;br /&gt;
* Property browser: display values for folders in verbose mode &lt;br /&gt;
* Route manager: select correct waypoint when duplicate waypoints exist&lt;br /&gt;
* Update AI traffic schedules and add new AI models&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
{{Appendix}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:FlightGear changelogs‎]]&lt;br /&gt;
[[Zh:2020.3]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_Flightplan&amp;diff=134525</id>
		<title>Nasal Flightplan</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_Flightplan&amp;diff=134525"/>
		<updated>2022-01-26T12:31:22Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: /* Leg methods and variables */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Systems Modeling Disclaimer}}&lt;br /&gt;
{{Autoflight Navigation}}&lt;br /&gt;
{{Nasal Navigation}}&lt;br /&gt;
&lt;br /&gt;
Because FlightGear's [[route manager]] flight plan system is exposed to [[Nasal]], '''Nasal can be used to interact with flight plans'''. Obviously, this is very useful, especially for aircraft like airliners, which have complex route managers systems. This article shows how this can be done.&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Nasal functions relating to the route manager system include:&lt;br /&gt;
* {{func link|flightplan()}} - return the active plan.&lt;br /&gt;
* {{func link|airwaysRoute()}}&lt;br /&gt;
* {{func link|createFlightplan()}} - creates new empty plan. A path can be supplied to load a plan from xml.&lt;br /&gt;
&lt;br /&gt;
Flight plans are based on waypoints, which, in C++, inherit from the {{API Link|flightgear|class|FGPositioned}} class.&lt;br /&gt;
&lt;br /&gt;
== Waypoint ghost ==&lt;br /&gt;
The following are members of a waypoint ghost, as generated by, for example, {{func link|airwaysRoute()}}:&lt;br /&gt;
&lt;br /&gt;
; wp_name ''or'' id: Name of the waypoint, returned as string.&lt;br /&gt;
; wp_type :Waypoint type, returned as string. One of &amp;quot;basic,&amp;quot; &amp;quot;navaid,&amp;quot; &amp;quot;offset-navaid,&amp;quot; &amp;quot;runway,&amp;quot; &amp;quot;hold&amp;quot;,  &amp;quot;hdgToAlt,&amp;quot; &amp;quot;dmeIntercept,&amp;quot; &amp;quot;radialIntercept,&amp;quot; &amp;quot;discontinuity&amp;quot;, &amp;quot;via&amp;quot;, or &amp;quot;vectors.&amp;quot;&lt;br /&gt;
; wp_role:Role of waypoint. One of &amp;quot;pseudo&amp;quot;, &amp;quot;sid&amp;quot;, &amp;quot;star&amp;quot;, &amp;quot;missed&amp;quot;, &amp;quot;approach&amp;quot;&lt;br /&gt;
; wp_lat ''or'' lat : Latitude of waypoint.&lt;br /&gt;
; wp_lon ''or'' lon : Longitude of waypoint.&lt;br /&gt;
; wp_parent_name : Name of waypoint's parent.&lt;br /&gt;
; wp_parent :Waypoint's parent as a ghost.&lt;br /&gt;
; fly_type : How to waypoint should be flown over or reacted to. One of &amp;quot;flyOver&amp;quot; or &amp;quot;flyBy&amp;quot; or &amp;quot;Hold&amp;quot;.&lt;br /&gt;
; heading_course :Heading of runway, hdgToAlt, hold, radialIntercept, or dmeIntercept waypoints&lt;br /&gt;
; hidden:Boolean flag as to whether it should be shown on map / navigation display when included in a flightplan&lt;br /&gt;
&lt;br /&gt;
=== Hold members ===&lt;br /&gt;
The following are hold-specific members:&lt;br /&gt;
; hold_is_left_handed : boolean, defines direction of turns in the hold&lt;br /&gt;
; hold_is_distance : boolean, defines if hold is measured by distance&lt;br /&gt;
; hold_is_time : boolean, defines if hold is measured by time&lt;br /&gt;
; hold_inbound_radial ''or'' hold_inbound_radial_deg : returns the inbound radial of the hold, measured in degrees&lt;br /&gt;
; hold_time_or_distance : the leg length, defined either in seconds or nautical miles&lt;br /&gt;
&lt;br /&gt;
== Flightplan methods and variables ==&lt;br /&gt;
Notice that instead of passing a leg as parameter, a waypoint can be passed.&lt;br /&gt;
; getWP(index) : Returns the leg for specified index.&lt;br /&gt;
; currentWP() : Return current active leg.&lt;br /&gt;
; nextWP() : Make next waypoint active.&lt;br /&gt;
; getPlanSize() : Returns number of waypoints&lt;br /&gt;
; appendWP(leg) : Add a leg to the end of the flightplan.&lt;br /&gt;
; insertWP(leg, index) : Pass a leg object and its position. Example: insertWP(leg, 1) --&amp;gt; leg becomes waypoint at index 1.&lt;br /&gt;
; deleteWP(index) : Deletes the waypoint at specified index. Example: deleteWP(0) --&amp;gt; deletes first waypoint. &lt;br /&gt;
; insertWPAfter() : &lt;br /&gt;
; insertWaypoints(vector, index) : Pass a vector of waypoint objects, and the position to insert.&lt;br /&gt;
; cleanPlan() : Clears all waypoints except destination and departure.&lt;br /&gt;
; clearWPType(type) : Supply a type string, it will clear all waypoints of the type.&lt;br /&gt;
; clone() : Return a copy of the flightplan.&lt;br /&gt;
; pathGeod() or pointAlongRoute() : (function has two associated names). This is used for graphical display: it’s an array of coordinates which show the path of the plan. This includes holds, procedure turns, turn anticipation and more.&lt;br /&gt;
; finish() : Finish the plan. (a call to delegate will be made)&lt;br /&gt;
; indexOfWP(wp) : Returns the index of the passed waypoint/leg.&lt;br /&gt;
; destination : airport object as destination.&lt;br /&gt;
; destination_runway : rwy object as destination and its airport implicit.&lt;br /&gt;
; departure : airport object as departure.&lt;br /&gt;
; departure_runway : rwy object as departure and its airport implicit.&lt;br /&gt;
; id : optional name of plan.&lt;br /&gt;
; sid : procedure object for SID.&lt;br /&gt;
; star : procedure object for STAR.&lt;br /&gt;
; sid_trans : procedure object for SID transition (as of 2020.2, may be written to)&lt;br /&gt;
; star_trans : procedure object for STAR transition (as of 2020.2, may be written to)&lt;br /&gt;
; approach : procedure object for approach.&lt;br /&gt;
; current : Index of current waypoint.&lt;br /&gt;
; aircraftCategory : ICAO aircraft category.&lt;br /&gt;
; followLegTrackToFix : Specific used by some procedures. It controls whether the system will fly on an intersection course (and hence, different track) to the end of the leg, or make a corrective S-turn to get back on the leg track immediately it becomes possible.&lt;br /&gt;
; activate() : This will make the flight plan the default (the one used in route-manager).&lt;br /&gt;
; save(path) : Save a plan to xml. Will return true or false for success.&lt;br /&gt;
&lt;br /&gt;
== Leg methods and variables ==&lt;br /&gt;
A leg is a wrapper for a waypoint, so it will have all waypoints variables and methods plus what is listed below.&lt;br /&gt;
Notice, that a leg you have gotten from a plan, but deleted in the plan, will be invalid and should not be used or modified.&lt;br /&gt;
A leg you have gotten from a plan, when modified, will modify the leg inside the plan you got it from.&lt;br /&gt;
; setSpeed(speed, type) : Sets the speed restriction. Setting nil type, will crash FG, setting empty type is same as setting &amp;quot;at&amp;quot;. See below for type list.&lt;br /&gt;
; setAltitude(altitude, type) : Sets the altitude restriction. Setting nil type, will crash FG, setting empty type is same as setting &amp;quot;at&amp;quot;. See below for type list.&lt;br /&gt;
; path() : Returns a vector of hashes containing lat and lon variables. These compromise a curved path for long non straight legs.&lt;br /&gt;
; courseAndDistanceFrom(coord) : Return vector with true course and distance. Coord is a geo.Coord.&lt;br /&gt;
; parents : Nasal parents.&lt;br /&gt;
; wp_parent: Will return you the owning route-structure of the WP - this could be an airway, procedure, or the flightplan if the waypoint doesn’t belong to a route structure.&lt;br /&gt;
; index : Returns the index of the leg in the owning route-structure.&lt;br /&gt;
; alt_cstr : Read-only. Altitude restriction output. Set using setAltitude.&lt;br /&gt;
; alt_cstr_type : Read-only. Altitude restriction type. See below for list.&lt;br /&gt;
; speed_cstr : Read-only. Speed restriction output. Set using setSpeed.&lt;br /&gt;
; speed_cstr_type : Read-only. Speed restriction. See below for list.&lt;br /&gt;
; leg_distance : Returns distance along the leg, from the preceding waypoint.&lt;br /&gt;
; leg_bearing : Returns the bearing along the leg.&lt;br /&gt;
; distance_along_route : Return the total distance laterally along the route to the beginning of the leg.&lt;br /&gt;
&lt;br /&gt;
For speed restrictions these types can be used:&lt;br /&gt;
* &amp;quot;at&amp;quot; = kt should be spot on&lt;br /&gt;
* &amp;quot;above&amp;quot; = kt should be higher&lt;br /&gt;
* &amp;quot;below&amp;quot; = kt should be under&lt;br /&gt;
* &amp;quot;computed&amp;quot; = predicted kt&lt;br /&gt;
* &amp;quot;computed-mach&amp;quot; = predicted mach&lt;br /&gt;
* &amp;quot;mach&amp;quot; = its in mach instead of kt&lt;br /&gt;
* &amp;quot;delete&amp;quot; = Cleared by ATC&lt;br /&gt;
&lt;br /&gt;
For altitude restrictions these types can be used:&lt;br /&gt;
* &amp;quot;at&amp;quot; = alt should be spot on&lt;br /&gt;
* &amp;quot;above&amp;quot; = alt should be higher&lt;br /&gt;
* &amp;quot;below&amp;quot; = alt should be below&lt;br /&gt;
* &amp;quot;computed&amp;quot; = predicted alt&lt;br /&gt;
* &amp;quot;computed-mach&amp;quot; = not used for altitude&lt;br /&gt;
* &amp;quot;mach&amp;quot; = not used for altitude&lt;br /&gt;
* &amp;quot;delete&amp;quot; = Cleared by ATC&lt;br /&gt;
&lt;br /&gt;
== Procedure methods and variables ==&lt;br /&gt;
; id : a string containing the name of the procedure&lt;br /&gt;
; airport : airport object associated with the procedure&lt;br /&gt;
; radio: for instrument approaches, returns the type of procedure (VOR, ILS, RNAV, or NDB)&lt;br /&gt;
; tp_type: returns the type of procedure (sid, star, or iap)&lt;br /&gt;
; runways: a vector containing the runways associated with the procedure&lt;br /&gt;
; transitions : a vector containing the transitions of the procedure (for SIDS and STARS only)&lt;br /&gt;
; route(runway) : Returns a vector of waypoints.&lt;br /&gt;
; transition() : Only works on STAR and SID.&lt;br /&gt;
&lt;br /&gt;
== Airport methods and variables ==&lt;br /&gt;
&lt;br /&gt;
; runway : a ghost for the runway passed as a string or nil&lt;br /&gt;
; runwaysWithoutReciprocals : &lt;br /&gt;
; helipad : a ghost for the helipad passed as a string or nil&lt;br /&gt;
; tower : returns hash containing airport tower location&lt;br /&gt;
; comms : contains vector containing communication frequencies&lt;br /&gt;
; sids : a vector containing the ids of sids of the airport, if a runway is passed, just for that runway. Pass an id into getSid to get the ghost.&lt;br /&gt;
; stars : a vector containing the ids of stars of the airport, if a runway is passed, just for that runway. Pass an id into getStar to get the ghost.&lt;br /&gt;
; getApproachList : a vector containing the ids of IAPs of the airport, if a runway is passed, just for that runway. Pass an id into getIAP to get the ghost.&lt;br /&gt;
; parking : a vector containing parking positions of the airport&lt;br /&gt;
; getSid : a ghost for a SID&lt;br /&gt;
; getStar : a ghost for a STAR&lt;br /&gt;
; getIAP : a ghost for a IAP&lt;br /&gt;
; findBestRunwayForPos : passed a position, returns a ghost for the runway it decides is best&lt;br /&gt;
; toString : returns &amp;quot;an airport &amp;quot; + the airport id&lt;br /&gt;
&lt;br /&gt;
== Airway methods and variables ==&lt;br /&gt;
&lt;br /&gt;
; id : returns identifier of airway&lt;br /&gt;
; level: &amp;quot;high&amp;quot;, &amp;quot;low&amp;quot;, or &amp;quot;both&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
# get the active flight plan (the one being used by the route manager)&lt;br /&gt;
var fp = flightplan();&lt;br /&gt;
&lt;br /&gt;
# or create one an XML file&lt;br /&gt;
fp = flightplan('/path/to/xml');&lt;br /&gt;
&lt;br /&gt;
# save the active flight plan&lt;br /&gt;
fgcommand(&amp;quot;save-flightplan&amp;quot;, props.Node.new({&amp;quot;path&amp;quot;: 'path/to/xml'}));&lt;br /&gt;
&lt;br /&gt;
# duplicate a flight-plan&lt;br /&gt;
var secondary = fp.clone();&lt;br /&gt;
&lt;br /&gt;
var dest = airportinfo('KSFO');&lt;br /&gt;
var rwy = dest.runway('19L');&lt;br /&gt;
# the the arrival runway (and airport, automatically)&lt;br /&gt;
fp.destination_runway = rwy;&lt;br /&gt;
&lt;br /&gt;
# or if no runway is known/specified&lt;br /&gt;
fp.destination = dest;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Building procedures and transitions. As mentioned above there's a couple of different ways to handle this, the examples below assume the C++ code automatically deletes and re-inserts waypoints for procedures, but that's only one possible design.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var apt = airportinfo('KSFO');&lt;br /&gt;
# example for SIDs, STARs are the same, approaches too&lt;br /&gt;
var allSids = apt.sids();&lt;br /&gt;
&lt;br /&gt;
# SIDs for a specific runway - note these return SID IDs as string, for compatibility with existing code&lt;br /&gt;
var rwySids = apt.sids('28L');&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Inserting and deleting waypoints (possibly in batches)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var fp = flightplan();&lt;br /&gt;
# waypoint created from lat, lon, or a navaid, or anything else?&lt;br /&gt;
var pos = geo.aircraft_position().apply_course_distance(getprop(&amp;quot;/orientation/heading-deg&amp;quot;), 100000);&lt;br /&gt;
var wp = createWP(pos.lat(), pos.lon(), &amp;quot;EPICA&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
# manually insert a waypoint at the end of the plan&lt;br /&gt;
fp.insertWP(wp, fp.getPlanSize());&lt;br /&gt;
&lt;br /&gt;
# manually insert a waypoint at a defined position (n) into the plan&lt;br /&gt;
fp.insertWP(wp, n);&lt;br /&gt;
&lt;br /&gt;
# route along airways, and insert a whole bunch of waypoints&lt;br /&gt;
# this is needed for the route-manager dialog, maybe not for a&lt;br /&gt;
# real FMS interface....&lt;br /&gt;
var segment = [&amp;lt;waypoint object&amp;gt;, &amp;lt;waypoint object&amp;gt;, &amp;lt;waypoint object&amp;gt;];&lt;br /&gt;
# segment is a vector of waypoints now&lt;br /&gt;
fp.insertWaypoints(segment, fp.getPlanSize());&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== aircraft.history() (3.2+) ==&lt;br /&gt;
&lt;br /&gt;
Function to expose flight history as aircraft.history()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var hist = aircraft.history();&lt;br /&gt;
&lt;br /&gt;
# get history of aircraft position/orientation collapsing&lt;br /&gt;
# nodes with a distance smaller than the given minimum&lt;br /&gt;
# edge length&lt;br /&gt;
debug.dump( hist.pathForHistory(&amp;lt;minimum-edge-length-meter&amp;gt;) );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Related content ==&lt;br /&gt;
=== Wiki articles ===&lt;br /&gt;
* [[Nasal library#Extension functions|Nasal library § Extension functions]]&lt;br /&gt;
* [[Navdata cache#Accessing via Nasal|Navdata cache § Accessing via Nasal]]&lt;br /&gt;
* [[Route Manager]]&lt;br /&gt;
* [[Route Manager internals]]&lt;br /&gt;
* [[Howto:Control the route manager in Nasal]]&lt;br /&gt;
&lt;br /&gt;
=== Documentation ===&lt;br /&gt;
* [http://api-docs.freeflightsim.org/flightgear/NasalPositioned_8cxx_source.html#l00585 flightplanGhostSetMember] — ''Members of a flight plan object that can be set.''&lt;br /&gt;
* [http://api-docs.freeflightsim.org/flightgear/NasalPositioned_8cxx_source.html#l00557 flightplanGhostGetMember] — ''Members of flight plan object that can be read.''&lt;br /&gt;
* [http://api-docs.freeflightsim.org/flightgear/NasalPositioned_8cxx_source.html#l02485 initNasalPositioned] — ''Contains a list of functions that can be called on airport, flight plan, waypoint, procedure, or flight plan leg objects.''&lt;br /&gt;
* [http://api-docs.freeflightsim.org/flightgear/route__mgr_8cxx_source.html#l00220 FGRouteMgr::FGRouteMgr] — ''List of [[fgcommands]] relating to the route manager.''&lt;br /&gt;
&lt;br /&gt;
=== Misc ===&lt;br /&gt;
* https://sourceforge.net/p/flightgear/mailman/message/34688624/&lt;br /&gt;
* https://sourceforge.net/p/flightgear/mailman/message/35164289/&lt;br /&gt;
* https://sourceforge.net/p/flightgear/mailman/flightgear-devel/thread/BB67C9F3-028B-40E5-94E4-246CD1E0B2CC%40mac.com/#msg23708827&lt;br /&gt;
* https://sourceforge.net/p/flightgear/mailman/message/33699574/&lt;br /&gt;
* https://sourceforge.net/p/flightgear/mailman/message/21010010/&lt;br /&gt;
* https://sourceforge.net/p/flightgear/mailman/message/23678747/&lt;br /&gt;
&lt;br /&gt;
=== Search Queries ===&lt;br /&gt;
&lt;br /&gt;
=== Commits ===&lt;br /&gt;
&lt;br /&gt;
=== Threads ===&lt;br /&gt;
{{Appendix}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Nasal]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_Flightplan&amp;diff=134482</id>
		<title>Nasal Flightplan</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_Flightplan&amp;diff=134482"/>
		<updated>2022-01-19T09:40:02Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: /* Waypoint ghost */ Add extra members&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Systems Modeling Disclaimer}}&lt;br /&gt;
{{Autoflight Navigation}}&lt;br /&gt;
{{Nasal Navigation}}&lt;br /&gt;
&lt;br /&gt;
Because FlightGear's [[route manager]] flight plan system is exposed to [[Nasal]], '''Nasal can be used to interact with flight plans'''. Obviously, this is very useful, especially for aircraft like airliners, which have complex route managers systems. This article shows how this can be done.&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Nasal functions relating to the route manager system include:&lt;br /&gt;
* {{func link|flightplan()}} - return the active plan.&lt;br /&gt;
* {{func link|airwaysRoute()}}&lt;br /&gt;
* {{func link|createFlightplan()}} - creates new empty plan. A path can be supplied to load a plan from xml.&lt;br /&gt;
&lt;br /&gt;
Flight plans are based on waypoints, which, in C++, inherit from the {{API Link|flightgear|class|FGPositioned}} class.&lt;br /&gt;
&lt;br /&gt;
== Waypoint ghost ==&lt;br /&gt;
The following are members of a waypoint ghost, as generated by, for example, {{func link|airwaysRoute()}}:&lt;br /&gt;
&lt;br /&gt;
; wp_name ''or'' id: Name of the waypoint, returned as string.&lt;br /&gt;
; wp_type :Waypoint type, returned as string. One of &amp;quot;basic,&amp;quot; &amp;quot;navaid,&amp;quot; &amp;quot;offset-navaid,&amp;quot; &amp;quot;runway,&amp;quot; &amp;quot;hold&amp;quot;,  &amp;quot;hdgToAlt,&amp;quot; &amp;quot;dmeIntercept,&amp;quot; &amp;quot;radialIntercept,&amp;quot; &amp;quot;discontinuity&amp;quot;, &amp;quot;via&amp;quot;, or &amp;quot;vectors.&amp;quot;&lt;br /&gt;
; wp_role:Role of waypoint. One of &amp;quot;pseudo&amp;quot;, &amp;quot;sid&amp;quot;, &amp;quot;star&amp;quot;, &amp;quot;missed&amp;quot;, &amp;quot;approach&amp;quot;&lt;br /&gt;
; wp_lat ''or'' lat : Latitude of waypoint.&lt;br /&gt;
; wp_lon ''or'' lon : Longitude of waypoint.&lt;br /&gt;
; wp_parent_name : Name of waypoint's parent.&lt;br /&gt;
; wp_parent :Waypoint's parent as a ghost.&lt;br /&gt;
; fly_type : How to waypoint should be flown over or reacted to. One of &amp;quot;flyOver&amp;quot; or &amp;quot;flyBy&amp;quot; or &amp;quot;Hold&amp;quot;.&lt;br /&gt;
; heading_course :Heading of runway, hdgToAlt, hold, radialIntercept, or dmeIntercept waypoints&lt;br /&gt;
; hidden:Boolean flag as to whether it should be shown on map / navigation display when included in a flightplan&lt;br /&gt;
&lt;br /&gt;
=== Hold members ===&lt;br /&gt;
The following are hold-specific members:&lt;br /&gt;
; hold_is_left_handed : boolean, defines direction of turns in the hold&lt;br /&gt;
; hold_is_distance : boolean, defines if hold is measured by distance&lt;br /&gt;
; hold_is_time : boolean, defines if hold is measured by time&lt;br /&gt;
; hold_inbound_radial ''or'' hold_inbound_radial_deg : returns the inbound radial of the hold, measured in degrees&lt;br /&gt;
; hold_time_or_distance : the leg length, defined either in seconds or nautical miles&lt;br /&gt;
&lt;br /&gt;
== Flightplan methods and variables ==&lt;br /&gt;
Notice that instead of passing a leg as parameter, a waypoint can be passed.&lt;br /&gt;
; getWP(index) : Returns the leg for specified index.&lt;br /&gt;
; currentWP() : Return current active leg.&lt;br /&gt;
; nextWP() : Make next waypoint active.&lt;br /&gt;
; getPlanSize() : Returns number of waypoints&lt;br /&gt;
; appendWP(leg) : Add a leg to the end of the flightplan.&lt;br /&gt;
; insertWP(leg, index) : Pass a leg object and its position. Example: insertWP(leg, 1) --&amp;gt; leg becomes waypoint at index 1.&lt;br /&gt;
; deleteWP(index) : Deletes the waypoint at specified index. Example: deleteWP(0) --&amp;gt; deletes first waypoint. &lt;br /&gt;
; insertWPAfter() : &lt;br /&gt;
; insertWaypoints(vector, index) : Pass a vector of waypoint objects, and the position to insert.&lt;br /&gt;
; cleanPlan() : Clears all waypoints except destination and departure.&lt;br /&gt;
; clearWPType(type) : Supply a type string, it will clear all waypoints of the type.&lt;br /&gt;
; clone() : Return a copy of the flightplan.&lt;br /&gt;
; pathGeod() or pointAlongRoute() : (function has two associated names). This is used for graphical display: it’s an array of coordinates which show the path of the plan. This includes holds, procedure turns, turn anticipation and more.&lt;br /&gt;
; finish() : Finish the plan. (a call to delegate will be made)&lt;br /&gt;
; indexOfWP(wp) : Returns the index of the passed waypoint/leg.&lt;br /&gt;
; destination : airport object as destination.&lt;br /&gt;
; destination_runway : rwy object as destination and its airport implicit.&lt;br /&gt;
; departure : airport object as departure.&lt;br /&gt;
; departure_runway : rwy object as departure and its airport implicit.&lt;br /&gt;
; id : optional name of plan.&lt;br /&gt;
; sid : procedure object for SID.&lt;br /&gt;
; star : procedure object for STAR.&lt;br /&gt;
; sid_trans : procedure object for SID transition (as of 2020.2, may be written to)&lt;br /&gt;
; star_trans : procedure object for STAR transition (as of 2020.2, may be written to)&lt;br /&gt;
; approach : procedure object for approach.&lt;br /&gt;
; current : Index of current waypoint.&lt;br /&gt;
; aircraftCategory : ICAO aircraft category.&lt;br /&gt;
; followLegTrackToFix : Specific used by some procedures. It controls whether the system will fly on an intersection course (and hence, different track) to the end of the leg, or make a corrective S-turn to get back on the leg track immediately it becomes possible.&lt;br /&gt;
; activate() : This will make the flight plan the default (the one used in route-manager).&lt;br /&gt;
; save(path) : Save a plan to xml. Will return true or false for success.&lt;br /&gt;
&lt;br /&gt;
== Leg methods and variables ==&lt;br /&gt;
A leg is a wrapper for a waypoint, so it will have all waypoints variables and methods plus what is listed below.&lt;br /&gt;
Notice, that a leg you have gotten from a plan, but deleted in the plan, will be invalid and should not be used or modified.&lt;br /&gt;
A leg you have gotten from a plan, when modified, will modify the leg inside the plan you got it from.&lt;br /&gt;
; setSpeed(speed, type) : Sets the speed restriction. Setting nil type, will crash FG, setting empty type is same as setting &amp;quot;at&amp;quot;. See below for type list.&lt;br /&gt;
; setAltitude(altitude, type) : Sets the altitude restriction. Setting nil type, will crash FG, setting empty type is same as setting &amp;quot;at&amp;quot;. See below for type list.&lt;br /&gt;
; path() : Returns a vector of hashes containing lat and lon variables. These compromise a curved path for long non straight legs.&lt;br /&gt;
; courseAndDistanceFrom(coord) : Return vector with true course and distance. Coord is a geo.Coord.&lt;br /&gt;
; parents : Nasal parents.&lt;br /&gt;
; wp_owner : Will return you the owning route-structure of the WP - this could be an airway, procedure, or the flightplan if the waypoint doesn’t belong to a route structure.&lt;br /&gt;
; index : Returns the index of the leg in the owning route-structure.&lt;br /&gt;
; alt_cstr : Read-only. Altitude restriction output. Set using setAltitude.&lt;br /&gt;
; alt_cstr_type : Read-only. Altitude restriction type. See below for list.&lt;br /&gt;
; speed_cstr : Read-only. Speed restriction output. Set using setSpeed.&lt;br /&gt;
; speed_cstr_type : Read-only. Speed restriction. See below for list.&lt;br /&gt;
; leg_distance : Returns distance along the leg, from the preceding waypoint.&lt;br /&gt;
; leg_bearing : Returns the bearing along the leg.&lt;br /&gt;
; distance_along_route : Return the total distance laterally along the route to the beginning of the leg.&lt;br /&gt;
&lt;br /&gt;
For speed restrictions these types can be used:&lt;br /&gt;
* &amp;quot;at&amp;quot; = kt should be spot on&lt;br /&gt;
* &amp;quot;above&amp;quot; = kt should be higher&lt;br /&gt;
* &amp;quot;below&amp;quot; = kt should be under&lt;br /&gt;
* &amp;quot;computed&amp;quot; = predicted kt&lt;br /&gt;
* &amp;quot;computed-mach&amp;quot; = predicted mach&lt;br /&gt;
* &amp;quot;mach&amp;quot; = its in mach instead of kt&lt;br /&gt;
* &amp;quot;delete&amp;quot; = Cleared by ATC&lt;br /&gt;
&lt;br /&gt;
For altitude restrictions these types can be used:&lt;br /&gt;
* &amp;quot;at&amp;quot; = alt should be spot on&lt;br /&gt;
* &amp;quot;above&amp;quot; = alt should be higher&lt;br /&gt;
* &amp;quot;below&amp;quot; = alt should be below&lt;br /&gt;
* &amp;quot;computed&amp;quot; = predicted alt&lt;br /&gt;
* &amp;quot;computed-mach&amp;quot; = not used for altitude&lt;br /&gt;
* &amp;quot;mach&amp;quot; = not used for altitude&lt;br /&gt;
* &amp;quot;delete&amp;quot; = Cleared by ATC&lt;br /&gt;
&lt;br /&gt;
== Procedure methods and variables ==&lt;br /&gt;
; id : a string containing the name of the procedure&lt;br /&gt;
; airport : airport object associated with the procedure&lt;br /&gt;
; radio: for instrument approaches, returns the type of procedure (VOR, ILS, RNAV, or NDB)&lt;br /&gt;
; tp_type: returns the type of procedure (sid, star, or iap)&lt;br /&gt;
; runways: a vector containing the runways associated with the procedure&lt;br /&gt;
; transitions : a vector containing the transitions of the procedure (for SIDS and STARS only)&lt;br /&gt;
; route(runway) : Returns a vector of waypoints.&lt;br /&gt;
; transition() : Only works on STAR and SID.&lt;br /&gt;
&lt;br /&gt;
== Airport methods and variables ==&lt;br /&gt;
&lt;br /&gt;
; runway : a ghost for the runway passed as a string or nil&lt;br /&gt;
; runwaysWithoutReciprocals : &lt;br /&gt;
; helipad : a ghost for the helipad passed as a string or nil&lt;br /&gt;
; tower : returns hash containing airport tower location&lt;br /&gt;
; comms : contains vector containing communication frequencies&lt;br /&gt;
; sids : a vector containing the ids of sids of the airport, if a runway is passed, just for that runway. Pass an id into getSid to get the ghost.&lt;br /&gt;
; stars : a vector containing the ids of stars of the airport, if a runway is passed, just for that runway. Pass an id into getStar to get the ghost.&lt;br /&gt;
; getApproachList : a vector containing the ids of IAPs of the airport, if a runway is passed, just for that runway. Pass an id into getIAP to get the ghost.&lt;br /&gt;
; parking : a vector containing parking positions of the airport&lt;br /&gt;
; getSid : a ghost for a SID&lt;br /&gt;
; getStar : a ghost for a STAR&lt;br /&gt;
; getIAP : a ghost for a IAP&lt;br /&gt;
; findBestRunwayForPos : passed a position, returns a ghost for the runway it decides is best&lt;br /&gt;
; toString : returns &amp;quot;an airport &amp;quot; + the airport id&lt;br /&gt;
&lt;br /&gt;
== Airway methods and variables ==&lt;br /&gt;
&lt;br /&gt;
; id : returns identifier of airway&lt;br /&gt;
; level: &amp;quot;high&amp;quot;, &amp;quot;low&amp;quot;, or &amp;quot;both&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
# get the active flight plan (the one being used by the route manager)&lt;br /&gt;
var fp = flightplan();&lt;br /&gt;
&lt;br /&gt;
# or create one an XML file&lt;br /&gt;
fp = flightplan('/path/to/xml');&lt;br /&gt;
&lt;br /&gt;
# save the active flight plan&lt;br /&gt;
fgcommand(&amp;quot;save-flightplan&amp;quot;, props.Node.new({&amp;quot;path&amp;quot;: 'path/to/xml'}));&lt;br /&gt;
&lt;br /&gt;
# duplicate a flight-plan&lt;br /&gt;
var secondary = fp.clone();&lt;br /&gt;
&lt;br /&gt;
var dest = airportinfo('KSFO');&lt;br /&gt;
var rwy = dest.runway('19L');&lt;br /&gt;
# the the arrival runway (and airport, automatically)&lt;br /&gt;
fp.destination_runway = rwy;&lt;br /&gt;
&lt;br /&gt;
# or if no runway is known/specified&lt;br /&gt;
fp.destination = dest;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Building procedures and transitions. As mentioned above there's a couple of different ways to handle this, the examples below assume the C++ code automatically deletes and re-inserts waypoints for procedures, but that's only one possible design.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var apt = airportinfo('KSFO');&lt;br /&gt;
# example for SIDs, STARs are the same, approaches too&lt;br /&gt;
var allSids = apt.sids();&lt;br /&gt;
&lt;br /&gt;
# SIDs for a specific runway - note these return SID IDs as string, for compatibility with existing code&lt;br /&gt;
var rwySids = apt.sids('28L');&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Inserting and deleting waypoints (possibly in batches)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var fp = flightplan();&lt;br /&gt;
# waypoint created from lat, lon, or a navaid, or anything else?&lt;br /&gt;
var pos = geo.aircraft_position().apply_course_distance(getprop(&amp;quot;/orientation/heading-deg&amp;quot;), 100000);&lt;br /&gt;
var wp = createWP(pos.lat(), pos.lon(), &amp;quot;EPICA&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
# manually insert a waypoint at the end of the plan&lt;br /&gt;
fp.insertWP(wp, fp.getPlanSize());&lt;br /&gt;
&lt;br /&gt;
# manually insert a waypoint at a defined position (n) into the plan&lt;br /&gt;
fp.insertWP(wp, n);&lt;br /&gt;
&lt;br /&gt;
# route along airways, and insert a whole bunch of waypoints&lt;br /&gt;
# this is needed for the route-manager dialog, maybe not for a&lt;br /&gt;
# real FMS interface....&lt;br /&gt;
var segment = [&amp;lt;waypoint object&amp;gt;, &amp;lt;waypoint object&amp;gt;, &amp;lt;waypoint object&amp;gt;];&lt;br /&gt;
# segment is a vector of waypoints now&lt;br /&gt;
fp.insertWaypoints(segment, fp.getPlanSize());&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== aircraft.history() (3.2+) ==&lt;br /&gt;
&lt;br /&gt;
Function to expose flight history as aircraft.history()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var hist = aircraft.history();&lt;br /&gt;
&lt;br /&gt;
# get history of aircraft position/orientation collapsing&lt;br /&gt;
# nodes with a distance smaller than the given minimum&lt;br /&gt;
# edge length&lt;br /&gt;
debug.dump( hist.pathForHistory(&amp;lt;minimum-edge-length-meter&amp;gt;) );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Related content ==&lt;br /&gt;
=== Wiki articles ===&lt;br /&gt;
* [[Nasal library#Extension functions|Nasal library § Extension functions]]&lt;br /&gt;
* [[Navdata cache#Accessing via Nasal|Navdata cache § Accessing via Nasal]]&lt;br /&gt;
* [[Route Manager]]&lt;br /&gt;
* [[Route Manager internals]]&lt;br /&gt;
* [[Howto:Control the route manager in Nasal]]&lt;br /&gt;
&lt;br /&gt;
=== Documentation ===&lt;br /&gt;
* [http://api-docs.freeflightsim.org/flightgear/NasalPositioned_8cxx_source.html#l00585 flightplanGhostSetMember] — ''Members of a flight plan object that can be set.''&lt;br /&gt;
* [http://api-docs.freeflightsim.org/flightgear/NasalPositioned_8cxx_source.html#l00557 flightplanGhostGetMember] — ''Members of flight plan object that can be read.''&lt;br /&gt;
* [http://api-docs.freeflightsim.org/flightgear/NasalPositioned_8cxx_source.html#l02485 initNasalPositioned] — ''Contains a list of functions that can be called on airport, flight plan, waypoint, procedure, or flight plan leg objects.''&lt;br /&gt;
* [http://api-docs.freeflightsim.org/flightgear/route__mgr_8cxx_source.html#l00220 FGRouteMgr::FGRouteMgr] — ''List of [[fgcommands]] relating to the route manager.''&lt;br /&gt;
&lt;br /&gt;
=== Misc ===&lt;br /&gt;
* https://sourceforge.net/p/flightgear/mailman/message/34688624/&lt;br /&gt;
* https://sourceforge.net/p/flightgear/mailman/message/35164289/&lt;br /&gt;
* https://sourceforge.net/p/flightgear/mailman/flightgear-devel/thread/BB67C9F3-028B-40E5-94E4-246CD1E0B2CC%40mac.com/#msg23708827&lt;br /&gt;
* https://sourceforge.net/p/flightgear/mailman/message/33699574/&lt;br /&gt;
* https://sourceforge.net/p/flightgear/mailman/message/21010010/&lt;br /&gt;
* https://sourceforge.net/p/flightgear/mailman/message/23678747/&lt;br /&gt;
&lt;br /&gt;
=== Search Queries ===&lt;br /&gt;
&lt;br /&gt;
=== Commits ===&lt;br /&gt;
&lt;br /&gt;
=== Threads ===&lt;br /&gt;
{{Appendix}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Nasal]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_Flightplan&amp;diff=134481</id>
		<title>Nasal Flightplan</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_Flightplan&amp;diff=134481"/>
		<updated>2022-01-19T09:38:08Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: /* Waypoint ghost */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Systems Modeling Disclaimer}}&lt;br /&gt;
{{Autoflight Navigation}}&lt;br /&gt;
{{Nasal Navigation}}&lt;br /&gt;
&lt;br /&gt;
Because FlightGear's [[route manager]] flight plan system is exposed to [[Nasal]], '''Nasal can be used to interact with flight plans'''. Obviously, this is very useful, especially for aircraft like airliners, which have complex route managers systems. This article shows how this can be done.&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Nasal functions relating to the route manager system include:&lt;br /&gt;
* {{func link|flightplan()}} - return the active plan.&lt;br /&gt;
* {{func link|airwaysRoute()}}&lt;br /&gt;
* {{func link|createFlightplan()}} - creates new empty plan. A path can be supplied to load a plan from xml.&lt;br /&gt;
&lt;br /&gt;
Flight plans are based on waypoints, which, in C++, inherit from the {{API Link|flightgear|class|FGPositioned}} class.&lt;br /&gt;
&lt;br /&gt;
== Waypoint ghost ==&lt;br /&gt;
The following are members of a waypoint ghost, as generated by, for example, {{func link|airwaysRoute()}}:&lt;br /&gt;
&lt;br /&gt;
; wp_name ''or'' id: Name of the waypoint, returned as string.&lt;br /&gt;
; wp_type :Waypoint type, returned as string. One of &amp;quot;basic,&amp;quot; &amp;quot;navaid,&amp;quot; &amp;quot;offset-navaid,&amp;quot; &amp;quot;runway,&amp;quot; &amp;quot;hold&amp;quot;,  &amp;quot;hdgToAlt,&amp;quot; &amp;quot;dmeIntercept,&amp;quot; &amp;quot;radialIntercept,&amp;quot; &amp;quot;discontinuity&amp;quot;, &amp;quot;via&amp;quot;, or &amp;quot;vectors.&amp;quot;&lt;br /&gt;
; wp_role:Role of waypoint. One of &amp;quot;pseudo&amp;quot;, &amp;quot;sid&amp;quot;, &amp;quot;star&amp;quot;, &amp;quot;missed&amp;quot;, &amp;quot;approach&amp;quot;&lt;br /&gt;
; wp_lat ''or'' lat : Latitude of waypoint.&lt;br /&gt;
; wp_lon ''or'' lon : Longitude of waypoint.&lt;br /&gt;
; wp_parent_name : Name of waypoint's parent.&lt;br /&gt;
; wp_parent :Waypoint's parent as a ghost.&lt;br /&gt;
; fly_type : How to waypoint should be flown over or reacted to. One of &amp;quot;flyOver&amp;quot; or &amp;quot;flyBy&amp;quot; or &amp;quot;Hold&amp;quot;.&lt;br /&gt;
; heading_course : Heading of runway.&lt;br /&gt;
&lt;br /&gt;
=== Hold members ===&lt;br /&gt;
The following are hold-specific members:&lt;br /&gt;
; hold_is_left_handed : boolean, defines direction of turns in the hold&lt;br /&gt;
; hold_is_distance : boolean, defines if hold is measured by distance&lt;br /&gt;
; hold_is_time : boolean, defines if hold is measured by time&lt;br /&gt;
; hold_inbound_radial ''or'' hold_inbound_radial_deg : returns the inbound radial of the hold, measured in degrees&lt;br /&gt;
; hold_time_or_distance : the leg length, defined either in seconds or nautical miles&lt;br /&gt;
&lt;br /&gt;
== Flightplan methods and variables ==&lt;br /&gt;
Notice that instead of passing a leg as parameter, a waypoint can be passed.&lt;br /&gt;
; getWP(index) : Returns the leg for specified index.&lt;br /&gt;
; currentWP() : Return current active leg.&lt;br /&gt;
; nextWP() : Make next waypoint active.&lt;br /&gt;
; getPlanSize() : Returns number of waypoints&lt;br /&gt;
; appendWP(leg) : Add a leg to the end of the flightplan.&lt;br /&gt;
; insertWP(leg, index) : Pass a leg object and its position. Example: insertWP(leg, 1) --&amp;gt; leg becomes waypoint at index 1.&lt;br /&gt;
; deleteWP(index) : Deletes the waypoint at specified index. Example: deleteWP(0) --&amp;gt; deletes first waypoint. &lt;br /&gt;
; insertWPAfter() : &lt;br /&gt;
; insertWaypoints(vector, index) : Pass a vector of waypoint objects, and the position to insert.&lt;br /&gt;
; cleanPlan() : Clears all waypoints except destination and departure.&lt;br /&gt;
; clearWPType(type) : Supply a type string, it will clear all waypoints of the type.&lt;br /&gt;
; clone() : Return a copy of the flightplan.&lt;br /&gt;
; pathGeod() or pointAlongRoute() : (function has two associated names). This is used for graphical display: it’s an array of coordinates which show the path of the plan. This includes holds, procedure turns, turn anticipation and more.&lt;br /&gt;
; finish() : Finish the plan. (a call to delegate will be made)&lt;br /&gt;
; indexOfWP(wp) : Returns the index of the passed waypoint/leg.&lt;br /&gt;
; destination : airport object as destination.&lt;br /&gt;
; destination_runway : rwy object as destination and its airport implicit.&lt;br /&gt;
; departure : airport object as departure.&lt;br /&gt;
; departure_runway : rwy object as departure and its airport implicit.&lt;br /&gt;
; id : optional name of plan.&lt;br /&gt;
; sid : procedure object for SID.&lt;br /&gt;
; star : procedure object for STAR.&lt;br /&gt;
; sid_trans : procedure object for SID transition (as of 2020.2, may be written to)&lt;br /&gt;
; star_trans : procedure object for STAR transition (as of 2020.2, may be written to)&lt;br /&gt;
; approach : procedure object for approach.&lt;br /&gt;
; current : Index of current waypoint.&lt;br /&gt;
; aircraftCategory : ICAO aircraft category.&lt;br /&gt;
; followLegTrackToFix : Specific used by some procedures. It controls whether the system will fly on an intersection course (and hence, different track) to the end of the leg, or make a corrective S-turn to get back on the leg track immediately it becomes possible.&lt;br /&gt;
; activate() : This will make the flight plan the default (the one used in route-manager).&lt;br /&gt;
; save(path) : Save a plan to xml. Will return true or false for success.&lt;br /&gt;
&lt;br /&gt;
== Leg methods and variables ==&lt;br /&gt;
A leg is a wrapper for a waypoint, so it will have all waypoints variables and methods plus what is listed below.&lt;br /&gt;
Notice, that a leg you have gotten from a plan, but deleted in the plan, will be invalid and should not be used or modified.&lt;br /&gt;
A leg you have gotten from a plan, when modified, will modify the leg inside the plan you got it from.&lt;br /&gt;
; setSpeed(speed, type) : Sets the speed restriction. Setting nil type, will crash FG, setting empty type is same as setting &amp;quot;at&amp;quot;. See below for type list.&lt;br /&gt;
; setAltitude(altitude, type) : Sets the altitude restriction. Setting nil type, will crash FG, setting empty type is same as setting &amp;quot;at&amp;quot;. See below for type list.&lt;br /&gt;
; path() : Returns a vector of hashes containing lat and lon variables. These compromise a curved path for long non straight legs.&lt;br /&gt;
; courseAndDistanceFrom(coord) : Return vector with true course and distance. Coord is a geo.Coord.&lt;br /&gt;
; parents : Nasal parents.&lt;br /&gt;
; wp_owner : Will return you the owning route-structure of the WP - this could be an airway, procedure, or the flightplan if the waypoint doesn’t belong to a route structure.&lt;br /&gt;
; index : Returns the index of the leg in the owning route-structure.&lt;br /&gt;
; alt_cstr : Read-only. Altitude restriction output. Set using setAltitude.&lt;br /&gt;
; alt_cstr_type : Read-only. Altitude restriction type. See below for list.&lt;br /&gt;
; speed_cstr : Read-only. Speed restriction output. Set using setSpeed.&lt;br /&gt;
; speed_cstr_type : Read-only. Speed restriction. See below for list.&lt;br /&gt;
; leg_distance : Returns distance along the leg, from the preceding waypoint.&lt;br /&gt;
; leg_bearing : Returns the bearing along the leg.&lt;br /&gt;
; distance_along_route : Return the total distance laterally along the route to the beginning of the leg.&lt;br /&gt;
&lt;br /&gt;
For speed restrictions these types can be used:&lt;br /&gt;
* &amp;quot;at&amp;quot; = kt should be spot on&lt;br /&gt;
* &amp;quot;above&amp;quot; = kt should be higher&lt;br /&gt;
* &amp;quot;below&amp;quot; = kt should be under&lt;br /&gt;
* &amp;quot;computed&amp;quot; = predicted kt&lt;br /&gt;
* &amp;quot;computed-mach&amp;quot; = predicted mach&lt;br /&gt;
* &amp;quot;mach&amp;quot; = its in mach instead of kt&lt;br /&gt;
* &amp;quot;delete&amp;quot; = Cleared by ATC&lt;br /&gt;
&lt;br /&gt;
For altitude restrictions these types can be used:&lt;br /&gt;
* &amp;quot;at&amp;quot; = alt should be spot on&lt;br /&gt;
* &amp;quot;above&amp;quot; = alt should be higher&lt;br /&gt;
* &amp;quot;below&amp;quot; = alt should be below&lt;br /&gt;
* &amp;quot;computed&amp;quot; = predicted alt&lt;br /&gt;
* &amp;quot;computed-mach&amp;quot; = not used for altitude&lt;br /&gt;
* &amp;quot;mach&amp;quot; = not used for altitude&lt;br /&gt;
* &amp;quot;delete&amp;quot; = Cleared by ATC&lt;br /&gt;
&lt;br /&gt;
== Procedure methods and variables ==&lt;br /&gt;
; id : a string containing the name of the procedure&lt;br /&gt;
; airport : airport object associated with the procedure&lt;br /&gt;
; radio: for instrument approaches, returns the type of procedure (VOR, ILS, RNAV, or NDB)&lt;br /&gt;
; tp_type: returns the type of procedure (sid, star, or iap)&lt;br /&gt;
; runways: a vector containing the runways associated with the procedure&lt;br /&gt;
; transitions : a vector containing the transitions of the procedure (for SIDS and STARS only)&lt;br /&gt;
; route(runway) : Returns a vector of waypoints.&lt;br /&gt;
; transition() : Only works on STAR and SID.&lt;br /&gt;
&lt;br /&gt;
== Airport methods and variables ==&lt;br /&gt;
&lt;br /&gt;
; runway : a ghost for the runway passed as a string or nil&lt;br /&gt;
; runwaysWithoutReciprocals : &lt;br /&gt;
; helipad : a ghost for the helipad passed as a string or nil&lt;br /&gt;
; tower : returns hash containing airport tower location&lt;br /&gt;
; comms : contains vector containing communication frequencies&lt;br /&gt;
; sids : a vector containing the ids of sids of the airport, if a runway is passed, just for that runway. Pass an id into getSid to get the ghost.&lt;br /&gt;
; stars : a vector containing the ids of stars of the airport, if a runway is passed, just for that runway. Pass an id into getStar to get the ghost.&lt;br /&gt;
; getApproachList : a vector containing the ids of IAPs of the airport, if a runway is passed, just for that runway. Pass an id into getIAP to get the ghost.&lt;br /&gt;
; parking : a vector containing parking positions of the airport&lt;br /&gt;
; getSid : a ghost for a SID&lt;br /&gt;
; getStar : a ghost for a STAR&lt;br /&gt;
; getIAP : a ghost for a IAP&lt;br /&gt;
; findBestRunwayForPos : passed a position, returns a ghost for the runway it decides is best&lt;br /&gt;
; toString : returns &amp;quot;an airport &amp;quot; + the airport id&lt;br /&gt;
&lt;br /&gt;
== Airway methods and variables ==&lt;br /&gt;
&lt;br /&gt;
; id : returns identifier of airway&lt;br /&gt;
; level: &amp;quot;high&amp;quot;, &amp;quot;low&amp;quot;, or &amp;quot;both&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
# get the active flight plan (the one being used by the route manager)&lt;br /&gt;
var fp = flightplan();&lt;br /&gt;
&lt;br /&gt;
# or create one an XML file&lt;br /&gt;
fp = flightplan('/path/to/xml');&lt;br /&gt;
&lt;br /&gt;
# save the active flight plan&lt;br /&gt;
fgcommand(&amp;quot;save-flightplan&amp;quot;, props.Node.new({&amp;quot;path&amp;quot;: 'path/to/xml'}));&lt;br /&gt;
&lt;br /&gt;
# duplicate a flight-plan&lt;br /&gt;
var secondary = fp.clone();&lt;br /&gt;
&lt;br /&gt;
var dest = airportinfo('KSFO');&lt;br /&gt;
var rwy = dest.runway('19L');&lt;br /&gt;
# the the arrival runway (and airport, automatically)&lt;br /&gt;
fp.destination_runway = rwy;&lt;br /&gt;
&lt;br /&gt;
# or if no runway is known/specified&lt;br /&gt;
fp.destination = dest;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Building procedures and transitions. As mentioned above there's a couple of different ways to handle this, the examples below assume the C++ code automatically deletes and re-inserts waypoints for procedures, but that's only one possible design.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var apt = airportinfo('KSFO');&lt;br /&gt;
# example for SIDs, STARs are the same, approaches too&lt;br /&gt;
var allSids = apt.sids();&lt;br /&gt;
&lt;br /&gt;
# SIDs for a specific runway - note these return SID IDs as string, for compatibility with existing code&lt;br /&gt;
var rwySids = apt.sids('28L');&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Inserting and deleting waypoints (possibly in batches)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var fp = flightplan();&lt;br /&gt;
# waypoint created from lat, lon, or a navaid, or anything else?&lt;br /&gt;
var pos = geo.aircraft_position().apply_course_distance(getprop(&amp;quot;/orientation/heading-deg&amp;quot;), 100000);&lt;br /&gt;
var wp = createWP(pos.lat(), pos.lon(), &amp;quot;EPICA&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
# manually insert a waypoint at the end of the plan&lt;br /&gt;
fp.insertWP(wp, fp.getPlanSize());&lt;br /&gt;
&lt;br /&gt;
# manually insert a waypoint at a defined position (n) into the plan&lt;br /&gt;
fp.insertWP(wp, n);&lt;br /&gt;
&lt;br /&gt;
# route along airways, and insert a whole bunch of waypoints&lt;br /&gt;
# this is needed for the route-manager dialog, maybe not for a&lt;br /&gt;
# real FMS interface....&lt;br /&gt;
var segment = [&amp;lt;waypoint object&amp;gt;, &amp;lt;waypoint object&amp;gt;, &amp;lt;waypoint object&amp;gt;];&lt;br /&gt;
# segment is a vector of waypoints now&lt;br /&gt;
fp.insertWaypoints(segment, fp.getPlanSize());&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== aircraft.history() (3.2+) ==&lt;br /&gt;
&lt;br /&gt;
Function to expose flight history as aircraft.history()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var hist = aircraft.history();&lt;br /&gt;
&lt;br /&gt;
# get history of aircraft position/orientation collapsing&lt;br /&gt;
# nodes with a distance smaller than the given minimum&lt;br /&gt;
# edge length&lt;br /&gt;
debug.dump( hist.pathForHistory(&amp;lt;minimum-edge-length-meter&amp;gt;) );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Related content ==&lt;br /&gt;
=== Wiki articles ===&lt;br /&gt;
* [[Nasal library#Extension functions|Nasal library § Extension functions]]&lt;br /&gt;
* [[Navdata cache#Accessing via Nasal|Navdata cache § Accessing via Nasal]]&lt;br /&gt;
* [[Route Manager]]&lt;br /&gt;
* [[Route Manager internals]]&lt;br /&gt;
* [[Howto:Control the route manager in Nasal]]&lt;br /&gt;
&lt;br /&gt;
=== Documentation ===&lt;br /&gt;
* [http://api-docs.freeflightsim.org/flightgear/NasalPositioned_8cxx_source.html#l00585 flightplanGhostSetMember] — ''Members of a flight plan object that can be set.''&lt;br /&gt;
* [http://api-docs.freeflightsim.org/flightgear/NasalPositioned_8cxx_source.html#l00557 flightplanGhostGetMember] — ''Members of flight plan object that can be read.''&lt;br /&gt;
* [http://api-docs.freeflightsim.org/flightgear/NasalPositioned_8cxx_source.html#l02485 initNasalPositioned] — ''Contains a list of functions that can be called on airport, flight plan, waypoint, procedure, or flight plan leg objects.''&lt;br /&gt;
* [http://api-docs.freeflightsim.org/flightgear/route__mgr_8cxx_source.html#l00220 FGRouteMgr::FGRouteMgr] — ''List of [[fgcommands]] relating to the route manager.''&lt;br /&gt;
&lt;br /&gt;
=== Misc ===&lt;br /&gt;
* https://sourceforge.net/p/flightgear/mailman/message/34688624/&lt;br /&gt;
* https://sourceforge.net/p/flightgear/mailman/message/35164289/&lt;br /&gt;
* https://sourceforge.net/p/flightgear/mailman/flightgear-devel/thread/BB67C9F3-028B-40E5-94E4-246CD1E0B2CC%40mac.com/#msg23708827&lt;br /&gt;
* https://sourceforge.net/p/flightgear/mailman/message/33699574/&lt;br /&gt;
* https://sourceforge.net/p/flightgear/mailman/message/21010010/&lt;br /&gt;
* https://sourceforge.net/p/flightgear/mailman/message/23678747/&lt;br /&gt;
&lt;br /&gt;
=== Search Queries ===&lt;br /&gt;
&lt;br /&gt;
=== Commits ===&lt;br /&gt;
&lt;br /&gt;
=== Threads ===&lt;br /&gt;
{{Appendix}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Nasal]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_Flightplan&amp;diff=134480</id>
		<title>Nasal Flightplan</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_Flightplan&amp;diff=134480"/>
		<updated>2022-01-19T09:35:49Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: /* Waypoint ghost */ Add more types&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Systems Modeling Disclaimer}}&lt;br /&gt;
{{Autoflight Navigation}}&lt;br /&gt;
{{Nasal Navigation}}&lt;br /&gt;
&lt;br /&gt;
Because FlightGear's [[route manager]] flight plan system is exposed to [[Nasal]], '''Nasal can be used to interact with flight plans'''. Obviously, this is very useful, especially for aircraft like airliners, which have complex route managers systems. This article shows how this can be done.&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
The Nasal functions relating to the route manager system include:&lt;br /&gt;
* {{func link|flightplan()}} - return the active plan.&lt;br /&gt;
* {{func link|airwaysRoute()}}&lt;br /&gt;
* {{func link|createFlightplan()}} - creates new empty plan. A path can be supplied to load a plan from xml.&lt;br /&gt;
&lt;br /&gt;
Flight plans are based on waypoints, which, in C++, inherit from the {{API Link|flightgear|class|FGPositioned}} class.&lt;br /&gt;
&lt;br /&gt;
== Waypoint ghost ==&lt;br /&gt;
The following are members of a waypoint ghost, as generated by, for example, {{func link|airwaysRoute()}}:&lt;br /&gt;
&lt;br /&gt;
; wp_name : Name of the waypoint, returned as string.&lt;br /&gt;
; wp_type :Waypoint type, returned as string. One of &amp;quot;basic,&amp;quot; &amp;quot;navaid,&amp;quot; &amp;quot;offset-navaid,&amp;quot; &amp;quot;runway,&amp;quot; &amp;quot;hold&amp;quot;,  &amp;quot;hdgToAlt,&amp;quot; &amp;quot;dmeIntercept,&amp;quot; &amp;quot;radialIntercept,&amp;quot; &amp;quot;discontinuity&amp;quot;, &amp;quot;via&amp;quot;, or &amp;quot;vectors.&amp;quot;&lt;br /&gt;
; wp_role: Role of waypoint.&lt;br /&gt;
; wp_lat ''or'' lat : Latitude of waypoint.&lt;br /&gt;
; wp_lon ''or'' lon : Longitude of waypoint.&lt;br /&gt;
; wp_parent_name : Name of waypoint's parent.&lt;br /&gt;
; wp_parent : Waypoint's parent.&lt;br /&gt;
; fly_type : How to waypoint should be flown over or reacted to. One of &amp;quot;flyOver&amp;quot; or &amp;quot;flyBy&amp;quot; or &amp;quot;Hold&amp;quot;.&lt;br /&gt;
; heading_course : Heading of runway.&lt;br /&gt;
&lt;br /&gt;
=== Hold members ===&lt;br /&gt;
The following are hold-specific members:&lt;br /&gt;
; hold_is_left_handed : boolean, defines direction of turns in the hold&lt;br /&gt;
; hold_is_distance : boolean, defines if hold is measured by distance&lt;br /&gt;
; hold_is_time : boolean, defines if hold is measured by time&lt;br /&gt;
; hold_inbound_radial ''or'' hold_inbound_radial_deg : returns the inbound radial of the hold, measured in degrees&lt;br /&gt;
; hold_time_or_distance : the leg length, defined either in seconds or nautical miles&lt;br /&gt;
&lt;br /&gt;
== Flightplan methods and variables ==&lt;br /&gt;
Notice that instead of passing a leg as parameter, a waypoint can be passed.&lt;br /&gt;
; getWP(index) : Returns the leg for specified index.&lt;br /&gt;
; currentWP() : Return current active leg.&lt;br /&gt;
; nextWP() : Make next waypoint active.&lt;br /&gt;
; getPlanSize() : Returns number of waypoints&lt;br /&gt;
; appendWP(leg) : Add a leg to the end of the flightplan.&lt;br /&gt;
; insertWP(leg, index) : Pass a leg object and its position. Example: insertWP(leg, 1) --&amp;gt; leg becomes waypoint at index 1.&lt;br /&gt;
; deleteWP(index) : Deletes the waypoint at specified index. Example: deleteWP(0) --&amp;gt; deletes first waypoint. &lt;br /&gt;
; insertWPAfter() : &lt;br /&gt;
; insertWaypoints(vector, index) : Pass a vector of waypoint objects, and the position to insert.&lt;br /&gt;
; cleanPlan() : Clears all waypoints except destination and departure.&lt;br /&gt;
; clearWPType(type) : Supply a type string, it will clear all waypoints of the type.&lt;br /&gt;
; clone() : Return a copy of the flightplan.&lt;br /&gt;
; pathGeod() or pointAlongRoute() : (function has two associated names). This is used for graphical display: it’s an array of coordinates which show the path of the plan. This includes holds, procedure turns, turn anticipation and more.&lt;br /&gt;
; finish() : Finish the plan. (a call to delegate will be made)&lt;br /&gt;
; indexOfWP(wp) : Returns the index of the passed waypoint/leg.&lt;br /&gt;
; destination : airport object as destination.&lt;br /&gt;
; destination_runway : rwy object as destination and its airport implicit.&lt;br /&gt;
; departure : airport object as departure.&lt;br /&gt;
; departure_runway : rwy object as departure and its airport implicit.&lt;br /&gt;
; id : optional name of plan.&lt;br /&gt;
; sid : procedure object for SID.&lt;br /&gt;
; star : procedure object for STAR.&lt;br /&gt;
; sid_trans : procedure object for SID transition (as of 2020.2, may be written to)&lt;br /&gt;
; star_trans : procedure object for STAR transition (as of 2020.2, may be written to)&lt;br /&gt;
; approach : procedure object for approach.&lt;br /&gt;
; current : Index of current waypoint.&lt;br /&gt;
; aircraftCategory : ICAO aircraft category.&lt;br /&gt;
; followLegTrackToFix : Specific used by some procedures. It controls whether the system will fly on an intersection course (and hence, different track) to the end of the leg, or make a corrective S-turn to get back on the leg track immediately it becomes possible.&lt;br /&gt;
; activate() : This will make the flight plan the default (the one used in route-manager).&lt;br /&gt;
; save(path) : Save a plan to xml. Will return true or false for success.&lt;br /&gt;
&lt;br /&gt;
== Leg methods and variables ==&lt;br /&gt;
A leg is a wrapper for a waypoint, so it will have all waypoints variables and methods plus what is listed below.&lt;br /&gt;
Notice, that a leg you have gotten from a plan, but deleted in the plan, will be invalid and should not be used or modified.&lt;br /&gt;
A leg you have gotten from a plan, when modified, will modify the leg inside the plan you got it from.&lt;br /&gt;
; setSpeed(speed, type) : Sets the speed restriction. Setting nil type, will crash FG, setting empty type is same as setting &amp;quot;at&amp;quot;. See below for type list.&lt;br /&gt;
; setAltitude(altitude, type) : Sets the altitude restriction. Setting nil type, will crash FG, setting empty type is same as setting &amp;quot;at&amp;quot;. See below for type list.&lt;br /&gt;
; path() : Returns a vector of hashes containing lat and lon variables. These compromise a curved path for long non straight legs.&lt;br /&gt;
; courseAndDistanceFrom(coord) : Return vector with true course and distance. Coord is a geo.Coord.&lt;br /&gt;
; parents : Nasal parents.&lt;br /&gt;
; wp_owner : Will return you the owning route-structure of the WP - this could be an airway, procedure, or the flightplan if the waypoint doesn’t belong to a route structure.&lt;br /&gt;
; index : Returns the index of the leg in the owning route-structure.&lt;br /&gt;
; alt_cstr : Read-only. Altitude restriction output. Set using setAltitude.&lt;br /&gt;
; alt_cstr_type : Read-only. Altitude restriction type. See below for list.&lt;br /&gt;
; speed_cstr : Read-only. Speed restriction output. Set using setSpeed.&lt;br /&gt;
; speed_cstr_type : Read-only. Speed restriction. See below for list.&lt;br /&gt;
; leg_distance : Returns distance along the leg, from the preceding waypoint.&lt;br /&gt;
; leg_bearing : Returns the bearing along the leg.&lt;br /&gt;
; distance_along_route : Return the total distance laterally along the route to the beginning of the leg.&lt;br /&gt;
&lt;br /&gt;
For speed restrictions these types can be used:&lt;br /&gt;
* &amp;quot;at&amp;quot; = kt should be spot on&lt;br /&gt;
* &amp;quot;above&amp;quot; = kt should be higher&lt;br /&gt;
* &amp;quot;below&amp;quot; = kt should be under&lt;br /&gt;
* &amp;quot;computed&amp;quot; = predicted kt&lt;br /&gt;
* &amp;quot;computed-mach&amp;quot; = predicted mach&lt;br /&gt;
* &amp;quot;mach&amp;quot; = its in mach instead of kt&lt;br /&gt;
* &amp;quot;delete&amp;quot; = Cleared by ATC&lt;br /&gt;
&lt;br /&gt;
For altitude restrictions these types can be used:&lt;br /&gt;
* &amp;quot;at&amp;quot; = alt should be spot on&lt;br /&gt;
* &amp;quot;above&amp;quot; = alt should be higher&lt;br /&gt;
* &amp;quot;below&amp;quot; = alt should be below&lt;br /&gt;
* &amp;quot;computed&amp;quot; = predicted alt&lt;br /&gt;
* &amp;quot;computed-mach&amp;quot; = not used for altitude&lt;br /&gt;
* &amp;quot;mach&amp;quot; = not used for altitude&lt;br /&gt;
* &amp;quot;delete&amp;quot; = Cleared by ATC&lt;br /&gt;
&lt;br /&gt;
== Procedure methods and variables ==&lt;br /&gt;
; id : a string containing the name of the procedure&lt;br /&gt;
; airport : airport object associated with the procedure&lt;br /&gt;
; radio: for instrument approaches, returns the type of procedure (VOR, ILS, RNAV, or NDB)&lt;br /&gt;
; tp_type: returns the type of procedure (sid, star, or iap)&lt;br /&gt;
; runways: a vector containing the runways associated with the procedure&lt;br /&gt;
; transitions : a vector containing the transitions of the procedure (for SIDS and STARS only)&lt;br /&gt;
; route(runway) : Returns a vector of waypoints.&lt;br /&gt;
; transition() : Only works on STAR and SID.&lt;br /&gt;
&lt;br /&gt;
== Airport methods and variables ==&lt;br /&gt;
&lt;br /&gt;
; runway : a ghost for the runway passed as a string or nil&lt;br /&gt;
; runwaysWithoutReciprocals : &lt;br /&gt;
; helipad : a ghost for the helipad passed as a string or nil&lt;br /&gt;
; tower : returns hash containing airport tower location&lt;br /&gt;
; comms : contains vector containing communication frequencies&lt;br /&gt;
; sids : a vector containing the ids of sids of the airport, if a runway is passed, just for that runway. Pass an id into getSid to get the ghost.&lt;br /&gt;
; stars : a vector containing the ids of stars of the airport, if a runway is passed, just for that runway. Pass an id into getStar to get the ghost.&lt;br /&gt;
; getApproachList : a vector containing the ids of IAPs of the airport, if a runway is passed, just for that runway. Pass an id into getIAP to get the ghost.&lt;br /&gt;
; parking : a vector containing parking positions of the airport&lt;br /&gt;
; getSid : a ghost for a SID&lt;br /&gt;
; getStar : a ghost for a STAR&lt;br /&gt;
; getIAP : a ghost for a IAP&lt;br /&gt;
; findBestRunwayForPos : passed a position, returns a ghost for the runway it decides is best&lt;br /&gt;
; toString : returns &amp;quot;an airport &amp;quot; + the airport id&lt;br /&gt;
&lt;br /&gt;
== Airway methods and variables ==&lt;br /&gt;
&lt;br /&gt;
; id : returns identifier of airway&lt;br /&gt;
; level: &amp;quot;high&amp;quot;, &amp;quot;low&amp;quot;, or &amp;quot;both&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
# get the active flight plan (the one being used by the route manager)&lt;br /&gt;
var fp = flightplan();&lt;br /&gt;
&lt;br /&gt;
# or create one an XML file&lt;br /&gt;
fp = flightplan('/path/to/xml');&lt;br /&gt;
&lt;br /&gt;
# save the active flight plan&lt;br /&gt;
fgcommand(&amp;quot;save-flightplan&amp;quot;, props.Node.new({&amp;quot;path&amp;quot;: 'path/to/xml'}));&lt;br /&gt;
&lt;br /&gt;
# duplicate a flight-plan&lt;br /&gt;
var secondary = fp.clone();&lt;br /&gt;
&lt;br /&gt;
var dest = airportinfo('KSFO');&lt;br /&gt;
var rwy = dest.runway('19L');&lt;br /&gt;
# the the arrival runway (and airport, automatically)&lt;br /&gt;
fp.destination_runway = rwy;&lt;br /&gt;
&lt;br /&gt;
# or if no runway is known/specified&lt;br /&gt;
fp.destination = dest;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Building procedures and transitions. As mentioned above there's a couple of different ways to handle this, the examples below assume the C++ code automatically deletes and re-inserts waypoints for procedures, but that's only one possible design.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var apt = airportinfo('KSFO');&lt;br /&gt;
# example for SIDs, STARs are the same, approaches too&lt;br /&gt;
var allSids = apt.sids();&lt;br /&gt;
&lt;br /&gt;
# SIDs for a specific runway - note these return SID IDs as string, for compatibility with existing code&lt;br /&gt;
var rwySids = apt.sids('28L');&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Inserting and deleting waypoints (possibly in batches)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var fp = flightplan();&lt;br /&gt;
# waypoint created from lat, lon, or a navaid, or anything else?&lt;br /&gt;
var pos = geo.aircraft_position().apply_course_distance(getprop(&amp;quot;/orientation/heading-deg&amp;quot;), 100000);&lt;br /&gt;
var wp = createWP(pos.lat(), pos.lon(), &amp;quot;EPICA&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
# manually insert a waypoint at the end of the plan&lt;br /&gt;
fp.insertWP(wp, fp.getPlanSize());&lt;br /&gt;
&lt;br /&gt;
# manually insert a waypoint at a defined position (n) into the plan&lt;br /&gt;
fp.insertWP(wp, n);&lt;br /&gt;
&lt;br /&gt;
# route along airways, and insert a whole bunch of waypoints&lt;br /&gt;
# this is needed for the route-manager dialog, maybe not for a&lt;br /&gt;
# real FMS interface....&lt;br /&gt;
var segment = [&amp;lt;waypoint object&amp;gt;, &amp;lt;waypoint object&amp;gt;, &amp;lt;waypoint object&amp;gt;];&lt;br /&gt;
# segment is a vector of waypoints now&lt;br /&gt;
fp.insertWaypoints(segment, fp.getPlanSize());&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== aircraft.history() (3.2+) ==&lt;br /&gt;
&lt;br /&gt;
Function to expose flight history as aircraft.history()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var hist = aircraft.history();&lt;br /&gt;
&lt;br /&gt;
# get history of aircraft position/orientation collapsing&lt;br /&gt;
# nodes with a distance smaller than the given minimum&lt;br /&gt;
# edge length&lt;br /&gt;
debug.dump( hist.pathForHistory(&amp;lt;minimum-edge-length-meter&amp;gt;) );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Related content ==&lt;br /&gt;
=== Wiki articles ===&lt;br /&gt;
* [[Nasal library#Extension functions|Nasal library § Extension functions]]&lt;br /&gt;
* [[Navdata cache#Accessing via Nasal|Navdata cache § Accessing via Nasal]]&lt;br /&gt;
* [[Route Manager]]&lt;br /&gt;
* [[Route Manager internals]]&lt;br /&gt;
* [[Howto:Control the route manager in Nasal]]&lt;br /&gt;
&lt;br /&gt;
=== Documentation ===&lt;br /&gt;
* [http://api-docs.freeflightsim.org/flightgear/NasalPositioned_8cxx_source.html#l00585 flightplanGhostSetMember] — ''Members of a flight plan object that can be set.''&lt;br /&gt;
* [http://api-docs.freeflightsim.org/flightgear/NasalPositioned_8cxx_source.html#l00557 flightplanGhostGetMember] — ''Members of flight plan object that can be read.''&lt;br /&gt;
* [http://api-docs.freeflightsim.org/flightgear/NasalPositioned_8cxx_source.html#l02485 initNasalPositioned] — ''Contains a list of functions that can be called on airport, flight plan, waypoint, procedure, or flight plan leg objects.''&lt;br /&gt;
* [http://api-docs.freeflightsim.org/flightgear/route__mgr_8cxx_source.html#l00220 FGRouteMgr::FGRouteMgr] — ''List of [[fgcommands]] relating to the route manager.''&lt;br /&gt;
&lt;br /&gt;
=== Misc ===&lt;br /&gt;
* https://sourceforge.net/p/flightgear/mailman/message/34688624/&lt;br /&gt;
* https://sourceforge.net/p/flightgear/mailman/message/35164289/&lt;br /&gt;
* https://sourceforge.net/p/flightgear/mailman/flightgear-devel/thread/BB67C9F3-028B-40E5-94E4-246CD1E0B2CC%40mac.com/#msg23708827&lt;br /&gt;
* https://sourceforge.net/p/flightgear/mailman/message/33699574/&lt;br /&gt;
* https://sourceforge.net/p/flightgear/mailman/message/21010010/&lt;br /&gt;
* https://sourceforge.net/p/flightgear/mailman/message/23678747/&lt;br /&gt;
&lt;br /&gt;
=== Search Queries ===&lt;br /&gt;
&lt;br /&gt;
=== Commits ===&lt;br /&gt;
&lt;br /&gt;
=== Threads ===&lt;br /&gt;
{{Appendix}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Nasal]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Howto:Complete_TerraGear_example_using_docker&amp;diff=134293</id>
		<title>Howto:Complete TerraGear example using docker</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Howto:Complete_TerraGear_example_using_docker&amp;diff=134293"/>
		<updated>2022-01-06T21:13:49Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: /* Process Elevation Data */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This article aims to serve as a quick starting point for people wanting to build scenery using the dockerized version of the TerraGear scenery toolchain. This will allow users to build scenery on all popular operating systems including Windows, macOS and Linux without the hassle of building the terragear toolchain themselves. This is in no way a comprehensive introduction, but should be enough to get one used to the scenery generation process.&lt;br /&gt;
&lt;br /&gt;
[[File:Saint Helena Island generated using dockerized TerraGear.jpg|thumb|Saint Helena island generated using the docker image for the TerraGear toolchain]]&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
TerraGear requires three pieces of data for scenery generation:&lt;br /&gt;
&lt;br /&gt;
# Elevation data: This data defines how high each point in the scenery or land is. One source for such data is http://viewfinderpanoramas.org/Coverage%20map%20viewfinderpanoramas_org3.htm.&lt;br /&gt;
# Landclass data: This data defines what kind of &amp;quot;land&amp;quot; is under each point in the scenery or land is. For example, some point might be &amp;quot;urban&amp;quot; class, or &amp;quot;forest&amp;quot; class. One source for such data is http://download.geofabrik.de/, which is derived from OSM. &lt;br /&gt;
# Airport data: This data defines the position of runways, taxiways and other assorted airport information. One source for such data is the XPlane gateway.&lt;br /&gt;
&lt;br /&gt;
TerraGear consists of five tools:&lt;br /&gt;
&lt;br /&gt;
# hgtchop - Processing elevation data&lt;br /&gt;
# terrafit - Processing elevation data&lt;br /&gt;
# genapts - Processing airport data&lt;br /&gt;
# ogr-decode - Processing landclass data&lt;br /&gt;
# tg-construct - Generating the final scenery.&lt;br /&gt;
&lt;br /&gt;
== Scenery location ==&lt;br /&gt;
We will build Saint Helena Island, an island in the Atlantic Ocean. Specifically, we will be building the island around [https://en.wikipedia.org/wiki/Saint_Helena_Airport Saint Helena Airport] (ICAO: '''FHSH''').&lt;br /&gt;
&lt;br /&gt;
Its location is: DMS 15° 57′ 33″ S, 5° 38′ 45″ W, Decimal -5.645833 -15.959167&lt;br /&gt;
&lt;br /&gt;
A good vantage point to see progress is to start FG with the following options:&lt;br /&gt;
&lt;br /&gt;
 --lon=-5.62000000 --lat=-16.00000000 --altitude=4000 --heading=310&lt;br /&gt;
&lt;br /&gt;
The bounds for our build will be:&lt;br /&gt;
* Latitude: -6 to -5&lt;br /&gt;
* Longitude: -17 to -15&lt;br /&gt;
&lt;br /&gt;
Let &amp;lt;code&amp;gt;$SCENERY_BUILD_DIR&amp;lt;/code&amp;gt; be the directory containing all of our working files for this project.&lt;br /&gt;
&lt;br /&gt;
== Getting docker running ==&lt;br /&gt;
The first step is to have docker installed and accessible through the command line. Run the following command to fetch the terragear toolchain:&lt;br /&gt;
 docker pull flightgear/terragear:ws20&lt;br /&gt;
&lt;br /&gt;
Next, start a docker container to access the terragear tools:&lt;br /&gt;
&lt;br /&gt;
 docker run -i -v $SCENERY_BUILD_DIR:/terragear-work/ -t flightgear/terragear:ws20 /bin/bash&lt;br /&gt;
&lt;br /&gt;
Once this command runs successfully, the command line will now be a &amp;quot;window&amp;quot; into the docker container, allowing you to run the entire terragear toolchain. Because of the &amp;lt;code&amp;gt;-v&amp;lt;/code&amp;gt; argument (bind mount), the container can see the contents of &amp;lt;code&amp;gt;$SCENERY_BUILD_DIR&amp;lt;/code&amp;gt; will be visible at &amp;lt;code&amp;gt;/terragear-work/&amp;lt;/code&amp;gt; inside the container.&lt;br /&gt;
&lt;br /&gt;
== Process Elevation Data ==&lt;br /&gt;
The elevation data can be obtained from [http://viewfinderpanoramas.org/Coverage%20map%20viewfinderpanoramas_org3.htm ViewFinderPanoramas], specifically, the [http://viewfinderpanoramas.org/dem3/SD30.zip SD30] and [SE30 http://viewfinderpanoramas.org/dem3/SE30.zip] tiles cover this island.&lt;br /&gt;
&lt;br /&gt;
Extract and add to &amp;lt;code&amp;gt;$SCENERY_BUILD_DIR/data/SRTM-3/*.hgt&amp;lt;/code&amp;gt;. Run the following commands in the docker container:&lt;br /&gt;
&lt;br /&gt;
 cd  /terragear-work/&lt;br /&gt;
 for f in data/SRTM-3/*.hgt; do hgtchop 3 &amp;quot;${f}&amp;quot; &amp;quot;work/SRTM-3&amp;quot;; done&lt;br /&gt;
 terrafit work/SRTM-3 -m 50 -x 22500 -e 1&lt;br /&gt;
&lt;br /&gt;
== Process Airport Data ==&lt;br /&gt;
'''FHSH'''  is not available in FlightGear's &amp;lt;code&amp;gt;apt.dat&amp;lt;/code&amp;gt;, so the airport information has to be fetched from elsewhere. The XPlane gateway is one possible source. For this sample project, we can use the following data from https://github.com/accek/fg-nav-fixups:&lt;br /&gt;
&lt;br /&gt;
 1   1023 1 0 FHSH St Helena&lt;br /&gt;
 100 45.00 2 0 0.00 1 2 1 02 -15.96694276 -005.64575428  100    0 2 9 0 2 20 -15.94934298 -005.64615237  300    0 2 9 0 2&lt;br /&gt;
 110 1 0.00 358.7100 New Taxiway 4&lt;br /&gt;
 111 -15.96166211 -005.64927678&lt;br /&gt;
 111 -15.96340503 -005.64926307&lt;br /&gt;
 111 -15.96340434 -005.64836151&lt;br /&gt;
 111 -15.96290056 -005.64836043&lt;br /&gt;
 111 -15.96284142 -005.64854134&lt;br /&gt;
 111 -15.96265507 -005.64854103&lt;br /&gt;
 113 -15.96155909 -005.64854086&lt;br /&gt;
 110 2 0.00 358.7100 New Taxiway 3&lt;br /&gt;
 111 -15.94934844 -005.64635879 3 102&lt;br /&gt;
 111 -15.94935248 -005.64663563 3 102&lt;br /&gt;
 111 -15.94995561 -005.64662024 3 102&lt;br /&gt;
 113 -15.95019415 -005.64634336&lt;br /&gt;
 110 2 0.00 358.7100 New Taxiway 2&lt;br /&gt;
 111 -15.96693818 -005.64554618 3 102&lt;br /&gt;
 111 -15.96693596 -005.64524600 3 102&lt;br /&gt;
 111 -15.96628657 -005.64526997 3 102&lt;br /&gt;
 113 -15.96603006 -005.64556883&lt;br /&gt;
 110 2 0.00 358.7100 New Taxiway 1&lt;br /&gt;
 111 -15.96305635 -005.64765837 3 102&lt;br /&gt;
 111 -15.96240410 -005.64767341 3 102&lt;br /&gt;
 112 -15.96226078 -005.64761762 -15.96220044 -005.64756860 3 102&lt;br /&gt;
 111 -15.96219925 -005.64745814 3 102&lt;br /&gt;
 111 -15.96219005 -005.64624609 3 102&lt;br /&gt;
 112 -15.96223439 -005.64613746 -15.96227201 -005.64609544 3 102&lt;br /&gt;
 111 -15.96236947 -005.64606567&lt;br /&gt;
 111 -15.96184016 -005.64607709 3 102&lt;br /&gt;
 112 -15.96195708 -005.64616687 -15.96199469 -005.64621034 3 102&lt;br /&gt;
 111 -15.96199881 -005.64627387 3 102&lt;br /&gt;
 111 -15.96200448 -005.64744540 3 102&lt;br /&gt;
 112 -15.96197248 -005.64759953 -15.96193665 -005.64765444 3 102&lt;br /&gt;
 111 -15.96183543 -005.64768917 3 102&lt;br /&gt;
 111 -15.96154350 -005.64769949 3 102&lt;br /&gt;
 111 -15.96155909 -005.64854086&lt;br /&gt;
 111 -15.96265507 -005.64854103&lt;br /&gt;
 111 -15.96265481 -005.64818499&lt;br /&gt;
 113 -15.96306600 -005.64818480 3 102&lt;br /&gt;
 130 Airport Boundary&lt;br /&gt;
 111 -15.95876878 -005.64712051&lt;br /&gt;
 111 -15.96005216 -005.64729370&lt;br /&gt;
 111 -15.96043831 -005.64731000&lt;br /&gt;
 111 -15.96048880 -005.64864132&lt;br /&gt;
 111 -15.96154716 -005.64921198&lt;br /&gt;
 111 -15.96159626 -005.65014384&lt;br /&gt;
 111 -15.96388391 -005.64953797&lt;br /&gt;
 111 -15.96430513 -005.64699927&lt;br /&gt;
 111 -15.96882642 -005.64692255&lt;br /&gt;
 111 -15.96885682 -005.64412109&lt;br /&gt;
 111 -15.94564642 -005.64456651&lt;br /&gt;
 113 -15.94563863 -005.64716916&lt;br /&gt;
 120 Hold&lt;br /&gt;
 111 -15.96200516 -005.64660225 4 103&lt;br /&gt;
 115 -15.96218383 -005.64660129&lt;br /&gt;
 120 Linear Feature 5&lt;br /&gt;
 111 -15.96210864 -005.64767019 1 101&lt;br /&gt;
 112 -15.96206007 -005.64782922 -15.96201482 -005.64792776 1 101&lt;br /&gt;
 115 -15.96188449 -005.64810582&lt;br /&gt;
 120 Linear Feature 4&lt;br /&gt;
 111 -15.96210864 -005.64767019 1 101&lt;br /&gt;
 112 -15.96213878 -005.64782592 -15.96215760 -005.64789051 1 101&lt;br /&gt;
 115 -15.96229199 -005.64808544&lt;br /&gt;
 120 Linear Feature 3&lt;br /&gt;
 111 -15.96156820 -005.64813668 20&lt;br /&gt;
 111 -15.96263721 -005.64810368 20&lt;br /&gt;
 111 -15.96263233 -005.64792345 20&lt;br /&gt;
 115 -15.96304480 -005.64791075&lt;br /&gt;
 120 Linear Feature 2&lt;br /&gt;
 111 -15.96210864 -005.64767019 1 101&lt;br /&gt;
 111 -15.96210128 -005.64660525 1 105&lt;br /&gt;
 115 -15.96209919 -005.64630388&lt;br /&gt;
 120 Linear Feature 1&lt;br /&gt;
 111 -15.96154408 -005.64588717 1 105&lt;br /&gt;
 111 -15.96184445 -005.64588139 1 105&lt;br /&gt;
 112 -15.96204503 -005.64596036 -15.96210198 -005.64604073 1 105&lt;br /&gt;
 111 -15.96209919 -005.64630388 1 105&lt;br /&gt;
 112 -15.96217524 -005.64595582 -15.96225060 -005.64588070 1 105&lt;br /&gt;
 111 -15.96236918 -005.64587174 1 105&lt;br /&gt;
 115 -15.96269552 -005.64586403&lt;br /&gt;
 21 -15.95361317 -005.64657631 3 180.0000 3.0 Papi&lt;br /&gt;
 21 -15.95359638 -005.64551140 2 180.0000 3.0 Papi&lt;br /&gt;
 21 -15.96347774 -005.64645343 2 -1.2600 3.0 Papi&lt;br /&gt;
 20 -15.96192491 -005.64660719 90.0000 0 3 {@R}20-02{@@}{@Y}APRON&lt;br /&gt;
 20 -15.96225995 -005.64660719 90.0000 0 3 {@R}20-02{@@}{@Y}APRON&lt;br /&gt;
 14 -15.96312208 -005.64867411  82.02 0 Tower Viewpoint&lt;br /&gt;
 15 -15.96179344 -005.64822577 -50.36 Ramp Start 1&lt;br /&gt;
 1300 -15.96238032 -005.64819725 -129.45 gate jets Ramp Start 2&lt;br /&gt;
 15 -15.96285880 -005.64779046 -181.04 Ramp Start 3&lt;br /&gt;
 19 -15.95196179 -005.64670036 0 New Windsock 2&lt;br /&gt;
 19 -15.96603475 -005.64630065 0 New Windsock 1&lt;br /&gt;
&lt;br /&gt;
Copy and paste the above into &amp;lt;code&amp;gt;$SCENERY_BUILD_DIR/data/airports/FHSH.dat&amp;lt;/code&amp;gt;. We can now run &amp;lt;code&amp;gt;genapts&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 genapts850 --input=data/airports/FHSH --work=./work --dem-path=SRTM-3 --min-lon=-6 --max-lon=-5 --min-lat=-17 --max-lat=-15&lt;br /&gt;
 genapts850 --input=data/airports/FHSH.dat --work=./work --dem-path=SRTM-3 --airport=FHSH&lt;br /&gt;
&lt;br /&gt;
== Process Landclass Data ==&lt;br /&gt;
We can download landclass data from GeoFabrik, specifically from http://download.geofabrik.de/africa/saint-helena-ascension-and-tristan-da-cunha.html. Download the *.shp files and extract them into &amp;lt;code&amp;gt;$SCENERY_BUILD_DATA/data/shapefiles&amp;lt;/code&amp;gt;. Each type of file should go into its own folder. For example, copy all &amp;lt;code&amp;gt;gis_osm_places_a_free_1.*&amp;lt;/code&amp;gt; files into &amp;lt;code&amp;gt;$SCENERY_BUILD_DATA/data/shapefiles/gis_osm_places_a_free_1/*&amp;lt;/code&amp;gt;, as this is the format that TerraGear expects the files to be in. Usually, we would use a landmass (See Notes below) shapefile as our Default, but to simplify things for this tutorial, we can use the &amp;lt;code&amp;gt;gis_osm_places_a_free_1.shp&amp;lt;/code&amp;gt; file, as the landmass file and this file are identical for this particular island. We are now ready to run &amp;lt;code&amp;gt;ogr-decode&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 ogr-decode --max-segment 500 --area-type Default work/Default data/shapefiles/gis_osm_places_a_free_1/&lt;br /&gt;
&lt;br /&gt;
We have to run &amp;lt;code&amp;gt;ogr-decode&amp;lt;/code&amp;gt; for every land class (so urban, forest, lakes, roads etc). At each time, we need to specify the shapefile (the last argument in the above command) and the corresponding area material type that FlightGear recognizes (&amp;quot;Default&amp;quot;) in the above command. For this tutorial, we will run the command just once to get the construct the entire island as a &amp;quot;Default&amp;quot; landclass.&lt;br /&gt;
&lt;br /&gt;
== Bringing it all together ==&lt;br /&gt;
We can finally run &amp;lt;code&amp;gt;tg-construct&amp;lt;/code&amp;gt; to bring everything together&lt;br /&gt;
 tg-construct --priorities=/usr/local/share/TerraGear/default_priorities.txt --work-dir=./work --output-dir=./output/Terrain --min-lon=-6 --max-lon=-5 --min-lat=-17 --max-lat=-15 AirportArea AirportObj Default SRTM-3&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;$SCENERY_BUILD_DIR/output&amp;lt;/code&amp;gt; will now contain the built scenery. Point your FG instance to this path using &amp;lt;code&amp;gt;--fg-scenery&amp;lt;/code&amp;gt; and take a look at the built scenery!&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
* There are two docker images, &amp;lt;code&amp;gt;flightgear/terragear:ws20&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;flightgear/terragear:latest&amp;lt;/code&amp;gt;. The former corresponds to the 2.0 world scenery build, while the later points to the latest code. The latest container has several improvements and GDAL tools which can be used to manipulate shapefiles, but also unfortunately has bugs in the hgtchop and terrafit tools for SRTM-3 data. The best way is to use &amp;lt;code&amp;gt;flightgear/terragear:ws20&amp;lt;/code&amp;gt; for elevation data processing, and &amp;lt;code&amp;gt;flightgear/terragear:latest&amp;lt;/code&amp;gt; for everything else.&lt;br /&gt;
* The [https://osmdata.openstreetmap.de/data/land-polygons.html OSM coastlines data] is a good source for the landmass (&amp;quot;Default&amp;quot;) terrain, but is a single file for the entire world. &lt;br /&gt;
* You can use the following command (found in the latest terragear docker image) to &amp;quot;crop&amp;quot; the shapefile to an area of interest:&lt;br /&gt;
 ogr2ogr -clipsrc -6 -17 -5 -15 cut_landmass.shp land_polygons.shp&lt;br /&gt;
* As mentioned in the introduction, this tutorial is just a starting point. Have a look at the other TerraGear wiki articles. A good resource is also provided [https://forum.flightgear.org/viewtopic.php?t=35618 on the forum], which uses TerraGear GUI. You can use the concepts learned from there and run the commands in the docker image.&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_library&amp;diff=134277</id>
		<title>Nasal library</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_library&amp;diff=134277"/>
		<updated>2022-01-04T00:46:36Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: /* courseAndDistance() */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Nasal Navigation|nocat=1}}&lt;br /&gt;
This page documents the global '''library functions and variables''' of FlightGear's built-in scripting language, [[Nasal]]. This includes ''[[#Core library functions|core library functions]]'', which were included in Nasal before its integration into FlightGear, the ''[[#Extension functions|extension functions]]'', which have been subsequently added, and are specifically designed for FlightGear, and the ''[[#variables|global variables]]'', which are conversion variables, added with extension functions, for converting between units. The relevant folders in [[Git]] are:&lt;br /&gt;
* {{flightgear file|src/Scripting}}&lt;br /&gt;
* {{simgear file|simgear/nasal}}&lt;br /&gt;
&lt;br /&gt;
All these functions and variables are in the global namespace, that is, they are directly accessible (e.g., one can call &amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; inline&amp;gt;magvar()&amp;lt;/syntaxhighlight&amp;gt; instead of &amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; inline&amp;gt;namespace.magvar()&amp;lt;/syntaxhighlight&amp;gt;). However, if a namespace must be used, &amp;lt;code&amp;gt;globals&amp;lt;/code&amp;gt; is the correct namespace, but using it is not recommended. For a more complete explanation, see [[Nasal Namespaces in-depth]].&lt;br /&gt;
&lt;br /&gt;
{{tip|Copy &amp;amp; paste the examples into your [[Nasal Console]] and execute them to see what they do.|width=70%}}&lt;br /&gt;
&lt;br /&gt;
== Core library functions ==&lt;br /&gt;
This is the list of the basic '''core library functions.''' Most of these functions were part of the original Nasal library (before its integration in to FlightGear), while some have been added or changed over time.  See also:&lt;br /&gt;
* http://plausible.org/nasal/lib.html ([http://web.archive.org/web/20101010094553/http://plausible.org/nasal/lib.html archive])&lt;br /&gt;
* {{simgear file|simgear/nasal/lib.c}} ([http://sourceforge.net/p/flightgear/simgear/ci/next/log/?path=/simgear/nasal/lib.c history])&lt;br /&gt;
&lt;br /&gt;
=== append() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = append(vector, element[, element[, ...]]);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=42|t=Source}}&lt;br /&gt;
|text = This function appends, or adds, the given element(s) to the end of the vector given in the first argument.  Returns the vector operated on.&lt;br /&gt;
|param1 = vector&lt;br /&gt;
|param1text = The vector to which the arguments will be appended.&lt;br /&gt;
|param2 = element&lt;br /&gt;
|param2text = An element to be added to the vector.&lt;br /&gt;
|example1 = &lt;br /&gt;
var vector = [1, 2, 3]; # Initialize the vector&lt;br /&gt;
append(vector, 4); # Append the number 4 to the end of the vector&lt;br /&gt;
debug.dump(vector); # Print the contents of the vector&lt;br /&gt;
|example2 = &lt;br /&gt;
var vector = [1, 2, 3]; # Initialize the vector&lt;br /&gt;
append(vector, 4, 5, 6); # Append the numbers 4, 5, and 6 to the end of the vector&lt;br /&gt;
debug.dump(vector); # Print the contents of the vector&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== bind() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = bind(function, locals[, outer_scope]);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=502|t=Source}}&lt;br /&gt;
|text = This creates a new function object. A function in Nasal is three things: the actual code, a hash/namespace of local variables available to the function namespace, and the closure object of that namespace. These correspond to the three arguments respectively.&lt;br /&gt;
|param1 = function&lt;br /&gt;
|param1text = Function to evaluate.&lt;br /&gt;
|param2 = locals&lt;br /&gt;
|param2text = Hash containing values that will become the namespace (first closure) for the function.&lt;br /&gt;
|param3 = outer_scope&lt;br /&gt;
|param3text = Optional function which is bound to the next closure. This can be bound to yet another, making a linked list.&lt;br /&gt;
|example1 = # This is a namespace/hash with a single member, named &amp;quot;key,&amp;quot; which is initialized to 12 &lt;br /&gt;
var Namespace = {&lt;br /&gt;
    key: 12&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
# This is different namespace/hash containing a function&lt;br /&gt;
# dividing a variable &amp;quot;key&amp;quot; (which is unavailable/nil in this namespace) by 2&lt;br /&gt;
var AnotherNamespace = {&lt;br /&gt;
    ret: func {&lt;br /&gt;
        key /= 2;&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
# To see that key is not available, try to call AnotherNamespace.ret() first&lt;br /&gt;
call(AnotherNamespace.ret, [], nil, nil, var errors = []);&lt;br /&gt;
if(size(errors)){&lt;br /&gt;
    print(&amp;quot;Key could not be divided/resolved!&amp;quot;);&lt;br /&gt;
    debug.printerror(errors);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Associate the AnotherNamespace.ret() function with the first namespace&lt;br /&gt;
# so that &amp;quot;key&amp;quot; is now available&lt;br /&gt;
var function = bind(AnotherNamespace.ret, Namespace);&lt;br /&gt;
&lt;br /&gt;
# Invoke the new function&lt;br /&gt;
function();&lt;br /&gt;
&lt;br /&gt;
# Print out the value of Namespace.key&lt;br /&gt;
# It was changed to 12 from 6 by AnotherNamespace.ret()&lt;br /&gt;
print(Namespace.key);&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== call() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = call(func[, args[, me[, locals[, error]]]);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=247|t=Source}}&lt;br /&gt;
|text = Calls the given function with the given arguments and returns the result.  This function is very useful as it allows much more control over function calls and catches any errors or {{func link|die()}} calls that would normally trigger run-time errors cancelling execution of the script otherwise. &lt;br /&gt;
|param1 = func&lt;br /&gt;
|param1text = Function to execute.&lt;br /&gt;
|param2 = args&lt;br /&gt;
|param2text = Vector containing arguments to give to the called function.&lt;br /&gt;
|param3 = me&lt;br /&gt;
|param3text = &amp;lt;code&amp;gt;'''me'''&amp;lt;/code&amp;gt; reference for the function call (i.e., for method calls). If given, this will override any &amp;lt;code&amp;gt;'''me'''&amp;lt;/code&amp;gt; value existing in the namespace (locals argument).&lt;br /&gt;
|param4 = locals&lt;br /&gt;
|param4text = A hash with key/value pairs that will be available to the called function, typically used as the namespace for the function to be called.&lt;br /&gt;
|param5 = error&lt;br /&gt;
|param5text = A vector to append errors to.  If the called function generates an error, the error, place, and line will be written to this.  These errors can be printed using {{func link|printerror()|debug}}.&lt;br /&gt;
|example1 =&lt;br /&gt;
# prints &amp;quot;Called from call()&amp;quot;&lt;br /&gt;
call(func {&lt;br /&gt;
    print(&amp;quot;Called from call()&amp;quot;);&lt;br /&gt;
});&lt;br /&gt;
|example2 =&lt;br /&gt;
# prints &amp;quot;a = 1 : b = 2&lt;br /&gt;
call(func(a, b){&lt;br /&gt;
        print(&amp;quot;a = &amp;quot;, a, &amp;quot; : b = &amp;quot;, b);&lt;br /&gt;
    },&lt;br /&gt;
    [1, 2]&lt;br /&gt;
);&lt;br /&gt;
|example3 =&lt;br /&gt;
var Hash = {&lt;br /&gt;
    new: func {&lt;br /&gt;
        var m = { parents: [Hash] };&lt;br /&gt;
&lt;br /&gt;
        m.el1 = &amp;quot;string1&amp;quot;;&lt;br /&gt;
        m.el2 = &amp;quot;string2&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        return m;&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
# prints &amp;quot;me.el1 = string1&amp;quot;, then &amp;quot;me.el2 = string2&amp;quot; on the next line&lt;br /&gt;
call(func(a, b){        &lt;br /&gt;
        print(&amp;quot;me.el&amp;quot;, a, &amp;quot; = &amp;quot;, me[&amp;quot;el&amp;quot; ~ a]);      &lt;br /&gt;
        print(&amp;quot;me.el&amp;quot;, b, &amp;quot; = &amp;quot;, me[&amp;quot;el&amp;quot; ~ b]);&lt;br /&gt;
    },&lt;br /&gt;
    [1, 2],&lt;br /&gt;
    Hash.new()&lt;br /&gt;
);&lt;br /&gt;
|example4 =&lt;br /&gt;
# prints the value of math.pi&lt;br /&gt;
call(func {&lt;br /&gt;
        print(pi);&lt;br /&gt;
    }, nil, nil, &lt;br /&gt;
    math&lt;br /&gt;
);&lt;br /&gt;
|example5 =&lt;br /&gt;
call(func {&lt;br /&gt;
        print(math.ip); # math.ip doesn't exist&lt;br /&gt;
    }, nil, nil, nil,&lt;br /&gt;
    var errs = []&lt;br /&gt;
);&lt;br /&gt;
debug.printerror(errs); # The error is caught and printed using debug.printerror()&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== caller() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = caller([level]);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=404|t=Source}}&lt;br /&gt;
|text = Returns a vector containing a record from the current call stack.  The level numbering starts from the currently executing function (level 0).  Level 1 (the default) is the caller of the current function, and so on.&lt;br /&gt;
&lt;br /&gt;
The result is a four-element vector containing '''[0]''' a hash of local variables, '''[1]''' the function object, '''[2]''' the full source file name (incl. path) and '''[3]''' the line number. &lt;br /&gt;
|param1 = level&lt;br /&gt;
|param1text = Optional integer specifying the stack level to return a result from.  Defaults to 1 (i.e. the caller of the currently executing function).&lt;br /&gt;
|example1 =&lt;br /&gt;
var myFunction = func(a, b){&lt;br /&gt;
    debug.dump(caller(0)[0]); # prints a hash of local variables, including arguments a and b&lt;br /&gt;
    return 2 * 2;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;2 x 2 = &amp;quot;, myFunction(2, 2));&lt;br /&gt;
|example2 =&lt;br /&gt;
var get_arg_value = func(){&lt;br /&gt;
    print(&amp;quot;Argument to myFunc = &amp;quot;, caller(1)[0]['a']); # print the value of myFunc's single argument, using caller()&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var myFunc = func(a){&lt;br /&gt;
    get_arg_value();&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
myFunc(3);&lt;br /&gt;
|example3text = This is a real example taken from {{fgdata file|Nasal/canvas/MapStructure.nas}}.  Function &amp;lt;code&amp;gt;r()&amp;lt;/code&amp;gt; (above the TODOs) returns a hash with the key/value pairs as per its arguments. For example, something like this is returned: &amp;lt;code&amp;gt;{ name: &amp;quot;&amp;lt;name&amp;gt;&amp;quot;, vis: 1, zindex: nil }&amp;lt;/code&amp;gt;.&lt;br /&gt;
|example3 =&lt;br /&gt;
var MapStructure_selfTest = func() {&lt;br /&gt;
	var temp = {};&lt;br /&gt;
	temp.dlg = canvas.Window.new([600,400],&amp;quot;dialog&amp;quot;);&lt;br /&gt;
	temp.canvas = temp.dlg.createCanvas().setColorBackground(1,1,1,0.5);&lt;br /&gt;
	temp.root = temp.canvas.createGroup();&lt;br /&gt;
	var TestMap = temp.root.createChild(&amp;quot;map&amp;quot;);&lt;br /&gt;
	TestMap.setController(&amp;quot;Aircraft position&amp;quot;);&lt;br /&gt;
	TestMap.setRange(25); # TODO: implement zooming/panning via mouse/wheel here, for lack of buttons :-/&lt;br /&gt;
	TestMap.setTranslation(&lt;br /&gt;
		temp.canvas.get(&amp;quot;view[0]&amp;quot;)/2,&lt;br /&gt;
		temp.canvas.get(&amp;quot;view[1]&amp;quot;)/2&lt;br /&gt;
	);&lt;br /&gt;
	var r = func(name,vis=1,zindex=nil) return caller(0)[0];&lt;br /&gt;
	# TODO: we'll need some z-indexing here, right now it's just random&lt;br /&gt;
	# TODO: use foreach/keys to show all layers in this case by traversing SymbolLayer.registry direclty ?&lt;br /&gt;
	# maybe encode implicit z-indexing for each lcontroller ctor call ? - i.e. preferred above/below order ?&lt;br /&gt;
	foreach(var type; [r('TFC',0),r('APT'),r('DME'),r('VOR'),r('NDB'),r('FIX',0),r('RTE'),r('WPT'),r('FLT'),r('WXR'),r('APS'), ] ) &lt;br /&gt;
		TestMap.addLayer(factory: canvas.SymbolLayer, type_arg: type.name,&lt;br /&gt;
					visible: type.vis, priority: type.zindex,&lt;br /&gt;
		);&lt;br /&gt;
}; # MapStructure_selfTest&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== chr() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = chr(code);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=175|t=Source}}&lt;br /&gt;
|text = Returns a character as per the single argument. Extended ASCII is supported (see http://www.asciitable.com/ for a list of supported characters), although this may vary between different systems.  For a list of the most commonly used characters, see the {{wikipedia|ASCII#ASCII printable code chart|ASCII printable code chart}} ('''Dec''' column). The following table lists supported control characters, along with their equivalent control characters in Nasal strings.  {{Note|In Nasal, only strings enclosed with double-quotes (&amp;lt;code&amp;gt;&amp;quot;string&amp;quot;&amp;lt;/code&amp;gt;) supports control chracters.  Strings in single quotes (&amp;lt;code&amp;gt;'string'&amp;lt;/code&amp;gt;) do not.}}&lt;br /&gt;
{{{!}} class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Code !! Name !! Equivalent to&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} 10 {{!!}} {{Wikipedia|Newline}} {{!!}} &amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt;&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} 9 {{!!}} {{Wikipedia|Tab key#Tab characters|Horizontal tab}} {{!!}} &amp;lt;code&amp;gt;\t&amp;lt;/code&amp;gt;&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} 13 {{!!}} {{Wikipedia|Carriage return}} {{!!}} &amp;lt;code&amp;gt;\r&amp;lt;/code&amp;gt;&lt;br /&gt;
{{!}}}&lt;br /&gt;
|param1 = code&lt;br /&gt;
|param1text = Integer character code for the desired glyph.&lt;br /&gt;
|example1 = print(&amp;quot;Code 65 = &amp;quot;, chr(65)); # prints &amp;quot;Code 65 = A&amp;quot;&lt;br /&gt;
|example2text = This example displays all of the characters in a list, in the format &amp;lt;code&amp;gt;Code '''n''' = &amp;gt;'''char'''&amp;lt;&amp;lt;/code&amp;gt;, '''n''' being the index, and '''char''' being the character.&lt;br /&gt;
|example2 =&lt;br /&gt;
for(var i = 0; i &amp;lt;= 255; i += 1){&lt;br /&gt;
    print(&amp;quot;Code &amp;quot;, i, &amp;quot; = &amp;gt;&amp;quot;, chr(i), &amp;quot;&amp;lt;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== closure() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = closure(func[, level]);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=421|t=Source}}&lt;br /&gt;
|text = Returns the hash table containing the lexical namespace of the given function. The level numbering start with level 0 being the namespace of '''func'''. &lt;br /&gt;
|param1 = func&lt;br /&gt;
|param1text = Function to evaluate.&lt;br /&gt;
|param2 = level&lt;br /&gt;
|param2text = Optional integer specifying the scope level.  Defaults to 0 (the namespace of '''func''').&lt;br /&gt;
|example1 =&lt;br /&gt;
var get_math_e = func {&lt;br /&gt;
    return e; # return the value of math.e&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var myFunction = bind(get_math_e, math); # bind get_math_e to the math namespace, so that math.e is immediately available to get_math_e&lt;br /&gt;
debug.dump(closure(myFunction)); # print the namespace of get_math_e&lt;br /&gt;
&lt;br /&gt;
print(myFunction());&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== cmp() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = cmp(a, b);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=112|t=Source}}&lt;br /&gt;
|text = Compares two strings, returning -1 if '''a''' is less than '''b''', 0 if they are identical and 1 if '''a''' is greater than '''b'''. &lt;br /&gt;
|param1 = a&lt;br /&gt;
|param1text = First string argument for comparison.&lt;br /&gt;
|param2 = b&lt;br /&gt;
|param2text = Second string argument for comparison.&lt;br /&gt;
|example1 = print(cmp(&amp;quot;1&amp;quot;, &amp;quot;two&amp;quot;)); # prints -1&lt;br /&gt;
|example2 = print(cmp(&amp;quot;string&amp;quot;, &amp;quot;string&amp;quot;)); # prints 0&lt;br /&gt;
|example3 = print(cmp(&amp;quot;one&amp;quot;, &amp;quot;2&amp;quot;)); # prints 1&lt;br /&gt;
|example4 = print(cmp(&amp;quot;string1&amp;quot;, &amp;quot;string2&amp;quot;)); # prints -1&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== compile() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = compile(code[, filename]);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=220|t=Source}}&lt;br /&gt;
|text = Compiles the specified code string and returns a function object bound to the current lexical context.  If there is an error, the function dies, with the argument to {{func link|die()}} being '''filename'''.&lt;br /&gt;
|param1 = code&lt;br /&gt;
|param1text = String containing Nasal code to be compiled.&lt;br /&gt;
|param2 = filename&lt;br /&gt;
|param2text = Optional string used for error messages/logging. Defaults to &amp;lt;code&amp;gt;&amp;lt;compile&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|example1 = &lt;br /&gt;
var myCode = 'print(&amp;quot;hello&amp;quot;);';&lt;br /&gt;
var helloFunc = compile(myCode, &amp;quot;myCode&amp;quot;);&lt;br /&gt;
helloFunc();&lt;br /&gt;
|example2text = &amp;lt;code&amp;gt;compile&amp;lt;/code&amp;gt; is very convenient to support Nasal loaded from other files.  For instance, [[PropertyList XML files]] (such as GUI dialogs) may contain embedded Nasal sections that need to be parsed, processed and compiled.  For an example of how to do this, save the below XML code as &amp;lt;tt&amp;gt;''[[$FG_ROOT]]/gui/dialogs/test.xml''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot;?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;PropertyList&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nasal&amp;gt;&amp;lt;![CDATA[&lt;br /&gt;
print(&amp;quot;You have FlightGear v&amp;quot;, getprop(&amp;quot;/sim/version/flightgear&amp;quot;));&lt;br /&gt;
]]&amp;gt;&amp;lt;/nasal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/PropertyList&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Now, start FlightGear and execute this code in the [[Nasal Console]].&lt;br /&gt;
|example2 =&lt;br /&gt;
# Build the path&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/gui/dialogs/test.xml&amp;quot;;&lt;br /&gt;
var path = FGRoot ~ filename;&lt;br /&gt;
&lt;br /&gt;
var blob = io.read_properties(path);&lt;br /&gt;
var script = blob.getValues().nasal; # Get the nasal string&lt;br /&gt;
&lt;br /&gt;
# Compile the script.  We're passing the filename here for better runtime diagnostics &lt;br /&gt;
var code = call(func {&lt;br /&gt;
    compile(script, filename);&lt;br /&gt;
}, nil, nil, var compilation_errors = []);&lt;br /&gt;
&lt;br /&gt;
if(size(compilation_errors)){&lt;br /&gt;
    die(&amp;quot;Error compiling code in: &amp;quot; ~ filename);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Invoke the compiled script, equivalent to code(); &lt;br /&gt;
# We're using call() here to detect errors:&lt;br /&gt;
call(code, [], nil, nil, var runtime_errors = []);&lt;br /&gt;
&lt;br /&gt;
if(size(runtime_errors)){&lt;br /&gt;
    die(&amp;quot;Error calling code compiled loaded from: &amp;quot; ~ filename);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== contains() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = contains(hash, key);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=184|t=Source}}&lt;br /&gt;
|text = Returns 1 (True) if the hash contains the specified key, or 0 (False) if not.&lt;br /&gt;
|param1 = hash&lt;br /&gt;
|param1text = The hash to search in.&lt;br /&gt;
|param2 = key&lt;br /&gt;
|param2text = The scalar to be searched for, contained as a key in the hash.&lt;br /&gt;
|example1 =&lt;br /&gt;
# Initialize a hash&lt;br /&gt;
var hash = {&lt;br /&gt;
    element: &amp;quot;value&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
print(contains(hash, &amp;quot;element&amp;quot;) ? &amp;quot;Yes&amp;quot; : &amp;quot;No&amp;quot;); # This will print &amp;quot;Yes&amp;quot;&lt;br /&gt;
|example2 =&lt;br /&gt;
# Initialize a hash&lt;br /&gt;
var hash = {&lt;br /&gt;
    element: &amp;quot;value&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
print(contains(hash, &amp;quot;element2&amp;quot;) ? &amp;quot;Yes&amp;quot; : &amp;quot;No&amp;quot;); # This will print &amp;quot;No&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== delete() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = delete(hash, key);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=83|t=Source}}&lt;br /&gt;
|text = Deletes the key from the hash if it exists. Operationally, this is NOT identical to setting the hash value specified by the key to &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt; as the key will stay in the hash (at least for a while). This variant potentially frees storage by deleting the reference to the key and by shrinking the hash.  Returns the hash that has been operated on.&lt;br /&gt;
|param1 = hash&lt;br /&gt;
|param1text = The hash from which to delete the key.&lt;br /&gt;
|param2 = key&lt;br /&gt;
|param2text = The scalar to be deleted, contained as a key in the hash.&lt;br /&gt;
|example1 =&lt;br /&gt;
# Initialize the hash&lt;br /&gt;
var hash = {&lt;br /&gt;
    element1: &amp;quot;value1&amp;quot;,&lt;br /&gt;
    element2: &amp;quot;value2&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
delete(hash, &amp;quot;element1&amp;quot;); # Delete element1&lt;br /&gt;
debug.dump(hash); # prints the hash, which is now minus element1&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== die() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = die(error);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=288|t=Source}}&lt;br /&gt;
|text = Terminates execution and unwinds the stack.  The place and the line will be added to the '''error'''.  This invokes the same internal exception handler used for internal runtime errors. Use this to signal fatal errors, or to implement exception handling. The error thrown (including internal runtime errors) can be caught with {{func link|call()}}.&lt;br /&gt;
|param1 = error&lt;br /&gt;
|param1text = String describing the error.&lt;br /&gt;
:{{inote|This parameter is technically optional, but it is highly recommended to use it.}}&lt;br /&gt;
|example1 = &lt;br /&gt;
print(&amp;quot;Will print&amp;quot;);&lt;br /&gt;
die(&amp;quot;Don't go any further!&amp;quot;); &lt;br /&gt;
print(&amp;quot;Won't print&amp;quot;); # Will not be printed because die() stops the process&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== find() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = find(needle, haystack);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=450|t=Source}}&lt;br /&gt;
|text = Finds and returns the index of the first occurrence of the string '''needle''' in the string '''haystack''', or -1 if no such occurrence was found.&lt;br /&gt;
|param1 = needle&lt;br /&gt;
|param1text = String to search for.&lt;br /&gt;
|param2 = haystack&lt;br /&gt;
|param2text = String to search in.&lt;br /&gt;
|example1 = print(find(&amp;quot;c&amp;quot;, &amp;quot;abcdef&amp;quot;)); # prints 2&lt;br /&gt;
|example2 = print(find(&amp;quot;x&amp;quot;, &amp;quot;abcdef&amp;quot;)); # prints -1&lt;br /&gt;
|example3 = print(find(&amp;quot;cd&amp;quot;, &amp;quot;abcdef&amp;quot;)); # prints 2&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== ghosttype() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = ghosttype(ghost);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=207|t=Source}}&lt;br /&gt;
|text = Returns a string containing either a descriptive name of a ghost (a raw C/C++ object), or a unique id (the pointer to the C/C++ &amp;lt;code&amp;gt;naGhostType&amp;lt;/code&amp;gt; instance) if no name has been set.  Ghost is an acronym that stands for '''G'''arbage-collected '''H'''andle to '''O'''ut'''S'''ide '''T'''hingy.&lt;br /&gt;
|param1 = ghost&lt;br /&gt;
|param1text = Ghost to return a description for.&lt;br /&gt;
|example1 = print(ghosttype(airportinfo())); # prints &amp;quot;airport&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== id() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = id(object);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=570|t=Source}}&lt;br /&gt;
|text = Returns a string containing information on the type and ID of the object provided in the single argument.  The information is returned in the form of &amp;lt;code&amp;gt;'''&amp;lt;type&amp;gt;''':'''&amp;lt;id&amp;gt;'''&amp;lt;/code&amp;gt;, where '''&amp;lt;type&amp;gt;''' is the type of object, and '''&amp;lt;id&amp;gt;''' is the ID.&lt;br /&gt;
|param1 = object&lt;br /&gt;
|param1text = Can be either of a string, a vector, a hash, a code, a function, or a ghost.&lt;br /&gt;
|example1 = print(id(&amp;quot;A&amp;quot;)); # prints &amp;quot;str:000000001624A590&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== int() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = int(number);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=90|t=Source}}&lt;br /&gt;
|text = Returns the integer part of the numeric value of the single argument, or &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt; if none exists.&lt;br /&gt;
|param1 = number&lt;br /&gt;
|param1text = Number or string with just a number in it to return an integer from.&lt;br /&gt;
|example1 = print(int(23)); # prints &amp;quot;23&amp;quot;&lt;br /&gt;
|example2 = print(int(23.123)); # prints &amp;quot;23&amp;quot;&lt;br /&gt;
|example3 = debug.dump(int(&amp;quot;string&amp;quot;)); # prints &amp;quot;nil&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== keys() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = keys(hash);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=33|t=Source}}&lt;br /&gt;
|text = Returns a vector containing the list of keys found in the single hash argument. &lt;br /&gt;
|param1 = hash&lt;br /&gt;
|param1text = The hash to return the keys from.&lt;br /&gt;
|example1 = &lt;br /&gt;
# Initialize a hash&lt;br /&gt;
var hash = {&lt;br /&gt;
    element1: &amp;quot;value&amp;quot;,&lt;br /&gt;
    element2: &amp;quot;value&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
debug.dump(keys(hash)); # print the vector&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== left() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = left(string, length);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=149|t=Source}}&lt;br /&gt;
|version = 2.12&lt;br /&gt;
|commit = {{simgear commit|bd7163|t=commit}}&lt;br /&gt;
|text = Returns a substring of '''string''', starting from the left.&lt;br /&gt;
|param1 = string&lt;br /&gt;
|param1text = String to return part of.&lt;br /&gt;
|param2 = length&lt;br /&gt;
|param2text = Integer specifying the length of the substring to return.&lt;br /&gt;
|example1 = print(left(&amp;quot;string&amp;quot;, 2)); # prints &amp;quot;st&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== num() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = num(number);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=102|t=Source}}&lt;br /&gt;
|text = Returns the numerical value of the single string argument, or &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt; if none exists. &lt;br /&gt;
|param1 = number&lt;br /&gt;
|param1text = String with just a number in it to return a number from.&lt;br /&gt;
|example1 = print(num(&amp;quot;23&amp;quot;)); # prints &amp;quot;23&amp;quot;&lt;br /&gt;
|example2 = print(num(&amp;quot;23.123&amp;quot;)); # prints &amp;quot;23.123&amp;quot;&lt;br /&gt;
|example3 = debug.dump(num(&amp;quot;string&amp;quot;)); # prints &amp;quot;nil&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== pop() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = pop(vector);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=50|t=Source}}&lt;br /&gt;
|text = Removes and returns the last element of the single vector argument, or &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt; if the vector is empty. &lt;br /&gt;
|param1 = vector&lt;br /&gt;
|param1text = Vector to remove an element from.&lt;br /&gt;
|example1 = &lt;br /&gt;
var vector = [1, 2, 3];&lt;br /&gt;
pop(vector);&lt;br /&gt;
debug.dump(vector); # prints &amp;quot;[1, 2]&amp;quot;&lt;br /&gt;
|example2 = &lt;br /&gt;
var vector = [1, 2, 3];&lt;br /&gt;
debug.dump(pop(vector)); # prints &amp;quot;3&amp;quot;&lt;br /&gt;
|example3 = &lt;br /&gt;
var vector = [];&lt;br /&gt;
debug.dump(pop(vector)); # prints &amp;quot;nil&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== right() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = right(string, length);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=161|t=Source}}&lt;br /&gt;
|version = 2.12&lt;br /&gt;
|commit = {{simgear commit|bd7163|t=commit}}&lt;br /&gt;
|text = Returns a substring of '''string''', starting from the right.&lt;br /&gt;
|param1 = string&lt;br /&gt;
|param1text = String to return part of.&lt;br /&gt;
|param2 = length&lt;br /&gt;
|param2text = Integer specifying the length of the substring to return.&lt;br /&gt;
|example1 = print(right(&amp;quot;string&amp;quot;, 2)); # prints &amp;quot;ng&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== setsize() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = setsize(vector, size);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=56|t=Source}}&lt;br /&gt;
|text = Sets the size of a vector. The first argument specifies a vector, the second a number representing the desired size of that vector. If the vector is currently larger than the specified size, it is truncated. If it is smaller, it is padded with &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt; entries. Returns the vector operated upon. &lt;br /&gt;
|param1 = vector&lt;br /&gt;
|param1text = The vector to be operated on.&lt;br /&gt;
|param2 = size&lt;br /&gt;
|param2text = The desired size of the vector in number of entries.&lt;br /&gt;
|example1 = &lt;br /&gt;
var vector = [1, 2, 3]; # Initialize a vector&lt;br /&gt;
setsize(vector, 4);&lt;br /&gt;
debug.dump(vector); # print the vector&lt;br /&gt;
|example2 = &lt;br /&gt;
var vector = [1, 2, 3]; # Initialize a vector&lt;br /&gt;
setsize(vector, 2);&lt;br /&gt;
debug.dump(vector); # print the vector&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== size() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = size(object);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=23|t=Source}}&lt;br /&gt;
|text = Returns the size of the single argument. For strings, this is the length in bytes. For vectors, this is the number of elements. For hashes, it is the number of key/value pairs. If the argument is &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt; or a number, this error will be thrown: &amp;lt;code&amp;gt;object has no size()&amp;lt;/code&amp;gt;.&lt;br /&gt;
|param1 = object&lt;br /&gt;
|param1text = Object to find the size of.  Must be a string, a vector or a hash.&lt;br /&gt;
|example1 = &lt;br /&gt;
var string = &amp;quot;string&amp;quot;;&lt;br /&gt;
print(size(string)); # prints &amp;quot;6&amp;quot;&lt;br /&gt;
|example2 =&lt;br /&gt;
var vector = [1, 2, 3];&lt;br /&gt;
print(size(vector)); # prints &amp;quot;3&amp;quot;&lt;br /&gt;
|example3 =&lt;br /&gt;
var hash = {&lt;br /&gt;
    element1: &amp;quot;value1&amp;quot;,&lt;br /&gt;
    element2: &amp;quot;value2&amp;quot;,&lt;br /&gt;
    element3: &amp;quot;value3&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
print(size(hash)); # prints &amp;quot;3&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== sort() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = sort(vector, function);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=542|t=Source}}&lt;br /&gt;
|text = Returns a vector containing the elements in the input '''vector''' sorted in according to the rule given by '''function'''. Implemented with the ANSI C {{func link|qsort()|link=http://www.cplusplus.com/reference/cstdlib/qsort/}}, &amp;lt;code&amp;gt;sort()&amp;lt;/code&amp;gt; is stable.  This means that if the rules in the first example are used, equal elements in the output vector will appear in the same relative order as they do in the input.  It is run in a loop, so '''function''' is run several times.&lt;br /&gt;
|param1 = vector&lt;br /&gt;
|param1text = Input vector to sort.&lt;br /&gt;
|param2 = function&lt;br /&gt;
|param2text = Function according to which the elements will be sorted by.  It should take two arguments and should return one of 1, 0, or -1.&lt;br /&gt;
{{{!}} class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Return value !! Meaning&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} less than 0 {{!!}} first argument should go before second argument&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} 0 {{!!}} first argument equals second argument&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} greater than 0 {{!!}} first argument should go after second argument&lt;br /&gt;
{{!}}}&lt;br /&gt;
&lt;br /&gt;
|example1text = This example sorts elements from smallest to greatest.&lt;br /&gt;
|example1 = &lt;br /&gt;
var sort_rules = func(a, b){&lt;br /&gt;
    if(a &amp;lt; b){&lt;br /&gt;
        return -1; # A should before b in the returned vector&lt;br /&gt;
    }elsif(a == b){&lt;br /&gt;
        return 0; # A is equivalent to b &lt;br /&gt;
    }else{&lt;br /&gt;
        return 1; # A should after b in the returned vector&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
debug.dump(sort([3, 2, 5, 6, 4, 1], sort_rules)); # prints &amp;quot;[1, 2, 3, 4, 5, 6]&amp;quot;&lt;br /&gt;
|example2text = This example sorts elements from greatest to smallest.&lt;br /&gt;
|example2 = &lt;br /&gt;
# Outputs the elements in reverse order (greatest to smallest)&lt;br /&gt;
var sort_rules = func(a, b){&lt;br /&gt;
    if(a &amp;lt; b){&lt;br /&gt;
        return 1; # -1 in the above example&lt;br /&gt;
    }elsif(a == b){&lt;br /&gt;
        return 0;&lt;br /&gt;
    }else{&lt;br /&gt;
        return -1; # 1 in the above example&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
debug.dump(sort([3, 2, 5, 6, 4, 1], sort_rules)); # prints &amp;quot;[6, 5, 4, 3, 2, 1]&amp;quot;&lt;br /&gt;
|example3text = This example sorts a vector of strings (runways for example) from smallest to greatest.&lt;br /&gt;
|example3 = &lt;br /&gt;
var runways = [&amp;quot;09R&amp;quot;,&amp;quot;27R&amp;quot;,&amp;quot;26L&amp;quot;,&amp;quot;09L&amp;quot;,&amp;quot;15&amp;quot;];&lt;br /&gt;
var rwy = sort(runways,func(a,b) cmp(a,b));&lt;br /&gt;
debug.dump(rwy); # prints ['09L','09R','15','26L','27R']&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== split() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = split(delimiter, string);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=460|t=Source}}&lt;br /&gt;
|text = Splits the input string into a vector of substrings bounded by occurrences of the delimiter substring.&lt;br /&gt;
|param1 = delimiter&lt;br /&gt;
|param1text = String that will split the substrings in the returned vector.&lt;br /&gt;
|param2 = string&lt;br /&gt;
|param2text = String to split up.&lt;br /&gt;
|example1 = debug.dump(split(&amp;quot;cd&amp;quot;, &amp;quot;abcdef&amp;quot;)); # prints &amp;quot;['ab', 'ef']&amp;quot;&lt;br /&gt;
|example2 = debug.dump(split(&amp;quot;.&amp;quot;, &amp;quot;3.2.0&amp;quot;)); # prints &amp;quot;[3, 2, 0]&amp;quot;&lt;br /&gt;
|example3 = debug.dump(split(&amp;quot;/&amp;quot;, &amp;quot;path/to/file&amp;quot;)); # prints &amp;quot;['path', 'to', 'file']&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== sprintf() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = sprintf(format[, arg[, arg, [...]]]);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=355|t=Source}}&lt;br /&gt;
|text = Creates and returns a string formatted using ANSI C {{func link|vsnprintf()|link=http://en.cppreference.com/w/c/io/vfprintf}} &amp;lt;ref&amp;gt;&lt;br /&gt;
{{Cite web&lt;br /&gt;
|url = http://sourceforge.net/p/flightgear/simgear/ci/next/tree/simgear/nasal/lib.c#l308&lt;br /&gt;
|title = fgdata/simgear/simgear/nasal/lib.c, line 308&lt;br /&gt;
|accessdate = October 2015&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/ref&amp;gt;.  Below is a table of supported format specifiers.&lt;br /&gt;
{{{!}} class=&amp;quot;wikitable&amp;quot; width=&amp;quot;75%&amp;quot;&lt;br /&gt;
{{!}}+ %[flags][width][.precision]specifier&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; {{!}} Flags&lt;br /&gt;
{{!-}}&lt;br /&gt;
! Flag !! Output&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;+&amp;lt;/code&amp;gt; {{!!}} Forces to precede the result with a plus or minus sign ('''+''' or '''-''') even for positive numbers. By default, only negative numbers are preceded with a '''-''' sign.&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} ''space'' {{!!}} Prefixes non-signed numbers with a space.&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;-&amp;lt;/code&amp;gt; {{!!}} Left-align the output of this placeholder (the default is to right-align the output) when the width option is specified.&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; {{!!}} Use 0 instead of spaces to pad a field when the width option is specified.&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt; {{!!}} Used with &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; specifiers the value is preceded with &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;0x&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;0X&amp;lt;/tt&amp;gt; respectively for values different than zero. Used with &amp;lt;code&amp;gt;e&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt;, it forces the written output to contain a decimal point even if no digits would follow. By default, if no digits follow, no decimal point is written. Used with &amp;lt;code&amp;gt;g&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;G&amp;lt;/code&amp;gt; the result is the same as with &amp;lt;code&amp;gt;e&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; but trailing zeros are not removed.&lt;br /&gt;
{{!-}}&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; {{!}} Width&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} colspan=&amp;quot;2&amp;quot; {{!}} Integer specifying the minimum number of characters to be returned. This includes the decimal point and decimal fraction as well as + or - signs.&lt;br /&gt;
{{!-}}&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; {{!}} Precision&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} colspan=&amp;quot;2&amp;quot; {{!}} Integer preceded by a dot specifying the number of decimal places to be written.&lt;br /&gt;
{{!-}}&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; {{!}} Specifiers&lt;br /&gt;
{{!-}}&lt;br /&gt;
! Specifier !! Output&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;d&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i&amp;lt;/code&amp;gt; {{!!}} Signed decimal number.&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt; {{!!}} A string&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;%&amp;lt;/code&amp;gt; {{!!}} Percent (%) character.&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt; {{!!}} A single character assigned to a character code, the code given in an integer argument.  See http://www.asciitable.com/ for a list of supported characters and their codes.&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; {{!!}} Unsigned integer as an octal number.&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt; {{!!}} Unsigned decimal integer.&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; {{!!}} Unsigned integer as a hexadecimal number.  If &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt; is used, any letters in the number are lowercase, while &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; gives uppercase.&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;e&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; {{!!}} Double value in scientific notation (i.e., ''[-]ddd.ddd'''e'''[+/-]ddd''), with an exponent being denoted by &amp;lt;tt&amp;gt;e&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;E&amp;lt;/tt&amp;gt; depending on whether an upper or lowercase is used respectively.&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; {{!!}} Floating-point number, in fixed decimal notation, by default with 6 decimal places.&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;F&amp;lt;/code&amp;gt; {{!!}} Appears to be available&amp;lt;ref&amp;gt;&lt;br /&gt;
{{Cite web&lt;br /&gt;
|url = http://sourceforge.net/p/flightgear/simgear/ci/next/tree/simgear/nasal/lib.c#l389&lt;br /&gt;
|title = fgdata/simgear/simgear/nasal/lib.c, line 389&lt;br /&gt;
|accessdate = October 2015&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/ref&amp;gt;, but doesn't work.&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;g&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;G&amp;lt;/code&amp;gt; {{!!}} Double in either normal or exponential notation, whichever is more appropriate for its magnitude. &amp;lt;code&amp;gt;g&amp;lt;/code&amp;gt; uses lower-case letters, &amp;lt;code&amp;gt;G&amp;lt;/code&amp;gt; uses upper-case letters. This type differs slightly from fixed-point notation in that insignificant zeroes to the right of the decimal point are not included.  Also, the decimal point is not included on whole numbers.&lt;br /&gt;
{{!}}}&lt;br /&gt;
&lt;br /&gt;
|param1 = format&lt;br /&gt;
|param1text = String specifying the format.  Can be used with or without a format specifiers.  See below for examples.&lt;br /&gt;
|param2 = arg&lt;br /&gt;
|param2text = Argument specifying a value to replace a format placeholder (such as &amp;lt;code&amp;gt;%d&amp;lt;/code&amp;gt;) in the format string.  Not required if there are no format specifiers.&lt;br /&gt;
&lt;br /&gt;
|example1 = print(sprintf(&amp;quot;%i&amp;quot;, 54)); # prints &amp;quot;54&amp;quot;&lt;br /&gt;
|example2 = print(sprintf(&amp;quot;Pi = %+.10f&amp;quot;, math.pi)); # prints &amp;quot;Pi = +3.1415926536&amp;quot;&lt;br /&gt;
|example3 = &lt;br /&gt;
print(sprintf(&amp;quot;%6d&amp;quot;, 23)); # prints &amp;quot;    23&amp;quot;&lt;br /&gt;
print(sprintf(&amp;quot;%06d&amp;quot;, 23)); # prints &amp;quot;000023&amp;quot;&lt;br /&gt;
|example4 =&lt;br /&gt;
var FGVer = getprop(&amp;quot;/sim/version/flightgear&amp;quot;);&lt;br /&gt;
print(sprintf(&amp;quot;You have FlightGear v%s&amp;quot;, FGVer)); # prints &amp;quot;You have FlightGear v&amp;lt;your version&amp;gt;&amp;quot;&lt;br /&gt;
|example5 = &lt;br /&gt;
print(sprintf(&amp;quot;Hexadecimal 100000 = %X&amp;quot;, 100000)); # prints &amp;quot;Hexadecimal 100000 = 186A0&amp;quot;&lt;br /&gt;
print(sprintf(&amp;quot;Hexadecimal 100000 = %x&amp;quot;, 100000)); # prints &amp;quot;Hexadecimal 100000 = 186a0&amp;quot;&lt;br /&gt;
|example6 = print(sprintf(&amp;quot;Code 65 is %c&amp;quot;, 65)); # prints &amp;quot;Code 65 is A&amp;quot;&lt;br /&gt;
|example7 = &lt;br /&gt;
print(sprintf(&amp;quot;%e&amp;quot;, 54)); # prints &amp;quot;5.400000e+001&amp;quot;&lt;br /&gt;
print(sprintf(&amp;quot;%E&amp;quot;, 54)); # prints &amp;quot;5.400000E+001&amp;quot;&lt;br /&gt;
|example8 = print(sprintf(&amp;quot;%o&amp;quot;, 54)); # prints &amp;quot;66&amp;quot;&lt;br /&gt;
|example9 = print(sprintf(&amp;quot;50%% of 100 is %i&amp;quot;, 100 / 2)); # prints &amp;quot;50% of 100 is 50&amp;quot;&lt;br /&gt;
|example10 =&lt;br /&gt;
print(sprintf(&amp;quot;%.2f&amp;quot;, 1.4));   #prints &amp;quot;1.40&amp;quot;&lt;br /&gt;
print(sprintf(&amp;quot;%.1f&amp;quot;, 1.4));   #prints &amp;quot;1.4&amp;quot;&lt;br /&gt;
print(sprintf(&amp;quot;% 4.1f&amp;quot;, 1.4)); #prints &amp;quot; 1.4&amp;quot;&lt;br /&gt;
print(sprintf(&amp;quot;%04.1f&amp;quot;, 1.4)); #prints &amp;quot;01.4&amp;quot;&lt;br /&gt;
print(sprintf(&amp;quot;% 6.1f&amp;quot;, 1.4)); #prints &amp;quot;   1.4&amp;quot;&lt;br /&gt;
print(sprintf(&amp;quot;%06.1f&amp;quot;, 1.4)); #prints &amp;quot;0001.4&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== streq() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = streq(a, b);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=129|t=Source}}&lt;br /&gt;
|text = Tests the string values of the two arguments for equality. This function is needed because the &amp;lt;code&amp;gt;'''=='''&amp;lt;/code&amp;gt; operator (see [[Nasal_Operators#Equality|Nasal Operators]]) tests for numeric equality first.  If either or both the arguments are not strings, 0 (False) will be returned.  Returns either 0 (False) or 1 (True).  {{Note|This function is rarely required in typical code.}}&lt;br /&gt;
|param1 = a&lt;br /&gt;
|param1text = First argument for testing equality.&lt;br /&gt;
|param2 = b&lt;br /&gt;
|param2text = Second argument for testing equality.&lt;br /&gt;
|example1 = print(streq(&amp;quot;0&amp;quot;, &amp;quot;0&amp;quot;)); # prints &amp;quot;1&amp;quot; (True)&lt;br /&gt;
|example2 = &lt;br /&gt;
print(0 == 0.0); # prints &amp;quot;1&amp;quot; (True)&lt;br /&gt;
print(streq(&amp;quot;0&amp;quot;, &amp;quot;0.0&amp;quot;)); # prints &amp;quot;0&amp;quot; (False)&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== substr() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = substr(string, start [, length]);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=129|t=Source}}&lt;br /&gt;
|text = Similar the {{func link|subvec()}}, but operates on strings. Computes and returns a substring. The first argument specifies a string, the second is the index of the start of a substring, the optional third argument specifies a length (the default is to return the rest of the string from the start).&lt;br /&gt;
|param1 = string&lt;br /&gt;
|param1text = String to return a substring from.&lt;br /&gt;
|param2 = start&lt;br /&gt;
|param2text = Integer specifying the start of a substring. Negative values specify a position from the end of the string.&lt;br /&gt;
|param3 = length&lt;br /&gt;
|param3text = Optional argument specifying the length of the substring. Defaults to the end of the string.&lt;br /&gt;
|example1 = print(substr(&amp;quot;abcde&amp;quot;, 1, 3)); # prints &amp;quot;bcd&amp;quot;&lt;br /&gt;
|example2 = print(substr(&amp;quot;abcde&amp;quot;, 1)); # prints &amp;quot;bcde&amp;quot;&lt;br /&gt;
|example3 = print(substr(&amp;quot;abcde&amp;quot;, 2, 1)); # prints &amp;quot;c&amp;quot;&lt;br /&gt;
|example4 = print(substr(&amp;quot;abcde&amp;quot;, -2)); # prints &amp;quot;de&amp;quot;&lt;br /&gt;
|example5 = print(substr(&amp;quot;abcde&amp;quot;, -3, 2)); # prints &amp;quot;cd&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== subvec() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = subvec(vector, start[, length]);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=63|t=Source}}&lt;br /&gt;
|text = Returns a sub-range of a vector. The first argument specifies a vector, the second a starting index, and the optional third argument indicates a length (the default is to the end of the vector). &lt;br /&gt;
|param1 = vector&lt;br /&gt;
|param1text = The vector to take the sub-vector from.&lt;br /&gt;
|param2 = start&lt;br /&gt;
|param2text = The starting point of the sub-vector within the given vector.&lt;br /&gt;
|param3 = length&lt;br /&gt;
|param3text = Optional argument specifying the length of the sub-vector, from the starting point.&lt;br /&gt;
'''Notes:'''&lt;br /&gt;
* Omitting the ''vector'' and ''start'' arguments is not an error (possibly it should be) but the return value is ''nil''.&lt;br /&gt;
* A negative ''start'' argument ''is'' an error. This seems wrong. Perhaps the language designer could comment.&lt;br /&gt;
* A value of ''start'' greater than ''size(vector)'' causes an error. A value equal to ''size(vector)'' returns an empty vector.&lt;br /&gt;
* If the value of ''length'' is greater than ''size(vector) - start'' then it is ignored. That is, all elements from ''start'' to the end of ''vector'' are returned. If ''length'' is zero then an empty vector is returned. A negative value of ''length'' causes an error.&lt;br /&gt;
|example1 = &lt;br /&gt;
var vector = [1, 2, 3];&lt;br /&gt;
debug.dump(subvec(vector, 0)); # prints &amp;quot;[1, 2, 3]&amp;quot;&lt;br /&gt;
|example2 = &lt;br /&gt;
var vector = [1, 2, 3];&lt;br /&gt;
debug.dump(subvec(vector, 1)); # prints &amp;quot;[2, 3]&amp;quot;&lt;br /&gt;
|example3 = &lt;br /&gt;
var vector = [1, 2, 3];&lt;br /&gt;
debug.dump(subvec(vector, 1, 1)); # prints &amp;quot;[2]&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== typeof() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = typeof(object);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=193|t=Source}}&lt;br /&gt;
|text = Returns a string indicating the whether the object is &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt;, a scalar (number or string), a vector, a hash, a function, or a ghost.&lt;br /&gt;
|param1 = object&lt;br /&gt;
|param1text = Object to return the type of.&lt;br /&gt;
|example1 = &lt;br /&gt;
var object = nil;&lt;br /&gt;
print(typeof(object)); # prints &amp;quot;nil&amp;quot;&lt;br /&gt;
|example2 = &lt;br /&gt;
var object = &amp;quot;Hello world!&amp;quot;;&lt;br /&gt;
print(typeof(object)); # prints &amp;quot;scalar&amp;quot;&lt;br /&gt;
|example3 = &lt;br /&gt;
var object = math.pi;&lt;br /&gt;
print(typeof(object)); # prints &amp;quot;scalar&amp;quot;&lt;br /&gt;
|example4 = &lt;br /&gt;
var object = [1, 2, 3];&lt;br /&gt;
print(typeof(object)); # prints &amp;quot;vector&amp;quot;&lt;br /&gt;
|example5 = &lt;br /&gt;
var object = {};&lt;br /&gt;
print(typeof(object)); # prints &amp;quot;hash&amp;quot;&lt;br /&gt;
|example6 = &lt;br /&gt;
var object = func {};&lt;br /&gt;
print(typeof(object)); # prints &amp;quot;func&amp;quot;&lt;br /&gt;
|example7 =&lt;br /&gt;
var object = airportinfo();&lt;br /&gt;
print(typeof(object)); # prints &amp;quot;ghost&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- == Extension modules ==&lt;br /&gt;
=== thread ===&lt;br /&gt;
{{WIP}}&lt;br /&gt;
&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = thread.newthread(func);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/threadlib.c|l=101|t=Source}}&lt;br /&gt;
|text = &lt;br /&gt;
|example1text = start a new worker thread&lt;br /&gt;
|example1 = thread.newthread( func() {} );&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = thread.newlock();&lt;br /&gt;
|source = {{simgear file|simgear/nasal/threadlib.c|l=101|t=Source}}&lt;br /&gt;
|text = &lt;br /&gt;
|example1text = create a new lock&lt;br /&gt;
|example1 = var lock = thread.newlock()&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = thread.lock();&lt;br /&gt;
|source = {{simgear file|simgear/nasal/threadlib.c|l=101|t=Source}}&lt;br /&gt;
|text = &lt;br /&gt;
|example1text = lock a lock&lt;br /&gt;
|example1 = var lock = thread.newlock()&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = thread.unlock();&lt;br /&gt;
|source = {{simgear file|simgear/nasal/threadlib.c|l=101|t=Source}}&lt;br /&gt;
|text = &lt;br /&gt;
|example1text = unlock a lock&lt;br /&gt;
|example1 = var lock = thread.unlock()&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = thread.newsem();&lt;br /&gt;
|source = {{simgear file|simgear/nasal/threadlib.c|l=101|t=Source}}&lt;br /&gt;
|text = &lt;br /&gt;
|example1text = create a new {{Wikipedia|semaphore}}&lt;br /&gt;
|example1 = var semaphore = thread.newsem()&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = thread.semdown();&lt;br /&gt;
|source = {{simgear file|simgear/nasal/threadlib.c|l=101|t=Source}}&lt;br /&gt;
|text = &lt;br /&gt;
|example1text = semaphore down&lt;br /&gt;
|example1 = thread.semdown(semaphore)&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = thread.semup();&lt;br /&gt;
|source = {{simgear file|simgear/nasal/threadlib.c|l=101|t=Source}}&lt;br /&gt;
|text = &lt;br /&gt;
|example1text = semaphore up&lt;br /&gt;
|example1 = thread.semup(semaphore)&lt;br /&gt;
}} --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Extension functions ==&lt;br /&gt;
The '''extension functions''' are global functions that have been added to Nasal since its integration into FlightGear. Unlike the core library functions, they are generally specifically designed to interact directly with FlightGear. Extension functions come from three source files:&lt;br /&gt;
* {{flightgear file|src/Scripting/NasalPositioned.cxx}}&lt;br /&gt;
* {{flightgear file|src/Scripting/NasalSys.cxx}}&lt;br /&gt;
* {{fgdata file|Nasal/globals.nas}}&lt;br /&gt;
&lt;br /&gt;
=== abort() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = abort();&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=565|t=Source}}&lt;br /&gt;
|text = This function is a wrapper for the C++ {{func link|abort()|link=http://www.cplusplus.com/reference/cstdlib/abort/}} function. It simply aborts FlightGear with an error, which varies depending on the operating system. This function should not really be used; instead, please use the &amp;quot;exit&amp;quot; [[Fgcommands|fgcommand]], which will exit FlightGear more gracefully (see example below).&lt;br /&gt;
|example1text = This example will immediately stop FlightGear with an error, such as &amp;quot;FlightGear has stopped working.&amp;quot;&lt;br /&gt;
|example1 = abort();&lt;br /&gt;
|example2text = For exiting FlightGear in a better way, please use the following code:&lt;br /&gt;
|example2 = fgcommand(&amp;quot;exit&amp;quot;);&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== abs() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = abs(number);&lt;br /&gt;
|source = {{fgdata file|Nasal/globals.nas|t=Source}}&lt;br /&gt;
|text = This simple function returns the {{wikipedia|absolute value|noicon=1}} of the provided number.&lt;br /&gt;
|param1 = number&lt;br /&gt;
|param1text = This argument is required and should be a number.&lt;br /&gt;
|example1 = print(abs(1)); # prints &amp;quot;1&amp;quot;&lt;br /&gt;
|example2 = print(abs(-1)); # prints &amp;quot;1&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== aircraftToCart() ===&lt;br /&gt;
This new function in FG 2017.2.1 takes coordinates in aircraft structural coordinate system, and translate them into geocentric coordinates.&lt;br /&gt;
Example for (5,6,7):&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var pos = aircraftToCart({x: -5, y: 6, z: -7});&lt;br /&gt;
var coord = geo.Coord.new();&lt;br /&gt;
coord.set_xyz(pos.x, pos.y, pos.z);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Notice: x and z is inverted sign on purpose.&lt;br /&gt;
if you want lat. lon, alt from that, just call: (degrees and meters)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
coord.lat()&lt;br /&gt;
coord.lon()&lt;br /&gt;
coord.alt()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== addcommand() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = addcommand(name, code);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=659|t=Source}}&lt;br /&gt;
|version = 2.12&lt;br /&gt;
|commit = {{flightgear commit|7b663c|t=commit}}&lt;br /&gt;
|text = {{see also|Howto:Add new fgcommands to FlightGear}}&lt;br /&gt;
&lt;br /&gt;
This function enables the addition of a new custom [[fgcommands|fgcommand]] to FlightGear from within Nasal. An fgcommand created using this method can be used in exactly the same way as the built-in fgcommands. Also, an fgcommand created via this method will always return True or 1, like all other fgcommands.&lt;br /&gt;
|param1 = name&lt;br /&gt;
|param1text = This will become the name of the new fgcommand. Must be a string.&lt;br /&gt;
|param2 = code&lt;br /&gt;
|param2text = The code that will be executed when the fgcommand is run. Must be a function.&lt;br /&gt;
|example1text = This example adds a new fgcommand and then runs it. Although it executes a simple {{func link|print()}} statement, any valid Nasal code can be used.&lt;br /&gt;
|example1 = addcommand(&amp;quot;myFGCmd&amp;quot;, func(node) {&lt;br /&gt;
    print(&amp;quot;fgcommand 'myFGCmd' has been run.&amp;quot;);&lt;br /&gt;
    props.dump( node );&lt;br /&gt;
});&lt;br /&gt;
fgcommand(&amp;quot;myFGCmd&amp;quot;, props.Node.new({foo:1, bar:2}) );&lt;br /&gt;
|example2text = This example demonstrates how parameters are defined in a new fgcommand.&lt;br /&gt;
|example2 = addcommand(&amp;quot;myFGCmd&amp;quot;, func(node){&lt;br /&gt;
    print(node.getNode(&amp;quot;number&amp;quot;).getValue()); # prints the value of &amp;quot;number,&amp;quot; which is 12&lt;br /&gt;
});&lt;br /&gt;
fgcommand(&amp;quot;myFGCmd&amp;quot;, props.Node.new({&amp;quot;number&amp;quot;: 12}));&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== airportinfo() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = airportinfo();&lt;br /&gt;
airportinfo(type);&lt;br /&gt;
airportinfo(id);&lt;br /&gt;
airportinfo(lat, lon[, type]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1024|t=Source}}&lt;br /&gt;
|text = Function for retrieval of airport, heliport, or seaplane base information. It returns a Nasal ghost; however, its structure is like that of a Nasal hash. The following information is returned:&lt;br /&gt;
* '''parents''': A vector containing a hash of various functions to access information about the runway. See {{flightgear file|src/Scripting/NasalPositioned.cxx|l=2659}} for full list.&lt;br /&gt;
* '''lon''': Longitude of the location.&lt;br /&gt;
* '''lat''': Latitude of the location.&lt;br /&gt;
* '''has_metar''': True or false depending whether the airport has a [[METAR]] code defined for it.&lt;br /&gt;
* '''elevation''': Elevation of the location in metres.&lt;br /&gt;
* '''id''': ICAO code of the airport (or ID of the seaplane base/heliport).&lt;br /&gt;
* '''name''': Name of the airport/heliport/seaplane base.&lt;br /&gt;
* '''runways'''&lt;br /&gt;
** '''&amp;lt;runway name&amp;gt;'''&lt;br /&gt;
*** '''id''': Name of runway.&lt;br /&gt;
*** '''lat''': Latitude of the runway.&lt;br /&gt;
*** '''lon''': Longitude of the runway.&lt;br /&gt;
*** '''heading''': Heading of the runway.&lt;br /&gt;
*** '''length''': Length of the runway in metres.&lt;br /&gt;
*** '''width''': Width of the runway in metres.&lt;br /&gt;
*** '''surface''': Runway surface type.&lt;br /&gt;
*** '''threshold''': Length of the runway's {{wikipedia|displaced threshold}} in metres. Will return 0 if there is none.&lt;br /&gt;
*** '''stopway''': Length of the runway's stopway (the area before the threshold) in metres. Will return 0 if there is none.&lt;br /&gt;
*** '''reciprocal''': &amp;lt;code&amp;gt;runway&amp;lt;/code&amp;gt; ghost of the reciprocal runway.&lt;br /&gt;
*** '''ils_frequency_mhz''': ILS frequency in megahertz.&lt;br /&gt;
*** '''ils''': &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt; ghost of the ILS transmitter.&lt;br /&gt;
* '''helipads'''&lt;br /&gt;
** '''&amp;lt;helipad name&amp;gt;'''&lt;br /&gt;
*** '''id''': Name of helipad.&lt;br /&gt;
*** '''lat''': Latitude of the helipad.&lt;br /&gt;
*** '''lon''': Longitude of the helipad.&lt;br /&gt;
*** '''heading''': Heading of the helipad.&lt;br /&gt;
*** '''length''': Length of the helipad in metres.&lt;br /&gt;
*** '''width''': Width of the helipad in metres.&lt;br /&gt;
*** '''surface''': Helipad surface type.&lt;br /&gt;
* '''taxiways'''&lt;br /&gt;
** '''&amp;lt;taxiway name&amp;gt;'''&lt;br /&gt;
*** '''id''': Name of taxiway.&lt;br /&gt;
*** '''lat''': Latitude of the taxiway.&lt;br /&gt;
*** '''lon''': Longitude of the taxiway.&lt;br /&gt;
*** '''heading''': Heading of the taxiway.&lt;br /&gt;
*** '''length''': Length of the taxiway in metres.&lt;br /&gt;
*** '''width''': Width of the taxiway in metres.&lt;br /&gt;
*** '''surface''': Taxiway surface type.&lt;br /&gt;
&lt;br /&gt;
Information is extracted in the same way as accessing members of a Nasal hash. For example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
# prints to lengths of the runways of the nearest airport in feet and metres&lt;br /&gt;
var info = airportinfo();&lt;br /&gt;
print(&amp;quot;-- Lengths of the runways at &amp;quot;, info.name, &amp;quot; (&amp;quot;, info.id, &amp;quot;) --&amp;quot;);&lt;br /&gt;
foreach(var rwy; keys(info.runways)){&lt;br /&gt;
    print(rwy, &amp;quot;: &amp;quot;, math.round(info.runways[rwy].length * M2FT), &amp;quot; ft (&amp;quot;, info.runways[rwy].length, &amp;quot; m)&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that searches for locations that are a long way away (e.g., the nearest seaplane base to the middle of the Sahara) may cause FlightGear to pause for an amount of time.&lt;br /&gt;
|param1 = id&lt;br /&gt;
|param1text = The {{wikipedia|International Civil Aviation Organization airport code|ICAO code|noicon=1}} of an airport to retrieve information about.&lt;br /&gt;
|param2 = type&lt;br /&gt;
|param2text = When this argument is used, the function will return the closest airport of a certain type. Can be one of &amp;quot;heliport,&amp;quot; &amp;quot;seaport,&amp;quot; or &amp;quot;airport&amp;quot; (default).&lt;br /&gt;
: {{inote|Running this function without any parameters is equivalent to this:&lt;br /&gt;
: &amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
airportinfo(&amp;quot;airport&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
|param3 = lat ''and'' lon&lt;br /&gt;
|param3text = When these parameters are used, the function will return information on the nearest airport, heliport or seaplane base (depending on the '''type''' parameter) to those coordinates.&lt;br /&gt;
|example1 = var info = airportinfo();&lt;br /&gt;
print(&amp;quot;Nearest airport: &amp;quot;, info.name, &amp;quot; (&amp;quot;, info.id, &amp;quot;)&amp;quot;); # prints the name and ICAO code of the nearest airport&lt;br /&gt;
|example2 = var info = airportinfo(&amp;quot;heliport&amp;quot;);&lt;br /&gt;
print(&amp;quot;Elevation of the nearest heliport: &amp;quot;, math.round(info.elevation * M2FT), &amp;quot; ft&amp;quot;); # prints the elevation and name of the nearest heliport&lt;br /&gt;
|example3 = var info = airportinfo(&amp;quot;KSQL&amp;quot;);&lt;br /&gt;
print(&amp;quot;-- Runways of &amp;quot;, info.name, &amp;quot; (&amp;quot;, info.id, &amp;quot;): --&amp;quot;);&lt;br /&gt;
foreach(var rwy; keys(info.runways)) {&lt;br /&gt;
    print(rwy); # prints the runways of KSQL&lt;br /&gt;
}&lt;br /&gt;
|example4 = var info = airportinfo(37.81909385, -122.4722484);&lt;br /&gt;
print(&amp;quot;Coordinates of the nearest airport: &amp;quot;, info.lat, &amp;quot;, &amp;quot;, info.lon); # print the name and ICAO of the nearest airport to the Golden Gate Bridge&lt;br /&gt;
|example5 = var info = airportinfo(37.81909385, -122.4722484, &amp;quot;seaport&amp;quot;);&lt;br /&gt;
print(&amp;quot;Nearest seaplane base: &amp;quot;, info.name, &amp;quot; (&amp;quot;, info.id, &amp;quot;)&amp;quot;); # print the name and ID of the nearest seaplane base to the Golden Gate Bridge&lt;br /&gt;
|example6text = This example prints the all information from an &amp;lt;code&amp;gt;airportinfo()&amp;lt;/code&amp;gt; call.&lt;br /&gt;
|example6 = var info = airportinfo(&amp;quot;KSFO&amp;quot;);&lt;br /&gt;
print(info.name);&lt;br /&gt;
print(info.id);&lt;br /&gt;
print(info.lat);&lt;br /&gt;
print(info.lon);&lt;br /&gt;
print(info.has_metar);&lt;br /&gt;
print(info.elevation);&lt;br /&gt;
foreach(var rwy; keys(info.runways)){&lt;br /&gt;
    print(&amp;quot;-- &amp;quot;, rwy, &amp;quot; --&amp;quot;);&lt;br /&gt;
    print(info.runways[rwy].lat);&lt;br /&gt;
    print(info.runways[rwy].lon);&lt;br /&gt;
    print(info.runways[rwy].length);&lt;br /&gt;
    print(info.runways[rwy].width);&lt;br /&gt;
    print(info.runways[rwy].heading);&lt;br /&gt;
    print(info.runways[rwy].stopway);&lt;br /&gt;
    print(info.runways[rwy].threshold);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== airwaysRoute() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = airwaysRoute(start, end[, type]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1933|t=Source}}&lt;br /&gt;
|text = {{see also|Nasal Flightplan}}&lt;br /&gt;
This function returns a vector containing waypoints between two given waypoints. The returned waypoints are ghosts, but can be accessed in the same way as a Nasal hash. See [[Nasal Flightplan]] for more information.&lt;br /&gt;
|param1 = start&lt;br /&gt;
|param1text = Start waypoint, in the form of a waypoint ghost, such as that provided by {{func link|flightplan()}}.&lt;br /&gt;
|param2 = end&lt;br /&gt;
|param2text = Same as above.&lt;br /&gt;
|param3 = type&lt;br /&gt;
|param3text = Instructs the function to compute a high level route (when set to &amp;quot;highlevel&amp;quot;), or a low level route (when set to &amp;quot;lowlevel&amp;quot;). Defaults to &amp;quot;highlevel.&amp;quot;&lt;br /&gt;
|example1text = In the [[route manager]] dialog, add two waypoints to the flightplan, ideally ones that are far apart (tip: use the [[Map]] for this). Then run this code in your Nasal Console.&lt;br /&gt;
|example1 = var fp = flightplan();&lt;br /&gt;
var start = fp.getWP(0);&lt;br /&gt;
var end = fp.getWP(fp.getPlanSize() - 1);&lt;br /&gt;
var rt = airwaysRoute(start, end);&lt;br /&gt;
foreach(var wp; rt){&lt;br /&gt;
    print(wp.wp_name); # print the waypoints in the computed route&lt;br /&gt;
}&lt;br /&gt;
|example2text = Exactly the same as above, but computes a low level path.&lt;br /&gt;
|example2 = var fp = flightplan();&lt;br /&gt;
var start = fp.getWP(0);&lt;br /&gt;
var end = fp.getWP(fp.getPlanSize() - 1);&lt;br /&gt;
var rt = airwaysRoute(start, end, &amp;quot;lowlevel&amp;quot;);&lt;br /&gt;
foreach(var wp; rt){&lt;br /&gt;
    print(wp.wp_name); # print the waypoints in the computed route&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== airway() ===&lt;br /&gt;
&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = airway(ident [, pos]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=2644|t=Source}}&lt;br /&gt;
|text = {{see also|Nasal Flightplan}}&lt;br /&gt;
This function returns a ghost containing an airway of a specified id.&lt;br /&gt;
|param1 = ident&lt;br /&gt;
|param1text = Identifier of airway&lt;br /&gt;
|param2 = pos&lt;br /&gt;
|param1text = a Positioned ghost (leg, navaid, airport) and so on, passed to the search function. &lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== assert() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = assert(condition[, message]);&lt;br /&gt;
|source = {{fgdata file|Nasal/globals.nas|t=Source}}&lt;br /&gt;
|version = 3.2&lt;br /&gt;
|commit = {{fgdata commit|8b16a7|t=commit}}&lt;br /&gt;
|text = Returns either true if the condition evaluates as true, or aborts with a {{func link|die()}} call, which can be customised.&lt;br /&gt;
|param1 = condition&lt;br /&gt;
|param1text = Condition to evaluate.&lt;br /&gt;
|param2 = message&lt;br /&gt;
|param2text = Optional message that will be used in any {{func link|die()}} call. Defaults to &amp;quot;assertion failed!&amp;quot;&lt;br /&gt;
|example1 = var a = 1;&lt;br /&gt;
var b = 2;&lt;br /&gt;
print(assert(a &amp;lt; b)); # prints &amp;quot;1&amp;quot; (true)&lt;br /&gt;
|example2 = var a = 1;&lt;br /&gt;
var b = 2;&lt;br /&gt;
assert(a &amp;gt; b, 'a is not greater than b'); # aborts with a custom error message&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== carttogeod() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = carttogeod(x, y, z);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=945|t=Source}}&lt;br /&gt;
|text = Converts {{wikipedia|ECEF|Earth-centered, Earth-fixed}} coordinates (x, y and z) to {{wikipedia|geodetic coordinates}} (latitude, longitude, and altitude). A vector is returned containing latitude and longitude, both in degrees, and altitude, which is returned in metres above the equatorial radius of Earth as defined by the {{wikipedia|WGS 84}} (6,378,137 metres).&amp;lt;ref&amp;gt;{{simgear file|simgear/math/sg_geodesy.hxx|l=43}}&amp;lt;/ref&amp;gt;&lt;br /&gt;
|param1 = x&lt;br /&gt;
|param1text = Mandatory x-axis value, in metres.&lt;br /&gt;
|param2 = y&lt;br /&gt;
|param2text = Mandatory y-axis value, in metres.&lt;br /&gt;
|param3 = z&lt;br /&gt;
|param3text = Mandatory z-axis value, in metres.&lt;br /&gt;
|example1 = var (lat, lon, alt) = carttogeod(6378137, 0, 0); # point is the intersection of the prime meridian and equator.&lt;br /&gt;
print(&amp;quot;Latitude: &amp;quot;, lat); # prints lat, lon and alt, which are all zero, see above&lt;br /&gt;
print(&amp;quot;Longitude: &amp;quot;, lon);&lt;br /&gt;
print(&amp;quot;Altitude: &amp;quot;, alt);&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== cmdarg() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|private = _cmdarg()&lt;br /&gt;
|syntax = cmdarg();&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=513|t=Part 1}} {{!}} {{fgdata file|Nasal/globals.nas|t=Part 2}}&lt;br /&gt;
|text = &amp;lt;code&amp;gt;cmdarg()&amp;lt;/code&amp;gt; returns the property root of certain types of XML files. These could be nodes in the [[Property Tree]], or temporary and/or non-public nodes outside the Property tree. &lt;br /&gt;
It is used by Nasal scripts embedded in XML files. It returns a &amp;lt;code&amp;gt;props.Node&amp;lt;/code&amp;gt; object (see {{fgdata file|Nasal/props.nas}}), and you can use all of its methods on the returned value. &amp;lt;code&amp;gt;cmdarg()&amp;lt;/code&amp;gt; should only be used in four types/places of XML files:&lt;br /&gt;
* Bindings: This is needed so that the value of a joystick's axis can be accessed internally.&lt;br /&gt;
* Dialogs: This will return the root of the dialog in the Property Tree. This is useful for dialogs that are created/modified procedurally (e.g. for populating/changing widgets while loading the dialog). &lt;br /&gt;
* Embedded Canvases: The Nasal code behind [[Canvas]] windows [[Howto:Adding a canvas to a GUI dialog|embedded in PUI dialogs]] can use it to accessing the root directory of their Canvas.&lt;br /&gt;
* Animation XML files: If the animation XML file is used in an AI/MP model, &amp;lt;code&amp;gt;cmdarg()&amp;lt;/code&amp;gt; will return the root of the AI model in the &amp;lt;code&amp;gt;/ai/models/&amp;lt;/code&amp;gt; directory. Examples: &amp;lt;code&amp;gt;/ai/models/aircraft[3]/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/ai/models/multiplayer[1]/&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should not use &amp;lt;code&amp;gt;cmdarg()&amp;lt;/code&amp;gt; in places other than those stated above. Although it won't cause an error, it will return the value of the last legitimate &amp;lt;code&amp;gt;cmdarg()&amp;lt;/code&amp;gt; call. &lt;br /&gt;
&lt;br /&gt;
Also, you should not delay &amp;lt;code&amp;gt;cmdarg()&amp;lt;/code&amp;gt; using {{func link|maketimer()}}, {{func link|settimer()}} or {{func link|setlistener()}}, because it will return an unrelated property.&lt;br /&gt;
|example1 = fgcommand(&amp;quot;dialog-show&amp;quot;, {&amp;quot;dialog-name&amp;quot;: &amp;quot;cmdarg-demo&amp;quot;});&lt;br /&gt;
|example1text = &amp;lt;br&amp;gt;This example demonstrates the usage of &amp;lt;code&amp;gt;cmdarg()&amp;lt;/code&amp;gt; in a binding.  Save the below XML snippet as &amp;lt;tt&amp;gt;[[$FG_ROOT]]/gui/dialogs/cmdarg-demo.xml&amp;lt;/tt&amp;gt;. Then run the Nasal snippet below in your [[Nasal Console]]. Upon clicking {{button|Close}}, a message will be printed sowing the root of the binding in the Property Tree.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;PropertyList&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;name&amp;gt;cmdarg-demo&amp;lt;/name&amp;gt;&lt;br /&gt;
&amp;lt;layout&amp;gt;vbox&amp;lt;/layout&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;text&amp;gt;&lt;br /&gt;
  &amp;lt;label&amp;gt;Click &amp;quot;Close&amp;quot; to activate the demonstration (a message in the console).&amp;lt;/label&amp;gt;&lt;br /&gt;
&amp;lt;/text&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;button&amp;gt;&lt;br /&gt;
  &amp;lt;legend&amp;gt;Close&amp;lt;/legend&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
    &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;print(&amp;quot;Button binding root: '&amp;quot; ~ cmdarg().getPath() ~ &amp;quot;'&amp;quot;);&amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
    &amp;lt;command&amp;gt;dialog-close&amp;lt;/command&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/PropertyList&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|example2text = This example demonstrates the usage of &amp;lt;code&amp;gt;cmdarg()&amp;lt;/code&amp;gt; in Nasal code within dialogs.  Open &amp;lt;tt&amp;gt;[[$FG_ROOT]]/gui/dialogs/cmdarg-demo.xml&amp;lt;/tt&amp;gt; from the previous example, copy &amp;amp; paste the code below, and save it. Then run the same Nasal snippet as the previous example in your Nasal Console. If you click {{button|Click me!}}, the button's label will change to &amp;quot;I've been changed!&amp;quot;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;PropertyList&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;name&amp;gt;cmdarg-demo&amp;lt;/name&amp;gt;&lt;br /&gt;
&amp;lt;layout&amp;gt;vbox&amp;lt;/layout&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;text&amp;gt;&lt;br /&gt;
  &amp;lt;label&amp;gt;Click &amp;quot;Click me!&amp;quot; to activate the demonstration (the button's label will change).&amp;lt;/label&amp;gt;&lt;br /&gt;
&amp;lt;/text&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;button&amp;gt;&lt;br /&gt;
  &amp;lt;legend&amp;gt;Click me!&amp;lt;/legend&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
    &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;change_label();&amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;button&amp;gt;&lt;br /&gt;
  &amp;lt;legend&amp;gt;Close&amp;lt;/legend&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
    &amp;lt;command&amp;gt;dialog-close&amp;lt;/command&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nasal&amp;gt;&lt;br /&gt;
  &amp;lt;open&amp;gt;&amp;lt;![CDATA[&lt;br /&gt;
    var dlg_root = cmdarg();&lt;br /&gt;
    var dlg_name = {&amp;quot;dialog-name&amp;quot;: &amp;quot;cmdarg-demo&amp;quot;};&lt;br /&gt;
    var change_label = func {&lt;br /&gt;
        dlg_root.getNode(&amp;quot;button[0]/legend&amp;quot;).setValue(&amp;quot;I've been changed!&amp;quot;);&lt;br /&gt;
        fgcommand(&amp;quot;dialog-close&amp;quot;, dlg_name);&lt;br /&gt;
        fgcommand(&amp;quot;dialog-show&amp;quot;, dlg_name);&lt;br /&gt;
    }&lt;br /&gt;
  ]]&amp;gt;&amp;lt;/open&amp;gt;&lt;br /&gt;
&amp;lt;/nasal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/PropertyList&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|example3text = For an example of &amp;lt;code&amp;gt;cmdarg()&amp;lt;/code&amp;gt; used with Canvas, please see [[Howto:Adding a canvas to a GUI dialog#FGPlot|Howto:Adding a canvas to a GUI dialog]].&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== courseAndDistance() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = courseAndDistance(to);&lt;br /&gt;
courseAndDistance(from, to);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1668|t=Source}}&lt;br /&gt;
|text = Returns a vector containing the course from one point to another and the distance between them in nautical miles. The course is the initial bearing (see [http://www.movable-type.co.uk/scripts/latlong.html#bearing here]), and is in the range 0–360. Both arguments can be one of:&lt;br /&gt;
:* An &amp;lt;code&amp;gt;airport&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;runway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;taxiway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fix&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;waypoint&amp;lt;/code&amp;gt; ghost type&lt;br /&gt;
:* A hash with ''lat'' and ''lon'' members&lt;br /&gt;
:* A geo.Coord object with geodetic coordinates (cartesian coordinates will not be accepted)&lt;br /&gt;
|param1 = from&lt;br /&gt;
|param1text = Optional parameter defining the from where the function should calculate its results. If the function is given one argument ('''to'''), the aircraft's current position will be used. As well as the argument types as defined above, this argument can be two numbers separated with a comma, as if the function is taking three arguments. See example 5 below.&lt;br /&gt;
|param2 = to&lt;br /&gt;
|param2text = Like the first parameter, but defines the second point.&lt;br /&gt;
|example1text = This example demonstrates the usage of the function with the &amp;lt;code&amp;gt;airport&amp;lt;/code&amp;gt; ghost type.&lt;br /&gt;
|example1 = var from = airportinfo(&amp;quot;KSFO&amp;quot;);&lt;br /&gt;
var to = airportinfo(&amp;quot;KSQL&amp;quot;);&lt;br /&gt;
var (course, dist) = courseAndDistance(from, to);&lt;br /&gt;
print(course); # prints course from KSFO to KSQL&lt;br /&gt;
print(dist); # prints distance in nm from KSFO to KSQL&lt;br /&gt;
|example2text = This example demonstrates the usage of the function with hashes containing ''lat'' and ''lon''.&lt;br /&gt;
|example2 = var from = {lat: 0, lon: 0};&lt;br /&gt;
var to = {lat: 1, lon: 1};&lt;br /&gt;
var (course, dist) = courseAndDistance(from, to);&lt;br /&gt;
print(course);&lt;br /&gt;
print(dist);&lt;br /&gt;
|example3text = This example demonstrates usage of a geo.Coord object.&lt;br /&gt;
|example3 = var from = geo.Coord.new().set_latlon(0, 0);&lt;br /&gt;
var to = geo.Coord.new().set_latlon(1, 1);&lt;br /&gt;
var (course, dist) = courseAndDistance(from, to);&lt;br /&gt;
print(course);&lt;br /&gt;
print(dist);&lt;br /&gt;
|example4text = This example demonstrates usage of differing parameter types.&lt;br /&gt;
|example4 = var from = airportinfo(&amp;quot;KSFO&amp;quot;);&lt;br /&gt;
var to = geo.Coord.new().set_latlon(0, 0);&lt;br /&gt;
var (course, dist) = courseAndDistance(from, to);&lt;br /&gt;
print(course);&lt;br /&gt;
print(dist);&lt;br /&gt;
|example5text = The same as above, but the other way round.&lt;br /&gt;
|example5 = var to = {lat: 1, lon: 1};&lt;br /&gt;
var (course, dist) = courseAndDistance(0, 0, to);&lt;br /&gt;
print(course);&lt;br /&gt;
print(dist);&lt;br /&gt;
|example6text = Usage of just one parameter.&lt;br /&gt;
|example6 = var dest = airportinfo(&amp;quot;KSQL&amp;quot;);&lt;br /&gt;
var (course, dist) = courseAndDistance(dest);&lt;br /&gt;
print(&amp;quot;Turn to heading &amp;quot;, math.round(course), &amp;quot;. You have &amp;quot;, sprintf(&amp;quot;%.2f&amp;quot;, dist), &amp;quot; nm to go&amp;quot;);&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== createFlightplan() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = createFlightplan(path);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=2331|t=Source}}&lt;br /&gt;
|text = Creates an empty flightplan object. It accepts one argument, ''path'' passed an absolute path to a .fgfp / .gpx file, it will populate the flightplan with waypoints from the file.&lt;br /&gt;
|param1 = path&lt;br /&gt;
|param1text = Optional parameter defining the file from which a flightplan will be populated.&lt;br /&gt;
|example1 = &lt;br /&gt;
var path = getprop(&amp;quot;/sim/fg-home&amp;quot;) ~ &amp;quot;/Export/test.fgfp&amp;quot;;&lt;br /&gt;
var flightplan = createFlightplan(path);&lt;br /&gt;
debug.dump(flightplan);&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== createDiscontinuity() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = createDiscontinuity();&lt;br /&gt;
|text = Returns a &amp;lt;code&amp;gt;waypoint&amp;lt;/code&amp;gt; ghost object. A route discontinuity is inserted by an {{abbr|FMS|Flight Management System}} when it is unsure how to connect two waypoints.&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=2045|t=Source}}&lt;br /&gt;
|version = 2016.1&lt;br /&gt;
|commit = {{flightgear commit|caead6|t=commit}}&lt;br /&gt;
}}&lt;br /&gt;
=== createViaTo() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = createViaTo(airway, waypoint);&lt;br /&gt;
|text = Returns a &amp;lt;code&amp;gt;waypoint&amp;lt;/code&amp;gt; ghost object. It represents a route &amp;quot;via '''airway''' to '''waypoint'''&amp;quot;.&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=2009|t=Source}}&lt;br /&gt;
|version = 2016.1&lt;br /&gt;
|commit = {{flightgear commit|caead6|t=commit}}&lt;br /&gt;
|param1 = airway&lt;br /&gt;
|param1text = The name of an airway.&lt;br /&gt;
|param2 = waypoint&lt;br /&gt;
|param2text = Must be in the airway and one of:&lt;br /&gt;
* The name of a waypoint.&lt;br /&gt;
* An &amp;lt;code&amp;gt;airport&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;runway&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;fix&amp;lt;/code&amp;gt; ghost object.&lt;br /&gt;
}}&lt;br /&gt;
=== createWP() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = createWP(pos, name[, flag]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1964|t=Source}}&lt;br /&gt;
|text = Creates a new waypoint ghost object.&lt;br /&gt;
|param1 = pos&lt;br /&gt;
|param1text = Dictates the position of the new waypoint. It can be one of the following:&lt;br /&gt;
:* An &amp;lt;code&amp;gt;airport&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;runway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;taxiway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fix&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;waypoint&amp;lt;/code&amp;gt; ghost type&lt;br /&gt;
:* A hash with ''lat'' and ''lon'' members&lt;br /&gt;
:* A geo.Coord object&lt;br /&gt;
:* Two numbers separated by a comma, as if the function is taking three arguments. See example 4 below.&lt;br /&gt;
|param2 = name&lt;br /&gt;
|param2text = String that will become the name of the new waypoint.&lt;br /&gt;
|param3 = flag&lt;br /&gt;
|param3text = Optional string that will tell FlightGear what type of waypoint it is. Must be one of &amp;quot;sid,&amp;quot; &amp;quot;star,&amp;quot; &amp;quot;approach,&amp;quot; &amp;quot;missed,&amp;quot; or &amp;quot;pseudo.&amp;quot;&lt;br /&gt;
|example1text = Creates a waypoint directly in front and 1 km away and appends it to the flight plan.&lt;br /&gt;
|example1 = var pos = geo.aircraft_position().apply_course_distance(getprop(&amp;quot;/orientation/heading-deg&amp;quot;), 1000);&lt;br /&gt;
var wp = createWP(pos, &amp;quot;NEWWP&amp;quot;);&lt;br /&gt;
var fp = flightplan();&lt;br /&gt;
fp.appendWP(wp);&lt;br /&gt;
|example2 = var pos = geo.aircraft_position().apply_course_distance(getprop(&amp;quot;/orientation/heading-deg&amp;quot;), 1000);&lt;br /&gt;
var wp = createWP({lat: pos.lat(), lon: pos.lon()}, &amp;quot;NEWWP&amp;quot;);&lt;br /&gt;
var fp = flightplan();&lt;br /&gt;
fp.appendWP(wp);&lt;br /&gt;
|example3 = var apt = airportinfo();&lt;br /&gt;
var wp = createWP(apt, &amp;quot;NEWWP&amp;quot;);&lt;br /&gt;
var fp = flightplan();&lt;br /&gt;
fp.appendWP(wp);&lt;br /&gt;
|example4 = var pos = geo.aircraft_position().apply_course_distance(getprop(&amp;quot;/orientation/heading-deg&amp;quot;), 1000);&lt;br /&gt;
var wp = createWP(pos.lat(), pos.lon(), &amp;quot;NEWWP&amp;quot;);&lt;br /&gt;
var fp = flightplan();&lt;br /&gt;
fp.appendWP(wp);&lt;br /&gt;
|example5text = Creates a new waypoint and adds it to the flight plan. Waypoints of the type &amp;quot;pseudo&amp;quot; are then removed from the flight plan, including the new waypoint. The {{func link|print()}} statements show this.&lt;br /&gt;
|example5 = var pos = geo.aircraft_position().apply_course_distance(getprop(&amp;quot;/orientation/heading-deg&amp;quot;), 1000);&lt;br /&gt;
var wp = createWP(pos, &amp;quot;NEWWP&amp;quot;, &amp;quot;pseudo&amp;quot;);&lt;br /&gt;
var fp = flightplan();&lt;br /&gt;
fp.appendWP(wp);&lt;br /&gt;
print(fp.getPlanSize());&lt;br /&gt;
fp.clearWPType(&amp;quot;pseudo&amp;quot;);&lt;br /&gt;
print(fp.getPlanSize());&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== createWPFrom() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = createWPFrom(object[, flag]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1989|t=Source}}&lt;br /&gt;
|text = Creates a new waypoint object from another object.&lt;br /&gt;
|param1 = object&lt;br /&gt;
|param1text = A ghost object. Must be a ghost type that is one of &amp;quot;airport,&amp;quot; &amp;quot;navaid,&amp;quot; &amp;quot;runway,&amp;quot; or &amp;quot;fix.&amp;quot;&lt;br /&gt;
|param2 = flag&lt;br /&gt;
|param2text = Optional string that will tell FlightGear what type of waypoint it is. Must be one of &amp;quot;sid,&amp;quot; &amp;quot;star,&amp;quot; &amp;quot;approach,&amp;quot; &amp;quot;missed,&amp;quot; or &amp;quot;pseudo.&amp;quot;&lt;br /&gt;
|example1text = Creates a new waypoint and appends it to the flight plan.&lt;br /&gt;
|example1 = var apt = airportinfo(&amp;quot;KSFO&amp;quot;);&lt;br /&gt;
var wp = createWPFrom(apt);&lt;br /&gt;
var fp = flightplan();&lt;br /&gt;
fp.appendWP(wp);&lt;br /&gt;
|example2text = Creates a new waypoint and appends it to the flight plan. This way point is then removed; the {{func link|print()}} statements prove this.&lt;br /&gt;
|example2 = var apt = airportinfo(&amp;quot;KSFO&amp;quot;);&lt;br /&gt;
var wp = createWPFrom(apt, &amp;quot;pseudo&amp;quot;);&lt;br /&gt;
print(wp.wp_name);&lt;br /&gt;
var fp = flightplan();&lt;br /&gt;
fp.appendWP(wp);&lt;br /&gt;
print(fp.getPlanSize());&lt;br /&gt;
fp.clearWPType(&amp;quot;pseudo&amp;quot;);&lt;br /&gt;
print(fp.getPlanSize());&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== defined() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = defined(symbol);&lt;br /&gt;
|source = {{fgdata file|Nasal/globals.nas|t=Source}}&lt;br /&gt;
|text = Returns 1 (true) or 0 (false) depending on whether a variable exists.&lt;br /&gt;
|param1 = symbol&lt;br /&gt;
|param1text = A string that will be what the function searches for.&lt;br /&gt;
|example1 = var number = 12;&lt;br /&gt;
var check_exist = func {&lt;br /&gt;
    print(&amp;quot;Variable 'number' &amp;quot;, defined(&amp;quot;number&amp;quot;) == 1 ? &amp;quot;exists&amp;quot; : &amp;quot;does not exist&amp;quot;); # 'number' does exist&lt;br /&gt;
    print(&amp;quot;Variable 'number2' &amp;quot;, defined(&amp;quot;number2&amp;quot;) == 1 ? &amp;quot;exists&amp;quot; : &amp;quot;does not exist&amp;quot;); # 'number2' does not exist&lt;br /&gt;
}&lt;br /&gt;
check_exist();&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== directory() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = directory(path);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=572|t=Source}}&lt;br /&gt;
|text = Returns a vector containing a list of the folders and files in a given file path or &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt; if the path doesn't exist. Hidden folders and files are not added to the vector.&lt;br /&gt;
{{inote|The first two elements of the vector will be &amp;lt;code&amp;gt;'.'&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;'..'&amp;lt;/code&amp;gt;. These are for navigating back up the file tree, but have no use in Nasal. They can be safely removed from the vector.}}&lt;br /&gt;
|param1 = path&lt;br /&gt;
|param1text = Absolute file path.&lt;br /&gt;
|example1text = Gets the folders and files in [[$FG_ROOT]], and then removes the extra first two elements (see note above). &lt;br /&gt;
|example1 = var dir = directory(getprop(&amp;quot;/sim/fg-root&amp;quot;)); # get directory&lt;br /&gt;
dir = subvec(dir, 2); # strips off the first two elements&lt;br /&gt;
debug.dump(dir); # dump the vector&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== fgcommand() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = fgcommand(cmd[, args]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=456|t=Part 1}} {{!}} {{fgdata file|Nasal/globals.nas|t=Part 2}}&lt;br /&gt;
|text = Runs an fgcommand. See also {{readme file|commands}} and [[Bindings]] for more information. See {{flightgear file|src/Main/fg_commands.cxx|l=1425}} for the full list of fgcommands. Note that fgcommands generated by {{func link|addcommand()}} can also be run using this function. Also, the full list of fgcommands depends on the version of FlightGear you have. Returns 1 (true) if the fgcommand succeeded or 0 (false) if it failed.&lt;br /&gt;
|param1 = cmd&lt;br /&gt;
|param1text = String that is the name of the command that is to be run.&lt;br /&gt;
|param2 = args&lt;br /&gt;
|param2text = If the fgcommand takes arguments, they are inputted using this argument. Can either be a &amp;lt;code&amp;gt;props.Node&amp;lt;/code&amp;gt; object, or a hash (see examples below).&lt;br /&gt;
|example1 = fgcommand(&amp;quot;null&amp;quot;); # does nothing&lt;br /&gt;
|example2 = var args = props.Node.new({'script': 'print(&amp;quot;Running fgcommand&amp;quot;);'});&lt;br /&gt;
if (fgcommand(&amp;quot;nasal&amp;quot;, args)) { # prints &amp;quot;Running fgcommand&amp;quot; and then one of these print statements&lt;br /&gt;
    print(&amp;quot;Fgcommand succeeded&amp;quot;);&lt;br /&gt;
} else {&lt;br /&gt;
    print(&amp;quot;Fgcommand encountered a problem&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
|example3 = var args = { 'dialog-name': 'about' };&lt;br /&gt;
fgcommand(&amp;quot;dialog-show&amp;quot;, args); # shows the 'about' dialog&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== findAirportsByICAO() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = findAirportsByICAO(search[, type]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1096|t=Source}}&lt;br /&gt;
|text = Returns a vector containing &amp;lt;code&amp;gt;airport&amp;lt;/code&amp;gt; ghost objects which are (by default) airports whose ICAO code matches the search string. The results are sorted by range from closest to furthest.&lt;br /&gt;
|param1 = search&lt;br /&gt;
|param1text = Search string for the function. Can either be a partial or a full ICAO code.&lt;br /&gt;
:{{icaution|The more matches there are for the given code, the longer the function will take. Passing just one character (e.g., &amp;quot;K&amp;quot;), might make FlightGear hang for a certain amount of time.}}&lt;br /&gt;
|param2 = type&lt;br /&gt;
|param2text = This will narrow the search to airports of a certain type. By default, only airports are searched for. May be one of &amp;quot;airport,&amp;quot; &amp;quot;heliport,&amp;quot; or &amp;quot;seaport.&amp;quot;&lt;br /&gt;
|example1 = var apts = findAirportsByICAO(&amp;quot;KSF&amp;quot;); # finds all airports matching &amp;quot;KSF&amp;quot;&lt;br /&gt;
foreach(var apt; apts){&lt;br /&gt;
    print(apt.name, &amp;quot; (&amp;quot;, apt.id, &amp;quot;)&amp;quot;); # prints them&lt;br /&gt;
}&lt;br /&gt;
|example2 = var apts = findAirportsByICAO(&amp;quot;SP0&amp;quot;, &amp;quot;seaport&amp;quot;); # finds all seaplane bases matching &amp;quot;SP0&amp;quot;&lt;br /&gt;
foreach(var apt; apts){&lt;br /&gt;
    print(apt.name, &amp;quot; (&amp;quot;, apt.id, &amp;quot;)&amp;quot;); # prints them&lt;br /&gt;
}&lt;br /&gt;
|example3 = var apt = findAirportsByICAO(&amp;quot;XBET&amp;quot;); # one way to check if an airport does exist&amp;quot;&lt;br /&gt;
if (size(apt) == 0) {&lt;br /&gt;
    print(&amp;quot;Airport does not exist&amp;quot;); # this one will be printed&lt;br /&gt;
} else {&lt;br /&gt;
    print(&amp;quot;Airport does exist&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== findAirportsWithinRange() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = findAirportsWithinRange([pos, ]range[, type]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1066|t=Source}}&lt;br /&gt;
|text = Returns a vector of &amp;lt;code&amp;gt;airport&amp;lt;/code&amp;gt; ghost object which are (by default) airports that are within a given range of a given position, or the aircraft's current position. The results are sorted by range from closest to furthest.&lt;br /&gt;
|param1 = pos&lt;br /&gt;
|param1text = Optional position to search around. If not given, the aircraft's current position will be used. Can be one of:&lt;br /&gt;
:* An &amp;lt;code&amp;gt;airport&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;runway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;taxiway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fix&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;waypoint&amp;lt;/code&amp;gt; ghost type&lt;br /&gt;
:* A hash with ''lat'' and ''lon'' members&lt;br /&gt;
:* A geo.Coord object&lt;br /&gt;
:* Two numbers separated by a comma, as if the function is taking three arguments. Example: &amp;lt;code&amp;gt;findAirportsWithinRange(lat, lon, range, type);&amp;lt;/code&amp;gt;.&lt;br /&gt;
|param2 = range&lt;br /&gt;
|param2text = Mandatory number giving the range in nautical miles within which to search for airports/heliports/seaplane bases.only airports are searched for.&lt;br /&gt;
|param3 = type&lt;br /&gt;
|param3text = This will narrow the search to airports of a certain type. By default, only airports are searched for. May be one of &amp;quot;airport,&amp;quot; &amp;quot;heliport,&amp;quot; or &amp;quot;seaport.&amp;quot;&lt;br /&gt;
|example1text = Searches for airports within 10 nm of [[KSFO]].&lt;br /&gt;
|example1 = var pos = airportinfo(&amp;quot;KSFO&amp;quot;);&lt;br /&gt;
var apts = findAirportsWithinRange(pos, 10);&lt;br /&gt;
foreach(var apt; apts){&lt;br /&gt;
    print(apt.name, &amp;quot; (&amp;quot;, apt.id, &amp;quot;)&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
|example2text = Searches for seaplane bases within 15 nm of [[KSFO]].&lt;br /&gt;
|example2 = var pos = airportinfo(&amp;quot;KSFO&amp;quot;);&lt;br /&gt;
var apts = findAirportsWithinRange(pos, 15, &amp;quot;seaport&amp;quot;);&lt;br /&gt;
foreach(var apt; apts){&lt;br /&gt;
    print(apt.name, &amp;quot; (&amp;quot;, apt.id, &amp;quot;)&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
|example3text = Searches for airports within 10 nm of your current position.&lt;br /&gt;
|example3 = var apts = findAirportsWithinRange(10);&lt;br /&gt;
foreach(var apt; apts){&lt;br /&gt;
    print(apt.name, &amp;quot; (&amp;quot;, apt.id, &amp;quot;)&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== findFixesByID() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = findFixesByID([pos, ]id);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1627|t=Source}}&lt;br /&gt;
|text = Returns a vector containing &amp;lt;code&amp;gt;fix&amp;lt;/code&amp;gt; ghost objects matching a given ID, sorted by range from a certain position.&lt;br /&gt;
{{inote|Fixes are (usually) also known as waypoints.}}&lt;br /&gt;
|param1 = pos&lt;br /&gt;
|param1text = Optional position to search around. If not given, the aircraft's current position will be used. Can be one of:&lt;br /&gt;
:* An &amp;lt;code&amp;gt;airport&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;runway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;taxiway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fix&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;waypoint&amp;lt;/code&amp;gt; ghost type&lt;br /&gt;
:* A hash with ''lat'' and ''lon'' members&lt;br /&gt;
:* A geo.Coord object&lt;br /&gt;
:* Two numbers separated by a comma, as if the function is taking three arguments. Example: &amp;lt;code&amp;gt;findFixesByID(lat, lon, id);&amp;lt;/code&amp;gt;.&lt;br /&gt;
|param2 = id&lt;br /&gt;
|param2text = Full or partial ID of the fix to search for.&lt;br /&gt;
:{{inote|1=Inputting a partial ID does not work correctly (see [http://forum.flightgear.org/viewtopic.php?f=30&amp;amp;t=28129 here]). It is best to just input a full ID.}}&lt;br /&gt;
|example1 = var fixes = findFixesByID(&amp;quot;POGIC&amp;quot;);&lt;br /&gt;
foreach(var fix; fixes){&lt;br /&gt;
    print(fix.id, &amp;quot; - lat: &amp;quot;, fix.lat, &amp;quot; {{!}} lon: &amp;quot;, fix.lon); # prints information about POGIC&lt;br /&gt;
}&lt;br /&gt;
|example2 = var fix = findFixesByID(&amp;quot;ZUNAP&amp;quot;);&lt;br /&gt;
fix = fix[0];&lt;br /&gt;
var (course, dist) = courseAndDistance(fix);&lt;br /&gt;
print(&amp;quot;Turn to heading &amp;quot;, math.round(course), &amp;quot;. You have &amp;quot;, sprintf(&amp;quot;%.2f&amp;quot;, dist), &amp;quot; nm to go to reach &amp;quot;, fixes[0].id);&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== findNavaidByFrequency() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = findNavaidByFrequency([pos, ]freq[, type]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1547|t=Source}}&lt;br /&gt;
|text = Returns a &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt; ghost object for a navaid matching a given frequency. If there is more than one navaid with that frequency, the nearest station is returned.&lt;br /&gt;
|param1 = pos&lt;br /&gt;
|param1text = Optional position to search around. If not given, the aircraft's current position will be used. Can be one of:&lt;br /&gt;
:* An &amp;lt;code&amp;gt;airport&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;runway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;taxiway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fix&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;waypoint&amp;lt;/code&amp;gt; ghost type&lt;br /&gt;
:* A hash with ''lat'' and ''lon'' members&lt;br /&gt;
:* A geo.Coord object&lt;br /&gt;
:* Two numbers separated by a comma, as if the function is taking three arguments. Example: &amp;lt;code&amp;gt;findNavaidByFrequency(lat, lon, freq, type);&amp;lt;/code&amp;gt;.&lt;br /&gt;
|param2 = freq&lt;br /&gt;
|param2text = Frequency, in megahertz, of the navaid to search for.&lt;br /&gt;
|param3 = type&lt;br /&gt;
|param3text = This will narrow the search to navaids of a certain type. Defaults to &amp;quot;all.&amp;quot; For the full list of accepted type arguments, see {{flightgear file|src/Navaids/positioned.cxx|l=127}}.&lt;br /&gt;
|example1 = var navaid = findNavaidByFrequency(11.17);&lt;br /&gt;
print(&amp;quot;ID: &amp;quot;, navaid.id); # prints info about the navaid&lt;br /&gt;
print(&amp;quot;Name: &amp;quot;, navaid.name);&lt;br /&gt;
print(&amp;quot;Latitude: &amp;quot;, navaid.lat);&lt;br /&gt;
print(&amp;quot;Longitude: &amp;quot;, navaid.lon);&lt;br /&gt;
print(&amp;quot;Elevation (AMSL): &amp;quot;, navaid.elevation, &amp;quot; m&amp;quot;);&lt;br /&gt;
print(&amp;quot;Type: &amp;quot;, navaid.type);&lt;br /&gt;
print(&amp;quot;Frequency: &amp;quot;, sprintf(&amp;quot;%.3f&amp;quot;, navaid.frequency / 1000), &amp;quot; Mhz&amp;quot;);&lt;br /&gt;
print(&amp;quot;Range: &amp;quot;, navaid.range_nm, &amp;quot; nm&amp;quot;);&lt;br /&gt;
if(navaid.course) print(&amp;quot;Course: &amp;quot;, navaid.course);&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== findNavaidsByFrequency() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = findNavaidsByFrequency([pos, ]freq[, type]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1572|t=Source}}&lt;br /&gt;
|text = Returns a vector conatining &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt; ghost objects for navaids that match a given frequency, sorted from nearest to furthest.&lt;br /&gt;
|param1 = pos&lt;br /&gt;
|param1text = Optional position to search around. If not given, the aircraft's current position will be used. Can be one of:&lt;br /&gt;
:* An &amp;lt;code&amp;gt;airport&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;runway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;taxiway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fix&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;waypoint&amp;lt;/code&amp;gt; ghost type&lt;br /&gt;
:* A hash with ''lat'' and ''lon'' members&lt;br /&gt;
:* A geo.Coord object&lt;br /&gt;
:* Two numbers separated by a comma, as if the function is taking three arguments. Example: &amp;lt;code&amp;gt;findNavaidsByFrequency(lat, lon, freq, type);&amp;lt;/code&amp;gt;.&lt;br /&gt;
|param2 = freq&lt;br /&gt;
|param2text = Frequency, in megahertz, of the navaid to search for.&lt;br /&gt;
|param3 = type&lt;br /&gt;
|param3text = This will narrow the search to navaids of a certain type. Defaults to &amp;quot;all.&amp;quot; For the full list of accepted type arguments, see {{flightgear file|src/Navaids/positioned.cxx|l=127}}.&lt;br /&gt;
|example1 = var navaids = findNavaidsByFrequency(10.955);&lt;br /&gt;
foreach(var navaid; navaids){&lt;br /&gt;
    print(&amp;quot;--&amp;quot;);&lt;br /&gt;
    print(&amp;quot;ID: &amp;quot;, navaid.id); # prints info about the navaid&lt;br /&gt;
    print(&amp;quot;Name: &amp;quot;, navaid.name);&lt;br /&gt;
    print(&amp;quot;Latitude: &amp;quot;, navaid.lat);&lt;br /&gt;
    print(&amp;quot;Longitude: &amp;quot;, navaid.lon);&lt;br /&gt;
    print(&amp;quot;Elevation (AMSL): &amp;quot;, navaid.elevation, &amp;quot; m&amp;quot;);&lt;br /&gt;
    print(&amp;quot;Type: &amp;quot;, navaid.type);&lt;br /&gt;
    print(&amp;quot;Frequency: &amp;quot;, sprintf(&amp;quot;%.3f&amp;quot;, navaid.frequency / 1000), &amp;quot; Mhz&amp;quot;);&lt;br /&gt;
    print(&amp;quot;Range: &amp;quot;, navaid.range_nm, &amp;quot; nm&amp;quot;);&lt;br /&gt;
    if(navaid.course) print(&amp;quot;Course: &amp;quot;, navaid.course);&lt;br /&gt;
    print(&amp;quot;--&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== findNavaidsByID() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = findNavaidsByID([pos, ]id[, type]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1600|t=Source}}&lt;br /&gt;
|text = Returns a vector containing &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt; ghost objects matching a given ID, sorted by range from a certain position.&lt;br /&gt;
|param1 = pos&lt;br /&gt;
|param1text = Optional position to search around. If not given, the aircraft's current position will be used. Can be one of:&lt;br /&gt;
:* An &amp;lt;code&amp;gt;airport&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;runway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;taxiway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fix&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;waypoint&amp;lt;/code&amp;gt; ghost type&lt;br /&gt;
:* A hash with ''lat'' and ''lon'' members&lt;br /&gt;
:* A geo.Coord object&lt;br /&gt;
:* Two numbers separated by a comma, as if the function is taking three arguments. Example: &amp;lt;code&amp;gt;findNavaidsByID(lat, lon, id, type);&amp;lt;/code&amp;gt;.&lt;br /&gt;
|param2 = id&lt;br /&gt;
|param2text = Full or partial ID of the fix to search for.&lt;br /&gt;
:{{inote|1=Inputting a partial ID does not work correctly (see [http://forum.flightgear.org/viewtopic.php?f=30&amp;amp;t=28129 here]). It is best to just input a full ID.}}&lt;br /&gt;
|param3 = type&lt;br /&gt;
|param3text = This will narrow the search to navaids of a certain type. Defaults to &amp;quot;all.&amp;quot; For the full list of accepted type arguments, see {{flightgear file|src/Navaids/positioned.cxx|l=127}}.&lt;br /&gt;
|example1 = var navaid = findNavaidsByID(&amp;quot;MXW&amp;quot;);&lt;br /&gt;
navaid = navaid[0];&lt;br /&gt;
print(&amp;quot;ID: &amp;quot;, navaid.id); # prints info about 'MXW' (a VOR station)&lt;br /&gt;
print(&amp;quot;Name: &amp;quot;, navaid.name);&lt;br /&gt;
print(&amp;quot;Latitude: &amp;quot;, navaid.lat);&lt;br /&gt;
print(&amp;quot;Longitude: &amp;quot;, navaid.lon);&lt;br /&gt;
print(&amp;quot;Elevation (AMSL): &amp;quot;, navaid.elevation, &amp;quot; m&amp;quot;);&lt;br /&gt;
print(&amp;quot;Type: &amp;quot;, navaid.type);&lt;br /&gt;
print(&amp;quot;Frequency: &amp;quot;, sprintf(&amp;quot;%.3f&amp;quot;, navaid.frequency / 1000), &amp;quot; Mhz&amp;quot;);&lt;br /&gt;
print(&amp;quot;Range: &amp;quot;, navaid.range_nm, &amp;quot; nm&amp;quot;);&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== findNavaidsWithinRange() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = findNavaidsWithinRange([pos, ]range[, type]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1518|t=Source}}&lt;br /&gt;
|text = Returns a vector of &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt; ghost objects which are within a given range of a given position (by default the aircraft's current position). The results are sorted from closest to furthest.&lt;br /&gt;
|param1 = pos&lt;br /&gt;
|param1text = Optional position to search around. If not given, the aircraft's current position will be used. Can be one of:&lt;br /&gt;
:* An &amp;lt;code&amp;gt;airport&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;runway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;taxiway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fix&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;waypoint&amp;lt;/code&amp;gt; ghost type&lt;br /&gt;
:* A hash with ''lat'' and ''lon'' members&lt;br /&gt;
:* A geo.Coord object&lt;br /&gt;
:* Two numbers separated by a comma, as if the function is taking three arguments. Example: &amp;lt;code&amp;gt;findNavaidsWithinRange(lat, lon, range, type);&amp;lt;/code&amp;gt;.&lt;br /&gt;
|param2 = range&lt;br /&gt;
|param2text = Mandatory number giving the range in nautical miles within which to search for navaids. Defaults to &amp;quot;all.&amp;quot; For the full list of accepted type arguments, see {{flightgear file|src/Navaids/positioned.cxx|l=127}}.&lt;br /&gt;
|param3 = type&lt;br /&gt;
|param3text = This will narrow the search to navaids of a certain type.&lt;br /&gt;
|example1text = Searches for navaids within 10 nm of [[KSFO]].&lt;br /&gt;
|example1 = var pos = airportinfo(&amp;quot;KSFO&amp;quot;);&lt;br /&gt;
var navs = findNavaidsWithinRange(pos, 10);&lt;br /&gt;
foreach(var nav; navs){&lt;br /&gt;
    print(nav.name, &amp;quot; (ID: &amp;quot;, nav.id, &amp;quot;)&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
|example2text = Searches for navaids within 10 nm of your current position.&lt;br /&gt;
|example2 = var navs = findNavaidsWithinRange(10);&lt;br /&gt;
foreach(var nav; navs){&lt;br /&gt;
    print(nav.name, &amp;quot; (ID: &amp;quot;, nav.id, &amp;quot;)&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== finddata() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = finddata(path);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=603|t=Source}}&lt;br /&gt;
|text = Takes a relative path and tries to return an absolute one. It works by appending the relative path to some paths and testing to see if they exist. As of FlightGear v3.7, these paths are the TerraSync directory (tested first) and [[$FG_ROOT]]. &lt;br /&gt;
|param1 = path&lt;br /&gt;
|param1text = A relative path as a string.&lt;br /&gt;
|example1 = var path = finddata(&amp;quot;Aircraft/Generic&amp;quot;);&lt;br /&gt;
print(path); # prints the absolute path to $FG_ROOT/Aircraft/Generic&lt;br /&gt;
|example2 = var path = finddata(&amp;quot;Airports&amp;quot;);&lt;br /&gt;
print(path); # prints the absolute path to &amp;lt;TerraSync dir&amp;gt;/Airports&lt;br /&gt;
|example3 = var path = finddata(&amp;quot;preferences.xml&amp;quot;);&lt;br /&gt;
print(path); # prints the absolute path to $FG_ROOT/preferences.xml&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== flightplan() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = flightplan([path]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1738|t=Source}}&lt;br /&gt;
|text = {{see also|Nasal Flightplan}}&lt;br /&gt;
Returns a flight plan object, either one for the current flight plan, or one loaded from a given path.&lt;br /&gt;
|param1 = path&lt;br /&gt;
|param1text = Optional path to flight plan XML file.&lt;br /&gt;
|example1text = Gets the active flight plan and gets the ID of the current waypoint. Note that this example requires a flight plan to be set in the [[Route Manager]] first.&lt;br /&gt;
|example1 = var fp = flightplan();&lt;br /&gt;
print(fp.getWP(fp.current).id);&lt;br /&gt;
|example2text = Creates a new flight plan from an XML file and prints the IDs of the waypoints. Note that this example requires a flight plan to have been created and saved as &amp;lt;tt&amp;gt;''[[$FG_HOME]]/fp-demo.xml''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
|example2 = var path = getprop('/sim/fg-home') ~ '/fp-demo.xml';&lt;br /&gt;
var fp = flightplan(path);&lt;br /&gt;
for(var i = 0; i &amp;lt; fp.getPlanSize(); i += 1){&lt;br /&gt;
    print(fp.getWP(i).id);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== geodinfo() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = geodinfo(lat, lon[, max_alt]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=981|t=Source}}&lt;br /&gt;
|text = Returns a vector containing two entries or &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt; if no information could be obtained because the terrain tile wasn't loaded. The first entry in the vector is the elevation (in meters) for the given point, and the second is a hash with information about the assigned material (as defined in &amp;lt;tt&amp;gt;''[[$FG_ROOT]]/Materials''&amp;lt;/tt&amp;gt;), or &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt; if there was no material information available (for example, because there is an untextured building at that location). The structure of the hash is as follows (see also {{readme file|materials}}):&lt;br /&gt;
* '''light_coverage:''' The coverage of a single point of light in m&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;.&lt;br /&gt;
* '''bumpiness:''' Normalized bumpiness factor for the material.&lt;br /&gt;
* '''load_resistance:''' The amount of pressure in N/m&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt; the material can withstand without deformation.&lt;br /&gt;
* '''solid:''' 1 (true) or false (0) depending on whether the material is solid or not.&lt;br /&gt;
* '''names:''' Vector of scenery types (usually generated by [[TerraGear]]) that will use this material. &lt;br /&gt;
* '''friction_factor:''' Normalized friction factor of the material.&lt;br /&gt;
* '''rolling_friction:''' The rolling friction coefficient of the material.&lt;br /&gt;
&lt;br /&gt;
Note that this function is a ''very'' CPU-intensive operation, particularly in FlightGear v2.4 and earlier. It is advised to use this function as little as possible.&lt;br /&gt;
|param1 = lat&lt;br /&gt;
|param1text = Latitude, inputted as a number.&lt;br /&gt;
|param2 = lon&lt;br /&gt;
|param2text = Longitude, inputted as a number.&lt;br /&gt;
|param3 = max_alt&lt;br /&gt;
|param3text = The altitude, in metres, from which the function will begin searching for the height of the terrain. Defaults to 10,000 metres. If the terrain is higher than this argument specifies, &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt; will be returned.&lt;br /&gt;
|example1text = Dumps information about ground underneath the aircraft.&lt;br /&gt;
|example1 = var pos = geo.aircraft_position();&lt;br /&gt;
var info = geodinfo(pos.lat(), pos.lon());&lt;br /&gt;
debug.dump(info);&lt;br /&gt;
|example2text = Prints whether the ground underneath the aircraft is solid or is water.&lt;br /&gt;
|example2 = var pos = geo.aircraft_position();&lt;br /&gt;
var info = geodinfo(pos.lat(), pos.lon());&lt;br /&gt;
if (info != nil and info[1] != nil) {&lt;br /&gt;
    print(&amp;quot;The ground underneath the aircraft is &amp;quot;, info[1].solid == 1 ? &amp;quot;solid.&amp;quot; : &amp;quot;water.&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== geodtocart() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = geodtocart(lat, lon, alt);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=962|t=Source}}&lt;br /&gt;
|text = Converts {{wikipedia|geodetic coordinates}} (latitude, longitude, and altitude) to {{wikipedia|ECEF|Earth-centered, Earth-fixed}} coordinates (x, y and z). A vector is returned containing x, y, and z in metres. The equatorial radius of earth used is that defined by the {{wikipedia|WGS 84}} (6,378,137 metres). All argument are mandatory.&lt;br /&gt;
|param1 = lat&lt;br /&gt;
|param1text = Latitude, in degrees.&lt;br /&gt;
|param2 = lon&lt;br /&gt;
|param2text = Longitude, in degrees.&lt;br /&gt;
|param3 = alt&lt;br /&gt;
|param3text = Altitude, in metres.&lt;br /&gt;
|example1 = var (x, y, z) = geodtocart(0, 0, 0); # point is the intersection of the prime meridian and equator.&lt;br /&gt;
print(&amp;quot;x: &amp;quot;, x); # prints &amp;quot;x: 6378137&amp;quot;&lt;br /&gt;
print(&amp;quot;y: &amp;quot;, y); # prints &amp;quot;y: 0&amp;quot;&lt;br /&gt;
print(&amp;quot;z: &amp;quot;, z); # prints &amp;quot;y: 0&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== get_cart_ground_intersection() ===&lt;br /&gt;
Introduced in 2017.2.1, see [[Terrain Detection]].&lt;br /&gt;
&lt;br /&gt;
=== getprop() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = getprop(path[, path[, ...]]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=345|t=Source}}&lt;br /&gt;
|text = Returns the value of a node in the [[Property Tree]] or &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt; if the node does not exist or the value is not a number (NaN).&lt;br /&gt;
|param1 = path&lt;br /&gt;
|param1text = There needs to be at least one argument, but there is no limit to the maximum amount of arguments that can be given. The arguments will be concatenated together to form a property tree path. The arguments must be strings, but in FlightGear v3.2 onwards, there is also support (added by {{flightgear commit|34ed79}}) for numeric arguments as indices. See example 2 below.&lt;br /&gt;
|example1 = print(&amp;quot;You have FlightGear v&amp;quot;, getprop(&amp;quot;/sim/version/flightgear&amp;quot;)); # prints FlightGear version&lt;br /&gt;
|example2text = Note that the example below will only work in FlightGear 3.2 and above.&lt;br /&gt;
|example2 = for(var i = 0; i &amp;lt; 8; i += 1){&lt;br /&gt;
    print(&amp;quot;View #&amp;quot;, i + 1, &amp;quot; is named &amp;quot;, getprop(&amp;quot;/sim/view&amp;quot;, i, &amp;quot;name&amp;quot;));&lt;br /&gt;
}&lt;br /&gt;
|example3text = Same as above, but is supported by all versions of FlightGear.&lt;br /&gt;
|example3 = for(var i = 0; i &amp;lt; 8; i += 1){&lt;br /&gt;
    print(&amp;quot;View #&amp;quot;, i + 1, &amp;quot; is named &amp;quot;, getprop(&amp;quot;/sim/view[&amp;quot; ~ i ~ &amp;quot;]/name&amp;quot;));&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
==== See also ====&lt;br /&gt;
{{note| If you have to read/write the same property multiple times (e.g. in an update loop), it is more efficient to use a node object: &lt;br /&gt;
To get a Node rather than its value, use &amp;lt;code&amp;gt;props.globals.getNode()&amp;lt;/code&amp;gt; - see [[Nasal_library/props]]. }}&lt;br /&gt;
&lt;br /&gt;
=== greatCircleMove() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = greatCircleMove([pos, ]course, dist);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1681|t=Source}}&lt;br /&gt;
|text = Calculates a new set of geodetic coordinates using inputs of course and distance, either from the aircraft's current position (by default) or from another set of coordinates. Returns a hash containing two members, ''lat'' and ''lon'' (latitude and longitude respectively).&lt;br /&gt;
|param1 = pos&lt;br /&gt;
|param1text = Optional position to calculate from. If not given, the aircraft's current position will be used. Can be one of:&lt;br /&gt;
:* An &amp;lt;code&amp;gt;airport&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;runway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;taxiway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fix&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;waypoint&amp;lt;/code&amp;gt; ghost object.&lt;br /&gt;
:* A hash with ''lat'' and ''lon'' members&lt;br /&gt;
:* A &amp;lt;code&amp;gt;geo.Coord&amp;lt;/code&amp;gt; object&lt;br /&gt;
:* A lat/lon pair, that is, a pair of numbers (latitude followed by longitude) separated by a comma: &amp;lt;code&amp;gt;greatCircleMove(lat,lon, ...)&amp;lt;/code&amp;gt;.&lt;br /&gt;
|param2 = course&lt;br /&gt;
|param2text = Course to new set of coordinates, in degrees (in the range 0–360).&lt;br /&gt;
|param3 = dist&lt;br /&gt;
|param3text = Distance in nautical miles to the new set of coordinates.&lt;br /&gt;
|example1 = var pos = greatCircleMove(0,0, 0, 1);&lt;br /&gt;
debug.dump(pos); # print hash with coordinates&lt;br /&gt;
|example2 = var fix = findFixesByID(&amp;quot;POGIC&amp;quot;);&lt;br /&gt;
fix = fix[0];&lt;br /&gt;
var pos = greatCircleMove(fix, 45, 10);&lt;br /&gt;
debug.dump(pos); # print hash with coordinates&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== interpolate() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|private = _interpolate()&lt;br /&gt;
|syntax = interpolate(prop, value1, time1[, value2, time2[, ...]]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=522|t=Part 1}} {{!}} {{fgdata file|Nasal/globals.nas|t=Part 2}}&lt;br /&gt;
|text = Linearly interpolates a node in the property tree to a given value in a specified time. The value/time pairs will be run one after the other in the order that they are passed to the function. Note that the interpolation will continue even when the simulation is paused.&lt;br /&gt;
|param1 = prop&lt;br /&gt;
|param1text = String or &amp;lt;code&amp;gt;props.Node&amp;lt;/code&amp;gt; object that indicates a node in the property tree to be used.&lt;br /&gt;
|param2 = value''n''&lt;br /&gt;
|param2text = Target value to change the property to in the set amount of time. This should be a number.&lt;br /&gt;
|param3 = time''n''&lt;br /&gt;
|param3text = Time in seconds, that will be taken for the interpolation.&lt;br /&gt;
|example1text = Paste the code below into the Nasal Console and execute. Then, open the Property Browser and look for the property. Finally, run the code again, and watch the value of the property change.&lt;br /&gt;
|example1 = setprop(&amp;quot;/test&amp;quot;, 0); # (re-)set property&lt;br /&gt;
interpolate(&amp;quot;/test&amp;quot;,&lt;br /&gt;
    50, 5, # interpolate to 50 in 5 seconds&lt;br /&gt;
    10, 2, # interpolate to 10 in 2 seconds&lt;br /&gt;
    0, 5); # interpolate to 0 in 5 seconds&lt;br /&gt;
|example2 = # Apply the left brake at 20% per second&lt;br /&gt;
var prop = &amp;quot;controls/gear/brake-left&amp;quot;;&lt;br /&gt;
var dist = 1 - getprop(prop);&lt;br /&gt;
if (dist == 1) {&lt;br /&gt;
    interpolate(prop, 1, dist / 0.2);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== isa() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = isa(object, class);&lt;br /&gt;
|source = {{fgdata file|Nasal/globals.nas|t=Source}}&lt;br /&gt;
|text = Checks if an object is an instance of, or inherits from, a second object (or class), returning 1 (true) if it is and 0 (false) if otherwise.&lt;br /&gt;
|param1 = object&lt;br /&gt;
|param1text = Object to check.&lt;br /&gt;
|param2 = class&lt;br /&gt;
|param2text = Class/object to check that '''object''' inherits from or is an instance of.&lt;br /&gt;
|example1 = var coord = geo.Coord.new();&lt;br /&gt;
if(isa(coord, geo.Coord)){&lt;br /&gt;
    print(&amp;quot;Variable 'coord' is an instance of class 'geo.Coord'&amp;quot;); # this one will be printed&lt;br /&gt;
} else {&lt;br /&gt;
    print(&amp;quot;Variable 'coord' is not an instance of class 'geo.Coord'&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
|example2 = var coord = geo.Coord.new();&lt;br /&gt;
if(isa(coord, props.Node)){&lt;br /&gt;
    print(&amp;quot;Variable 'coord' is an instance of class 'props.Node'&amp;quot;);&lt;br /&gt;
} else {&lt;br /&gt;
    print(&amp;quot;Variable 'coord' is not an instance of class 'props.Node'&amp;quot;); # this one will be printed&lt;br /&gt;
}&lt;br /&gt;
|example3text = The example below demonstrates checking of inheritance.&lt;br /&gt;
|example3 = var Const = {&lt;br /&gt;
    constant: 2,&lt;br /&gt;
    getConst: func {&lt;br /&gt;
        return me.constant;&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var Add = {&lt;br /&gt;
    new: func {&lt;br /&gt;
        return { parents: [Add, Const] };&lt;br /&gt;
    },&lt;br /&gt;
&lt;br /&gt;
    addToConst: func(a){&lt;br /&gt;
        return a * me.getConst();&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var m = Add.new();&lt;br /&gt;
print(m.addToConst(4));&lt;br /&gt;
&lt;br /&gt;
if(isa(m, Add)) print(&amp;quot;Variable 'm' is an instance of class 'Add'&amp;quot;); # will be printed&lt;br /&gt;
if(isa(m, Const)) print(&amp;quot;Variable 'm' is an instance of class 'Const'&amp;quot;); # will also be printed&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== logprint() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = logprint(priority[, msg[, msg[, ...]]]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=431|t=Source}}&lt;br /&gt;
|text = Concatenates a message and logs it with a given priority level. Unlike {{func link|print()}} and {{func link|printlog()}}, message outputted by this function will be logged in your &amp;lt;code&amp;gt;[[Commonly used debugging tools#fgfs.log|fgfs.log]]&amp;lt;/code&amp;gt; file as coming from the Nasal file itself rather than from {{flightgear file|src/Scripting/NasalSys.cxx}}.&lt;br /&gt;
|param1 = priority&lt;br /&gt;
|param1text = Number specifying the priority level of the outputted message:&lt;br /&gt;
:{{{!}} class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Number !! Debug type&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} 1 {{!!}} Bulk&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} 2 {{!!}} Debug&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} 3 {{!!}} Info&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} 4 {{!!}} Warn&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} 5 {{!!}} Alert&lt;br /&gt;
{{!}}}&lt;br /&gt;
|param2 = msg&lt;br /&gt;
|param2text = The message. There is no limit to the arguments you give give. They will be concatenated together before logging.&lt;br /&gt;
|example1 = # logs the value of pi to three decimal places with log level 3&lt;br /&gt;
logprint(3, &amp;quot;pi = &amp;quot;, sprintf(&amp;quot;%.3f&amp;quot;, math.pi));&lt;br /&gt;
|example2 = logprint(5, &amp;quot;Alert! This is an important message!&amp;quot;);&lt;br /&gt;
}}&lt;br /&gt;
{{note| &lt;br /&gt;
The following constants have been added to the development branch of FlightGear (&amp;quot;next&amp;quot;) and will be releases with FG 2020.1 so you won't have to remember the numbers anymore:&lt;br /&gt;
&lt;br /&gt;
LOG_BULK, LOG_WARN, LOG_DEBUG, LOG_INFO, LOG_ALERT, DEV_WARN, DEV_ALERT }}&lt;br /&gt;
&lt;br /&gt;
=== magvar() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = magvar([pos]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1642|t=Source}}&lt;br /&gt;
|text = Returns the {{wikipedia|magnetic variation}} at a given set of coordinates. The table below gives the magnetic model used depending on the version of FlightGear.&lt;br /&gt;
{{{!}} class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! FlightGear versions !! Model !! Reference date&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} 3.6 and above {{!!}} {{wikipedia|World Magnetic Model}} (WMM) 2015 {{!!}} 1 January 2015&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} 0.9.11-pre1 to 3.4 {{!!}} WMM 2005 {{!!}} 1 January 2005&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} 0.7.3 to 0.9.10 {{!!}} WMM 2000 {{!!}} 1 January 2000&lt;br /&gt;
{{!}}}&lt;br /&gt;
|param1 = pos&lt;br /&gt;
|param1text = Optional position to calculate from. If not given, the aircraft's current position will be used. Can be one of:&lt;br /&gt;
:* An &amp;lt;code&amp;gt;airport&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;runway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;taxiway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fix&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;waypoint&amp;lt;/code&amp;gt; ghost object.&lt;br /&gt;
:* A hash with ''lat'' and ''lon'' members&lt;br /&gt;
:* A &amp;lt;code&amp;gt;geo.Coord&amp;lt;/code&amp;gt; object&lt;br /&gt;
:* A lat/lon pair, that is, a pair of numbers (latitude followed by longitude) separated by a comma: &amp;lt;code&amp;gt;magvar(lat,lon)&amp;lt;/code&amp;gt;.&lt;br /&gt;
|example1 = print(magvar(0, 0)); # prints the magnetic variation at 0, 0&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== maketimer() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = maketimer(interval[, self], function);&lt;br /&gt;
|source = ''Implemented using the {{API Link|flightgear|class|TimerObj}} class.''&amp;lt;br&amp;gt;{{flightgear file|src/Scripting/NasalSys.cxx|l=90|t=Part 1}} {{!}} {{flightgear file|src/Scripting/NasalSys.cxx|l=533|t=Part 2}}&lt;br /&gt;
|version = 2.12&lt;br /&gt;
|commit = {{flightgear commit|ab939f|t=commit}}&lt;br /&gt;
|text = Returns a timer object containing the following methods and members:&lt;br /&gt;
* '''start()''': Starts the timer.&lt;br /&gt;
* '''stop()''': Stops the timer.&lt;br /&gt;
* '''restart(interval)''': Restarts the timer with the given interval.&lt;br /&gt;
* '''singleShot''': Bool showing whether the timer is only to be run once, or continuously until told to stop. Can be both set and read from (see examples).&lt;br /&gt;
* '''isRunning''': Read-only bool telling whether the timer is currently running.&lt;br /&gt;
* '''simulatedTime''': (FG 2017.1+; {{flightgear commit|0af316|t=commit}}) Bool telling whether the timer is using simulated time (which accounts for pause, etc.). Defaults to false (use real time). Can be both read and set. This cannot be changed while the timer is running.&lt;br /&gt;
Unlike {{func link|settimer()}}, which it replaces, &amp;lt;code&amp;gt;maketimer()&amp;lt;/code&amp;gt; provides more control over the timer. In addition, it can help reduce memory usage.&lt;br /&gt;
|param1 = interval&lt;br /&gt;
|param1text = Interval in seconds for the timer.&lt;br /&gt;
|param2 = self&lt;br /&gt;
|param2text = Optional parameter specifying what any &amp;lt;code&amp;gt;'''me'''&amp;lt;/code&amp;gt; references in the function being called will refer to.&lt;br /&gt;
|param3 = function&lt;br /&gt;
|param3text = Function to be called at the given interval.&lt;br /&gt;
|example1 = var timer = maketimer(1, func(){&lt;br /&gt;
    print(&amp;quot;Hello, World!&amp;quot;); # print &amp;quot;Hello, World!&amp;quot; once every second (call timer.stop() to stop it)&lt;br /&gt;
});&lt;br /&gt;
timer.start();&lt;br /&gt;
|example2 = var timer = maketimer(1, math, func(){&lt;br /&gt;
    print(me.math); # 'me' reference is the 'math' namespace&lt;br /&gt;
});&lt;br /&gt;
timer.singleShot = 1; # timer will only be run once&lt;br /&gt;
timer.start();&lt;br /&gt;
|example3 = var timer = maketimer(1, func(){&lt;br /&gt;
    print(&amp;quot;Hello, World!&amp;quot;); # print &amp;quot;Hello, World!&amp;quot; once every second (call timer.stop() to stop it)&lt;br /&gt;
});&lt;br /&gt;
timer.start();&lt;br /&gt;
print(timer.isRunning); # prints 1&lt;br /&gt;
|example4text = In the example below, &amp;quot;Hello, World!&amp;quot; will be printed after one second the first time, and after two seconds thereafter.&lt;br /&gt;
|example4 = var update = func(){&lt;br /&gt;
    print(&amp;quot;Hello, World!&amp;quot;);&lt;br /&gt;
    timer.restart(2); # restarts the timer with a two second interval&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var timer = maketimer(1, update);&lt;br /&gt;
timer.singleShot = 1;&lt;br /&gt;
timer.start();&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== maketimestamp() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = maketimestamp()&lt;br /&gt;
|source = ''Implemented using the {{API Link|flightgear|class|TimeStampObj}} class.''&amp;lt;br&amp;gt;{{flightgear file|src/Scripting/NasalSys.cxx|l=214|t=Part 1}} {{!}} {{flightgear file|src/Scripting/NasalSys.cxx|l=589|t=Part 2}}&lt;br /&gt;
|version = 2019.2&lt;br /&gt;
|commit = {{flightgear commit|7db06300|t=commit}}&lt;br /&gt;
|text = Returns a time stamp object to allow high resolution timing of Nasal operations. When created the timer will automatically be stamped. The object has the following methods:&lt;br /&gt;
* '''stamp()''': Resets the timing operation. Call this first.&lt;br /&gt;
* '''elapsedMSec()''': returns number of milliseconds elapsed since stamp() called. Resolution may vary depending on platform but is usually at least millisecond accuracy.&lt;br /&gt;
* '''elapsedUSec()''': returns number of microseconds elapsed since stamp() called. Resolution may vary depending on platform but is usually at least millisecond accuracy.&lt;br /&gt;
|&lt;br /&gt;
|example1text = In the example below the number of milliseconds elapsed will be printed.&lt;br /&gt;
|example1 = var timestamp = maketimestamp();&lt;br /&gt;
timestamp.stamp();&lt;br /&gt;
print(timestamp.elapsedMSec(), &amp;quot;ms elapsed&amp;quot;);&lt;br /&gt;
print(timestamp.elapsedMSec(), &amp;quot;ms elapsed&amp;quot;);&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== md5() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = md5(string);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=758|t=Source}}&lt;br /&gt;
|version = 3.2&lt;br /&gt;
|commit = {{flightgear commit|cfbf9e|t=commit}}&lt;br /&gt;
|text = Returns a the {{wikipedia|MD5}} hash (as a string) of the inputted string.&lt;br /&gt;
|param1 = string&lt;br /&gt;
|param1text = String the generate the hash of. Mandatory.&lt;br /&gt;
|example1text = The below code should output &amp;lt;code&amp;gt;65a8e27d8879283831b664bd8b7f0ad4&amp;lt;/code&amp;gt;.&lt;br /&gt;
|example1 = print(md5(&amp;quot;Hello, World!&amp;quot;));&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== navinfo() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = navinfo(lat, lon, type, id);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1453|t=Source}}&lt;br /&gt;
|text = Returns vector &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt; ghost objects matching the given '''type''' and '''id''' or &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt; on error.&lt;br /&gt;
|param1 = lat ''and'' lon&lt;br /&gt;
|param1text = If given, the returned navaids will be put into order of ascending distance from the location.&lt;br /&gt;
|param2 = type&lt;br /&gt;
|param2text = Narrows the search to the given type. Must be one of &amp;quot;any,&amp;quot; &amp;quot;fix,&amp;quot; &amp;quot;vor,&amp;quot; &amp;quot;ndb,&amp;quot; &amp;quot;ils,&amp;quot; &amp;quot;dme,&amp;quot; or &amp;quot;tacan.&amp;quot; Defaults to the equivalent of &amp;quot;any.&amp;quot;&lt;br /&gt;
|param3 = id&lt;br /&gt;
|param3text = ID to search for. Note that, although all the parameters are technically optional, this parameter must be given, otherwise an empty vector will be returned.&lt;br /&gt;
|example1 = navinfo(&amp;quot;vor&amp;quot;); # returns all VORs&lt;br /&gt;
|example2 = navinfo(&amp;quot;HAM&amp;quot;); # return all navaids whose names start with &amp;quot;HAM&amp;quot;&lt;br /&gt;
|example3 = navinfo(&amp;quot;vor&amp;quot;, &amp;quot;HAM&amp;quot;); # return all VORs whose names start with &amp;quot;HAM&amp;quot;&lt;br /&gt;
|example4 = navinfo(34,48,&amp;quot;vor&amp;quot;,&amp;quot;HAM&amp;quot;); # return all VORs whose names start with &amp;quot;HAM&amp;quot; and sorted by distance relative to 34°, 48°&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== parse_markdown() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = parse_markdown(markdown);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=745|t=Part 1}} {{!}} {{simgear file|simgear/misc/SimpleMarkdown.cxx|t=Part 2}} &lt;br /&gt;
|version = 3.2&lt;br /&gt;
|text = Parses a string containing {{wikipedia|Markdown}} and returns the result as a string. As of FlightGear 2016.1, it is just a simple parser, and does the following:&lt;br /&gt;
* It strips whitespace from the beginning of the string.&lt;br /&gt;
* It supports [http://daringfireball.net/projects/markdown/syntax#p paragraphs and line breaks].&lt;br /&gt;
* It collapses whitespace.&lt;br /&gt;
* It converts unordered [http://daringfireball.net/projects/markdown/syntax#list lists] to use a bullet character (&amp;amp;bull;). Note that the bullet character is implemented in hexadecimal UTF-8 character bytes (&amp;lt;code&amp;gt;E2 80 A2&amp;lt;/code&amp;gt;), as so may not work properly when the being displayed in an encoding other than UTF-8.&lt;br /&gt;
|param1 = markdown&lt;br /&gt;
|param1text = String containing Markdown to be parsed.&lt;br /&gt;
|example1text = &lt;br /&gt;
Save the below code as &amp;lt;tt&amp;gt;''[[$FG_ROOT]]/gui/dialogs/test.xml''&amp;lt;/tt&amp;gt;, then run the Nasal code below it to open the dialog. To change the markdown to be parsed, simply change the code in the highlighted section, save it, and reload the GUI (&amp;lt;tt&amp;gt;Debug &amp;gt; Reload GUI&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot; highlight=&amp;quot;41-50&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;PropertyList&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;name&amp;gt;test&amp;lt;/name&amp;gt;&lt;br /&gt;
&amp;lt;layout&amp;gt;vbox&amp;lt;/layout&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;group&amp;gt;&lt;br /&gt;
    &amp;lt;layout&amp;gt;hbox&amp;lt;/layout&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &amp;lt;empty&amp;gt;&lt;br /&gt;
        &amp;lt;stretch&amp;gt;true&amp;lt;/stretch&amp;gt;&lt;br /&gt;
    &amp;lt;/empty&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &amp;lt;text&amp;gt;&lt;br /&gt;
        &amp;lt;label&amp;gt;parse_markdown() test dialog&amp;lt;/label&amp;gt;&lt;br /&gt;
    &amp;lt;/text&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &amp;lt;empty&amp;gt;&lt;br /&gt;
        &amp;lt;stretch&amp;gt;true&amp;lt;/stretch&amp;gt;&lt;br /&gt;
    &amp;lt;/empty&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;button&amp;gt;&lt;br /&gt;
        &amp;lt;legend&amp;gt;&amp;lt;/legend&amp;gt;&lt;br /&gt;
        &amp;lt;pref-width&amp;gt;16&amp;lt;/pref-width&amp;gt;&lt;br /&gt;
        &amp;lt;pref-height&amp;gt;16&amp;lt;/pref-height&amp;gt;&lt;br /&gt;
        &amp;lt;binding&amp;gt;&lt;br /&gt;
            &amp;lt;command&amp;gt;dialog-close&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/button&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/group&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;canvas&amp;gt;&lt;br /&gt;
    &amp;lt;name&amp;gt;Canvas plot&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;stretch&amp;gt;true&amp;lt;/stretch&amp;gt;&lt;br /&gt;
    &amp;lt;pref-width&amp;gt;400&amp;lt;/pref-width&amp;gt;&lt;br /&gt;
    &amp;lt;pref-height&amp;gt;300&amp;lt;/pref-height&amp;gt;&lt;br /&gt;
    &amp;lt;nasal&amp;gt;&lt;br /&gt;
        &amp;lt;load&amp;gt;&amp;lt;![CDATA[&lt;br /&gt;
var text = 'Items:&lt;br /&gt;
* apples&lt;br /&gt;
* oranges&lt;br /&gt;
* pears&lt;br /&gt;
&lt;br /&gt;
Some text.&lt;br /&gt;
Some more items:&lt;br /&gt;
* apples&lt;br /&gt;
* oranges&lt;br /&gt;
* pears';&lt;br /&gt;
&lt;br /&gt;
var parsed = parse_markdown(text);&lt;br /&gt;
&lt;br /&gt;
var root_canvas = canvas.get(cmdarg());&lt;br /&gt;
root_canvas.setColorBackground(255, 255, 255);&lt;br /&gt;
var root = root_canvas.createGroup();&lt;br /&gt;
&lt;br /&gt;
var text_dis = root.createChild(&amp;quot;text&amp;quot;)&lt;br /&gt;
    .setText(parsed)&lt;br /&gt;
    .setTranslation(5, 5)&lt;br /&gt;
    .setFont(&amp;quot;LiberationFonts\LiberationSans-Regular.ttf&amp;quot;)&lt;br /&gt;
    .setFontSize(15)&lt;br /&gt;
    .setColor(0, 0, 0)&lt;br /&gt;
    .setDrawMode(canvas.Text.TEXT)&lt;br /&gt;
    .setAlignment(&amp;quot;left-top&amp;quot;);&lt;br /&gt;
        ]]&amp;gt;&amp;lt;/load&amp;gt;&lt;br /&gt;
    &amp;lt;/nasal&amp;gt;&lt;br /&gt;
&amp;lt;/canvas&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/PropertyList&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|example1 = fgcommand(&amp;quot;dialog-show&amp;quot;, {&amp;quot;dialog-name&amp;quot;: &amp;quot;test&amp;quot;});&lt;br /&gt;
|example2text = The example below parses Markdown and outputs it in a HTML document. The parsed text is placed in &amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot; inline&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;/syntaxhighlight&amp;gt; tags. To change the Markdown to be parsed, simply edit the variable &amp;lt;tt&amp;gt;markdown&amp;lt;/tt&amp;gt; at the top of the code.&lt;br /&gt;
|example2 = &amp;lt;nowiki&amp;gt;var markdown = 'Items:&lt;br /&gt;
* apples&lt;br /&gt;
* oranges&lt;br /&gt;
* pears&lt;br /&gt;
&lt;br /&gt;
Some text.&lt;br /&gt;
Some more items:&lt;br /&gt;
* apples&lt;br /&gt;
* oranges&lt;br /&gt;
* pears';&lt;br /&gt;
&lt;br /&gt;
var parsed = parse_markdown(markdown);&lt;br /&gt;
&lt;br /&gt;
debug.dump(parsed);&lt;br /&gt;
&lt;br /&gt;
var path = string.normpath(getprop(&amp;quot;/sim/fg-home&amp;quot;) ~ '/Export/parse_markdown()-test.html');&lt;br /&gt;
&lt;br /&gt;
var file = io.open(path, &amp;quot;w&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
var html = &amp;quot;&amp;lt;!DOCTYPE html&amp;gt;\n\n&amp;lt;html&amp;gt;\n\n&amp;lt;head&amp;gt;\n\t&amp;lt;meta charset=\&amp;quot;UTF-8\&amp;quot;&amp;gt;\n\t&amp;lt;title&amp;gt;parse_markdown() test generated by Nasal&amp;lt;/title&amp;gt;\n&amp;lt;/head&amp;gt;\n\n&amp;lt;body&amp;gt;\n\t&amp;lt;pre&amp;gt;&amp;quot; ~ parsed ~ &amp;quot;&amp;lt;/pre&amp;gt;\n&amp;lt;/body&amp;gt;\n\n&amp;lt;/html&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
io.write(file, html);&lt;br /&gt;
io.close(file);&lt;br /&gt;
print(&amp;quot;Done, file ready for viewing (&amp;quot; ~ path ~ &amp;quot;)&amp;quot;);&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== parsexml() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = parsexml(path[, start[, end[, data[, pro_ins]]]]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=710|t=Source}}&lt;br /&gt;
|text = This function is an interface into the built-in [http://expat.sourceforge.net/ Expat XML parser]. The absolute path to the file is returned as string, or &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt; is returned on error.&lt;br /&gt;
|param1 = path&lt;br /&gt;
|param1text = Mandatory absolute path to the XML file to be parsed.&lt;br /&gt;
|param2 = start&lt;br /&gt;
|param2text = Optional callback function that will be called for every starting tag. The function should take two argument: the tag name and a hash containing attributes.&lt;br /&gt;
|param3 = end&lt;br /&gt;
|param3text = Optional callback function that will be called for every ending tag. The function should take one argument: the tag name.&lt;br /&gt;
|param4 = data&lt;br /&gt;
|param4text = Optional callback function that will be called for every piece of data within a set of tags. The function should take one argument: the data as a string.&lt;br /&gt;
|param5 = pro_ins&lt;br /&gt;
|param5text = Optional callback function that will be called for every {{wikipedia|Processing Instruction|processing instruction}}. The function should take two argument: the target and the data string.&lt;br /&gt;
|example1text = Save the below XML code in &amp;lt;tt&amp;gt;''[[$FG_HOME]]/Export/demo.xml''&amp;lt;/tt&amp;gt;. Then, execute the Nasal code below in the Nasal Console. The XML will be parsed and each bit of the code will be printed.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;?xml-stylesheet type=&amp;quot;text/xsl&amp;quot; href=&amp;quot;style.xsl&amp;quot;?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;foo&amp;gt;&lt;br /&gt;
  &amp;lt;blah type=&amp;quot;string&amp;quot;&amp;gt;&amp;lt;![CDATA[ &amp;lt;sender&amp;gt;John Smith&amp;lt;/sender&amp;gt; ]]&amp;gt;&amp;lt;/blah&amp;gt;&lt;br /&gt;
  &amp;lt;blah2 type=&amp;quot;string&amp;quot;&amp;gt;Orange &amp;amp;amp; lemons&amp;lt;/blah2&amp;gt;&lt;br /&gt;
&amp;lt;/foo&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|example1 = var start = func(name, attr){&lt;br /&gt;
    print(&amp;quot;Starting tag: '&amp;quot;, name, &amp;quot;'&amp;quot;);&lt;br /&gt;
    foreach(var a; keys(attr)){&lt;br /&gt;
        print(&amp;quot;\twith attribute &amp;quot;, a, '=&amp;quot;', attr[a], '&amp;quot;');&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var end = func(name){&lt;br /&gt;
    print(&amp;quot;Ending tag: '&amp;quot;, name, &amp;quot;'&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var data = func(data){&lt;br /&gt;
    print(&amp;quot;Data = '&amp;quot;, data, &amp;quot;'&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var pro_instr = func(target, data){&lt;br /&gt;
    print(&amp;quot;Processing instruction: target = '&amp;quot;, target, &amp;quot;', data = '&amp;quot;, data, &amp;quot;'&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
parsexml(getprop(&amp;quot;/sim/fg-home&amp;quot;) ~ '/Export/demo.xml', start, end, data, pro_instr);&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== print() ===&lt;br /&gt;
{{Note|As of 07/2020, we are in the process of slowly deprecating and removing Nasal print() (in fgdata) where possible in favor of log [[#logprint()]] which takes a priority level.&lt;br /&gt;
&lt;br /&gt;
This is part of the goal that we achieve zero output at log-level at alert, and everything shown at ‘warn; is really a warning, not just information.&amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/37042224/&amp;lt;/ref&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = print(data[, data[, ...]]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=415|t=Source}}&lt;br /&gt;
|text = Concatenates its arguments and then prints it to the terminal and the [[Commonly used debugging tools#fgfs.log|log]]. Note that a newline is automatically added.&lt;br /&gt;
|param1 = data&lt;br /&gt;
|param1text = Data to print. Only strings and numbers can be printed; other data types will not be. There many be any number of arguments; they will just be concatenated together.&lt;br /&gt;
|example1 = print(&amp;quot;Just&amp;quot;, &amp;quot; a &amp;quot;, &amp;quot;test&amp;quot;); # prints &amp;quot;Just a test&amp;quot;&lt;br /&gt;
|example2 = print(&amp;quot;pi = &amp;quot;, math.pi); # prints &amp;quot;pi = 3.141592...&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== printf() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = printf(format[, arg[, arg, [...]]]);&lt;br /&gt;
|source = {{fgdata file|Nasal/globals.nas|t=Source}}&lt;br /&gt;
|text = Creates and prints a formatted string. For a description of its arguments, see {{func link|sprintf()}} (it is, in fact, implemented using &amp;lt;code&amp;gt;sprintf()&amp;lt;/code&amp;gt;).&lt;br /&gt;
|example1 = printf(&amp;quot;In hexadecimal, 100000 = %X&amp;quot;, 186A0); # prints &amp;quot;In hexadecimal, 100000 = 186A0&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== printlog() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = printlog(level, data[, data[, ...]]);&lt;br /&gt;
|source = {{fgdata file|Nasal/globals.nas|t=Source}}&lt;br /&gt;
|text = Prints the given message with the given log level. If the log level is higher or equal to &amp;lt;code&amp;gt;/sim/logging/priority&amp;lt;/code&amp;gt;, it is printed.&lt;br /&gt;
|param1 = level&lt;br /&gt;
|param1text = Mandatory log level as a string. Must be one of &amp;quot;none,&amp;quot; &amp;quot;bulk,&amp;quot; &amp;quot;debug,&amp;quot; &amp;quot;info,&amp;quot; &amp;quot;warn,&amp;quot; or &amp;quot;alert.&amp;quot; Note that &amp;quot;none&amp;quot; will mean that the message will never be printed.&lt;br /&gt;
|param2 = data&lt;br /&gt;
|param2text = Data to be printed. Only strings and numbers will be printed; others will not be. There may be any number of arguments; they will just be concatenated together.&lt;br /&gt;
|example1 = printlog(&amp;quot;alert&amp;quot;, &amp;quot;This is an alert&amp;quot;); # message will be printed&lt;br /&gt;
|example2 = printlog(&amp;quot;info&amp;quot;, &amp;quot;Just informing you about something&amp;quot;); # message will be printed only if log level is set to &amp;quot;info&amp;quot; or less&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== rand() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = rand();&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=554|t=Source}}&lt;br /&gt;
|text = Returns a random floating point number between 0 (inclusive) and 1 (exclusive). It takes no arguments.&lt;br /&gt;
|example1 = print(rand()); # prints random number&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== registerFlightPlanDelegate() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = registerFlightPlanDelegate(init_func);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1879|t=Source}}&lt;br /&gt;
|text = Registers a flight plan delegate. See &amp;lt;tt&amp;gt;''{{fgdata file|Nasal/route_manager.nas|t=$FG_ROOT/Nasal/route_manager.nas}}''&amp;lt;/tt&amp;gt; for examples.&lt;br /&gt;
|param1 = init_func&lt;br /&gt;
|param1text = Initialization function which will be called during FlightGear's startup.&lt;br /&gt;
}}&lt;br /&gt;
=== removecommand() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = removecommand(cmd);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=668|t=Source}}&lt;br /&gt;
|text = Removes the given fgcommand. Returns &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt;.&lt;br /&gt;
{{caution|This will remove '''any''' [[fgcommands|fgcommand]], even those implemented in C++, so use with caution!}}&lt;br /&gt;
|param1 = cmd&lt;br /&gt;
|param1text = String specifying the name of the command to remove.&lt;br /&gt;
|example1 = addcommand(&amp;quot;hello&amp;quot;, func(){&lt;br /&gt;
    print(&amp;quot;Hello&amp;quot;);&lt;br /&gt;
});&lt;br /&gt;
fgcommand(&amp;quot;hello&amp;quot;); # &amp;quot;Hello&amp;quot; will be printed&lt;br /&gt;
removecommand(&amp;quot;hello&amp;quot;); # removes it&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== removelistener() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = removelistener(id);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=1384|t=Part 1}} {{!}} {{flightgear file|src/Scripting/NasalSys.cxx|l=506|t=Part 2}}&lt;br /&gt;
|text = Removes and deactivates the given listener and returns the number of listeners left or &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt; on error.&lt;br /&gt;
{{note|It is good practice to remove listeners when they are not required anymore. This prevents the listeners reducing FlightGear's run performance.}}&lt;br /&gt;
|param1 = id&lt;br /&gt;
|param1text = ID of listener as returned by {{func link|setlistener()}}.&lt;br /&gt;
|example1 = var ls = setlistener(&amp;quot;/sim/test&amp;quot;, func(){&lt;br /&gt;
    print(&amp;quot;Property '/sim/test' has been changed&amp;quot;);&lt;br /&gt;
});&lt;br /&gt;
setprop(&amp;quot;/sim/test&amp;quot;, &amp;quot;blah&amp;quot;); # trigger listener&lt;br /&gt;
var rem = removelistener(ls); # remove listener&lt;br /&gt;
print(&amp;quot;There are &amp;quot;, rem, &amp;quot; listeners remaining&amp;quot;);&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== resolvepath() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = resolvepath(path);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=604|t=Source}}&lt;br /&gt;
|text = Takes a relative path as a string and uses [[SimGear]]'s path-resolving framework to return an absolute path as a string. If the path could not be resolved, an empty string is returned. See [[Resolving Paths]] for a detailed description of the algorithm. This function can also be used to check if a file exists.&lt;br /&gt;
|param1 = path&lt;br /&gt;
|param1text = Relative path to be completed.&lt;br /&gt;
|example1 = print(resolvepath(&amp;quot;Nasal/globals.nas&amp;quot;)); # prints the equivalent of $FG_ROOT/Nasal/globals.nas&lt;br /&gt;
|example2 = print(resolvepath(&amp;quot;blah&amp;quot;)); # prints nothing; could not be resolved&lt;br /&gt;
|example3 = var file_path = resolvepath(&amp;quot;Aircraft/SenecaII/some-file&amp;quot;);&lt;br /&gt;
if (file_path != &amp;quot;&amp;quot;){&lt;br /&gt;
    gui.popupTip(&amp;quot;some-file found&amp;quot;, 2);&lt;br /&gt;
} else {&lt;br /&gt;
    gui.popupTip(&amp;quot;some-file not found&amp;quot;, 2);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== setlistener() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = setlistener(node, code[, init[, type]]);&lt;br /&gt;
|private = _setlistener()&lt;br /&gt;
|source = {{flightgear file|src/Scripting/Nasal|l=499|t=Part 1}} {{!}} {{flightgear file|src/Scripting/Nasal|l=1350|t=Part 2}}&amp;lt;br&amp;gt;''Listener implemented using the {{API Link|flightgear|class|FGNasalListener}} class.''&lt;br /&gt;
|text = Creates a listener which will be triggered when the given property is changed (depending on the '''type'''). A unique integer ID is returned; this can later be used as the argument to {{func link|removelistener()}}.&lt;br /&gt;
{{note|Listeners are known to be a source of resource leaks. To avoid this, please take measures such as:&lt;br /&gt;
* Using {{func link|removelistener()}} when they are not needed any more.&lt;br /&gt;
* Using a single initialization listener.&lt;br /&gt;
* Avoiding tying listeners to properties that are rapidly updated (e.g., many times per frame).&lt;br /&gt;
}}&lt;br /&gt;
|param1 = node&lt;br /&gt;
|param1text = Mandatory string or &amp;lt;code&amp;gt;props.Node&amp;lt;/code&amp;gt; object pointing to a property in the [[Property Tree]].&lt;br /&gt;
|param2 = code&lt;br /&gt;
|param2text = Mandatory callback function to execute when the listener is triggered. The function can take up to four arguments in the following order:&lt;br /&gt;
* '''changed''': a &amp;lt;code&amp;gt;props.Node&amp;lt;/code&amp;gt; object pointing to the changed node.&lt;br /&gt;
* '''listen''': a &amp;lt;code&amp;gt;props.Node&amp;lt;/code&amp;gt; object pointing to the listened-to node. Note that this argument maybe different depending on the '''type'''.&lt;br /&gt;
* '''mode''': an integer telling how the listener was triggered. 0 means that the value was changed. 1 means that a child property was added. -1 means that a child property was removed.&lt;br /&gt;
* '''is_child''': boolean telling whether '''changed''' is a child property of the listened-to '''node''' or not. 1 (true) if it is, 0 (false) otherwise.&lt;br /&gt;
|param3 = init&lt;br /&gt;
|param3text = If set to 1 (true), the listener will additionally be triggered when it is created. This argument is optional and defaults to 0 (false).&lt;br /&gt;
|param4 = type&lt;br /&gt;
|param4text = Integer specifying the listener's behavior. 0 means that the listener will only trigger when the property is changed. 1 means that the trigger will always be triggered when the property is written to. 2 will mean that the listener will be triggered even if child properties are modified. This argument is optional and defaults to 1.&lt;br /&gt;
|example1 = var prop = props.globals.initNode(&amp;quot;/sim/test&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;STRING&amp;quot;); # create property&lt;br /&gt;
var id = setlistener(&amp;quot;/sim/test&amp;quot;, func(n){ # create listener&lt;br /&gt;
    print(&amp;quot;Value: &amp;quot;, n.getValue());&lt;br /&gt;
});&lt;br /&gt;
setprop(&amp;quot;/sim/test&amp;quot;, &amp;quot;blah&amp;quot;); # trigger listener&lt;br /&gt;
removelistener(id); # remove listener&lt;br /&gt;
prop.remove(); # remove property&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== setprop() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = setprop(path[, path[, ...]], value);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=385|t=Source}}&lt;br /&gt;
|text = Sets the value of a property in the [[Property Tree]]. If the property does not exist, it will be created. Returns 1 (true) on success or 0 (false) if there was an error.&lt;br /&gt;
{{note|If you want to remove a property, you will have to use one of the &amp;lt;code&amp;gt;props&amp;lt;/code&amp;gt; helpers:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
props.globals.getNode(&amp;quot;foo/bar&amp;quot;).remove(); # take out the complete node&lt;br /&gt;
props.globals.getNode(&amp;quot;foo&amp;quot;).removeChild(&amp;quot;bar&amp;quot;); # take out a certain child node&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
|param1 = path&lt;br /&gt;
|param1text = There needs to be at least one '''path''' argument, but there is no limit to the maximum amount that can be given. They will be concatenated together to form a property tree path. The arguments must be strings, but in FlightGear v3.2 onwards, there also is support (added by {{flightgear commit|34ed79}}) for numeric arguments as indices. See example 2 below.&lt;br /&gt;
|param2 = value&lt;br /&gt;
|param2text = Value to write to the given property. Must be either a string or a number.&lt;br /&gt;
|example1 = setprop(&amp;quot;/sim/demo&amp;quot;, &amp;quot;This is a demo&amp;quot;);&lt;br /&gt;
|example2text = Note that the example below will only work in FlightGear 3.2 and above.&lt;br /&gt;
|example2 = for(var i = 0; i &amp;lt; 3; i += 1){&lt;br /&gt;
    setprop(&amp;quot;/sim/demo&amp;quot;, i, &amp;quot;Demo #&amp;quot; ~ i));&lt;br /&gt;
}&lt;br /&gt;
|example3text = Same as above, but is supported by all versions of FlightGear.&lt;br /&gt;
|example3 = for(var i = 0; i &amp;lt; 3; i += 1){&lt;br /&gt;
    setprop(&amp;quot;/sim/demo[&amp;quot; ~ i ~ &amp;quot;]&amp;quot;, &amp;quot;Demo #&amp;quot; ~ i));&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
==== See also ====&lt;br /&gt;
{{note| If you have to read/write the same property multiple times (e.g. in an update loop), it is more efficient to use a node object: &lt;br /&gt;
To get a Node rather than its value, use &amp;lt;code&amp;gt;props.globals.getNode()&amp;lt;/code&amp;gt; - see [[Nasal_library/props]]. }}&lt;br /&gt;
&lt;br /&gt;
=== settimer() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = settimer(function, delta[, realtime]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=499|t=Part 1}} {{!}} {{flightgear file|src/Scripting/NasalSys.cxx|l=1286|t=Part 2}}&lt;br /&gt;
|text = Runs the given function a specified amount of seconds after the current time. Returns &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt;.&lt;br /&gt;
{{note|Improper use of &amp;lt;code&amp;gt;settimer()&amp;lt;/code&amp;gt; may cause resource leaks. It is also highly recommended that the newer {{func link|maketimer()}} should be used instead of this function.}} &lt;br /&gt;
|param1 = function&lt;br /&gt;
|param1text = Mandatory function that will be called. It may be necessary to enclose code in an anonymous function (see example).&lt;br /&gt;
|param2 = delta&lt;br /&gt;
|param2text = Mandatory amount of time in seconds after which the function will be called.&lt;br /&gt;
|param3 = realtime&lt;br /&gt;
|param3text = If 1 (true), &amp;quot;real time&amp;quot; will be used instead of &amp;quot;simulation time.&amp;quot; Defaults to 0 (false). Note that if &amp;quot;simulation time&amp;quot; is used, the timer will not run while FlightGear is paused.&lt;br /&gt;
|example1 = var myFunc = func(){&lt;br /&gt;
    print(&amp;quot;Hello&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
settimer(myFunc, 2); # runs myFunc after 2 seconds&lt;br /&gt;
|example2 = var sqr = func(a){&lt;br /&gt;
    return a * a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
settimer(func(){&lt;br /&gt;
    print(sqr(2)); # will print 4 after 2 seconds&lt;br /&gt;
}, 2);&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== srand() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = srand();&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=559|t=Source}}&lt;br /&gt;
|text = Makes the pseudorandom number generator (see {{func link|rand()}}) generate a new {{wikipedia|random seed|noicon=1}} based on time. Returns 0.&lt;br /&gt;
}}&lt;br /&gt;
=== systime() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = systime();&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=770|t=Source}}&lt;br /&gt;
|text = Returns the {{wikipedia|Unix time}} (seconds since since 00:00:00 UTC, 1/1/1970) as a floating point number with high resolution. This function is useful for benchmarking purposes (see example 2).&lt;br /&gt;
{{note|1=High resolution timers under Windows can produce inaccurate or fixed sub-millisecond results.&amp;lt;ref&amp;gt;{{cite web|url=http://forum.flightgear.org/viewtopic.php?f=30&amp;amp;t=29259|title=Nasal: systime() ??!?|author=Necolatis|date=Apr 2nd, 2016}}&amp;lt;/ref&amp;gt; This is due to the underlying {{func link|GetSystemTimeAsFileTime()|link=https://msdn.microsoft.com/en-us/library/windows/desktop/ms724397(v=vs.85).aspx}} API call, which depends on hardware availability of suitable high resolution timers. See also [https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx Acquiring high-resolution time stamps]}}&lt;br /&gt;
|example1 = print(&amp;quot;Unix time: &amp;quot;, systime()); # prints Unix time&lt;br /&gt;
|example2 = var myFunc = func(){&lt;br /&gt;
    for(var i = 0; i &amp;lt;= 10; i += 1){&lt;br /&gt;
        print(&amp;quot;Interation #&amp;quot;, i);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
var t = systime(); # record time&lt;br /&gt;
myFunc(); # run function&lt;br /&gt;
var t2 = systime(); # record new time&lt;br /&gt;
print(&amp;quot;myFunc() took &amp;quot;, t2 - t, &amp;quot; seconds&amp;quot;); # print result&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== thisfunc() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = thisfunc();&lt;br /&gt;
|source = {{fgdata file|Nasal/globals.nas|t=Source}}&lt;br /&gt;
|text = Returns the function from which this function is called. This allows a function to reliably and safely call itself from within a closure.&lt;br /&gt;
|example1 = var stringify_vec = func(input){&lt;br /&gt;
    if (typeof(input) == &amp;quot;scalar&amp;quot;){&lt;br /&gt;
        return sprintf(&amp;quot;%s&amp;quot;, input);&lt;br /&gt;
    } elsif (typeof(input) == &amp;quot;vector&amp;quot;) {&lt;br /&gt;
        if (size(input) == 0) return &amp;quot;[]&amp;quot;;&lt;br /&gt;
        var this = thisfunc();&lt;br /&gt;
        var buffer = &amp;quot;[&amp;quot;;&lt;br /&gt;
        for(var i = 0; i &amp;lt; size(input); i += 1){&lt;br /&gt;
            buffer ~= this(input[i]);&lt;br /&gt;
            if (i == size(input) - 1) {&lt;br /&gt;
                buffer ~= &amp;quot;]&amp;quot;;&lt;br /&gt;
            } else {&lt;br /&gt;
                buffer ~= &amp;quot;, &amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        return buffer;&lt;br /&gt;
    } else {&lt;br /&gt;
        die(&amp;quot;stringify_vec(): Error! Invalid input. Must be a vector or scalar&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var test_vec = [&amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;c&amp;quot;, 1, 2, 3];&lt;br /&gt;
debug.dump(stringify_vec(test_vec)); # prints &amp;quot;[a, b, c, 1, 2, 3]&amp;quot;&lt;br /&gt;
test_vec = [];&lt;br /&gt;
debug.dump(stringify_vec(test_vec)); # prints &amp;quot;[]&amp;quot;&lt;br /&gt;
test_vec = {};&lt;br /&gt;
debug.dump(stringify_vec(test_vec)); # will throw an error&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== tileIndex() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = tileIndex();&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1720|t=Source}}&lt;br /&gt;
|text = Returns the index of the tile at the aircraft's current position as a string. This corresponds to the name of the STG file of the tile. For example, at [[KSFO]], this would be &amp;lt;code&amp;gt;942050&amp;lt;/code&amp;gt;, corresponding to &amp;lt;tt&amp;gt;''[[$FG_SCENERY]]/Terrain/w130n30/w123n3/942050.stg''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
|example1 = print(tileIndex()); # print index&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== tilePath() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = tilePath();&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1712|t=Source}}&lt;br /&gt;
|text = Returns the base path of the tile at the aircraft's current position as a string. For example, at KSFO, this would be &amp;lt;code&amp;gt;w130n30/w123n3&amp;lt;/code&amp;gt;, corresponding to &amp;lt;tt&amp;gt;''[[$FG_SCENERY]]/Terrain/w130n30/w123n3''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
|example1 = print(tilePath()); # print path&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== values() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = values(hash);&lt;br /&gt;
|source = {{fgdata file|Nasal/globals.nas|t=Source}}&lt;br /&gt;
|text = Returns a vector containing the values of the given hash.&lt;br /&gt;
|param1 = hash&lt;br /&gt;
|param1text = Mandatory hash to get the values of.&lt;br /&gt;
|example1 = var hash = {&lt;br /&gt;
    &amp;quot;a&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;b&amp;quot;: 2,&lt;br /&gt;
    &amp;quot;c&amp;quot;: 3&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
foreach(var val; values(hash)){&lt;br /&gt;
    print(val);&lt;br /&gt;
}&lt;br /&gt;
|example2text = The below example does exactly the same thing as the above example, but does not use &amp;lt;code&amp;gt;values()&amp;lt;/code&amp;gt;:&lt;br /&gt;
|example2 = var hash = {&lt;br /&gt;
    &amp;quot;a&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;b&amp;quot;: 2,&lt;br /&gt;
    &amp;quot;c&amp;quot;: 3&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
foreach(var key; keys(hash)){&lt;br /&gt;
    print(hash[key]);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Extension functions new in FG 2020.1 ==&lt;br /&gt;
The following functions have been added to the nasal core library and will be released with FlightGear version 2020.1. &lt;br /&gt;
Before the release they are available in the development branch &amp;quot;next&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== isfunc() ===&lt;br /&gt;
Returns 1 if type or argument is a function, otherwise 0.&lt;br /&gt;
&lt;br /&gt;
=== isghost() ===&lt;br /&gt;
Returns 1 if type or argument is a ghost, otherwise 0.&lt;br /&gt;
&lt;br /&gt;
=== ishash() ===&lt;br /&gt;
Returns 1 if type or argument is a hash, otherwise 0.&lt;br /&gt;
&lt;br /&gt;
=== isint() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = isint(x);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|t=Source}}&lt;br /&gt;
|text = Returns 1 if argument has a numeric value and x == floor(x), e.g. integer.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== isnum() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = isnum(x);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|t=Source}}&lt;br /&gt;
|text = Returns 1 if typeof(x) is &amp;quot;scalar&amp;quot; and x has a numeric value otherwise 0. &lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== isscalar() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = isscalar(x);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|t=Source}}&lt;br /&gt;
|text = Returns 1 if type or argument is a scalar (string or numeric), otherwise (vector, hash, func, ...) it returns 0. This is useful to check if a variable can be converted to string e.g. when useing the string concat operator &amp;quot;~&amp;quot;. &lt;br /&gt;
|example1 = var a = &amp;quot;foo&amp;quot;; &lt;br /&gt;
var b=42;&lt;br /&gt;
if (isscalar(a) and isscalar(b)) print(a~b);&lt;br /&gt;
if (isstr(a)) print(&amp;quot;a is a string&amp;quot;);&lt;br /&gt;
if (isint(b)) print(&amp;quot;b is an integer&amp;quot;);&lt;br /&gt;
# if (isscalar(a))... is equivalent to if (typeof(a) == &amp;quot;scalar&amp;quot;)...&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== isstr() ===&lt;br /&gt;
Returns 1 if type or argument is a string, otherwise 0. &lt;br /&gt;
&lt;br /&gt;
=== isvec() ===&lt;br /&gt;
Returns 1 if type or argument is a vector, otherwise 0.&lt;br /&gt;
&lt;br /&gt;
=== vecindex() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = vecindex(vector, value);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|t=Source}}&lt;br /&gt;
|text = Returns the index of value or nil, if value is not found in vector.&lt;br /&gt;
|example1=&lt;br /&gt;
var myvector = [&amp;quot;apple&amp;quot;, &amp;quot;bananna&amp;quot;, &amp;quot;coconut&amp;quot;];&lt;br /&gt;
# to check if a vector contains a certain value compare vecindex to nil&lt;br /&gt;
if (vecindex(myvector, &amp;quot;apple&amp;quot;) != nil) {&lt;br /&gt;
    print(&amp;quot;found apple&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
# WARNING: this will not work as desired because index is 0&lt;br /&gt;
if (vecindex(myvector, &amp;quot;apple&amp;quot;)) {&lt;br /&gt;
    print(&amp;quot;found apple&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{note| There is a similar function function contains(hash, key) to check if a hash contains a key (not value!).&lt;br /&gt;
It is to be discussed, if contains can/should be extended to support vectors in the above mentioned way. }}&lt;br /&gt;
&lt;br /&gt;
== Variables ==&lt;br /&gt;
Various global constants (technically variables) are provided for use in converting between different units. They are all found in {{fgdata file|Nasal/globals.nas|text=$FG_ROOT/Nasal/globals.nas}}.&lt;br /&gt;
&lt;br /&gt;
=== D2R ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var radians = degrees * D2R;&lt;br /&gt;
|text = Converts an angle from degrees to radians when multiplied by the angle in degrees. Equal to &amp;lt;code&amp;gt;π / 180&amp;lt;/code&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
=== FPS2KT ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var knots = feet_per_second * FPS2KT;&lt;br /&gt;
|text = Converts a velocity from feet per second to knots when multiplied by the velocity in feet per second. Approximately equal to 0.5925.&lt;br /&gt;
}}&lt;br /&gt;
=== FT2M ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var metres = feet * FT2M;&lt;br /&gt;
|text = Converts a length from feet to metres when multiplied by the length in feet. Equal to 0.3048.&lt;br /&gt;
}}&lt;br /&gt;
=== GAL2L ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var litres = gallons * GAL2L;&lt;br /&gt;
|text = Converts a volume from US liquid gallons to litres when multiplied by the volume in gallons. Approximately equal to 3.7854.&lt;br /&gt;
}}&lt;br /&gt;
=== IN2M ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var metres = inches * IN2M;&lt;br /&gt;
|text = Converts a length from inches to metres when multiplied by the length in inches. Equal to 0.0254.&lt;br /&gt;
}}&lt;br /&gt;
=== KG2LB ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var pounds = kilograms * KG2LB;&lt;br /&gt;
|text = Converts a mass from kilograms to pounds when multiplied by the mass in kilograms. Approximately equal to 2.2046.&lt;br /&gt;
}}&lt;br /&gt;
=== KT2FPS ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var feet_per_second = knots * KT2FPS;&lt;br /&gt;
|text = Converts a velocity from knots to feet per second when multiplied by the velocity in knots. Approximately equal to 1.6878.&lt;br /&gt;
}}&lt;br /&gt;
=== KT2MPS ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var metres_per_second = knots * KT2MPS;&lt;br /&gt;
|text = Converts a velocity from knots to metres per second when multiplied by the velocity in knots. Approximately equal to 0.5144.&lt;br /&gt;
}}&lt;br /&gt;
=== L2GAL ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var gallons = litres * L2GAL;&lt;br /&gt;
|text = Converts a volume from litres to US liquid gallons when multiplied by the volume in litres. Approximately equal to 0.2642.&lt;br /&gt;
}}&lt;br /&gt;
=== LB2KG ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var kilograms = pounds * LB2KG;&lt;br /&gt;
|text = Converts a mass from pounds to kilograms when multiplied by the mass in pounds. Approximately equal to 0.4536.&lt;br /&gt;
}}&lt;br /&gt;
=== M2FT ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var feet = metres * M2FT;&lt;br /&gt;
|text = Converts a length from metres to feet when multiplied by the length in metres. Approximately equal to 3.2808.&lt;br /&gt;
}}&lt;br /&gt;
=== M2IN ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var inches = metres * M2IN;&lt;br /&gt;
|text = Converts a length from metres to inches when multiplied by the length in metres. Approximately equal to 39.3701.&lt;br /&gt;
}}&lt;br /&gt;
=== M2NM ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var nautical_miles = metres * M2NM;&lt;br /&gt;
|text = Converts a length from metres to nautical miles when multiplied by the length in metres. Approximately equal to 0.00054.&lt;br /&gt;
}}&lt;br /&gt;
=== MPS2KT ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var knots = metres_per_second * MPS2KT;&lt;br /&gt;
|text = Converts a velocity from metres per second to knots when multiplied by the velocity in metres per second. Approximately equal to 1.9438.&lt;br /&gt;
}}&lt;br /&gt;
=== NM2M ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var metres = nautical_miles * NM2M;&lt;br /&gt;
|text = Converts a length from nautical miles to metres when multiplied by the length in nautical miles. Equal to 1,852.&lt;br /&gt;
}}&lt;br /&gt;
=== R2D ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var degrees = radians * R2D;&lt;br /&gt;
|text = Converts an angle from radians to degrees when multiplied by the angle in radians. Equal to &amp;lt;code&amp;gt;180 / π&amp;lt;/code&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Appendix}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Nasal namespaces}}&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Building_using_CMake_-_Windows&amp;diff=133923</id>
		<title>Building using CMake - Windows</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Building_using_CMake_-_Windows&amp;diff=133923"/>
		<updated>2021-12-13T12:59:59Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: /* Scripted Compilation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Main article|Building Flightgear}}&lt;br /&gt;
This article is intended to give an overview of building FlightGear on modern Windows systems. It was created using Windows 10 and VS 2019. It ought to be transferrable to earlier versions of the Windows OS and software.&lt;br /&gt;
&lt;br /&gt;
As FlightGear is now 64-bit only, the guide only describes building on a 64-bit system.&lt;br /&gt;
&lt;br /&gt;
== Required software ==&lt;br /&gt;
* [https://cmake.org/download/ CMake for Windows]. Download and install the Windows Win64-x64 Installer.&lt;br /&gt;
* [https://visualstudio.microsoft.com/downloads/ Microsoft Visual Studio 2019] (MSVC). The Community version is free. There is no need for the premium versions; none of their features are required to build FlightGear. The C++ compiler will not be installed by default. You either choose this component during installation or after installation by starting MSVC and trying to create a new C++ project. The one to download is &amp;quot;Desktop Development with C++&amp;quot;. Make sure to have the last version of the Windows SDK and C++ Compiler checked. As of 08/10/2020, the latest version of the compiler is &amp;quot;MSVC 142 - VS 2019 C++ x64/86 build tools (v14.27)&amp;quot;.&lt;br /&gt;
* [https://www.qt.io/download-open-source/ Qt5] for the [[Integrated Qt5 Launcher]]. Download the online installer, and choose the version matching your toolchain of Visual Studio e.g. &amp;quot;Qt 5.15.1 --&amp;gt; MSVC 2019 64 bit&amp;quot;. Any version past 5.9 will be fine; 5.15 recommended. Leave the default Developer and Designer Tools selection - these are needed for coding and compiling.&lt;br /&gt;
* [https://git-scm.com/download/win Git] to keep your build up to date. It also simplifies downloads of components. Optional, but can't recommend it enough!&lt;br /&gt;
&lt;br /&gt;
== Obtaining source ==&lt;br /&gt;
{{Main article|FlightGear and Git}}&lt;br /&gt;
Throughout this article it is assumed that you have set up git clones of the various source repositories (FlightGear, SimGear, data...).&lt;br /&gt;
Using an organized directory (see below) will help significantly.&lt;br /&gt;
&lt;br /&gt;
The commands to run are:&lt;br /&gt;
&lt;br /&gt;
{{code|git clone https://git.code.sf.net/p/flightgear/simgear simgear}}&lt;br /&gt;
&lt;br /&gt;
{{code|git clone https://git.code.sf.net/p/flightgear/flightgear flightgear}}&lt;br /&gt;
&lt;br /&gt;
{{code|git clone https://git.code.sf.net/p/flightgear/fgdata fgdata}}&lt;br /&gt;
&lt;br /&gt;
{{code|git clone https://git.code.sf.net/p/flightgear/windows-3rd-party windows-3rd-party}}&lt;br /&gt;
&lt;br /&gt;
{{code|git clone -b fgfs-osg-36-1 https://github.com/zakalawe/osg.git osg}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After downloading these, I would suggest assembling a folder structure as below:&lt;br /&gt;
&lt;br /&gt;
== Directory Tree ==&lt;br /&gt;
On Windows, assumptions on the directory structure are made to automate the discovery of dependencies. This recommended directory structure is described below. The components can be downloaded from the links above. If you do not use the recommended structure you will need to enter paths by hand and some parts may not input correctly.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Caveat -- spaces in the directory names will cause errors. It is best to make sure there are no spaces in the path anywhere.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: FlightGearBuild / &amp;lt;/tt&amp;gt; (Main root directory) &amp;lt;tt&amp;gt;&lt;br /&gt;
:: fgdata / &amp;lt;/tt&amp;gt; (FlightGear data files) &amp;lt;tt&amp;gt;&lt;br /&gt;
:: flightgear / &amp;lt;/tt&amp;gt; (FlightGear sources) &amp;lt;tt&amp;gt;&lt;br /&gt;
:: install / &amp;lt;/tt&amp;gt; (Directory where you will install the built binaries to) &amp;lt;tt&amp;gt;&lt;br /&gt;
::: launch.bat / &amp;lt;/tt&amp;gt; (launch script if desired, see below) &amp;lt;tt&amp;gt;&lt;br /&gt;
:: osg / &amp;lt;/tt&amp;gt; (OSG sources) &amp;lt;tt&amp;gt;&lt;br /&gt;
:: simgear / &amp;lt;/tt&amp;gt; (SimGear sources) &amp;lt;tt&amp;gt;&lt;br /&gt;
:: windows-3rd-party /&lt;br /&gt;
:: build.bat / &amp;lt;/tt&amp;gt; (build script, see below) &amp;lt;tt&amp;gt;&lt;br /&gt;
:: update.bat / &amp;lt;/tt&amp;gt; (update script, see below)&lt;br /&gt;
&lt;br /&gt;
== Building ==&lt;br /&gt;
=== Scripted Compilation ===&lt;br /&gt;
This script will allow you to build OpenSceneGraph, SimGear and FlightGear automatically.&lt;br /&gt;
 &lt;br /&gt;
{{collapsible script&lt;br /&gt;
| type   = Windows batch file&lt;br /&gt;
| title  = The &amp;lt;code&amp;gt;build.bat&amp;lt;/code&amp;gt; script for configuring and compiling OSG, SG, and FG&lt;br /&gt;
| lang   = batch&lt;br /&gt;
| script =&lt;br /&gt;
SET PATH=%PATH%;%ProgramFiles%\CMake\bin&lt;br /&gt;
SET QT5SDK64=C:\Qt\5.15.0\msvc2019_64&lt;br /&gt;
SET CMAKE_TOOLCHAIN=&amp;quot;Visual Studio 16 2019&amp;quot;&lt;br /&gt;
SET ROOT_DIR=C:\path\to\FlightGearBuild&lt;br /&gt;
&lt;br /&gt;
md osg-build&lt;br /&gt;
md simgear-build&lt;br /&gt;
md flightgear-build&lt;br /&gt;
&lt;br /&gt;
cd %ROOT_DIR%\osg-build&lt;br /&gt;
&lt;br /&gt;
cmake  %ROOT_DIR%\osg -G  %CMAKE_TOOLCHAIN% -A x64 ^&lt;br /&gt;
                 -DACTUAL_3RDPARTY_DIR=%ROOT_DIR%\windows-3rd-party/msvc140/3rdParty.x64 ^&lt;br /&gt;
                 -DCMAKE_RELWITHDEBINFO_POSTFIX:STRING= ^&lt;br /&gt;
                 -DOSG_USE_UTF8_FILENAME:BOOL=ON ^&lt;br /&gt;
                 -DWIN32_USE_MP:BOOL=ON ^&lt;br /&gt;
                 -DCMAKE_INSTALL_PREFIX:PATH=%ROOT_DIR%\install&lt;br /&gt;
cmake --build . --config RelWithDebInfo --target INSTALL&lt;br /&gt;
&lt;br /&gt;
cd %ROOT_DIR%\simgear-build&lt;br /&gt;
cmake  %ROOT_DIR%\simgear -G  %CMAKE_TOOLCHAIN% -A x64 ^&lt;br /&gt;
                 -DOSG_FSTREAM_EXPORT_FIXED:BOOL=ON ^&lt;br /&gt;
                 -DCMAKE_INSTALL_PREFIX:PATH=%ROOT_DIR%\install&lt;br /&gt;
cmake --build . --config RelWithDebInfo --target INSTALL&lt;br /&gt;
&lt;br /&gt;
cd %ROOT_DIR%\flightgear-build&lt;br /&gt;
cmake  %ROOT_DIR%\flightgear -G  %CMAKE_TOOLCHAIN% -A x64 ^&lt;br /&gt;
                  -DCMAKE_INSTALL_PREFIX:PATH=%ROOT_DIR%\install ^&lt;br /&gt;
                  -DCMAKE_PREFIX_PATH=%QT5SDK64% ^&lt;br /&gt;
                  -DOSG_FSTREAM_EXPORT_FIXED:BOOL=ON&lt;br /&gt;
                    &lt;br /&gt;
cmake --build . --config RelWithDebInfo --target INSTALL&lt;br /&gt;
&lt;br /&gt;
pause&lt;br /&gt;
| show  = 1&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Before starting to use the script, you need to edit the top few lines of the script. You will have to:&lt;br /&gt;
&lt;br /&gt;
1. Set the path to your CMake installation.&lt;br /&gt;
&lt;br /&gt;
2. Ensure that the path to your QT SDK is correct for your version of MSVC.&lt;br /&gt;
&lt;br /&gt;
3. Ensure your toolchain version matches, e.g. &amp;quot;Visual Studio 16 2019&amp;quot; for MSVC 2019 or &amp;quot;Visual Studio 15 2017&amp;quot; for MSVC 2017.&lt;br /&gt;
&lt;br /&gt;
4. Set ROOT_DIR to the FlightgearBuild folder you created (the above directory structure)&lt;br /&gt;
&lt;br /&gt;
==== Post-compilation: Launching FlightGear ====&lt;br /&gt;
'''In the debugger:'''&lt;br /&gt;
Open flightgear-build/FlightGear.sln. You can then perform all your development / debugging directly in VS. You normally only need to run build.bat again, if you update SimGear or OSG. &lt;br /&gt;
&lt;br /&gt;
To launch FlightGear from Visual Studio, you can follow the following steps:&lt;br /&gt;
The first time only:&lt;br /&gt;
# Make sure you set your build type to RelWithDebInfo in the top bar.&lt;br /&gt;
# To start with the launcher, click on the small black arrow beside Local Windows Debugger to open 'fgfs debug properties'. Switch to debugging; add {{code|--launcher}} to the 'Command Arguments'. Click Apply and then OK.&lt;br /&gt;
# Press the green arrow (Local Windows Debugger) to start up FlightGear. &lt;br /&gt;
# The first time you'll have to choose where FGDATA is -- to do this, select the 'fgdata' directory you cloned at the start.&lt;br /&gt;
&lt;br /&gt;
Therafter, simply press the green arrow directly each time you want to start. If there are any local changes, it will recompile; alternatively it will start up directly. It will take a little longer to start as it loads symbols; however you also have the benefit that any segfaults will be caught allowing you to report them!&lt;br /&gt;
&lt;br /&gt;
'''As a standard .exe:'''&lt;br /&gt;
NB these instructions overall are intended for setting up for development; there's a slightly more convoluted process for setting up for just plain flying (e.g. taking advantage of new features for aircraft development).&lt;br /&gt;
&lt;br /&gt;
Essentially, Visual Studio doesn't copy in the DLLs into the /bin/ folder. It's also not ideal to manually copy in the DLLS as it can cause all sorts of issues. However, without the DLLs FlightGear won't work; therefore, you need to set the PATH so it knows where to look for them.&lt;br /&gt;
This launch script should work, put into your /install/bin/ folder:&lt;br /&gt;
{{collapsible script&lt;br /&gt;
| type   = Windows batch file&lt;br /&gt;
| title  = The &amp;lt;code&amp;gt;launch.bat&amp;lt;/code&amp;gt; script for launching flightgear&lt;br /&gt;
| lang   = batch&lt;br /&gt;
| script =&lt;br /&gt;
SET PATH=C:\path\to\FlightGearBuild\install\bin;C:\path\to\FlightGearBuild\windows-3rd-party\msvc140\3rdParty.x64\bin;C:\Qt\5.15.0\msvc2019_64\bin;%PATH%&lt;br /&gt;
fgfs.exe --launcher&lt;br /&gt;
| show  = 1&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Adjust the &amp;quot;path\to&amp;quot; references to suit your own personal installation, as well as the QT5 path.&lt;br /&gt;
&lt;br /&gt;
=== Updating ===&lt;br /&gt;
To update FlightGear, in general, just run ''git pull'' on the source directories and then re-run the build.bat script -- it will update what it needs to, relatively quickly.&lt;br /&gt;
&lt;br /&gt;
=== Changing the Configuration ===&lt;br /&gt;
When the Simgear/FlightGear version numbers change, or you change configuration options (e.g. toggling Compositor, changing OSG versions, changing QT versions) you do have to re-configure in CMake. To do this, it's usually safest to delete the  simgear-build and flightgear-build folders and re-run the build.bat script, to ensure the build is clean. There is no need to delete osg-build unless changing OSG version.&lt;br /&gt;
&lt;br /&gt;
In case of problems, most of the time deleting the simgear-build and flightgear-build folders and re-running the build.bat script will be sufficient.&lt;br /&gt;
&lt;br /&gt;
{{building}}&lt;br /&gt;
[[fr:compiler flightear avec CMake - Windows]]&lt;br /&gt;
[[Category:Windows specific]]&lt;br /&gt;
[[Category:Hackathon Materials]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Building_using_CMake_-_Windows&amp;diff=133914</id>
		<title>Building using CMake - Windows</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Building_using_CMake_-_Windows&amp;diff=133914"/>
		<updated>2021-12-12T21:06:12Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: /* Directory Tree */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Main article|Building Flightgear}}&lt;br /&gt;
This article is intended to give an overview of building FlightGear on modern Windows systems. It was created using Windows 10 and VS 2019. It ought to be transferrable to earlier versions of the Windows OS and software.&lt;br /&gt;
&lt;br /&gt;
As FlightGear is now 64-bit only, the guide only describes building on a 64-bit system.&lt;br /&gt;
&lt;br /&gt;
== Required software ==&lt;br /&gt;
* [https://cmake.org/download/ CMake for Windows]. Download and install the Windows Win64-x64 Installer.&lt;br /&gt;
* [https://visualstudio.microsoft.com/downloads/ Microsoft Visual Studio 2019] (MSVC). The Community version is free. There is no need for the premium versions; none of their features are required to build FlightGear. The C++ compiler will not be installed by default. You either choose this component during installation or after installation by starting MSVC and trying to create a new C++ project. The one to download is &amp;quot;Desktop Development with C++&amp;quot;. Make sure to have the last version of the Windows SDK and C++ Compiler checked. As of 08/10/2020, the latest version of the compiler is &amp;quot;MSVC 142 - VS 2019 C++ x64/86 build tools (v14.27)&amp;quot;.&lt;br /&gt;
* [https://www.qt.io/download-open-source/ Qt5] for the [[Integrated Qt5 Launcher]]. Download the online installer, and choose the version matching your toolchain of Visual Studio e.g. &amp;quot;Qt 5.15.1 --&amp;gt; MSVC 2019 64 bit&amp;quot;. Any version past 5.9 will be fine; 5.15 recommended. Leave the default Developer and Designer Tools selection - these are needed for coding and compiling.&lt;br /&gt;
* [https://git-scm.com/download/win Git] to keep your build up to date. It also simplifies downloads of components. Optional, but can't recommend it enough!&lt;br /&gt;
&lt;br /&gt;
== Obtaining source ==&lt;br /&gt;
{{Main article|FlightGear and Git}}&lt;br /&gt;
Throughout this article it is assumed that you have set up git clones of the various source repositories (FlightGear, SimGear, data...).&lt;br /&gt;
Using an organized directory (see below) will help significantly.&lt;br /&gt;
&lt;br /&gt;
The commands to run are:&lt;br /&gt;
&lt;br /&gt;
{{code|git clone https://git.code.sf.net/p/flightgear/simgear simgear}}&lt;br /&gt;
&lt;br /&gt;
{{code|git clone https://git.code.sf.net/p/flightgear/flightgear flightgear}}&lt;br /&gt;
&lt;br /&gt;
{{code|git clone https://git.code.sf.net/p/flightgear/fgdata fgdata}}&lt;br /&gt;
&lt;br /&gt;
{{code|git clone https://git.code.sf.net/p/flightgear/windows-3rd-party windows-3rd-party}}&lt;br /&gt;
&lt;br /&gt;
{{code|git clone -b fgfs-osg-36-1 https://github.com/zakalawe/osg.git osg}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After downloading these, I would suggest assembling a folder structure as below:&lt;br /&gt;
&lt;br /&gt;
== Directory Tree ==&lt;br /&gt;
On Windows, assumptions on the directory structure are made to automate the discovery of dependencies. This recommended directory structure is described below. The components can be downloaded from the links above. If you do not use the recommended structure you will need to enter paths by hand and some parts may not input correctly.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Caveat -- spaces in the directory names will cause errors. It is best to make sure there are no spaces in the path anywhere.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: FlightGearBuild / &amp;lt;/tt&amp;gt; (Main root directory) &amp;lt;tt&amp;gt;&lt;br /&gt;
:: fgdata / &amp;lt;/tt&amp;gt; (FlightGear data files) &amp;lt;tt&amp;gt;&lt;br /&gt;
:: flightgear / &amp;lt;/tt&amp;gt; (FlightGear sources) &amp;lt;tt&amp;gt;&lt;br /&gt;
:: install / &amp;lt;/tt&amp;gt; (Directory where you will install the built binaries to) &amp;lt;tt&amp;gt;&lt;br /&gt;
::: launch.bat / &amp;lt;/tt&amp;gt; (launch script if desired, see below) &amp;lt;tt&amp;gt;&lt;br /&gt;
:: osg / &amp;lt;/tt&amp;gt; (OSG sources) &amp;lt;tt&amp;gt;&lt;br /&gt;
:: simgear / &amp;lt;/tt&amp;gt; (SimGear sources) &amp;lt;tt&amp;gt;&lt;br /&gt;
:: windows-3rd-party /&lt;br /&gt;
:: build.bat / &amp;lt;/tt&amp;gt; (build script, see below) &amp;lt;tt&amp;gt;&lt;br /&gt;
:: update.bat / &amp;lt;/tt&amp;gt; (update script, see below)&lt;br /&gt;
&lt;br /&gt;
== Building ==&lt;br /&gt;
=== Scripted Compilation ===&lt;br /&gt;
This script will allow you to build OpenSceneGraph, SimGear and FlightGear automatically.&lt;br /&gt;
 &lt;br /&gt;
{{collapsible script&lt;br /&gt;
| type   = Windows batch file&lt;br /&gt;
| title  = The &amp;lt;code&amp;gt;build.bat&amp;lt;/code&amp;gt; script for configuring and compiling OSG, SG, and FG&lt;br /&gt;
| lang   = batch&lt;br /&gt;
| script =&lt;br /&gt;
SET PATH=%PATH%;%ProgramFiles%\CMake\bin&lt;br /&gt;
SET QT5SDK64=C:\Qt\5.15.0\msvc2019_64&lt;br /&gt;
SET CMAKE_TOOLCHAIN=&amp;quot;Visual Studio 16 2019&amp;quot;&lt;br /&gt;
SET ROOT_DIR=C:\path\to\FlightGearBuild&lt;br /&gt;
&lt;br /&gt;
md osg-build&lt;br /&gt;
md simgear-build&lt;br /&gt;
md flightgear-build&lt;br /&gt;
&lt;br /&gt;
cd %ROOT_DIR%\osg-build&lt;br /&gt;
&lt;br /&gt;
cmake  %ROOT_DIR%\osg -G  %CMAKE_TOOLCHAIN% -A x64 ^&lt;br /&gt;
                 -DACTUAL_3RDPARTY_DIR=%ROOT_DIR%\windows-3rd-party/msvc140/3rdParty.x64 ^&lt;br /&gt;
                 -DCMAKE_RELWITHDEBINFO_POSTFIX:STRING= ^&lt;br /&gt;
                 -DOSG_USE_UTF8_FILENAME:BOOL=ON ^&lt;br /&gt;
                 -DWIN32_USE_MP:BOOL=ON ^&lt;br /&gt;
                 -DCMAKE_INSTALL_PREFIX:PATH=%ROOT_DIR%\install&lt;br /&gt;
cmake --build . --config RelWithDebInfo --target INSTALL&lt;br /&gt;
&lt;br /&gt;
cd %ROOT_DIR%\simgear-build&lt;br /&gt;
cmake  %ROOT_DIR%\simgear -G  %CMAKE_TOOLCHAIN% -A x64 ^&lt;br /&gt;
                 -DOSG_FSTREAM_EXPORT_FIXED:BOOL=ON ^&lt;br /&gt;
                 -DCMAKE_INSTALL_PREFIX:PATH=%ROOT_DIR%\install&lt;br /&gt;
cmake --build . --config RelWithDebInfo --target INSTALL&lt;br /&gt;
&lt;br /&gt;
cd %ROOT_DIR%\flightgear-build&lt;br /&gt;
cmake  %ROOT_DIR%\flightgear -G  %CMAKE_TOOLCHAIN% -A x64 ^&lt;br /&gt;
                  -DCMAKE_INSTALL_PREFIX:PATH=%ROOT_DIR%\install ^&lt;br /&gt;
                  -DCMAKE_PREFIX_PATH=%QT5SDK64% ^&lt;br /&gt;
                  -DOSG_FSTREAM_EXPORT_FIXED:BOOL=ON ^&lt;br /&gt;
                  -DENABLE_COMPOSITOR:BOOL=OFF&lt;br /&gt;
                    &lt;br /&gt;
cmake --build . --config RelWithDebInfo --target INSTALL&lt;br /&gt;
&lt;br /&gt;
pause&lt;br /&gt;
| show  = 1&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Before starting to use the script, you need to edit the top few lines of the script. You will have to:&lt;br /&gt;
&lt;br /&gt;
1. Set the path to your CMake installation.&lt;br /&gt;
&lt;br /&gt;
2. Ensure that the path to your QT SDK is correct for your version of MSVC.&lt;br /&gt;
&lt;br /&gt;
3. Ensure your toolchain version matches, e.g. &amp;quot;Visual Studio 16 2019&amp;quot; for MSVC 2019 or &amp;quot;Visual Studio 15 2017&amp;quot; for MSVC 2017.&lt;br /&gt;
&lt;br /&gt;
4. Set ROOT_DIR to the FlightgearBuild folder you created (the above directory structure)&lt;br /&gt;
&lt;br /&gt;
==== Post-compilation: Launching FlightGear ====&lt;br /&gt;
'''In the debugger:'''&lt;br /&gt;
Open flightgear-build/FlightGear.sln. You can then perform all your development / debugging directly in VS. You normally only need to run build.bat again, if you update SimGear or OSG. &lt;br /&gt;
&lt;br /&gt;
To launch FlightGear from Visual Studio, you can follow the following steps:&lt;br /&gt;
The first time only:&lt;br /&gt;
# Make sure you set your build type to RelWithDebInfo in the top bar.&lt;br /&gt;
# To start with the launcher, click on the small black arrow beside Local Windows Debugger to open 'fgfs debug properties'. Switch to debugging; add {{code|--launcher}} to the 'Command Arguments'. Click Apply and then OK.&lt;br /&gt;
# Press the green arrow (Local Windows Debugger) to start up FlightGear. &lt;br /&gt;
# The first time you'll have to choose where FGDATA is -- to do this, select the 'fgdata' directory you cloned at the start.&lt;br /&gt;
&lt;br /&gt;
Therafter, simply press the green arrow directly each time you want to start. If there are any local changes, it will recompile; alternatively it will start up directly. It will take a little longer to start as it loads symbols; however you also have the benefit that any segfaults will be caught allowing you to report them!&lt;br /&gt;
&lt;br /&gt;
'''As a standard .exe:'''&lt;br /&gt;
NB these instructions overall are intended for setting up for development; there's a slightly more convoluted process for setting up for just plain flying (e.g. taking advantage of new features for aircraft development).&lt;br /&gt;
&lt;br /&gt;
Essentially, Visual Studio doesn't copy in the DLLs into the /bin/ folder. It's also not ideal to manually copy in the DLLS as it can cause all sorts of issues. However, without the DLLs FlightGear won't work; therefore, you need to set the PATH so it knows where to look for them.&lt;br /&gt;
This launch script should work, put into your /install/bin/ folder:&lt;br /&gt;
{{collapsible script&lt;br /&gt;
| type   = Windows batch file&lt;br /&gt;
| title  = The &amp;lt;code&amp;gt;launch.bat&amp;lt;/code&amp;gt; script for launching flightgear&lt;br /&gt;
| lang   = batch&lt;br /&gt;
| script =&lt;br /&gt;
SET PATH=C:\path\to\FlightGearBuild\install\bin;C:\path\to\FlightGearBuild\windows-3rd-party\msvc140\3rdParty.x64\bin;C:\Qt\5.15.0\msvc2019_64\bin;%PATH%&lt;br /&gt;
fgfs.exe --launcher&lt;br /&gt;
| show  = 1&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Adjust the &amp;quot;path\to&amp;quot; references to suit your own personal installation, as well as the QT5 path.&lt;br /&gt;
&lt;br /&gt;
=== Updating ===&lt;br /&gt;
To update FlightGear, in general, just run ''git pull'' on the source directories and then re-run the build.bat script -- it will update what it needs to, relatively quickly.&lt;br /&gt;
&lt;br /&gt;
=== Changing the Configuration ===&lt;br /&gt;
When the Simgear/FlightGear version numbers change, or you change configuration options (e.g. toggling Compositor, changing OSG versions, changing QT versions) you do have to re-configure in CMake. To do this, it's usually safest to delete the  simgear-build and flightgear-build folders and re-run the build.bat script, to ensure the build is clean. There is no need to delete osg-build unless changing OSG version.&lt;br /&gt;
&lt;br /&gt;
In case of problems, most of the time deleting the simgear-build and flightgear-build folders and re-running the build.bat script will be sufficient.&lt;br /&gt;
&lt;br /&gt;
{{building}}&lt;br /&gt;
[[fr:compiler flightear avec CMake - Windows]]&lt;br /&gt;
[[Category:Windows specific]]&lt;br /&gt;
[[Category:Hackathon Materials]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Building_using_CMake_-_Windows&amp;diff=133913</id>
		<title>Building using CMake - Windows</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Building_using_CMake_-_Windows&amp;diff=133913"/>
		<updated>2021-12-12T21:05:56Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: /* Directory Tree */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Main article|Building Flightgear}}&lt;br /&gt;
This article is intended to give an overview of building FlightGear on modern Windows systems. It was created using Windows 10 and VS 2019. It ought to be transferrable to earlier versions of the Windows OS and software.&lt;br /&gt;
&lt;br /&gt;
As FlightGear is now 64-bit only, the guide only describes building on a 64-bit system.&lt;br /&gt;
&lt;br /&gt;
== Required software ==&lt;br /&gt;
* [https://cmake.org/download/ CMake for Windows]. Download and install the Windows Win64-x64 Installer.&lt;br /&gt;
* [https://visualstudio.microsoft.com/downloads/ Microsoft Visual Studio 2019] (MSVC). The Community version is free. There is no need for the premium versions; none of their features are required to build FlightGear. The C++ compiler will not be installed by default. You either choose this component during installation or after installation by starting MSVC and trying to create a new C++ project. The one to download is &amp;quot;Desktop Development with C++&amp;quot;. Make sure to have the last version of the Windows SDK and C++ Compiler checked. As of 08/10/2020, the latest version of the compiler is &amp;quot;MSVC 142 - VS 2019 C++ x64/86 build tools (v14.27)&amp;quot;.&lt;br /&gt;
* [https://www.qt.io/download-open-source/ Qt5] for the [[Integrated Qt5 Launcher]]. Download the online installer, and choose the version matching your toolchain of Visual Studio e.g. &amp;quot;Qt 5.15.1 --&amp;gt; MSVC 2019 64 bit&amp;quot;. Any version past 5.9 will be fine; 5.15 recommended. Leave the default Developer and Designer Tools selection - these are needed for coding and compiling.&lt;br /&gt;
* [https://git-scm.com/download/win Git] to keep your build up to date. It also simplifies downloads of components. Optional, but can't recommend it enough!&lt;br /&gt;
&lt;br /&gt;
== Obtaining source ==&lt;br /&gt;
{{Main article|FlightGear and Git}}&lt;br /&gt;
Throughout this article it is assumed that you have set up git clones of the various source repositories (FlightGear, SimGear, data...).&lt;br /&gt;
Using an organized directory (see below) will help significantly.&lt;br /&gt;
&lt;br /&gt;
The commands to run are:&lt;br /&gt;
&lt;br /&gt;
{{code|git clone https://git.code.sf.net/p/flightgear/simgear simgear}}&lt;br /&gt;
&lt;br /&gt;
{{code|git clone https://git.code.sf.net/p/flightgear/flightgear flightgear}}&lt;br /&gt;
&lt;br /&gt;
{{code|git clone https://git.code.sf.net/p/flightgear/fgdata fgdata}}&lt;br /&gt;
&lt;br /&gt;
{{code|git clone https://git.code.sf.net/p/flightgear/windows-3rd-party windows-3rd-party}}&lt;br /&gt;
&lt;br /&gt;
{{code|git clone -b fgfs-osg-36-1 https://github.com/zakalawe/osg.git osg}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After downloading these, I would suggest assembling a folder structure as below:&lt;br /&gt;
&lt;br /&gt;
== Directory Tree ==&lt;br /&gt;
On Windows, assumptions on the directory structure are made to automate the discovery of dependencies. This recommended directory structure is described below. Clicking the links allows you to download pre-built parts. If you do not use the recommended structure you will need to enter paths by hand and some parts may not input correctly.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Caveat -- spaces in the directory names will cause errors. It is best to make sure there are no spaces in the path anywhere.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: FlightGearBuild / &amp;lt;/tt&amp;gt; (Main root directory) &amp;lt;tt&amp;gt;&lt;br /&gt;
:: fgdata / &amp;lt;/tt&amp;gt; (FlightGear data files) &amp;lt;tt&amp;gt;&lt;br /&gt;
:: flightgear / &amp;lt;/tt&amp;gt; (FlightGear sources) &amp;lt;tt&amp;gt;&lt;br /&gt;
:: install / &amp;lt;/tt&amp;gt; (Directory where you will install the built binaries to) &amp;lt;tt&amp;gt;&lt;br /&gt;
::: launch.bat / &amp;lt;/tt&amp;gt; (launch script if desired, see below) &amp;lt;tt&amp;gt;&lt;br /&gt;
:: osg / &amp;lt;/tt&amp;gt; (OSG sources) &amp;lt;tt&amp;gt;&lt;br /&gt;
:: simgear / &amp;lt;/tt&amp;gt; (SimGear sources) &amp;lt;tt&amp;gt;&lt;br /&gt;
:: windows-3rd-party /&lt;br /&gt;
:: build.bat / &amp;lt;/tt&amp;gt; (build script, see below) &amp;lt;tt&amp;gt;&lt;br /&gt;
:: update.bat / &amp;lt;/tt&amp;gt; (update script, see below)&lt;br /&gt;
&lt;br /&gt;
== Building ==&lt;br /&gt;
=== Scripted Compilation ===&lt;br /&gt;
This script will allow you to build OpenSceneGraph, SimGear and FlightGear automatically.&lt;br /&gt;
 &lt;br /&gt;
{{collapsible script&lt;br /&gt;
| type   = Windows batch file&lt;br /&gt;
| title  = The &amp;lt;code&amp;gt;build.bat&amp;lt;/code&amp;gt; script for configuring and compiling OSG, SG, and FG&lt;br /&gt;
| lang   = batch&lt;br /&gt;
| script =&lt;br /&gt;
SET PATH=%PATH%;%ProgramFiles%\CMake\bin&lt;br /&gt;
SET QT5SDK64=C:\Qt\5.15.0\msvc2019_64&lt;br /&gt;
SET CMAKE_TOOLCHAIN=&amp;quot;Visual Studio 16 2019&amp;quot;&lt;br /&gt;
SET ROOT_DIR=C:\path\to\FlightGearBuild&lt;br /&gt;
&lt;br /&gt;
md osg-build&lt;br /&gt;
md simgear-build&lt;br /&gt;
md flightgear-build&lt;br /&gt;
&lt;br /&gt;
cd %ROOT_DIR%\osg-build&lt;br /&gt;
&lt;br /&gt;
cmake  %ROOT_DIR%\osg -G  %CMAKE_TOOLCHAIN% -A x64 ^&lt;br /&gt;
                 -DACTUAL_3RDPARTY_DIR=%ROOT_DIR%\windows-3rd-party/msvc140/3rdParty.x64 ^&lt;br /&gt;
                 -DCMAKE_RELWITHDEBINFO_POSTFIX:STRING= ^&lt;br /&gt;
                 -DOSG_USE_UTF8_FILENAME:BOOL=ON ^&lt;br /&gt;
                 -DWIN32_USE_MP:BOOL=ON ^&lt;br /&gt;
                 -DCMAKE_INSTALL_PREFIX:PATH=%ROOT_DIR%\install&lt;br /&gt;
cmake --build . --config RelWithDebInfo --target INSTALL&lt;br /&gt;
&lt;br /&gt;
cd %ROOT_DIR%\simgear-build&lt;br /&gt;
cmake  %ROOT_DIR%\simgear -G  %CMAKE_TOOLCHAIN% -A x64 ^&lt;br /&gt;
                 -DOSG_FSTREAM_EXPORT_FIXED:BOOL=ON ^&lt;br /&gt;
                 -DCMAKE_INSTALL_PREFIX:PATH=%ROOT_DIR%\install&lt;br /&gt;
cmake --build . --config RelWithDebInfo --target INSTALL&lt;br /&gt;
&lt;br /&gt;
cd %ROOT_DIR%\flightgear-build&lt;br /&gt;
cmake  %ROOT_DIR%\flightgear -G  %CMAKE_TOOLCHAIN% -A x64 ^&lt;br /&gt;
                  -DCMAKE_INSTALL_PREFIX:PATH=%ROOT_DIR%\install ^&lt;br /&gt;
                  -DCMAKE_PREFIX_PATH=%QT5SDK64% ^&lt;br /&gt;
                  -DOSG_FSTREAM_EXPORT_FIXED:BOOL=ON ^&lt;br /&gt;
                  -DENABLE_COMPOSITOR:BOOL=OFF&lt;br /&gt;
                    &lt;br /&gt;
cmake --build . --config RelWithDebInfo --target INSTALL&lt;br /&gt;
&lt;br /&gt;
pause&lt;br /&gt;
| show  = 1&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Before starting to use the script, you need to edit the top few lines of the script. You will have to:&lt;br /&gt;
&lt;br /&gt;
1. Set the path to your CMake installation.&lt;br /&gt;
&lt;br /&gt;
2. Ensure that the path to your QT SDK is correct for your version of MSVC.&lt;br /&gt;
&lt;br /&gt;
3. Ensure your toolchain version matches, e.g. &amp;quot;Visual Studio 16 2019&amp;quot; for MSVC 2019 or &amp;quot;Visual Studio 15 2017&amp;quot; for MSVC 2017.&lt;br /&gt;
&lt;br /&gt;
4. Set ROOT_DIR to the FlightgearBuild folder you created (the above directory structure)&lt;br /&gt;
&lt;br /&gt;
==== Post-compilation: Launching FlightGear ====&lt;br /&gt;
'''In the debugger:'''&lt;br /&gt;
Open flightgear-build/FlightGear.sln. You can then perform all your development / debugging directly in VS. You normally only need to run build.bat again, if you update SimGear or OSG. &lt;br /&gt;
&lt;br /&gt;
To launch FlightGear from Visual Studio, you can follow the following steps:&lt;br /&gt;
The first time only:&lt;br /&gt;
# Make sure you set your build type to RelWithDebInfo in the top bar.&lt;br /&gt;
# To start with the launcher, click on the small black arrow beside Local Windows Debugger to open 'fgfs debug properties'. Switch to debugging; add {{code|--launcher}} to the 'Command Arguments'. Click Apply and then OK.&lt;br /&gt;
# Press the green arrow (Local Windows Debugger) to start up FlightGear. &lt;br /&gt;
# The first time you'll have to choose where FGDATA is -- to do this, select the 'fgdata' directory you cloned at the start.&lt;br /&gt;
&lt;br /&gt;
Therafter, simply press the green arrow directly each time you want to start. If there are any local changes, it will recompile; alternatively it will start up directly. It will take a little longer to start as it loads symbols; however you also have the benefit that any segfaults will be caught allowing you to report them!&lt;br /&gt;
&lt;br /&gt;
'''As a standard .exe:'''&lt;br /&gt;
NB these instructions overall are intended for setting up for development; there's a slightly more convoluted process for setting up for just plain flying (e.g. taking advantage of new features for aircraft development).&lt;br /&gt;
&lt;br /&gt;
Essentially, Visual Studio doesn't copy in the DLLs into the /bin/ folder. It's also not ideal to manually copy in the DLLS as it can cause all sorts of issues. However, without the DLLs FlightGear won't work; therefore, you need to set the PATH so it knows where to look for them.&lt;br /&gt;
This launch script should work, put into your /install/bin/ folder:&lt;br /&gt;
{{collapsible script&lt;br /&gt;
| type   = Windows batch file&lt;br /&gt;
| title  = The &amp;lt;code&amp;gt;launch.bat&amp;lt;/code&amp;gt; script for launching flightgear&lt;br /&gt;
| lang   = batch&lt;br /&gt;
| script =&lt;br /&gt;
SET PATH=C:\path\to\FlightGearBuild\install\bin;C:\path\to\FlightGearBuild\windows-3rd-party\msvc140\3rdParty.x64\bin;C:\Qt\5.15.0\msvc2019_64\bin;%PATH%&lt;br /&gt;
fgfs.exe --launcher&lt;br /&gt;
| show  = 1&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Adjust the &amp;quot;path\to&amp;quot; references to suit your own personal installation, as well as the QT5 path.&lt;br /&gt;
&lt;br /&gt;
=== Updating ===&lt;br /&gt;
To update FlightGear, in general, just run ''git pull'' on the source directories and then re-run the build.bat script -- it will update what it needs to, relatively quickly.&lt;br /&gt;
&lt;br /&gt;
=== Changing the Configuration ===&lt;br /&gt;
When the Simgear/FlightGear version numbers change, or you change configuration options (e.g. toggling Compositor, changing OSG versions, changing QT versions) you do have to re-configure in CMake. To do this, it's usually safest to delete the  simgear-build and flightgear-build folders and re-run the build.bat script, to ensure the build is clean. There is no need to delete osg-build unless changing OSG version.&lt;br /&gt;
&lt;br /&gt;
In case of problems, most of the time deleting the simgear-build and flightgear-build folders and re-running the build.bat script will be sufficient.&lt;br /&gt;
&lt;br /&gt;
{{building}}&lt;br /&gt;
[[fr:compiler flightear avec CMake - Windows]]&lt;br /&gt;
[[Category:Windows specific]]&lt;br /&gt;
[[Category:Hackathon Materials]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=De/FlightGear_Newsletter_Juni_2017&amp;diff=132765</id>
		<title>De/FlightGear Newsletter Juni 2017</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=De/FlightGear_Newsletter_Juni_2017&amp;diff=132765"/>
		<updated>2021-08-13T17:56:54Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: /* FGRUN patch */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{De/Newsletter-header|2017-06}}&lt;br /&gt;
&amp;lt;div style=&amp;quot;border-bottom:3px double #BBB;&amp;quot;&amp;gt;&lt;br /&gt;
{| width=&amp;quot;100%&amp;quot; |&lt;br /&gt;
 | valign=&amp;quot;top&amp;quot; width=&amp;quot;33%&amp;quot; |&lt;br /&gt;
{{Newsletter-cover-header|Neuigkeiten in der Entwicklung}}&amp;lt;br&amp;gt;&lt;br /&gt;
[[#FGRUN patch|FGRUN patch]]&amp;lt;br&amp;gt;&lt;br /&gt;
{{Newsletter-cover-header|Im Hangar}}&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Flugzeugträger|Flugzeugträger]]&amp;lt;br&amp;gt;&lt;br /&gt;
 | valign=&amp;quot;top&amp;quot; width=&amp;quot;33%&amp;quot; |&lt;br /&gt;
{{Newsletter-cover-header|Szenerie-Abteilung}}&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Prag|Prag]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Helgoland mit OSM Daten|Helgoland mit OSM Daten]]&amp;lt;br&amp;gt;&lt;br /&gt;
 | valign=&amp;quot;top&amp;quot; width=&amp;quot;33%&amp;quot; |&lt;br /&gt;
{{Newsletter-cover-header|Mitarbeiten}}&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Übersetzer gesucht|Übersetzer gesucht]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#FlightGear Logos|FlightGear Logos]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[#Screenshots|Screenshots]]&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;small&amp;gt;[[#Screenshot des Monats|Screenshot des Monats]]&amp;lt;/small&amp;gt;&lt;br /&gt;
|}&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Neuigkeiten in der Entwicklung ==&lt;br /&gt;
=== FGRUN patch ===&lt;br /&gt;
Aufgrund von Komplikationen zwischen FGRun und der neusten FlightGear Version hat [[User:legoboyvdlp]] ein Patch für den alten Launcher geschrieben. Alle Nutzer von FlightGear 2017.3.0, die also lieber den alten [[FlightGear_Launch_Control|FGRun]] Launcher nutzen wollen, sollten sich den Patch von Jonathans [https://drive.google.com/open?id=0ByRqiv5ho2DZSjVRUGd4dDJRNmM|Google Drive] Account herunterladen. Allerdings empfehlen wir allen Nutzern natürlich den neueren [[FlightGear_Qt_launcher|FlightGear Launcher]], der als Bestandteil aller neuen FlightGear Versionen schon seit 2016.4 FGRun offiziell ersetzt.&lt;br /&gt;
&lt;br /&gt;
== Im Hangar ==&lt;br /&gt;
===Flugzeugträger===&lt;br /&gt;
Karla hat schon vor Maonaten ein 13MB großes vollständiges Blender Model des Flugzeugträgers Nimitz zusammen mit 64MB dazugehörigen Gimp .xcf Dateien der FlightGear community zukommen lassen.&lt;br /&gt;
Seither sind mehrere Entwickler damit beschäftigt, Karla's Model für FlightGear nutzbar zu machen. Außerdem wird er an die schon existierenden Flugzuegträgermodelle in der FlightGear-Welt angepasst.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der originale Post von Karla findet sich im [https://forum.flightgear.org/viewtopic.php?f=5&amp;amp;t=31817 FlightGer Forum]. Hier findest Du auch den neusten Entwicklungsstand.&amp;lt;br&amp;gt;mhab hat außerdem ein [https://gitlab.com/mhab/Flightgear-Carrier-Upgrade Vinson repository auf gitlab] erstellt.&lt;br /&gt;
&lt;br /&gt;
Ein großer Dank geht an Karla, ein weiterer an jeden, der dabei beiträgt.&lt;br /&gt;
{{Gallery&lt;br /&gt;
|width = 300&lt;br /&gt;
|Vinson HD-005.png|mhab's Arbeit an der Vinson&lt;br /&gt;
|Vinson HD-008.png|Blick aufs Deck der Vinson&lt;br /&gt;
|Truman F14 Elevator-013.png|Truman Elevator}}&lt;br /&gt;
== Szenerie-Abteilung ==&lt;br /&gt;
=== Prag ===&lt;br /&gt;
{{usr|Catalanoic}} hat Gebäude und 3D-Objekte zum Václav Havel Flughafen Prag (LKPR) erstellt und eingebaut. Der Flughafen Prag ist der nächste StandardFlughafen in [[Changelog 2017.3|FlightGear 2017.3]], dessen Daten schon in der Installationsdatei enthalten sind und auf dem man startet, wenn kein Flughafen angegeben wurde.&lt;br /&gt;
&lt;br /&gt;
[[File:Helgoland.jpg|thumb|Die Insel Helgoland mit OSM Daten]]&lt;br /&gt;
=== Helgoland mit OSM Daten===&lt;br /&gt;
{{usr|D-ECHO}} hat eine neue Scenerie für Helgoland (und Düne) erstellt! Es hat jetzt verbesserte Landclasses, ein besseres Airport Layout und mehr Objekte.&lt;br /&gt;
Zur Zeit ist es nur auf github verfügbar: https://github.com/D-ECHO/Helgoland-CustomScenery &amp;lt;br&amp;gt;&lt;br /&gt;
Sobald die Arbeit fertig ist soll es auch in Terrasync eingebracht werden.&lt;br /&gt;
&lt;br /&gt;
== Mitarbeiten ==&lt;br /&gt;
=== Übersetzer gesucht ===&lt;br /&gt;
{|&lt;br /&gt;
| [[File:en.gif]]&lt;br /&gt;
| The FlightGear Wiki still needs help for translating it into various languages. If you are interested in making the FlightGear Wiki multilingual,  start at [[Help:Translate]].&lt;br /&gt;
|-&lt;br /&gt;
| [[File:fr.gif]]&lt;br /&gt;
| Le wiki de FlightGear a toujours besoin d'aide pour être traduit en différentes langues. Si vous êtes intéressé par le rendre multilingue, commencez par lire [[:fr:Help:Traduire|Help:Traduire]].&lt;br /&gt;
|-&lt;br /&gt;
| [[File:de.gif]]&lt;br /&gt;
| Das FlightGear Wiki benötigt immer noch Hilfe bei der Übersetzung in verschiedene Sprachen. Wenn Du Interesse daran hast, das FlightGear Wiki mehrsprachig zu machen, dann fang doch mit [[:de:Help:Übersetzen|Help:Übersetzen]] an.&lt;br /&gt;
|-&lt;br /&gt;
| [[File:nl.gif]]&lt;br /&gt;
| De FlightGear Wiki kan nog steed hulp gebruiken bij het vertalen van artikelen. Als je interesse hebt om de wiki meertalig te maken, raden we je aan om een kijkje te nemen bij [[:nl:Help:Vertalen|Help:Vertalen]].&lt;br /&gt;
|-&lt;br /&gt;
| [[File:es.gif]]&lt;br /&gt;
| La wiki de FlightGear todavía necesita ayuda para traducirla a varios lenguajes. Si estás interesado en hacer la FlightGear wiki multilingüe, entonces comienza en [[:es:Help:Traducir|Help:Traducir]].&lt;br /&gt;
|-&lt;br /&gt;
| [[File:cat.gif]]&lt;br /&gt;
| La wiki de FlightGear encara necessita ajuda per traduir-la a diverses llengües. Si esteu interessat en fer la wiki de FlightGear multilingüe, llavors comenceu a [[:ca:Help:Traduir|Help:Traduir]].&lt;br /&gt;
|-&lt;br /&gt;
| [[File:pt.gif]]&lt;br /&gt;
| A wiki de FlightGear ainda necessita de ajuda para traduzi-la em vários idiomas. Se estás interessado em tornar a wiki de FlightGear multi-lingual, por favor começa em [[:pt:Help: Traduzir|Help: Traduzir]].&lt;br /&gt;
|-&lt;br /&gt;
| [[File:zh.gif]]&lt;br /&gt;
| FlightGear 百科仍然需要志愿者将其翻译为各种语言。如果你有兴趣让FlightGear百科支持更多语言, 你可以查看 [[Help:Translate]].&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== FlightGear Logos ===&lt;br /&gt;
Solltest Du graphische Elemente für deine FlightGear Website (Hangar, YouTube-Kanal, o.ä.) suchen, wirf doch einen Blick auf die [[FlightGear logos|FlightGear Logos]]. Und falls Du eine künstlerische Ader hast, fühl Dich frei, eigene Designs zu erstellen und hier hochzuladen.&lt;br /&gt;
&lt;br /&gt;
=== Screenshots ===&lt;br /&gt;
Das FlightGear-Projekt benötigt ständig Screenshots, welche neue Features seit dem letzten Release zeigen. Diese sollten von hoher Qualität sein, besonders von inhaltlicher und technischer Seite. Dafür wird empfohlen, die besten Graphikfilter zu nutzen ([[:de:Antialiasing|Antialiasing]], Texturenschärfung, etc.). Näheres unter [[:de:Howto:Gute Screenshots machen|Howto:Gute Screenshots machen]].&lt;br /&gt;
&lt;br /&gt;
==== Screenshot des Monats ====&lt;br /&gt;
Kandidaten für den besten Screenshot dieses Monats können in [https://forum.flightgear.org/viewtopic.php?f=19&amp;amp;t=32296 diesem] Forum Thread eingereicht werden. Beachte auch die Teilnahmeregeln im [https://forum.flightgear.org/viewtopic.php?f=19&amp;amp;t=32296 ersten Post]. Aus Gründen der Zweckmäßigkeit werden, wenn alle Kandidaten eingereicht wurden, alle Einträge in einem separaten Thread zusammengefasst, wo auch das Voting stattfinden wird. Am Ende des Monats, nach Abschluss des Votings, wird der beste Screenshot in dieser Newsletter präsentiert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:De/FlightGear Newsletter|2017 06]]&lt;br /&gt;
[[Category:Changes after 2017.2]]&lt;br /&gt;
&lt;br /&gt;
[[en:FlightGear Newsletter June 2017]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Release_plan/Lessons_learned&amp;diff=132764</id>
		<title>Release plan/Lessons learned</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Release_plan/Lessons_learned&amp;diff=132764"/>
		<updated>2021-08-13T17:56:43Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: /* 2016.1 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Release}}&lt;br /&gt;
This is a list of '''lessons learned from the previous releases''', things that turned out well and should be kept for the next release as well as thing that didn't turn out so well and should be changed for future releases. Ideally, the [[release plan]] should be updated and augmented so that the lessons learned are incorporated accordingly.&lt;br /&gt;
&lt;br /&gt;
== General ==&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= As mentioned by Curt on previous occasions, one of the more labour intense parts of managing a release consists of the compilation of a comprehensible revision log that lists the major changes / improvements to FlightGear. I would appreciate it if somebody would give a hand in compiling such a list. &lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/20478104/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;[Flightgear-devel] Revision Log / Intended developments&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Durk Talsma&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Oct 5th, 2008&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= We normally highlight particularly exciting new and improved aircraft, but I have struggled to keep up with the rapid pace of development. Please let me know of any particular aircraft that you think should be included. To qualify they must be in FGDATA, and must have been introduced/improved significantly&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/30366915/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;[Flightgear-devel] 2.10.0 Changelog - help required&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Stuart Buchanan&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Jan 18th, 2013&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
* I'd instead suggest that aircraft making an incompatible change add a version tag to their data files and discard data files without it. (We could also have a &amp;quot;delete data files on aircraft upgrade&amp;quot; (not core-FG upgrade, aircraft aren't required to have the same release cycle as core FG) *option*, but the aircraft developer should be able to choose whether they want it.)&amp;lt;ref&amp;gt;{{cite web&lt;br /&gt;
  |url    =  https://sourceforge.net/p/flightgear/mailman/message/35441263/ &lt;br /&gt;
  |title  =  &amp;lt;nowiki&amp;gt; Re: [Flightgear-devel] C172P version in 2016.3.1 broken ASI? &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |author =  &amp;lt;nowiki&amp;gt; Rebecca N. Palmer &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |date   =  Oct 21st, 2016 &lt;br /&gt;
  |added  =  Oct 21st, 2016 &lt;br /&gt;
  |script_version = 0.40 &lt;br /&gt;
  }}&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* the best thing would be for aircraft to version their data files individually&amp;lt;ref&amp;gt;{{cite web&lt;br /&gt;
  |url    =  https://sourceforge.net/p/flightgear/mailman/message/35441430/ &lt;br /&gt;
  |title  =  &amp;lt;nowiki&amp;gt; Re: [Flightgear-devel] C172P version in 2016.3.1 broken ASI? &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |author =  &amp;lt;nowiki&amp;gt; James Turner &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |date   =  Oct 21st, 2016 &lt;br /&gt;
  |added  =  Oct 21st, 2016 &lt;br /&gt;
  |script_version = 0.40 &lt;br /&gt;
  }}&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* FG should save data files also when a user presses the X button in the window decoration, not just when the user goes to File &amp;gt; Exit &amp;gt; Yes&amp;lt;ref&amp;gt;{{cite web&lt;br /&gt;
  |url    =  https://sourceforge.net/p/flightgear/mailman/message/35440828/ &lt;br /&gt;
  |title  =  &amp;lt;nowiki&amp;gt; Re: [Flightgear-devel] C172P version in 2016.3.1 broken ASI? &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |author =  &amp;lt;nowiki&amp;gt; Denk Padje &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |date   =  Oct 20th, 2016 &lt;br /&gt;
  |added  =  Oct 20th, 2016 &lt;br /&gt;
  |script_version = 0.40 &lt;br /&gt;
  }}&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* When FG initialies itself after the version number has changed, it should either delete old data files (because new aircraft might be incompatible) or somehow migrate the data file (IIRC the issue resolves itself if the user exits via File &amp;gt; Exit &amp;gt; Yes, so possibly FG could load the aircraft, shut it down in order to save a new data file, and then reload new data)&amp;lt;ref&amp;gt;{{cite web&lt;br /&gt;
  |url    =  https://sourceforge.net/p/flightgear/mailman/message/35440828/ &lt;br /&gt;
  |title  =  &amp;lt;nowiki&amp;gt; Re: [Flightgear-devel] C172P version in 2016.3.1 broken ASI? &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |author =  &amp;lt;nowiki&amp;gt; Denk Padje &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |date   =  Oct 20th, 2016 &lt;br /&gt;
  |added  =  Oct 20th, 2016 &lt;br /&gt;
  |script_version = 0.40 &lt;br /&gt;
  }}&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* if an aircraft defines all possible properties in the protocol, it tries to send 14988 bytes per packet, almost 12.5 times the allowed limit! Your idea of sending properties in a round-robin fashion is good IMHO but good MP debugging tools are necessary for aircraft developers.&amp;lt;ref&amp;gt;{{cite web&lt;br /&gt;
  |url    =  https://sourceforge.net/p/flightgear/mailman/message/35441502/ &lt;br /&gt;
  |title  =  &amp;lt;nowiki&amp;gt; Re: [Flightgear-devel] C172 MP alert on console &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |author =  &amp;lt;nowiki&amp;gt; Ludovic Brenta &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |date   =  Oct 21st, 2016 &lt;br /&gt;
  |added  =  Oct 21st, 2016 &lt;br /&gt;
  |script_version = 0.40 &lt;br /&gt;
  }}&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2016.3 ==&lt;br /&gt;
* I would much prefer we solve this by generating new apt.dat offline and distributing them, rather than ending up with a large number of small apt.dat files, which is not what the maintainers of the main file expect.&amp;lt;ref&amp;gt;{{cite web&lt;br /&gt;
  |url    =  https://sourceforge.net/p/flightgear/mailman/message/35104907/ &lt;br /&gt;
  |title  =  &amp;lt;nowiki&amp;gt; Re: [Flightgear-devel] apt.dat - add local version  ? &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |author =  &amp;lt;nowiki&amp;gt; James Turner &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |date   =  May 21st, 2016 &lt;br /&gt;
  |added  =  May 21st, 2016 &lt;br /&gt;
  |script_version = 0.40 &lt;br /&gt;
  }}&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* integration of the maldives scenery took an afternoon to complete. Maybe we can come up with a scripted/automated solution if this should be required again.&amp;lt;ref&amp;gt;{{cite web&lt;br /&gt;
  |url    =  https://sourceforge.net/p/flightgear/mailman/message/35360342/ &lt;br /&gt;
  |title  =  &amp;lt;nowiki&amp;gt; Re: [Flightgear-devel] Subject: Re: Maldives, once again ;) &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |author =  &amp;lt;nowiki&amp;gt; Torsten Dreyer &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |date   =  Sep 10th, 2016 &lt;br /&gt;
  |added  =  Sep 10th, 2016 &lt;br /&gt;
  |script_version = 0.40 &lt;br /&gt;
  }}&amp;lt;/ref&amp;gt; Is there any format this could be submitted which would be easier to incorporate, or is the issue really that the sequence takes too long due to sie? I guess if there's an input format that makes life easier, we could publish it and encourage people to meet it.&amp;lt;ref&amp;gt;{{cite web&lt;br /&gt;
  |url    =  https://sourceforge.net/p/flightgear/mailman/message/35361727/ &lt;br /&gt;
  |title  =  &amp;lt;nowiki&amp;gt; Re: [Flightgear-devel] Subject: Re: Maldives, once again ;) &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |author =  &amp;lt;nowiki&amp;gt; Thorsten Renk &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |date   =  Sep 11th, 2016 &lt;br /&gt;
  |added  =  Sep 11th, 2016 &lt;br /&gt;
  |script_version = 0.40 &lt;br /&gt;
  }}&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Regarding the 2016.3.1 RC I've noticed that initialiing subsystems takes a lot longer than in earlier versions of flightgear(1 minute or more compatred to 10 or 15 seconds).&amp;lt;ref&amp;gt;{{cite web&lt;br /&gt;
  |url    =  https://sourceforge.net/p/flightgear/mailman/message/35362429/ &lt;br /&gt;
  |title  =  &amp;lt;nowiki&amp;gt; [Flightgear-devel] Boeing 777-200 taking a lot longer during&lt;br /&gt;
 initializing subsystems in flightgear 2016.3.1 RC &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |author =  &amp;lt;nowiki&amp;gt; Mihajlo Tomic &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |date   =  Sep 11th, 2016 &lt;br /&gt;
  |added  =  Sep 11th, 2016 &lt;br /&gt;
  |script_version = 0.40 &lt;br /&gt;
  }}&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* We should probably download a new catalog for each new version upon installation or first run, or at least check the date. I had an out of data catalogue and had to refresh manually.&amp;lt;ref&amp;gt;{{cite web&lt;br /&gt;
  |url    =  https://sourceforge.net/p/flightgear/mailman/message/35362096/ &lt;br /&gt;
  |title  =  &amp;lt;nowiki&amp;gt; Re: [Flightgear-devel] Release-Candidate 2016.3.1 ready for testing &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |author =  &amp;lt;nowiki&amp;gt; Richard Harrison &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |date   =  Sep 11th, 2016 &lt;br /&gt;
  |added  =  Sep 11th, 2016 &lt;br /&gt;
  |script_version = 0.40 &lt;br /&gt;
  }}&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Are there any remaining changes required to use the new default aircraft catalog: http://mirrors.ibiblio.org/flightgear/ftp/Aircraft/catalog.xml &amp;lt;ref&amp;gt;{{cite web&lt;br /&gt;
  |url    =  https://sourceforge.net/p/flightgear/mailman/message/35352712/ &lt;br /&gt;
  |title  =  &amp;lt;nowiki&amp;gt; Re: [Flightgear-devel] Release process 2016.3.1 &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |author =  &amp;lt;nowiki&amp;gt; Curtis Olson &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |date   =  Sep 7th, 2016 &lt;br /&gt;
  |added  =  Sep 7th, 2016 &lt;br /&gt;
  |script_version = 0.40 &lt;br /&gt;
  }}&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* The whole &amp;quot;navdb build thing&amp;quot; &amp;lt;ref&amp;gt;{{cite web&lt;br /&gt;
  |url    =  {{forum url|p=293163}}&lt;br /&gt;
  |title  =  &amp;lt;nowiki&amp;gt; Sqlite errror &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |author =  &amp;lt;nowiki&amp;gt; WAZZA &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |date   =  Aug 26th, 2016 &lt;br /&gt;
  |added  =  Aug 26th, 2016 &lt;br /&gt;
  |script_version = 0.40 &lt;br /&gt;
  }}&amp;lt;/ref&amp;gt; is proving to be the single most problematic feature added in the last couple of years affecting potentially all users, because unlike most additions, it's not an optional thing, i.e. it must be executed, and is needed for FG to work - given that, it would really make sense exploring to ship a pre-built navdb with future FlightGear releases, or at least factor out the corresponding code so that it can be provided as a standalone executable that is shipped as part of fgfs, so that it can be executed by the installer, without fgfs being affected by it inevitably - that way, troubleshooting related issues should also become much easier, in addition, this separation would facilitate having sync'ed navdbs across multiple instances (think virtual ATC, multiplayer, combat simulation, or even just a fsweekend/linuxTag-like setup). This work would also greatly facilitate turning the navdb into a HLA/IPC-enabled service one day.&amp;lt;ref&amp;gt;{{cite web&lt;br /&gt;
  |url    =  {{forum url|p=293128}}&lt;br /&gt;
  |title  =  &amp;lt;nowiki&amp;gt; Re: takes a long time to open &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |author =  &amp;lt;nowiki&amp;gt; Hooray &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |date   =  Aug 25th, 2016 &lt;br /&gt;
  |added  =  Aug 25th, 2016 &lt;br /&gt;
  |script_version = 0.40 &lt;br /&gt;
  }}&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* would it be possible (for the next release) to put startup defaults/properties in a startup-preferences.xml file and include it in preferences.xml. That would probably make it slightly easier to maintain and may be a start for an automatic update script which automatically generates startup-preferences.xml&amp;lt;ref&amp;gt;{{cite web&lt;br /&gt;
  |url    =  https://sourceforge.net/p/flightgear/mailman/message/35264900/ &lt;br /&gt;
  |title  =  &amp;lt;nowiki&amp;gt; Re: [Flightgear-devel] [Flightgear-commitlogs] [FGData] branch next&lt;br /&gt;
 updated: presets for new default airport SBRJ &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |author =  &amp;lt;nowiki&amp;gt; Erik Hofman &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |date   =  Aug 6th, 2016 &lt;br /&gt;
  |added  =  Aug 6th, 2016 &lt;br /&gt;
  |script_version = 0.40 &lt;br /&gt;
  }}&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2016.2 ==&lt;br /&gt;
=== Catalogs ===&lt;br /&gt;
* We need to come up with a solution that doesn’t require me to remember to make a new symlink every time the version number changes&amp;lt;ref&amp;gt;{{cite web&lt;br /&gt;
  |url    =  https://sourceforge.net/p/flightgear/mailman/message/35104912/ &lt;br /&gt;
  |title  =  &amp;lt;nowiki&amp;gt; Re: [Flightgear-devel] 2016.2.1 Catalog &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |author =  &amp;lt;nowiki&amp;gt; James Turner &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |date   =  May 21st, 2016 &lt;br /&gt;
  |added  =  May 21st, 2016 &lt;br /&gt;
  |script_version = 0.40 &lt;br /&gt;
  }}&amp;lt;/ref&amp;gt;, i.e. have a script that checks the version file in fgdata... when that file changes, the catalog symlink is created... if needed also add a new version tag to the catalog file... looking at the current version strings, we're apparently good to go until 2017... which fgdata to look at? perhaps the one that jenkins builds  for the release packages? if the symlink already exists, of course do nothing...&lt;br /&gt;
&lt;br /&gt;
=== Model Organization ===&lt;br /&gt;
We need to find a better way of organiing models for one of the following releases.&amp;lt;ref&amp;gt;{{cite web&lt;br /&gt;
  |url    =  https://sourceforge.net/p/flightgear/mailman/message/35075151/ &lt;br /&gt;
  |title  =  &amp;lt;nowiki&amp;gt; Re: [Flightgear-devel] Missing objects - WAS: [Final call for&lt;br /&gt;
 2016.1.1 &amp;quot;Barcelona&amp;quot; release] &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |author =  &amp;lt;nowiki&amp;gt; Torsten Dreyer &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |date   =  May 9th, 2016 &lt;br /&gt;
  |added  =  May 9th, 2016 &lt;br /&gt;
  |script_version = 0.39 &lt;br /&gt;
  }}&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The status which prompted the change was that we had two databases for models - FGData and Scenemodels. At the same time, we had four (at least) use cases for models - static scenery models, shared scenery models, random object models and common models referenced by aircraft. And everything got mixed up somehow.&amp;lt;ref&amp;gt;{{cite web&lt;br /&gt;
  |url    =  https://sourceforge.net/p/flightgear/mailman/message/35075962/ &lt;br /&gt;
  |title  =  &amp;lt;nowiki&amp;gt; Re: [Flightgear-devel] Missing objects - WAS: [Final call for&lt;br /&gt;
 2016.1.1 &amp;quot;Barcelona&amp;quot; release] &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |author =  &amp;lt;nowiki&amp;gt; Thorsten Renk &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |date   =  May 10th, 2016 &lt;br /&gt;
  |added  =  May 10th, 2016 &lt;br /&gt;
  |script_version = 0.39 &lt;br /&gt;
  }}&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2016.1 == &lt;br /&gt;
=== Codenames &amp;amp; Standard Airports ===&lt;br /&gt;
{{Main article|FlightGear Versioning Scheme based on Airports}}&lt;br /&gt;
* {{forum url|p=11381}}&lt;br /&gt;
* {{forum url|p=244430|hilit=ksfo+default+release}}&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= part of the discussion was also that the release will be known as 'San Francisco' for the default airport. And that we will change the default airport (and the name) for subsequent releases.&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34837768/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] i think 2016.x.x is a bad name&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Thorsten Renk&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Feb 10th, 2016&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= I feel Gatwick would be a nice place for a start. Schipol, though nice, would negatively disturb Omega's professional ATC. Maiquetia is certainly the most detailed airport in South America, in terms of detail; it is pretty nicely modeled by viveFG. Of course, I wouldn't be too happy about '' my airport '' being full of KSFO people, but then, it would be a nice showcase of what can be done in Blender and WED, as well as Gilberto's beautiful textures. For Asia, Kansai Intl promises to be very nice, but it would be better to wait till at least August, due to the Japan Festival in May. For North America... hmmm... LAX is always there; then there is JFK. The JFK terminal and layout could possibly use some updating; at least, Terminal 4 is incorrect, and I believe some newer taxiways are missing.&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34743914/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] Release preparations&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;legoboyvdlp&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Jan 6th, 2016&lt;br /&gt;
  | added   = Jan 6th, 2016&lt;br /&gt;
  | script_version = 0.23&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= Given the international flavour of our community, I'd suggest somewhere outside of North America for this release, but probably not Frankfurt or one of the airports that regularly hosts serious ATC services. I'm not particularly familiar with what airports have been developed, so I don't have a suggestion to make. A couple of related questions: 1) I assume we are going to include scenery for the selected airport within the release package? 2) The Cessna in-sim tutorials and the cross-country tutorial in The Manual are based around KSFO. Would we want to continue so ship some KSFO scenery with the release to avoid users having to download those areas?&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34746309/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;[Flightgear-devel] Airport Choice for 2016.2 (was Re: Release&lt;br /&gt;
	preparations)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Stuart Buchanan&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Jan 7th, 2016&lt;br /&gt;
  | added   = Jan 7th, 2016&lt;br /&gt;
  | script_version = 0.23&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= To have enough time to prepare this, I'd like to make our first release the &amp;quot;San Francisco&amp;quot; edition.&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34744027/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] Release preparations&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Torsten Dreyer&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Jan 6th, 2016&lt;br /&gt;
  | added   = Jan 6th, 2016&lt;br /&gt;
  | script_version = 0.23&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= This is definitely becoming one of the most completely modeled locations in FlightGear, guess we should seriously consider making it the default startup location for the next release&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = {{forum url|p=104646}}&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: LOWI airport&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Hooray&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Dec 4th, 2010&lt;br /&gt;
  | added   = Dec 4th, 2010&lt;br /&gt;
  | script_version = 0.23&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= I'm just curious, any significance to using KSFO as a default airport starting or it's just chosen at random? &lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = {{forum url|p=244384}}&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Reason for &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;HJ1AN&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = May 26th, 2015&lt;br /&gt;
  | added   = May 26th, 2015&lt;br /&gt;
  | script_version = 0.23&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= &amp;lt;nowiki&amp;gt;I proposed to rotate the default airport each major release to give other airports some exposure. Hence we could use the corresponding airport name as the release name, i.e: 2016.1 ‘Gatwick’ 2016.2 ‘Innsbruck’ 2017.1 ‘Finkenwerder’ 2017.2 ’Schiphol’ .. and so on .. I’m not suggesting to implement this change for 2016.1 of course - it needs some tooling changes to adjust the default scenery which is non-trivial. And no one really seemed that interested last time, so perhaps I am the only person who likes this idea anyway!&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34706595/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] Relesae 3.8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;James Turner&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Dec 19th, 2015&lt;br /&gt;
  | added   = Dec 19th, 2015&lt;br /&gt;
  | script_version = 0.23&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= I second that. Over the years FG has seen some pretty dedicated scenery builders at work. It would honor their steady effort to create these great alternatives to KSFO. &lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34706676/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] Relesae 3.8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Frans de Vre&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Dec 19th, 2015&lt;br /&gt;
  | added   = Dec 19th, 2015&lt;br /&gt;
  | script_version = 0.23&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= &amp;lt;nowiki&amp;gt;+1 on this idea. It nicely addresses several issues.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34706693/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] Relesae 3.8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Gary Neely&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Dec 19th, 2015&lt;br /&gt;
  | added   = Dec 19th, 2015&lt;br /&gt;
  | script_version = 0.23&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= do like the idea of rotating the default airport and the code naming the release with that airport name. That's pretty clever and cool I think.&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34706606/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] Relesae 3.8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Curtis Olson&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Dec 19th, 2015&lt;br /&gt;
  | added   = Dec 19th, 2015&lt;br /&gt;
  | script_version = 0.23&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= It is a cool idea and I think more than a few people liked it last time - the stumbling blocks I remember were the fact that the manual (TM) specifically assumes that you're at KSFO and would have to be re-written - and that it was close to impossible to agree on an airport for us :-)&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34706903/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] Release 3.8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Thorsten Renk&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Dec 19th, 2015&lt;br /&gt;
  | added   = Dec 19th, 2015&lt;br /&gt;
  | script_version = 0.23&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= Yes, that is a neat idea. I suggest to make a 2016.1.1 'San Franciso' in January and start a poll for the location of 2016.2.1. One little detail question: What's the number of the first version in a year? Do we count geek-style/ero-based or natural/one-based (2016.0.1 or 2016.1.1)? I have a tiny tendency towards one-based to start with 2016.1.1 for the release and make current 'next' v2016.0.0.&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34710782/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] Release 3.8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Torsten Dreyer&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Dec 21st, 2015&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== 3.6 ==&lt;br /&gt;
=== ChangeLog automation ===&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= There are two manual steps that I usually perform: 1) Generating the latest version of the manual 2) Writing the release note Frankly, updates to the Manual are currently limited to checking that all the menu items are described and incrementing the version number. The latter could be automated by Jenkins I suspect. Writing the release note isn't a massive amount of work, and given that there will be 3 months of logs to check rather than 6, should be a bit less work per-release.&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34631381/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] Some thoughts about the release process&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Stuart Buchanan&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Nov 19th, 2015&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= For the release notes - well, we could prepare some prettyfied git-log if that helps.&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34634440/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] Some thoughts about the release process&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Torsten Dreyer&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Nov 20th, 2015&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Jenkins (build server) ===&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= Could we have Jenkins continue to build from the release branch after the release is made and copy those to SourceForge as well? That would allow us to easily deliver critical fixes found in a release. &lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34631381/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] Some thoughts about the release process&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Stuart Buchanan&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Nov 19th, 2015&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= Jenkins will do the release-number handling anyway. Probably we can just include the version file into the latex compile process?&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34634440/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] Some thoughts about the release process&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Torsten Dreyer&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Nov 20th, 2015&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Review &amp;amp; optimize the release plan ? ===&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= You're basically advocating offloading much of the testing to the broad public. In the short term, I agree this is likely to increases the total manpower behind the project. However, it's equally clear that it will decrease release quality - short term at least.&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34631380/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] Some thoughts about the release process&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Markus Wanner&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Nov 19th, 2015&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= My personal experience with relaxed release processes is rather negative. And I don't think release-early-release-often means one shouldn't differentiate between releases of different quality (i.e. beta, RCs, stable). But then again, I'm a Debian Developer. I'm clearly biased.&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34631380/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] Some thoughts about the release process&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Markus Wanner&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Nov 19th, 2015&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= I can barely keep up packaging two releases per year for Debian. I certainly can't do four. So I'd have to decide which ones to pick.[...]I'd appreciate fewer releases with higher quality, rather than the opposite.&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34631284/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] Some thoughts about the release process&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Markus Wanner&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Nov 19th, 2015&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= When we started the release plan, I had much time during summer/winter holidays. If I had to do it again, I would have avoided thoses seasons.&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34631277/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] Some thoughts about the release process&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Torsten Dreyer&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Nov 19th, 2015&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= &amp;quot;Release early, release often&amp;quot; is result of other peoples experience and so is the idea behind &amp;quot;Agile&amp;quot; development where you create something potentially deliverable every 2 weeks. To be honest, I was even thinking about having monthly releases. Given the relative low number of contributors at the moment, I just expected that we'd create subsequent releases with no change but the version number.&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34631277/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] Some thoughts about the release process&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Torsten Dreyer&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Nov 19th, 2015&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= The major flaws I've perceived in the release processes I have witnessed are a) release candidates came out too late, giving barely a week of testing and feedback, not enough time to do fixing b) users not adopting and testing the release candidate with the argument that they'd 'wait for the stable version' c) real life of many people (especially during summer holidays) interfering with the ability to deal with bug reports&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34631200/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] Some thoughts about the release process&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Thorsten Renk&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Nov 19th, 2015&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= one of the things we've encountered in past release cycles is that it seems like it takes some extra effort (James?) to configure Jenkins to do release candidate builds, and because of that we often haven't had release candidates until very late (i.e. days before the official release, sometimes after.) But if Jenkins can automatically build release candidates, that would be wonderful.&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34627418/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] Some thoughts about the release process&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Curtis Olson&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Nov 17th, 2015&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= Today, thanks to James, Clement and Gene, we have Jenkins that basically creates a complete release after every commit in our source repository. Because of this and because human resources have become more precious than ever, I'd like to discuss a new release plan for FlightGear here.&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34627074/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;[Flightgear-devel] Some thoughts about the release process&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Torsten Dreyer&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Nov 17th, 2015&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= The steps required to release a software product are usually quite intense and take a -lot- of time.  There were also Northern hemisphere holiday related delays.  The release process is ongoing, but patience is required&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = {{forum url|p=256506}}&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: FlightGear 3.4/5/6/7 - please help me understand&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;bugman&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Sep 8th, 2015&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= Because creating a release requires that certain people do certain things and that the last show-stopper bugs (e.g. is the Mac build ok now? The Windows build?) have been solved. All by a small number of people (some quite non-interchangeable due to limited access to certain resources) working on their spare time.&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = {{forum url|p=256513}}&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: FlightGear 3.4/5/6/7 - please help me understand&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;AndersG&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Sep 8th, 2015&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= there is currently no defined status of 3.6 due to lack of (human) resources. Some of us have thought about refactoring the release schedule due to the fact that a freee around christmas and a release during summer holidays is very unfortunate. So far, there are no clear results from these thoughts available. The entire process is somewhat volatile at the moment. Sorry for any inconvenience that may cause.&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34606005/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] Status of Release 3.6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Torsten Dreyer&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Nov 9th, 2015&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote|1= I just know from other conversations that quite a few people are on holiday. I guess we'll just have to wait. Maybe trying to do a summer release is a bit awkward in the first place and we should reconsider the idea? |2= {{cite web  | url    = http://sourceforge.net/p/flightgear/mailman/message/34402855/  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] FGAddon freeze for 3.6?&amp;lt;/nowiki&amp;gt;  | author = &amp;lt;nowiki&amp;gt;Renk, Thorsten&amp;lt;/nowiki&amp;gt;  | date   = Aug 25th, 2015  }}}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= In general, I see there being two fundamental approaches for the approach to the release. First, time based. Target a date and taint that date with a realistic set of hoped for features, what is ready is what is ready. What is not, slips to the next release. Second, feature based. Target a set of features, allowing it to be tainted with a reasonably realistic date. When the features are complete, the release is made. Which is preferred approach for those on the list? Can I suggest a wiki page to provide a focus for burning down issues prior to the release?&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/20544310/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;[Flightgear-devel] Towards a release - Re: Revision Log / Intended&lt;br /&gt;
 developments&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Matthew Tippett&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Oct 13th, 2008&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Code names instead of version numbers? ===&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= What happened to the idea of naming releases after an airport/a scenery? I rather liked that &lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34742832/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] Release preparations&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Thorsten Renk&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Jan 6th, 2016&lt;br /&gt;
  | added   = Jan 6th, 2016&lt;br /&gt;
  | script_version = 0.23&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= Just a cray random thought, perhaps, like many other software we could add a codename for each release. It could be a just-for-fun thing, or you could think of it as a way to divert the attention away from the version number, just in case you don't like the number.&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/15646733/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] Informal version number poll&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Pigeon&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Nov 30th, 2007&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= People also seem to assign expectations to a product based on the way it's version number looks.  Commercial companies realie this and try to leverage it to a competitive advantage (my version number is higher or better than your version number!)  FlightGear doesn't compete commercially so we don't have to play dumb psychological games with consumers -- we could, we just don't have to if we don't want to.&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = {{forum url|p=178351}}&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: the way each version is numbered is confusing&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;curt&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Feb 27th, 2013&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= the accomplishment of switching from 1.x to 2.x and to 3.x still does mean something to many people, not just FG &amp;quot;outsiders&amp;quot; (or new users), but also long-term contributors, as was mentioned by Torsten on the devel list:&lt;br /&gt;
http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg38888.html&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = {{forum url|p=178353}}&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: the way each version is numbered is confusing&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Hooray&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Feb 27th, 2013&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= why not call it flightgear 2013.... and flightgear 2014 ?&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = {{forum url|p=186390}}&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: Clouds&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Bomber&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Jul 7th, 2013&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= the whole major/minor concept is clearly irritating to people not familiar with software development and labeling schemes, which is why software is often versioned using code names or simply years: '''FlightGear 2013-1''' or '''FlightGear 2013-2''', '''FlightGear 2013-ALPHA''' or '''FlightGear 2013-BRAVO'''&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = {{forum url|p=178334}}&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: the way each version is numbered is confusing&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Hooray&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Feb 27th, 2013&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= Ultimately, it probably isn't worth the hassle - and we should identify the whole scheme as a bottleneck and come up with something less prone to interpretation and subjective opinions, i.e. having releases in the form of &amp;quot;FlightGear 2013/1&amp;quot; or &amp;quot;FlightGear 2013/2&amp;quot; - or even just code names.&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = {{forum url|p=185619}}&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;to put things into perspective ...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Hooray&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Jun 23rd, 2013&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= &amp;quot;first impressions&amp;quot; would be hugely different if we were to start an orchestrated effort to bundle our most-developed features (aircraft, scenery, addons) together, instead of offering an infinite number of more or less developed options to our end-users.&lt;br /&gt;
We have some extremely well-developed aircraft and scenery, such as the Seneca, the 777 - France, LOWI. It would just be a matter of packaging these as &amp;quot;positive examples&amp;quot; for a release - even if that would just be a downstripped &amp;quot;preview&amp;quot; release, it would go a long way to demonstrate what FG is capable of: &lt;br /&gt;
{{forum link|p=170522|title=Help needed - market research for FG}}&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = {{forum url|p=175192}}&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: Help needed - market research for FG&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Hooray&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Jan 24th, 2013&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= in terms of making some of our more advanced aircraft/airports more prominent. I think I read about this on the wiki:&lt;br /&gt;
&lt;br /&gt;
For instance, we are currently having two releases per year. But we've been using KSFO/c172p as the standard startup settings for many years.&lt;br /&gt;
&lt;br /&gt;
Personally, I would think that it would be a great incentive for aircraft and scenery developers if we could have polls prior to each release phase to determine which airport/aircraft is going to be the defaults for the next release.&lt;br /&gt;
For example, just look at all the fantastic work done for LOWI - or amaing aircraft like the Seneca.&lt;br /&gt;
&lt;br /&gt;
I could imagine we could make such work more prominent by changing the defaults for each release accordingly.&lt;br /&gt;
&lt;br /&gt;
And we could then also change our release naming accordingl: FlightGear 3.2 (LOWI/Seneca)&lt;br /&gt;
That would go a long way to demonstrate to NEW users that we really have AWESOME scenery and extremely well-developed airports.&lt;br /&gt;
&lt;br /&gt;
The current situation works such that only the &amp;quot;insiders&amp;quot; know about such things, and know how to download/install/configure everything.&lt;br /&gt;
&lt;br /&gt;
And the screen shot competitions that we've had also demonstrate that we have an active community interested in contributing to polls.&lt;br /&gt;
&lt;br /&gt;
So why not use polls AFTER each release to directly determine which aircraft/airport will be featured in the upcoming release?&lt;br /&gt;
&lt;br /&gt;
That would give us plenty of time to focus on the corresponding scenery/aircraft, and to give other contributors a chance to even improve things further.&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = {{forum url|p=170522}}&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: Help needed - market research for FG&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Hooray&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Nov 13th, 2012&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Scenery versioning ===&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= It is a bit of a mess, Martin had his own way of doing things and didn't really seem to care about or pay attention to the FlightGear release cycle so our numbers got out of sync. I can try to take a look at this over the weekend....&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34565300/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] Scenery versioning&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Curtis Olson&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Oct 23rd, 2015&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= I'm thinking with things the way they are, pages created and databases mirrored around the world it might be clever after the rebuild of the scenery that will replace the current 2.0 scenery, to go back to the version-of-FG numbers, simply because, like said the enormous work of the past and because that number will always be linked to when the scenery was/is created. I understand that simgear and flightgear are sync'd in such a maner.&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34569098/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] Scenery versioning&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Ray St. Marie&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Oct 26th, 2015&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= unlike FG and SG which have strong dependencies (try compiling FG 3.7 against SG 2.12 and see what happens), the scenery-core dependency is much weaker - FG 3.7 will actually run fine with the scenery from 2.12 (that would be World Scenery 1.0.1 I guess). So there's no need to update the scenery version number when it really hasn't changed, and scenery versioning can reflect actual re-builds for clarity.&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34569211/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] Scenery versioning&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Thorsten Renk&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Oct 26th, 2015&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== 3.4 ==&lt;br /&gt;
=== PUI fonts affected by features using effects/shaders (Rembrandt/ALS) ===&lt;br /&gt;
{{Note|Also see {{Issue|1730}} }}&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |I notice that the first item in flightgear menus is missing if I use the property sim &amp;quot;--prop:/sim/rendering/multi-samples{{=}}3&amp;quot;,&lt;br /&gt;
  |{{cite web |url={{forum url|p=237489}}&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;Missing label menus if /rendering/multi-samples is enabled&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;Curtis&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;Wed Apr 01&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |This is something to do with the builtin bitmapped font and shaders as it affects me when I have either rembrandt or ALS turned on;&lt;br /&gt;
If you change the gui current style in either preferences or autosave to 0 it'll use a real font which fixes it mostly (there are still certain elements in the GUI such as MP Pilot list that use the builtin font)&lt;br /&gt;
  |{{cite web |url={{forum url|p=237617}}&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;Re: Missing label menus if /rendering/multi-samples is enabl&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;Richard&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;Thu Apr 02&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Scenery not loading ===&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |it just says &amp;quot;Loading Scenery&amp;quot; and doesnt load.&lt;br /&gt;
  |{{cite web |url={{forum url|p=234640}}&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;Why is my Flightgear still saying Loading Scenery?&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;JackT44&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;Mon Mar 09&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Selecting Parking Positions ===&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |not able to choose under menue Select an Airport /Aircraft Position /Parking&amp;lt;br/&amp;gt;&lt;br /&gt;
an exist Parkposition.&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
For example, select the airport EDDF. Under Aircraft Position you choose Parking positions. Set the cursor in the yellow case and you got the&amp;lt;br/&amp;gt;&lt;br /&gt;
announcement &amp;quot; Parking position not found &amp;quot;.&lt;br /&gt;
  |{{cite web |url={{forum url|p=234563}}&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;3.4. Selecting airports...Aircraft Position...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;D-ABBA&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;Sun Mar 08&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Qt5/Mac launcher debate ===&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |Related to Qt, I can say that up to now - as far as I can tell - only a simple replacement for the Mac Launcher has been introduced. This is not related to the internal user interface of FlightGear, at least for now. If, how and when the internal gui can leverage Qt is under investigation and in such an early state that those responsible preferred to not announce anything yet. If this ever happens, this will be discussed on the mailing list &lt;br /&gt;
  |{{cite web |url={{forum url|p=229563}}&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;Re: FlightGear GUI hell: PUI, Canvas GUI, Mongoose, &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;Torsten&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;Sun Jan 11&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Mid-term Project Goals? ===&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |Has FlightGear got a list of goals for 5-10 years? How about making or adding to it?&lt;br /&gt;
  |{{cite web |url={{forum url|p=229633}}&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;5-10 Year Goals?&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;legoboyvdlp&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;Tue Jan 13&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |One of my observations as an observer with just enough knowledge to understand the situation, from a distance, is that it would be extremely helpful for this project to come to some kind of a consensuses. This free-for-all is confusing and counter productive. Even if a few, or many, core developers know what is going on and are in lockstep, it is very disheartening to contemplate helping or contributing to anything &amp;quot;major&amp;quot; as you have the appearance of no consensuses. &lt;br /&gt;
I see advertisements for needed help everywhere I look, but many are not willing to spend significant time on anything that may be in vain.&lt;br /&gt;
  |{{cite web |url={{forum url|p=231383}}&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;Re: Aircraft center: &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;wlbragg&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;Thu Feb 05&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|Following on from the recent discussions about git/svn and attribution on the -devellist, and discussions about the structure and the future of the project on the forum, the group of developers who get together on a weekly Google Hangout organized by Curt realized that we would benefit from a more detailed policy document and roadmap than the high level statement available at [http://www.flightgear.org/about/ http://www.flightgear.org/about/].&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
There is a draft document circulating on the -devel list  ([http://sourceforge.net/p/flightgear/mailman/message/34183645/ http://sourceforge.net/p/flightgear/mailman/message/34183645/]).  If you'd like to comment and take part in the discussion, please subscriber to the -devel list&lt;br /&gt;
| {{cite web&lt;br /&gt;
  | url	= {{forum url|p=246162}}&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;FlightGear Policy and Roadmap Documents&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;stuart&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Jun 8th, 2015&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== FlightGear on 32 bit Windows ===&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |The point I am getting at is we have a ton of 32 bit windows users trying to download and run FlightGear.  Out of the box with the startup defaults that pretty much doesn't work right now.  This is leading to a ton of bug reports, a ton of frustrated new users, and a general perception that FlightGear is a POS that isn't worth messing with.&lt;br /&gt;
  |{{cite web |url=http://sourceforge.net/p/flightgear/mailman/message/33353889/&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] FlightGear on low (&amp;lt;=4GB) memory systems&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;Curtis Olson&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;2015-02-05&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== FileSelection on Windows hidden by fullscreen Window ===&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |In FG 3.4 (full screen mode) I wondered what happens when I try to set e.g. the '''Screenshot Directory''' ?&lt;br /&gt;
the new and nice designed Fileselection box is just not displayed, because it is hidden below the full screened FG main window ...&lt;br /&gt;
&lt;br /&gt;
  |{{cite web |url={{forum url|p=234056}}&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;FG 3.4 Windows: File Selection Box&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;mhab&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;Wed Mar 04&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== No LOD for aircraft previews in fgrun causing lag ===&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |Models (and liveries) take some time to load, if the model (livery,...) is very detailed, that time may be substantial. That's all there is to it. Just wait it out. (When I ask the launcher to get me a preview of the Vostok for instance, I get a 5 second freeze. Given the vertex count of the beast, I'm not surprised.)&lt;br /&gt;
(In principle, we could load a simplified 3d model in the launcher, but I doubt it would be worth the trouble asking people to provide that).&lt;br /&gt;
  |{{cite web |url={{forum url|p=227686}}&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;Re: Flight Gear not responding&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;Thorsten&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;Sun Dec 21&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Broken FGCom cleanup triggers crashrpt during process termination ===&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |Shut off FGcom, no more need to report constantly.&lt;br /&gt;
  |{{cite web |url={{forum url|p=232207}}&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;SOLVED: Re: FG3.2 wants to always send error report&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;clrCoda&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;Mon Feb 16&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}} &lt;br /&gt;
&lt;br /&gt;
=== repare_ground_cache(): scenery_available returns false ===&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |A fortunate coincidence, I have just experienced this, too and was able to&amp;lt;br/&amp;gt;&lt;br /&gt;
gather some logging.&lt;br /&gt;
  |{{cite web |url=http://sourceforge.net/p/flightgear/mailman/message/33555237/&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] prepare_ground_cache(): scenery_available&lt;br /&gt;
 returns false&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;Torsten Dreyer&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;2015-03-06&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Crash due to corrupt NavDB ===&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |at least on my 10.7 build, I’m seeing an issue with the nav-cache not initialising. This is actually good, because it gives me a way, finally, to trace down the ‘nav-cache never initialises’ bug that some folks have reported. But it will take a little time. Since the same binary works perfectly on my 10.10 box, I assume it’s something /very/ subtle, probably uninitialised memory or some tiny change in zlib’s gzread functions (since we use the system Zlib library which hence could be different between 10.7 and 10.10).&lt;br /&gt;
  |{{cite web |url=http://sourceforge.net/p/flightgear/mailman/message/33457470/&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] Release 3.4.0 is coming&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;James Turner&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;2015-02-18&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |Is this a fresh &amp;quot;clean&amp;quot; install or are you installing it after 3.2?&amp;lt;br/&amp;gt;&lt;br /&gt;
If after 3.2 try renaming &amp;lt;br/&amp;gt;&lt;br /&gt;
C:\Users\USERNAME\AppData\Roaming\flightgear.org to C:\Users\USERNAME\AppData\Roaming\flightgear.BAK&amp;lt;br/&amp;gt;&lt;br /&gt;
Then restart FG and let it rebuild all cache. You will have to setup your configuration again.&lt;br /&gt;
  |{{cite web |url={{forum url|p=232502}}&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;Re: 3.4 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;wlbragg&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;Thu Feb 19&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |there's currently a bug in FG 3.2 (under investigation) that makes the simulator crash when you upgrade from FG 3.0 to 3.2, and it seems FG 3.2 crashes even before writing to the log.&lt;br /&gt;
  |{{cite web |url={{forum url|p=228177}}&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;Re: Problems getting FG running&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;elgaton&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;Fri Dec 26&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Instant Crashes ===&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |FlightGear 3.4.0 Fails after initializing subsystems and then I received a crash report&amp;lt;br/&amp;gt;&lt;br /&gt;
with other data.&amp;lt;br/&amp;gt;&lt;br /&gt;
3.4.0 RC1 and 2 also failed&lt;br /&gt;
  |{{cite web |url={{forum url|p=232565}}&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;FlightGear 3.4.0 Fails after initializing subsystems&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;matt1717don&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;Thu Feb 19&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |It gets to &amp;quot;Loading Navigation (something)&amp;quot; then crashes. As opposed to, essentially, flashing up for a split second like it does with Terrasync enabled.&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
EDIT: With the minimal startup profile -&amp;amp;gt; still crashes!&lt;br /&gt;
  |{{cite web |url={{forum url|p=233363}}&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;Re: 3.4.0 instantly crashes&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;Figaro&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;Fri Feb 27&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Route Manager Crash/freezing ===&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |The only problem is that the route manager crash every time I want to open it. Thats the same problem I had with FG 3.2&lt;br /&gt;
  |{{cite web |url={{forum url|p=234167}}&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;Re: Flightgear 3.4 on Yosemite&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;Niki&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;Thu Mar 05&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |I have problems with route manager, fg just freezes every time I try to use route manager. On every aircraft&lt;br /&gt;
  |{{cite web |url={{forum url|p=237179}}&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt; &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;VladimirZ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;Sun Mar 29&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Multithreading Issue ===&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |Looks like a multi threading issue to me. When I run FlightGear with multiple screens and multiple cameras, the highes threading mode for OpenSceneGraph that works reliable is '''CullDrawThreadPerContext''' while the '''CullThreadPerCameraDrawThreadPerContext''' quickly leads to a crash.&lt;br /&gt;
  |{{cite web |url={{forum url|p=228282}}&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;Re: Error when trying to run FlightGear with three monitors&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;Torsten&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;Sun Dec 28&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Intel GPU Support ===&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |Has any dev tried to disable their nvidia card and use their built-in intel GPU for once?&lt;br /&gt;
  |{{cite web |url={{forum url|p=218382}}&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;Re: 3.2rc1 Overall impression&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;onox&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;Sat Sep 13&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== More widespread testing ===&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |We could be using our most talented, experience sim pilots to produce more of the necessary tests during release candidates rather than after release. &amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
There has to be a way to have a stable release AND a testing suite of the release candidate that co-exist in order to be the helpers we would like to be. &lt;br /&gt;
  |{{cite web |url={{forum url|p=231852}}&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;Re: RC 3.4&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;clrCoda&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;Wed Feb 11&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |ideally, people doing such flights regularly would provide a corresponding &amp;quot;fgtape&amp;quot; file using a standard aircraft and get this committed to $FG_ROOT into some kind of &amp;quot;Tests&amp;quot; directory containing pre-recorded flights for doing regression testing in an automated fashion. The thing to keep in mind here is that those among us able (and willing) to troubleshoot such issues are most unlikely to ever actually use FlightGear like this, which certainly includes Zakalawe. Thorsten recently also mentioned that he'll typically just start up FlightGear a few dozen of times using a simple aircraft to test things, without really doing any &amp;quot;real&amp;quot; flying at all. So there are certainly a number  of use-cases that aren't getting much attention unfortunately.&amp;lt;br/&amp;gt;&lt;br /&gt;
Which is why it would be a good idea for  people to provide flight recorder tapes covering use-cases they care about, and get those committed to fgroot (fgdata) - so that we can grow a library of useful flights to do regression testing - as long as those flights are using standard aircraft and features, they should also be useful for people entirely new to FlightGear.&lt;br /&gt;
  |{{cite web |url={{forum url|p=233211}}&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;Re: 3.4 and the pain begins ...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;Hooray&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;Thu Feb 26&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== legacy GUI Z-ordering issue (PUI) ===&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |if i have the radio dialogue (F12) and the map dialogue (CTRL-M) open with one overlapping the other, when i release my left mouse button on the top dialogue in a position over a portion of the lower dialogue, the lower one will pop to the top&lt;br /&gt;
  |{{cite web |url={{forum url|p=233315}}&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;GUI dialog box Z-ordering&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;wkitty42&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;Thu Feb 26&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |Dialog z-ordering (fighting?) is my biggest annoyance with the current GUI&lt;br /&gt;
  |{{cite web |url={{forum url|p=233595}}&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;Re: GUI dialog box Z-ordering&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;Johan G&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;Sun Mar 01&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== ALS impact on PUI styles for ATI/AMD cards ===&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |There are a lot topics concerning AMD graphic cards with flickering problems, but that seems not to match with the issue i have. Maybe there is someone who has or had the same problem and could solve it.&lt;br /&gt;
  |{{cite web |url={{forum url|p=234492}}&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;No Text displayed when using ALS&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;Solid&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;Sun Mar 08&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |When I use either of Rembrandt or Atmospheric Light Scattering, some of the text in the menus disappear, with various bits of text disappearing then reappearing every second&lt;br /&gt;
  |{{cite web |url={{forum url|p=201328}}&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;Corrupt textures when using Rembrandt or ALS&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;Stevy&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;Thu Feb 20&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |n the HUD (windows, menus), labels tend to be clipped. You can see this, on the previous image, in the rendering options window.&amp;lt;br/&amp;gt;&lt;br /&gt;
And that's more visible when I enable the atmospheric light scattering&lt;br /&gt;
  |{{cite web |url={{forum url|p=202508}}&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;Flightgear doesn't use 100% of the workload and Fonts bug&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;Saga&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;Tue Mar 04&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |I've succeed to partially circumvent the problem (not solved it). Menu, windows are displayed well unlike labels directly displayed on the screen like &amp;quot;Airspeed exceed vne&amp;quot;. You must change the style of the gui in data/preferences.xml&lt;br /&gt;
  |{{cite web |url={{forum url|p=207870}}&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;Re: Flightgear doesn't use 100% of the workload and GUI clip&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;Saga&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;Fri May 02&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |JUST CHANGE THE 1 to a 2 in&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
/FGROOT/preferences.xml&lt;br /&gt;
  |{{cite web |url={{forum url|p=218196}}&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;For people with amd graphics &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;cain071546&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;Wed Sep 10&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |the fact to just change the font seems to solve the bug (just for some labels). I've spotted a font which don't provoke it (lucida.txf)&lt;br /&gt;
  |{{cite web |url={{forum url|p=212615}}&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;Re: Flightgear doesn't use 100% of the workload and GUI clip&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;Saga&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;Sun Jun 15&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
 &lt;br /&gt;
=== Release Schedule ===&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |I cannot guarantee for this to be the case in the future, nor is it even likely to happen again. Thus, if the release cycles of Ubuntu and FlightGear stays the same, I fear the next newest FlightGear won't make it into the newest Ubuntu release.&lt;br /&gt;
  |{{cite web |url=http://sourceforge.net/p/flightgear/mailman/message/33458290/&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] Release 3.4.0 is coming&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;Markus Wanner&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;2015-02-18&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}} &lt;br /&gt;
&lt;br /&gt;
=== Updating &amp;quot;Catalog Metadata&amp;quot; version, vars and data paths ===&lt;br /&gt;
Something that appears to have fallen through the cracks is the Experimental Aircraft Center Catalog creation and version update. Need to implement some automatic feature to handle these type of routine version updates.&lt;br /&gt;
&lt;br /&gt;
=== Windows: Installer Issues ===&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |Today I installed FlightGear on a 32 bit windows laptop that had an&amp;lt;br/&amp;gt;&lt;br /&gt;
existing v3.2 install already loaded.  I ran into several issues that I&amp;lt;br/&amp;gt;&lt;br /&gt;
would consider suboptimal and so I'm posting them here for discussion and&amp;lt;br/&amp;gt;&lt;br /&gt;
possible improvement.&lt;br /&gt;
  |{{cite web |url=http://sourceforge.net/p/flightgear/mailman/message/33348310/&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;[Flightgear-devel] FlightGear 3.4 RC1 (Windows) feedback&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;Curtis Olson&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;2015-02-04&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |The installer came up and wanted to install FlightGear-3.4.0 into&amp;lt;br/&amp;gt;&lt;br /&gt;
FlightGear-3.2.0's folder.  I had to manually switch this to&amp;lt;br/&amp;gt;&lt;br /&gt;
FlightGear-3.4.0.  I don't think it should work like this, should it?  If&amp;lt;br/&amp;gt;&lt;br /&gt;
we are going to install into FlightGear-v&amp;lt;anything&amp;gt; shouldn't we make sure&amp;lt;br/&amp;gt;&lt;br /&gt;
it's the right number?&lt;br /&gt;
  |{{cite web |url=http://sourceforge.net/p/flightgear/mailman/message/33348310/&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;[Flightgear-devel] FlightGear 3.4 RC1 (Windows) feedback&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;Curtis Olson&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;2015-02-04&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  | If I don't choose any aircraft at all, the default comes up as the C172&amp;lt;br/&amp;gt;&lt;br /&gt;
with a 2D panel.  Again is that really what we want?  Is it time to&amp;lt;br/&amp;gt;&lt;br /&gt;
deprecate the 2d panel version?  Also the way the launcher window is&amp;lt;br/&amp;gt;&lt;br /&gt;
constructed, the information saying this is a 2d panel version is off the&amp;lt;br/&amp;gt;&lt;br /&gt;
screen so had to go to the bottom and scroll side to side to see it.  I&amp;lt;br/&amp;gt;&lt;br /&gt;
imagine a lot of first time users wouldn't think or know to do this?&lt;br /&gt;
  |{{cite web |url=http://sourceforge.net/p/flightgear/mailman/message/33348310/&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;[Flightgear-devel] FlightGear 3.4 RC1 (Windows) feedback&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;Curtis Olson&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;2015-02-04&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |Again, without selecting any airport, the launcher chose 17CL for me&amp;lt;br/&amp;gt;&lt;br /&gt;
which is some random little bitty strip I don't even know where.  Wouldn't&amp;lt;br/&amp;gt;&lt;br /&gt;
we want to start in SFO?  Wasn't that always our intent?&lt;br /&gt;
  |{{cite web |url=http://sourceforge.net/p/flightgear/mailman/message/33348310/&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;[Flightgear-devel] FlightGear 3.4 RC1 (Windows) feedback&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;Curtis Olson&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;2015-02-04&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |FlightGear 3.4 is essentially unusable on a 32 bit windows system&amp;lt;br/&amp;gt;&lt;br /&gt;
outside of very remote/simple areas with no scenery.  Should we consider&amp;lt;br/&amp;gt;&lt;br /&gt;
seeing if we can just abort the installer on a 32 bit system and quit&amp;lt;br/&amp;gt;&lt;br /&gt;
pretending like maybe it should work?  It just doesn't so we could save&amp;lt;br/&amp;gt;&lt;br /&gt;
users with 32 bit systems a whole lot of time if we just bail out of the&amp;lt;br/&amp;gt;&lt;br /&gt;
installer.  Is there any reason we shouldn't at least list a 64 bit system&amp;lt;br/&amp;gt;&lt;br /&gt;
as a minimum requirement now for FlightGear?&lt;br /&gt;
  |{{cite web |url=http://sourceforge.net/p/flightgear/mailman/message/33348310/&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;[Flightgear-devel] FlightGear 3.4 RC1 (Windows) feedback&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;Curtis Olson&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;2015-02-04&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
  |I seem to recall that there was some work on reducing the memory footprint&amp;lt;br/&amp;gt;&lt;br /&gt;
of FlightGear.  Did any of those changes make it into the 3.4 branch?&lt;br /&gt;
  |{{cite web |url=http://sourceforge.net/p/flightgear/mailman/message/33348310/&lt;br /&gt;
     |title=&amp;lt;nowiki&amp;gt;[Flightgear-devel] FlightGear 3.4 RC1 (Windows) feedback&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |author=&amp;lt;nowiki&amp;gt;Curtis Olson&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     |date=&amp;lt;nowiki&amp;gt;2015-02-04&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Updating Dependencies ===&lt;br /&gt;
* Updating the SG/FG source trees for dependencies (JSBSim, OpenSceneGraph etc) should be done right at the beginning of the new release cycle, or at least be closely coordinated.&lt;br /&gt;
&lt;br /&gt;
=== Bugfix releases ===&lt;br /&gt;
* {{thumbs down}} In case a serious bug is found, there should be a process in place to create and distribute a bugfix release as soon as possible.&lt;br /&gt;
--[[User:Elgaton|Elgaton]] ([[User talk:Elgaton|talk]]) 05:31, 16 March 2015 (EDT)&lt;br /&gt;
&lt;br /&gt;
== 3.2 ==&lt;br /&gt;
* {{thumbs down}} The release should not be announced ''only'' on the main web page. It should also be announced on the following places:&lt;br /&gt;
** The official forum&lt;br /&gt;
** The developer list&lt;br /&gt;
** The newsletter&lt;br /&gt;
&lt;br /&gt;
: As things turned out this time around, most of our users seem unaware that a new version have been released.&lt;br /&gt;
&lt;br /&gt;
: —[[User:Johan G|Johan G]] ([[User_talk:Johan_G|Talk]] | [[Special:Contributions/Johan_G|contribs]]) 19:33, 18 October 2014 (UTC)&lt;br /&gt;
&lt;br /&gt;
=== {{thumbs down}}Advice users to delete residual settings from previous versions. ===&lt;br /&gt;
After upgrading to 3.2 on Windows 7, I struggled with strange rendering, misbehaving TerraSync and endless crash on load until I found out that the old 3.0 settings were still there in the Roaming folder. After simply deleting this folder ( ''C:\Users\USERNAME\AppData\Roaming\flightgear.org\'' ), and reinstalling FlightGear, I think, there was never any more trouble and everything worked perfectly.&lt;br /&gt;
--[[User:Jarl Arntzen|Jarl Arntzen]] ([[User talk:Jarl Arntzen|talk]]) 19:03, 22 November 2014 (UTC)&lt;br /&gt;
&lt;br /&gt;
== 3.0 ==&lt;br /&gt;
=== JSBSim Sync ===&lt;br /&gt;
{{cquote|&amp;lt;nowiki&amp;gt;One point that might be worth considering is whether we want to update JSBSim now or not. OTOH one consequence of updating is that there might be need to adjust  some FDM configurations (I have no clear picture what has changed in JSBSim/CVS since the last update and therefore the size of that risk). &lt;br /&gt;
Otherwise we leave the update to post-3.0.0. &amp;lt;/nowiki&amp;gt;&amp;lt;ref&amp;gt;{{cite web &lt;br /&gt;
|url=http://sourceforge.net/p/flightgear/mailman/message/31762311/&lt;br /&gt;
|title=&amp;lt;nowiki&amp;gt;Release preparations - feature freeze starts today&amp;lt;/nowiki&amp;gt;|author=&amp;lt;nowiki&amp;gt;Anders Gidenstam&amp;lt;/nowiki&amp;gt;|date=&amp;lt;nowiki&amp;gt;2013-12-17 21:15:58&amp;lt;/nowiki&amp;gt;}}&amp;lt;/ref&amp;gt;|&amp;lt;nowiki&amp;gt;Anders Gidenstam&amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
{{cquote|&amp;lt;nowiki&amp;gt;I did not see this coming (feature freeze) and, yes, there are some important changes in JSBSim that should be updated. I need to merge some offline changes into JSBSim CVS first, though.&amp;lt;/nowiki&amp;gt;&amp;lt;ref&amp;gt;{{cite web &lt;br /&gt;
|url=http://sourceforge.net/p/flightgear/mailman/message/31762311/&lt;br /&gt;
|title=&amp;lt;nowiki&amp;gt;Release preparations - feature freeze starts today&amp;lt;/nowiki&amp;gt;|author=&amp;lt;nowiki&amp;gt;Jon S. Berndt&amp;lt;/nowiki&amp;gt;|date=&amp;lt;nowiki&amp;gt;2013-12-17 21:15:58&amp;lt;/nowiki&amp;gt;}}&amp;lt;/ref&amp;gt;|&amp;lt;nowiki&amp;gt;Jon S. Berndt&amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
{{cquote|&amp;lt;nowiki&amp;gt;I Guess it's too late to integrate the latest JSBSim code now?&amp;lt;/nowiki&amp;gt;&amp;lt;ref&amp;gt;{{cite web &lt;br /&gt;
|url=http://sourceforge.net/p/flightgear/mailman/message/31856512/&lt;br /&gt;
|title=&amp;lt;nowiki&amp;gt;Release preparations: version number is now 3.0.0&amp;lt;/nowiki&amp;gt;|author=&amp;lt;nowiki&amp;gt;Erik Hofman&amp;lt;/nowiki&amp;gt;|date=&amp;lt;nowiki&amp;gt;2014-01-17 10:27:53&amp;lt;/nowiki&amp;gt;}}&amp;lt;/ref&amp;gt;|&amp;lt;nowiki&amp;gt;Erik Hofman&amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Merge Request Handling ===&lt;br /&gt;
{{cquote|&amp;lt;nowiki&amp;gt;Fact is, merge requests do get ignored most of the time, unless you know one of the active developers. I had a merge request pending for three months to update my own code in the tree, not touching anything else. It wasn't downright rejected, but was ignored for enough time for me to start working on &lt;br /&gt;
something else. Hence I'm not posting any more merge requests and instead I'm keeping my own separate tree (let's not call it fork, since I'm the only &lt;br /&gt;
user). Though I admit, sometimes it's a major pain to keep up with changes in the main tree.&amp;lt;/nowiki&amp;gt;&amp;lt;ref&amp;gt;{{cite web &lt;br /&gt;
|url=http://sourceforge.net/p/flightgear/mailman/message/31754689/&lt;br /&gt;
|title=&amp;lt;nowiki&amp;gt;osgEarth integration into FG 3.0&amp;lt;/nowiki&amp;gt;|author=&amp;lt;nowiki&amp;gt;Adrian Musceac&amp;lt;/nowiki&amp;gt;|date=&amp;lt;nowiki&amp;gt;2013-12-16 06:12:12&amp;lt;/nowiki&amp;gt;}}&amp;lt;/ref&amp;gt;|&amp;lt;nowiki&amp;gt;Adrian Musceac&amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
{{cquote|&amp;lt;nowiki&amp;gt;I can sympathize with the developers. I do know they have their personal agendas, limited time, and a lot to do without having to bother &lt;br /&gt;
with external users's whining. On the other hand, I can't be expected to babysit my merge requests too much either since I'm in the same position (I do &lt;br /&gt;
contribute to other projects as well, and have my own to contend with). I think the best way would be to asign a developer by drawing straws every &lt;br /&gt;
month, and whoever loses gets to look at merge requests on Gitorious and make at least one comment (looks good/ugly code/don't like your nickname etc.).&lt;br /&gt;
Having one year old merge requests without even one comment is unacceptable in my opinion, no matter which excuses can be provided.&amp;lt;/nowiki&amp;gt;&amp;lt;ref&amp;gt;{{cite web &lt;br /&gt;
|url=http://sourceforge.net/p/flightgear/mailman/message/31754689/&lt;br /&gt;
|title=&amp;lt;nowiki&amp;gt;osgEarth integration into FG 3.0&amp;lt;/nowiki&amp;gt;|author=&amp;lt;nowiki&amp;gt;Adrian Musceac&amp;lt;/nowiki&amp;gt;|date=&amp;lt;nowiki&amp;gt;2013-12-16 06:12:12&amp;lt;/nowiki&amp;gt;}}&amp;lt;/ref&amp;gt;|&amp;lt;nowiki&amp;gt;Adrian Musceac&amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
{{cquote|&amp;lt;nowiki&amp;gt;People get busy and miss things.  If someone sits quietly for a year on a &lt;br /&gt;
commit request, they've got nobody to blame other than themselves.&lt;br /&gt;
&lt;br /&gt;
I agree that some kind of scheduled review process should be put in place &lt;br /&gt;
- things shouldn't fall through the cracks if it can be avoided. &amp;lt;/nowiki&amp;gt;&amp;lt;ref&amp;gt;{{cite web &lt;br /&gt;
|url=http://sourceforge.net/p/flightgear/mailman/message/31757710/&lt;br /&gt;
|title=&amp;lt;nowiki&amp;gt;osgEarth integration into FG 3.0&amp;lt;/nowiki&amp;gt;|author=&amp;lt;nowiki&amp;gt;GeneB&amp;lt;/nowiki&amp;gt;|date=&amp;lt;nowiki&amp;gt;2013-12-16 17:25:37&amp;lt;/nowiki&amp;gt;}}&amp;lt;/ref&amp;gt;|&amp;lt;nowiki&amp;gt;GeneB&amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
{{cquote|&amp;lt;nowiki&amp;gt;I agree pretty much entirely - not commenting one merge requests for&lt;br /&gt;
such a long time&lt;br /&gt;
is a Bad Thing, and indeed discourages contribution.  I like the idea&lt;br /&gt;
of having a rota&lt;br /&gt;
of people responsible to at least reviewing merge requests.  At&lt;br /&gt;
present I'm discouraged&lt;br /&gt;
from reviewing merge requests because I don't feel qualified to do so&lt;br /&gt;
in many areas,&lt;br /&gt;
but I could easily provide at least some useful feedback.&amp;lt;/nowiki&amp;gt;&amp;lt;ref&amp;gt;{{cite web &lt;br /&gt;
|url=http://sourceforge.net/p/flightgear/mailman/message/31762420/&lt;br /&gt;
|title=&amp;lt;nowiki&amp;gt;osgEarth integration into FG 3.0&amp;lt;/nowiki&amp;gt;|author=&amp;lt;nowiki&amp;gt;Stuart Buchanan&amp;lt;/nowiki&amp;gt;|date=&amp;lt;nowiki&amp;gt;2013-12-17 21:53:24&amp;lt;/nowiki&amp;gt;}}&amp;lt;/ref&amp;gt;|&amp;lt;nowiki&amp;gt; Stuart Buchanan&amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Distribution ===&lt;br /&gt;
* Seed torrents once the release is out&lt;br /&gt;
&lt;br /&gt;
== 2.12 ==&lt;br /&gt;
'''Release postponed''':&lt;br /&gt;
&lt;br /&gt;
Due to real life constraints and the low number of active core developers, we've hit a fluctuation where pretty much everyone is occupied with &lt;br /&gt;
something else at the moment. As everybody seems to be caught in some real life trouble, we can't see a better way to get the release out than delaying it for a while.&lt;br /&gt;
Also, it seems that it will take longer than usual to address any issues found in the RCs. Thus, we have agreed to postpone the upcoming FlightGear 2.12 release by a month, to provide sufficient time to handle release candidates and process end-user feedback. &amp;lt;ref&amp;gt;http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg40568.html&amp;lt;/ref&amp;gt;&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Distribution:'''&lt;br /&gt;
* we should make sure to seed torrents once the release is out {{forum link|p=190780}} {{forum link|t=20987}} {{forum link|t=21058}}&lt;br /&gt;
&lt;br /&gt;
'''RCs:'''&lt;br /&gt;
* we should try to get out release candidates earlier to give testers a chance to actually run the RCs [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg40522.html] &lt;br /&gt;
&lt;br /&gt;
{{cquote|&amp;lt;nowiki&amp;gt;could we generate a full installation RC package for testing?  It would make it easier for testers not familiar with Git to use it, and would be quite&lt;br /&gt;
handy for people like myself who do their development on Linux, but have Windows systems available for testing but without the git infrastructure or the time to download the entire git fgdata repository.&amp;lt;/nowiki&amp;gt;&amp;lt;ref&amp;gt;{{cite web |url=http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg40608.html|title=&amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] 2.12 is branched&amp;lt;/nowiki&amp;gt;|author=&amp;lt;nowiki&amp;gt;Stuart Buchanan&amp;lt;/nowiki&amp;gt;|date=&amp;lt;nowiki&amp;gt;Wed, 21 Aug 2013 07:29:32 -0700&amp;lt;/nowiki&amp;gt;}}&amp;lt;/ref&amp;gt;|&amp;lt;nowiki&amp;gt;Stuart Buchanan&amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
{{cquote|&amp;lt;nowiki&amp;gt;Jenkins only does what it's told by the scripts (mostly in fgmeta besides the CMake files) - so we're still at the mercy of missing files in the &lt;br /&gt;
installer description and so on - I didn't yet automate a 'smoke test'[1] on Jenkins, since that would mean keeping a clean environment to run test &lt;br /&gt;
installs, and involve several expensive operations since we'd be launching the sim. That's all doable but requires VMs and more energy than I have. In general &lt;br /&gt;
I've been hoping to get enough people using the nightly builds that an automated smoke-test would be unnecessary but that's probably optimistic&amp;lt;/nowiki&amp;gt;&amp;lt;ref&amp;gt;{{cite web |url=http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg40609.html|title=&amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] 2.12 is branched&amp;lt;/nowiki&amp;gt;|author=&amp;lt;nowiki&amp;gt;James Turner&amp;lt;/nowiki&amp;gt;|date=&amp;lt;nowiki&amp;gt;Wed, 21 Aug 2013 07:52:59 -0700&amp;lt;/nowiki&amp;gt;}}&amp;lt;/ref&amp;gt;|&amp;lt;nowiki&amp;gt;James Turner&amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
{{cquote|&amp;lt;nowiki&amp;gt;MSVC has a very powerful source view level debugging, but at present this fails in some auto-generated ctor/dtor &lt;br /&gt;
code before it reaches 'main()' so can not be used ;=((.&lt;br /&gt;
&lt;br /&gt;
In the Debug build 'new' is replaced with a 'new_dbg'  which deliberately fills the allocation with 0xcc... &lt;br /&gt;
so if a person does NOT initialize ALL variables simple dtor code like 'if (buf) delete buf;' crashes.&amp;lt;/nowiki&amp;gt;&amp;lt;ref&amp;gt;{{cite web |url=http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg40615.html|title=&amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] 2.12 is branched&amp;lt;/nowiki&amp;gt;|author=&amp;lt;nowiki&amp;gt;Geoff McLane&amp;lt;/nowiki&amp;gt;|date=&amp;lt;nowiki&amp;gt;Wed, 21 Aug 2013 10:04:18 -0700&amp;lt;/nowiki&amp;gt;}}&amp;lt;/ref&amp;gt;|&amp;lt;nowiki&amp;gt;Geoff McLane&amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
'''FGData:'''&lt;br /&gt;
* {{getstart source|view=commit|commit=4b0ee648b59e9456d0f653b432a10305560cce0b|text=Stuart's PDF generator in bin/makereadmepdf.pl should be run as part of the installer creation process}}.&lt;br /&gt;
* Once again, some users were asking for a more lightweight/essential FGData distribution {{forum link|t=20716}}&lt;br /&gt;
* Some users reported broken sound configurations for a number of aircraft due to stereo files {{forum link|t=20332}}&lt;br /&gt;
* We still keep seeing issues due to aircraft developers contributing resources with files, file names, paths  that would break support on OS with case-sensitive OS or a different locale, it would make sense to add some form of automated/scripted validation during startup to detect such issues, without requiring a manual review, possibly through [[Catalog metadata]] [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg40407.html] {{forum link|p=185963|hilit=xml+french}} [https://code.google.com/p/flightgear-bugs/issues/detail?id=1158] [{{gitorious merge request|proj=fg|repo=fgdata|mr=224|full=1}}]&lt;br /&gt;
&lt;br /&gt;
'''Usability/GUI:'''&lt;br /&gt;
* the menubar is increasingly getting a little cluttered, especially the &amp;quot;debug&amp;quot; entry - given the inflexibility of PUI, this also means that there are usability issues, because certain menu items are only accessible with a certain minimal screen resolution, other items cannot be accessed easily. A short term suggestion made, was moving all &amp;quot;Reload X&amp;quot; items into a dedicated &amp;quot;reload&amp;quot; menu, and moving tools to a separate &amp;quot;tools&amp;quot; menu, so help reduce the size of the debug menu {{forum link|p=186615|hilit=cluttered}} {{forum link|p=186742|hilit=reload+menu}}&lt;br /&gt;
&lt;br /&gt;
'''Core:'''&lt;br /&gt;
* A few users reported issues that seemed possibly related to aggressive compiler optimizations, exposing the cmake/build flags via the property tree would seem like a good idea {{forum link|p=193138|hilit=funroll}}&lt;br /&gt;
* Some windows users reported that TerraSync would only work for them in 32-bit compatibility mode {{forum link|p=191789}}&lt;br /&gt;
* Providing support to new users would  be greatly simplified if we could expose debug related  info via the property tree, i.e. to ensure that OSG/SG/FG were not built in DEBUG mode {{forum link|p=191627}}&lt;br /&gt;
* We should look into exposing OSG plugin information via the help/about dialog, i.e. writing the info the property tree [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg40859.html]&lt;br /&gt;
* There we still some reports about &amp;quot;SQLite API abuse&amp;quot;, presumably due to non-English characters in installation paths,maybe the installer could check paths prior to installation? {{forum link|p=189083}}&lt;br /&gt;
* We kept seeing SQLite/NavDB Cache related bug reports {{forum link|p=191552}} {{Issue|1227}}&lt;br /&gt;
* Like it used to be the case with detailed log files, most end users are usually very willing to help, but unable to provide backtraces - reconsider adding google breakpad support {{forum link|p=188017}}&lt;br /&gt;
* under some circumsances, initial navcache/POI processing took up to 10 minutes, even on powerful Linux boxes with plenty of horsepower and RAM using just the default settings {{forum link|p=187417}}&lt;br /&gt;
* the way we are incrementing version numbers in SG_SRC/FG_SRC and FGDATA seems to be causing issues (&amp;quot;base package check failed&amp;quot;), which were reported already during the last release cycles (all the way back to 2.8), even one core developer reported the issue during the 2.10 cycle (many people affected by this seem to be using brisa's download &amp;amp; compile script, but it doesn't appear to be Linux-specific, it also seems to happen on Windows). It seems fgdata version is 2.12 while the SG/FG source trees in next were still looking for 2.11 - could be also because of cmake caching, and the cache not being updated properly once certain files are touched in SG/FG source, still investigating... {{forum link|p=186647}} {{forum link|t=20467}}. The problem seems to be {{forum link|p=186942|text=this}}.&lt;br /&gt;
* some rendering issues related to OSG 3.1.9 were reported [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg40390.html] [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg40422.html] [{{simgear source|view=commit|commit=5320d0ecaa696eb2712598879a15ae505bb65e4f|full=1}}] [http://photos.mxchange.org/?d=albums/Flightgear-Flight-Simulator/screenshots-master/bugs]&lt;br /&gt;
* it would probably be a good idea to explicitly check for the latest supported OSG version in our SG/FG CMakeLists.txt, to ensure that people do not build FG against OSG versions that are not yet supported, with some option to override/disable the check (for developers) [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg40352.html] [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg40431.html]&lt;br /&gt;
* while the delayed tile loading is a big improvement in the responsiveness, delayed loading of models caused issues for helicopter pilots, because they could no longer start on buildings - it might be better to make the new behavior property-configurable through a prop switch, so that helicopters could override the setting during startup in their aircraft-set.xml file [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg40421.html]&lt;br /&gt;
&lt;br /&gt;
'''Version numbering:'''&lt;br /&gt;
{{cquote|There was already a couple of people on IRC confused that 2.12 is different to 2.1.2 (since minor version numbers &amp;gt; 9 are something of a rarity in many people's perception).&amp;lt;ref&amp;gt;{{cite web |url=http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg40339.html|title=&amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] reminder: entering feature freeze now&amp;lt;/nowiki&amp;gt;|author=James Turner|date=Mon, 24 Jun 2013 14:15:00 -0700}}&amp;lt;/ref&amp;gt;|James Turner}}&lt;br /&gt;
&lt;br /&gt;
{{cquote|Give our release pattern is date scheduled, an Ubuntu style numbering scheme would actually make more sense, but a bit more effort to move too.&amp;lt;ref&amp;gt;{{cite web |url=http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg40339.html|title=&amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] reminder: entering feature freeze now&amp;lt;/nowiki&amp;gt;|author=James Turner|date=Mon, 24 Jun 2013 14:15:00 -0700}}&amp;lt;/ref&amp;gt;|James Turner}}&lt;br /&gt;
&lt;br /&gt;
{{cquote|Externally, 3.0 is going to be considered a bigger deal than 2.12.0.&amp;lt;ref&amp;gt;{{cite web |url=http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg40357.html|title=&amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] reminder: entering feature freeze now&amp;lt;/nowiki&amp;gt;|author=Stuart Buchanan|date=Tue, 25 Jun 2013 14:48:56 -0700}}&amp;lt;/ref&amp;gt;|Stuart Buchanan}}&lt;br /&gt;
&lt;br /&gt;
{{cquote|I suggest that we zero-pad the minor release digit after 3.0.0 so we have 3.02, 3.04 etc. to reduce confusion if we reach double digits.&amp;lt;ref&amp;gt;{{cite web |url=http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg40357.html|title=&amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] reminder: entering feature freeze now&amp;lt;/nowiki&amp;gt;|author=Stuart Buchanan|date=Tue, 25 Jun 2013 14:48:56 -0700}}&amp;lt;/ref&amp;gt;|Stuart Buchanan}}&lt;br /&gt;
&lt;br /&gt;
{{cquote|many computer systems sort file names in ascii order, many people don't seem to pay careful attention to where the decimal points are placed, etc.&lt;br /&gt;
&lt;br /&gt;
Once we clear past the 2.10, 2.12, etc. series, I'd like to go back to keeping things single digits in the major and minor version numbers and when we run out of a single digits bump up the major number (so 3.8.x -&amp;gt; 4.0.x).  Number are numbers, but this one confused a lot more people than I expected it would or should so maybe it's good to be sensitive to that after we clear the 2.x series of versions.&amp;lt;ref&amp;gt;{{cite web |url=http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg40358.html|title=&amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] reminder: entering feature freeze now&amp;lt;/nowiki&amp;gt;|author=Curtis Olson|date=Tue, 25 Jun 2013 14:59:08 -0700}}&amp;lt;/ref&amp;gt;|Curtis Olson}}&lt;br /&gt;
&lt;br /&gt;
{{cquote|That sounds OK to me, as it would imply a full release every 2.5 years, give a clear flag ahead of time when we're nearing a major release, and save having these discussions in the future.  For reference, with the current plan there will be 4 years between 2.0.0 (Feb 2010) was and 3.0.0 (Feb 2014). &amp;lt;ref&amp;gt;{{cite web |url=http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg40437.html|title=&amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] reminder: entering feature freeze now&amp;lt;/nowiki&amp;gt;|author=Stuart Buchanan|date=Mon, 08 Jul 2013 14:42:16 -0700}}&amp;lt;/ref&amp;gt;|Stuart Buchanan}}&lt;br /&gt;
&lt;br /&gt;
{{cquote|&amp;lt;nowiki&amp;gt;I've set the version files on 'next' to be 2.99, on the assumption the next release will be 3.0 as discussed.&amp;lt;/nowiki&amp;gt;&amp;lt;ref&amp;gt;{{cite web |url=http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg40481.html|title=&amp;lt;nowiki&amp;gt;[Flightgear-devel] 2.12 is branched&amp;lt;/nowiki&amp;gt;|author=&amp;lt;nowiki&amp;gt;James Turner&amp;lt;/nowiki&amp;gt;|date=&amp;lt;nowiki&amp;gt;Wed, 17 Jul 2013 12:39:56 -0700&amp;lt;/nowiki&amp;gt;}}&amp;lt;/ref&amp;gt;|&amp;lt;nowiki&amp;gt;James Turner&amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
'''Backwards Compatibility:'''&lt;br /&gt;
{{cquote|I think I sensible step in that case is to keep 3.0 as backward compatible (in terms of Aircraft APIs) with 2.12 as possible, which mostly means my resisting the urge to clean up legacy stuff :)&lt;br /&gt;
&lt;br /&gt;
Obviously it's tricky to offer a 100% guarantee, but I don't have anything planned for 3.0 that will require aircraft changes - I'm sure new technologies &lt;br /&gt;
such as state machines, knob/slider animations and tooltips will mature and gain some new features but hopefully aircraft developers will be able to work &lt;br /&gt;
against 2.12 with confidence that things will work the same in 3.0&amp;lt;ref&amp;gt;{{cite web |url=http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg40366.html|title=&amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] reminder: entering feature freeze now&amp;lt;/nowiki&amp;gt;|author=James Turner|date=Wed, 26 Jun 2013 02:49:00 -0700}}&amp;lt;/ref&amp;gt;|James Turner}}&lt;br /&gt;
&lt;br /&gt;
{{cquote|It's a bit tricky because I haven't had much feedback from aircraft developers about the new APIs (since they aren't in 2.10), but once 2.12 ships we would want to keep them compatible, so fingers crossed the current design is sensible &amp;lt;ref&amp;gt;{{cite web |url=http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg40366.html|title=&amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] reminder: entering feature freeze now&amp;lt;/nowiki&amp;gt;|author=James Turner|date=Wed, 26 Jun 2013 02:49:00 -0700}}&amp;lt;/ref&amp;gt;|James Turner}}&lt;br /&gt;
&lt;br /&gt;
== 2.10 ==&lt;br /&gt;
'''!!! NOTE: None of these issues have been incorporated into the release plan yet !!!'''&lt;br /&gt;
* '''FlightGear Core related ''':&lt;br /&gt;
** a number of users reported segfaults related to the new flight recorder system [https://code.google.com/p/flightgear-bugs/issues/detail?id=1023] {{forum link|p=181414}}&lt;br /&gt;
** the [[Scripted_Compilation_on_Linux_Debian/Ubuntu| download &amp;amp; compile]] script in fgmeta should be updated for each release {{forum link|p=180879}}&lt;br /&gt;
**  {{Thumbs up}} It is great news if you are able to crank out full installers right from Jenkins.  That will save me a bunch of downloading and hours of uploading for every new release candidate [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg39781.html].&lt;br /&gt;
** But it might be a good idea to create a script that will distribute the new builds to the various mirrors.  That way I'm less likely to throttle the build server to 10k/sec [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg39782.html]&lt;br /&gt;
** we could also automatically seed them in BitTorrent, on a Linux box and use &amp;quot;btmakemetafile&amp;quot; which I use here to generate those update packages on [http://mxchange.org:23456/ the tracker] [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg39783.html]&lt;br /&gt;
** {{Improve Release Plan|perform a sync with JSBSim sources before the feature freeze}} [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg40179.html].&lt;br /&gt;
** {{Improve Release Plan|decide early on if/when navdata can be updated}} [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg39280.html]&lt;br /&gt;
** {{Improve Release Plan|merge requests that didn't make it into the previous release should probably be handled early during the upcoming release cycle}}&lt;br /&gt;
** {{Improve Release Plan|distro-specific repositories should probably be updated, too}} {{forum link|p=174943}}&lt;br /&gt;
** {{Improve Release Plan|the &amp;quot;FlightGear &amp;amp; friends&amp;quot; SuseStudio images should probably be also updated for each release cycle }}[http://susestudio.com/a/sBTdmU/flightgear-friends--2]&lt;br /&gt;
** every now and then, people raise the issue of the major/minor version numbering scheme being a little confusing to people not familiar with software development, thinking that 2.8 must be newer/better/more recent than 2.11 - using code names or release dates instead was suggested {{forum link|t=19255}}&lt;br /&gt;
** there are usually reviews posted on blogs, forums etc after each release - we should specifically collect links to those and evaluate all opinions [http://forum.avsim.net/topic/400897-my-experience-with-flightgear-210/] [http://forum.avsim.net/topic/399809-fg-210-most-certainly-a-new-era-of-fg/]&lt;br /&gt;
** {{Improve Release Plan|the release plan should be augmented for the sub-release procedures }}[http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg39710.html]&lt;br /&gt;
** there were a number of navcache/SQLite related issues reported via the issue tracker and the forum/devel list [https://code.google.com/p/flightgear-bugs/issues/detail?id=894] {{forum link|p=175690}} [http://code.google.com/p/flightgear-bugs/issues/detail?id=1055]&lt;br /&gt;
** a little irritation/frustration was caused due to the conflicting review statements concerning the new radio propagation code [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg38905.html] [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg38825.html] [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg33692.html] - some of this boiled down to coding style related issues, highlighting the fact that different core developers have different &amp;quot;coding styles&amp;quot; and requirements when reviewing merge requests, because we still lack an official &amp;quot;FlightGear coding style guide&amp;quot; [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg38958.html]&lt;br /&gt;
** according to Windows users, the installer created by jenkins could use some optimizations {{forum link|t=19745}}&lt;br /&gt;
** a number of Windows7/Windows8 users reported issues that needed a &amp;quot;force 32/64 bit&amp;quot; workaround during startup {{forum link|p=182923}} {{forum link|p=182759}} {{forum link|p=182724}}&lt;br /&gt;
** {{Improve Release Plan|new GUI widgets, new fgcommands and new Nasal APIs should ideally be documented prior the release, at least through updated README files, preferably also through the wiki}}&lt;br /&gt;
&lt;br /&gt;
* '''Better bug reports and troubleshooting''':&lt;br /&gt;
** show HLA/OpenRTI availability {{fixed since|release=2.11+}} [{{flightgear source|view=commit|commit=c61583de5daddaa901ff52562645fac3f04dd225|full=1}}]&lt;br /&gt;
** add a string property with list of startup arguments used by the user, for use in the about dialog&lt;br /&gt;
** add a property specifying if the binary is 32/64 bit for use in the about dialog (to check if segfaults are related to 32bit RAM limits)&lt;br /&gt;
** add a property specifying the CMAKE_BUILD_TYPE variable used during compilation, for use in the about dialog (debug, release, RelWithDbgInfo) [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg40311.html]&lt;br /&gt;
** show the threading mode in use in the about dialog&lt;br /&gt;
** show average frame rate and frame spacing in about dialog&lt;br /&gt;
** add a property specifying how much physical RAM is detected (to see if people are running out of RAM) {{forum link|p=164936|hilit=swapping}}&lt;br /&gt;
** is there a portable ARB/WGL extension to determine the amount of dedicated VRAM available ?&lt;br /&gt;
** try to detect Intel GPUs and Mesa drivers ? (some of the more common issues were related to Intel/Mesa)&lt;br /&gt;
&lt;br /&gt;
* '''Changelog / Release Announcement''':&lt;br /&gt;
** {{Thumbs up}} Walking through the list of &amp;quot;lessons learned&amp;quot; as part of the &amp;quot;Upcoming release&amp;quot; announcement was useful [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg38749.html]&lt;br /&gt;
** {{Improve Release Plan|Probably it would be even better to directly process all &amp;quot;lessons learned&amp;quot; items and improve the release plan after each release accordingly}}&lt;br /&gt;
** To get to the 3.0 goal sometime in the near future, it's probably a good  idea to [[FlightGear 3.0 backlog|create a backlog of open items in the wiki and link the release plan document to that]]. As usual, we don't have to be perfect for a new major release number. But the new features being the reason for the new major  number should work reasonably correct.  [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg38888.html] (also see [[:Category:Developer Plans]])&lt;br /&gt;
** {{Thumbs up}} Posting the link to the changelog for the upcoming release helped writing the changelog early, this should also be done for the [[Hardware Recommendations]] and [[Notebooks known to run FlightGear]] pages probably?&lt;br /&gt;
** {{Thumbs up}} The changelog can be easily written by using &amp;quot;git log&amp;quot;, searching the issue tracker and by going through the last 6 newsletters published since the previous release. It might make sense to explicitly add a &amp;quot;ChangeLog&amp;quot; message to important commits, so that the Changelog can be compiled more easily ?&lt;br /&gt;
** Alternatively, request developers to add major changes also to $FG_SRC/ChangeLog again (last updated in 2001)?&lt;br /&gt;
** {{Improve Release Plan|for the web-based release announcement, it would be helpful to have screen shots or even youtube videos to demonstrate new features - get the community involved EARLY}}&lt;br /&gt;
** {{Improve Release Plan|it may make sense to also allow artwork contributors to contribute new splash screen images for use in the upcoming release. The screen shot contest should provide plenty of options}} {{forum link|t=16795}}.&lt;br /&gt;
** {{Improve Release Plan|a screenshot/banner contest should be held early on, so that we can use the images for our promo work-NOT after the release}} {{forum link|t=19220}}&lt;br /&gt;
** {{Improve Release Plan|for the changelog we should early on invite volunteers to help translate it, useful for the release promotion}}&lt;br /&gt;
** {{Improve Release Plan|having dedicated promo videos sounds like a good idea}}, see {{forum link|t=19158}} [[Howto:Creating FlightGear Promo Videos]]&lt;br /&gt;
** The RC announcement should also contain links to 1) the issue tracker and 2) the RC subforum [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg39222.html]&lt;br /&gt;
** Using wiki tagging, we could ensure that we can also tag our wiki documentation after each release, so that we can provide older versions of our docs for old FG versions {{forum link|p=170735|hilit=wiki+tagging}}&lt;br /&gt;
** various files in $FG_ROOT haven't been updated in YEARS, either update them in the future, or just get rid of them: THANKS, NEWS, ChangeLog etc&lt;br /&gt;
&lt;br /&gt;
* '''Shaders''':&lt;br /&gt;
** the ATI viewport hack didn't seem enabled in the RCs, as reported by a number of users on the forum {{forum link|p=176549}}&lt;br /&gt;
** the ATI viewport hack should only be enabled by default if ATI/AMD hardware is detected [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg39900.html] {{forum link|p=176183|hilit=viewport}} {{gitorious merge request|proj=fg|repo=fgdata|mr=190|full=1}}]&lt;br /&gt;
** we should probably try to detect if software emulated OpenGL is in use (i.e. using Mesa) and show a corresponding warning {{forum link|type=search|keywords=libtxc_dxtn}}&lt;br /&gt;
** texture compression should be disabled by default {{forum link|p=175123}} {{forum link|p=177902}} {{forum link|p=177983}} {{forum link|p=178307}} {{forum link|p=180049}}&lt;br /&gt;
** {{Thumbs up}} lowering the default shader level to 1 improved compatibility for older/underpowered systems [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg39189.html]&lt;br /&gt;
** but there were still '''many''' users reporting issues like crashes/segfaults during startup, that seemed affected by changing graphics settings {{forum link|p=181033}}&lt;br /&gt;
** we should make sure that the default shader level (and related shaders!) works for all common setups, including ATI/AMD cards (Mac!) and Intel GPUs&lt;br /&gt;
** {{Improve Release Plan|GLSL shaders and effects should be treated like core code, and should be tested on different platforms before being enabled by default (i.e. signed-off by people using NVIDIA, ATI/AMD, Intel)}} [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg39120.html]&lt;br /&gt;
** {{Improve Release Plan|modified shaders should be tested with other shader-related features to prevent breakage }} {{forum link|p=175583}} (there might be a way to automate this a litle by catching GLSL compiler errors?)&lt;br /&gt;
** to address all the intel GPU related issues, we may want to show an info dialog on computers where /sim/rendering/gl-vendor contains &amp;quot;intel&amp;quot; as a substring and provide an option to disable all shaders {{forum link|p=175774}}&lt;br /&gt;
** we probably need a separate article detailing GLSL coding requirements to ensure that portable constructs are used [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg39278.html] so that problematic shaders are not just identified at the end of the release cycle&lt;br /&gt;
&lt;br /&gt;
* '''Installer''':&lt;br /&gt;
** The installer should be updated to show a warning regarding TerraSync update time {{forum link|p=175779}}&lt;br /&gt;
** When Flightgear releases a new version, can the staff create a way for the average computer users to install a new version without doing anything to the old version but still use the terrain files from the older version? {{forum link|p=175762}}&lt;br /&gt;
** I believe Fred intentionally chose to use the same registry key from one version to the next.   Thus if you install a new version over the top of an existing version it will end up in the same path under C:\&amp;lt;PF&amp;gt; [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg39246.html]&lt;br /&gt;
&lt;br /&gt;
* '''FGData related (Base Package)''':&lt;br /&gt;
** accessibility of README files in $FG_ROOT/Docs should be improved for our Win/Mac users {{forum link|t=19725}} {{fixed since|release=2.11+}} (by Stuart)&lt;br /&gt;
** aircraft included in the base package should not require DDS support {{forum link|p=183549}}&lt;br /&gt;
** a bunch of Intel GPU related issues were tracked down to be related to texture dimensions beyond 512x512 not being supported, suggested workarounds are mentioned at [http://code.google.com/p/flightgear-bugs/issues/detail?id=1100#c2]&lt;br /&gt;
** &amp;quot;Funny how the 172P doesn't have it (crash detection via limits.nas). It is something like a default aircraft for the sim, isn't it? Which aircraft are considered the most &amp;quot;finished&amp;quot;?&amp;quot; {{forum link|p=180157}}&lt;br /&gt;
** &amp;quot; I'm a bit confused by all the aircraft models in various stages of completion. Even the install package comes with some below-par and alpha stage models. Is there a compiled list of aircraft that are considered &amp;quot;well done&amp;quot;?&amp;quot; {{forum link|p=180196}}&lt;br /&gt;
** The default set of airplanes in FG should be the absolute best of the best, simply because that's what a new user is going to be exposed to for their first time. [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg39609.html]&lt;br /&gt;
** Language files should be synced between English and other languages, so translators can work on them before the release ;-)&lt;br /&gt;
** the {{flightgear source|path=scripts/python/nasal_api_doc.py|text=nasal_api_doc.py}} script in $FG_SRC/scripts/python should be run as part of the release process, to create an updated doc file for [[$FG_ROOT]]/Docs and ship it with each release {{forum link|t=15133}}&lt;br /&gt;
** {{Improve Release Plan|New/updated Nasal scripts contributed to the base package should be checked to properly support important features like simulator reset, this also applies to Nasal scripts used by aircraft, Nasal scripts that fail these criteria, end up breaking existing features! }}[https://code.google.com/p/flightgear-bugs/issues/detail?id=956] (also see [[Release:Aircraft Selection Criteria]])&lt;br /&gt;
** {{Thumbs up}} regarding aircraft included in the release: &amp;quot;I must stress usefulness of the Autostart feature, present in most aircraft not running at startup. It keeps frustration away from those who just want to enjoy the flight . (Please note that I actually agree with aircraft being shut down at startup, as long as autostart is present, or the starting procedure is trivially doable by just trying what you see in the cockpit.) &amp;quot; {{forum link|p=175117}} (also see [[Release:Aircraft Selection Criteria]])&lt;br /&gt;
** {{Thumbs up}} also, it would apparently make sense to provide tutorials for the default aircraft: &amp;quot;At first startup, I noticed the &amp;quot;Need help? use help-&amp;gt;tutorials&amp;quot; message, and because I had no idea how to start up the plane (it would be just plain try and fail, than try something else), I did just that and started some basic tutorials. I wouldn't say going through the tutorials was frustrating, but they were quite boring and I was eager to get in the air as soon as possible.&amp;quot; {{forum link|t=16795}} (also see [[Release:Aircraft Selection Criteria]])&lt;br /&gt;
** &amp;quot;I discovered however, that there can be some problems on Linux about the planes (eg. some versions of the L39 Albatros undergoing several improvements lately). The problems can be caused by Linux being case sensitive about file paths (Windows is not), and I suspect, more models could suffer from some developers not knowing that. It's easy to fix if you know about the problem, but it would better be done on the developer side, as you never know if the smoke is just not implemented or missing due to this. Not to mention how lengthy it would be to go through more aircraft...&amp;quot; {{forum link|t=16795}}&lt;br /&gt;
** Docs: Relevant FlightGear paths should ideally not be &amp;quot;hard-coded&amp;quot; in the manual, but rather also configured via the build system, i.e. using cmake, so that the FG/SG cmake configuration can be shared, to automatically update the correct paths without requiring manual maintenance {{forum link|p=180119}}&lt;br /&gt;
&lt;br /&gt;
* '''Usability''':&lt;br /&gt;
** the huge number of ads placed on the official website, and the non-intuitive layout of the website caused quite some irritation, not only among new users, but also among seasoned long-time contributors - flightgear.org has been repeatedly described as leaving the impression of even being a &amp;quot;scam&amp;quot; {{forum link|t=18863}} [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg39533.html]&lt;br /&gt;
** {{Thumbs down}} A little downside is how the FGcom is done as a standalone program just cooperating with FG itself. It took me some fiddling with the settings for about two hours to get it working, but again installation was simply done from repos (FGcom and than FGcomGui as well). {{forum link|t=16795}} (this is planned [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg38057.html]) {{fixed since|release=2.99+}}&lt;br /&gt;
** {{Thumbs down}} Most likely because of the Intel graphics, I suffered for a long time from a problem with aircraft models (and some ground textures too) being black or missing some parts (see my post in an older thread complaining about similar problem). I solved it by adding a command line option turning off texture compression. {{forum link|t=16795}} (also see [[Release:Aircraft Selection Criteria]])&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
** I also vote for hosting a non-GPL hangar on the FG site, and tighter coordination with the aircraft developers (I think they should be asked to actively propose their models to the hangar once it is created, of course there could be link to their site/hangar). It would help nice models to be more easily found, an more people could enjoy them. And that's why people spend time creating them, right? {{forum link|t=16795}}&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
** We should probably add a new menu to the menubar for our online resources (wiki, forum, issue tracker, FAQ) so that people more easily find important resources just by selecting them from a menu.&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
** Our GUI dialogs are currently not designed with a fixed resolution in mind, also they cannot be easily resized/changed, so that some dialogs may not be usable under certain circumstances {{forum link|p=170232|hilit=canvas+screen}} {{forum link|p=175738&amp;amp;hilit=768}} We should ensure that all dialogs can be used with the recommended minimal screen size, or even better, provide a way to dynamically make dialogs resizable/tabbed to support smaller screen devices (like netbooks). This should be easier with the upcoming [[Canvas GUI]] system.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Release Candidates''':&lt;br /&gt;
** a number of users reported crashes, for better debugging support, consider linking in Google BreakPad (cross platform stack traces) {{forum link|p=176669}}&lt;br /&gt;
** Release Candidates should probably have a higher default logging level while writing everything to a log file that can be easily shared via the issue tracker/forums, so that end users can provide better bug reports.&lt;br /&gt;
** some users reported &amp;quot;OpenGL out of memory&amp;quot; and &amp;quot;out of space&amp;quot; errors when testing the RCs, we may want to link in a leak detector library or simply add BoehmGC - which is used by Mozilla to track leaking subsystems (a runtime log is created and dumped at process termination), that way non-developers could provide better leak reports. {{forum link|t=17114}} {{forum link|p=163132}} {{forum link|p=171329}}&lt;br /&gt;
** How about having a test run a week or two in advance, just to make sure  we can indeed produce release installers for Win+Mac - and then release  the first RC on December 17th/18th or 19th [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg38765.html]&lt;br /&gt;
** We've already got a fairly extensive lead-in time for the release.  More testers on more platforms would seem to be the answer.  Perhaps we should advertize for testers of those platforms that aren't adequately covered by developers running git? Making a complete package available, not just the binaries would help, as testers wouldn't need to be git-aware. [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg38764.html]&lt;br /&gt;
** {{Improve Release Plan|The main area to improve is to distribute release candidates for all  platforms earlier - preferably starting immediately after the freeze. That would already give us more time for testing - without extending the  actual freeze period.}}[http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg38765.html]&lt;br /&gt;
** {{Improve Release Plan|aircraft packages should be prepared prior to the official release date: &amp;quot;For the 2.8 release I didn't start making aircraft download packages (or uploading them to the ftp servers) until after the official release date which was a mistake&amp;quot;}} [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg39227.html]&lt;br /&gt;
** {{Improve Release Plan|RC's should probably be built with [[Built-in Profiler]] support enabled}} {{forum link|p=175689}}.&lt;br /&gt;
** {{Improve Release Plan|When releasing RC's do not limit them to Win/Mac binaries, but also create source snapshots so that distros can already work on the next package versions.}}&lt;br /&gt;
** {{Improve Release Plan|For RC's it might make sense to distribute binaries with debugging symbols included}} and [[Built-in Profiler|profiling support enabled]], so that people can more easily provide useful bug reports, or even backtraces.&lt;br /&gt;
** Also, many end users still prefer using the forum for making bug reports and don't use the issue tracker - it might help to add a link (button) to the issue tracker to the about dialog or maybe even directly to the help menu (&amp;quot;Report an issue&amp;quot;) (same for wiki/troubleshooting/faq ?)&lt;br /&gt;
** {{Improve Release Plan|it might make sense to give wider exposure to our RCs, i.e. via the newsletter - possibly by adjusting the release schedule}}&lt;br /&gt;
** actually, it would even seem better to use our [[Release promotion]] checklist to send out an &amp;quot;Upcoming Release&amp;quot; announcement 4-6 weeks prior to the actual release, so that all the flightsim websites can notify their users to participate in RC beta testing.&lt;br /&gt;
** a number of forum users reported that the RC/release mirrors were a real bottleneck, and that downloading the 800MB RC installer would often take 2-3 hours (using torrents instead was suggested)&lt;br /&gt;
** it also seemed that a number of users had issues related to their browser corrupting the huge image download {{forum link|p=176087}} (website should suggest to use a download manager instead!)&lt;br /&gt;
** so reducing the size of the installer (i.e. base package) would seem like another good idea to give our RCs wider exposure, for example by focusing only on 2-3 aircraft&lt;br /&gt;
** certain reported issues were really tricky to reproduce, we may want to provide an option to export crucial runtime settings to an XML file that can be easily shared with other testers/developers, or even extend the new flight recorder/replay tape system accordingly {{forum link|p=176023}}&lt;br /&gt;
** it might be good if the forum release-candidates announcement mentions that tests and bug-reports should be done with a clean install of the release-candidate, with no third-party data used in tests.&lt;br /&gt;
&lt;br /&gt;
* '''Build related''':&lt;br /&gt;
* A normal Linux user has practically no chance to get last stable on his box running if it isn't in his distro - a normal Windows user gets everything nice and streamlined. [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg38817.html]&lt;br /&gt;
* According to the issue tracker there were 3-5 different contributors who provided C++ patches that didn't end up reviewed/merged, which caused some irritation.&lt;br /&gt;
&lt;br /&gt;
== 2.8 ==&lt;br /&gt;
* {{Thumbs down}} Lack of stress-testing: A number of users reported severe memory growth issues (with fgfs consuming as much as 14gb of RAM), many directly related to new features, such as random buildings: {{forum link|p=160747|hilit=vegetation}} {{forum link|t=17249}} {{forum link|p=163829}} [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg38007.html] These could have probably been identified earlier by running FG for extended periods of time, and testing the shipped aircraft with the default KSFO scenery, and new features such as random buildings enabled.&lt;br /&gt;
* {{Thumbs down}} Lack of graceful feature scaling: Several users with old graphics cards reported not being able to run FG 2.8 without crashing during startup, because the FG defaults didn't scale for old hardware {{forum link|t=17308}}&lt;br /&gt;
* {{Thumbs down}} According to noaa.gov it seems that the NOAA metar source got phased out in 04/2012 and moved to a new URL[http://weather.noaa.gov/weather/coded.html], some users reported issues related to this {{forum link|p=165784|hilit=metar}}. However, the metar URL is currently hard-coded in the fgfs/metar source code - in addition, the default format is no longer a plain text dump [http://www.aviationweather.gov/adds/metars/]. It would make sense to make the URL a string property that can be put into preferences.xml and then use a Nasal listener to parse the resulting XML/HTML and set a plain text property instead, that can be processed by the existing metar code.&lt;br /&gt;
* {{Thumbs down}} [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg38113.html Broken OSX downloads]&lt;br /&gt;
* {{Thumbs down}} {{forum link|p=165841|text=the OSX 10.8 release and code signing caused some irritation}}&lt;br /&gt;
* {{Thumbs down}} {{forum link|p=166062|text=After the 2.8 release a number of users on the forums reported seeing GLSL related errors, because some of the 2.8 shaders used GLSL features only supported by more recent GLSL compilers/drivers - it would probably make sense to test all shader settings on all 3 platforms and check if they cause any errors (and &amp;quot;backport&amp;quot; shaders as necessary). Apple/Mac OSX seems to be more problematic}}&lt;br /&gt;
* {{Thumbs down}} [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg38121.html Microsoft Redistributables were apparently not shipped with the Windows installer ?]&lt;br /&gt;
* {{Thumbs down}} [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg38089.html The changelog should be written as early as possible]&lt;br /&gt;
* The code freeze could probably be lifted for patches that are not normally enabled/used by any default code paths (or shipped aircraft) in a FlightGear release. This probably involves Nasal extension functions, fgcommands, telnet commands, but also custom hard coded instruments or instrumentation-related APIs (think Canvas). Basically, whenever there's no chance to break a release by committing a certain patch, because the code path will not be executed by default without explicitly enabling it. For 2.8, this also meant that the Nasal [[Canvas]] API could not be included due to the code freeze, which however wasn't used by any systems or aircraft - so that there would have been zero chance for breakage [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg37622.html] {{forum link|p=165413}}.&lt;br /&gt;
* The wiki contains a number of resources to help new users with hardware decisions, such as [[Hardware Recommendations]] [[Notebooks known to run FlightGear]] and [[Supported Video Cards]] - these should probably be updated for each release several weeks in advance.&lt;br /&gt;
&lt;br /&gt;
== 2.6 ==&lt;br /&gt;
* {{Thumbs up}} feature freeze in general&lt;br /&gt;
*: helped a lot during release management. Kept the commit traffic low and thus helped identifying those commits required to pick into the release.&lt;br /&gt;
* {{Thumbs down}} feature freeze for aircraft&lt;br /&gt;
*: Technically, a feature freeze for aircraft is not necessary as long as this aircraft is not part of the base distribution and no common parts are affected. If it's guaranteed that the changes remain in FGDATA/Aircraft/MyAircraft and no other files are touched, these updates should be OK up to shortly before the release.&lt;br /&gt;
* {{Thumbs down}} switching to a new version of supporting libraries like OSG.&lt;br /&gt;
*: The move to OSG 3.x introduced some major issues. If at all possible, switch to a new library early in the development cycle.&lt;br /&gt;
* {{Thumbs down}} manual creation of release candidates and the release binaries&lt;br /&gt;
*: It's preferable to have equal numbers for release candidates for all O/S and probably a git-tag for each candidate.&lt;br /&gt;
* {{Thumbs down}} release date/time frame&lt;br /&gt;
*: It took several days to release all the subparts. Might be better to upload all files and pages to hidden folders and publish them all at once (or at least within a couple of hours). That'll have several advantages:&lt;br /&gt;
*:* no big difference between releases for the various OS.&lt;br /&gt;
*:* the website will switch to the new release state quickly. With 2.6.0, the aircraft page was published before the setup. The release announcement was published even later.&lt;br /&gt;
&lt;br /&gt;
{{Appendix}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Core developer documentation]]&lt;br /&gt;
[[Category:FlightGear]]&lt;br /&gt;
[[Category:Release plans]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Changelog_2018.3&amp;diff=132763</id>
		<title>Changelog 2018.3</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Changelog_2018.3&amp;diff=132763"/>
		<updated>2021-08-13T17:56:18Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: /* 2018.3.3 point release */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{changelogs|prev=2018.2|next=2019.1}}&lt;br /&gt;
Available in: [[Changelog_2018.3|English]], [[Zh/2018.3|Chinese]].&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Please help us translate in other languages!&lt;br /&gt;
&lt;br /&gt;
----&amp;lt;noinclude&amp;gt;&lt;br /&gt;
[[Category:Undocumented templates]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The FlightGear development team is delighted to announce the v2018.3 release of FlightGear, the free, open-source flight simulator. This new version contains many exciting new features, enhancements and bugfixes including usability improvements to the launcher, improved scenery for Hawaii and the Arctic island of Jan Mayan, Italian, Chinese and Russian translations, better visuals for AI and MP aircraft.&lt;br /&gt;
&lt;br /&gt;
Founded in 1997, FlightGear is developed by a worldwide group of volunteers, brought together by a shared ambition to create the most realistic flight simulator possible that is free to use, modify and distribute. FlightGear is used all over the world by desktop flight simulator enthusiasts, for research in universities and for interactive exhibits in museums.&lt;br /&gt;
&lt;br /&gt;
FlightGear features more than 400 aircraft, a worldwide scenery database, a multiplayer environment, detailed sky modeling, a flexible and open aircraft modeling system, varied networking options, multiple display support, a powerful scripting language, and an open architecture. Best of all, being open-source, the simulator is owned by the community and everyone is encouraged to contribute. &lt;br /&gt;
&lt;br /&gt;
Download FlightGear v2018.3 for free from [http://www.flightgear.org/ FlightGear.org].&lt;br /&gt;
&lt;br /&gt;
FlightGear - Fly Free!&lt;br /&gt;
&lt;br /&gt;
== Usability ==&lt;br /&gt;
* Flightplan loading within the launcher.&lt;br /&gt;
* Chinese, Russian and Italian translations for the launcher and UI&lt;br /&gt;
* Improved support for the state of the aircraft depending on starting location - cold and dark on the ramp, engine running ready for take-off on the runway, or in cruise flight.&lt;br /&gt;
&lt;br /&gt;
== Input ==&lt;br /&gt;
* Improved joystick configuration and binding options.&lt;br /&gt;
&lt;br /&gt;
== AI / Multiplayer ==&lt;br /&gt;
* Multiple Levels of Detail (LoD) for MP and AI aircraft.  To improve performance, low-detail models are used when the viewer is far from the MP aircraft.&lt;br /&gt;
* Fallback models to display in the case where a viewer does not have the MP aircraft installed.&lt;br /&gt;
* Many improvements to AI models including new liveries, timetabled movements&lt;br /&gt;
&lt;br /&gt;
== Graphics ==&lt;br /&gt;
* Support for retrieving Canvas images over HTTP. This is a useful feature for displaying instruments like a PFD, ND, EICAS or any MFD externally from the FlightGear 3D main window in a separate window or on a separate monitor, computer or a mobile device. See [[Read_canvas_image_by_HTTP]] for more information.&lt;br /&gt;
* Improved cloud rendering with stronger Mie scattering on cloud fringes, improved scattering on cirrus clouds&lt;br /&gt;
* Reset: wipe the Effect UniformCache&lt;br /&gt;
&lt;br /&gt;
== Scenery ==&lt;br /&gt;
* Improved scenery for Hawaii, the default location for this release.&lt;br /&gt;
* New scenery for Jan Mayen, situated northeast of Iceland.  Including the active volcano of Beerenberg (2277m).&lt;br /&gt;
&lt;br /&gt;
== JSBSim ==&lt;br /&gt;
* The feature fail_hardover of the &amp;lt;actuator&amp;gt; component was not giving the correct output in some occurences when clipmax was smaller in absolute value than clipmin.&lt;br /&gt;
* Tables CORNERING_COEFF could not be used for BOGEY contact points.&lt;br /&gt;
* Bug fixes for JSBSim atmosphere model at very high altitudes&lt;br /&gt;
* Fixed PID integration with the 3rd order Adams-Bashforth was inccorect.&lt;br /&gt;
* The fail_stuck property of sensors (accelerometers, magnetometers, gyro, etc.) without a &amp;lt;lag&amp;gt; element was setting the output to zero instead of sticking to the last output value.&lt;br /&gt;
* When a sensor was stuck, the drift, gain, bias and quantization of the last output before being stuck were ignored.&lt;br /&gt;
* Fixed the Calibrated Air Speed (CAS) computations for supersonic velocities&lt;br /&gt;
* Fixed the Nlf (Normal load factor) sign&lt;br /&gt;
* Nlf can now be specified as an initial condition via the property ic/targetNlf&lt;br /&gt;
* Added blocking sockets to the input features&lt;br /&gt;
* Added a property to piston engines to get the AFR (Air to Fuel Ratio)&lt;br /&gt;
* Added conversion from m/s to ft/s&lt;br /&gt;
* Restored the initial conditions for engines running (-1 means all engines)&lt;br /&gt;
&lt;br /&gt;
== Significant Aircraft Updates ==&lt;br /&gt;
* &amp;quot;Metadata&amp;quot; has been added to many aircraft, making it easier to find new exciting aircraft to fly using the launcher, whether you are interested in aircraft from the 1920s or twin engined business jets.&lt;br /&gt;
* B-25 : Various bug fixes and minor improvements&lt;br /&gt;
* Cessna 172 : Improved cockpit, interior lighting.&lt;br /&gt;
* Citation II : New panels, radio instruments. Complete remodeling of the electric system, with accurate bus voltage, circuit breakers.  System test knob implemented.&lt;br /&gt;
* F4U : new FDM&lt;br /&gt;
* F-14 : V1.8.  Improved flight model, particularly in a low-speed regime. Improved cockpit.&lt;br /&gt;
* F-15 : V1.8.  Updated flight model, particularly armament mass location.  Performance optimizations.  Autopilot improvements.&lt;br /&gt;
* F-16 : v3.0.  Store options. New liveries. Radar performance optimizations. Autopilot and system improvements. FDM fixes.&lt;br /&gt;
* Saab 37 Viggen : Version 4.313. Various updates, particularly to radar and armament models.&lt;br /&gt;
* Seneca II:  Long range tanks, interior lighting,&lt;br /&gt;
* SpaceShuttle : Milestone-10. Improved interior (including furry velcro), launch guidance and orbital plane targeting, more realistic OMS burn procedures, expanded systems including circuit breaker simulation and failure modeling.&lt;br /&gt;
* 777: Our flagship airliner now fully supports checklists, allowing you to learn everything about the aircraft from within the simulator. Full support to auto-push was also implemented. Bug fixes and minor improvements.&lt;br /&gt;
&lt;br /&gt;
== Other ==&lt;br /&gt;
* [[FG1000]] glass panel display, inspired by moving map devices like the the Garmin G1000&lt;br /&gt;
* Improved Replay handling of AI aircraft and carriers - judge your own carrier landings.&lt;br /&gt;
* KC-130 tanker aircraft for air-to-air refueling&lt;br /&gt;
* Flightplan GPX import now supports elevation values.&lt;br /&gt;
* TACAN: Add support for setting TACAN by frequency&lt;br /&gt;
&lt;br /&gt;
== 2018.3.2 point release ==&lt;br /&gt;
* Chinese font support for the splash screen / tips, and some updated Chinese translations&lt;br /&gt;
* C172P bug fixes&lt;br /&gt;
* fixed crash on certain AMD 64-bit systems relating to SSE intrinsics and memory alignment&lt;br /&gt;
* fixed crash loading flightplans saved from LittleNavMap with non-sequential waypoint indices&lt;br /&gt;
* tolerate missing runways parsing Navigraph procedures, so current cycle can be used at more airports&lt;br /&gt;
* use Ref versions of osgDB methods to avoid crashes, especially after long flights&lt;br /&gt;
* fix a NaN in the sky rendering code at extreme orbital altitudes&lt;br /&gt;
* set default values of some position properties for consistency with the rest (affected C172 tie-down mode)&lt;br /&gt;
* fix JSBSim wheel-spin down regression&lt;br /&gt;
&lt;br /&gt;
== 2018.3.3 point release ==&lt;br /&gt;
* Avoid crash on Cmd-Q exit of the app on macOS&lt;br /&gt;
* JSBSim bug fixes&lt;br /&gt;
* Fix for route-path when leg 0 is not a runway&lt;br /&gt;
* Improve parsing of apt.dat header&lt;br /&gt;
* Prevent a segfault when parsing malformed nav.dat files&lt;br /&gt;
* Fix crash loading a flight-plan&lt;br /&gt;
* Tolerate missing runways parsing procedures&lt;br /&gt;
* Change screenshot filename to have date time&lt;br /&gt;
* Split up SIMD support in ENABLE_SIMD which enables sse2 support for the compiler and ENABLE_SIMD_CODE which enables the hand crafted SIMD math functions which defaults to OFF now since compilers have catched up on generating optimized vectorized SIMD code.&lt;br /&gt;
* Add some /sim/presets properties to setDefaults&lt;br /&gt;
* LOD: Multiplayer fix&lt;br /&gt;
* PID integration with the 3rd order Adams-Bashforth was inccorect.&lt;br /&gt;
* The fail_stuck property of sensors (accelerometers, magnetometers, gyro, etc.) without a &amp;lt;lag&amp;gt; element was setting the output to zero instead of sticking to the last output value. Thanks to legoboyvdlp for the bug report.&lt;br /&gt;
* When a sensor was stuck, the drift, gain, bias and quantization of the last output before being stuck were ignored. Thanks to Dennis J. Linse for the bug report.&lt;br /&gt;
* Bug fixes for JSBSim atmosphere model at very high altitudes&lt;br /&gt;
* Fix an inverted flag in Radar calculation&lt;br /&gt;
* Fix crash on Ctrl-V in PUI&lt;br /&gt;
* Fix for jumping view when right-dragging&lt;br /&gt;
* Bug fix for JSBSim.&lt;br /&gt;
* Switch to new stable-2018 catalog for the release&lt;br /&gt;
* Flight-plan: improve GPX loading&lt;br /&gt;
* Change CAVOK visibility to 9999.0 metres&lt;br /&gt;
&lt;br /&gt;
== 2018.3.4 point release ==&lt;br /&gt;
* Launcher: fix aircraft switching on update&lt;br /&gt;
* METAR fix&lt;br /&gt;
* All start from parking position with no ground net&lt;br /&gt;
* [security] Prevent buffer overrun.&lt;br /&gt;
* Arrival procedure routing fixes&lt;br /&gt;
* Avoid a warning when inserting nil into a FP&lt;br /&gt;
&lt;br /&gt;
== 2018.3.5 point release ==&lt;br /&gt;
* Joystick initialization fixes&lt;br /&gt;
* Fixes for JSB trimming&lt;br /&gt;
* [JSBSim] The sign of the XZ inertia has been fixed in the property inertia/ixz-slug_ft2 (was just an output error, the correct XZ inertia was used internally).&lt;br /&gt;
* Tweaking macOS HID code to avoid a Catalina crash&lt;br /&gt;
&lt;br /&gt;
== 2018.3.6 point release ==&lt;br /&gt;
* Fix crash on first run on macOS due to Gatekeeper&lt;br /&gt;
* Fix missing file menu on macOS when using Dutch localization&lt;br /&gt;
* Add Ctrl-F shortcut to launcher to Fly!&lt;br /&gt;
* Improve launcher aircraft searching&lt;br /&gt;
&lt;br /&gt;
== Footnotes ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Changes after 2018.2]]&lt;br /&gt;
[[Category:FlightGear changelogs]]&lt;br /&gt;
[[Zh:2018.3]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=MD-80&amp;diff=132762</id>
		<title>MD-80</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=MD-80&amp;diff=132762"/>
		<updated>2021-08-13T17:56:06Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: /* The Team */ remove personal data&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{:{{PAGENAME}}/info}}&lt;br /&gt;
&lt;br /&gt;
This is an accurate, and complex recreation of the McDonnell Douglas MD-80 by [[User:Octal450|Josh Davidson (Octal450)]]&lt;br /&gt;
&lt;br /&gt;
== MD-80 Overview ==&lt;br /&gt;
&lt;br /&gt;
Includes:&lt;br /&gt;
* MD-82 (JT8D-217A)&lt;br /&gt;
&lt;br /&gt;
See the right InfoBox for the Repository, or Download. &amp;lt;u&amp;gt;Remember to rename the aircraft's folder to &amp;quot;MD-80&amp;quot;&amp;lt;/u&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== The Team ==&lt;br /&gt;
* Flight Dynamics: Josh Davidson (Octal450)&lt;br /&gt;
* Systems: Josh Davidson (Octal450)&lt;br /&gt;
* Instruments: Josh Davidson (Octal450), legoboyvdlp, Gary Neely (Buckaroo), chad3006&lt;br /&gt;
* 3D/Textures: Gary Neely (Buckaroo), legoboyvdlp&lt;br /&gt;
&lt;br /&gt;
== Credits ==&lt;br /&gt;
Thank you to the following people for their contributions to this project!&lt;br /&gt;
* Necolatis: Help on the MFD System&lt;br /&gt;
* Various others: Liveries, Some Code, Some 3D Models, Some Textures&lt;br /&gt;
&lt;br /&gt;
== Aircraft help ==&lt;br /&gt;
{| class=&amp;quot;keytable&amp;quot;&lt;br /&gt;
! Key !! Function&lt;br /&gt;
|-&lt;br /&gt;
| {{key press|1}}&lt;br /&gt;
| Show Captains View&lt;br /&gt;
|-&lt;br /&gt;
| {{key press|2}}&lt;br /&gt;
| Show First Officers View&lt;br /&gt;
|-&lt;br /&gt;
| {{key press|3}}&lt;br /&gt;
| Show Overhead View&lt;br /&gt;
|-&lt;br /&gt;
| {{key press|4}}&lt;br /&gt;
| Show Forward Pedestal View&lt;br /&gt;
|-&lt;br /&gt;
| {{key press|5}}&lt;br /&gt;
| Show Aft Pedestal View&lt;br /&gt;
|-&lt;br /&gt;
| {{key press|6}}&lt;br /&gt;
| Show FGCP Panel View&lt;br /&gt;
|-&lt;br /&gt;
| {{key press|F1}}&lt;br /&gt;
| Disengage/Decrease Reverse Thrust&lt;br /&gt;
|-&lt;br /&gt;
| {{key press|F2}}&lt;br /&gt;
| Engage/Increase Reverse Thrust&lt;br /&gt;
|-&lt;br /&gt;
| {{key press|C}}&lt;br /&gt;
| Reset Current View&lt;br /&gt;
|-&lt;br /&gt;
| {{key press|E}}&lt;br /&gt;
| Set Idle Thrust&lt;br /&gt;
|-&lt;br /&gt;
| {{key press|F}}&lt;br /&gt;
| Set Full Thrust&lt;br /&gt;
|-&lt;br /&gt;
| {{key press|DEL}}&lt;br /&gt;
| Toggle Thrust Reversers&lt;br /&gt;
|-&lt;br /&gt;
| {{key press|CTRL|B}}&lt;br /&gt;
| Cycle Spoilers&lt;br /&gt;
|-&lt;br /&gt;
| {{key press|Shift|B}}&lt;br /&gt;
| Toggle Parking Brake&lt;br /&gt;
|-&lt;br /&gt;
| {{key press|CTRL|D}}&lt;br /&gt;
| Disconnect Autothrottle&lt;br /&gt;
|-&lt;br /&gt;
| {{key press|Shift|D}}&lt;br /&gt;
| Disconnect Autopilot&lt;br /&gt;
|-&lt;br /&gt;
| {{key press|CTRL|G}}&lt;br /&gt;
| Takeoff/Go Around Button&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{{MDouglas}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Airliners]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Release:_Airport_Selection_Criteria&amp;diff=132760</id>
		<title>Release: Airport Selection Criteria</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Release:_Airport_Selection_Criteria&amp;diff=132760"/>
		<updated>2021-08-13T17:55:04Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stub}}&lt;br /&gt;
{{Release}}&lt;br /&gt;
&lt;br /&gt;
== Intro ==&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= As we have never changed our default startup before, we should have some time for preparing the data. Would it be possible to have a decision by end of March? That would give us 6 weeks until the next release date, mid of May. &lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34868405/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] After the release is before the next&lt;br /&gt;
	release...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Torsten Dreyer&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Feb 20th, 2016&lt;br /&gt;
  | added   = Feb 20th, 2016&lt;br /&gt;
  | script_version = 0.25&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= If we want to name the next release after a different airport, we should decide now what airport this is going to be, get the airport in shape, get maybe the relevant manual pages written and get prepared. The way I see it, it'd be a terrific way for scenery developers to showcase their efforts - you've worked long and hard to make an airport and its surroundings shine - use it to impress everyone who fires up FG for the first time! The procedure I would suggest is that we first spread the word, then that airport developers (or anyone else who wants to attract users to his region of the world) makes a proposal with 2-3 screenshots outlining how the airport and the scenery look, and then we can vote (or Curt can pick one if we're too lay to vote, or I can pick one,...) I've seen Hamza's work - so we could pick a startup in the Middle East for a change. In the forum there's work on Heathrow - Jonathan, are you interested? There's been some compelling work on Rio as well. Anyone else? Please speak now, and you may be the one naming the next release :-)&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34865050/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;[Flightgear-devel] After the release is before the next release...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Thorsten Renk&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Feb 19th, 2016&lt;br /&gt;
  | added   = Feb 19th, 2016&lt;br /&gt;
  | script_version = 0.25&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= I think the proposal/vote might be good to run on the forum. I expect there are various scenery developers who don't monitor the -devel mailing list and the wider user-base of the forum may know of &amp;quot;hidden gems&amp;quot; those on this list might miss. It would also perhaps encourage a wider group of people to participate in improving the scenery. Regarding manual updates, I'm not sure there's massive value in re-writing the tutorials etc. for each new location. It would a lot of work, and the San Francisco scenery is just a download/terrasync away. Of course, it would be nice to have a well documented VFR tutorial flight as part of the release, if only to introduce virtual fliers to the area. But that can be done as an additon to The Manual, or on the wiki or main website.&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34866730/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] After the release is before the next&lt;br /&gt;
	release...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Stuart Buchanan&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Feb 19th, 2016&lt;br /&gt;
  | added   = Feb 19th, 2016&lt;br /&gt;
  | script_version = 0.25&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Status ==&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= The plan is to query the community for a new default location, to be determined within the next three weeks.&lt;br /&gt;
'''...then''' the devel community tries to make it work from there (or not) &lt;br /&gt;
&lt;br /&gt;
'''...then''' we need user feedback on what doesn't work&lt;br /&gt;
&lt;br /&gt;
'''...then''' we can do lessons learned&lt;br /&gt;
and then we start it all over - or not. So please don't discuss the process right now - such discussions won't do anything right now because we have no data either way - just focus on finding a location.&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://forum.flightgear.org/viewtopic.php?p=276840#p276840&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: Help us find the next default airport!&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Thorsten&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Feb 20th, 2016&lt;br /&gt;
  | added   = Feb 20th, 2016&lt;br /&gt;
  | script_version = 0.25&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
== Background ==&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= part of the discussion was also that the release will be known as 'San Francisco' for the default airport. And that we will change the default airport (and the name) for subsequent releases.&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34837768/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] i think 2016.x.x is a bad name&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Thorsten Renk&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Feb 10th, 2016&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= I think (anyone please chime in if this is incomplete) this'd need: &lt;br /&gt;
* an airport well-supplied with 3d models for terminals &lt;br /&gt;
* an appealing regional texture scheme around &lt;br /&gt;
* possibly definitions for AI traffic (?) - I'm not a user myself... &lt;br /&gt;
* someone to add some instructions to 'The Manual' which right now refers to KSFO (?) &lt;br /&gt;
&lt;br /&gt;
I hope we can really base the future versioning scheme on scenery object contributor's proposal to showcase their projects. So i 2016.x.x sounds like a bad name, how does 'FG 2016 Jeddah' sound?&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://sourceforge.net/p/flightgear/mailman/message/34837768/&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] i think 2016.x.x is a bad name&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;Thorsten Renk&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Feb 10th, 2016&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== XML based Default Airport ==&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= I do agree that it should be xml based; &lt;br /&gt;
nevertheless, in a seperate file perhaps, called &lt;br /&gt;
init.preferences.xml (with warnings not to change it at your &lt;br /&gt;
own risk!)&lt;br /&gt;
&lt;br /&gt;
Since this job will have to be done every 3 months or so it makes sense to do it via one file, instead of &lt;br /&gt;
'working through this mess'.&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
     | url = http://permalink.gmane.org/gmane.games.flightgear.devel/81126&lt;br /&gt;
     | title = &amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] initial aircraft position when no location specified&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     | author = &amp;lt;nowiki&amp;gt;legoboyvdlp&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     | date   = Mar 29th 2016&lt;br /&gt;
   }}&lt;br /&gt;
}}&lt;br /&gt;
== Default Starting Position with no airport or lat/lon ==&lt;br /&gt;
&lt;br /&gt;
Consider starting at a parking position on the ramp, not &lt;br /&gt;
on a runway or the center of the field!&lt;br /&gt;
Even if 3 planes start on top of each other, it is easy to &lt;br /&gt;
disconnect MP and taxi.&lt;br /&gt;
== Checklist ==&lt;br /&gt;
&lt;br /&gt;
== Roadmap ==&lt;br /&gt;
* Update multiplayer defaults, settings and instructions&lt;br /&gt;
* Update tutorials (possibly in a scripted/automated fashion)&lt;br /&gt;
* Update AI scenarios&lt;br /&gt;
* Update preferences.xml&lt;br /&gt;
* Update the manual&lt;br /&gt;
* Update the wiki&lt;br /&gt;
* Develop airport procedures (SID/STAR), as appropriate&lt;br /&gt;
* Submit missing fixes around the airport, especially RNAV approach fixes&lt;br /&gt;
* Add parking positions&lt;br /&gt;
* Check local radio frequencies (ATIS, VOR, NDB, ILS)&lt;br /&gt;
* Verify ILS parameters (heading, glideslope, lat/lon)&lt;br /&gt;
&lt;br /&gt;
== Lessons learnt ==&lt;br /&gt;
&lt;br /&gt;
[[Category: Release]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=General_Dynamics_F-16_Fighting_Falcon/info&amp;diff=132759</id>
		<title>General Dynamics F-16 Fighting Falcon/info</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=General_Dynamics_F-16_Fighting_Falcon/info&amp;diff=132759"/>
		<updated>2021-08-13T17:54:46Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: Remove personal data&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;{{infobox aircraft&lt;br /&gt;
| name           = General Dynamics F-16 Fighting Falcon&lt;br /&gt;
| hangar         = fgaddon&lt;br /&gt;
| aircraft       = f16&lt;br /&gt;
| image          = F-16C KLSV.jpg&lt;br /&gt;
| image2         = F-16C Cockpit.png&lt;br /&gt;
| alt2           = {{LangSwitch&lt;br /&gt;
                     | en = F-16CG Cockpit view&lt;br /&gt;
                     | de = F-16CG cockpit aussicht&lt;br /&gt;
                   }}&lt;br /&gt;
| type           = Military aircraft/Attack aircraft/Fighter aircraft&lt;br /&gt;
| config         = Retractable gear aircraft&lt;br /&gt;
| propulsion     = Single-engine jet&lt;br /&gt;
| manufacturer   = General Dynamics/Lockheed&lt;br /&gt;
| authors        = Erik Hofman/Pensacola/Martin &amp;quot;Pegasus&amp;quot; Schmitt/Nikolai V. Chr./J Maverick 16/Richard Harrison/Josh Davidson/Martien Van Der P./Gary Brown/Justin Nicholson/legoboyvdlp/Timi/Enrico Castaldi&lt;br /&gt;
| fdm            = JSBSim&lt;br /&gt;
| fgname1        = f16-block-10&lt;br /&gt;
| fgname2        = f16-block-20&lt;br /&gt;
| fgname3        = f16-block-30&lt;br /&gt;
| fgname4        = f16-block-32&lt;br /&gt;
| fgname5        = f16-block-40&lt;br /&gt;
| fgname6        = f16-block-42&lt;br /&gt;
| fgname7        = f16-block-50&lt;br /&gt;
| fgname8        = f16-block-52&lt;br /&gt;
| fgname9        = f16-block-60&lt;br /&gt;
| fgname10       = f16-simplified&lt;br /&gt;
| fgname11       = YF-16&lt;br /&gt;
| status-fdm     = 5&lt;br /&gt;
| status-systems = 4&lt;br /&gt;
| status-cockpit = 4&lt;br /&gt;
| status-model   = 4&lt;br /&gt;
| ready          = airrefuel/canvas/checklist&lt;br /&gt;
| liverydbid     = 20&lt;br /&gt;
| license        = GPLv2+&lt;br /&gt;
| forumtid       = 2003&lt;br /&gt;
| navbar         = 1&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/includeonly&amp;gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
This is the aircraft infobox subpage of the [[General Dynamics F-16 Fighting Falcon]].&lt;br /&gt;
[[Category:Aircraft infobox documentation]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=CH750/info&amp;diff=132758</id>
		<title>CH750/info</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=CH750/info&amp;diff=132758"/>
		<updated>2021-08-13T17:54:33Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: Remove personal data&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;{{infobox aircraft&lt;br /&gt;
| name           = Zenith Air CH750 STOL&lt;br /&gt;
| image          = CH750_at_dawn.jpg&lt;br /&gt;
| alt            = The CH750 at dawn&lt;br /&gt;
| image2         = CH750_Cockpit.jpg&lt;br /&gt;
| alt2           = The CH750 cockpit&lt;br /&gt;
| hangar         = fgaddon&lt;br /&gt;
| aircraft       = CH750STOL&lt;br /&gt;
| type           = Civil aircraft/Civil utility aircraft&lt;br /&gt;
| config         = High wing aircraft/Fixed gear aircraft&lt;br /&gt;
| propulsion     = Propeller aircraft/Single-engine aircraft&lt;br /&gt;
| manufacturer   = Zenith Air&lt;br /&gt;
| authors        = hydroz.net (X-Plane model used as 3d base for this aircraft)/Legoboyvdlp/D-ECHO&lt;br /&gt;
| fdm            = JSBSim&lt;br /&gt;
| fgname         = CH750&lt;br /&gt;
| status-fdm     = 1&lt;br /&gt;
| status-systems = 3&lt;br /&gt;
| status-cockpit = 4&lt;br /&gt;
| status-model   = 3&lt;br /&gt;
| wikipedia      = Zenith_STOL_CH_701&lt;br /&gt;
| navbar         = 1&lt;br /&gt;
}}&amp;lt;/includeonly&amp;gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
This is the aircraft infobox subpage of the [[CH750]].&lt;br /&gt;
[[Category:Aircraft infobox documentation]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=MD-80/info&amp;diff=132757</id>
		<title>MD-80/info</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=MD-80/info&amp;diff=132757"/>
		<updated>2021-08-13T17:54:21Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: Remove personal data&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;{{infobox aircraft&lt;br /&gt;
| name           = McDonnell Douglas MD-80&lt;br /&gt;
| hangar         = Octal450&lt;br /&gt;
| aircraft       = MD-80&lt;br /&gt;
| image          = MD-80.png&lt;br /&gt;
| alt            = The MD-80&lt;br /&gt;
| type           = Airliner&lt;br /&gt;
| config         = Low wing aircraft/Monoplane aircraft/Retractable gear aircraft/Tricycle landing gear aircraft&lt;br /&gt;
| propulsion     = Twinjet&lt;br /&gt;
| manufacturer   = McDonnell Douglas&lt;br /&gt;
| authors        = Josh Davidson (Octal450)/Gary Neely (Buckaroo)/ legoboyvdlp&lt;br /&gt;
| fdm            = JSBsim&lt;br /&gt;
| status-fdm     = 4&lt;br /&gt;
| status-systems = 2&lt;br /&gt;
| status-cockpit = 3&lt;br /&gt;
| status-model   = 4&lt;br /&gt;
| navbar         = 1&lt;br /&gt;
| ready          = canvas&lt;br /&gt;
| forumtid       = 38797&lt;br /&gt;
}}&amp;lt;/includeonly&amp;gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
This is the aircraft infobox subpage of the [[MD-80]].&lt;br /&gt;
[[Category:Aircraft infobox documentation]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Pottier_P130_UltraLight/info&amp;diff=132756</id>
		<title>Pottier P130 UltraLight/info</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Pottier_P130_UltraLight/info&amp;diff=132756"/>
		<updated>2021-08-13T17:54:01Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: Personal data removal&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;{{infobox aircraft&lt;br /&gt;
| name           = Pottier P130UL Coccinelle&lt;br /&gt;
| hangar         = fgaddon&lt;br /&gt;
| aircraft       = P130UL&lt;br /&gt;
| type           = Ultralight aircraft&lt;br /&gt;
| config         = High wing aircraft&lt;br /&gt;
| propulsion     = Propeller aircraft&lt;br /&gt;
| manufacturer   = Jean Pottier&lt;br /&gt;
| author1        = {{usr|Legoboyvdlp}}&lt;br /&gt;
| author2        = {{usr|D-ECHO}}&lt;br /&gt;
| author3        = Hydroz.net (3D model)&lt;br /&gt;
| fdm            = JSBSim&lt;br /&gt;
| fgname         = p130ul&lt;br /&gt;
| status-fdm     = 1&lt;br /&gt;
| status-systems = 0&lt;br /&gt;
| status-cockpit = 3&lt;br /&gt;
| status-model   = 1&lt;br /&gt;
| navbar         = 1&lt;br /&gt;
}}&amp;lt;/includeonly&amp;gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
This is the aircraft infobox subpage of the [[Pottier P130 UltraLight]].&lt;br /&gt;
[[Category:Aircraft infobox documentation]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Bombardier_CSeries/info&amp;diff=132748</id>
		<title>Bombardier CSeries/info</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Bombardier_CSeries/info&amp;diff=132748"/>
		<updated>2021-08-12T21:08:07Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: remove full name&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;&lt;br /&gt;
{{infobox aircraft&lt;br /&gt;
| name           = C-Series&lt;br /&gt;
| image          = CS300IRL.jpg&lt;br /&gt;
| alt            = CS300 departing CYUL (IRL)&lt;br /&gt;
| type           = Civil aircraft/Airliner/Regional Airliner&lt;br /&gt;
| config         = Retractable gear aircraft &lt;br /&gt;
| propulsion     = Twinjet&lt;br /&gt;
| manufacturer   = Bombardier Aerospace&lt;br /&gt;
| author1        = ACJZA &lt;br /&gt;
| author2        = Joshua Davidson (Octal450)&lt;br /&gt;
| author3        = legoboyvdlp&lt;br /&gt;
| author4        = D-ECHO&lt;br /&gt;
| author5        = Suleman Siddiqui (Pakistan-1)&lt;br /&gt;
| author6        = Gabriel Hernandez (YV3399)&lt;br /&gt;
| author7        = Israel Hernandez (IAHM-COL)&lt;br /&gt;
| author8        = Wesley Ou (C-FWES)&lt;br /&gt;
| fdm            = YASim&lt;br /&gt;
| fgname         = CS100/CS300&lt;br /&gt;
| status         = dev&lt;br /&gt;
&lt;br /&gt;
| ready          = canvas/checklist/tutorials &lt;br /&gt;
| devel-website  = https://github.com/Next-Level-Simulations/CSeries&lt;br /&gt;
| devel-repo     = https://github.com/Next-Level-Simulations/CSeries&lt;br /&gt;
| download       = https://github.com/Next-Level-Simulations/CSeries&lt;br /&gt;
| forumtid       = 19859&lt;br /&gt;
| navbar         = 1&lt;br /&gt;
| navbarlevel    =&lt;br /&gt;
}}&amp;lt;/includeonly&amp;gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
This is the aircraft infobox subpage of the [[{{#titleparts:{{PAGENAME}}|1}}]].&lt;br /&gt;
[[Category:Aircraft infobox documentation]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Canvas_Nasal_API&amp;diff=132384</id>
		<title>Canvas Nasal API</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Canvas_Nasal_API&amp;diff=132384"/>
		<updated>2021-06-17T17:57:12Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: /* get */  Explain that you can fetch the character size&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:Canvas Navigation}}&lt;br /&gt;
&lt;br /&gt;
Canvas consist of a class with various nestable classes (elements).&lt;br /&gt;
&lt;br /&gt;
See inside the current (Git) API {{fgdata source|Nasal/canvas/api.nas|text=here}} and {{simgear source|simgear/canvas/|text=here}}.&lt;br /&gt;
&lt;br /&gt;
'''For the Canvas GUI API see [[Canvas GUI API]]'''&lt;br /&gt;
&lt;br /&gt;
== Canvas ==&lt;br /&gt;
For constructor see: [[Howto:Add_a_2D_canvas_instrument_to_your_aircraft#Initialize_a_Canvas|Initialize a Canvas]]&lt;br /&gt;
=== addPlacement ===&lt;br /&gt;
{{Note|It is possible to place a canvas on models in the scene. Tom has not tested if it also works for MP/AI aircraft but it should. The placement in scenery objects needs a different placement type to select also the model it should be placed on. For scenery objects a special placement exists: &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var placement = { &amp;quot;module-id&amp;quot;: _module_id, type: &amp;quot;scenery-object&amp;quot;, &amp;lt;normal placement parameters like eg. node&amp;gt; }&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'_module_id' is a special variable which is only set in scenery object &amp;lt;load&amp;gt; handlers.&amp;lt;ref&amp;gt;{{cite web&lt;br /&gt;
  |url    =  https://sourceforge.net/p/flightgear/mailman/message/35093833/ &lt;br /&gt;
  |title  =  &amp;lt;nowiki&amp;gt; Re: [Flightgear-devel] Canvas in dynamically loaded scene models &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |author =  &amp;lt;nowiki&amp;gt; Thomas Geymayer &amp;lt;/nowiki&amp;gt; &lt;br /&gt;
  |date   =  May 17th, 2016 &lt;br /&gt;
  |added  =  May 17th, 2016 &lt;br /&gt;
  |script_version = 0.40 &lt;br /&gt;
  }}&amp;lt;/ref&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
See: [[Howto:Add_a_2D_canvas_instrument_to_your_aircraft#Place_it_somewhere_on_your_aircraft|Place a Canvas]]&lt;br /&gt;
&lt;br /&gt;
=== setColorBackground ===&lt;br /&gt;
'''Parameters:''' (r, g, b, a)&lt;br /&gt;
&lt;br /&gt;
Fills the background of the entire canvas with the supplied color.&lt;br /&gt;
=== createGroup ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:''' (name)&lt;br /&gt;
&lt;br /&gt;
'''Returns:''' Group&lt;br /&gt;
&lt;br /&gt;
Create a new group under this Canvas. Supplying name is optional.&lt;br /&gt;
=== getPath ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
?&lt;br /&gt;
=== del ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
Deletes this Canvas.&lt;br /&gt;
=== wrapCanvas ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
?&lt;br /&gt;
=== get ===&lt;br /&gt;
'''Parameters:''' (name)&lt;br /&gt;
&lt;br /&gt;
'''Returns:''' Canvas&lt;br /&gt;
&lt;br /&gt;
Returns the canvas with the specified name.&lt;br /&gt;
&lt;br /&gt;
Possible settings&lt;br /&gt;
&lt;br /&gt;
* character-size - font size&lt;br /&gt;
* character-aspect-ratio - font aspect ratio&lt;br /&gt;
* ... please contribute and expand this list!&lt;br /&gt;
&lt;br /&gt;
=== set ===&lt;br /&gt;
'''Parameters:''' (setting, value)&lt;br /&gt;
&lt;br /&gt;
Not sure all the below settings can be used after initialization.&lt;br /&gt;
&lt;br /&gt;
Settings can be: &lt;br /&gt;
&lt;br /&gt;
&amp;quot;name&amp;quot; string&lt;br /&gt;
&lt;br /&gt;
&amp;quot;size&amp;quot; vector of size 2 with ints&lt;br /&gt;
&lt;br /&gt;
&amp;quot;view&amp;quot; vector of size 2 with ints&lt;br /&gt;
&lt;br /&gt;
&amp;quot;mipmapping&amp;quot; bool&lt;br /&gt;
&lt;br /&gt;
&amp;quot;additive-blend&amp;quot; bool&lt;br /&gt;
&lt;br /&gt;
&amp;quot;coverage-samples&amp;quot; int&lt;br /&gt;
&lt;br /&gt;
&amp;quot;color-samples&amp;quot; int&lt;br /&gt;
&lt;br /&gt;
&amp;quot;freeze&amp;quot; bool&lt;br /&gt;
&lt;br /&gt;
&amp;quot;render-always&amp;quot; bool&lt;br /&gt;
&lt;br /&gt;
&amp;quot;update&amp;quot; bool&lt;br /&gt;
&lt;br /&gt;
=== parsesvg ===&lt;br /&gt;
'''Parameters:''' (group, file)&lt;br /&gt;
&lt;br /&gt;
'''Parameters:''' (group, file, font-mapper)&lt;br /&gt;
&lt;br /&gt;
See: [[Howto:Use_SVG_inside_a_Canvas|SVG inside a Canvas]]&lt;br /&gt;
== Element == &lt;br /&gt;
Note that in each element there are 2 transformation matrices. The first will be applied first, then the second.&lt;br /&gt;
&lt;br /&gt;
=== set ===&lt;br /&gt;
'''Parameters:''' (key, value)&lt;br /&gt;
&lt;br /&gt;
''Key = &amp;quot;z-index&amp;quot;:''&lt;br /&gt;
&lt;br /&gt;
Default value = 0&lt;br /&gt;
&lt;br /&gt;
Minimum value = 0&lt;br /&gt;
&lt;br /&gt;
Integer value indicates the explicit Z sort order, highest on top. If this is not set, elements that are added later gets drawn on top.&lt;br /&gt;
Notice that if you have for example two paths inside their own groups, and you want to order those paths in relation to each other, its on their groups you should call this method, not on the paths themselves.&lt;br /&gt;
&lt;br /&gt;
FG 2.10.0.3: Elements added after z-index has been set will overrule it. (fix is in GIT)&lt;br /&gt;
&lt;br /&gt;
''Key = &amp;quot;blend-source&amp;quot;:''&lt;br /&gt;
&lt;br /&gt;
''Key = &amp;quot;blend-destination&amp;quot;:''&lt;br /&gt;
&lt;br /&gt;
''Key = &amp;quot;blend-source-rgb&amp;quot;:''&lt;br /&gt;
&lt;br /&gt;
''Key = &amp;quot;blend-destination-rgb&amp;quot;:''&lt;br /&gt;
&lt;br /&gt;
''Key = &amp;quot;blend-source-alpha&amp;quot;:''&lt;br /&gt;
&lt;br /&gt;
''Key = &amp;quot;blend-destination-alpha&amp;quot;:''&lt;br /&gt;
&lt;br /&gt;
These are blending operations, they determine how a texel is drawn based on what your current element want to draw (source) and what is already drawn at this texel (destination).&lt;br /&gt;
&lt;br /&gt;
For example for the 2 first listed keys, the formula is ''output_color = (blend_source * src_color) + (blend_destination * dst_color).''&lt;br /&gt;
&lt;br /&gt;
The value for the keys can be one of: (string)&lt;br /&gt;
&lt;br /&gt;
''zero, one, dst-color, src-color, one-minus-dst-color, one-minus-src-color, src-alpha, dst-alpha, one-minus-dst-alpha, one-minus-src-alpha, src-alpha-saturate''&lt;br /&gt;
&lt;br /&gt;
You can see the formulas [[https://web.cs.ship.edu/~djmoon/cg/cg-notes/cg-ogl-blending.pdf here]]&lt;br /&gt;
&lt;br /&gt;
With a little creativity these can be used for many things, like creating custom clipping geometry and other stuff.&lt;br /&gt;
&lt;br /&gt;
NOTICE: Blending does NOT work for paths. They are confirmed to work with text and images though.&lt;br /&gt;
&lt;br /&gt;
=== update ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
Normally an element gets updated in the next frame. Calling this will make it update in the current frame.&lt;br /&gt;
Note that visibility methods do get updated in the current frame.&lt;br /&gt;
=== getVisible ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
'''Returns:''' visible&lt;br /&gt;
&lt;br /&gt;
Returns 0 if not visible, 1 if visible.&lt;br /&gt;
=== setVisible ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:''' (visible)&lt;br /&gt;
&lt;br /&gt;
Sets if this element should be visible. 0 sets it not visible, 1 visible. No parameters sets it visible.&lt;br /&gt;
=== show ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
Sets the element visible.&lt;br /&gt;
=== hide ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
Sets the element not visible.&lt;br /&gt;
=== toggleVisibility ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
Toggles if element should be visible.&lt;br /&gt;
=== setGeoPosition ===&lt;br /&gt;
'''Parameters:''' (lat, lon)&lt;br /&gt;
&lt;br /&gt;
Sets the geographic coordinates for a map element. Parent element must be of type &amp;quot;map&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
'''Example:''' setGeoPosition(37.615223, -122.389978)&lt;br /&gt;
&lt;br /&gt;
Places element at [[San Francisco International Airport]].&lt;br /&gt;
&lt;br /&gt;
=== createTransform ===&lt;br /&gt;
createTransform creates a new matrix on top of the existing matrix stack. A while ago I've added an example for a HUD built using the Canvas to the wiki: [[Canvas HUD]]&lt;br /&gt;
It doesn't use SVG but manually creates everything instead. As loading an SVG should basically do the same than handcrafting icons there shouldn't be much of a difference.&lt;br /&gt;
&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:''' ([a, b, c, d, e, f])&lt;br /&gt;
&lt;br /&gt;
'''Return:''' The new (second) transform &lt;br /&gt;
&lt;br /&gt;
Creates a new (second) transformation matrix for this element. No parameters will create a default identity matrix transform. Otherwise supply a 6 element vector for the matrix:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| a || b || c&lt;br /&gt;
|-&lt;br /&gt;
| d || e || f &lt;br /&gt;
|-&lt;br /&gt;
| 0 || 0 || 1 &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
You should probably change the order of creating the transforms for pitch and roll as normally one would rotate first and then move according to roll and then move according to pitch up and down. Keep in mind that rotations always happens around the origin of the local coordinate frame of the object being rotated. For a rotation around another point you would need to move the object first until the center coincides with the local origin then rotate and afterwards move back. Instead of applying three transformations there exists a shortcut to pass the center of rotation as second argument to setRotation.&lt;br /&gt;
&lt;br /&gt;
To further shorten the code an especially to allow rotating objects imported from SVG there exists setRotation also for canvas Elements (not only Transformation) and additionally setCenter which instead of passing the center as an argument sets the center which is being used while calling setRotation on this element. setCenter only affects setRotation of this not object but not for any matrix added with createTransform. If you set the center of rotation in Inkscape (switch to rotate mode and drag the cross to the center of rotation) it is automatically loaded with setCenter so you just need to call setRotation and automatically get a rotation around the correct center.&lt;br /&gt;
&lt;br /&gt;
You don't need to care about tf[0] being reserved as it only reserves the index 0 and doesn't affect anything if not used. createTransform creates a new matrix with the next unused index starting at 1 (0 is reserved). If you later call setRotation directly on an element a new Transform will be created but this time using tf[0] to ensure it is applied before all other matrices and therefore rotating the object around its own center before being moved around.&lt;br /&gt;
&lt;br /&gt;
For the HUD I'd set the rotation center correctly inside Inkscape and later on just call ladder.setRotation to rotate for changes in the roll angle. Afterwards create a Transform and use setTranslate for changes in pitch angle.&lt;br /&gt;
&lt;br /&gt;
=== setTranslation ===&lt;br /&gt;
'''Parameters:''' (x, y)&lt;br /&gt;
&lt;br /&gt;
Translates the element. The translation is set on the second transform.&lt;br /&gt;
=== setRotation ===&lt;br /&gt;
'''Parameters:''' (x, y)&lt;br /&gt;
&lt;br /&gt;
Rotates the element around the center. The rotation is set on the first transform.&lt;br /&gt;
&lt;br /&gt;
setRotation really just combines a rotation with two translations -&amp;gt; translate(-center[0], -center[1]) * rotate * translate(center[0], center[1])&lt;br /&gt;
&lt;br /&gt;
You can also have a look in the property browser and check the bounding box (/canvas/by-index/texture[i]/[group[j]+]/path[j]/bounding-box) and use its coordinates to determine the correct center of rotation.&lt;br /&gt;
&lt;br /&gt;
=== setScale ===&lt;br /&gt;
'''Parameters:''' (x, y)&lt;br /&gt;
&lt;br /&gt;
Scales the element. The scale is set on the second transform.&lt;br /&gt;
=== getScale ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
'''Return:''' 2 element vector [x,y]&lt;br /&gt;
&lt;br /&gt;
Returns the scale of this element.&lt;br /&gt;
=== setColorFill ===&lt;br /&gt;
'''Parameters:''' (r, g, b)&lt;br /&gt;
&lt;br /&gt;
'''Parameters:''' (r, g, b, a)&lt;br /&gt;
&lt;br /&gt;
Sets the color/alpha to be used as fill value. If you do not want the element to be filled, do not call this method.&lt;br /&gt;
=== getBoundingBox ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
'''Returns:''' [minX, minY, maxX, maxY]&lt;br /&gt;
&lt;br /&gt;
Returns the bounds of the element.&lt;br /&gt;
=== updateCenter ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
Sets the center to be the center of the boundingbox in relation to the elements position in its parent.&lt;br /&gt;
=== setCenter ===&lt;br /&gt;
'''Parameters:''' (x, y)&lt;br /&gt;
&lt;br /&gt;
Sets the center of the element that is used for rotation.&lt;br /&gt;
=== getCenter ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
Gets the center of the element.&lt;br /&gt;
&lt;br /&gt;
== Group ==&lt;br /&gt;
Inherits from Element.&lt;br /&gt;
=== set ===&lt;br /&gt;
'''Parameters:''' (key, value)&lt;br /&gt;
&lt;br /&gt;
''key = &amp;quot;clip&amp;quot;''&lt;br /&gt;
{{Note|&lt;br /&gt;
{{FGCquote&lt;br /&gt;
|1= Scaling or any other type of transformation or changing the coordinates of individual points is definitely more efficient than clipping (which requires to change the OpenGL clip planes for every rendered object with a different clipping rectangle).&lt;br /&gt;
|2= {{cite web&lt;br /&gt;
  | url    = http://forum.flightgear.org/viewtopic.php?p=277062#p277062&lt;br /&gt;
  | title  = &amp;lt;nowiki&amp;gt;Re: Space Shuttle&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | author = &amp;lt;nowiki&amp;gt;TheTom&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  | date   = Feb 21st, 2016&lt;br /&gt;
  | added   = Feb 21st, 2016&lt;br /&gt;
  | script_version = 0.25&lt;br /&gt;
  }}&lt;br /&gt;
}}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Makes a clipping bounds for the group, only what is inside the clipping bounds will be shown.&lt;br /&gt;
&lt;br /&gt;
It uses same coordinate format as [http://www.w3.org/TR/CSS21/visufx.html#clipping Clipping]&lt;br /&gt;
&lt;br /&gt;
'''Example:''' my_grp.set(&amp;quot;clip&amp;quot;, &amp;quot;rect(62px, 587px, 262px, 437px)&amp;quot;); # top,right,bottom,left&lt;br /&gt;
&lt;br /&gt;
''key = &amp;quot;clip-frame&amp;quot;''&lt;br /&gt;
&lt;br /&gt;
Sets the coordinate system to be used for clip coordinates.&lt;br /&gt;
&lt;br /&gt;
Can be canvas.Element.GLOBAL (the default value), canvas.Element.PARENT or canvas.Element.LOCAL&lt;br /&gt;
&lt;br /&gt;
Notice that if set to local or parent and there is a rotation is play, the clipping wont rotate properly, it will move around and scale instead.&lt;br /&gt;
&lt;br /&gt;
''key = &amp;quot;font&amp;quot;''&lt;br /&gt;
&lt;br /&gt;
Sets the default font.&lt;br /&gt;
&lt;br /&gt;
'''Example:''' my_group.set(&amp;quot;font&amp;quot;, &amp;quot;LiberationFonts/LiberationMono-Regular.ttf&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
''key = &amp;quot;stroke&amp;quot;''&lt;br /&gt;
&lt;br /&gt;
?&lt;br /&gt;
&lt;br /&gt;
''key = &amp;quot;fill&amp;quot;''&lt;br /&gt;
&lt;br /&gt;
?&lt;br /&gt;
&lt;br /&gt;
=== setDouble ===&lt;br /&gt;
'''Parameters:''' (key, value)&lt;br /&gt;
&lt;br /&gt;
''key = &amp;quot;character-aspect-ration&amp;quot;''&lt;br /&gt;
&lt;br /&gt;
?&lt;br /&gt;
&lt;br /&gt;
''key = &amp;quot;character-size&amp;quot;''&lt;br /&gt;
&lt;br /&gt;
?&lt;br /&gt;
&lt;br /&gt;
=== createChild ===&lt;br /&gt;
'''Parameters:''' (type)&lt;br /&gt;
&lt;br /&gt;
'''Parameters:''' (type, name)&lt;br /&gt;
&lt;br /&gt;
'''Returns:''' Element&lt;br /&gt;
&lt;br /&gt;
Creates a child element under this Group. Name can be supplied. Type can be &amp;quot;text&amp;quot;, &amp;quot;group&amp;quot;, &amp;quot;path&amp;quot;, &amp;quot;image&amp;quot;, &amp;quot;map&amp;quot;.&lt;br /&gt;
Return an Element of the particular type specified.&lt;br /&gt;
=== createChildren ===&lt;br /&gt;
'''Parameters:''' (type, count)&lt;br /&gt;
&lt;br /&gt;
'''Returns:''' [Element]&lt;br /&gt;
&lt;br /&gt;
Creates a number of child elements under this Group. Return a vector of Elements of the particular type specified.&lt;br /&gt;
=== getChildren ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
'''Returns:''' [Element]&lt;br /&gt;
&lt;br /&gt;
Returns all the child elements of this group.&lt;br /&gt;
=== getElementById ===&lt;br /&gt;
'''Parameters:''' (name)&lt;br /&gt;
&lt;br /&gt;
'''Returns:''' Element&lt;br /&gt;
&lt;br /&gt;
Returns the first found child element with the specified name.&lt;br /&gt;
=== removeAllChildren ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
Removes all the child elements from this group.&lt;br /&gt;
== Text ==&lt;br /&gt;
Inherits from Element.&lt;br /&gt;
&lt;br /&gt;
=== enableUpdate ===&lt;br /&gt;
&lt;br /&gt;
Enables the updateText() method for a text element.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== setText ===&lt;br /&gt;
'''Parameters:''' (text)&lt;br /&gt;
&lt;br /&gt;
Sets the text to be displayed.&lt;br /&gt;
&lt;br /&gt;
=== updateText ===&lt;br /&gt;
'''Parameters:''' (text)&lt;br /&gt;
&lt;br /&gt;
The setText method internally writes the text string into a property node. If the method is run inside an update loop (as usually done for displays), setText writes the property regardless of whether the text has actually changed in the last update cycle. For complicated displays, this may cause a lot of unnecessary property I/O slowing down the simulation.&lt;br /&gt;
&lt;br /&gt;
To improve this, updateText() keeps a Nasal variable record of the last text that has been written and writes the property only if the text has changed. Since this record needs to be allocated, the method requires to call enableUpdate() once before using it.&lt;br /&gt;
&lt;br /&gt;
Note also that updateText() and setText() should not be both used on the same text element (updateText() will not register any changes made to the property string by any other means).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== setAlignment ===&lt;br /&gt;
'''Parameters:''' (alignment)&lt;br /&gt;
&lt;br /&gt;
Sets how the text should be aligned with its position.&lt;br /&gt;
&lt;br /&gt;
Full list:&lt;br /&gt;
* left-top&lt;br /&gt;
* left-center&lt;br /&gt;
* left-bottom&lt;br /&gt;
* center-top&lt;br /&gt;
* center-center&lt;br /&gt;
* center-bottom&lt;br /&gt;
* right-top&lt;br /&gt;
* right-center&lt;br /&gt;
* right-bottom&lt;br /&gt;
* left-baseline&lt;br /&gt;
* center-baseline&lt;br /&gt;
* right-baseline&lt;br /&gt;
* left-bottom-baseline&lt;br /&gt;
* center-bottom-baseline&lt;br /&gt;
* right-bottom-baseline&lt;br /&gt;
&lt;br /&gt;
=== setFontSize ===&lt;br /&gt;
'''Parameters:''' (size, aspectRatio)&lt;br /&gt;
&lt;br /&gt;
Sets the size and aspectRatio of the font. AspectRatio is the Ratio between character height and width. Default aspectRatio is 1.&lt;br /&gt;
=== setFont ===&lt;br /&gt;
'''Parameters:''' (fontName)&lt;br /&gt;
&lt;br /&gt;
Sets the font to be used. See [[$FG_ROOT]]/Fonts for list of fonts.&lt;br /&gt;
&lt;br /&gt;
=== setDrawMode ===&lt;br /&gt;
'''Parameters:''' (mode)&lt;br /&gt;
&lt;br /&gt;
Sets the drawing mode. You can use the values below and add those you need.&lt;br /&gt;
&lt;br /&gt;
'''Text.TEXT:''' Draws the text&lt;br /&gt;
&lt;br /&gt;
'''Text.BOUNDINGBOX:''' Draws the boundingbox&lt;br /&gt;
&lt;br /&gt;
'''Text.FILLEDBOUNDINGBOX:''' Draws the filled boundingbox&lt;br /&gt;
&lt;br /&gt;
'''Text.ALIGNMENT:''' Draws a cross where the element position is&lt;br /&gt;
&lt;br /&gt;
'''Example:''' my_text.setDrawMode(Text.TEXT + Text.BOUNDINGBOX);&lt;br /&gt;
=== setPadding ===&lt;br /&gt;
Sets bounding box padding&lt;br /&gt;
&lt;br /&gt;
=== setMaxWidth ===&lt;br /&gt;
?&lt;br /&gt;
=== setColor ===&lt;br /&gt;
'''Parameters:''' (r, g, b)&lt;br /&gt;
&lt;br /&gt;
'''Parameters:''' (r, g, b, a)&lt;br /&gt;
&lt;br /&gt;
Sets the color the text should be drawn in.&lt;br /&gt;
=== setColorFill ===&lt;br /&gt;
'''Parameters:''' (r, g, b)&lt;br /&gt;
&lt;br /&gt;
'''Parameters:''' (r, g, b, a)&lt;br /&gt;
&lt;br /&gt;
Sets the color the text background should be drawn in.&lt;br /&gt;
&lt;br /&gt;
== Path ==&lt;br /&gt;
Inherits from Element.&lt;br /&gt;
&lt;br /&gt;
A path is similar to drawing with a pen on paper. The move and moveTo methods represent lifting the pen from the paper and moving to a new position. The drawing methods like lineTo would then be seen as starting from the current position of the pen. Therefore offcouse the order the methods is called in, is important.&lt;br /&gt;
=== pop_front ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
Remove first segment&lt;br /&gt;
=== pop_back ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
Remove last segment&lt;br /&gt;
=== getNumSegments ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
Get the number of segments&lt;br /&gt;
=== reset ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
Remove all existing path data&lt;br /&gt;
=== moveTo ===&lt;br /&gt;
'''Parameters:''' (x, y)&lt;br /&gt;
&lt;br /&gt;
Moves the position to an new absolute position.&lt;br /&gt;
=== move ===&lt;br /&gt;
'''Parameters:''' (x, y)&lt;br /&gt;
&lt;br /&gt;
Moves the position to a new relative position from the current.&lt;br /&gt;
=== lineTo ===&lt;br /&gt;
'''Parameters:''' (x, y)&lt;br /&gt;
&lt;br /&gt;
Draws a line to specified position.&lt;br /&gt;
=== line ===&lt;br /&gt;
'''Parameters:''' (x, y)&lt;br /&gt;
&lt;br /&gt;
Draws a line to specified relative position.&lt;br /&gt;
=== horizTo ===&lt;br /&gt;
'''Parameters:''' (x)&lt;br /&gt;
&lt;br /&gt;
Draws a horizontal line to specified position.&lt;br /&gt;
=== horiz ===&lt;br /&gt;
'''Parameters:''' (x)&lt;br /&gt;
&lt;br /&gt;
Draws a horizontal line to specified relative position.&lt;br /&gt;
=== vertTo ===&lt;br /&gt;
'''Parameters:''' (y)&lt;br /&gt;
&lt;br /&gt;
Draws a vertical line to specified position.&lt;br /&gt;
=== vert ===&lt;br /&gt;
'''Parameters:''' (y)&lt;br /&gt;
&lt;br /&gt;
Draws a vertical line to specified relative position.&lt;br /&gt;
=== quadTo ===&lt;br /&gt;
'''Parameters:''' (x0, y0, x1, y1)&lt;br /&gt;
&lt;br /&gt;
Draws quadratic Bézier curve.&lt;br /&gt;
=== quad ===&lt;br /&gt;
'''Parameters:''' (x0, y0, x1, y1)&lt;br /&gt;
&lt;br /&gt;
Draws quadratic Bézier curve. Relative coordinates.&lt;br /&gt;
=== squadTo ===&lt;br /&gt;
'''Parameters:''' (x, y)&lt;br /&gt;
&lt;br /&gt;
Draws smooth quadratic Bézier curve.&lt;br /&gt;
=== squad ===&lt;br /&gt;
'''Parameters:''' (x, y)&lt;br /&gt;
&lt;br /&gt;
Draws smooth quadratic Bézier curve. Relative coordinates.&lt;br /&gt;
=== cubicTo ===&lt;br /&gt;
'''Parameters:''' (x0, y0, x1, y1, x2, y2)&lt;br /&gt;
&lt;br /&gt;
Draws cubic Bézier curve.&lt;br /&gt;
=== cubic ===&lt;br /&gt;
'''Parameters:''' (x0, y0, x1, y1, x2, y2)&lt;br /&gt;
&lt;br /&gt;
Draws cubic Bézier curve. Relative coordinates.&lt;br /&gt;
=== scubicTo ===&lt;br /&gt;
'''Parameters:''' (x, y, x2, y2)&lt;br /&gt;
&lt;br /&gt;
Add a smooth cubic Bézier curve&lt;br /&gt;
=== scubic ===&lt;br /&gt;
'''Parameters:''' (x, y)&lt;br /&gt;
&lt;br /&gt;
Add a smooth cubic Bézier curve. Relative coordinates.&lt;br /&gt;
=== rect ===&lt;br /&gt;
'''Parameters:''' (x, y, w, h, cfg = nil)&lt;br /&gt;
&lt;br /&gt;
cfg:  Optional settings (eg. {&amp;quot;border-top-radius&amp;quot;: 5}, {&amp;quot;border-bottom-radius&amp;quot;: 5}, {&amp;quot;border-radius&amp;quot;: 5}, {&amp;quot;border-bottom-right-radius&amp;quot;: 5} or {&amp;quot;border-left-radius&amp;quot;: 5})&lt;br /&gt;
&lt;br /&gt;
Add a (rounded) rectangle to the path&lt;br /&gt;
&lt;br /&gt;
=== square ===&lt;br /&gt;
''' available on next, expected release 2019.1 '''&lt;br /&gt;
&lt;br /&gt;
'''Parameters:''' (x, y, length, cfg = nil)&lt;br /&gt;
&lt;br /&gt;
alias for rect(x, y, length, length, cfg)&lt;br /&gt;
&lt;br /&gt;
Add a (rounded) square to the path&lt;br /&gt;
&lt;br /&gt;
=== arcSmallCCWTo ===&lt;br /&gt;
=== arcSmallCCW ===&lt;br /&gt;
=== arcSmallCWTo ===&lt;br /&gt;
=== arcSmallCW ===&lt;br /&gt;
'''Parameters:''' (xRadius, yRadius,0,xEnd,yEnd)&lt;br /&gt;
&lt;br /&gt;
Draws an arc with the specified radii, up to the specified end point. The end point is relative to the starting point.&lt;br /&gt;
&lt;br /&gt;
To draw half a circle with radius 20 around the origin:&lt;br /&gt;
 .moveTo(-20,0)&lt;br /&gt;
 .arcSmallCW(20,20,0,40,0);&lt;br /&gt;
&lt;br /&gt;
To draw a circle with radius 20 around the origin:&lt;br /&gt;
 .moveTo(-20,0)&lt;br /&gt;
 .arcSmallCW(20,20,0,40,0)&lt;br /&gt;
 .arcSmallCW(20,20,0,-40,0);&lt;br /&gt;
&lt;br /&gt;
=== arcLargeCCWTo ===&lt;br /&gt;
=== arcLargeCCW ===&lt;br /&gt;
=== arcLargeCWTo ===&lt;br /&gt;
=== arcLargeCW ===&lt;br /&gt;
&lt;br /&gt;
Drawing arcs examples : &lt;br /&gt;
[[File:Canvas arc.png|thumb|Canvas arc draw examples]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
	var fpv = group.createChild(&amp;quot;group&amp;quot;, &amp;quot;FPV&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        fpv.createChild(&amp;quot;path&amp;quot;).setStrokeLineWidth(4).set(&amp;quot;stroke&amp;quot;, &amp;quot;rgba(255,0,255,1)&amp;quot;)&lt;br /&gt;
        .moveTo(100, 100).arcSmallCCW(50, 50, 0,  50, 50);&lt;br /&gt;
        fpv.createChild(&amp;quot;path&amp;quot;).setStrokeLineWidth(4) .set(&amp;quot;stroke&amp;quot;, &amp;quot;rgba(255,0,255,1)&amp;quot;)&lt;br /&gt;
        .moveTo(300, 100).arcSmallCCW(50, 50, 0,  100, 0);&lt;br /&gt;
        fpv.createChild(&amp;quot;path&amp;quot;).setStrokeLineWidth(4).set(&amp;quot;stroke&amp;quot;, &amp;quot;rgba(255,0,255,1)&amp;quot;)&lt;br /&gt;
        .moveTo(500, 100).arcSmallCCW(50, 50, 0,  50, -50);&lt;br /&gt;
&lt;br /&gt;
        fpv.createChild(&amp;quot;path&amp;quot;).setStrokeLineWidth(4).set(&amp;quot;stroke&amp;quot;, &amp;quot;rgba(55,0,255,1)&amp;quot;)&lt;br /&gt;
        .moveTo(100, 300).arcSmallCW(50, 50, 0,  50, 50);&lt;br /&gt;
        fpv.createChild(&amp;quot;path&amp;quot;).setStrokeLineWidth(4).set(&amp;quot;stroke&amp;quot;, &amp;quot;rgba(55,0,255,1)&amp;quot;)&lt;br /&gt;
        .moveTo(300, 300).arcSmallCW(50, 50, 0,  100, 0);&lt;br /&gt;
        fpv.createChild(&amp;quot;path&amp;quot;).setStrokeLineWidth(4).set(&amp;quot;stroke&amp;quot;, &amp;quot;rgba(55,0,255,1)&amp;quot;)&lt;br /&gt;
        .moveTo(500, 300).arcSmallCW(50, 50, 0,  50, -50);&lt;br /&gt;
&lt;br /&gt;
        fpv.createChild(&amp;quot;path&amp;quot;).setStrokeLineWidth(4).set(&amp;quot;stroke&amp;quot;, &amp;quot;rgba(255,0,55,1)&amp;quot;)&lt;br /&gt;
        .moveTo(100, 500).arcLargeCCW(50, 50, 0,  50, 50);&lt;br /&gt;
        fpv.createChild(&amp;quot;path&amp;quot;).setStrokeLineWidth(4).set(&amp;quot;stroke&amp;quot;, &amp;quot;rgba(255,0,55,1)&amp;quot;)&lt;br /&gt;
        .moveTo(300, 500).arcLargeCCW(50, 50, 0,  100, 0);&lt;br /&gt;
        fpv.createChild(&amp;quot;path&amp;quot;).setStrokeLineWidth(4).set(&amp;quot;stroke&amp;quot;, &amp;quot;rgba(255,0,55,1)&amp;quot;)&lt;br /&gt;
        .moveTo(500, 500).arcLargeCCW(50, 50, 0,  50, -50);&lt;br /&gt;
&lt;br /&gt;
        fpv.createChild(&amp;quot;path&amp;quot;).setStrokeLineWidth(4).set(&amp;quot;stroke&amp;quot;, &amp;quot;rgba(255,0,55,1)&amp;quot;)&lt;br /&gt;
        .moveTo(100, 500).arcLargeCCW(50, 50, 0,  50, 50);&lt;br /&gt;
        fpv.createChild(&amp;quot;path&amp;quot;).setStrokeLineWidth(4).set(&amp;quot;stroke&amp;quot;, &amp;quot;rgba(255,0,55,1)&amp;quot;)&lt;br /&gt;
        .moveTo(300, 500).arcLargeCCW(50, 50, 0,  100, 0);&lt;br /&gt;
        fpv.createChild(&amp;quot;path&amp;quot;).setStrokeLineWidth(4).set(&amp;quot;stroke&amp;quot;, &amp;quot;rgba(255,0,55,1)&amp;quot;)&lt;br /&gt;
        .moveTo(500, 500).arcLargeCCW(50, 50, 0,  50, -50);&lt;br /&gt;
&lt;br /&gt;
        fpv.createChild(&amp;quot;path&amp;quot;).setStrokeLineWidth(4).set(&amp;quot;stroke&amp;quot;, &amp;quot;rgba(255,0,55,1)&amp;quot;)&lt;br /&gt;
        .moveTo(100, 700).arcLargeCW(50, 50, 0,  50, 50);&lt;br /&gt;
        fpv.createChild(&amp;quot;path&amp;quot;).setStrokeLineWidth(4).set(&amp;quot;stroke&amp;quot;, &amp;quot;rgba(255,0,55,1)&amp;quot;)&lt;br /&gt;
        .moveTo(300, 700).arcLargeCW(50, 50, 0,  100, 0);&lt;br /&gt;
        fpv.createChild(&amp;quot;path&amp;quot;).setStrokeLineWidth(4).set(&amp;quot;stroke&amp;quot;, &amp;quot;rgba(255,0,5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== ellipse ===&lt;br /&gt;
''' available on next, expected release 2019.1 '''&lt;br /&gt;
&lt;br /&gt;
'''Parameters:''' (rx, ry, cx = nil, cy = nil)&lt;br /&gt;
&lt;br /&gt;
rx, ry are the radii of the ellipse&lt;br /&gt;
cx, cy is optional for the center coordinates&lt;br /&gt;
&lt;br /&gt;
Add an ellipse to the path&lt;br /&gt;
&lt;br /&gt;
=== circle ===&lt;br /&gt;
''' available on next, expected release 2019.1 '''&lt;br /&gt;
&lt;br /&gt;
'''Parameters:''' (r, cx, cy)&lt;br /&gt;
&lt;br /&gt;
alias for ellipse(r, r, cx, cy), cx, cy optional for center coordinates&lt;br /&gt;
&lt;br /&gt;
Add a circle to the path.&lt;br /&gt;
&lt;br /&gt;
=== close ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
Close the path (implicit lineTo to first point of path)&lt;br /&gt;
=== setColor ===&lt;br /&gt;
'''Parameters:''' (r, g, b)&lt;br /&gt;
&lt;br /&gt;
'''Parameters:''' (r, g, b, a)&lt;br /&gt;
&lt;br /&gt;
Sets the color of the drawn path&lt;br /&gt;
=== setColorFill ===&lt;br /&gt;
'''Parameters:''' (r, g, b)&lt;br /&gt;
&lt;br /&gt;
'''Parameters:''' (r, g, b, a)&lt;br /&gt;
&lt;br /&gt;
Calling this will make the path get filled in the specified color. For example if you draw a 'V' and fill it, the fill area will be a triangle inside the 'V'.&lt;br /&gt;
=== setStrokeLineWidth ===&lt;br /&gt;
'''Parameters:''' (width)&lt;br /&gt;
&lt;br /&gt;
The width of the path.&lt;br /&gt;
=== setStrokeLineJoin ===&lt;br /&gt;
'''Parameters:''' (type)&lt;br /&gt;
&lt;br /&gt;
Set stroke linejoin. Type can be &amp;quot;miter&amp;quot;, &amp;quot;round&amp;quot; or &amp;quot;bevel&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
[[File:Stroke join.png|Canvas stroke join]]&lt;br /&gt;
&lt;br /&gt;
=== setStrokeLineCap ===&lt;br /&gt;
'''Parameters:''' (type)&lt;br /&gt;
&lt;br /&gt;
Caps the path. Type can be &amp;quot;butt&amp;quot;, &amp;quot;round&amp;quot; or &amp;quot;square&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
[[File:Stroke cap.png|Canvas stroke cap]]&lt;br /&gt;
&lt;br /&gt;
=== setStrokeDashArray ===&lt;br /&gt;
'''Parameters:''' (pattern)&lt;br /&gt;
&lt;br /&gt;
Make dashed path. Pattern is a vector of alternating dash and gap lengths. Lines drawn will follow this pattern.&lt;br /&gt;
&lt;br /&gt;
'''Example:''' my_path.setStrokeDashArray([10, 20, 10, 20, 10]);&lt;br /&gt;
&lt;br /&gt;
=== setData ===&lt;br /&gt;
&lt;br /&gt;
'''Parameters:''' (cmds, points)&lt;br /&gt;
&lt;br /&gt;
Re-sets the data structure for a plot. cmds is an array containing the draw commands (integers, but they can be referenced via canvas.Path.VG_LINE_TO or canvas.Path.VG_MOVE_TO etc.) and points an array containing the associated points to which the curve is to be drawn in the form [x1, y1, x2, y2,...].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Example:''' my_path.setData([2, 4], [10, 20, 10, 40]);&lt;br /&gt;
&lt;br /&gt;
See addSegment for list of commands.&lt;br /&gt;
&lt;br /&gt;
=== setDataGeo ===&lt;br /&gt;
'''Parameters:''' (cmds, points)&lt;br /&gt;
&lt;br /&gt;
Same as setData(), just for GPS coords. See addSegmentGeo() for details.&lt;br /&gt;
&lt;br /&gt;
Parent element must be of type &amp;quot;map&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== addSegment ===&lt;br /&gt;
'''Parameters:''' (cmd, coords)&lt;br /&gt;
&lt;br /&gt;
Add a path segment.&lt;br /&gt;
&lt;br /&gt;
Cmd can for example be canvas.Path.VG_MOVE_TO&lt;br /&gt;
&lt;br /&gt;
Coords is a vector with the numbers/coordinates that the command needs.&lt;br /&gt;
&lt;br /&gt;
See this list of all commands and how many coords they require.&lt;br /&gt;
&lt;br /&gt;
  VG_CLOSE_PATH:     0,&lt;br /&gt;
  VG_MOVE_TO:        2,&lt;br /&gt;
  VG_MOVE_TO_ABS:    2,&lt;br /&gt;
  VG_MOVE_TO_REL:    2,&lt;br /&gt;
  VG_LINE_TO:        2,&lt;br /&gt;
  VG_LINE_TO_ABS:    2,&lt;br /&gt;
  VG_LINE_TO_REL:    2,&lt;br /&gt;
  VG_HLINE_TO:       1,&lt;br /&gt;
  VG_HLINE_TO_ABS:   1,&lt;br /&gt;
  VG_HLINE_TO_REL:   1,&lt;br /&gt;
  VG_VLINE_TO:       1,&lt;br /&gt;
  VG_VLINE_TO_ABS:   1,&lt;br /&gt;
  VG_VLINE_TO_REL:   1,&lt;br /&gt;
  VG_QUAD_TO:        4,&lt;br /&gt;
  VG_QUAD_TO_ABS:    4,&lt;br /&gt;
  VG_QUAD_TO_REL:    4,&lt;br /&gt;
  VG_CUBIC_TO:       6,&lt;br /&gt;
  VG_CUBIC_TO_ABS:   6,&lt;br /&gt;
  VG_CUBIC_TO_REL:   6,&lt;br /&gt;
  VG_SQUAD_TO:       2,&lt;br /&gt;
  VG_SQUAD_TO_ABS:   2,&lt;br /&gt;
  VG_SQUAD_TO_REL:   2,&lt;br /&gt;
  VG_SCUBIC_TO:      4,&lt;br /&gt;
  VG_SCUBIC_TO_ABS:  4,&lt;br /&gt;
  VG_SCUBIC_TO_REL:  4,&lt;br /&gt;
  VG_SCCWARC_TO:     5,&lt;br /&gt;
  VG_SCCWARC_TO_ABS: 5,&lt;br /&gt;
  VG_SCCWARC_TO_REL: 5,&lt;br /&gt;
  VG_SCWARC_TO:      5,&lt;br /&gt;
  VG_SCWARC_TO_ABS:  5,&lt;br /&gt;
  VG_SCWARC_TO_REL:  5,&lt;br /&gt;
  VG_LCCWARC_TO:     5,&lt;br /&gt;
  VG_LCCWARC_TO_ABS: 5,&lt;br /&gt;
  VG_LCCWARC_TO_REL: 5,&lt;br /&gt;
  VG_LCWARC_TO:      5,&lt;br /&gt;
  VG_LCWARC_TO_ABS:  5,&lt;br /&gt;
  VG_LCWARC_TO_REL:  5,&lt;br /&gt;
&lt;br /&gt;
=== addSegmentGeo ===&lt;br /&gt;
'''Parameters:''' (cmd, coords)&lt;br /&gt;
&lt;br /&gt;
Add a path segment.&lt;br /&gt;
&lt;br /&gt;
Cmd can for example be canvas.Path.VG_MOVE_TO&lt;br /&gt;
&lt;br /&gt;
Coords is a vector with the numbers/coordinates that the command needs in GPS format.&lt;br /&gt;
&lt;br /&gt;
The coords can for example be &amp;quot;E32.45&amp;quot; for latitude and &amp;quot;N45.34&amp;quot; for longitude. If an 'S' or 'W' is seen instead of E or N, the sign is flipped.&lt;br /&gt;
&lt;br /&gt;
See addSegment for list of commands.&lt;br /&gt;
&lt;br /&gt;
Parent element must be of type &amp;quot;map&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Map ==&lt;br /&gt;
Inherits from Element.&lt;br /&gt;
&lt;br /&gt;
Class for a group element on a canvas with possibly geographic positions which automatically get projected according to the specified projection.&lt;br /&gt;
Each map consists of an arbitrary number of layers (canvas groups)&lt;br /&gt;
=== del ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
Deletes the Map instance.&lt;br /&gt;
=== setController ===&lt;br /&gt;
'''Parameters:''' (controller)&lt;br /&gt;
&lt;br /&gt;
A controller needs to inherit from Map.Controller&lt;br /&gt;
=== addLayer ===&lt;br /&gt;
'''Parameters:''' (factory, type_arg=nil, priority=nil, style=nil, opts=nil, visible=1)&lt;br /&gt;
&lt;br /&gt;
Each layer is some kind of data to be rendered - there’s all the built in layers but WXR, TERRain or anything else specific to the acft would be another layer.&lt;br /&gt;
=== getLayer ===&lt;br /&gt;
'''Parameters:''' (type_arg)&lt;br /&gt;
&lt;br /&gt;
Returns the layer corresponding to the argument type.&lt;br /&gt;
=== setRange ===&lt;br /&gt;
'''Parameters:''' (range)&lt;br /&gt;
&lt;br /&gt;
This sets the display range of the map in NM.&lt;br /&gt;
=== getRange ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
Get current range setting&lt;br /&gt;
=== setPos ===&lt;br /&gt;
'''Parameters:''' (lat, lon, hdg=nil, range=nil, alt=nil)&lt;br /&gt;
&lt;br /&gt;
This is the center of the map (very often the aircraft position, except in something special such as PLAN mode). Hdg sets the up direction (could be north, track, heading and true vs magnetic depending on the aircraft)&lt;br /&gt;
&lt;br /&gt;
=== getPos ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
Returns vector with lat, lon, heading, range and altitude&lt;br /&gt;
=== getLat ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
Returns position latitude.&lt;br /&gt;
=== getLon ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
Returns position longitude.&lt;br /&gt;
=== getHdg ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
Return current 'up' heading.&lt;br /&gt;
=== getAlt ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
Returns current altitude setting in feet.&lt;br /&gt;
=== getRange ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
Returns current range setting.&lt;br /&gt;
=== getLatLon ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
Returns the center position of the map as a vector with lat and lon&lt;br /&gt;
=== getPosCoord ===&lt;br /&gt;
'''Parameters:''' ()&lt;br /&gt;
&lt;br /&gt;
Returns the center position of the map as a geo.Coord&lt;br /&gt;
&lt;br /&gt;
N.B.: This always returns the same geo.Coord object,&lt;br /&gt;
so its values can and will change at any time (call&lt;br /&gt;
update() on the coord to ensure it is up-to-date,&lt;br /&gt;
which basically calls this method again).&lt;br /&gt;
=== update ===&lt;br /&gt;
'''Parameters:''' (predicate=nil)&lt;br /&gt;
&lt;br /&gt;
Update each layer on this Map. Predicate is a function that takes a layer as argument and returns true if that layer should be updated. If predicate is not supplied, all layers will be updated.&lt;br /&gt;
=== See also ===&lt;br /&gt;
[[Canvas_Maps|Canvas Maps]] and [[Canvas_Map_API|Canvas Map API]]&lt;br /&gt;
&lt;br /&gt;
== Image ==&lt;br /&gt;
Inherits from Element.&lt;br /&gt;
&lt;br /&gt;
See: [[Canvas_Image|Canvas Image]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Changelog_2020.3&amp;diff=132378</id>
		<title>Changelog 2020.3</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Changelog_2020.3&amp;diff=132378"/>
		<updated>2021-06-16T12:44:23Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: /* 2020.3.8 */ 2020.3.9&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{changelogs|prev=2020.1|next=2022.1}}&lt;br /&gt;
&lt;br /&gt;
Available in: [[Changelog_2020.3|English]], [[Zh/2020.3|Chinese]]&lt;br /&gt;
&lt;br /&gt;
Please help us translate into other languages!&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
The FlightGear development team is delighted to announce the v2020.3 LTS release of FlightGear, the free, open-source flight simulator. This is the second Long Term Support release for FlightGear, since the project changed to offering both Long Term Support releases, and more cutting-edge Preview releases.  This release represents the culmination of two years of development effort by a worldwide group of volunteers, brought together by a shared ambition to create the most realistic flight simulator possible that is free to use, modify and distribute. FlightGear is used all over the world by desktop flight simulator enthusiasts, for research in universities and for interactive exhibits in museums.&lt;br /&gt;
&lt;br /&gt;
Major enhancements since the v2020.3 LTS include: &lt;br /&gt;
* a developer preview of the upcoming Compositor graphical rendering framework as a separate pre-built binary, &lt;br /&gt;
* enhancements to both the JSBSim and YASim flight dynamics models&lt;br /&gt;
* DDS texture caching to reduce load times&lt;br /&gt;
* faster loading and more memory efficient buildings&lt;br /&gt;
* improved aircraft carrier support&lt;br /&gt;
&lt;br /&gt;
Additionally 30 completely new aircraft have been added to the official hangar, and a further 71 have received major updates.&lt;br /&gt;
&lt;br /&gt;
{{Disclaimer|id=final-fixed-function-release}}&lt;br /&gt;
&lt;br /&gt;
Founded in 1997, FlightGear features more than 700 aircraft, a worldwide scenery database, a multiplayer environment, detailed sky modelling, a flexible and open aircraft modelling system, varied networking options, multiple display support, a powerful scripting language, and an open architecture. Best of all, being open-source, the simulator is owned by the community and everyone is encouraged to contribute.&lt;br /&gt;
&lt;br /&gt;
FlightGear - Fly Free! &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Launcher ==&lt;br /&gt;
* Addition of a welcome screen on first launch, providing helpful information to first time users.&lt;br /&gt;
* Aircraft can now be marked as Favourites, and filtered, making it easier to see find your favourite aircraft out of the hundreds available.&lt;br /&gt;
* The launcher now supports aircraft carriers, including selecting a carrier and setting a start position.&lt;br /&gt;
* {{key press|Ctrl|F}} shortcut for when you just want to Fly!&lt;br /&gt;
* Improved support for helipads and seaports, including detection of current aircraft type.&lt;br /&gt;
* Numerous bugfixes and stability improvements, in particular for the aircraft and addons tabs.&lt;br /&gt;
&lt;br /&gt;
== Graphics ==&lt;br /&gt;
* To provide a developer preview, the [[Compositor]] renderer is included as part of this release.  It provides a fully XML-configurable multi-pass rendering pipeline that is compatible with ALS and includes clustered shading.&lt;br /&gt;
* Support for DDS Texture Cache, improving loading times for texture files.&lt;br /&gt;
* Star visibility is configurable based on magnitude of star and atmospheric conditions.&lt;br /&gt;
* Use of non-directional point sprites as a fallback for drivers that do not support triangles of point sprites is now supported by setting &amp;lt;code&amp;gt;/rendering/triangle-directional-lights=false&amp;lt;/code&amp;gt;.&lt;br /&gt;
* A new Tower AGL view has been added.  This is similar to Tower View, except that it keeps both the aircraft and the ground immediately below the aircraft in view, zooming and panning smoothly as the aircraft moves. Good for viewing landings.&lt;br /&gt;
* Improved airport grass textures&lt;br /&gt;
* Implemented tidal movement for littoral areas.&lt;br /&gt;
* Updated regional material definitions for California, Asia, Northern Brazil, Iceland, Jan Mayen island.&lt;br /&gt;
* Active volcanoes - Katla, Eyjafjallajokull, Surtsey.  &lt;br /&gt;
* Instanced-based random and OpenStreetMap buildings, improving performance and graphical quality significantly.&lt;br /&gt;
* Improvements to the Wingflex Shader.&lt;br /&gt;
* Users may enable/disable the pilot model from the View Options dialog.&lt;br /&gt;
&lt;br /&gt;
== JSBSim ==&lt;br /&gt;
* Added the ability to set up the starter and acceleration times of a turbine (parameters &amp;lt;code&amp;gt;&amp;lt;n1spinup&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;lt;n2spinup&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;lt;n1startrate&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;lt;n2startrate&amp;gt;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* The &amp;lt;code&amp;gt;&amp;lt;integrator&amp;gt;&amp;lt;/code&amp;gt; filter can now be reset to 0.0 by setting its &amp;lt;code&amp;gt;&amp;lt;trigger&amp;gt;&amp;lt;/code&amp;gt; property to a negative value.&lt;br /&gt;
* The integration scheme of the &amp;lt;code&amp;gt;&amp;lt;integrator&amp;gt;&amp;lt;/code&amp;gt; filter can now be chosen among &amp;lt;code&amp;gt;rect&amp;lt;/code&amp;gt; (Euler), &amp;lt;code&amp;gt;trap&amp;lt;/code&amp;gt; (Trapezoidal), &amp;lt;code&amp;gt;ab2&amp;lt;/code&amp;gt; (2nd order Adams-BashForth) and &amp;lt;code&amp;gt;ab3&amp;lt;/code&amp;gt; (3rd order Adams-Bashforth)&lt;br /&gt;
* The following functions can now be used in &amp;lt;code&amp;gt;&amp;lt;function&amp;gt;&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;floor&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ceil&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;fmod&amp;lt;/code&amp;gt;. Their functionalities are the same than the corresponding C/C++ functions.&lt;br /&gt;
* &amp;lt;code&amp;gt;&amp;lt;function&amp;gt;&amp;lt;/code&amp;gt; now checks the number of its arguments.&lt;br /&gt;
* New system component linear_actuator&lt;br /&gt;
* Export the fuel density to the property tree&lt;br /&gt;
* Added cyclic clipping for FCS components&lt;br /&gt;
* Added the ability to control the turbine engines spin down factor&lt;br /&gt;
* [Backward compatibility breakage] Gyros are now measuring rotation rates instead of rotational accelerations. Gyros that measure rotational accelerations do not exist in the real world.&lt;br /&gt;
* Output properties of flight control elements are no longer tied. This saves a lot of spurious warning messages and allows direct references of the same properties among several flight controls.&lt;br /&gt;
* Water vapor in the atmosphere is now managed through its mass fraction rather than its partial pressure. The former being the physical quantity that is conserved when pressure and temperature vary.&lt;br /&gt;
* Check that there are at least 3 contacts before trying to trim on ground.&lt;br /&gt;
* Added optional transmission of the simulation time for FG UDP interface&lt;br /&gt;
* The existence of the property that is used for table independent vars is now checked during execution rather than when the XML definition is parsed. This relaxes the order in which filters, table and more generally flight controls need to be declared in the XML definition files.&lt;br /&gt;
* Electric engines RPM is now exported in UDP sockets.&lt;br /&gt;
* The parameter &amp;lt;code&amp;gt;&amp;lt;ignitionn2&amp;gt;&amp;lt;/code&amp;gt; now affects N2 rather than N1. &lt;br /&gt;
* A warning is now given when max &amp;lt; min in a &amp;lt;code&amp;gt;&amp;lt;clipto&amp;gt;&amp;lt;/code&amp;gt; rather than throwing an exception&lt;br /&gt;
* Added the ability to log properties in a CSV file with the new fgfs executable argument &amp;lt;code&amp;gt;--jsbsim-output-directive-file&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== YASim ==&lt;br /&gt;
* Ground friction (stiction) changes&lt;br /&gt;
* Support for transonic flow effects.&lt;br /&gt;
* Control initial gear state directly by setting &amp;lt;code&amp;gt;/fdm/yasim/respect-external-gear-state=true&amp;lt;/code&amp;gt;, rather then YASim settings this depending on whether the aircraft is in the air or on the ground.&lt;br /&gt;
* Electric engines are now supported.&lt;br /&gt;
&lt;br /&gt;
== Weather and Environment ==&lt;br /&gt;
* Increased turbulence will be encountered near active volcanoes.&lt;br /&gt;
* Configurable METAR URL.&lt;br /&gt;
* METAR strings are decoded and displayed in a human-readable form in the weather dialog.&lt;br /&gt;
&lt;br /&gt;
== Carriers ==&lt;br /&gt;
* Two new carrier-specific starting options are supported in the launcher: &amp;lt;code&amp;gt;carrier-takeoff&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;carrier-approach&amp;lt;/code&amp;gt;.&lt;br /&gt;
* A new &amp;lt;code&amp;gt;--carrier-position&amp;lt;/code&amp;gt; command-line argument has been added.  This can be used to select the aircraft start position on an aircraft carrier.  Either a catapult (e.g. &amp;lt;code&amp;gt;cat-1&amp;lt;/code&amp;gt;), a parking position (e.g. &amp;lt;code&amp;gt;park-1&amp;lt;/code&amp;gt;), on final approach on the FLOLS (&amp;lt;code&amp;gt;flols&amp;lt;/code&amp;gt;) or abeam the carrier (&amp;lt;code&amp;gt;abeam&amp;lt;/code&amp;gt;).&lt;br /&gt;
* MPCarrier can now be detected by the GUI even if not available on startup.  To enable this feature set &amp;lt;code&amp;gt;/sim/mp-carriers/auto-attach=true&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== AI ==&lt;br /&gt;
* New fgcommands &amp;lt;code&amp;gt;add-aiobject&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;remove-aiobject&amp;lt;/code&amp;gt; for adding/removing objects to the AI subsystem.&lt;br /&gt;
* New AI aircraft, including 747 Freighter, CRJ900, SR-71, Saab 340.&lt;br /&gt;
* Numerous updates to AI traffic schedules and airline liveries.&lt;br /&gt;
* Space Shuttle TAEM and approach at KEDW scenario.&lt;br /&gt;
* Accurate Britten-Norman Islander performance data, from an Islander pilot.&lt;br /&gt;
&lt;br /&gt;
== Multiplayer ==&lt;br /&gt;
* Connection to VATSIM via swift is now available via the GUI.&lt;br /&gt;
* FGCom now supports both COM1 and COM2, as well as volume settings.&lt;br /&gt;
* The views defined by the user's aircraft (Pilot view, Helicopter view, Tower view etc) can now be used with multiplayer aircraft.  Viewing a particular multiplayer aircraft is done by clicking in the Pilot List dialogue's &amp;quot;view' column (see the &amp;quot;Multiplayer/Pilot List&amp;quot; menu).&lt;br /&gt;
* &amp;lt;code&amp;gt;--disable-hold-short&amp;lt;/code&amp;gt; option which allows the user to force a start on the runway when multiplayer is enabled.  This option should be used with caution - it can give other pilots and ATC a nasty fright to find an aircraft materialize on the runway!&lt;br /&gt;
* Support for recording multiplayer data&lt;br /&gt;
&lt;br /&gt;
== Nasal Scripting ==&lt;br /&gt;
* Configurable load order for core Nasal modules.&lt;br /&gt;
* Improvements and bug fixes to Emesary, the messaging interface.&lt;br /&gt;
* Improvements to the core libraries.&lt;br /&gt;
* Garbage collection improvements to reduce frame stuttering&lt;br /&gt;
* Re-loadable Nasal modules&lt;br /&gt;
* Canvas EFIS framework&lt;br /&gt;
* New methods in Canvas Image to set colors of pixels in the image.&lt;br /&gt;
&lt;br /&gt;
== Aircraft == &lt;br /&gt;
* FG1000 Glass Panel improvements include user-configurable VFR transponder codes, volume controls, new fascia, UI is now resizeable, support for custom SVG files (e.g. for a G500).  The FG1000 is now available on the Cessna 182T, J3 Cub, Diamond DA40.&lt;br /&gt;
* Improved glider vario instrument.&lt;br /&gt;
* New Aircraft: &lt;br /&gt;
** Airbus A320 - airliner&lt;br /&gt;
** Alisport Silent2Electro - glider with electric sustainer motor&lt;br /&gt;
** Bombardier Q400 DHC8-402 - shorthaul turboprop airliner&lt;br /&gt;
** Breguet Atlantic BR 1150 - long-range maritime patrol aircraft&lt;br /&gt;
** Cessna 140 - GA aircraft&lt;br /&gt;
** Cessna 208B Caravan - short range passenger, freighter and utility aircraft&lt;br /&gt;
** Cirrus SR22T - GA aircraft&lt;br /&gt;
** Diamond DA40 NG - GA aircraft, including FG1000 glass panel cockpit&lt;br /&gt;
** Diamond DA62 Twinstar- Twin engine GA aircraft&lt;br /&gt;
** Diamond HK36 Super Dimona - motorglider&lt;br /&gt;
** Dornier DO 28 Skyservant - Twin engine STOL utility aircraft&lt;br /&gt;
** Douglas TBD Devastator - WWII Torpedo bomber&lt;br /&gt;
** Draco Wilga - turboprop taildragger bush plane&lt;br /&gt;
** Fokker T.V - twin engine bomber&lt;br /&gt;
** Glasfluegel H201B Standard Libelle - glider&lt;br /&gt;
** Grumman F11-Tiger - carrier-based fighter&lt;br /&gt;
** Grumman HU-16A Albatross - twin engine amphibian&lt;br /&gt;
** Petliakov PE-8 (Ant-42/TB-7) - WWII bomber&lt;br /&gt;
** Piper PA28-161 Warrior II - GA aircraft&lt;br /&gt;
** Pipistrel Alpha Electro - electric training aircraft&lt;br /&gt;
** Pipistrel Taurus Electro G2.5 - glider with electric sustainer motor&lt;br /&gt;
** Rolladen Schneider LS8sc neo - standard glider with electric sustainer motor&lt;br /&gt;
** Robin DR400 Ecoflyer - GA Aircraft&lt;br /&gt;
** Scheibe Bergfalke II/55 - training glider&lt;br /&gt;
** Schempp-Hirth Arcus S - high performance glider&lt;br /&gt;
** Schleicher Ka6(CR) &amp;quot;Rhoensegler&amp;quot; - training glider&lt;br /&gt;
** SEPECAT Jaguar GR.1 - jet attack aircraft&lt;br /&gt;
** SUMPAC - Human powered airplane&lt;br /&gt;
** Supermarine Swift - jet fighter&lt;br /&gt;
** Yak 52 - training aircraft&lt;br /&gt;
* Major updates to over 70 aircraft.  Including 737-100, 737-300, 777, A-26-Invader, AR-234, ASG29, ASK13, ASK21, Aero-Commander, Aichi-D3A, B-17, B-24-Liberator, B-25, Bombardier-415, CH750STOL, CRJ700-family, Cessna-208-Caravan, Cessna Citation II, Cessna-L19, Cirrus-SR22, Concorde, DO-228, DO-335, Diamond-Da40, Diamond-Da42, Dragonfly, Embraer-ERJ-145, F-15, Fairchild-Metroliner, Falcon-50, Fokker-S-11, Fw200, H4-Hercules, Harrier-GR3, Horten-Ho-IX, Hughes-XF11, J3Cub, JA37, JAS39-Gripen, Jaguar, LS4, Lancair-235, Lionceau, Lockheed-NF104A, Lockheed-P38, ME-262, Mirage-2000, MirageIV, Northrop-xb35, PC-12, Piaggio-P166, Piper-PA-28, Potez-630, R44, Ryan-Navion, SIAI-Marchetti-SF.260, Socata-ST10, SpaceShuttle, Starship, Tecnam-P2006T, UH-1, Yak-18T, Zlin-50lx, an24b, bluebird, c182s, dhc1, f-14b, f16.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous ==&lt;br /&gt;
* Updated Chinese, Dutch, French, German, Italian, Polish and Slovak translations.&lt;br /&gt;
* Map dialog displays heliports and allows configurable cursor key panning&lt;br /&gt;
* Faster Terrasync:  Download a tarball of airport information on first start and only check for updates every 24 hours rather than every simulator run.&lt;br /&gt;
* GPS fly-by mode&lt;br /&gt;
* Sentry.io integration to provide centralized crash reporting.&lt;br /&gt;
* Change screenshot filename to have date and time&lt;br /&gt;
* New thread safe particle manager -- should reduce random crashes around particles.&lt;br /&gt;
&lt;br /&gt;
=Updates since 2020.1=&lt;br /&gt;
Changes since the 2020.1 preview release include:&lt;br /&gt;
* Various launcher improvements including a Welcome screen and a keyboard shortcut (Ctrl+F) to Fly!&lt;br /&gt;
* Improved regional definitions for California, Iceland and Northern Brazil and better grass textures.&lt;br /&gt;
* Implemented tidal movement for littoral areas.&lt;br /&gt;
* New AI model for the 747 Freighter, and numerous AI livery and traffic updates.&lt;br /&gt;
* Updates to the FG1000 glass panel display including configurable VFR transponder codes, volume controls, a new fascia, resizeable UI and support for custom SVG files.&lt;br /&gt;
* A hangar full of new aircraft: HU-16A-Albatross, LS8, Embraer-ERJ-145, Cessna 208B Caravan, PZL 104 wilga 2000 Draco, Scheibe Bergfalke, Taurus, f16, Dornier Do 28 Skyservant, Petliakov Pe 8 (Ant 42/DB 7), Grumman F.11 Tiger&lt;br /&gt;
* Updates to a large number of aircraft including CRJ700, Dragonfly, Mirage 2000, Jaguar GR1, H4 Hercules, JA37, Supermarine Swift, A320, Cirrus-SR22, Cessna Citation, J3Cub&lt;br /&gt;
* Updated Chinese, Dutch, French, German, Italian, Polish and Slovak translations.&lt;br /&gt;
* Faster Terrasync:  Download a tarball of airport information on first start and only check for updates every 24 hours rather than every simulator run.&lt;br /&gt;
* GPS fly-by mode&lt;br /&gt;
* Sentry.io integration to provide centralized crash reporting.&lt;br /&gt;
* New thread safe particle manager -- should reduce random crashes around particles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Updates since 2020.3.0=&lt;br /&gt;
&lt;br /&gt;
As 2020.3 is a long term supported release, there are ongoing bug-fixes and small improvements happening, based on user feedback and automatic reporting of crashes and issues. Significant fixes are listed below:&lt;br /&gt;
&lt;br /&gt;
==2020.3.1==&lt;br /&gt;
* Add help page to the launcher&lt;br /&gt;
* Fix handling of helipads at heliports&lt;br /&gt;
* Migrate installed aircraft packages, when migrating to the new stable catalog&lt;br /&gt;
* TerraSync: improve startup performance on Windows&lt;br /&gt;
&lt;br /&gt;
==2020.3.2==&lt;br /&gt;
* TerraSync waits for Models to be completely sync-ed, to avoid missing models when starting&lt;br /&gt;
* First-run screen: add a 'scroll to the bottom' hint icon&lt;br /&gt;
* Tides fixes from Erik Hofman&lt;br /&gt;
* Use nicer scrollbar for the launcher, fixes some issue with long aircraft lists&lt;br /&gt;
* Support Apt.dat v1000 comm frequencies&lt;br /&gt;
* Fix an ATC crash when repositioning&lt;br /&gt;
* Many translations fixes identified by Michael Danilov&lt;br /&gt;
* Greatly improve the Brazilian cerradio areas (near SBMQ)&lt;br /&gt;
* Russian translation updates&lt;br /&gt;
* Iceland materials fixes&lt;br /&gt;
&lt;br /&gt;
==2020.3.3==&lt;br /&gt;
* Fix accidental mouse picks while using a right-mouse-drag to look around&lt;br /&gt;
* Fix the download location we recommend in the 'setup root' dialog&lt;br /&gt;
&lt;br /&gt;
==2020.3.4==&lt;br /&gt;
* Handle more METAR strings correctly, including wind sensor failures&lt;br /&gt;
* Fix airmass velocity being applied to sub-models twice (eg, when dropping payloads in a cross-wind)&lt;br /&gt;
* Fix crash on shutdown in the properties code&lt;br /&gt;
* Spanish translation updates &lt;br /&gt;
* Disable flights to EGEL to avoid crashes in traffic code&lt;br /&gt;
&lt;br /&gt;
==2020.3.5==&lt;br /&gt;
* Change default Windows download location to %USERS%\FlightGear\Downloads, to avoid problems with Windows Defender blocking un-trusted applications from writing to Documents, which was the previous location.&lt;br /&gt;
* Fix a crash when returning to FlightGear from another application and scrolling or clicking&lt;br /&gt;
* Avoid crashing with UIUC-based aircraft such as the Wright Flyer&lt;br /&gt;
* Fix a crash on macOS when a joystick failed to open&lt;br /&gt;
* Update the macOS application icon&lt;br /&gt;
* Fix Nasal crash on reset&lt;br /&gt;
* Canvas: allow anisotropic filtering&lt;br /&gt;
* Larger, improved moon texture&lt;br /&gt;
* UFO speed goes to 11&lt;br /&gt;
* Fix taxiway markings disappearing in specific graphics settings&lt;br /&gt;
&lt;br /&gt;
==2020.3.6==&lt;br /&gt;
* Fixed crash downloading the default aircraft catalog&lt;br /&gt;
* Fix a hang starting at scenery in the ocean&lt;br /&gt;
* Fix incorrect sky &amp;amp; cockpit rendering with certain METAR values&lt;br /&gt;
* Add getting-started hints to the launcher (English only for now)&lt;br /&gt;
* Fix Shuttle AI scenarios&lt;br /&gt;
* Improvements to flight-planning mode&lt;br /&gt;
* Sun / moon scaling fixes&lt;br /&gt;
* Fix initial position of submodels&lt;br /&gt;
* macOS: warn if running with app translocation&lt;br /&gt;
* Windows: detect missing OpenGL drivers&lt;br /&gt;
* Fix UIUC FDM crashes&lt;br /&gt;
* Fix crash with invalid view numbers&lt;br /&gt;
* Catch FDM NaN errors more gracefully&lt;br /&gt;
* KAP-140 approach mode improvements&lt;br /&gt;
* Traffic+AI livery updates&lt;br /&gt;
&lt;br /&gt;
== 2020.3.7 ==&lt;br /&gt;
&lt;br /&gt;
* Enable OSM2City buildings via TerraSync for the whole planet&lt;br /&gt;
* C172 bug-fixes and updates&lt;br /&gt;
* Improved regional material definitions for Europe, California&lt;br /&gt;
* Allow chat box to be re-positioned&lt;br /&gt;
* Fix crashes related to particle systems&lt;br /&gt;
* Fix selection of time-zone around Beijing&lt;br /&gt;
* Fix display of non-Latin1 strings in Canvas displays&lt;br /&gt;
* Fix Multi-player mode runway-start logic to select hold-short position correctly&lt;br /&gt;
* macOS: fix crash on text with certain fonts&lt;br /&gt;
* Fix launcher language selection when the UI language include a script specifier (eg zh-Hans-CN)&lt;br /&gt;
* Fix aircraft-id property when loading from a hangar ( https://sourceforge.net/p/flightgear/codetickets/2502/ )&lt;br /&gt;
* Improve checks for out-of-date Intel Graphics drivers on Windows&lt;br /&gt;
&lt;br /&gt;
== 2020.3.8 ==&lt;br /&gt;
&lt;br /&gt;
* Fix behaviour of &amp;lt;code&amp;gt;&amp;lt;local&amp;gt;&amp;lt;/code&amp;gt; particle systems &lt;br /&gt;
* Fix autumn tree appearance&lt;br /&gt;
&lt;br /&gt;
== 2020.3.9 ==&lt;br /&gt;
&lt;br /&gt;
* Fix crash in Swift&lt;br /&gt;
* Corrections to MP protocol timing&lt;br /&gt;
* Correct URL to FGData&lt;br /&gt;
* Fix bug in cache reload dialog&lt;br /&gt;
* Improvements to ATC dialog to display frequencies with 3 decimal places correctly&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
{{Appendix}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:FlightGear changelogs‎]]&lt;br /&gt;
[[Zh:2020.3]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_library&amp;diff=132366</id>
		<title>Nasal library</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_library&amp;diff=132366"/>
		<updated>2021-06-16T10:46:38Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: /* sprintf() */ I learned that it includes + or - signs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Nasal Navigation|nocat=1}}&lt;br /&gt;
This page documents the global '''library functions and variables''' of FlightGear's built-in scripting language, [[Nasal]]. This includes ''[[#Core library functions|core library functions]]'', which were included in Nasal before its integration into FlightGear, the ''[[#Extension functions|extension functions]]'', which have been subsequently added, and are specifically designed for FlightGear, and the ''[[#variables|global variables]]'', which are conversion variables, added with extension functions, for converting between units. The relevant folders in [[Git]] are:&lt;br /&gt;
* {{flightgear file|src/Scripting}}&lt;br /&gt;
* {{simgear file|simgear/nasal}}&lt;br /&gt;
&lt;br /&gt;
All these functions and variables are in the global namespace, that is, they are directly accessible (e.g., one can call &amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; inline&amp;gt;magvar()&amp;lt;/syntaxhighlight&amp;gt; instead of &amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; inline&amp;gt;namespace.magvar()&amp;lt;/syntaxhighlight&amp;gt;). However, if a namespace must be used, &amp;lt;code&amp;gt;globals&amp;lt;/code&amp;gt; is the correct namespace, but using it is not recommended. For a more complete explanation, see [[Nasal Namespaces in-depth]].&lt;br /&gt;
&lt;br /&gt;
{{tip|Copy &amp;amp; paste the examples into your [[Nasal Console]] and execute them to see what they do.|width=70%}}&lt;br /&gt;
&lt;br /&gt;
== Core library functions ==&lt;br /&gt;
This is the list of the basic '''core library functions.''' Most of these functions were part of the original Nasal library (before its integration in to FlightGear), while some have been added or changed over time.  See also:&lt;br /&gt;
* http://plausible.org/nasal/lib.html ([http://web.archive.org/web/20101010094553/http://plausible.org/nasal/lib.html archive])&lt;br /&gt;
* {{simgear file|simgear/nasal/lib.c}} ([http://sourceforge.net/p/flightgear/simgear/ci/next/log/?path=/simgear/nasal/lib.c history])&lt;br /&gt;
&lt;br /&gt;
=== append() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = append(vector, element[, element[, ...]]);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=42|t=Source}}&lt;br /&gt;
|text = This function appends, or adds, the given element(s) to the end of the vector given in the first argument.  Returns the vector operated on.&lt;br /&gt;
|param1 = vector&lt;br /&gt;
|param1text = The vector to which the arguments will be appended.&lt;br /&gt;
|param2 = element&lt;br /&gt;
|param2text = An element to be added to the vector.&lt;br /&gt;
|example1 = &lt;br /&gt;
var vector = [1, 2, 3]; # Initialize the vector&lt;br /&gt;
append(vector, 4); # Append the number 4 to the end of the vector&lt;br /&gt;
debug.dump(vector); # Print the contents of the vector&lt;br /&gt;
|example2 = &lt;br /&gt;
var vector = [1, 2, 3]; # Initialize the vector&lt;br /&gt;
append(vector, 4, 5, 6); # Append the numbers 4, 5, and 6 to the end of the vector&lt;br /&gt;
debug.dump(vector); # Print the contents of the vector&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== bind() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = bind(function, locals[, outer_scope]);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=502|t=Source}}&lt;br /&gt;
|text = This creates a new function object. A function in Nasal is three things: the actual code, a hash/namespace of local variables available to the function namespace, and the closure object of that namespace. These correspond to the three arguments respectively.&lt;br /&gt;
|param1 = function&lt;br /&gt;
|param1text = Function to evaluate.&lt;br /&gt;
|param2 = locals&lt;br /&gt;
|param2text = Hash containing values that will become the namespace (first closure) for the function.&lt;br /&gt;
|param3 = outer_scope&lt;br /&gt;
|param3text = Optional function which is bound to the next closure. This can be bound to yet another, making a linked list.&lt;br /&gt;
|example1 = # This is a namespace/hash with a single member, named &amp;quot;key,&amp;quot; which is initialized to 12 &lt;br /&gt;
var Namespace = {&lt;br /&gt;
    key: 12&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
# This is different namespace/hash containing a function&lt;br /&gt;
# dividing a variable &amp;quot;key&amp;quot; (which is unavailable/nil in this namespace) by 2&lt;br /&gt;
var AnotherNamespace = {&lt;br /&gt;
    ret: func {&lt;br /&gt;
        key /= 2;&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
# To see that key is not available, try to call AnotherNamespace.ret() first&lt;br /&gt;
call(AnotherNamespace.ret, [], nil, nil, var errors = []);&lt;br /&gt;
if(size(errors)){&lt;br /&gt;
    print(&amp;quot;Key could not be divided/resolved!&amp;quot;);&lt;br /&gt;
    debug.printerror(errors);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Associate the AnotherNamespace.ret() function with the first namespace&lt;br /&gt;
# so that &amp;quot;key&amp;quot; is now available&lt;br /&gt;
var function = bind(AnotherNamespace.ret, Namespace);&lt;br /&gt;
&lt;br /&gt;
# Invoke the new function&lt;br /&gt;
function();&lt;br /&gt;
&lt;br /&gt;
# Print out the value of Namespace.key&lt;br /&gt;
# It was changed to 12 from 6 by AnotherNamespace.ret()&lt;br /&gt;
print(Namespace.key);&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== call() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = call(func[, args[, me[, locals[, error]]]);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=247|t=Source}}&lt;br /&gt;
|text = Calls the given function with the given arguments and returns the result.  This function is very useful as it allows much more control over function calls and catches any errors or {{func link|die()}} calls that would normally trigger run-time errors cancelling execution of the script otherwise. &lt;br /&gt;
|param1 = func&lt;br /&gt;
|param1text = Function to execute.&lt;br /&gt;
|param2 = args&lt;br /&gt;
|param2text = Vector containing arguments to give to the called function.&lt;br /&gt;
|param3 = me&lt;br /&gt;
|param3text = &amp;lt;code&amp;gt;'''me'''&amp;lt;/code&amp;gt; reference for the function call (i.e., for method calls). If given, this will override any &amp;lt;code&amp;gt;'''me'''&amp;lt;/code&amp;gt; value existing in the namespace (locals argument).&lt;br /&gt;
|param4 = locals&lt;br /&gt;
|param4text = A hash with key/value pairs that will be available to the called function, typically used as the namespace for the function to be called.&lt;br /&gt;
|param5 = error&lt;br /&gt;
|param5text = A vector to append errors to.  If the called function generates an error, the error, place, and line will be written to this.  These errors can be printed using {{func link|printerror()|debug}}.&lt;br /&gt;
|example1 =&lt;br /&gt;
# prints &amp;quot;Called from call()&amp;quot;&lt;br /&gt;
call(func {&lt;br /&gt;
    print(&amp;quot;Called from call()&amp;quot;);&lt;br /&gt;
});&lt;br /&gt;
|example2 =&lt;br /&gt;
# prints &amp;quot;a = 1 : b = 2&lt;br /&gt;
call(func(a, b){&lt;br /&gt;
        print(&amp;quot;a = &amp;quot;, a, &amp;quot; : b = &amp;quot;, b);&lt;br /&gt;
    },&lt;br /&gt;
    [1, 2]&lt;br /&gt;
);&lt;br /&gt;
|example3 =&lt;br /&gt;
var Hash = {&lt;br /&gt;
    new: func {&lt;br /&gt;
        var m = { parents: [Hash] };&lt;br /&gt;
&lt;br /&gt;
        m.el1 = &amp;quot;string1&amp;quot;;&lt;br /&gt;
        m.el2 = &amp;quot;string2&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        return m;&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
# prints &amp;quot;me.el1 = string1&amp;quot;, then &amp;quot;me.el2 = string2&amp;quot; on the next line&lt;br /&gt;
call(func(a, b){        &lt;br /&gt;
        print(&amp;quot;me.el&amp;quot;, a, &amp;quot; = &amp;quot;, me[&amp;quot;el&amp;quot; ~ a]);      &lt;br /&gt;
        print(&amp;quot;me.el&amp;quot;, b, &amp;quot; = &amp;quot;, me[&amp;quot;el&amp;quot; ~ b]);&lt;br /&gt;
    },&lt;br /&gt;
    [1, 2],&lt;br /&gt;
    Hash.new()&lt;br /&gt;
);&lt;br /&gt;
|example4 =&lt;br /&gt;
# prints the value of math.pi&lt;br /&gt;
call(func {&lt;br /&gt;
        print(pi);&lt;br /&gt;
    }, nil, nil, &lt;br /&gt;
    math&lt;br /&gt;
);&lt;br /&gt;
|example5 =&lt;br /&gt;
call(func {&lt;br /&gt;
        print(math.ip); # math.ip doesn't exist&lt;br /&gt;
    }, nil, nil, nil,&lt;br /&gt;
    var errs = []&lt;br /&gt;
);&lt;br /&gt;
debug.printerror(errs); # The error is caught and printed using debug.printerror()&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== caller() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = caller([level]);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=404|t=Source}}&lt;br /&gt;
|text = Returns a vector containing a record from the current call stack.  The level numbering starts from the currently executing function (level 0).  Level 1 (the default) is the caller of the current function, and so on.&lt;br /&gt;
&lt;br /&gt;
The result is a four-element vector containing '''[0]''' a hash of local variables, '''[1]''' the function object, '''[2]''' the full source file name (incl. path) and '''[3]''' the line number. &lt;br /&gt;
|param1 = level&lt;br /&gt;
|param1text = Optional integer specifying the stack level to return a result from.  Defaults to 1 (i.e. the caller of the currently executing function).&lt;br /&gt;
|example1 =&lt;br /&gt;
var myFunction = func(a, b){&lt;br /&gt;
    debug.dump(caller(0)[0]); # prints a hash of local variables, including arguments a and b&lt;br /&gt;
    return 2 * 2;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;2 x 2 = &amp;quot;, myFunction(2, 2));&lt;br /&gt;
|example2 =&lt;br /&gt;
var get_arg_value = func(){&lt;br /&gt;
    print(&amp;quot;Argument to myFunc = &amp;quot;, caller(1)[0]['a']); # print the value of myFunc's single argument, using caller()&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var myFunc = func(a){&lt;br /&gt;
    get_arg_value();&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
myFunc(3);&lt;br /&gt;
|example3text = This is a real example taken from {{fgdata file|Nasal/canvas/MapStructure.nas}}.  Function &amp;lt;code&amp;gt;r()&amp;lt;/code&amp;gt; (above the TODOs) returns a hash with the key/value pairs as per its arguments. For example, something like this is returned: &amp;lt;code&amp;gt;{ name: &amp;quot;&amp;lt;name&amp;gt;&amp;quot;, vis: 1, zindex: nil }&amp;lt;/code&amp;gt;.&lt;br /&gt;
|example3 =&lt;br /&gt;
var MapStructure_selfTest = func() {&lt;br /&gt;
	var temp = {};&lt;br /&gt;
	temp.dlg = canvas.Window.new([600,400],&amp;quot;dialog&amp;quot;);&lt;br /&gt;
	temp.canvas = temp.dlg.createCanvas().setColorBackground(1,1,1,0.5);&lt;br /&gt;
	temp.root = temp.canvas.createGroup();&lt;br /&gt;
	var TestMap = temp.root.createChild(&amp;quot;map&amp;quot;);&lt;br /&gt;
	TestMap.setController(&amp;quot;Aircraft position&amp;quot;);&lt;br /&gt;
	TestMap.setRange(25); # TODO: implement zooming/panning via mouse/wheel here, for lack of buttons :-/&lt;br /&gt;
	TestMap.setTranslation(&lt;br /&gt;
		temp.canvas.get(&amp;quot;view[0]&amp;quot;)/2,&lt;br /&gt;
		temp.canvas.get(&amp;quot;view[1]&amp;quot;)/2&lt;br /&gt;
	);&lt;br /&gt;
	var r = func(name,vis=1,zindex=nil) return caller(0)[0];&lt;br /&gt;
	# TODO: we'll need some z-indexing here, right now it's just random&lt;br /&gt;
	# TODO: use foreach/keys to show all layers in this case by traversing SymbolLayer.registry direclty ?&lt;br /&gt;
	# maybe encode implicit z-indexing for each lcontroller ctor call ? - i.e. preferred above/below order ?&lt;br /&gt;
	foreach(var type; [r('TFC',0),r('APT'),r('DME'),r('VOR'),r('NDB'),r('FIX',0),r('RTE'),r('WPT'),r('FLT'),r('WXR'),r('APS'), ] ) &lt;br /&gt;
		TestMap.addLayer(factory: canvas.SymbolLayer, type_arg: type.name,&lt;br /&gt;
					visible: type.vis, priority: type.zindex,&lt;br /&gt;
		);&lt;br /&gt;
}; # MapStructure_selfTest&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== chr() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = chr(code);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=175|t=Source}}&lt;br /&gt;
|text = Returns a character as per the single argument. Extended ASCII is supported (see http://www.asciitable.com/ for a list of supported characters), although this may vary between different systems.  For a list of the most commonly used characters, see the {{wikipedia|ASCII#ASCII printable code chart|ASCII printable code chart}} ('''Dec''' column). The following table lists supported control characters, along with their equivalent control characters in Nasal strings.  {{Note|In Nasal, only strings enclosed with double-quotes (&amp;lt;code&amp;gt;&amp;quot;string&amp;quot;&amp;lt;/code&amp;gt;) supports control chracters.  Strings in single quotes (&amp;lt;code&amp;gt;'string'&amp;lt;/code&amp;gt;) do not.}}&lt;br /&gt;
{{{!}} class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Code !! Name !! Equivalent to&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} 10 {{!!}} {{Wikipedia|Newline}} {{!!}} &amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt;&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} 9 {{!!}} {{Wikipedia|Tab key#Tab characters|Horizontal tab}} {{!!}} &amp;lt;code&amp;gt;\t&amp;lt;/code&amp;gt;&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} 13 {{!!}} {{Wikipedia|Carriage return}} {{!!}} &amp;lt;code&amp;gt;\r&amp;lt;/code&amp;gt;&lt;br /&gt;
{{!}}}&lt;br /&gt;
|param1 = code&lt;br /&gt;
|param1text = Integer character code for the desired glyph.&lt;br /&gt;
|example1 = print(&amp;quot;Code 65 = &amp;quot;, chr(65)); # prints &amp;quot;Code 65 = A&amp;quot;&lt;br /&gt;
|example2text = This example displays all of the characters in a list, in the format &amp;lt;code&amp;gt;Code '''n''' = &amp;gt;'''char'''&amp;lt;&amp;lt;/code&amp;gt;, '''n''' being the index, and '''char''' being the character.&lt;br /&gt;
|example2 =&lt;br /&gt;
for(var i = 0; i &amp;lt;= 255; i += 1){&lt;br /&gt;
    print(&amp;quot;Code &amp;quot;, i, &amp;quot; = &amp;gt;&amp;quot;, chr(i), &amp;quot;&amp;lt;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== closure() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = closure(func[, level]);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=421|t=Source}}&lt;br /&gt;
|text = Returns the hash table containing the lexical namespace of the given function. The level numbering start with level 0 being the namespace of '''func'''. &lt;br /&gt;
|param1 = func&lt;br /&gt;
|param1text = Function to evaluate.&lt;br /&gt;
|param2 = level&lt;br /&gt;
|param2text = Optional integer specifying the scope level.  Defaults to 0 (the namespace of '''func''').&lt;br /&gt;
|example1 =&lt;br /&gt;
var get_math_e = func {&lt;br /&gt;
    return e; # return the value of math.e&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var myFunction = bind(get_math_e, math); # bind get_math_e to the math namespace, so that math.e is immediately available to get_math_e&lt;br /&gt;
debug.dump(closure(myFunction)); # print the namespace of get_math_e&lt;br /&gt;
&lt;br /&gt;
print(myFunction());&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== cmp() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = cmp(a, b);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=112|t=Source}}&lt;br /&gt;
|text = Compares two strings, returning -1 if '''a''' is less than '''b''', 0 if they are identical and 1 if '''a''' is greater than '''b'''. &lt;br /&gt;
|param1 = a&lt;br /&gt;
|param1text = First string argument for comparison.&lt;br /&gt;
|param2 = b&lt;br /&gt;
|param2text = Second string argument for comparison.&lt;br /&gt;
|example1 = print(cmp(&amp;quot;1&amp;quot;, &amp;quot;two&amp;quot;)); # prints -1&lt;br /&gt;
|example2 = print(cmp(&amp;quot;string&amp;quot;, &amp;quot;string&amp;quot;)); # prints 0&lt;br /&gt;
|example3 = print(cmp(&amp;quot;one&amp;quot;, &amp;quot;2&amp;quot;)); # prints 1&lt;br /&gt;
|example4 = print(cmp(&amp;quot;string1&amp;quot;, &amp;quot;string2&amp;quot;)); # prints -1&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== compile() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = compile(code[, filename]);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=220|t=Source}}&lt;br /&gt;
|text = Compiles the specified code string and returns a function object bound to the current lexical context.  If there is an error, the function dies, with the argument to {{func link|die()}} being '''filename'''.&lt;br /&gt;
|param1 = code&lt;br /&gt;
|param1text = String containing Nasal code to be compiled.&lt;br /&gt;
|param2 = filename&lt;br /&gt;
|param2text = Optional string used for error messages/logging. Defaults to &amp;lt;code&amp;gt;&amp;lt;compile&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|example1 = &lt;br /&gt;
var myCode = 'print(&amp;quot;hello&amp;quot;);';&lt;br /&gt;
var helloFunc = compile(myCode, &amp;quot;myCode&amp;quot;);&lt;br /&gt;
helloFunc();&lt;br /&gt;
|example2text = &amp;lt;code&amp;gt;compile&amp;lt;/code&amp;gt; is very convenient to support Nasal loaded from other files.  For instance, [[PropertyList XML files]] (such as GUI dialogs) may contain embedded Nasal sections that need to be parsed, processed and compiled.  For an example of how to do this, save the below XML code as &amp;lt;tt&amp;gt;''[[$FG_ROOT]]/gui/dialogs/test.xml''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot;?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;PropertyList&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nasal&amp;gt;&amp;lt;![CDATA[&lt;br /&gt;
print(&amp;quot;You have FlightGear v&amp;quot;, getprop(&amp;quot;/sim/version/flightgear&amp;quot;));&lt;br /&gt;
]]&amp;gt;&amp;lt;/nasal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/PropertyList&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Now, start FlightGear and execute this code in the [[Nasal Console]].&lt;br /&gt;
|example2 =&lt;br /&gt;
# Build the path&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/gui/dialogs/test.xml&amp;quot;;&lt;br /&gt;
var path = FGRoot ~ filename;&lt;br /&gt;
&lt;br /&gt;
var blob = io.read_properties(path);&lt;br /&gt;
var script = blob.getValues().nasal; # Get the nasal string&lt;br /&gt;
&lt;br /&gt;
# Compile the script.  We're passing the filename here for better runtime diagnostics &lt;br /&gt;
var code = call(func {&lt;br /&gt;
    compile(script, filename);&lt;br /&gt;
}, nil, nil, var compilation_errors = []);&lt;br /&gt;
&lt;br /&gt;
if(size(compilation_errors)){&lt;br /&gt;
    die(&amp;quot;Error compiling code in: &amp;quot; ~ filename);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Invoke the compiled script, equivalent to code(); &lt;br /&gt;
# We're using call() here to detect errors:&lt;br /&gt;
call(code, [], nil, nil, var runtime_errors = []);&lt;br /&gt;
&lt;br /&gt;
if(size(runtime_errors)){&lt;br /&gt;
    die(&amp;quot;Error calling code compiled loaded from: &amp;quot; ~ filename);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== contains() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = contains(hash, key);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=184|t=Source}}&lt;br /&gt;
|text = Returns 1 (True) if the hash contains the specified key, or 0 (False) if not.&lt;br /&gt;
|param1 = hash&lt;br /&gt;
|param1text = The hash to search in.&lt;br /&gt;
|param2 = key&lt;br /&gt;
|param2text = The scalar to be searched for, contained as a key in the hash.&lt;br /&gt;
|example1 =&lt;br /&gt;
# Initialize a hash&lt;br /&gt;
var hash = {&lt;br /&gt;
    element: &amp;quot;value&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
print(contains(hash, &amp;quot;element&amp;quot;) ? &amp;quot;Yes&amp;quot; : &amp;quot;No&amp;quot;); # This will print &amp;quot;Yes&amp;quot;&lt;br /&gt;
|example2 =&lt;br /&gt;
# Initialize a hash&lt;br /&gt;
var hash = {&lt;br /&gt;
    element: &amp;quot;value&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
print(contains(hash, &amp;quot;element2&amp;quot;) ? &amp;quot;Yes&amp;quot; : &amp;quot;No&amp;quot;); # This will print &amp;quot;No&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== delete() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = delete(hash, key);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=83|t=Source}}&lt;br /&gt;
|text = Deletes the key from the hash if it exists. Operationally, this is NOT identical to setting the hash value specified by the key to &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt; as the key will stay in the hash (at least for a while). This variant potentially frees storage by deleting the reference to the key and by shrinking the hash.  Returns the hash that has been operated on.&lt;br /&gt;
|param1 = hash&lt;br /&gt;
|param1text = The hash from which to delete the key.&lt;br /&gt;
|param2 = key&lt;br /&gt;
|param2text = The scalar to be deleted, contained as a key in the hash.&lt;br /&gt;
|example1 =&lt;br /&gt;
# Initialize the hash&lt;br /&gt;
var hash = {&lt;br /&gt;
    element1: &amp;quot;value1&amp;quot;,&lt;br /&gt;
    element2: &amp;quot;value2&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
delete(hash, &amp;quot;element1&amp;quot;); # Delete element1&lt;br /&gt;
debug.dump(hash); # prints the hash, which is now minus element1&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== die() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = die(error);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=288|t=Source}}&lt;br /&gt;
|text = Terminates execution and unwinds the stack.  The place and the line will be added to the '''error'''.  This invokes the same internal exception handler used for internal runtime errors. Use this to signal fatal errors, or to implement exception handling. The error thrown (including internal runtime errors) can be caught with {{func link|call()}}.&lt;br /&gt;
|param1 = error&lt;br /&gt;
|param1text = String describing the error.&lt;br /&gt;
:{{inote|This parameter is technically optional, but it is highly recommended to use it.}}&lt;br /&gt;
|example1 = &lt;br /&gt;
print(&amp;quot;Will print&amp;quot;);&lt;br /&gt;
die(&amp;quot;Don't go any further!&amp;quot;); &lt;br /&gt;
print(&amp;quot;Won't print&amp;quot;); # Will not be printed because die() stops the process&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== find() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = find(needle, haystack);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=450|t=Source}}&lt;br /&gt;
|text = Finds and returns the index of the first occurrence of the string '''needle''' in the string '''haystack''', or -1 if no such occurrence was found.&lt;br /&gt;
|param1 = needle&lt;br /&gt;
|param1text = String to search for.&lt;br /&gt;
|param2 = haystack&lt;br /&gt;
|param2text = String to search in.&lt;br /&gt;
|example1 = print(find(&amp;quot;c&amp;quot;, &amp;quot;abcdef&amp;quot;)); # prints 2&lt;br /&gt;
|example2 = print(find(&amp;quot;x&amp;quot;, &amp;quot;abcdef&amp;quot;)); # prints -1&lt;br /&gt;
|example3 = print(find(&amp;quot;cd&amp;quot;, &amp;quot;abcdef&amp;quot;)); # prints 2&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== ghosttype() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = ghosttype(ghost);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=207|t=Source}}&lt;br /&gt;
|text = Returns a string containing either a descriptive name of a ghost (a raw C/C++ object), or a unique id (the pointer to the C/C++ &amp;lt;code&amp;gt;naGhostType&amp;lt;/code&amp;gt; instance) if no name has been set.  Ghost is an acronym that stands for '''G'''arbage-collected '''H'''andle to '''O'''ut'''S'''ide '''T'''hingy.&lt;br /&gt;
|param1 = ghost&lt;br /&gt;
|param1text = Ghost to return a description for.&lt;br /&gt;
|example1 = print(ghosttype(airportinfo())); # prints &amp;quot;airport&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== id() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = id(object);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=570|t=Source}}&lt;br /&gt;
|text = Returns a string containing information on the type and ID of the object provided in the single argument.  The information is returned in the form of &amp;lt;code&amp;gt;'''&amp;lt;type&amp;gt;''':'''&amp;lt;id&amp;gt;'''&amp;lt;/code&amp;gt;, where '''&amp;lt;type&amp;gt;''' is the type of object, and '''&amp;lt;id&amp;gt;''' is the ID.&lt;br /&gt;
|param1 = object&lt;br /&gt;
|param1text = Can be either of a string, a vector, a hash, a code, a function, or a ghost.&lt;br /&gt;
|example1 = print(id(&amp;quot;A&amp;quot;)); # prints &amp;quot;str:000000001624A590&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== int() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = int(number);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=90|t=Source}}&lt;br /&gt;
|text = Returns the integer part of the numeric value of the single argument, or &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt; if none exists.&lt;br /&gt;
|param1 = number&lt;br /&gt;
|param1text = Number or string with just a number in it to return an integer from.&lt;br /&gt;
|example1 = print(int(23)); # prints &amp;quot;23&amp;quot;&lt;br /&gt;
|example2 = print(int(23.123)); # prints &amp;quot;23&amp;quot;&lt;br /&gt;
|example3 = debug.dump(int(&amp;quot;string&amp;quot;)); # prints &amp;quot;nil&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== keys() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = keys(hash);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=33|t=Source}}&lt;br /&gt;
|text = Returns a vector containing the list of keys found in the single hash argument. &lt;br /&gt;
|param1 = hash&lt;br /&gt;
|param1text = The hash to return the keys from.&lt;br /&gt;
|example1 = &lt;br /&gt;
# Initialize a hash&lt;br /&gt;
var hash = {&lt;br /&gt;
    element1: &amp;quot;value&amp;quot;,&lt;br /&gt;
    element2: &amp;quot;value&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
debug.dump(keys(hash)); # print the vector&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== left() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = left(string, length);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=149|t=Source}}&lt;br /&gt;
|version = 2.12&lt;br /&gt;
|commit = {{simgear commit|bd7163|t=commit}}&lt;br /&gt;
|text = Returns a substring of '''string''', starting from the left.&lt;br /&gt;
|param1 = string&lt;br /&gt;
|param1text = String to return part of.&lt;br /&gt;
|param2 = length&lt;br /&gt;
|param2text = Integer specifying the length of the substring to return.&lt;br /&gt;
|example1 = print(left(&amp;quot;string&amp;quot;, 2)); # prints &amp;quot;st&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== num() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = num(number);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=102|t=Source}}&lt;br /&gt;
|text = Returns the numerical value of the single string argument, or &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt; if none exists. &lt;br /&gt;
|param1 = number&lt;br /&gt;
|param1text = String with just a number in it to return a number from.&lt;br /&gt;
|example1 = print(num(&amp;quot;23&amp;quot;)); # prints &amp;quot;23&amp;quot;&lt;br /&gt;
|example2 = print(num(&amp;quot;23.123&amp;quot;)); # prints &amp;quot;23.123&amp;quot;&lt;br /&gt;
|example3 = debug.dump(num(&amp;quot;string&amp;quot;)); # prints &amp;quot;nil&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== pop() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = pop(vector);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=50|t=Source}}&lt;br /&gt;
|text = Removes and returns the last element of the single vector argument, or &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt; if the vector is empty. &lt;br /&gt;
|param1 = vector&lt;br /&gt;
|param1text = Vector to remove an element from.&lt;br /&gt;
|example1 = &lt;br /&gt;
var vector = [1, 2, 3];&lt;br /&gt;
pop(vector);&lt;br /&gt;
debug.dump(vector); # prints &amp;quot;[1, 2]&amp;quot;&lt;br /&gt;
|example2 = &lt;br /&gt;
var vector = [1, 2, 3];&lt;br /&gt;
debug.dump(pop(vector)); # prints &amp;quot;3&amp;quot;&lt;br /&gt;
|example3 = &lt;br /&gt;
var vector = [];&lt;br /&gt;
debug.dump(pop(vector)); # prints &amp;quot;nil&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== right() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = right(string, length);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=161|t=Source}}&lt;br /&gt;
|version = 2.12&lt;br /&gt;
|commit = {{simgear commit|bd7163|t=commit}}&lt;br /&gt;
|text = Returns a substring of '''string''', starting from the right.&lt;br /&gt;
|param1 = string&lt;br /&gt;
|param1text = String to return part of.&lt;br /&gt;
|param2 = length&lt;br /&gt;
|param2text = Integer specifying the length of the substring to return.&lt;br /&gt;
|example1 = print(right(&amp;quot;string&amp;quot;, 2)); # prints &amp;quot;ng&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== setsize() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = setsize(vector, size);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=56|t=Source}}&lt;br /&gt;
|text = Sets the size of a vector. The first argument specifies a vector, the second a number representing the desired size of that vector. If the vector is currently larger than the specified size, it is truncated. If it is smaller, it is padded with &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt; entries. Returns the vector operated upon. &lt;br /&gt;
|param1 = vector&lt;br /&gt;
|param1text = The vector to be operated on.&lt;br /&gt;
|param2 = size&lt;br /&gt;
|param2text = The desired size of the vector in number of entries.&lt;br /&gt;
|example1 = &lt;br /&gt;
var vector = [1, 2, 3]; # Initialize a vector&lt;br /&gt;
setsize(vector, 4);&lt;br /&gt;
debug.dump(vector); # print the vector&lt;br /&gt;
|example2 = &lt;br /&gt;
var vector = [1, 2, 3]; # Initialize a vector&lt;br /&gt;
setsize(vector, 2);&lt;br /&gt;
debug.dump(vector); # print the vector&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== size() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = size(object);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=23|t=Source}}&lt;br /&gt;
|text = Returns the size of the single argument. For strings, this is the length in bytes. For vectors, this is the number of elements. For hashes, it is the number of key/value pairs. If the argument is &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt; or a number, this error will be thrown: &amp;lt;code&amp;gt;object has no size()&amp;lt;/code&amp;gt;.&lt;br /&gt;
|param1 = object&lt;br /&gt;
|param1text = Object to find the size of.  Must be a string, a vector or a hash.&lt;br /&gt;
|example1 = &lt;br /&gt;
var string = &amp;quot;string&amp;quot;;&lt;br /&gt;
print(size(string)); # prints &amp;quot;6&amp;quot;&lt;br /&gt;
|example2 =&lt;br /&gt;
var vector = [1, 2, 3];&lt;br /&gt;
print(size(vector)); # prints &amp;quot;3&amp;quot;&lt;br /&gt;
|example3 =&lt;br /&gt;
var hash = {&lt;br /&gt;
    element1: &amp;quot;value1&amp;quot;,&lt;br /&gt;
    element2: &amp;quot;value2&amp;quot;,&lt;br /&gt;
    element3: &amp;quot;value3&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
print(size(hash)); # prints &amp;quot;3&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== sort() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = sort(vector, function);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=542|t=Source}}&lt;br /&gt;
|text = Returns a vector containing the elements in the input '''vector''' sorted in according to the rule given by '''function'''. Implemented with the ANSI C {{func link|qsort()|link=http://www.cplusplus.com/reference/cstdlib/qsort/}}, &amp;lt;code&amp;gt;sort()&amp;lt;/code&amp;gt; is stable.  This means that if the rules in the first example are used, equal elements in the output vector will appear in the same relative order as they do in the input.  It is run in a loop, so '''function''' is run several times.&lt;br /&gt;
|param1 = vector&lt;br /&gt;
|param1text = Input vector to sort.&lt;br /&gt;
|param2 = function&lt;br /&gt;
|param2text = Function according to which the elements will be sorted by.  It should take two arguments and should return one of 1, 0, or -1.&lt;br /&gt;
{{{!}} class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Return value !! Meaning&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} less than 0 {{!!}} first argument should go before second argument&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} 0 {{!!}} first argument equals second argument&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} greater than 0 {{!!}} first argument should go after second argument&lt;br /&gt;
{{!}}}&lt;br /&gt;
&lt;br /&gt;
|example1text = This example sorts elements from smallest to greatest.&lt;br /&gt;
|example1 = &lt;br /&gt;
var sort_rules = func(a, b){&lt;br /&gt;
    if(a &amp;lt; b){&lt;br /&gt;
        return -1; # A should before b in the returned vector&lt;br /&gt;
    }elsif(a == b){&lt;br /&gt;
        return 0; # A is equivalent to b &lt;br /&gt;
    }else{&lt;br /&gt;
        return 1; # A should after b in the returned vector&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
debug.dump(sort([3, 2, 5, 6, 4, 1], sort_rules)); # prints &amp;quot;[1, 2, 3, 4, 5, 6]&amp;quot;&lt;br /&gt;
|example2text = This example sorts elements from greatest to smallest.&lt;br /&gt;
|example2 = &lt;br /&gt;
# Outputs the elements in reverse order (greatest to smallest)&lt;br /&gt;
var sort_rules = func(a, b){&lt;br /&gt;
    if(a &amp;lt; b){&lt;br /&gt;
        return 1; # -1 in the above example&lt;br /&gt;
    }elsif(a == b){&lt;br /&gt;
        return 0;&lt;br /&gt;
    }else{&lt;br /&gt;
        return -1; # 1 in the above example&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
debug.dump(sort([3, 2, 5, 6, 4, 1], sort_rules)); # prints &amp;quot;[6, 5, 4, 3, 2, 1]&amp;quot;&lt;br /&gt;
|example3text = This example sorts a vector of strings (runways for example) from smallest to greatest.&lt;br /&gt;
|example3 = &lt;br /&gt;
var runways = [&amp;quot;09R&amp;quot;,&amp;quot;27R&amp;quot;,&amp;quot;26L&amp;quot;,&amp;quot;09L&amp;quot;,&amp;quot;15&amp;quot;];&lt;br /&gt;
var rwy = sort(runways,func(a,b) cmp(a,b));&lt;br /&gt;
debug.dump(rwy); # prints ['09L','09R','15','26L','27R']&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== split() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = split(delimiter, string);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=460|t=Source}}&lt;br /&gt;
|text = Splits the input string into a vector of substrings bounded by occurrences of the delimiter substring.&lt;br /&gt;
|param1 = delimiter&lt;br /&gt;
|param1text = String that will split the substrings in the returned vector.&lt;br /&gt;
|param2 = string&lt;br /&gt;
|param2text = String to split up.&lt;br /&gt;
|example1 = debug.dump(split(&amp;quot;cd&amp;quot;, &amp;quot;abcdef&amp;quot;)); # prints &amp;quot;['ab', 'ef']&amp;quot;&lt;br /&gt;
|example2 = debug.dump(split(&amp;quot;.&amp;quot;, &amp;quot;3.2.0&amp;quot;)); # prints &amp;quot;[3, 2, 0]&amp;quot;&lt;br /&gt;
|example3 = debug.dump(split(&amp;quot;/&amp;quot;, &amp;quot;path/to/file&amp;quot;)); # prints &amp;quot;['path', 'to', 'file']&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== sprintf() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = sprintf(format[, arg[, arg, [...]]]);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=355|t=Source}}&lt;br /&gt;
|text = Creates and returns a string formatted using ANSI C {{func link|vsnprintf()|link=http://en.cppreference.com/w/c/io/vfprintf}} &amp;lt;ref&amp;gt;&lt;br /&gt;
{{Cite web&lt;br /&gt;
|url = http://sourceforge.net/p/flightgear/simgear/ci/next/tree/simgear/nasal/lib.c#l308&lt;br /&gt;
|title = fgdata/simgear/simgear/nasal/lib.c, line 308&lt;br /&gt;
|accessdate = October 2015&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/ref&amp;gt;.  Below is a table of supported format specifiers.&lt;br /&gt;
{{{!}} class=&amp;quot;wikitable&amp;quot; width=&amp;quot;75%&amp;quot;&lt;br /&gt;
{{!}}+ %[flags][width][.precision]specifier&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; {{!}} Flags&lt;br /&gt;
{{!-}}&lt;br /&gt;
! Flag !! Output&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;+&amp;lt;/code&amp;gt; {{!!}} Forces to precede the result with a plus or minus sign ('''+''' or '''-''') even for positive numbers. By default, only negative numbers are preceded with a '''-''' sign.&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} ''space'' {{!!}} Prefixes non-signed numbers with a space.&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;-&amp;lt;/code&amp;gt; {{!!}} Left-align the output of this placeholder (the default is to right-align the output) when the width option is specified.&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; {{!!}} Use 0 instead of spaces to pad a field when the width option is specified.&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt; {{!!}} Used with &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; specifiers the value is preceded with &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;0x&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;0X&amp;lt;/tt&amp;gt; respectively for values different than zero. Used with &amp;lt;code&amp;gt;e&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt;, it forces the written output to contain a decimal point even if no digits would follow. By default, if no digits follow, no decimal point is written. Used with &amp;lt;code&amp;gt;g&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;G&amp;lt;/code&amp;gt; the result is the same as with &amp;lt;code&amp;gt;e&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; but trailing zeros are not removed.&lt;br /&gt;
{{!-}}&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; {{!}} Width&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} colspan=&amp;quot;2&amp;quot; {{!}} Integer specifying the minimum number of characters to be returned. This includes the decimal point and decimal fraction as well as + or - signs.&lt;br /&gt;
{{!-}}&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; {{!}} Precision&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} colspan=&amp;quot;2&amp;quot; {{!}} Integer preceded by a dot specifying the number of decimal places to be written.&lt;br /&gt;
{{!-}}&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; {{!}} Specifiers&lt;br /&gt;
{{!-}}&lt;br /&gt;
! Specifier !! Output&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;d&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i&amp;lt;/code&amp;gt; {{!!}} Signed decimal number.&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt; {{!!}} A string&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;%&amp;lt;/code&amp;gt; {{!!}} Percent (%) character.&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt; {{!!}} A single character assigned to a character code, the code given in an integer argument.  See http://www.asciitable.com/ for a list of supported characters and their codes.&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; {{!!}} Unsigned integer as an octal number.&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt; {{!!}} Unsigned decimal integer.&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; {{!!}} Unsigned integer as a hexadecimal number.  If &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt; is used, any letters in the number are lowercase, while &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; gives uppercase.&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;e&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;E&amp;lt;/code&amp;gt; {{!!}} Double value in scientific notation (i.e., ''[-]ddd.ddd'''e'''[+/-]ddd''), with an exponent being denoted by &amp;lt;tt&amp;gt;e&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;E&amp;lt;/tt&amp;gt; depending on whether an upper or lowercase is used respectively.&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; {{!!}} Floating-point number, in fixed decimal notation, by default with 6 decimal places.&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;F&amp;lt;/code&amp;gt; {{!!}} Appears to be available&amp;lt;ref&amp;gt;&lt;br /&gt;
{{Cite web&lt;br /&gt;
|url = http://sourceforge.net/p/flightgear/simgear/ci/next/tree/simgear/nasal/lib.c#l389&lt;br /&gt;
|title = fgdata/simgear/simgear/nasal/lib.c, line 389&lt;br /&gt;
|accessdate = October 2015&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/ref&amp;gt;, but doesn't work.&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} &amp;lt;code&amp;gt;g&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;G&amp;lt;/code&amp;gt; {{!!}} Double in either normal or exponential notation, whichever is more appropriate for its magnitude. &amp;lt;code&amp;gt;g&amp;lt;/code&amp;gt; uses lower-case letters, &amp;lt;code&amp;gt;G&amp;lt;/code&amp;gt; uses upper-case letters. This type differs slightly from fixed-point notation in that insignificant zeroes to the right of the decimal point are not included.  Also, the decimal point is not included on whole numbers.&lt;br /&gt;
{{!}}}&lt;br /&gt;
&lt;br /&gt;
|param1 = format&lt;br /&gt;
|param1text = String specifying the format.  Can be used with or without a format specifiers.  See below for examples.&lt;br /&gt;
|param2 = arg&lt;br /&gt;
|param2text = Argument specifying a value to replace a format placeholder (such as &amp;lt;code&amp;gt;%d&amp;lt;/code&amp;gt;) in the format string.  Not required if there are no format specifiers.&lt;br /&gt;
&lt;br /&gt;
|example1 = print(sprintf(&amp;quot;%i&amp;quot;, 54)); # prints &amp;quot;54&amp;quot;&lt;br /&gt;
|example2 = print(sprintf(&amp;quot;Pi = %+.10f&amp;quot;, math.pi)); # prints &amp;quot;Pi = +3.1415926536&amp;quot;&lt;br /&gt;
|example3 = &lt;br /&gt;
print(sprintf(&amp;quot;%6d&amp;quot;, 23)); # prints &amp;quot;    23&amp;quot;&lt;br /&gt;
print(sprintf(&amp;quot;%06d&amp;quot;, 23)); # prints &amp;quot;000023&amp;quot;&lt;br /&gt;
|example4 =&lt;br /&gt;
var FGVer = getprop(&amp;quot;/sim/version/flightgear&amp;quot;);&lt;br /&gt;
print(sprintf(&amp;quot;You have FlightGear v%s&amp;quot;, FGVer)); # prints &amp;quot;You have FlightGear v&amp;lt;your version&amp;gt;&amp;quot;&lt;br /&gt;
|example5 = &lt;br /&gt;
print(sprintf(&amp;quot;Hexadecimal 100000 = %X&amp;quot;, 100000)); # prints &amp;quot;Hexadecimal 100000 = 186A0&amp;quot;&lt;br /&gt;
print(sprintf(&amp;quot;Hexadecimal 100000 = %x&amp;quot;, 100000)); # prints &amp;quot;Hexadecimal 100000 = 186a0&amp;quot;&lt;br /&gt;
|example6 = print(sprintf(&amp;quot;Code 65 is %c&amp;quot;, 65)); # prints &amp;quot;Code 65 is A&amp;quot;&lt;br /&gt;
|example7 = &lt;br /&gt;
print(sprintf(&amp;quot;%e&amp;quot;, 54)); # prints &amp;quot;5.400000e+001&amp;quot;&lt;br /&gt;
print(sprintf(&amp;quot;%E&amp;quot;, 54)); # prints &amp;quot;5.400000E+001&amp;quot;&lt;br /&gt;
|example8 = print(sprintf(&amp;quot;%o&amp;quot;, 54)); # prints &amp;quot;66&amp;quot;&lt;br /&gt;
|example9 = print(sprintf(&amp;quot;50%% of 100 is %i&amp;quot;, 100 / 2)); # prints &amp;quot;50% of 100 is 50&amp;quot;&lt;br /&gt;
|example10 =&lt;br /&gt;
print(sprintf(&amp;quot;%.2f&amp;quot;, 1.4));   #prints &amp;quot;1.40&amp;quot;&lt;br /&gt;
print(sprintf(&amp;quot;%.1f&amp;quot;, 1.4));   #prints &amp;quot;1.4&amp;quot;&lt;br /&gt;
print(sprintf(&amp;quot;% 4.1f&amp;quot;, 1.4)); #prints &amp;quot; 1.4&amp;quot;&lt;br /&gt;
print(sprintf(&amp;quot;%04.1f&amp;quot;, 1.4)); #prints &amp;quot;01.4&amp;quot;&lt;br /&gt;
print(sprintf(&amp;quot;% 6.1f&amp;quot;, 1.4)); #prints &amp;quot;   1.4&amp;quot;&lt;br /&gt;
print(sprintf(&amp;quot;%06.1f&amp;quot;, 1.4)); #prints &amp;quot;0001.4&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== streq() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = streq(a, b);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=129|t=Source}}&lt;br /&gt;
|text = Tests the string values of the two arguments for equality. This function is needed because the &amp;lt;code&amp;gt;'''=='''&amp;lt;/code&amp;gt; operator (see [[Nasal_Operators#Equality|Nasal Operators]]) tests for numeric equality first.  If either or both the arguments are not strings, 0 (False) will be returned.  Returns either 0 (False) or 1 (True).  {{Note|This function is rarely required in typical code.}}&lt;br /&gt;
|param1 = a&lt;br /&gt;
|param1text = First argument for testing equality.&lt;br /&gt;
|param2 = b&lt;br /&gt;
|param2text = Second argument for testing equality.&lt;br /&gt;
|example1 = print(streq(&amp;quot;0&amp;quot;, &amp;quot;0&amp;quot;)); # prints &amp;quot;1&amp;quot; (True)&lt;br /&gt;
|example2 = &lt;br /&gt;
print(0 == 0.0); # prints &amp;quot;1&amp;quot; (True)&lt;br /&gt;
print(streq(&amp;quot;0&amp;quot;, &amp;quot;0.0&amp;quot;)); # prints &amp;quot;0&amp;quot; (False)&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== substr() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = substr(string, start [, length]);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=129|t=Source}}&lt;br /&gt;
|text = Similar the {{func link|subvec()}}, but operates on strings. Computes and returns a substring. The first argument specifies a string, the second is the index of the start of a substring, the optional third argument specifies a length (the default is to return the rest of the string from the start).&lt;br /&gt;
|param1 = string&lt;br /&gt;
|param1text = String to return a substring from.&lt;br /&gt;
|param2 = start&lt;br /&gt;
|param2text = Integer specifying the start of a substring. Negative values specify a position from the end of the string.&lt;br /&gt;
|param3 = length&lt;br /&gt;
|param3text = Optional argument specifying the length of the substring. Defaults to the end of the string.&lt;br /&gt;
|example1 = print(substr(&amp;quot;abcde&amp;quot;, 1, 3)); # prints &amp;quot;bcd&amp;quot;&lt;br /&gt;
|example2 = print(substr(&amp;quot;abcde&amp;quot;, 1)); # prints &amp;quot;bcde&amp;quot;&lt;br /&gt;
|example3 = print(substr(&amp;quot;abcde&amp;quot;, 2, 1)); # prints &amp;quot;c&amp;quot;&lt;br /&gt;
|example4 = print(substr(&amp;quot;abcde&amp;quot;, -2)); # prints &amp;quot;de&amp;quot;&lt;br /&gt;
|example5 = print(substr(&amp;quot;abcde&amp;quot;, -3, 2)); # prints &amp;quot;cd&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== subvec() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = subvec(vector, start[, length]);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=63|t=Source}}&lt;br /&gt;
|text = Returns a sub-range of a vector. The first argument specifies a vector, the second a starting index, and the optional third argument indicates a length (the default is to the end of the vector). &lt;br /&gt;
|param1 = vector&lt;br /&gt;
|param1text = The vector to take the sub-vector from.&lt;br /&gt;
|param2 = start&lt;br /&gt;
|param2text = The starting point of the sub-vector within the given vector.&lt;br /&gt;
|param3 = length&lt;br /&gt;
|param3text = Optional argument specifying the length of the sub-vector, from the starting point.&lt;br /&gt;
'''Notes:'''&lt;br /&gt;
* Omitting the ''vector'' and ''start'' arguments is not an error (possibly it should be) but the return value is ''nil''.&lt;br /&gt;
* A negative ''start'' argument ''is'' an error. This seems wrong. Perhaps the language designer could comment.&lt;br /&gt;
* A value of ''start'' greater than ''size(vector)'' causes an error. A value equal to ''size(vector)'' returns an empty vector.&lt;br /&gt;
* If the value of ''length'' is greater than ''size(vector) - start'' then it is ignored. That is, all elements from ''start'' to the end of ''vector'' are returned. If ''length'' is zero then an empty vector is returned. A negative value of ''length'' causes an error.&lt;br /&gt;
|example1 = &lt;br /&gt;
var vector = [1, 2, 3];&lt;br /&gt;
debug.dump(subvec(vector, 0)); # prints &amp;quot;[1, 2, 3]&amp;quot;&lt;br /&gt;
|example2 = &lt;br /&gt;
var vector = [1, 2, 3];&lt;br /&gt;
debug.dump(subvec(vector, 1)); # prints &amp;quot;[2, 3]&amp;quot;&lt;br /&gt;
|example3 = &lt;br /&gt;
var vector = [1, 2, 3];&lt;br /&gt;
debug.dump(subvec(vector, 1, 1)); # prints &amp;quot;[2]&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== typeof() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = typeof(object);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|l=193|t=Source}}&lt;br /&gt;
|text = Returns a string indicating the whether the object is &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt;, a scalar (number or string), a vector, a hash, a function, or a ghost.&lt;br /&gt;
|param1 = object&lt;br /&gt;
|param1text = Object to return the type of.&lt;br /&gt;
|example1 = &lt;br /&gt;
var object = nil;&lt;br /&gt;
print(typeof(object)); # prints &amp;quot;nil&amp;quot;&lt;br /&gt;
|example2 = &lt;br /&gt;
var object = &amp;quot;Hello world!&amp;quot;;&lt;br /&gt;
print(typeof(object)); # prints &amp;quot;scalar&amp;quot;&lt;br /&gt;
|example3 = &lt;br /&gt;
var object = math.pi;&lt;br /&gt;
print(typeof(object)); # prints &amp;quot;scalar&amp;quot;&lt;br /&gt;
|example4 = &lt;br /&gt;
var object = [1, 2, 3];&lt;br /&gt;
print(typeof(object)); # prints &amp;quot;vector&amp;quot;&lt;br /&gt;
|example5 = &lt;br /&gt;
var object = {};&lt;br /&gt;
print(typeof(object)); # prints &amp;quot;hash&amp;quot;&lt;br /&gt;
|example6 = &lt;br /&gt;
var object = func {};&lt;br /&gt;
print(typeof(object)); # prints &amp;quot;func&amp;quot;&lt;br /&gt;
|example7 =&lt;br /&gt;
var object = airportinfo();&lt;br /&gt;
print(typeof(object)); # prints &amp;quot;ghost&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- == Extension modules ==&lt;br /&gt;
=== thread ===&lt;br /&gt;
{{WIP}}&lt;br /&gt;
&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = thread.newthread(func);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/threadlib.c|l=101|t=Source}}&lt;br /&gt;
|text = &lt;br /&gt;
|example1text = start a new worker thread&lt;br /&gt;
|example1 = thread.newthread( func() {} );&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = thread.newlock();&lt;br /&gt;
|source = {{simgear file|simgear/nasal/threadlib.c|l=101|t=Source}}&lt;br /&gt;
|text = &lt;br /&gt;
|example1text = create a new lock&lt;br /&gt;
|example1 = var lock = thread.newlock()&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = thread.lock();&lt;br /&gt;
|source = {{simgear file|simgear/nasal/threadlib.c|l=101|t=Source}}&lt;br /&gt;
|text = &lt;br /&gt;
|example1text = lock a lock&lt;br /&gt;
|example1 = var lock = thread.newlock()&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = thread.unlock();&lt;br /&gt;
|source = {{simgear file|simgear/nasal/threadlib.c|l=101|t=Source}}&lt;br /&gt;
|text = &lt;br /&gt;
|example1text = unlock a lock&lt;br /&gt;
|example1 = var lock = thread.unlock()&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = thread.newsem();&lt;br /&gt;
|source = {{simgear file|simgear/nasal/threadlib.c|l=101|t=Source}}&lt;br /&gt;
|text = &lt;br /&gt;
|example1text = create a new {{Wikipedia|semaphore}}&lt;br /&gt;
|example1 = var semaphore = thread.newsem()&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = thread.semdown();&lt;br /&gt;
|source = {{simgear file|simgear/nasal/threadlib.c|l=101|t=Source}}&lt;br /&gt;
|text = &lt;br /&gt;
|example1text = semaphore down&lt;br /&gt;
|example1 = thread.semdown(semaphore)&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = thread.semup();&lt;br /&gt;
|source = {{simgear file|simgear/nasal/threadlib.c|l=101|t=Source}}&lt;br /&gt;
|text = &lt;br /&gt;
|example1text = semaphore up&lt;br /&gt;
|example1 = thread.semup(semaphore)&lt;br /&gt;
}} --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Extension functions ==&lt;br /&gt;
The '''extension functions''' are global functions that have been added to Nasal since its integration into FlightGear. Unlike the core library functions, they are generally specifically designed to interact directly with FlightGear. Extension functions come from three source files:&lt;br /&gt;
* {{flightgear file|src/Scripting/NasalPositioned.cxx}}&lt;br /&gt;
* {{flightgear file|src/Scripting/NasalSys.cxx}}&lt;br /&gt;
* {{fgdata file|Nasal/globals.nas}}&lt;br /&gt;
&lt;br /&gt;
=== abort() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = abort();&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=565|t=Source}}&lt;br /&gt;
|text = This function is a wrapper for the C++ {{func link|abort()|link=http://www.cplusplus.com/reference/cstdlib/abort/}} function. It simply aborts FlightGear with an error, which varies depending on the operating system. This function should not really be used; instead, please use the &amp;quot;exit&amp;quot; [[Fgcommands|fgcommand]], which will exit FlightGear more gracefully (see example below).&lt;br /&gt;
|example1text = This example will immediately stop FlightGear with an error, such as &amp;quot;FlightGear has stopped working.&amp;quot;&lt;br /&gt;
|example1 = abort();&lt;br /&gt;
|example2text = For exiting FlightGear in a better way, please use the following code:&lt;br /&gt;
|example2 = fgcommand(&amp;quot;exit&amp;quot;);&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== abs() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = abs(number);&lt;br /&gt;
|source = {{fgdata file|Nasal/globals.nas|t=Source}}&lt;br /&gt;
|text = This simple function returns the {{wikipedia|absolute value|noicon=1}} of the provided number.&lt;br /&gt;
|param1 = number&lt;br /&gt;
|param1text = This argument is required and should be a number.&lt;br /&gt;
|example1 = print(abs(1)); # prints &amp;quot;1&amp;quot;&lt;br /&gt;
|example2 = print(abs(-1)); # prints &amp;quot;1&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== aircraftToCart() ===&lt;br /&gt;
This new function in FG 2017.2.1 takes coordinates in aircraft structural coordinate system, and translate them into geocentric coordinates.&lt;br /&gt;
Example for (5,6,7):&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var pos = aircraftToCart({x: -5, y: 6, z: -7});&lt;br /&gt;
var coord = geo.Coord.new();&lt;br /&gt;
coord.set_xyz(pos.x, pos.y, pos.z);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Notice: x and z is inverted sign on purpose.&lt;br /&gt;
if you want lat. lon, alt from that, just call: (degrees and meters)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
coord.lat()&lt;br /&gt;
coord.lon()&lt;br /&gt;
coord.alt()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== addcommand() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = addcommand(name, code);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=659|t=Source}}&lt;br /&gt;
|version = 2.12&lt;br /&gt;
|commit = {{flightgear commit|7b663c|t=commit}}&lt;br /&gt;
|text = {{see also|Howto:Add new fgcommands to FlightGear}}&lt;br /&gt;
&lt;br /&gt;
This function enables the addition of a new custom [[fgcommands|fgcommand]] to FlightGear from within Nasal. An fgcommand created using this method can be used in exactly the same way as the built-in fgcommands. Also, an fgcommand created via this method will always return True or 1, like all other fgcommands.&lt;br /&gt;
|param1 = name&lt;br /&gt;
|param1text = This will become the name of the new fgcommand. Must be a string.&lt;br /&gt;
|param2 = code&lt;br /&gt;
|param2text = The code that will be executed when the fgcommand is run. Must be a function.&lt;br /&gt;
|example1text = This example adds a new fgcommand and then runs it. Although it executes a simple {{func link|print()}} statement, any valid Nasal code can be used.&lt;br /&gt;
|example1 = addcommand(&amp;quot;myFGCmd&amp;quot;, func(node) {&lt;br /&gt;
    print(&amp;quot;fgcommand 'myFGCmd' has been run.&amp;quot;);&lt;br /&gt;
    props.dump( node );&lt;br /&gt;
});&lt;br /&gt;
fgcommand(&amp;quot;myFGCmd&amp;quot;, props.Node.new({foo:1, bar:2}) );&lt;br /&gt;
|example2text = This example demonstrates how parameters are defined in a new fgcommand.&lt;br /&gt;
|example2 = addcommand(&amp;quot;myFGCmd&amp;quot;, func(node){&lt;br /&gt;
    print(node.getNode(&amp;quot;number&amp;quot;).getValue()); # prints the value of &amp;quot;number,&amp;quot; which is 12&lt;br /&gt;
});&lt;br /&gt;
fgcommand(&amp;quot;myFGCmd&amp;quot;, props.Node.new({&amp;quot;number&amp;quot;: 12}));&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== airportinfo() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = airportinfo();&lt;br /&gt;
airportinfo(type);&lt;br /&gt;
airportinfo(id);&lt;br /&gt;
airportinfo(lat, lon[, type]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1024|t=Source}}&lt;br /&gt;
|text = Function for retrieval of airport, heliport, or seaplane base information. It returns a Nasal ghost; however, its structure is like that of a Nasal hash. The following information is returned:&lt;br /&gt;
* '''parents''': A vector containing a hash of various functions to access information about the runway. See {{flightgear file|src/Scripting/NasalPositioned.cxx|l=2659}} for full list.&lt;br /&gt;
* '''lon''': Longitude of the location.&lt;br /&gt;
* '''lat''': Latitude of the location.&lt;br /&gt;
* '''has_metar''': True or false depending whether the airport has a [[METAR]] code defined for it.&lt;br /&gt;
* '''elevation''': Elevation of the location in metres.&lt;br /&gt;
* '''id''': ICAO code of the airport (or ID of the seaplane base/heliport).&lt;br /&gt;
* '''name''': Name of the airport/heliport/seaplane base.&lt;br /&gt;
* '''runways'''&lt;br /&gt;
** '''&amp;lt;runway name&amp;gt;'''&lt;br /&gt;
*** '''id''': Name of runway.&lt;br /&gt;
*** '''lat''': Latitude of the runway.&lt;br /&gt;
*** '''lon''': Longitude of the runway.&lt;br /&gt;
*** '''heading''': Heading of the runway.&lt;br /&gt;
*** '''length''': Length of the runway in metres.&lt;br /&gt;
*** '''width''': Width of the runway in metres.&lt;br /&gt;
*** '''surface''': Runway surface type.&lt;br /&gt;
*** '''threshold''': Length of the runway's {{wikipedia|displaced threshold}} in metres. Will return 0 if there is none.&lt;br /&gt;
*** '''stopway''': Length of the runway's stopway (the area before the threshold) in metres. Will return 0 if there is none.&lt;br /&gt;
*** '''reciprocal''': &amp;lt;code&amp;gt;runway&amp;lt;/code&amp;gt; ghost of the reciprocal runway.&lt;br /&gt;
*** '''ils_frequency_mhz''': ILS frequency in megahertz.&lt;br /&gt;
*** '''ils''': &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt; ghost of the ILS transmitter.&lt;br /&gt;
* '''helipads'''&lt;br /&gt;
** '''&amp;lt;helipad name&amp;gt;'''&lt;br /&gt;
*** '''id''': Name of helipad.&lt;br /&gt;
*** '''lat''': Latitude of the helipad.&lt;br /&gt;
*** '''lon''': Longitude of the helipad.&lt;br /&gt;
*** '''heading''': Heading of the helipad.&lt;br /&gt;
*** '''length''': Length of the helipad in metres.&lt;br /&gt;
*** '''width''': Width of the helipad in metres.&lt;br /&gt;
*** '''surface''': Helipad surface type.&lt;br /&gt;
* '''taxiways'''&lt;br /&gt;
** '''&amp;lt;taxiway name&amp;gt;'''&lt;br /&gt;
*** '''id''': Name of taxiway.&lt;br /&gt;
*** '''lat''': Latitude of the taxiway.&lt;br /&gt;
*** '''lon''': Longitude of the taxiway.&lt;br /&gt;
*** '''heading''': Heading of the taxiway.&lt;br /&gt;
*** '''length''': Length of the taxiway in metres.&lt;br /&gt;
*** '''width''': Width of the taxiway in metres.&lt;br /&gt;
*** '''surface''': Taxiway surface type.&lt;br /&gt;
&lt;br /&gt;
Information is extracted in the same way as accessing members of a Nasal hash. For example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
# prints to lengths of the runways of the nearest airport in feet and metres&lt;br /&gt;
var info = airportinfo();&lt;br /&gt;
print(&amp;quot;-- Lengths of the runways at &amp;quot;, info.name, &amp;quot; (&amp;quot;, info.id, &amp;quot;) --&amp;quot;);&lt;br /&gt;
foreach(var rwy; keys(info.runways)){&lt;br /&gt;
    print(rwy, &amp;quot;: &amp;quot;, math.round(info.runways[rwy].length * M2FT), &amp;quot; ft (&amp;quot;, info.runways[rwy].length, &amp;quot; m)&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that searches for locations that are a long way away (e.g., the nearest seaplane base to the middle of the Sahara) may cause FlightGear to pause for an amount of time.&lt;br /&gt;
|param1 = id&lt;br /&gt;
|param1text = The {{wikipedia|International Civil Aviation Organization airport code|ICAO code|noicon=1}} of an airport to retrieve information about.&lt;br /&gt;
|param2 = type&lt;br /&gt;
|param2text = When this argument is used, the function will return the closest airport of a certain type. Can be one of &amp;quot;heliport,&amp;quot; &amp;quot;seaport,&amp;quot; or &amp;quot;airport&amp;quot; (default).&lt;br /&gt;
: {{inote|Running this function without any parameters is equivalent to this:&lt;br /&gt;
: &amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
airportinfo(&amp;quot;airport&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
|param3 = lat ''and'' lon&lt;br /&gt;
|param3text = When these parameters are used, the function will return information on the nearest airport, heliport or seaplane base (depending on the '''type''' parameter) to those coordinates.&lt;br /&gt;
|example1 = var info = airportinfo();&lt;br /&gt;
print(&amp;quot;Nearest airport: &amp;quot;, info.name, &amp;quot; (&amp;quot;, info.id, &amp;quot;)&amp;quot;); # prints the name and ICAO code of the nearest airport&lt;br /&gt;
|example2 = var info = airportinfo(&amp;quot;heliport&amp;quot;);&lt;br /&gt;
print(&amp;quot;Elevation of the nearest heliport: &amp;quot;, math.round(info.elevation * M2FT), &amp;quot; ft&amp;quot;); # prints the elevation and name of the nearest heliport&lt;br /&gt;
|example3 = var info = airportinfo(&amp;quot;KSQL&amp;quot;);&lt;br /&gt;
print(&amp;quot;-- Runways of &amp;quot;, info.name, &amp;quot; (&amp;quot;, info.id, &amp;quot;): --&amp;quot;);&lt;br /&gt;
foreach(var rwy; keys(info.runways)) {&lt;br /&gt;
    print(rwy); # prints the runways of KSQL&lt;br /&gt;
}&lt;br /&gt;
|example4 = var info = airportinfo(37.81909385, -122.4722484);&lt;br /&gt;
print(&amp;quot;Coordinates of the nearest airport: &amp;quot;, info.lat, &amp;quot;, &amp;quot;, info.lon); # print the name and ICAO of the nearest airport to the Golden Gate Bridge&lt;br /&gt;
|example5 = var info = airportinfo(37.81909385, -122.4722484, &amp;quot;seaport&amp;quot;);&lt;br /&gt;
print(&amp;quot;Nearest seaplane base: &amp;quot;, info.name, &amp;quot; (&amp;quot;, info.id, &amp;quot;)&amp;quot;); # print the name and ID of the nearest seaplane base to the Golden Gate Bridge&lt;br /&gt;
|example6text = This example prints the all information from an &amp;lt;code&amp;gt;airportinfo()&amp;lt;/code&amp;gt; call.&lt;br /&gt;
|example6 = var info = airportinfo(&amp;quot;KSFO&amp;quot;);&lt;br /&gt;
print(info.name);&lt;br /&gt;
print(info.id);&lt;br /&gt;
print(info.lat);&lt;br /&gt;
print(info.lon);&lt;br /&gt;
print(info.has_metar);&lt;br /&gt;
print(info.elevation);&lt;br /&gt;
foreach(var rwy; keys(info.runways)){&lt;br /&gt;
    print(&amp;quot;-- &amp;quot;, rwy, &amp;quot; --&amp;quot;);&lt;br /&gt;
    print(info.runways[rwy].lat);&lt;br /&gt;
    print(info.runways[rwy].lon);&lt;br /&gt;
    print(info.runways[rwy].length);&lt;br /&gt;
    print(info.runways[rwy].width);&lt;br /&gt;
    print(info.runways[rwy].heading);&lt;br /&gt;
    print(info.runways[rwy].stopway);&lt;br /&gt;
    print(info.runways[rwy].threshold);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== airwaysRoute() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = airwaysRoute(start, end[, type]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1933|t=Source}}&lt;br /&gt;
|text = {{see also|Nasal Flightplan}}&lt;br /&gt;
This function returns a vector containing waypoints between two given waypoints. The returned waypoints are ghosts, but can be accessed in the same way as a Nasal hash. See [[Nasal Flightplan]] for more information.&lt;br /&gt;
|param1 = start&lt;br /&gt;
|param1text = Start waypoint, in the form of a waypoint ghost, such as that provided by {{func link|flightplan()}}.&lt;br /&gt;
|param2 = end&lt;br /&gt;
|param2text = Same as above.&lt;br /&gt;
|param3 = type&lt;br /&gt;
|param3text = Instructs the function to compute a high level route (when set to &amp;quot;highlevel&amp;quot;), or a low level route (when set to &amp;quot;lowlevel&amp;quot;). Defaults to &amp;quot;highlevel.&amp;quot;&lt;br /&gt;
|example1text = In the [[route manager]] dialog, add two waypoints to the flightplan, ideally ones that are far apart (tip: use the [[Map]] for this). Then run this code in your Nasal Console.&lt;br /&gt;
|example1 = var fp = flightplan();&lt;br /&gt;
var start = fp.getWP(0);&lt;br /&gt;
var end = fp.getWP(fp.getPlanSize() - 1);&lt;br /&gt;
var rt = airwaysRoute(start, end);&lt;br /&gt;
foreach(var wp; rt){&lt;br /&gt;
    print(wp.wp_name); # print the waypoints in the computed route&lt;br /&gt;
}&lt;br /&gt;
|example2text = Exactly the same as above, but computes a low level path.&lt;br /&gt;
|example2 = var fp = flightplan();&lt;br /&gt;
var start = fp.getWP(0);&lt;br /&gt;
var end = fp.getWP(fp.getPlanSize() - 1);&lt;br /&gt;
var rt = airwaysRoute(start, end, &amp;quot;lowlevel&amp;quot;);&lt;br /&gt;
foreach(var wp; rt){&lt;br /&gt;
    print(wp.wp_name); # print the waypoints in the computed route&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== airway() ===&lt;br /&gt;
&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = airway(ident [, pos]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=2644|t=Source}}&lt;br /&gt;
|text = {{see also|Nasal Flightplan}}&lt;br /&gt;
This function returns a ghost containing an airway of a specified id.&lt;br /&gt;
|param1 = ident&lt;br /&gt;
|param1text = Identifier of airway&lt;br /&gt;
|param2 = pos&lt;br /&gt;
|param1text = a Positioned ghost (leg, navaid, airport) and so on, passed to the search function. &lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== assert() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = assert(condition[, message]);&lt;br /&gt;
|source = {{fgdata file|Nasal/globals.nas|t=Source}}&lt;br /&gt;
|version = 3.2&lt;br /&gt;
|commit = {{fgdata commit|8b16a7|t=commit}}&lt;br /&gt;
|text = Returns either true if the condition evaluates as true, or aborts with a {{func link|die()}} call, which can be customised.&lt;br /&gt;
|param1 = condition&lt;br /&gt;
|param1text = Condition to evaluate.&lt;br /&gt;
|param2 = message&lt;br /&gt;
|param2text = Optional message that will be used in any {{func link|die()}} call. Defaults to &amp;quot;assertion failed!&amp;quot;&lt;br /&gt;
|example1 = var a = 1;&lt;br /&gt;
var b = 2;&lt;br /&gt;
print(assert(a &amp;lt; b)); # prints &amp;quot;1&amp;quot; (true)&lt;br /&gt;
|example2 = var a = 1;&lt;br /&gt;
var b = 2;&lt;br /&gt;
assert(a &amp;gt; b, 'a is not greater than b'); # aborts with a custom error message&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== carttogeod() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = carttogeod(x, y, z);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=945|t=Source}}&lt;br /&gt;
|text = Converts {{wikipedia|ECEF|Earth-centered, Earth-fixed}} coordinates (x, y and z) to {{wikipedia|geodetic coordinates}} (latitude, longitude, and altitude). A vector is returned containing latitude and longitude, both in degrees, and altitude, which is returned in metres above the equatorial radius of Earth as defined by the {{wikipedia|WGS 84}} (6,378,137 metres).&amp;lt;ref&amp;gt;{{simgear file|simgear/math/sg_geodesy.hxx|l=43}}&amp;lt;/ref&amp;gt;&lt;br /&gt;
|param1 = x&lt;br /&gt;
|param1text = Mandatory x-axis value, in metres.&lt;br /&gt;
|param2 = y&lt;br /&gt;
|param2text = Mandatory y-axis value, in metres.&lt;br /&gt;
|param3 = z&lt;br /&gt;
|param3text = Mandatory z-axis value, in metres.&lt;br /&gt;
|example1 = var (lat, lon, alt) = carttogeod(6378137, 0, 0); # point is the intersection of the prime meridian and equator.&lt;br /&gt;
print(&amp;quot;Latitude: &amp;quot;, lat); # prints lat, lon and alt, which are all zero, see above&lt;br /&gt;
print(&amp;quot;Longitude: &amp;quot;, lon);&lt;br /&gt;
print(&amp;quot;Altitude: &amp;quot;, alt);&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== cmdarg() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|private = _cmdarg()&lt;br /&gt;
|syntax = cmdarg();&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=513|t=Part 1}} {{!}} {{fgdata file|Nasal/globals.nas|t=Part 2}}&lt;br /&gt;
|text = &amp;lt;code&amp;gt;cmdarg()&amp;lt;/code&amp;gt; returns the property root of certain types of XML files. These could be nodes in the [[Property Tree]], or temporary and/or non-public nodes outside the Property tree. &lt;br /&gt;
It is used by Nasal scripts embedded in XML files. It returns a &amp;lt;code&amp;gt;props.Node&amp;lt;/code&amp;gt; object (see {{fgdata file|Nasal/props.nas}}), and you can use all of its methods on the returned value. &amp;lt;code&amp;gt;cmdarg()&amp;lt;/code&amp;gt; should only be used in four types/places of XML files:&lt;br /&gt;
* Bindings: This is needed so that the value of a joystick's axis can be accessed internally.&lt;br /&gt;
* Dialogs: This will return the root of the dialog in the Property Tree. This is useful for dialogs that are created/modified procedurally (e.g. for populating/changing widgets while loading the dialog). &lt;br /&gt;
* Embedded Canvases: The Nasal code behind [[Canvas]] windows [[Howto:Adding a canvas to a GUI dialog|embedded in PUI dialogs]] can use it to accessing the root directory of their Canvas.&lt;br /&gt;
* Animation XML files: If the animation XML file is used in an AI/MP model, &amp;lt;code&amp;gt;cmdarg()&amp;lt;/code&amp;gt; will return the root of the AI model in the &amp;lt;code&amp;gt;/ai/models/&amp;lt;/code&amp;gt; directory. Examples: &amp;lt;code&amp;gt;/ai/models/aircraft[3]/&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/ai/models/multiplayer[1]/&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should not use &amp;lt;code&amp;gt;cmdarg()&amp;lt;/code&amp;gt; in places other than those stated above. Although it won't cause an error, it will return the value of the last legitimate &amp;lt;code&amp;gt;cmdarg()&amp;lt;/code&amp;gt; call. &lt;br /&gt;
&lt;br /&gt;
Also, you should not delay &amp;lt;code&amp;gt;cmdarg()&amp;lt;/code&amp;gt; using {{func link|maketimer()}}, {{func link|settimer()}} or {{func link|setlistener()}}, because it will return an unrelated property.&lt;br /&gt;
|example1 = fgcommand(&amp;quot;dialog-show&amp;quot;, {&amp;quot;dialog-name&amp;quot;: &amp;quot;cmdarg-demo&amp;quot;});&lt;br /&gt;
|example1text = &amp;lt;br&amp;gt;This example demonstrates the usage of &amp;lt;code&amp;gt;cmdarg()&amp;lt;/code&amp;gt; in a binding.  Save the below XML snippet as &amp;lt;tt&amp;gt;[[$FG_ROOT]]/gui/dialogs/cmdarg-demo.xml&amp;lt;/tt&amp;gt;. Then run the Nasal snippet below in your [[Nasal Console]]. Upon clicking {{button|Close}}, a message will be printed sowing the root of the binding in the Property Tree.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;PropertyList&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;name&amp;gt;cmdarg-demo&amp;lt;/name&amp;gt;&lt;br /&gt;
&amp;lt;layout&amp;gt;vbox&amp;lt;/layout&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;text&amp;gt;&lt;br /&gt;
  &amp;lt;label&amp;gt;Click &amp;quot;Close&amp;quot; to activate the demonstration (a message in the console).&amp;lt;/label&amp;gt;&lt;br /&gt;
&amp;lt;/text&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;button&amp;gt;&lt;br /&gt;
  &amp;lt;legend&amp;gt;Close&amp;lt;/legend&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
    &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;print(&amp;quot;Button binding root: '&amp;quot; ~ cmdarg().getPath() ~ &amp;quot;'&amp;quot;);&amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
    &amp;lt;command&amp;gt;dialog-close&amp;lt;/command&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/PropertyList&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|example2text = This example demonstrates the usage of &amp;lt;code&amp;gt;cmdarg()&amp;lt;/code&amp;gt; in Nasal code within dialogs.  Open &amp;lt;tt&amp;gt;[[$FG_ROOT]]/gui/dialogs/cmdarg-demo.xml&amp;lt;/tt&amp;gt; from the previous example, copy &amp;amp; paste the code below, and save it. Then run the same Nasal snippet as the previous example in your Nasal Console. If you click {{button|Click me!}}, the button's label will change to &amp;quot;I've been changed!&amp;quot;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;PropertyList&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;name&amp;gt;cmdarg-demo&amp;lt;/name&amp;gt;&lt;br /&gt;
&amp;lt;layout&amp;gt;vbox&amp;lt;/layout&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;text&amp;gt;&lt;br /&gt;
  &amp;lt;label&amp;gt;Click &amp;quot;Click me!&amp;quot; to activate the demonstration (the button's label will change).&amp;lt;/label&amp;gt;&lt;br /&gt;
&amp;lt;/text&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;button&amp;gt;&lt;br /&gt;
  &amp;lt;legend&amp;gt;Click me!&amp;lt;/legend&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
    &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;change_label();&amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;button&amp;gt;&lt;br /&gt;
  &amp;lt;legend&amp;gt;Close&amp;lt;/legend&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
    &amp;lt;command&amp;gt;dialog-close&amp;lt;/command&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nasal&amp;gt;&lt;br /&gt;
  &amp;lt;open&amp;gt;&amp;lt;![CDATA[&lt;br /&gt;
    var dlg_root = cmdarg();&lt;br /&gt;
    var dlg_name = {&amp;quot;dialog-name&amp;quot;: &amp;quot;cmdarg-demo&amp;quot;};&lt;br /&gt;
    var change_label = func {&lt;br /&gt;
        dlg_root.getNode(&amp;quot;button[0]/legend&amp;quot;).setValue(&amp;quot;I've been changed!&amp;quot;);&lt;br /&gt;
        fgcommand(&amp;quot;dialog-close&amp;quot;, dlg_name);&lt;br /&gt;
        fgcommand(&amp;quot;dialog-show&amp;quot;, dlg_name);&lt;br /&gt;
    }&lt;br /&gt;
  ]]&amp;gt;&amp;lt;/open&amp;gt;&lt;br /&gt;
&amp;lt;/nasal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/PropertyList&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|example3text = For an example of &amp;lt;code&amp;gt;cmdarg()&amp;lt;/code&amp;gt; used with Canvas, please see [[Howto:Adding a canvas to a GUI dialog#FGPlot|Howto:Adding a canvas to a GUI dialog]].&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== courseAndDistance() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = courseAndDistance(to);&lt;br /&gt;
courseAndDistance(from, to);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1668|t=Source}}&lt;br /&gt;
|text = Returns a vector containing the course from one point to another and the distance between them in nautical miles. The course is the initial bearing (see [http://www.movable-type.co.uk/scripts/latlong.html#bearing here]), and is in the range 0–360. Both arguments can be one of:&lt;br /&gt;
:* An &amp;lt;code&amp;gt;airport&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;runway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;taxiway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fix&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;waypoint&amp;lt;/code&amp;gt; ghost type&lt;br /&gt;
:* A hash with ''lat'' and ''lon'' members&lt;br /&gt;
:* A geo.Coord object&lt;br /&gt;
|param1 = from&lt;br /&gt;
|param1text = Optional parameter defining the from where the function should calculate its results. If the function is given one argument ('''to'''), the aircraft's current position will be used. As well as the argument types as defined above, this argument can be two numbers separated with a comma, as if the function is taking three arguments. See example 5 below.&lt;br /&gt;
|param2 = to&lt;br /&gt;
|param2text = Like the first parameter, but defines the second point.&lt;br /&gt;
|example1text = This example demonstrates the usage of the function with the &amp;lt;code&amp;gt;airport&amp;lt;/code&amp;gt; ghost type.&lt;br /&gt;
|example1 = var from = airportinfo(&amp;quot;KSFO&amp;quot;);&lt;br /&gt;
var to = airportinfo(&amp;quot;KSQL&amp;quot;);&lt;br /&gt;
var (course, dist) = courseAndDistance(from, to);&lt;br /&gt;
print(course); # prints course from KSFO to KSQL&lt;br /&gt;
print(dist); # prints distance in nm from KSFO to KSQL&lt;br /&gt;
|example2text = This example demonstrates the usage of the function with hashes containing ''lat'' and ''lon''.&lt;br /&gt;
|example2 = var from = {lat: 0, lon: 0};&lt;br /&gt;
var to = {lat: 1, lon: 1};&lt;br /&gt;
var (course, dist) = courseAndDistance(from, to);&lt;br /&gt;
print(course);&lt;br /&gt;
print(dist);&lt;br /&gt;
|example3text = This example demonstrates usage of a geo.Coord object.&lt;br /&gt;
|example3 = var from = geo.Coord.new().set_latlon(0, 0);&lt;br /&gt;
var to = geo.Coord.new().set_latlon(1, 1);&lt;br /&gt;
var (course, dist) = courseAndDistance(from, to);&lt;br /&gt;
print(course);&lt;br /&gt;
print(dist);&lt;br /&gt;
|example4text = This example demonstrates usage of differing parameter types.&lt;br /&gt;
|example4 = var from = airportinfo(&amp;quot;KSFO&amp;quot;);&lt;br /&gt;
var to = geo.Coord.new().set_latlon(0, 0);&lt;br /&gt;
var (course, dist) = courseAndDistance(from, to);&lt;br /&gt;
print(course);&lt;br /&gt;
print(dist);&lt;br /&gt;
|example5text = The same as above, but the other way round.&lt;br /&gt;
|example5 = var to = {lat: 1, lon: 1};&lt;br /&gt;
var (course, dist) = courseAndDistance(0, 0, to);&lt;br /&gt;
print(course);&lt;br /&gt;
print(dist);&lt;br /&gt;
|example6text = Usage of just one parameter.&lt;br /&gt;
|example6 = var dest = airportinfo(&amp;quot;KSQL&amp;quot;);&lt;br /&gt;
var (course, dist) = courseAndDistance(dest);&lt;br /&gt;
print(&amp;quot;Turn to heading &amp;quot;, math.round(course), &amp;quot;. You have &amp;quot;, sprintf(&amp;quot;%.2f&amp;quot;, dist), &amp;quot; nm to go&amp;quot;);&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== createFlightplan() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = createFlightplan(path);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=2331|t=Source}}&lt;br /&gt;
|text = Creates an empty flightplan object. It accepts one argument, ''path'' passed an absolute path to a .fgfp / .gpx file, it will populate the flightplan with waypoints from the file.&lt;br /&gt;
|param1 = path&lt;br /&gt;
|param1text = Optional parameter defining the file from which a flightplan will be populated.&lt;br /&gt;
|example1 = &lt;br /&gt;
var path = getprop(&amp;quot;/sim/fg-home&amp;quot;) ~ &amp;quot;/Export/test.fgfp&amp;quot;;&lt;br /&gt;
var flightplan = createFlightplan(path);&lt;br /&gt;
debug.dump(flightplan);&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== createDiscontinuity() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = createDiscontinuity();&lt;br /&gt;
|text = Returns a &amp;lt;code&amp;gt;waypoint&amp;lt;/code&amp;gt; ghost object. A route discontinuity is inserted by an {{abbr|FMS|Flight Management System}} when it is unsure how to connect two waypoints.&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=2045|t=Source}}&lt;br /&gt;
|version = 2016.1&lt;br /&gt;
|commit = {{flightgear commit|caead6|t=commit}}&lt;br /&gt;
}}&lt;br /&gt;
=== createViaTo() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = createViaTo(airway, waypoint);&lt;br /&gt;
|text = Returns a &amp;lt;code&amp;gt;waypoint&amp;lt;/code&amp;gt; ghost object. It represents a route &amp;quot;via '''airway''' to '''waypoint'''&amp;quot;.&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=2009|t=Source}}&lt;br /&gt;
|version = 2016.1&lt;br /&gt;
|commit = {{flightgear commit|caead6|t=commit}}&lt;br /&gt;
|param1 = airway&lt;br /&gt;
|param1text = The name of an airway.&lt;br /&gt;
|param2 = waypoint&lt;br /&gt;
|param2text = Must be in the airway and one of:&lt;br /&gt;
* The name of a waypoint.&lt;br /&gt;
* An &amp;lt;code&amp;gt;airport&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;runway&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;fix&amp;lt;/code&amp;gt; ghost object.&lt;br /&gt;
}}&lt;br /&gt;
=== createWP() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = createWP(pos, name[, flag]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1964|t=Source}}&lt;br /&gt;
|text = Creates a new waypoint ghost object.&lt;br /&gt;
|param1 = pos&lt;br /&gt;
|param1text = Dictates the position of the new waypoint. It can be one of the following:&lt;br /&gt;
:* An &amp;lt;code&amp;gt;airport&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;runway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;taxiway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fix&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;waypoint&amp;lt;/code&amp;gt; ghost type&lt;br /&gt;
:* A hash with ''lat'' and ''lon'' members&lt;br /&gt;
:* A geo.Coord object&lt;br /&gt;
:* Two numbers separated by a comma, as if the function is taking three arguments. See example 4 below.&lt;br /&gt;
|param2 = name&lt;br /&gt;
|param2text = String that will become the name of the new waypoint.&lt;br /&gt;
|param3 = flag&lt;br /&gt;
|param3text = Optional string that will tell FlightGear what type of waypoint it is. Must be one of &amp;quot;sid,&amp;quot; &amp;quot;star,&amp;quot; &amp;quot;approach,&amp;quot; &amp;quot;missed,&amp;quot; or &amp;quot;pseudo.&amp;quot;&lt;br /&gt;
|example1text = Creates a waypoint directly in front and 1 km away and appends it to the flight plan.&lt;br /&gt;
|example1 = var pos = geo.aircraft_position().apply_course_distance(getprop(&amp;quot;/orientation/heading-deg&amp;quot;), 1000);&lt;br /&gt;
var wp = createWP(pos, &amp;quot;NEWWP&amp;quot;);&lt;br /&gt;
var fp = flightplan();&lt;br /&gt;
fp.appendWP(wp);&lt;br /&gt;
|example2 = var pos = geo.aircraft_position().apply_course_distance(getprop(&amp;quot;/orientation/heading-deg&amp;quot;), 1000);&lt;br /&gt;
var wp = createWP({lat: pos.lat(), lon: pos.lon()}, &amp;quot;NEWWP&amp;quot;);&lt;br /&gt;
var fp = flightplan();&lt;br /&gt;
fp.appendWP(wp);&lt;br /&gt;
|example3 = var apt = airportinfo();&lt;br /&gt;
var wp = createWP(apt, &amp;quot;NEWWP&amp;quot;);&lt;br /&gt;
var fp = flightplan();&lt;br /&gt;
fp.appendWP(wp);&lt;br /&gt;
|example4 = var pos = geo.aircraft_position().apply_course_distance(getprop(&amp;quot;/orientation/heading-deg&amp;quot;), 1000);&lt;br /&gt;
var wp = createWP(pos.lat(), pos.lon(), &amp;quot;NEWWP&amp;quot;);&lt;br /&gt;
var fp = flightplan();&lt;br /&gt;
fp.appendWP(wp);&lt;br /&gt;
|example5text = Creates a new waypoint and adds it to the flight plan. Waypoints of the type &amp;quot;pseudo&amp;quot; are then removed from the flight plan, including the new waypoint. The {{func link|print()}} statements show this.&lt;br /&gt;
|example5 = var pos = geo.aircraft_position().apply_course_distance(getprop(&amp;quot;/orientation/heading-deg&amp;quot;), 1000);&lt;br /&gt;
var wp = createWP(pos, &amp;quot;NEWWP&amp;quot;, &amp;quot;pseudo&amp;quot;);&lt;br /&gt;
var fp = flightplan();&lt;br /&gt;
fp.appendWP(wp);&lt;br /&gt;
print(fp.getPlanSize());&lt;br /&gt;
fp.clearWPType(&amp;quot;pseudo&amp;quot;);&lt;br /&gt;
print(fp.getPlanSize());&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== createWPFrom() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = createWPFrom(object[, flag]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1989|t=Source}}&lt;br /&gt;
|text = Creates a new waypoint object from another object.&lt;br /&gt;
|param1 = object&lt;br /&gt;
|param1text = A ghost object. Must be a ghost type that is one of &amp;quot;airport,&amp;quot; &amp;quot;navaid,&amp;quot; &amp;quot;runway,&amp;quot; or &amp;quot;fix.&amp;quot;&lt;br /&gt;
|param2 = flag&lt;br /&gt;
|param2text = Optional string that will tell FlightGear what type of waypoint it is. Must be one of &amp;quot;sid,&amp;quot; &amp;quot;star,&amp;quot; &amp;quot;approach,&amp;quot; &amp;quot;missed,&amp;quot; or &amp;quot;pseudo.&amp;quot;&lt;br /&gt;
|example1text = Creates a new waypoint and appends it to the flight plan.&lt;br /&gt;
|example1 = var apt = airportinfo(&amp;quot;KSFO&amp;quot;);&lt;br /&gt;
var wp = createWPFrom(apt);&lt;br /&gt;
var fp = flightplan();&lt;br /&gt;
fp.appendWP(wp);&lt;br /&gt;
|example2text = Creates a new waypoint and appends it to the flight plan. This way point is then removed; the {{func link|print()}} statements prove this.&lt;br /&gt;
|example2 = var apt = airportinfo(&amp;quot;KSFO&amp;quot;);&lt;br /&gt;
var wp = createWPFrom(apt, &amp;quot;pseudo&amp;quot;);&lt;br /&gt;
print(wp.wp_name);&lt;br /&gt;
var fp = flightplan();&lt;br /&gt;
fp.appendWP(wp);&lt;br /&gt;
print(fp.getPlanSize());&lt;br /&gt;
fp.clearWPType(&amp;quot;pseudo&amp;quot;);&lt;br /&gt;
print(fp.getPlanSize());&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== defined() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = defined(symbol);&lt;br /&gt;
|source = {{fgdata file|Nasal/globals.nas|t=Source}}&lt;br /&gt;
|text = Returns 1 (true) or 0 (false) depending on whether a variable exists.&lt;br /&gt;
|param1 = symbol&lt;br /&gt;
|param1text = A string that will be what the function searches for.&lt;br /&gt;
|example1 = var number = 12;&lt;br /&gt;
var check_exist = func {&lt;br /&gt;
    print(&amp;quot;Variable 'number' &amp;quot;, defined(&amp;quot;number&amp;quot;) == 1 ? &amp;quot;exists&amp;quot; : &amp;quot;does not exist&amp;quot;); # 'number' does exist&lt;br /&gt;
    print(&amp;quot;Variable 'number2' &amp;quot;, defined(&amp;quot;number2&amp;quot;) == 1 ? &amp;quot;exists&amp;quot; : &amp;quot;does not exist&amp;quot;); # 'number2' does not exist&lt;br /&gt;
}&lt;br /&gt;
check_exist();&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== directory() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = directory(path);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=572|t=Source}}&lt;br /&gt;
|text = Returns a vector containing a list of the folders and files in a given file path or &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt; if the path doesn't exist. Hidden folders and files are not added to the vector.&lt;br /&gt;
{{inote|The first two elements of the vector will be &amp;lt;code&amp;gt;'.'&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;'..'&amp;lt;/code&amp;gt;. These are for navigating back up the file tree, but have no use in Nasal. They can be safely removed from the vector.}}&lt;br /&gt;
|param1 = path&lt;br /&gt;
|param1text = Absolute file path.&lt;br /&gt;
|example1text = Gets the folders and files in [[$FG_ROOT]], and then removes the extra first two elements (see note above). &lt;br /&gt;
|example1 = var dir = directory(getprop(&amp;quot;/sim/fg-root&amp;quot;)); # get directory&lt;br /&gt;
dir = subvec(dir, 2); # strips off the first two elements&lt;br /&gt;
debug.dump(dir); # dump the vector&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== fgcommand() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = fgcommand(cmd[, args]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=456|t=Part 1}} {{!}} {{fgdata file|Nasal/globals.nas|t=Part 2}}&lt;br /&gt;
|text = Runs an fgcommand. See also {{readme file|commands}} and [[Bindings]] for more information. See {{flightgear file|src/Main/fg_commands.cxx|l=1425}} for the full list of fgcommands. Note that fgcommands generated by {{func link|addcommand()}} can also be run using this function. Also, the full list of fgcommands depends on the version of FlightGear you have. Returns 1 (true) if the fgcommand succeeded or 0 (false) if it failed.&lt;br /&gt;
|param1 = cmd&lt;br /&gt;
|param1text = String that is the name of the command that is to be run.&lt;br /&gt;
|param2 = args&lt;br /&gt;
|param2text = If the fgcommand takes arguments, they are inputted using this argument. Can either be a &amp;lt;code&amp;gt;props.Node&amp;lt;/code&amp;gt; object, or a hash (see examples below).&lt;br /&gt;
|example1 = fgcommand(&amp;quot;null&amp;quot;); # does nothing&lt;br /&gt;
|example2 = var args = props.Node.new({'script': 'print(&amp;quot;Running fgcommand&amp;quot;);'});&lt;br /&gt;
if (fgcommand(&amp;quot;nasal&amp;quot;, args)) { # prints &amp;quot;Running fgcommand&amp;quot; and then one of these print statements&lt;br /&gt;
    print(&amp;quot;Fgcommand succeeded&amp;quot;);&lt;br /&gt;
} else {&lt;br /&gt;
    print(&amp;quot;Fgcommand encountered a problem&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
|example3 = var args = { 'dialog-name': 'about' };&lt;br /&gt;
fgcommand(&amp;quot;dialog-show&amp;quot;, args); # shows the 'about' dialog&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== findAirportsByICAO() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = findAirportsByICAO(search[, type]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1096|t=Source}}&lt;br /&gt;
|text = Returns a vector containing &amp;lt;code&amp;gt;airport&amp;lt;/code&amp;gt; ghost objects which are (by default) airports whose ICAO code matches the search string. The results are sorted by range from closest to furthest.&lt;br /&gt;
|param1 = search&lt;br /&gt;
|param1text = Search string for the function. Can either be a partial or a full ICAO code.&lt;br /&gt;
:{{icaution|The more matches there are for the given code, the longer the function will take. Passing just one character (e.g., &amp;quot;K&amp;quot;), might make FlightGear hang for a certain amount of time.}}&lt;br /&gt;
|param2 = type&lt;br /&gt;
|param2text = This will narrow the search to airports of a certain type. By default, only airports are searched for. May be one of &amp;quot;airport,&amp;quot; &amp;quot;heliport,&amp;quot; or &amp;quot;seaport.&amp;quot;&lt;br /&gt;
|example1 = var apts = findAirportsByICAO(&amp;quot;KSF&amp;quot;); # finds all airports matching &amp;quot;KSF&amp;quot;&lt;br /&gt;
foreach(var apt; apts){&lt;br /&gt;
    print(apt.name, &amp;quot; (&amp;quot;, apt.id, &amp;quot;)&amp;quot;); # prints them&lt;br /&gt;
}&lt;br /&gt;
|example2 = var apts = findAirportsByICAO(&amp;quot;SP0&amp;quot;, &amp;quot;seaport&amp;quot;); # finds all seaplane bases matching &amp;quot;SP0&amp;quot;&lt;br /&gt;
foreach(var apt; apts){&lt;br /&gt;
    print(apt.name, &amp;quot; (&amp;quot;, apt.id, &amp;quot;)&amp;quot;); # prints them&lt;br /&gt;
}&lt;br /&gt;
|example3 = var apt = findAirportsByICAO(&amp;quot;XBET&amp;quot;); # one way to check if an airport does exist&amp;quot;&lt;br /&gt;
if (size(apt) == 0) {&lt;br /&gt;
    print(&amp;quot;Airport does not exist&amp;quot;); # this one will be printed&lt;br /&gt;
} else {&lt;br /&gt;
    print(&amp;quot;Airport does exist&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== findAirportsWithinRange() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = findAirportsWithinRange([pos, ]range[, type]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1066|t=Source}}&lt;br /&gt;
|text = Returns a vector of &amp;lt;code&amp;gt;airport&amp;lt;/code&amp;gt; ghost object which are (by default) airports that are within a given range of a given position, or the aircraft's current position. The results are sorted by range from closest to furthest.&lt;br /&gt;
|param1 = pos&lt;br /&gt;
|param1text = Optional position to search around. If not given, the aircraft's current position will be used. Can be one of:&lt;br /&gt;
:* An &amp;lt;code&amp;gt;airport&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;runway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;taxiway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fix&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;waypoint&amp;lt;/code&amp;gt; ghost type&lt;br /&gt;
:* A hash with ''lat'' and ''lon'' members&lt;br /&gt;
:* A geo.Coord object&lt;br /&gt;
:* Two numbers separated by a comma, as if the function is taking three arguments. Example: &amp;lt;code&amp;gt;findAirportsWithinRange(lat, lon, range, type);&amp;lt;/code&amp;gt;.&lt;br /&gt;
|param2 = range&lt;br /&gt;
|param2text = Mandatory number giving the range in nautical miles within which to search for airports/heliports/seaplane bases.only airports are searched for.&lt;br /&gt;
|param3 = type&lt;br /&gt;
|param3text = This will narrow the search to airports of a certain type. By default, only airports are searched for. May be one of &amp;quot;airport,&amp;quot; &amp;quot;heliport,&amp;quot; or &amp;quot;seaport.&amp;quot;&lt;br /&gt;
|example1text = Searches for airports within 10 nm of [[KSFO]].&lt;br /&gt;
|example1 = var pos = airportinfo(&amp;quot;KSFO&amp;quot;);&lt;br /&gt;
var apts = findAirportsWithinRange(pos, 10);&lt;br /&gt;
foreach(var apt; apts){&lt;br /&gt;
    print(apt.name, &amp;quot; (&amp;quot;, apt.id, &amp;quot;)&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
|example2text = Searches for seaplane bases within 15 nm of [[KSFO]].&lt;br /&gt;
|example2 = var pos = airportinfo(&amp;quot;KSFO&amp;quot;);&lt;br /&gt;
var apts = findAirportsWithinRange(pos, 15, &amp;quot;seaport&amp;quot;);&lt;br /&gt;
foreach(var apt; apts){&lt;br /&gt;
    print(apt.name, &amp;quot; (&amp;quot;, apt.id, &amp;quot;)&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
|example3text = Searches for airports within 10 nm of your current position.&lt;br /&gt;
|example3 = var apts = findAirportsWithinRange(10);&lt;br /&gt;
foreach(var apt; apts){&lt;br /&gt;
    print(apt.name, &amp;quot; (&amp;quot;, apt.id, &amp;quot;)&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== findFixesByID() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = findFixesByID([pos, ]id);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1627|t=Source}}&lt;br /&gt;
|text = Returns a vector containing &amp;lt;code&amp;gt;fix&amp;lt;/code&amp;gt; ghost objects matching a given ID, sorted by range from a certain position.&lt;br /&gt;
{{inote|Fixes are (usually) also known as waypoints.}}&lt;br /&gt;
|param1 = pos&lt;br /&gt;
|param1text = Optional position to search around. If not given, the aircraft's current position will be used. Can be one of:&lt;br /&gt;
:* An &amp;lt;code&amp;gt;airport&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;runway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;taxiway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fix&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;waypoint&amp;lt;/code&amp;gt; ghost type&lt;br /&gt;
:* A hash with ''lat'' and ''lon'' members&lt;br /&gt;
:* A geo.Coord object&lt;br /&gt;
:* Two numbers separated by a comma, as if the function is taking three arguments. Example: &amp;lt;code&amp;gt;findFixesByID(lat, lon, id);&amp;lt;/code&amp;gt;.&lt;br /&gt;
|param2 = id&lt;br /&gt;
|param2text = Full or partial ID of the fix to search for.&lt;br /&gt;
:{{inote|1=Inputting a partial ID does not work correctly (see [http://forum.flightgear.org/viewtopic.php?f=30&amp;amp;t=28129 here]). It is best to just input a full ID.}}&lt;br /&gt;
|example1 = var fixes = findFixesByID(&amp;quot;POGIC&amp;quot;);&lt;br /&gt;
foreach(var fix; fixes){&lt;br /&gt;
    print(fix.id, &amp;quot; - lat: &amp;quot;, fix.lat, &amp;quot; {{!}} lon: &amp;quot;, fix.lon); # prints information about POGIC&lt;br /&gt;
}&lt;br /&gt;
|example2 = var fix = findFixesByID(&amp;quot;ZUNAP&amp;quot;);&lt;br /&gt;
fix = fix[0];&lt;br /&gt;
var (course, dist) = courseAndDistance(fix);&lt;br /&gt;
print(&amp;quot;Turn to heading &amp;quot;, math.round(course), &amp;quot;. You have &amp;quot;, sprintf(&amp;quot;%.2f&amp;quot;, dist), &amp;quot; nm to go to reach &amp;quot;, fixes[0].id);&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== findNavaidByFrequency() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = findNavaidByFrequency([pos, ]freq[, type]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1547|t=Source}}&lt;br /&gt;
|text = Returns a &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt; ghost object for a navaid matching a given frequency. If there is more than one navaid with that frequency, the nearest station is returned.&lt;br /&gt;
|param1 = pos&lt;br /&gt;
|param1text = Optional position to search around. If not given, the aircraft's current position will be used. Can be one of:&lt;br /&gt;
:* An &amp;lt;code&amp;gt;airport&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;runway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;taxiway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fix&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;waypoint&amp;lt;/code&amp;gt; ghost type&lt;br /&gt;
:* A hash with ''lat'' and ''lon'' members&lt;br /&gt;
:* A geo.Coord object&lt;br /&gt;
:* Two numbers separated by a comma, as if the function is taking three arguments. Example: &amp;lt;code&amp;gt;findNavaidByFrequency(lat, lon, freq, type);&amp;lt;/code&amp;gt;.&lt;br /&gt;
|param2 = freq&lt;br /&gt;
|param2text = Frequency, in megahertz, of the navaid to search for.&lt;br /&gt;
|param3 = type&lt;br /&gt;
|param3text = This will narrow the search to navaids of a certain type. Defaults to &amp;quot;all.&amp;quot; For the full list of accepted type arguments, see {{flightgear file|src/Navaids/positioned.cxx|l=127}}.&lt;br /&gt;
|example1 = var navaid = findNavaidByFrequency(11.17);&lt;br /&gt;
print(&amp;quot;ID: &amp;quot;, navaid.id); # prints info about the navaid&lt;br /&gt;
print(&amp;quot;Name: &amp;quot;, navaid.name);&lt;br /&gt;
print(&amp;quot;Latitude: &amp;quot;, navaid.lat);&lt;br /&gt;
print(&amp;quot;Longitude: &amp;quot;, navaid.lon);&lt;br /&gt;
print(&amp;quot;Elevation (AMSL): &amp;quot;, navaid.elevation, &amp;quot; m&amp;quot;);&lt;br /&gt;
print(&amp;quot;Type: &amp;quot;, navaid.type);&lt;br /&gt;
print(&amp;quot;Frequency: &amp;quot;, sprintf(&amp;quot;%.3f&amp;quot;, navaid.frequency / 1000), &amp;quot; Mhz&amp;quot;);&lt;br /&gt;
print(&amp;quot;Range: &amp;quot;, navaid.range_nm, &amp;quot; nm&amp;quot;);&lt;br /&gt;
if(navaid.course) print(&amp;quot;Course: &amp;quot;, navaid.course);&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== findNavaidsByFrequency() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = findNavaidsByFrequency([pos, ]freq[, type]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1572|t=Source}}&lt;br /&gt;
|text = Returns a vector conatining &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt; ghost objects for navaids that match a given frequency, sorted from nearest to furthest.&lt;br /&gt;
|param1 = pos&lt;br /&gt;
|param1text = Optional position to search around. If not given, the aircraft's current position will be used. Can be one of:&lt;br /&gt;
:* An &amp;lt;code&amp;gt;airport&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;runway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;taxiway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fix&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;waypoint&amp;lt;/code&amp;gt; ghost type&lt;br /&gt;
:* A hash with ''lat'' and ''lon'' members&lt;br /&gt;
:* A geo.Coord object&lt;br /&gt;
:* Two numbers separated by a comma, as if the function is taking three arguments. Example: &amp;lt;code&amp;gt;findNavaidsByFrequency(lat, lon, freq, type);&amp;lt;/code&amp;gt;.&lt;br /&gt;
|param2 = freq&lt;br /&gt;
|param2text = Frequency, in megahertz, of the navaid to search for.&lt;br /&gt;
|param3 = type&lt;br /&gt;
|param3text = This will narrow the search to navaids of a certain type. Defaults to &amp;quot;all.&amp;quot; For the full list of accepted type arguments, see {{flightgear file|src/Navaids/positioned.cxx|l=127}}.&lt;br /&gt;
|example1 = var navaids = findNavaidsByFrequency(10.955);&lt;br /&gt;
foreach(var navaid; navaids){&lt;br /&gt;
    print(&amp;quot;--&amp;quot;);&lt;br /&gt;
    print(&amp;quot;ID: &amp;quot;, navaid.id); # prints info about the navaid&lt;br /&gt;
    print(&amp;quot;Name: &amp;quot;, navaid.name);&lt;br /&gt;
    print(&amp;quot;Latitude: &amp;quot;, navaid.lat);&lt;br /&gt;
    print(&amp;quot;Longitude: &amp;quot;, navaid.lon);&lt;br /&gt;
    print(&amp;quot;Elevation (AMSL): &amp;quot;, navaid.elevation, &amp;quot; m&amp;quot;);&lt;br /&gt;
    print(&amp;quot;Type: &amp;quot;, navaid.type);&lt;br /&gt;
    print(&amp;quot;Frequency: &amp;quot;, sprintf(&amp;quot;%.3f&amp;quot;, navaid.frequency / 1000), &amp;quot; Mhz&amp;quot;);&lt;br /&gt;
    print(&amp;quot;Range: &amp;quot;, navaid.range_nm, &amp;quot; nm&amp;quot;);&lt;br /&gt;
    if(navaid.course) print(&amp;quot;Course: &amp;quot;, navaid.course);&lt;br /&gt;
    print(&amp;quot;--&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== findNavaidsByID() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = findNavaidsByID([pos, ]id[, type]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1600|t=Source}}&lt;br /&gt;
|text = Returns a vector containing &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt; ghost objects matching a given ID, sorted by range from a certain position.&lt;br /&gt;
|param1 = pos&lt;br /&gt;
|param1text = Optional position to search around. If not given, the aircraft's current position will be used. Can be one of:&lt;br /&gt;
:* An &amp;lt;code&amp;gt;airport&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;runway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;taxiway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fix&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;waypoint&amp;lt;/code&amp;gt; ghost type&lt;br /&gt;
:* A hash with ''lat'' and ''lon'' members&lt;br /&gt;
:* A geo.Coord object&lt;br /&gt;
:* Two numbers separated by a comma, as if the function is taking three arguments. Example: &amp;lt;code&amp;gt;findNavaidsByID(lat, lon, id, type);&amp;lt;/code&amp;gt;.&lt;br /&gt;
|param2 = id&lt;br /&gt;
|param2text = Full or partial ID of the fix to search for.&lt;br /&gt;
:{{inote|1=Inputting a partial ID does not work correctly (see [http://forum.flightgear.org/viewtopic.php?f=30&amp;amp;t=28129 here]). It is best to just input a full ID.}}&lt;br /&gt;
|param3 = type&lt;br /&gt;
|param3text = This will narrow the search to navaids of a certain type. Defaults to &amp;quot;all.&amp;quot; For the full list of accepted type arguments, see {{flightgear file|src/Navaids/positioned.cxx|l=127}}.&lt;br /&gt;
|example1 = var navaid = findNavaidsByID(&amp;quot;MXW&amp;quot;);&lt;br /&gt;
navaid = navaid[0];&lt;br /&gt;
print(&amp;quot;ID: &amp;quot;, navaid.id); # prints info about 'MXW' (a VOR station)&lt;br /&gt;
print(&amp;quot;Name: &amp;quot;, navaid.name);&lt;br /&gt;
print(&amp;quot;Latitude: &amp;quot;, navaid.lat);&lt;br /&gt;
print(&amp;quot;Longitude: &amp;quot;, navaid.lon);&lt;br /&gt;
print(&amp;quot;Elevation (AMSL): &amp;quot;, navaid.elevation, &amp;quot; m&amp;quot;);&lt;br /&gt;
print(&amp;quot;Type: &amp;quot;, navaid.type);&lt;br /&gt;
print(&amp;quot;Frequency: &amp;quot;, sprintf(&amp;quot;%.3f&amp;quot;, navaid.frequency / 1000), &amp;quot; Mhz&amp;quot;);&lt;br /&gt;
print(&amp;quot;Range: &amp;quot;, navaid.range_nm, &amp;quot; nm&amp;quot;);&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== findNavaidsWithinRange() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = findNavaidsWithinRange([pos, ]range[, type]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1518|t=Source}}&lt;br /&gt;
|text = Returns a vector of &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt; ghost objects which are within a given range of a given position (by default the aircraft's current position). The results are sorted from closest to furthest.&lt;br /&gt;
|param1 = pos&lt;br /&gt;
|param1text = Optional position to search around. If not given, the aircraft's current position will be used. Can be one of:&lt;br /&gt;
:* An &amp;lt;code&amp;gt;airport&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;runway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;taxiway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fix&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;waypoint&amp;lt;/code&amp;gt; ghost type&lt;br /&gt;
:* A hash with ''lat'' and ''lon'' members&lt;br /&gt;
:* A geo.Coord object&lt;br /&gt;
:* Two numbers separated by a comma, as if the function is taking three arguments. Example: &amp;lt;code&amp;gt;findNavaidsWithinRange(lat, lon, range, type);&amp;lt;/code&amp;gt;.&lt;br /&gt;
|param2 = range&lt;br /&gt;
|param2text = Mandatory number giving the range in nautical miles within which to search for navaids. Defaults to &amp;quot;all.&amp;quot; For the full list of accepted type arguments, see {{flightgear file|src/Navaids/positioned.cxx|l=127}}.&lt;br /&gt;
|param3 = type&lt;br /&gt;
|param3text = This will narrow the search to navaids of a certain type.&lt;br /&gt;
|example1text = Searches for navaids within 10 nm of [[KSFO]].&lt;br /&gt;
|example1 = var pos = airportinfo(&amp;quot;KSFO&amp;quot;);&lt;br /&gt;
var navs = findNavaidsWithinRange(pos, 10);&lt;br /&gt;
foreach(var nav; navs){&lt;br /&gt;
    print(nav.name, &amp;quot; (ID: &amp;quot;, nav.id, &amp;quot;)&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
|example2text = Searches for navaids within 10 nm of your current position.&lt;br /&gt;
|example2 = var navs = findNavaidsWithinRange(10);&lt;br /&gt;
foreach(var nav; navs){&lt;br /&gt;
    print(nav.name, &amp;quot; (ID: &amp;quot;, nav.id, &amp;quot;)&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== finddata() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = finddata(path);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=603|t=Source}}&lt;br /&gt;
|text = Takes a relative path and tries to return an absolute one. It works by appending the relative path to some paths and testing to see if they exist. As of FlightGear v3.7, these paths are the TerraSync directory (tested first) and [[$FG_ROOT]]. &lt;br /&gt;
|param1 = path&lt;br /&gt;
|param1text = A relative path as a string.&lt;br /&gt;
|example1 = var path = finddata(&amp;quot;Aircraft/Generic&amp;quot;);&lt;br /&gt;
print(path); # prints the absolute path to $FG_ROOT/Aircraft/Generic&lt;br /&gt;
|example2 = var path = finddata(&amp;quot;Airports&amp;quot;);&lt;br /&gt;
print(path); # prints the absolute path to &amp;lt;TerraSync dir&amp;gt;/Airports&lt;br /&gt;
|example3 = var path = finddata(&amp;quot;preferences.xml&amp;quot;);&lt;br /&gt;
print(path); # prints the absolute path to $FG_ROOT/preferences.xml&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== flightplan() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = flightplan([path]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1738|t=Source}}&lt;br /&gt;
|text = {{see also|Nasal Flightplan}}&lt;br /&gt;
Returns a flight plan object, either one for the current flight plan, or one loaded from a given path.&lt;br /&gt;
|param1 = path&lt;br /&gt;
|param1text = Optional path to flight plan XML file.&lt;br /&gt;
|example1text = Gets the active flight plan and gets the ID of the current waypoint. Note that this example requires a flight plan to be set in the [[Route Manager]] first.&lt;br /&gt;
|example1 = var fp = flightplan();&lt;br /&gt;
print(fp.getWP(fp.current).id);&lt;br /&gt;
|example2text = Creates a new flight plan from an XML file and prints the IDs of the waypoints. Note that this example requires a flight plan to have been created and saved as &amp;lt;tt&amp;gt;''[[$FG_HOME]]/fp-demo.xml''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
|example2 = var path = getprop('/sim/fg-home') ~ '/fp-demo.xml';&lt;br /&gt;
var fp = flightplan(path);&lt;br /&gt;
for(var i = 0; i &amp;lt; fp.getPlanSize(); i += 1){&lt;br /&gt;
    print(fp.getWP(i).id);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== geodinfo() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = geodinfo(lat, lon[, max_alt]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=981|t=Source}}&lt;br /&gt;
|text = Returns a vector containing two entries or &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt; if no information could be obtained because the terrain tile wasn't loaded. The first entry in the vector is the elevation (in meters) for the given point, and the second is a hash with information about the assigned material (as defined in &amp;lt;tt&amp;gt;''[[$FG_ROOT]]/Materials''&amp;lt;/tt&amp;gt;), or &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt; if there was no material information available (for example, because there is an untextured building at that location). The structure of the hash is as follows (see also {{readme file|materials}}):&lt;br /&gt;
* '''light_coverage:''' The coverage of a single point of light in m&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;.&lt;br /&gt;
* '''bumpiness:''' Normalized bumpiness factor for the material.&lt;br /&gt;
* '''load_resistance:''' The amount of pressure in N/m&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt; the material can withstand without deformation.&lt;br /&gt;
* '''solid:''' 1 (true) or false (0) depending on whether the material is solid or not.&lt;br /&gt;
* '''names:''' Vector of scenery types (usually generated by [[TerraGear]]) that will use this material. &lt;br /&gt;
* '''friction_factor:''' Normalized friction factor of the material.&lt;br /&gt;
* '''rolling_friction:''' The rolling friction coefficient of the material.&lt;br /&gt;
&lt;br /&gt;
Note that this function is a ''very'' CPU-intensive operation, particularly in FlightGear v2.4 and earlier. It is advised to use this function as little as possible.&lt;br /&gt;
|param1 = lat&lt;br /&gt;
|param1text = Latitude, inputted as a number.&lt;br /&gt;
|param2 = lon&lt;br /&gt;
|param2text = Longitude, inputted as a number.&lt;br /&gt;
|param3 = max_alt&lt;br /&gt;
|param3text = The altitude, in metres, from which the function will begin searching for the height of the terrain. Defaults to 10,000 metres. If the terrain is higher than this argument specifies, &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt; will be returned.&lt;br /&gt;
|example1text = Dumps information about ground underneath the aircraft.&lt;br /&gt;
|example1 = var pos = geo.aircraft_position();&lt;br /&gt;
var info = geodinfo(pos.lat(), pos.lon());&lt;br /&gt;
debug.dump(info);&lt;br /&gt;
|example2text = Prints whether the ground underneath the aircraft is solid or is water.&lt;br /&gt;
|example2 = var pos = geo.aircraft_position();&lt;br /&gt;
var info = geodinfo(pos.lat(), pos.lon());&lt;br /&gt;
if (info != nil and info[1] != nil) {&lt;br /&gt;
    print(&amp;quot;The ground underneath the aircraft is &amp;quot;, info[1].solid == 1 ? &amp;quot;solid.&amp;quot; : &amp;quot;water.&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== geodtocart() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = geodtocart(lat, lon, alt);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=962|t=Source}}&lt;br /&gt;
|text = Converts {{wikipedia|geodetic coordinates}} (latitude, longitude, and altitude) to {{wikipedia|ECEF|Earth-centered, Earth-fixed}} coordinates (x, y and z). A vector is returned containing x, y, and z in metres. The equatorial radius of earth used is that defined by the {{wikipedia|WGS 84}} (6,378,137 metres). All argument are mandatory.&lt;br /&gt;
|param1 = lat&lt;br /&gt;
|param1text = Latitude, in degrees.&lt;br /&gt;
|param2 = lon&lt;br /&gt;
|param2text = Longitude, in degrees.&lt;br /&gt;
|param3 = alt&lt;br /&gt;
|param3text = Altitude, in metres.&lt;br /&gt;
|example1 = var (x, y, z) = geodtocart(0, 0, 0); # point is the intersection of the prime meridian and equator.&lt;br /&gt;
print(&amp;quot;x: &amp;quot;, x); # prints &amp;quot;x: 6378137&amp;quot;&lt;br /&gt;
print(&amp;quot;y: &amp;quot;, y); # prints &amp;quot;y: 0&amp;quot;&lt;br /&gt;
print(&amp;quot;z: &amp;quot;, z); # prints &amp;quot;y: 0&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== get_cart_ground_intersection() ===&lt;br /&gt;
Introduced in 2017.2.1, see [[Terrain Detection]].&lt;br /&gt;
&lt;br /&gt;
=== getprop() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = getprop(path[, path[, ...]]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=345|t=Source}}&lt;br /&gt;
|text = Returns the value of a node in the [[Property Tree]] or &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt; if the node does not exist or the value is not a number (NaN).&lt;br /&gt;
|param1 = path&lt;br /&gt;
|param1text = There needs to be at least one argument, but there is no limit to the maximum amount of arguments that can be given. The arguments will be concatenated together to form a property tree path. The arguments must be strings, but in FlightGear v3.2 onwards, there is also support (added by {{flightgear commit|34ed79}}) for numeric arguments as indices. See example 2 below.&lt;br /&gt;
|example1 = print(&amp;quot;You have FlightGear v&amp;quot;, getprop(&amp;quot;/sim/version/flightgear&amp;quot;)); # prints FlightGear version&lt;br /&gt;
|example2text = Note that the example below will only work in FlightGear 3.2 and above.&lt;br /&gt;
|example2 = for(var i = 0; i &amp;lt; 8; i += 1){&lt;br /&gt;
    print(&amp;quot;View #&amp;quot;, i + 1, &amp;quot; is named &amp;quot;, getprop(&amp;quot;/sim/view&amp;quot;, i, &amp;quot;name&amp;quot;));&lt;br /&gt;
}&lt;br /&gt;
|example3text = Same as above, but is supported by all versions of FlightGear.&lt;br /&gt;
|example3 = for(var i = 0; i &amp;lt; 8; i += 1){&lt;br /&gt;
    print(&amp;quot;View #&amp;quot;, i + 1, &amp;quot; is named &amp;quot;, getprop(&amp;quot;/sim/view[&amp;quot; ~ i ~ &amp;quot;]/name&amp;quot;));&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
==== See also ====&lt;br /&gt;
{{note| If you have to read/write the same property multiple times (e.g. in an update loop), it is more efficient to use a node object: &lt;br /&gt;
To get a Node rather than its value, use &amp;lt;code&amp;gt;props.globals.getNode()&amp;lt;/code&amp;gt; - see [[Nasal_library/props]]. }}&lt;br /&gt;
&lt;br /&gt;
=== greatCircleMove() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = greatCircleMove([pos, ]course, dist);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1681|t=Source}}&lt;br /&gt;
|text = Calculates a new set of geodetic coordinates using inputs of course and distance, either from the aircraft's current position (by default) or from another set of coordinates. Returns a hash containing two members, ''lat'' and ''lon'' (latitude and longitude respectively).&lt;br /&gt;
|param1 = pos&lt;br /&gt;
|param1text = Optional position to calculate from. If not given, the aircraft's current position will be used. Can be one of:&lt;br /&gt;
:* An &amp;lt;code&amp;gt;airport&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;runway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;taxiway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fix&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;waypoint&amp;lt;/code&amp;gt; ghost object.&lt;br /&gt;
:* A hash with ''lat'' and ''lon'' members&lt;br /&gt;
:* A &amp;lt;code&amp;gt;geo.Coord&amp;lt;/code&amp;gt; object&lt;br /&gt;
:* A lat/lon pair, that is, a pair of numbers (latitude followed by longitude) separated by a comma: &amp;lt;code&amp;gt;greatCircleMove(lat,lon, ...)&amp;lt;/code&amp;gt;.&lt;br /&gt;
|param2 = course&lt;br /&gt;
|param2text = Course to new set of coordinates, in degrees (in the range 0–360).&lt;br /&gt;
|param3 = dist&lt;br /&gt;
|param3text = Distance in nautical miles to the new set of coordinates.&lt;br /&gt;
|example1 = var pos = greatCircleMove(0,0, 0, 1);&lt;br /&gt;
debug.dump(pos); # print hash with coordinates&lt;br /&gt;
|example2 = var fix = findFixesByID(&amp;quot;POGIC&amp;quot;);&lt;br /&gt;
fix = fix[0];&lt;br /&gt;
var pos = greatCircleMove(fix, 45, 10);&lt;br /&gt;
debug.dump(pos); # print hash with coordinates&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== interpolate() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|private = _interpolate()&lt;br /&gt;
|syntax = interpolate(prop, value1, time1[, value2, time2[, ...]]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=522|t=Part 1}} {{!}} {{fgdata file|Nasal/globals.nas|t=Part 2}}&lt;br /&gt;
|text = Linearly interpolates a node in the property tree to a given value in a specified time. The value/time pairs will be run one after the other in the order that they are passed to the function. Note that the interpolation will continue even when the simulation is paused.&lt;br /&gt;
|param1 = prop&lt;br /&gt;
|param1text = String or &amp;lt;code&amp;gt;props.Node&amp;lt;/code&amp;gt; object that indicates a node in the property tree to be used.&lt;br /&gt;
|param2 = value''n''&lt;br /&gt;
|param2text = Target value to change the property to in the set amount of time. This should be a number.&lt;br /&gt;
|param3 = time''n''&lt;br /&gt;
|param3text = Time in seconds, that will be taken for the interpolation.&lt;br /&gt;
|example1text = Paste the code below into the Nasal Console and execute. Then, open the Property Browser and look for the property. Finally, run the code again, and watch the value of the property change.&lt;br /&gt;
|example1 = setprop(&amp;quot;/test&amp;quot;, 0); # (re-)set property&lt;br /&gt;
interpolate(&amp;quot;/test&amp;quot;,&lt;br /&gt;
    50, 5, # interpolate to 50 in 5 seconds&lt;br /&gt;
    10, 2, # interpolate to 10 in 2 seconds&lt;br /&gt;
    0, 5); # interpolate to 0 in 5 seconds&lt;br /&gt;
|example2 = # Apply the left brake at 20% per second&lt;br /&gt;
var prop = &amp;quot;controls/gear/brake-left&amp;quot;;&lt;br /&gt;
var dist = 1 - getprop(prop);&lt;br /&gt;
if (dist == 1) {&lt;br /&gt;
    interpolate(prop, 1, dist / 0.2);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== isa() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = isa(object, class);&lt;br /&gt;
|source = {{fgdata file|Nasal/globals.nas|t=Source}}&lt;br /&gt;
|text = Checks if an object is an instance of, or inherits from, a second object (or class), returning 1 (true) if it is and 0 (false) if otherwise.&lt;br /&gt;
|param1 = object&lt;br /&gt;
|param1text = Object to check.&lt;br /&gt;
|param2 = class&lt;br /&gt;
|param2text = Class/object to check that '''object''' inherits from or is an instance of.&lt;br /&gt;
|example1 = var coord = geo.Coord.new();&lt;br /&gt;
if(isa(coord, geo.Coord)){&lt;br /&gt;
    print(&amp;quot;Variable 'coord' is an instance of class 'geo.Coord'&amp;quot;); # this one will be printed&lt;br /&gt;
} else {&lt;br /&gt;
    print(&amp;quot;Variable 'coord' is not an instance of class 'geo.Coord'&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
|example2 = var coord = geo.Coord.new();&lt;br /&gt;
if(isa(coord, props.Node)){&lt;br /&gt;
    print(&amp;quot;Variable 'coord' is an instance of class 'props.Node'&amp;quot;);&lt;br /&gt;
} else {&lt;br /&gt;
    print(&amp;quot;Variable 'coord' is not an instance of class 'props.Node'&amp;quot;); # this one will be printed&lt;br /&gt;
}&lt;br /&gt;
|example3text = The example below demonstrates checking of inheritance.&lt;br /&gt;
|example3 = var Const = {&lt;br /&gt;
    constant: 2,&lt;br /&gt;
    getConst: func {&lt;br /&gt;
        return me.constant;&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var Add = {&lt;br /&gt;
    new: func {&lt;br /&gt;
        return { parents: [Add, Const] };&lt;br /&gt;
    },&lt;br /&gt;
&lt;br /&gt;
    addToConst: func(a){&lt;br /&gt;
        return a * me.getConst();&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var m = Add.new();&lt;br /&gt;
print(m.addToConst(4));&lt;br /&gt;
&lt;br /&gt;
if(isa(m, Add)) print(&amp;quot;Variable 'm' is an instance of class 'Add'&amp;quot;); # will be printed&lt;br /&gt;
if(isa(m, Const)) print(&amp;quot;Variable 'm' is an instance of class 'Const'&amp;quot;); # will also be printed&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== logprint() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = logprint(priority[, msg[, msg[, ...]]]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=431|t=Source}}&lt;br /&gt;
|text = Concatenates a message and logs it with a given priority level. Unlike {{func link|print()}} and {{func link|printlog()}}, message outputted by this function will be logged in your &amp;lt;code&amp;gt;[[Commonly used debugging tools#fgfs.log|fgfs.log]]&amp;lt;/code&amp;gt; file as coming from the Nasal file itself rather than from {{flightgear file|src/Scripting/NasalSys.cxx}}.&lt;br /&gt;
|param1 = priority&lt;br /&gt;
|param1text = Number specifying the priority level of the outputted message:&lt;br /&gt;
:{{{!}} class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Number !! Debug type&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} 1 {{!!}} Bulk&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} 2 {{!!}} Debug&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} 3 {{!!}} Info&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} 4 {{!!}} Warn&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} 5 {{!!}} Alert&lt;br /&gt;
{{!}}}&lt;br /&gt;
|param2 = msg&lt;br /&gt;
|param2text = The message. There is no limit to the arguments you give give. They will be concatenated together before logging.&lt;br /&gt;
|example1 = # logs the value of pi to three decimal places with log level 3&lt;br /&gt;
logprint(3, &amp;quot;pi = &amp;quot;, sprintf(&amp;quot;%.3f&amp;quot;, math.pi));&lt;br /&gt;
|example2 = logprint(5, &amp;quot;Alert! This is an important message!&amp;quot;);&lt;br /&gt;
}}&lt;br /&gt;
{{note| &lt;br /&gt;
The following constants have been added to the development branch of FlightGear (&amp;quot;next&amp;quot;) and will be releases with FG 2020.1 so you won't have to remember the numbers anymore:&lt;br /&gt;
&lt;br /&gt;
LOG_BULK, LOG_WARN, LOG_DEBUG, LOG_INFO, LOG_ALERT, DEV_WARN, DEV_ALERT }}&lt;br /&gt;
&lt;br /&gt;
=== magvar() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = magvar([pos]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1642|t=Source}}&lt;br /&gt;
|text = Returns the {{wikipedia|magnetic variation}} at a given set of coordinates. The table below gives the magnetic model used depending on the version of FlightGear.&lt;br /&gt;
{{{!}} class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! FlightGear versions !! Model !! Reference date&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} 3.6 and above {{!!}} {{wikipedia|World Magnetic Model}} (WMM) 2015 {{!!}} 1 January 2015&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} 0.9.11-pre1 to 3.4 {{!!}} WMM 2005 {{!!}} 1 January 2005&lt;br /&gt;
{{!-}}&lt;br /&gt;
{{!}} 0.7.3 to 0.9.10 {{!!}} WMM 2000 {{!!}} 1 January 2000&lt;br /&gt;
{{!}}}&lt;br /&gt;
|param1 = pos&lt;br /&gt;
|param1text = Optional position to calculate from. If not given, the aircraft's current position will be used. Can be one of:&lt;br /&gt;
:* An &amp;lt;code&amp;gt;airport&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;runway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;taxiway&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fix&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;waypoint&amp;lt;/code&amp;gt; ghost object.&lt;br /&gt;
:* A hash with ''lat'' and ''lon'' members&lt;br /&gt;
:* A &amp;lt;code&amp;gt;geo.Coord&amp;lt;/code&amp;gt; object&lt;br /&gt;
:* A lat/lon pair, that is, a pair of numbers (latitude followed by longitude) separated by a comma: &amp;lt;code&amp;gt;magvar(lat,lon)&amp;lt;/code&amp;gt;.&lt;br /&gt;
|example1 = print(magvar(0, 0)); # prints the magnetic variation at 0, 0&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== maketimer() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = maketimer(interval[, self], function);&lt;br /&gt;
|source = ''Implemented using the {{API Link|flightgear|class|TimerObj}} class.''&amp;lt;br&amp;gt;{{flightgear file|src/Scripting/NasalSys.cxx|l=90|t=Part 1}} {{!}} {{flightgear file|src/Scripting/NasalSys.cxx|l=533|t=Part 2}}&lt;br /&gt;
|version = 2.12&lt;br /&gt;
|commit = {{flightgear commit|ab939f|t=commit}}&lt;br /&gt;
|text = Returns a timer object containing the following methods and members:&lt;br /&gt;
* '''start()''': Starts the timer.&lt;br /&gt;
* '''stop()''': Stops the timer.&lt;br /&gt;
* '''restart(interval)''': Restarts the timer with the given interval.&lt;br /&gt;
* '''singleShot''': Bool showing whether the timer is only to be run once, or continuously until told to stop. Can be both set and read from (see examples).&lt;br /&gt;
* '''isRunning''': Read-only bool telling whether the timer is currently running.&lt;br /&gt;
* '''simulatedTime''': (FG 2017.1+; {{flightgear commit|0af316|t=commit}}) Bool telling whether the timer is using simulated time (which accounts for pause, etc.). Defaults to false (use real time). Can be both read and set. This cannot be changed while the timer is running.&lt;br /&gt;
Unlike {{func link|settimer()}}, which it replaces, &amp;lt;code&amp;gt;maketimer()&amp;lt;/code&amp;gt; provides more control over the timer. In addition, it can help reduce memory usage.&lt;br /&gt;
|param1 = interval&lt;br /&gt;
|param1text = Interval in seconds for the timer.&lt;br /&gt;
|param2 = self&lt;br /&gt;
|param2text = Optional parameter specifying what any &amp;lt;code&amp;gt;'''me'''&amp;lt;/code&amp;gt; references in the function being called will refer to.&lt;br /&gt;
|param3 = function&lt;br /&gt;
|param3text = Function to be called at the given interval.&lt;br /&gt;
|example1 = var timer = maketimer(1, func(){&lt;br /&gt;
    print(&amp;quot;Hello, World!&amp;quot;); # print &amp;quot;Hello, World!&amp;quot; once every second (call timer.stop() to stop it)&lt;br /&gt;
});&lt;br /&gt;
timer.start();&lt;br /&gt;
|example2 = var timer = maketimer(1, math, func(){&lt;br /&gt;
    print(me.math); # 'me' reference is the 'math' namespace&lt;br /&gt;
});&lt;br /&gt;
timer.singleShot = 1; # timer will only be run once&lt;br /&gt;
timer.start();&lt;br /&gt;
|example3 = var timer = maketimer(1, func(){&lt;br /&gt;
    print(&amp;quot;Hello, World!&amp;quot;); # print &amp;quot;Hello, World!&amp;quot; once every second (call timer.stop() to stop it)&lt;br /&gt;
});&lt;br /&gt;
timer.start();&lt;br /&gt;
print(timer.isRunning); # prints 1&lt;br /&gt;
|example4text = In the example below, &amp;quot;Hello, World!&amp;quot; will be printed after one second the first time, and after two seconds thereafter.&lt;br /&gt;
|example4 = var update = func(){&lt;br /&gt;
    print(&amp;quot;Hello, World!&amp;quot;);&lt;br /&gt;
    timer.restart(2); # restarts the timer with a two second interval&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var timer = maketimer(1, update);&lt;br /&gt;
timer.singleShot = 1;&lt;br /&gt;
timer.start();&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== maketimestamp() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = maketimestamp()&lt;br /&gt;
|source = ''Implemented using the {{API Link|flightgear|class|TimeStampObj}} class.''&amp;lt;br&amp;gt;{{flightgear file|src/Scripting/NasalSys.cxx|l=214|t=Part 1}} {{!}} {{flightgear file|src/Scripting/NasalSys.cxx|l=589|t=Part 2}}&lt;br /&gt;
|version = 2019.2&lt;br /&gt;
|commit = {{flightgear commit|7db06300|t=commit}}&lt;br /&gt;
|text = Returns a time stamp object to allow high resolution timing of Nasal operations. When created the timer will automatically be stamped. The object has the following methods:&lt;br /&gt;
* '''stamp()''': Resets the timing operation. Call this first.&lt;br /&gt;
* '''elapsedMSec()''': returns number of milliseconds elapsed since stamp() called. Resolution may vary depending on platform but is usually at least millisecond accuracy.&lt;br /&gt;
* '''elapsedUSec()''': returns number of microseconds elapsed since stamp() called. Resolution may vary depending on platform but is usually at least millisecond accuracy.&lt;br /&gt;
|&lt;br /&gt;
|example1text = In the example below the number of milliseconds elapsed will be printed.&lt;br /&gt;
|example1 = var timestamp = maketimestamp();&lt;br /&gt;
timestamp.stamp();&lt;br /&gt;
print(timestamp.elapsedMSec(), &amp;quot;ms elapsed&amp;quot;);&lt;br /&gt;
print(timestamp.elapsedMSec(), &amp;quot;ms elapsed&amp;quot;);&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== md5() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = md5(string);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=758|t=Source}}&lt;br /&gt;
|version = 3.2&lt;br /&gt;
|commit = {{flightgear commit|cfbf9e|t=commit}}&lt;br /&gt;
|text = Returns a the {{wikipedia|MD5}} hash (as a string) of the inputted string.&lt;br /&gt;
|param1 = string&lt;br /&gt;
|param1text = String the generate the hash of. Mandatory.&lt;br /&gt;
|example1text = The below code should output &amp;lt;code&amp;gt;65a8e27d8879283831b664bd8b7f0ad4&amp;lt;/code&amp;gt;.&lt;br /&gt;
|example1 = print(md5(&amp;quot;Hello, World!&amp;quot;));&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== navinfo() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = navinfo(lat, lon, type, id);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1453|t=Source}}&lt;br /&gt;
|text = Returns vector &amp;lt;code&amp;gt;navaid&amp;lt;/code&amp;gt; ghost objects matching the given '''type''' and '''id''' or &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt; on error.&lt;br /&gt;
|param1 = lat ''and'' lon&lt;br /&gt;
|param1text = If given, the returned navaids will be put into order of ascending distance from the location.&lt;br /&gt;
|param2 = type&lt;br /&gt;
|param2text = Narrows the search to the given type. Must be one of &amp;quot;any,&amp;quot; &amp;quot;fix,&amp;quot; &amp;quot;vor,&amp;quot; &amp;quot;ndb,&amp;quot; &amp;quot;ils,&amp;quot; &amp;quot;dme,&amp;quot; or &amp;quot;tacan.&amp;quot; Defaults to the equivalent of &amp;quot;any.&amp;quot;&lt;br /&gt;
|param3 = id&lt;br /&gt;
|param3text = ID to search for. Note that, although all the parameters are technically optional, this parameter must be given, otherwise an empty vector will be returned.&lt;br /&gt;
|example1 = navinfo(&amp;quot;vor&amp;quot;); # returns all VORs&lt;br /&gt;
|example2 = navinfo(&amp;quot;HAM&amp;quot;); # return all navaids whose names start with &amp;quot;HAM&amp;quot;&lt;br /&gt;
|example3 = navinfo(&amp;quot;vor&amp;quot;, &amp;quot;HAM&amp;quot;); # return all VORs whose names start with &amp;quot;HAM&amp;quot;&lt;br /&gt;
|example4 = navinfo(34,48,&amp;quot;vor&amp;quot;,&amp;quot;HAM&amp;quot;); # return all VORs whose names start with &amp;quot;HAM&amp;quot; and sorted by distance relative to 34°, 48°&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== parse_markdown() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = parse_markdown(markdown);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=745|t=Part 1}} {{!}} {{simgear file|simgear/misc/SimpleMarkdown.cxx|t=Part 2}} &lt;br /&gt;
|version = 3.2&lt;br /&gt;
|text = Parses a string containing {{wikipedia|Markdown}} and returns the result as a string. As of FlightGear 2016.1, it is just a simple parser, and does the following:&lt;br /&gt;
* It strips whitespace from the beginning of the string.&lt;br /&gt;
* It supports [http://daringfireball.net/projects/markdown/syntax#p paragraphs and line breaks].&lt;br /&gt;
* It collapses whitespace.&lt;br /&gt;
* It converts unordered [http://daringfireball.net/projects/markdown/syntax#list lists] to use a bullet character (&amp;amp;bull;). Note that the bullet character is implemented in hexadecimal UTF-8 character bytes (&amp;lt;code&amp;gt;E2 80 A2&amp;lt;/code&amp;gt;), as so may not work properly when the being displayed in an encoding other than UTF-8.&lt;br /&gt;
|param1 = markdown&lt;br /&gt;
|param1text = String containing Markdown to be parsed.&lt;br /&gt;
|example1text = &lt;br /&gt;
Save the below code as &amp;lt;tt&amp;gt;''[[$FG_ROOT]]/gui/dialogs/test.xml''&amp;lt;/tt&amp;gt;, then run the Nasal code below it to open the dialog. To change the markdown to be parsed, simply change the code in the highlighted section, save it, and reload the GUI (&amp;lt;tt&amp;gt;Debug &amp;gt; Reload GUI&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot; highlight=&amp;quot;41-50&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;PropertyList&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;name&amp;gt;test&amp;lt;/name&amp;gt;&lt;br /&gt;
&amp;lt;layout&amp;gt;vbox&amp;lt;/layout&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;group&amp;gt;&lt;br /&gt;
    &amp;lt;layout&amp;gt;hbox&amp;lt;/layout&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &amp;lt;empty&amp;gt;&lt;br /&gt;
        &amp;lt;stretch&amp;gt;true&amp;lt;/stretch&amp;gt;&lt;br /&gt;
    &amp;lt;/empty&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &amp;lt;text&amp;gt;&lt;br /&gt;
        &amp;lt;label&amp;gt;parse_markdown() test dialog&amp;lt;/label&amp;gt;&lt;br /&gt;
    &amp;lt;/text&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &amp;lt;empty&amp;gt;&lt;br /&gt;
        &amp;lt;stretch&amp;gt;true&amp;lt;/stretch&amp;gt;&lt;br /&gt;
    &amp;lt;/empty&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;button&amp;gt;&lt;br /&gt;
        &amp;lt;legend&amp;gt;&amp;lt;/legend&amp;gt;&lt;br /&gt;
        &amp;lt;pref-width&amp;gt;16&amp;lt;/pref-width&amp;gt;&lt;br /&gt;
        &amp;lt;pref-height&amp;gt;16&amp;lt;/pref-height&amp;gt;&lt;br /&gt;
        &amp;lt;binding&amp;gt;&lt;br /&gt;
            &amp;lt;command&amp;gt;dialog-close&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/button&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/group&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;canvas&amp;gt;&lt;br /&gt;
    &amp;lt;name&amp;gt;Canvas plot&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;stretch&amp;gt;true&amp;lt;/stretch&amp;gt;&lt;br /&gt;
    &amp;lt;pref-width&amp;gt;400&amp;lt;/pref-width&amp;gt;&lt;br /&gt;
    &amp;lt;pref-height&amp;gt;300&amp;lt;/pref-height&amp;gt;&lt;br /&gt;
    &amp;lt;nasal&amp;gt;&lt;br /&gt;
        &amp;lt;load&amp;gt;&amp;lt;![CDATA[&lt;br /&gt;
var text = 'Items:&lt;br /&gt;
* apples&lt;br /&gt;
* oranges&lt;br /&gt;
* pears&lt;br /&gt;
&lt;br /&gt;
Some text.&lt;br /&gt;
Some more items:&lt;br /&gt;
* apples&lt;br /&gt;
* oranges&lt;br /&gt;
* pears';&lt;br /&gt;
&lt;br /&gt;
var parsed = parse_markdown(text);&lt;br /&gt;
&lt;br /&gt;
var root_canvas = canvas.get(cmdarg());&lt;br /&gt;
root_canvas.setColorBackground(255, 255, 255);&lt;br /&gt;
var root = root_canvas.createGroup();&lt;br /&gt;
&lt;br /&gt;
var text_dis = root.createChild(&amp;quot;text&amp;quot;)&lt;br /&gt;
    .setText(parsed)&lt;br /&gt;
    .setTranslation(5, 5)&lt;br /&gt;
    .setFont(&amp;quot;LiberationFonts\LiberationSans-Regular.ttf&amp;quot;)&lt;br /&gt;
    .setFontSize(15)&lt;br /&gt;
    .setColor(0, 0, 0)&lt;br /&gt;
    .setDrawMode(canvas.Text.TEXT)&lt;br /&gt;
    .setAlignment(&amp;quot;left-top&amp;quot;);&lt;br /&gt;
        ]]&amp;gt;&amp;lt;/load&amp;gt;&lt;br /&gt;
    &amp;lt;/nasal&amp;gt;&lt;br /&gt;
&amp;lt;/canvas&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/PropertyList&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|example1 = fgcommand(&amp;quot;dialog-show&amp;quot;, {&amp;quot;dialog-name&amp;quot;: &amp;quot;test&amp;quot;});&lt;br /&gt;
|example2text = The example below parses Markdown and outputs it in a HTML document. The parsed text is placed in &amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot; inline&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;/syntaxhighlight&amp;gt; tags. To change the Markdown to be parsed, simply edit the variable &amp;lt;tt&amp;gt;markdown&amp;lt;/tt&amp;gt; at the top of the code.&lt;br /&gt;
|example2 = &amp;lt;nowiki&amp;gt;var markdown = 'Items:&lt;br /&gt;
* apples&lt;br /&gt;
* oranges&lt;br /&gt;
* pears&lt;br /&gt;
&lt;br /&gt;
Some text.&lt;br /&gt;
Some more items:&lt;br /&gt;
* apples&lt;br /&gt;
* oranges&lt;br /&gt;
* pears';&lt;br /&gt;
&lt;br /&gt;
var parsed = parse_markdown(markdown);&lt;br /&gt;
&lt;br /&gt;
debug.dump(parsed);&lt;br /&gt;
&lt;br /&gt;
var path = string.normpath(getprop(&amp;quot;/sim/fg-home&amp;quot;) ~ '/Export/parse_markdown()-test.html');&lt;br /&gt;
&lt;br /&gt;
var file = io.open(path, &amp;quot;w&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
var html = &amp;quot;&amp;lt;!DOCTYPE html&amp;gt;\n\n&amp;lt;html&amp;gt;\n\n&amp;lt;head&amp;gt;\n\t&amp;lt;meta charset=\&amp;quot;UTF-8\&amp;quot;&amp;gt;\n\t&amp;lt;title&amp;gt;parse_markdown() test generated by Nasal&amp;lt;/title&amp;gt;\n&amp;lt;/head&amp;gt;\n\n&amp;lt;body&amp;gt;\n\t&amp;lt;pre&amp;gt;&amp;quot; ~ parsed ~ &amp;quot;&amp;lt;/pre&amp;gt;\n&amp;lt;/body&amp;gt;\n\n&amp;lt;/html&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
io.write(file, html);&lt;br /&gt;
io.close(file);&lt;br /&gt;
print(&amp;quot;Done, file ready for viewing (&amp;quot; ~ path ~ &amp;quot;)&amp;quot;);&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== parsexml() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = parsexml(path[, start[, end[, data[, pro_ins]]]]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=710|t=Source}}&lt;br /&gt;
|text = This function is an interface into the built-in [http://expat.sourceforge.net/ Expat XML parser]. The absolute path to the file is returned as string, or &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt; is returned on error.&lt;br /&gt;
|param1 = path&lt;br /&gt;
|param1text = Mandatory absolute path to the XML file to be parsed.&lt;br /&gt;
|param2 = start&lt;br /&gt;
|param2text = Optional callback function that will be called for every starting tag. The function should take two argument: the tag name and a hash containing attributes.&lt;br /&gt;
|param3 = end&lt;br /&gt;
|param3text = Optional callback function that will be called for every ending tag. The function should take one argument: the tag name.&lt;br /&gt;
|param4 = data&lt;br /&gt;
|param4text = Optional callback function that will be called for every piece of data within a set of tags. The function should take one argument: the data as a string.&lt;br /&gt;
|param5 = pro_ins&lt;br /&gt;
|param5text = Optional callback function that will be called for every {{wikipedia|Processing Instruction|processing instruction}}. The function should take two argument: the target and the data string.&lt;br /&gt;
|example1text = Save the below XML code in &amp;lt;tt&amp;gt;''[[$FG_HOME]]/Export/demo.xml''&amp;lt;/tt&amp;gt;. Then, execute the Nasal code below in the Nasal Console. The XML will be parsed and each bit of the code will be printed.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;?xml-stylesheet type=&amp;quot;text/xsl&amp;quot; href=&amp;quot;style.xsl&amp;quot;?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;foo&amp;gt;&lt;br /&gt;
  &amp;lt;blah type=&amp;quot;string&amp;quot;&amp;gt;&amp;lt;![CDATA[ &amp;lt;sender&amp;gt;John Smith&amp;lt;/sender&amp;gt; ]]&amp;gt;&amp;lt;/blah&amp;gt;&lt;br /&gt;
  &amp;lt;blah2 type=&amp;quot;string&amp;quot;&amp;gt;Orange &amp;amp;amp; lemons&amp;lt;/blah2&amp;gt;&lt;br /&gt;
&amp;lt;/foo&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|example1 = var start = func(name, attr){&lt;br /&gt;
    print(&amp;quot;Starting tag: '&amp;quot;, name, &amp;quot;'&amp;quot;);&lt;br /&gt;
    foreach(var a; keys(attr)){&lt;br /&gt;
        print(&amp;quot;\twith attribute &amp;quot;, a, '=&amp;quot;', attr[a], '&amp;quot;');&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var end = func(name){&lt;br /&gt;
    print(&amp;quot;Ending tag: '&amp;quot;, name, &amp;quot;'&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var data = func(data){&lt;br /&gt;
    print(&amp;quot;Data = '&amp;quot;, data, &amp;quot;'&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var pro_instr = func(target, data){&lt;br /&gt;
    print(&amp;quot;Processing instruction: target = '&amp;quot;, target, &amp;quot;', data = '&amp;quot;, data, &amp;quot;'&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
parsexml(getprop(&amp;quot;/sim/fg-home&amp;quot;) ~ '/Export/demo.xml', start, end, data, pro_instr);&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== print() ===&lt;br /&gt;
{{Note|As of 07/2020, we are in the process of slowly deprecating and removing Nasal print() (in fgdata) where possible in favor of log [[#logprint()]] which takes a priority level.&lt;br /&gt;
&lt;br /&gt;
This is part of the goal that we achieve zero output at log-level at alert, and everything shown at ‘warn; is really a warning, not just information.&amp;lt;ref&amp;gt;https://sourceforge.net/p/flightgear/mailman/message/37042224/&amp;lt;/ref&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = print(data[, data[, ...]]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=415|t=Source}}&lt;br /&gt;
|text = Concatenates its arguments and then prints it to the terminal and the [[Commonly used debugging tools#fgfs.log|log]]. Note that a newline is automatically added.&lt;br /&gt;
|param1 = data&lt;br /&gt;
|param1text = Data to print. Only strings and numbers can be printed; other data types will not be. There many be any number of arguments; they will just be concatenated together.&lt;br /&gt;
|example1 = print(&amp;quot;Just&amp;quot;, &amp;quot; a &amp;quot;, &amp;quot;test&amp;quot;); # prints &amp;quot;Just a test&amp;quot;&lt;br /&gt;
|example2 = print(&amp;quot;pi = &amp;quot;, math.pi); # prints &amp;quot;pi = 3.141592...&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== printf() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = printf(format[, arg[, arg, [...]]]);&lt;br /&gt;
|source = {{fgdata file|Nasal/globals.nas|t=Source}}&lt;br /&gt;
|text = Creates and prints a formatted string. For a description of its arguments, see {{func link|sprintf()}} (it is, in fact, implemented using &amp;lt;code&amp;gt;sprintf()&amp;lt;/code&amp;gt;).&lt;br /&gt;
|example1 = printf(&amp;quot;In hexadecimal, 100000 = %X&amp;quot;, 186A0); # prints &amp;quot;In hexadecimal, 100000 = 186A0&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== printlog() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = printlog(level, data[, data[, ...]]);&lt;br /&gt;
|source = {{fgdata file|Nasal/globals.nas|t=Source}}&lt;br /&gt;
|text = Prints the given message with the given log level. If the log level is higher or equal to &amp;lt;code&amp;gt;/sim/logging/priority&amp;lt;/code&amp;gt;, it is printed.&lt;br /&gt;
|param1 = level&lt;br /&gt;
|param1text = Mandatory log level as a string. Must be one of &amp;quot;none,&amp;quot; &amp;quot;bulk,&amp;quot; &amp;quot;debug,&amp;quot; &amp;quot;info,&amp;quot; &amp;quot;warn,&amp;quot; or &amp;quot;alert.&amp;quot; Note that &amp;quot;none&amp;quot; will mean that the message will never be printed.&lt;br /&gt;
|param2 = data&lt;br /&gt;
|param2text = Data to be printed. Only strings and numbers will be printed; others will not be. There may be any number of arguments; they will just be concatenated together.&lt;br /&gt;
|example1 = printlog(&amp;quot;alert&amp;quot;, &amp;quot;This is an alert&amp;quot;); # message will be printed&lt;br /&gt;
|example2 = printlog(&amp;quot;info&amp;quot;, &amp;quot;Just informing you about something&amp;quot;); # message will be printed only if log level is set to &amp;quot;info&amp;quot; or less&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== rand() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = rand();&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=554|t=Source}}&lt;br /&gt;
|text = Returns a random floating point number between 0 (inclusive) and 1 (exclusive). It takes no arguments.&lt;br /&gt;
|example1 = print(rand()); # prints random number&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== registerFlightPlanDelegate() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = registerFlightPlanDelegate(init_func);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1879|t=Source}}&lt;br /&gt;
|text = Registers a flight plan delegate. See &amp;lt;tt&amp;gt;''{{fgdata file|Nasal/route_manager.nas|t=$FG_ROOT/Nasal/route_manager.nas}}''&amp;lt;/tt&amp;gt; for examples.&lt;br /&gt;
|param1 = init_func&lt;br /&gt;
|param1text = Initialization function which will be called during FlightGear's startup.&lt;br /&gt;
}}&lt;br /&gt;
=== removecommand() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = removecommand(cmd);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=668|t=Source}}&lt;br /&gt;
|text = Removes the given fgcommand. Returns &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt;.&lt;br /&gt;
{{caution|This will remove '''any''' [[fgcommands|fgcommand]], even those implemented in C++, so use with caution!}}&lt;br /&gt;
|param1 = cmd&lt;br /&gt;
|param1text = String specifying the name of the command to remove.&lt;br /&gt;
|example1 = addcommand(&amp;quot;hello&amp;quot;, func(){&lt;br /&gt;
    print(&amp;quot;Hello&amp;quot;);&lt;br /&gt;
});&lt;br /&gt;
fgcommand(&amp;quot;hello&amp;quot;); # &amp;quot;Hello&amp;quot; will be printed&lt;br /&gt;
removecommand(&amp;quot;hello&amp;quot;); # removes it&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== removelistener() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = removelistener(id);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=1384|t=Part 1}} {{!}} {{flightgear file|src/Scripting/NasalSys.cxx|l=506|t=Part 2}}&lt;br /&gt;
|text = Removes and deactivates the given listener and returns the number of listeners left or &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt; on error.&lt;br /&gt;
{{note|It is good practice to remove listeners when they are not required anymore. This prevents the listeners reducing FlightGear's run performance.}}&lt;br /&gt;
|param1 = id&lt;br /&gt;
|param1text = ID of listener as returned by {{func link|setlistener()}}.&lt;br /&gt;
|example1 = var ls = setlistener(&amp;quot;/sim/test&amp;quot;, func(){&lt;br /&gt;
    print(&amp;quot;Property '/sim/test' has been changed&amp;quot;);&lt;br /&gt;
});&lt;br /&gt;
setprop(&amp;quot;/sim/test&amp;quot;, &amp;quot;blah&amp;quot;); # trigger listener&lt;br /&gt;
var rem = removelistener(ls); # remove listener&lt;br /&gt;
print(&amp;quot;There are &amp;quot;, rem, &amp;quot; listeners remaining&amp;quot;);&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== resolvepath() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = resolvepath(path);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=604|t=Source}}&lt;br /&gt;
|text = Takes a relative path as a string and uses [[SimGear]]'s path-resolving framework to return an absolute path as a string. If the path could not be resolved, an empty string is returned. See [[Resolving Paths]] for a detailed description of the algorithm. This function can also be used to check if a file exists.&lt;br /&gt;
|param1 = path&lt;br /&gt;
|param1text = Relative path to be completed.&lt;br /&gt;
|example1 = print(resolvepath(&amp;quot;Nasal/globals.nas&amp;quot;)); # prints the equivalent of $FG_ROOT/Nasal/globals.nas&lt;br /&gt;
|example2 = print(resolvepath(&amp;quot;blah&amp;quot;)); # prints nothing; could not be resolved&lt;br /&gt;
|example3 = var file_path = resolvepath(&amp;quot;Aircraft/SenecaII/some-file&amp;quot;);&lt;br /&gt;
if (file_path != &amp;quot;&amp;quot;){&lt;br /&gt;
    gui.popupTip(&amp;quot;some-file found&amp;quot;, 2);&lt;br /&gt;
} else {&lt;br /&gt;
    gui.popupTip(&amp;quot;some-file not found&amp;quot;, 2);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== setlistener() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = setlistener(node, code[, init[, type]]);&lt;br /&gt;
|private = _setlistener()&lt;br /&gt;
|source = {{flightgear file|src/Scripting/Nasal|l=499|t=Part 1}} {{!}} {{flightgear file|src/Scripting/Nasal|l=1350|t=Part 2}}&amp;lt;br&amp;gt;''Listener implemented using the {{API Link|flightgear|class|FGNasalListener}} class.''&lt;br /&gt;
|text = Creates a listener which will be triggered when the given property is changed (depending on the '''type'''). A unique integer ID is returned; this can later be used as the argument to {{func link|removelistener()}}.&lt;br /&gt;
{{note|Listeners are known to be a source of resource leaks. To avoid this, please take measures such as:&lt;br /&gt;
* Using {{func link|removelistener()}} when they are not needed any more.&lt;br /&gt;
* Using a single initialization listener.&lt;br /&gt;
* Avoiding tying listeners to properties that are rapidly updated (e.g., many times per frame).&lt;br /&gt;
}}&lt;br /&gt;
|param1 = node&lt;br /&gt;
|param1text = Mandatory string or &amp;lt;code&amp;gt;props.Node&amp;lt;/code&amp;gt; object pointing to a property in the [[Property Tree]].&lt;br /&gt;
|param2 = code&lt;br /&gt;
|param2text = Mandatory callback function to execute when the listener is triggered. The function can take up to four arguments in the following order:&lt;br /&gt;
* '''changed''': a &amp;lt;code&amp;gt;props.Node&amp;lt;/code&amp;gt; object pointing to the changed node.&lt;br /&gt;
* '''listen''': a &amp;lt;code&amp;gt;props.Node&amp;lt;/code&amp;gt; object pointing to the listened-to node. Note that this argument maybe different depending on the '''type'''.&lt;br /&gt;
* '''mode''': an integer telling how the listener was triggered. 0 means that the value was changed. 1 means that a child property was added. -1 means that a child property was removed.&lt;br /&gt;
* '''is_child''': boolean telling whether '''changed''' is a child property of the listened-to '''node''' or not. 1 (true) if it is, 0 (false) otherwise.&lt;br /&gt;
|param3 = init&lt;br /&gt;
|param3text = If set to 1 (true), the listener will additionally be triggered when it is created. This argument is optional and defaults to 0 (false).&lt;br /&gt;
|param4 = type&lt;br /&gt;
|param4text = Integer specifying the listener's behavior. 0 means that the listener will only trigger when the property is changed. 1 means that the trigger will always be triggered when the property is written to. 2 will mean that the listener will be triggered even if child properties are modified. This argument is optional and defaults to 1.&lt;br /&gt;
|example1 = var prop = props.globals.initNode(&amp;quot;/sim/test&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;STRING&amp;quot;); # create property&lt;br /&gt;
var id = setlistener(&amp;quot;/sim/test&amp;quot;, func(n){ # create listener&lt;br /&gt;
    print(&amp;quot;Value: &amp;quot;, n.getValue());&lt;br /&gt;
});&lt;br /&gt;
setprop(&amp;quot;/sim/test&amp;quot;, &amp;quot;blah&amp;quot;); # trigger listener&lt;br /&gt;
removelistener(id); # remove listener&lt;br /&gt;
prop.remove(); # remove property&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== setprop() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = setprop(path[, path[, ...]], value);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=385|t=Source}}&lt;br /&gt;
|text = Sets the value of a property in the [[Property Tree]]. If the property does not exist, it will be created. Returns 1 (true) on success or 0 (false) if there was an error.&lt;br /&gt;
{{note|If you want to remove a property, you will have to use one of the &amp;lt;code&amp;gt;props&amp;lt;/code&amp;gt; helpers:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
props.globals.getNode(&amp;quot;foo/bar&amp;quot;).remove(); # take out the complete node&lt;br /&gt;
props.globals.getNode(&amp;quot;foo&amp;quot;).removeChild(&amp;quot;bar&amp;quot;); # take out a certain child node&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
|param1 = path&lt;br /&gt;
|param1text = There needs to be at least one '''path''' argument, but there is no limit to the maximum amount that can be given. They will be concatenated together to form a property tree path. The arguments must be strings, but in FlightGear v3.2 onwards, there also is support (added by {{flightgear commit|34ed79}}) for numeric arguments as indices. See example 2 below.&lt;br /&gt;
|param2 = value&lt;br /&gt;
|param2text = Value to write to the given property. Must be either a string or a number.&lt;br /&gt;
|example1 = setprop(&amp;quot;/sim/demo&amp;quot;, &amp;quot;This is a demo&amp;quot;);&lt;br /&gt;
|example2text = Note that the example below will only work in FlightGear 3.2 and above.&lt;br /&gt;
|example2 = for(var i = 0; i &amp;lt; 3; i += 1){&lt;br /&gt;
    setprop(&amp;quot;/sim/demo&amp;quot;, i, &amp;quot;Demo #&amp;quot; ~ i));&lt;br /&gt;
}&lt;br /&gt;
|example3text = Same as above, but is supported by all versions of FlightGear.&lt;br /&gt;
|example3 = for(var i = 0; i &amp;lt; 3; i += 1){&lt;br /&gt;
    setprop(&amp;quot;/sim/demo[&amp;quot; ~ i ~ &amp;quot;]&amp;quot;, &amp;quot;Demo #&amp;quot; ~ i));&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
==== See also ====&lt;br /&gt;
{{note| If you have to read/write the same property multiple times (e.g. in an update loop), it is more efficient to use a node object: &lt;br /&gt;
To get a Node rather than its value, use &amp;lt;code&amp;gt;props.globals.getNode()&amp;lt;/code&amp;gt; - see [[Nasal_library/props]]. }}&lt;br /&gt;
&lt;br /&gt;
=== settimer() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = settimer(function, delta[, realtime]);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=499|t=Part 1}} {{!}} {{flightgear file|src/Scripting/NasalSys.cxx|l=1286|t=Part 2}}&lt;br /&gt;
|text = Runs the given function a specified amount of seconds after the current time. Returns &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt;.&lt;br /&gt;
{{note|Improper use of &amp;lt;code&amp;gt;settimer()&amp;lt;/code&amp;gt; may cause resource leaks. It is also highly recommended that the newer {{func link|maketimer()}} should be used instead of this function.}} &lt;br /&gt;
|param1 = function&lt;br /&gt;
|param1text = Mandatory function that will be called. It may be necessary to enclose code in an anonymous function (see example).&lt;br /&gt;
|param2 = delta&lt;br /&gt;
|param2text = Mandatory amount of time in seconds after which the function will be called.&lt;br /&gt;
|param3 = realtime&lt;br /&gt;
|param3text = If 1 (true), &amp;quot;real time&amp;quot; will be used instead of &amp;quot;simulation time.&amp;quot; Defaults to 0 (false). Note that if &amp;quot;simulation time&amp;quot; is used, the timer will not run while FlightGear is paused.&lt;br /&gt;
|example1 = var myFunc = func(){&lt;br /&gt;
    print(&amp;quot;Hello&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
settimer(myFunc, 2); # runs myFunc after 2 seconds&lt;br /&gt;
|example2 = var sqr = func(a){&lt;br /&gt;
    return a * a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
settimer(func(){&lt;br /&gt;
    print(sqr(2)); # will print 4 after 2 seconds&lt;br /&gt;
}, 2);&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== srand() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = srand();&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=559|t=Source}}&lt;br /&gt;
|text = Makes the pseudorandom number generator (see {{func link|rand()}}) generate a new {{wikipedia|random seed|noicon=1}} based on time. Returns 0.&lt;br /&gt;
}}&lt;br /&gt;
=== systime() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = systime();&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=770|t=Source}}&lt;br /&gt;
|text = Returns the {{wikipedia|Unix time}} (seconds since since 00:00:00 UTC, 1/1/1970) as a floating point number with high resolution. This function is useful for benchmarking purposes (see example 2).&lt;br /&gt;
{{note|1=High resolution timers under Windows can produce inaccurate or fixed sub-millisecond results.&amp;lt;ref&amp;gt;{{cite web|url=http://forum.flightgear.org/viewtopic.php?f=30&amp;amp;t=29259|title=Nasal: systime() ??!?|author=Necolatis|date=Apr 2nd, 2016}}&amp;lt;/ref&amp;gt; This is due to the underlying {{func link|GetSystemTimeAsFileTime()|link=https://msdn.microsoft.com/en-us/library/windows/desktop/ms724397(v=vs.85).aspx}} API call, which depends on hardware availability of suitable high resolution timers. See also [https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx Acquiring high-resolution time stamps]}}&lt;br /&gt;
|example1 = print(&amp;quot;Unix time: &amp;quot;, systime()); # prints Unix time&lt;br /&gt;
|example2 = var myFunc = func(){&lt;br /&gt;
    for(var i = 0; i &amp;lt;= 10; i += 1){&lt;br /&gt;
        print(&amp;quot;Interation #&amp;quot;, i);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
var t = systime(); # record time&lt;br /&gt;
myFunc(); # run function&lt;br /&gt;
var t2 = systime(); # record new time&lt;br /&gt;
print(&amp;quot;myFunc() took &amp;quot;, t2 - t, &amp;quot; seconds&amp;quot;); # print result&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== thisfunc() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = thisfunc();&lt;br /&gt;
|source = {{fgdata file|Nasal/globals.nas|t=Source}}&lt;br /&gt;
|text = Returns the function from which this function is called. This allows a function to reliably and safely call itself from within a closure.&lt;br /&gt;
|example1 = var stringify_vec = func(input){&lt;br /&gt;
    if (typeof(input) == &amp;quot;scalar&amp;quot;){&lt;br /&gt;
        return sprintf(&amp;quot;%s&amp;quot;, input);&lt;br /&gt;
    } elsif (typeof(input) == &amp;quot;vector&amp;quot;) {&lt;br /&gt;
        if (size(input) == 0) return &amp;quot;[]&amp;quot;;&lt;br /&gt;
        var this = thisfunc();&lt;br /&gt;
        var buffer = &amp;quot;[&amp;quot;;&lt;br /&gt;
        for(var i = 0; i &amp;lt; size(input); i += 1){&lt;br /&gt;
            buffer ~= this(input[i]);&lt;br /&gt;
            if (i == size(input) - 1) {&lt;br /&gt;
                buffer ~= &amp;quot;]&amp;quot;;&lt;br /&gt;
            } else {&lt;br /&gt;
                buffer ~= &amp;quot;, &amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        return buffer;&lt;br /&gt;
    } else {&lt;br /&gt;
        die(&amp;quot;stringify_vec(): Error! Invalid input. Must be a vector or scalar&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var test_vec = [&amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;c&amp;quot;, 1, 2, 3];&lt;br /&gt;
debug.dump(stringify_vec(test_vec)); # prints &amp;quot;[a, b, c, 1, 2, 3]&amp;quot;&lt;br /&gt;
test_vec = [];&lt;br /&gt;
debug.dump(stringify_vec(test_vec)); # prints &amp;quot;[]&amp;quot;&lt;br /&gt;
test_vec = {};&lt;br /&gt;
debug.dump(stringify_vec(test_vec)); # will throw an error&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== tileIndex() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = tileIndex();&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1720|t=Source}}&lt;br /&gt;
|text = Returns the index of the tile at the aircraft's current position as a string. This corresponds to the name of the STG file of the tile. For example, at [[KSFO]], this would be &amp;lt;code&amp;gt;942050&amp;lt;/code&amp;gt;, corresponding to &amp;lt;tt&amp;gt;''[[$FG_SCENERY]]/Terrain/w130n30/w123n3/942050.stg''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
|example1 = print(tileIndex()); # print index&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== tilePath() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = tilePath();&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalPositioned.cxx|l=1712|t=Source}}&lt;br /&gt;
|text = Returns the base path of the tile at the aircraft's current position as a string. For example, at KSFO, this would be &amp;lt;code&amp;gt;w130n30/w123n3&amp;lt;/code&amp;gt;, corresponding to &amp;lt;tt&amp;gt;''[[$FG_SCENERY]]/Terrain/w130n30/w123n3''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
|example1 = print(tilePath()); # print path&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== values() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = values(hash);&lt;br /&gt;
|source = {{fgdata file|Nasal/globals.nas|t=Source}}&lt;br /&gt;
|text = Returns a vector containing the values of the given hash.&lt;br /&gt;
|param1 = hash&lt;br /&gt;
|param1text = Mandatory hash to get the values of.&lt;br /&gt;
|example1 = var hash = {&lt;br /&gt;
    &amp;quot;a&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;b&amp;quot;: 2,&lt;br /&gt;
    &amp;quot;c&amp;quot;: 3&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
foreach(var val; values(hash)){&lt;br /&gt;
    print(val);&lt;br /&gt;
}&lt;br /&gt;
|example2text = The below example does exactly the same thing as the above example, but does not use &amp;lt;code&amp;gt;values()&amp;lt;/code&amp;gt;:&lt;br /&gt;
|example2 = var hash = {&lt;br /&gt;
    &amp;quot;a&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;b&amp;quot;: 2,&lt;br /&gt;
    &amp;quot;c&amp;quot;: 3&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
foreach(var key; keys(hash)){&lt;br /&gt;
    print(hash[key]);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Extension functions new in FG 2020.1 ==&lt;br /&gt;
The following functions have been added to the nasal core library and will be released with FlightGear version 2020.1. &lt;br /&gt;
Before the release they are available in the development branch &amp;quot;next&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== isfunc() ===&lt;br /&gt;
Returns 1 if type or argument is a function, otherwise 0.&lt;br /&gt;
&lt;br /&gt;
=== isghost() ===&lt;br /&gt;
Returns 1 if type or argument is a ghost, otherwise 0.&lt;br /&gt;
&lt;br /&gt;
=== ishash() ===&lt;br /&gt;
Returns 1 if type or argument is a hash, otherwise 0.&lt;br /&gt;
&lt;br /&gt;
=== isint() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = isint(x);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|t=Source}}&lt;br /&gt;
|text = Returns 1 if argument has a numeric value and x == floor(x), e.g. integer.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== isnum() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = isnum(x);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|t=Source}}&lt;br /&gt;
|text = Returns 1 if typeof(x) is &amp;quot;scalar&amp;quot; and x has a numeric value otherwise 0. &lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== isscalar() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = isnum(x);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|t=Source}}&lt;br /&gt;
|text = Returns 1 if type or argument is a scalar (string or numeric), otherwise (vector, hash, func, ...) it returns 0. This is useful to check if a variable can be converted to string e.g. when useing the string concat operator &amp;quot;~&amp;quot;. &lt;br /&gt;
|example1 = var a = &amp;quot;foo&amp;quot;; &lt;br /&gt;
var b=42;&lt;br /&gt;
if (isscalar(a) and isscalar(b)) print(a~b);&lt;br /&gt;
if (isstr(a)) print(&amp;quot;a is a string&amp;quot;);&lt;br /&gt;
if (isint(b)) print(&amp;quot;b is an integer&amp;quot;);&lt;br /&gt;
# if (isscalar(a))... is equivalent to if (typeof(a) == &amp;quot;scalar&amp;quot;)...&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== isstr() ===&lt;br /&gt;
Returns 1 if type or argument is a string, otherwise 0. &lt;br /&gt;
&lt;br /&gt;
=== isvec() ===&lt;br /&gt;
Returns 1 if type or argument is a vector, otherwise 0.&lt;br /&gt;
&lt;br /&gt;
=== vecindex() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = vecindex(vector, value);&lt;br /&gt;
|source = {{simgear file|simgear/nasal/lib.c|t=Source}}&lt;br /&gt;
|text = Returns the index of value or nil, if value is not found in vector.&lt;br /&gt;
|example1=&lt;br /&gt;
var myvector = [&amp;quot;apple&amp;quot;, &amp;quot;bananna&amp;quot;, &amp;quot;coconut&amp;quot;];&lt;br /&gt;
# to check if a vector contains a certain value compare vecindex to nil&lt;br /&gt;
if (vecindex(myvector, &amp;quot;apple&amp;quot;) != nil) {&lt;br /&gt;
    print(&amp;quot;found apple&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
# WARNING: this will not work as desired because index is 0&lt;br /&gt;
if (vecindex(myvector, &amp;quot;apple&amp;quot;)) {&lt;br /&gt;
    print(&amp;quot;found apple&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{note| There is a similar function function contains(hash, key) to check if a hash contains a key (not value!).&lt;br /&gt;
It is to be discussed, if contains can/should be extended to support vectors in the above mentioned way. }}&lt;br /&gt;
&lt;br /&gt;
== Variables ==&lt;br /&gt;
Various global constants (technically variables) are provided for use in converting between different units. They are all found in {{fgdata file|Nasal/globals.nas|text=$FG_ROOT/Nasal/globals.nas}}.&lt;br /&gt;
&lt;br /&gt;
=== D2R ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var radians = degrees * D2R;&lt;br /&gt;
|text = Converts an angle from degrees to radians when multiplied by the angle in degrees. Equal to &amp;lt;code&amp;gt;π / 180&amp;lt;/code&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
=== FPS2KT ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var knots = feet_per_second * FPS2KT;&lt;br /&gt;
|text = Converts a velocity from feet per second to knots when multiplied by the velocity in feet per second. Approximately equal to 0.5925.&lt;br /&gt;
}}&lt;br /&gt;
=== FT2M ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var metres = feet * FT2M;&lt;br /&gt;
|text = Converts a length from feet to metres when multiplied by the length in feet. Equal to 0.3048.&lt;br /&gt;
}}&lt;br /&gt;
=== GAL2L ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var litres = gallons * GAL2L;&lt;br /&gt;
|text = Converts a volume from US liquid gallons to litres when multiplied by the volume in gallons. Approximately equal to 3.7854.&lt;br /&gt;
}}&lt;br /&gt;
=== IN2M ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var metres = inches * IN2M;&lt;br /&gt;
|text = Converts a length from inches to metres when multiplied by the length in inches. Equal to 0.0254.&lt;br /&gt;
}}&lt;br /&gt;
=== KG2LB ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var pounds = kilograms * KG2LB;&lt;br /&gt;
|text = Converts a mass from kilograms to pounds when multiplied by the mass in kilograms. Approximately equal to 2.2046.&lt;br /&gt;
}}&lt;br /&gt;
=== KT2FPS ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var feet_per_second = knots * KT2FPS;&lt;br /&gt;
|text = Converts a velocity from knots to feet per second when multiplied by the velocity in knots. Approximately equal to 1.6878.&lt;br /&gt;
}}&lt;br /&gt;
=== KT2MPS ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var metres_per_second = knots * KT2MPS;&lt;br /&gt;
|text = Converts a velocity from knots to metres per second when multiplied by the velocity in knots. Approximately equal to 0.5144.&lt;br /&gt;
}}&lt;br /&gt;
=== L2GAL ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var gallons = litres * L2GAL;&lt;br /&gt;
|text = Converts a volume from litres to US liquid gallons when multiplied by the volume in litres. Approximately equal to 0.2642.&lt;br /&gt;
}}&lt;br /&gt;
=== LB2KG ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var kilograms = pounds * LB2KG;&lt;br /&gt;
|text = Converts a mass from pounds to kilograms when multiplied by the mass in pounds. Approximately equal to 0.4536.&lt;br /&gt;
}}&lt;br /&gt;
=== M2FT ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var feet = metres * M2FT;&lt;br /&gt;
|text = Converts a length from metres to feet when multiplied by the length in metres. Approximately equal to 3.2808.&lt;br /&gt;
}}&lt;br /&gt;
=== M2IN ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var inches = metres * M2IN;&lt;br /&gt;
|text = Converts a length from metres to inches when multiplied by the length in metres. Approximately equal to 39.3701.&lt;br /&gt;
}}&lt;br /&gt;
=== M2NM ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var nautical_miles = metres * M2NM;&lt;br /&gt;
|text = Converts a length from metres to nautical miles when multiplied by the length in metres. Approximately equal to 0.00054.&lt;br /&gt;
}}&lt;br /&gt;
=== MPS2KT ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var knots = metres_per_second * MPS2KT;&lt;br /&gt;
|text = Converts a velocity from metres per second to knots when multiplied by the velocity in metres per second. Approximately equal to 1.9438.&lt;br /&gt;
}}&lt;br /&gt;
=== NM2M ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var metres = nautical_miles * NM2M;&lt;br /&gt;
|text = Converts a length from nautical miles to metres when multiplied by the length in nautical miles. Equal to 1,852.&lt;br /&gt;
}}&lt;br /&gt;
=== R2D ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = var degrees = radians * R2D;&lt;br /&gt;
|text = Converts an angle from radians to degrees when multiplied by the angle in radians. Equal to &amp;lt;code&amp;gt;180 / π&amp;lt;/code&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Appendix}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Nasal namespaces}}&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Aircraft_tester_list&amp;diff=130367</id>
		<title>Aircraft tester list</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Aircraft_tester_list&amp;diff=130367"/>
		<updated>2021-02-18T17:32:43Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: -&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a list of '''aircraft testers''' using using the procedures laid out in [[Aircraft testing checklist]] to validate that aircraft below are compatible with a FlightGear version.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Aircraft !! Tester(s) !! Remarks&lt;br /&gt;
|-&lt;br /&gt;
| 737NGs || James Turner || &lt;br /&gt;
|-&lt;br /&gt;
| 757 || James Turner|| &lt;br /&gt;
|-&lt;br /&gt;
| A300 || J Redpath|| &lt;br /&gt;
|-&lt;br /&gt;
| A320-200 || J Redpath|| [NB - upstream github repo for issues]&lt;br /&gt;
|-&lt;br /&gt;
| A340-600 || J Redpath|| &lt;br /&gt;
|-&lt;br /&gt;
| A380 || J Redpath|| &lt;br /&gt;
|-&lt;br /&gt;
| A6M2 Zero || Stuart Buchanan || &lt;br /&gt;
|-&lt;br /&gt;
| Aerostar-700 || James Turner || &lt;br /&gt;
|-&lt;br /&gt;
| B1900D || James Turner || &lt;br /&gt;
|-&lt;br /&gt;
| CH-53E || Richard H. || &lt;br /&gt;
|-&lt;br /&gt;
| CRJ700 family || Henning, Daniel || &lt;br /&gt;
|-&lt;br /&gt;
| Cap 10C || Scott || &lt;br /&gt;
|-&lt;br /&gt;
| Cessna 208B Caravan || James Turner || &lt;br /&gt;
|-&lt;br /&gt;
| DR400 || Scott || &lt;br /&gt;
|-&lt;br /&gt;
| DaSH || Wayne Bragg|| &lt;br /&gt;
|-&lt;br /&gt;
| F-14 || Richard H. || Willing to reassign upon request to those with experience of this aircraft&lt;br /&gt;
|-&lt;br /&gt;
| F-15 || Richard H. || Willing to reassign upon request to those with experience of this aircraft&lt;br /&gt;
|-&lt;br /&gt;
| F-16 || Stuart ||&lt;br /&gt;
|-&lt;br /&gt;
| F6F - Hellcat || Keith  || &lt;br /&gt;
|-&lt;br /&gt;
| F-86 || J Redpath || &lt;br /&gt;
|-&lt;br /&gt;
| Fokker 100 || J Redpath || &lt;br /&gt;
|-&lt;br /&gt;
| Grob || Scott || &lt;br /&gt;
|-&lt;br /&gt;
| Hansa Jet || Adrian S. || &lt;br /&gt;
|-&lt;br /&gt;
| Jaguar || Richard || &lt;br /&gt;
|-&lt;br /&gt;
| Junkers JU-52 || James Turner || &lt;br /&gt;
|-&lt;br /&gt;
| hunter || Stuart || &lt;br /&gt;
|-&lt;br /&gt;
| J3Cub || Wayne Bragg|| &lt;br /&gt;
|-&lt;br /&gt;
| Lionceau || Scott || &lt;br /&gt;
|-&lt;br /&gt;
| p51d || Stuart || &lt;br /&gt;
|-&lt;br /&gt;
| SUMPAC || Wayne Bragg|| &lt;br /&gt;
|-&lt;br /&gt;
| Skyvan || Keith  || &lt;br /&gt;
|-&lt;br /&gt;
| Socata  || Scott || &lt;br /&gt;
|-&lt;br /&gt;
| seahawk || Stuart || &lt;br /&gt;
|-&lt;br /&gt;
| wrightFlyer || Stuart || &lt;br /&gt;
|-&lt;br /&gt;
| tu154b || Gaétan Allaert || &lt;br /&gt;
|-&lt;br /&gt;
| Pilatus PC-9M || vanosten || &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Aircraft enhancement]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Aircraft_tester_list&amp;diff=130366</id>
		<title>Aircraft tester list</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Aircraft_tester_list&amp;diff=130366"/>
		<updated>2021-02-18T17:32:28Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: -&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a list of '''aircraft testers''' using using the procedures laid out in [[Aircraft testing checklist]] to validate that aircraft below are compatible with a FlightGear version.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Aircraft !! Tester(s) !! Remarks&lt;br /&gt;
|-&lt;br /&gt;
| 737NGs || James Turner || &lt;br /&gt;
|-&lt;br /&gt;
| 757 || James Turner|| &lt;br /&gt;
|-&lt;br /&gt;
| A300 || J Redpath|| &lt;br /&gt;
|-&lt;br /&gt;
| A320-200 || J Redpath|| [NB - upstream github repo for issues]&lt;br /&gt;
|-&lt;br /&gt;
| A340-600 || J Redpath|| &lt;br /&gt;
|-&lt;br /&gt;
| A380 || J Redpath|| &lt;br /&gt;
|-&lt;br /&gt;
| A6M2 Zero || Stuart Buchanan || &lt;br /&gt;
|-&lt;br /&gt;
| Aerostar-700 || James Turner || &lt;br /&gt;
|-&lt;br /&gt;
| B1900D || James Turner || &lt;br /&gt;
|-&lt;br /&gt;
| CH-53E || Richard H. || &lt;br /&gt;
|-&lt;br /&gt;
| CRJ700 family || Henning, Daniel || &lt;br /&gt;
|-&lt;br /&gt;
| Cap 10C || Scott || &lt;br /&gt;
|-&lt;br /&gt;
| Cessna 208B Caravan || James Turner || &lt;br /&gt;
|-&lt;br /&gt;
| DR400 || Scott || &lt;br /&gt;
|-&lt;br /&gt;
| DaSH || Wayne Bragg|| &lt;br /&gt;
|-&lt;br /&gt;
| F-14 || Richard H. || Willing to reassign upon request to those with experience of this aircraft&lt;br /&gt;
|-&lt;br /&gt;
| F-15 || Richard H. || Willing to reassign upon request to those with experience of this aircraft&lt;br /&gt;
|-&lt;br /&gt;
| F-16 || Stuart ||&lt;br /&gt;
|-&lt;br /&gt;
| F6F - Hellcat || Keith  || &lt;br /&gt;
|-&lt;br /&gt;
| F-86 || Jonathan Redpath || &lt;br /&gt;
|-&lt;br /&gt;
| Fokker 100 || Jonathan Redpath || &lt;br /&gt;
|-&lt;br /&gt;
| Grob || Scott || &lt;br /&gt;
|-&lt;br /&gt;
| Hansa Jet || Adrian S. || &lt;br /&gt;
|-&lt;br /&gt;
| Jaguar || Richard || &lt;br /&gt;
|-&lt;br /&gt;
| Junkers JU-52 || James Turner || &lt;br /&gt;
|-&lt;br /&gt;
| hunter || Stuart || &lt;br /&gt;
|-&lt;br /&gt;
| J3Cub || Wayne Bragg|| &lt;br /&gt;
|-&lt;br /&gt;
| Lionceau || Scott || &lt;br /&gt;
|-&lt;br /&gt;
| p51d || Stuart || &lt;br /&gt;
|-&lt;br /&gt;
| SUMPAC || Wayne Bragg|| &lt;br /&gt;
|-&lt;br /&gt;
| Skyvan || Keith  || &lt;br /&gt;
|-&lt;br /&gt;
| Socata  || Scott || &lt;br /&gt;
|-&lt;br /&gt;
| seahawk || Stuart || &lt;br /&gt;
|-&lt;br /&gt;
| wrightFlyer || Stuart || &lt;br /&gt;
|-&lt;br /&gt;
| tu154b || Gaétan Allaert || &lt;br /&gt;
|-&lt;br /&gt;
| Pilatus PC-9M || vanosten || &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Aircraft enhancement]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=File:SOTM_2019-12_Caribbean_Island_by_Madbyte70.jpg&amp;diff=130062</id>
		<title>File:SOTM 2019-12 Caribbean Island by Madbyte70.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=File:SOTM_2019-12_Caribbean_Island_by_Madbyte70.jpg&amp;diff=130062"/>
		<updated>2021-02-01T22:14:21Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=={{int:filedesc}}==&lt;br /&gt;
{{Information&lt;br /&gt;
|description={{en|1=SOTM 2019-12:}}&lt;br /&gt;
|date=2019-12-31&lt;br /&gt;
|source=SOTM 2019-12&lt;br /&gt;
|author=X&lt;br /&gt;
|permission=&lt;br /&gt;
|other versions=&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=={{int:license-header}}==&lt;br /&gt;
{{cc-by-sa-4.0}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Screenshot of the month]]&lt;br /&gt;
[[Category:Screenshot of the month/2019-12]]&lt;br /&gt;
[[Category:Screenshot_of_the_year/2019]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=File:SOTM_2019-11_Boulon_Woods_patrol_by_LesterBoffo.jpg&amp;diff=130061</id>
		<title>File:SOTM 2019-11 Boulon Woods patrol by LesterBoffo.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=File:SOTM_2019-11_Boulon_Woods_patrol_by_LesterBoffo.jpg&amp;diff=130061"/>
		<updated>2021-02-01T22:14:12Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=={{int:filedesc}}==&lt;br /&gt;
{{Information&lt;br /&gt;
|description={{en|1=SOTM 2019-11:}}&lt;br /&gt;
|date=2019-11-30&lt;br /&gt;
|source=SOTM 2019-11&lt;br /&gt;
|author=X&lt;br /&gt;
|permission=&lt;br /&gt;
|other versions=&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=={{int:license-header}}==&lt;br /&gt;
{{cc-by-sa-4.0}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Screenshot of the month]]&lt;br /&gt;
[[Category:Screenshot of the month/2019-11]]&lt;br /&gt;
[[Category:Screenshot_of_the_year/2019]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=File:SOTM_2019-09_Firing_at_Dawn_by_GinGin.jpg&amp;diff=130060</id>
		<title>File:SOTM 2019-09 Firing at Dawn by GinGin.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=File:SOTM_2019-09_Firing_at_Dawn_by_GinGin.jpg&amp;diff=130060"/>
		<updated>2021-02-01T22:13:49Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=={{int:filedesc}}==&lt;br /&gt;
{{Information&lt;br /&gt;
|description={{en|1=SOTM 2019-09: Firing at Dawn by GinGin}}&lt;br /&gt;
|date=2019-09-30&lt;br /&gt;
|source=SOTM 2019-09&lt;br /&gt;
|author=X&lt;br /&gt;
|permission=&lt;br /&gt;
|other versions=&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=={{int:license-header}}==&lt;br /&gt;
{{cc-by-sa-4.0}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Screenshot of the month]]&lt;br /&gt;
[[Category:Screenshot of the month/2019-09]]&lt;br /&gt;
[[Category:Screenshots of Earthview]]&lt;br /&gt;
[[Category:Space_Shuttle_screenshots]]&lt;br /&gt;
[[Category:Screenshots_at_high_settings]]&lt;br /&gt;
[[Category:Screenshots_at_high_settings/2019]]&lt;br /&gt;
[[Category:Screenshots_at_high_settings/sotm]]&lt;br /&gt;
[[Category:Screenshot_of_the_year/2019]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=File:SOTM_2019-08_Low_Landing_by_sidi762.jpg&amp;diff=130059</id>
		<title>File:SOTM 2019-08 Low Landing by sidi762.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=File:SOTM_2019-08_Low_Landing_by_sidi762.jpg&amp;diff=130059"/>
		<updated>2021-02-01T22:13:40Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=={{int:filedesc}}==&lt;br /&gt;
{{Information&lt;br /&gt;
|description={{en|1=SOTM 2019-08: Low Landing by sidi762}}&lt;br /&gt;
|date=2019-08-31&lt;br /&gt;
|source=SOTM 2019-08&lt;br /&gt;
|author=X&lt;br /&gt;
|permission=&lt;br /&gt;
|other versions=&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=={{int:license-header}}==&lt;br /&gt;
{{cc-by-sa-4.0}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Screenshot of the month]]&lt;br /&gt;
[[Category:Screenshot of the month/2019-08]]&lt;br /&gt;
[[Category:Screenshot_of_the_year/2019]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=File:SOTM_2019-07_Sunset_Sortie_in_the_Alps_by_J-Maverick_16.jpg&amp;diff=130058</id>
		<title>File:SOTM 2019-07 Sunset Sortie in the Alps by J-Maverick 16.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=File:SOTM_2019-07_Sunset_Sortie_in_the_Alps_by_J-Maverick_16.jpg&amp;diff=130058"/>
		<updated>2021-02-01T22:13:29Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=={{int:filedesc}}==&lt;br /&gt;
{{Information&lt;br /&gt;
|description={{en|1=SOTM 2019-07: Sunset Sortie in the Alps by J-Maverick 16}}&lt;br /&gt;
|date=2019-07-31&lt;br /&gt;
|source=SOTM 2019-07&lt;br /&gt;
|author=X&lt;br /&gt;
|permission=&lt;br /&gt;
|other versions=&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=={{int:license-header}}==&lt;br /&gt;
{{cc-by-sa-4.0}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Screenshot of the month]]&lt;br /&gt;
[[Category:Screenshot of the month/2019-07]]&lt;br /&gt;
[[Category:Screenshot_of_the_year/2019]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=File:SOTM_2019-06_Stormy_Singapore_by_sidi762.jpg&amp;diff=130057</id>
		<title>File:SOTM 2019-06 Stormy Singapore by sidi762.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=File:SOTM_2019-06_Stormy_Singapore_by_sidi762.jpg&amp;diff=130057"/>
		<updated>2021-02-01T22:12:54Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=={{int:filedesc}}==&lt;br /&gt;
{{Information&lt;br /&gt;
|description={{en|1=SOTM 2019-06: Stormy Singapore by sidi762}}&lt;br /&gt;
|date=2019-06-30&lt;br /&gt;
|source=SOTM 2019-06&lt;br /&gt;
|author=sidi762&lt;br /&gt;
|permission=&lt;br /&gt;
|other versions=&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=={{int:license-header}}==&lt;br /&gt;
{{cc-by-sa-4.0}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Screenshot of the month|2019 06]]&lt;br /&gt;
[[Category:Screenshot of the month/2019-06]]&lt;br /&gt;
[[Category:Screenshots_at_high_settings]]&lt;br /&gt;
[[Category:Screenshots_at_high_settings/2019]]&lt;br /&gt;
[[Category:Screenshots_at_high_settings/sotm]]&lt;br /&gt;
[[Category:Boeing 777 screenshots]]&lt;br /&gt;
[[Category:Screenshot_of_the_year/2019]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=File:SOTM_2019-06_Ice_and_fire_by_vnts.jpg&amp;diff=130056</id>
		<title>File:SOTM 2019-06 Ice and fire by vnts.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=File:SOTM_2019-06_Ice_and_fire_by_vnts.jpg&amp;diff=130056"/>
		<updated>2021-02-01T22:12:50Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=={{int:filedesc}}==&lt;br /&gt;
{{Information&lt;br /&gt;
|description={{en|1=SOTM 2019-06: Ice and fire by vnts}}&lt;br /&gt;
|date=2019-06-28&lt;br /&gt;
|source=SOTM June 2019&lt;br /&gt;
|author=vnts&lt;br /&gt;
|permission=&lt;br /&gt;
|other versions=&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=={{int:license-header}}==&lt;br /&gt;
{{cc-by-sa-4.0}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Screenshot of the month|2019 06]]&lt;br /&gt;
[[Category:Screenshot of the month/2019-06]]&lt;br /&gt;
[[Category:Screenshots of volcanoes]]&lt;br /&gt;
[[Category:Screenshots_at_high_settings]]&lt;br /&gt;
[[Category:Screenshots_at_high_settings/2019]]&lt;br /&gt;
[[Category:Screenshots of scenery in Sicily]]&lt;br /&gt;
[[Category:Bell 412 screenshots]]&lt;br /&gt;
[[Category:Screenshots_at_high_settings/sotm]]&lt;br /&gt;
[[Category:Screenshot_of_the_year/2019]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=File:SOTM-May19.jpg&amp;diff=130055</id>
		<title>File:SOTM-May19.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=File:SOTM-May19.jpg&amp;diff=130055"/>
		<updated>2021-02-01T22:12:18Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=={{int:filedesc}}==&lt;br /&gt;
{{Information&lt;br /&gt;
|description={{en|1=New Aviatik to Colmar Sud by LesterBoffo}}&lt;br /&gt;
|date=2019-06-01&lt;br /&gt;
|source=SOTM Contest&lt;br /&gt;
|author=LesterBoffo&lt;br /&gt;
|permission=&lt;br /&gt;
|other versions=&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=={{int:license-header}}==&lt;br /&gt;
{{cc-by-sa-4.0}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Screenshot of the month|2019 05]]&lt;br /&gt;
[[Category:Screenshot of the month/2019-05]]&lt;br /&gt;
[[Category:Screenshot_of_the_year/2019]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=File:SOTM_2019-04_Space_Sauna_by_GinGin.jpg&amp;diff=130054</id>
		<title>File:SOTM 2019-04 Space Sauna by GinGin.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=File:SOTM_2019-04_Space_Sauna_by_GinGin.jpg&amp;diff=130054"/>
		<updated>2021-02-01T22:11:58Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=={{int:filedesc}}==&lt;br /&gt;
{{Information&lt;br /&gt;
|description={{en|1=Space Sauna by GinGin}}&lt;br /&gt;
|date=2019-04-30&lt;br /&gt;
|source=SOTM April 2019&lt;br /&gt;
|author=GinGin&lt;br /&gt;
|permission=&lt;br /&gt;
|other versions=&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=={{int:license-header}}==&lt;br /&gt;
{{cc-by-sa-4.0}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Screenshot of the month|2019 04]]&lt;br /&gt;
[[Category:Screenshot of the month/2019-04]]&lt;br /&gt;
[[Category:Screenshots of Earthview]]&lt;br /&gt;
[[Category:Space_Shuttle_screenshots]]&lt;br /&gt;
[[Category:Screenshots_at_high_settings]]&lt;br /&gt;
[[Category:Screenshots_at_high_settings/2019]]&lt;br /&gt;
[[Category:Screenshots_at_high_settings/sotm]]&lt;br /&gt;
[[Category:Screenshot_of_the_year/2019]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=File:SOTM-Mar19.jpg&amp;diff=130053</id>
		<title>File:SOTM-Mar19.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=File:SOTM-Mar19.jpg&amp;diff=130053"/>
		<updated>2021-02-01T22:11:36Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=={{int:filedesc}}==&lt;br /&gt;
{{File information&lt;br /&gt;
|description    = {{en|1=Dawn Trip over Madrid by StuartC}}&lt;br /&gt;
|date           = &lt;br /&gt;
|source         = &lt;br /&gt;
|author         = &lt;br /&gt;
|other versions = &lt;br /&gt;
|other fields   = &lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=={{int:license-header}}==&lt;br /&gt;
{{self|cc-by-sa-4.0}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Screenshot of the month|2019 03]]&lt;br /&gt;
[[Category:Screenshot of the month/2019-03]]&lt;br /&gt;
[[Category:Screenshots_at_high_settings]]&lt;br /&gt;
[[Category:Screenshots_at_high_settings/2019]]&lt;br /&gt;
[[Category:Screenshots of scenery with OSM2City output]]&lt;br /&gt;
[[Category:Aérospatiale/Westland Gazelle screenshots]]&lt;br /&gt;
[[Category:Screenshots of scenery in Spain]]&lt;br /&gt;
[[Category:Screenshots_at_high_settings/sotm]]&lt;br /&gt;
[[Category:Screenshot_of_the_year/2019]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=File:SOTM-Feb19.jpg&amp;diff=130052</id>
		<title>File:SOTM-Feb19.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=File:SOTM-Feb19.jpg&amp;diff=130052"/>
		<updated>2021-02-01T22:11:15Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=={{int:filedesc}}==&lt;br /&gt;
{{Information&lt;br /&gt;
|description={{en|1=Scramble, Scramble by legoboyvdlp}}&lt;br /&gt;
|date=2019-03-07&lt;br /&gt;
|source={{own}}&lt;br /&gt;
|author=[[User:Legoboyvdlp|Legoboyvdlp]]&lt;br /&gt;
|permission=&lt;br /&gt;
|other versions=&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=={{int:license-header}}==&lt;br /&gt;
{{self|cc-by-sa-4.0}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Screenshot of the month|2019 02]]&lt;br /&gt;
[[Category:Screenshot of the month/2019-02]]&lt;br /&gt;
[[Category:Screenshot_of_the_year/2019]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=File:SOTM-Jan19.jpg&amp;diff=130051</id>
		<title>File:SOTM-Jan19.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=File:SOTM-Jan19.jpg&amp;diff=130051"/>
		<updated>2021-02-01T22:10:33Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: SOTY&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=={{int:filedesc}}==&lt;br /&gt;
{{Information&lt;br /&gt;
|description={{en|1=Rising Around Wales by StuartC}}&lt;br /&gt;
|date=2019-02-04&lt;br /&gt;
|source=SOTM contest&lt;br /&gt;
|author=StuartC&lt;br /&gt;
|permission=&lt;br /&gt;
|other versions=&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=={{int:license-header}}==&lt;br /&gt;
{{cc-by-sa-4.0}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Screenshot of the month|2019 01]]&lt;br /&gt;
[[Category:Screenshot of the month/2019-01]]&lt;br /&gt;
[[Category:Screenshots_at_high_settings]]&lt;br /&gt;
[[Category:Screenshots_at_high_settings/2019]]&lt;br /&gt;
[[Category:Screenshots_at_high_settings/sotm]]&lt;br /&gt;
[[Category:Robinson_R44_screenshots]]&lt;br /&gt;
[[Category:Screenshot_of_the_year/2019]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Category:Screenshot_of_the_year/2019&amp;diff=130050</id>
		<title>Category:Screenshot of the year/2019</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Category:Screenshot_of_the_year/2019&amp;diff=130050"/>
		<updated>2021-02-01T22:09:48Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: Created page with &amp;quot;See {{forum link|title=Voting for the SOTY of 2019|t=36740}}.&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;See {{forum link|title=Voting for the SOTY of 2019|t=36740}}.&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Category:Screenshot_of_the_month/2019-12&amp;diff=130049</id>
		<title>Category:Screenshot of the month/2019-12</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Category:Screenshot_of_the_month/2019-12&amp;diff=130049"/>
		<updated>2021-02-01T22:08:36Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;See {{forum link|title=Submit your screenshot for the SOTM of December 2019|t=36643}} and {{forum link|title=Voting for the SOTM of December 2019|t=36702}}.&lt;br /&gt;
[[Category:Screenshot of the month]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Category:Screenshot_of_the_month/2019-11&amp;diff=130048</id>
		<title>Category:Screenshot of the month/2019-11</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Category:Screenshot_of_the_month/2019-11&amp;diff=130048"/>
		<updated>2021-02-01T22:08:02Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;See {{forum link|title=Submit your screenshot for the SOTM of November 2019|t=36496}} and {{forum link|title=Voting for the SOTM of November 2019|t=36616}}.&lt;br /&gt;
[[Category:Screenshot of the month]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Category:Screenshot_of_the_month&amp;diff=130047</id>
		<title>Category:Screenshot of the month</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Category:Screenshot_of_the_month&amp;diff=130047"/>
		<updated>2021-02-01T22:07:29Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{en|Category with winners of the ''Screenshot of the Month'' contests from April 2011 to April 2012, and since June 2015.}}&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: center&amp;quot;&lt;br /&gt;
! Date&lt;br /&gt;
! Screenshot submission&lt;br /&gt;
! Vote&lt;br /&gt;
! Subcategory&lt;br /&gt;
|-&lt;br /&gt;
| 2019-01&lt;br /&gt;
| {{forum link|title=Submit your screenshot for the SOTM of January!|t=35229}}&lt;br /&gt;
| {{forum link|title=Voting for the SOTM January|t=35303}}&lt;br /&gt;
| [[:Category:Screenshot of the month/2019-01]]&lt;br /&gt;
|-&lt;br /&gt;
| 2019-02&lt;br /&gt;
| {{forum link|title=Submit your Screenshot for February's SOTM!|t=35319}}&lt;br /&gt;
| {{forum link|title=Voting for the SOTM|t=35413}}&lt;br /&gt;
| [[:Category:Screenshot of the month/2019-02]]&lt;br /&gt;
|-&lt;br /&gt;
| 2019-03&lt;br /&gt;
| {{forum link|title=Submit your screenshot for the SOTM of March|t=35436}}&lt;br /&gt;
| {{forum link|title=Voting for the SOTM|t=35554}}&lt;br /&gt;
| [[:Category:Screenshot of the month/2019-03]]&lt;br /&gt;
|-&lt;br /&gt;
| 2019-04&lt;br /&gt;
| {{forum link|title=Submit your screenshot for the SOTM of April|t=35574}}&lt;br /&gt;
| {{forum link|title=Voting for the SOTM|t=35720}}&lt;br /&gt;
| [[:Category:Screenshot of the month/2019-04]]&lt;br /&gt;
|-&lt;br /&gt;
| 2019-05&lt;br /&gt;
| {{forum link|title=Submit your screenshot for the SOTM of May|t=35746}}&lt;br /&gt;
| {{forum link|title=Voting for the SOTM of May|t=35880}}&lt;br /&gt;
| [[:Category:Screenshot of the month/2019-05]]&lt;br /&gt;
|-&lt;br /&gt;
| 2019-06&lt;br /&gt;
| {{forum link|title=Submit your screenshot for the SOTM of June!|t=35903}}&lt;br /&gt;
| {{forum link|title=Vote for the SOTM of June|t=36046}}&lt;br /&gt;
| [[:Category:Screenshot of the month/2019-06]]&lt;br /&gt;
|-&lt;br /&gt;
| 2019-07&lt;br /&gt;
| {{forum link|title=Submit your screenshot for the SOTM of July|t=36088}}&lt;br /&gt;
| {{forum link|title=Vote for the SOTM July 2019|t=36149}}&lt;br /&gt;
| [[:Category:Screenshot of the month/2019-07]]&lt;br /&gt;
|-&lt;br /&gt;
| 2019-08&lt;br /&gt;
| {{forum link|title=Submit your screenshot for the SOTM of August!|t=36188}}&lt;br /&gt;
| {{forum link|title=Vote for the SOTM August 2019|t=36265}}&lt;br /&gt;
| [[:Category:Screenshot of the month/2019-08]]&lt;br /&gt;
|-&lt;br /&gt;
| 2019-09&lt;br /&gt;
| {{forum link|title=Submit your screenshot for SOTM of September|t=36316}}&lt;br /&gt;
| {{forum link|title=Voting for the SOTM September|t=36361}}&lt;br /&gt;
| [[:Category:Screenshot of the month/2019-09]]&lt;br /&gt;
|-&lt;br /&gt;
| 2019-10&lt;br /&gt;
| - no contest -&lt;br /&gt;
| &lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 2019-11&lt;br /&gt;
| {{forum link|title=Submit your screenshot for the SOTM of November 2019|t=36496}}&lt;br /&gt;
| {{forum link|title=Voting for the SOTM of November 2019|t=36616}}&lt;br /&gt;
| [[:Category:Screenshot of the month/2019-11]]&lt;br /&gt;
|-&lt;br /&gt;
| 2019-12&lt;br /&gt;
| {{forum link|title=Submit your screenshot for the SOTM of December 2019|t=36643}}&lt;br /&gt;
| {{forum link|title=Voting for the SOTM of December 2019|t=36702}}&lt;br /&gt;
| [[:Category:Screenshot of the month/2019-12]]&lt;br /&gt;
|-&lt;br /&gt;
| 2019 SOTY&lt;br /&gt;
| - Used previous month's winners -&lt;br /&gt;
| {{forum link|title=Voting for the SOTY of 2019|t=36740}}&lt;br /&gt;
| [[:Category:Screenshot of the year/2019]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:FlightGear screenshots]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Category:Screenshot_of_the_month/2019-09&amp;diff=130046</id>
		<title>Category:Screenshot of the month/2019-09</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Category:Screenshot_of_the_month/2019-09&amp;diff=130046"/>
		<updated>2021-02-01T22:06:12Z</updated>

		<summary type="html">&lt;p&gt;Legoboyvdlp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;See {{forum link|title=Submit your screenshot for SOTM of September|t=36316}} and {{forum link|title=Voting for the SOTM September|t=36361}}.&lt;br /&gt;
[[Category:Screenshot of the month]]&lt;/div&gt;</summary>
		<author><name>Legoboyvdlp</name></author>
	</entry>
</feed>