<?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=Chris-barry</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=Chris-barry"/>
	<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/Special:Contributions/Chris-barry"/>
	<updated>2026-04-05T05:53:05Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.6</generator>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_library&amp;diff=92156</id>
		<title>Nasal library</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_library&amp;diff=92156"/>
		<updated>2016-02-01T03:45:49Z</updated>

		<summary type="html">&lt;p&gt;Chris-barry: /* subvec() */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Nasal Navigation}}&lt;br /&gt;
&lt;br /&gt;
This page documents the global '''library functions''' 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, and ''[[#Extension functions|extension functions]]'', which have been subsequently added, and are specifically designed for FlightGear. The main 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;
{{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|debug.printerror()|ext=http://sourceforge.net/p/flightgear/fgdata/ci/next/tree/Nasal/debug.nas}}.&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.  The result is a four-element vector containing a hash of local variables, the function object, the source, and 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 (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 land=&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 identical to setting the hash value specified by the key to &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt;, but 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;
|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;
|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()|ext=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;
|example1text = 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;
}}&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()|ext=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.&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;%&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;
}}&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=107|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.&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;
}}&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;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&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;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
A negative ''start'' argument ''is'' an error. This seems wrong. Perhaps the language designer could comment.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&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;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&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;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&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;
== 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()|ext=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;
=== addcommand() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = addcommand(name, code);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=648|t=Source}}&lt;br /&gt;
|version = 2.12&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 {&lt;br /&gt;
    print(&amp;quot;fgcommand 'myFGCmd' has been run.&amp;quot;);&lt;br /&gt;
});&lt;br /&gt;
fgcommand(&amp;quot;myFGCmd&amp;quot;);&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;
* '''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;
*** '''stopway''': Length of the runway's stopway (the area before the threshold) in metres. Will return 0 if there is none.&lt;br /&gt;
*** '''threshold''': Length of the runway's {{wikipedia|displaced threshold}} in metres. Will return 0 if there is none.&lt;br /&gt;
*** '''lat''': Latitude of the runway.&lt;br /&gt;
*** '''lon''': Longitude of the runway.&lt;br /&gt;
*** '''width''': Width of the runway in metres.&lt;br /&gt;
*** '''heading''': Heading of the runway.&lt;br /&gt;
*** '''length''': Length of the runway in metres.&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;
=== 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;
|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;
=== 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;
=== getprop() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = getprop(arg[, arg[, ...]]);&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 = arg&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 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 version 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;
&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, for example, the Nasal Console, rather than {{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;
&lt;br /&gt;
=== removecommand() ===&lt;br /&gt;
&lt;br /&gt;
As you can guess, there's also a removecommand() function which will remove '''any''' command – even those implemented in C++! As such it can be very dangerous and remove core functionality, so use with caution.&lt;br /&gt;
&lt;br /&gt;
=== print() ===&lt;br /&gt;
Concatenates an arbitrary number of arguments to one string, appends a new-line, and prints it to the terminal. Returns the number of printed characters.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
print(&amp;quot;Just&amp;quot;, &amp;quot; a &amp;quot;, &amp;quot;test&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== setprop() ===&lt;br /&gt;
Sets a property value for a given node path string. Returns 1 on success or 0 if the property could not be set (i.e. was read-only).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
setprop(&amp;lt;path&amp;gt; [, &amp;lt;path&amp;gt;, [...]], &amp;lt;value&amp;gt;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All arguments but the last are concatenated to a path string, like getprop() above. The last value is written to the respective node. If the node isn't writable, then an error message is printed to the console.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
setprop(&amp;quot;/sim/current-view/view-number&amp;quot;, 2);&lt;br /&gt;
setprop(&amp;quot;/controls&amp;quot;, &amp;quot;engines/engine[0]&amp;quot;, &amp;quot;reverser&amp;quot;, 1);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Erasing a property from the property tree''': a property that has been created, for example through &amp;lt;tt&amp;gt;setprop()&amp;lt;/tt&amp;gt; has to be erased using the props namespace helper, like this:&lt;br /&gt;
&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;
=== setlistener() ===&lt;br /&gt;
&lt;br /&gt;
=== settimer() ===&lt;br /&gt;
{{Leaking Nasal Disclaimer&lt;br /&gt;
|oldapi=settimer()&lt;br /&gt;
|newapi=maketimer()&lt;br /&gt;
}}&lt;br /&gt;
Runs a function after a given simulation time (default) or real time in seconds.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
settimer(&amp;lt;function&amp;gt;, &amp;lt;time&amp;gt; [, &amp;lt;realtime=0&amp;gt;]);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The '''first argument''' is a function object (ie, &amp;quot;func { ... }&amp;quot;).  Note that this is different from a function call (ie, &amp;quot;func ( ... )&amp;quot;). If you don't understand what this means, just remember to always enclose the first argument in any call to settimer with the word &amp;quot;func&amp;quot; and braces &amp;quot;{ }&amp;quot;, and it will always work. &lt;br /&gt;
&lt;br /&gt;
The '''second argument''' is a delay time. After this amount of time the function will be executed.&lt;br /&gt;
For instance, if you want to print the words &amp;quot;My result&amp;quot; in five seconds, use this code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
settimer ( func { print ( &amp;quot;My result&amp;quot;); }, 5);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Inside the braces of the func object you can put any valid Nasal code, including a function call.  In fact, if you want to call a function with certain values as arguments, the way to do it is to turn it into a function object by enclosing it with a func{}, for example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
myarg1=&amp;quot;My favorite string&amp;quot;;&lt;br /&gt;
myarg2=432;&lt;br /&gt;
settimer ( func { myfunction ( myarg1, myarg2); }, 25);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The '''third argument''' is optional and defaults to 0, which lets the time argument be interpreted as &amp;quot;seconds simulation time&amp;quot;. In this case the timer doesn't run when FlightGear is paused. For user interaction purposes (measuring key press time, displaying popups, etc.) one usually prefers real time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
# simulation time example&lt;br /&gt;
var copilot_annoyed = func { setprop(&amp;quot;/sim/messages/copilot&amp;quot;, &amp;quot;Stop it! Immediately!&amp;quot;) }&lt;br /&gt;
settimer(copilot_annoyed, 10);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
# real time example&lt;br /&gt;
var popdown = func ( tipArg ) { &lt;br /&gt;
    fgcommand(&amp;quot;dialog-close&amp;quot;, tipArg); &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var selfStatusPopupTip = func (label, delay = 10, override = nil) {	&lt;br /&gt;
    var tmpl = props.Node.new({&lt;br /&gt;
            name : &amp;quot;PopTipSelf&amp;quot;, modal : 0, layout : &amp;quot;hbox&amp;quot;,&lt;br /&gt;
            y: 140,&lt;br /&gt;
            text : { label : label, padding : 6 }&lt;br /&gt;
    });&lt;br /&gt;
    if (override != nil) tmpl.setValues(override);&lt;br /&gt;
&lt;br /&gt;
    popdown(tipArgSelf);&lt;br /&gt;
    fgcommand(&amp;quot;dialog-new&amp;quot;, tmpl);&lt;br /&gt;
    fgcommand(&amp;quot;dialog-show&amp;quot;, tipArgSelf);&lt;br /&gt;
&lt;br /&gt;
    currTimerSelf += 1;&lt;br /&gt;
    var thisTimerSelf = currTimerSelf;&lt;br /&gt;
&lt;br /&gt;
    # Final argument 1 is a flag to use &amp;quot;real&amp;quot; time, not simulated time&lt;br /&gt;
    settimer(func { if(currTimerSelf == thisTimerSelf) { popdown(tipArgSelf) } }, delay, 1);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Nasal scripting language#settimer loops|More information about using the settimer function to create loops.]]&lt;br /&gt;
&lt;br /&gt;
=== maketimer() ===&lt;br /&gt;
{{FG ver|2.12+}}&lt;br /&gt;
&lt;br /&gt;
Since FlightGear v2.12, there is a new API for making a timer that allows more control over what happens in a timer, as opposed to setting one and forgetting about it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var timer = maketimer(&amp;lt;interval&amp;gt;, &amp;lt;function&amp;gt;);&lt;br /&gt;
var timer = maketimer(&amp;lt;interval&amp;gt;, &amp;lt;self&amp;gt;, &amp;lt;function&amp;gt;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
timer.start();&lt;br /&gt;
timer.stop();&lt;br /&gt;
timer.restart(&amp;lt;interval&amp;gt;);&lt;br /&gt;
timer.singleShot [read/write]&lt;br /&gt;
timer.isRunning [read-only]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
# create timer with 1 second interval&lt;br /&gt;
var timer = maketimer(1, func(){ &lt;br /&gt;
    print('timer called'); &lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
# start the timer (with 1 second inverval)&lt;br /&gt;
timer.start();&lt;br /&gt;
&lt;br /&gt;
# restart timer with 4 second interval&lt;br /&gt;
timer.restart(4);&lt;br /&gt;
&lt;br /&gt;
# fire one single time in 6 seconds&lt;br /&gt;
timer.singleShot = 1;&lt;br /&gt;
timer.restart(6);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var Tooltip = {&lt;br /&gt;
    new: func(){&lt;br /&gt;
        var m = { parents: [Tooltip] };&lt;br /&gt;
&lt;br /&gt;
        m._hideTimer = maketimer(1.0, m, Tooltip._hideTimeout);&lt;br /&gt;
        m._hideTimer.singleShot = 1;&lt;br /&gt;
&lt;br /&gt;
        return m;&lt;br /&gt;
    },&lt;br /&gt;
&lt;br /&gt;
    run: func(){&lt;br /&gt;
        if(!me._hideTimer.isRunning) me._hideTimer.start();&lt;br /&gt;
    },&lt;br /&gt;
&lt;br /&gt;
    _hideTimeout: func(){&lt;br /&gt;
        print(&amp;quot;_hideTimeout&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var t = Tooltip.new();&lt;br /&gt;
t.run();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== history() (3.1+) ===&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 legth&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;
=== systime() ===&lt;br /&gt;
Returns epoch time (time since 1970/01/01 00:00) in seconds as a floating point number with high resolution. This is useful for benchmarking purposes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
#benchmarking example:&lt;br /&gt;
var start = systime();&lt;br /&gt;
how_fast_am_I(123);&lt;br /&gt;
var end = systime();&lt;br /&gt;
print(&amp;quot;took &amp;quot;, end - start, &amp;quot; seconds&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== parsexml() ===&lt;br /&gt;
&lt;br /&gt;
This function is an interface to the built-in [http://expat.sourceforge.net/ Expat XML parser]. It takes up to five arguments. The first is a mandatory absolute path to an XML file, the remaining four are optional callback functions, each of which can be nil (which is also the default value).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var ret = parsexml(&amp;lt;path&amp;gt; [, &amp;lt;start-elem&amp;gt; [, &amp;lt;end-elem&amp;gt; [, &amp;lt;data&amp;gt; [, &amp;lt;pi&amp;gt; ]]]]);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;start-elem&amp;gt;  ... called for every starting tag with two arguments: the tag name, and an attribute hash&lt;br /&gt;
&amp;lt;end-elem&amp;gt;    ... called for every ending tag with one argument: the tag name&lt;br /&gt;
&amp;lt;data&amp;gt;        ... called for every piece of data with one argument: the data string&lt;br /&gt;
&amp;lt;pi&amp;gt;          ... called for every &amp;quot;processing information&amp;quot; with two args: target and data string&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ret&amp;gt;         ... the return value is nil on error, and the &amp;lt;path&amp;gt; otherwise&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var start = func(name, attr) {&lt;br /&gt;
    print(&amp;quot;starting tag &amp;quot;, name);&lt;br /&gt;
    foreach (var a; keys(attr))&lt;br /&gt;
        print(&amp;quot;\twith attribute &amp;quot;, a, &amp;quot;=&amp;quot;, attr[a]);&lt;br /&gt;
}&lt;br /&gt;
var end = func(name) { print(&amp;quot;ending tag &amp;quot;, name) }&lt;br /&gt;
var data = func(data) { print(&amp;quot;data=&amp;quot;, data) }&lt;br /&gt;
var pi = func(target, data) { print(&amp;quot;processing instruction: target=&amp;quot;, target, &amp;quot; data=&amp;quot;, data) }&lt;br /&gt;
parsexml(&amp;quot;/tmp/foo.xml&amp;quot;, start, end, data, pi);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== resolvepath() ===&lt;br /&gt;
&lt;br /&gt;
SimGear features its own [[Resolving Paths|path resolving framework]] that takes a relative path and returns an absolute path, checking from base directories such as [[$FG_ROOT]], [[$FG_HOME]], [[$FG_AIRCRAFT]], and the current aircraft directory (&amp;lt;tt&amp;gt;/sim/aircraft-dir&amp;lt;/tt&amp;gt;). This function in Nasal takes a path string and returns the absolute path or an empty string if the path couldn't be resolved.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var guess_path = func(path...) {&lt;br /&gt;
    var path_concat = string.join(path, &amp;quot;/&amp;quot;);&lt;br /&gt;
    var file_path = resolvepath(path_concat);&lt;br /&gt;
    if (file_path == &amp;quot;&amp;quot;) die(&amp;quot;Path not found: &amp;quot;~path_concat);&lt;br /&gt;
    return file_path;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== HTTP module (2.99+) ===&lt;br /&gt;
&lt;br /&gt;
Get remote data using the HTTP.&lt;br /&gt;
&lt;br /&gt;
==== http.load() ====&lt;br /&gt;
&lt;br /&gt;
Load resource identified by its URL into memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var request = http.load(&amp;lt;url&amp;gt;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
http.load(&amp;quot;http://example.com/test.txt&amp;quot;)&lt;br /&gt;
    .done(func(r) print(&amp;quot;Got response: &amp;quot; ~ r.response));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== http.save() ====&lt;br /&gt;
&lt;br /&gt;
Save resource to a local file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var request = http.save(&amp;lt;url&amp;gt;, &amp;lt;file_path&amp;gt;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
http.save(&amp;quot;http://example.com/test.png&amp;quot;, getprop('/sim/fg-home') ~ '/cache/test.png')&lt;br /&gt;
    .fail(func print(&amp;quot;Download failed!&amp;quot;))&lt;br /&gt;
    .done(func(r) print(&amp;quot;Finished request with status: &amp;quot; ~ r.status ~ &amp;quot; &amp;quot; ~ r.reason))&lt;br /&gt;
    .always(func print(&amp;quot;Request complete (fail or success)&amp;quot;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== rand() ===&lt;br /&gt;
&lt;br /&gt;
Return a random number as generated by &amp;lt;tt&amp;gt;sg_random&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== srand() ===&lt;br /&gt;
&lt;br /&gt;
Seed the random number generator based upon the current time. Returns 0.&lt;br /&gt;
&lt;br /&gt;
=== md5() (3.1+) ===&lt;br /&gt;
&lt;br /&gt;
Get the md5 hash of a string.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var hash = md5(&amp;lt;str&amp;gt;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Appendix}}&lt;/div&gt;</summary>
		<author><name>Chris-barry</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_library&amp;diff=92155</id>
		<title>Nasal library</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_library&amp;diff=92155"/>
		<updated>2016-02-01T03:34:45Z</updated>

		<summary type="html">&lt;p&gt;Chris-barry: /* subvec() */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Nasal Navigation}}&lt;br /&gt;
&lt;br /&gt;
This page documents the global '''library functions''' 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, and ''[[#Extension functions|extension functions]]'', which have been subsequently added, and are specifically designed for FlightGear. The main 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;
{{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|debug.printerror()|ext=http://sourceforge.net/p/flightgear/fgdata/ci/next/tree/Nasal/debug.nas}}.&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.  The result is a four-element vector containing a hash of local variables, the function object, the source, and 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 (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 land=&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 identical to setting the hash value specified by the key to &amp;lt;code&amp;gt;'''nil'''&amp;lt;/code&amp;gt;, but 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;
|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;
|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()|ext=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;
|example1text = 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;
}}&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()|ext=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.&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;%&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;
}}&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=107|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.&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;
}}&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;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&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;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
A negative ''start'' argument ''is'' an error. This seems wrong. Perhaps the language designer could comment.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
A value of ''start'' greater than ''size(vect)'' causes an error. A value equal to ''size(vector)'' returns an empty vector.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&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;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&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;
== 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()|ext=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;
=== addcommand() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = addcommand(name, code);&lt;br /&gt;
|source = {{flightgear file|src/Scripting/NasalSys.cxx|l=648|t=Source}}&lt;br /&gt;
|version = 2.12&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 {&lt;br /&gt;
    print(&amp;quot;fgcommand 'myFGCmd' has been run.&amp;quot;);&lt;br /&gt;
});&lt;br /&gt;
fgcommand(&amp;quot;myFGCmd&amp;quot;);&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;
* '''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;
*** '''stopway''': Length of the runway's stopway (the area before the threshold) in metres. Will return 0 if there is none.&lt;br /&gt;
*** '''threshold''': Length of the runway's {{wikipedia|displaced threshold}} in metres. Will return 0 if there is none.&lt;br /&gt;
*** '''lat''': Latitude of the runway.&lt;br /&gt;
*** '''lon''': Longitude of the runway.&lt;br /&gt;
*** '''width''': Width of the runway in metres.&lt;br /&gt;
*** '''heading''': Heading of the runway.&lt;br /&gt;
*** '''length''': Length of the runway in metres.&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;
=== 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;
|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;
=== 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;
=== getprop() ===&lt;br /&gt;
{{Nasal doc&lt;br /&gt;
|syntax = getprop(arg[, arg[, ...]]);&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 = arg&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 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 version 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;
&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, for example, the Nasal Console, rather than {{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;
&lt;br /&gt;
=== removecommand() ===&lt;br /&gt;
&lt;br /&gt;
As you can guess, there's also a removecommand() function which will remove '''any''' command – even those implemented in C++! As such it can be very dangerous and remove core functionality, so use with caution.&lt;br /&gt;
&lt;br /&gt;
=== print() ===&lt;br /&gt;
Concatenates an arbitrary number of arguments to one string, appends a new-line, and prints it to the terminal. Returns the number of printed characters.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
print(&amp;quot;Just&amp;quot;, &amp;quot; a &amp;quot;, &amp;quot;test&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== setprop() ===&lt;br /&gt;
Sets a property value for a given node path string. Returns 1 on success or 0 if the property could not be set (i.e. was read-only).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
setprop(&amp;lt;path&amp;gt; [, &amp;lt;path&amp;gt;, [...]], &amp;lt;value&amp;gt;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All arguments but the last are concatenated to a path string, like getprop() above. The last value is written to the respective node. If the node isn't writable, then an error message is printed to the console.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
setprop(&amp;quot;/sim/current-view/view-number&amp;quot;, 2);&lt;br /&gt;
setprop(&amp;quot;/controls&amp;quot;, &amp;quot;engines/engine[0]&amp;quot;, &amp;quot;reverser&amp;quot;, 1);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Erasing a property from the property tree''': a property that has been created, for example through &amp;lt;tt&amp;gt;setprop()&amp;lt;/tt&amp;gt; has to be erased using the props namespace helper, like this:&lt;br /&gt;
&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;
=== setlistener() ===&lt;br /&gt;
&lt;br /&gt;
=== settimer() ===&lt;br /&gt;
{{Leaking Nasal Disclaimer&lt;br /&gt;
|oldapi=settimer()&lt;br /&gt;
|newapi=maketimer()&lt;br /&gt;
}}&lt;br /&gt;
Runs a function after a given simulation time (default) or real time in seconds.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
settimer(&amp;lt;function&amp;gt;, &amp;lt;time&amp;gt; [, &amp;lt;realtime=0&amp;gt;]);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The '''first argument''' is a function object (ie, &amp;quot;func { ... }&amp;quot;).  Note that this is different from a function call (ie, &amp;quot;func ( ... )&amp;quot;). If you don't understand what this means, just remember to always enclose the first argument in any call to settimer with the word &amp;quot;func&amp;quot; and braces &amp;quot;{ }&amp;quot;, and it will always work. &lt;br /&gt;
&lt;br /&gt;
The '''second argument''' is a delay time. After this amount of time the function will be executed.&lt;br /&gt;
For instance, if you want to print the words &amp;quot;My result&amp;quot; in five seconds, use this code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
settimer ( func { print ( &amp;quot;My result&amp;quot;); }, 5);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Inside the braces of the func object you can put any valid Nasal code, including a function call.  In fact, if you want to call a function with certain values as arguments, the way to do it is to turn it into a function object by enclosing it with a func{}, for example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
myarg1=&amp;quot;My favorite string&amp;quot;;&lt;br /&gt;
myarg2=432;&lt;br /&gt;
settimer ( func { myfunction ( myarg1, myarg2); }, 25);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The '''third argument''' is optional and defaults to 0, which lets the time argument be interpreted as &amp;quot;seconds simulation time&amp;quot;. In this case the timer doesn't run when FlightGear is paused. For user interaction purposes (measuring key press time, displaying popups, etc.) one usually prefers real time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
# simulation time example&lt;br /&gt;
var copilot_annoyed = func { setprop(&amp;quot;/sim/messages/copilot&amp;quot;, &amp;quot;Stop it! Immediately!&amp;quot;) }&lt;br /&gt;
settimer(copilot_annoyed, 10);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
# real time example&lt;br /&gt;
var popdown = func ( tipArg ) { &lt;br /&gt;
    fgcommand(&amp;quot;dialog-close&amp;quot;, tipArg); &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var selfStatusPopupTip = func (label, delay = 10, override = nil) {	&lt;br /&gt;
    var tmpl = props.Node.new({&lt;br /&gt;
            name : &amp;quot;PopTipSelf&amp;quot;, modal : 0, layout : &amp;quot;hbox&amp;quot;,&lt;br /&gt;
            y: 140,&lt;br /&gt;
            text : { label : label, padding : 6 }&lt;br /&gt;
    });&lt;br /&gt;
    if (override != nil) tmpl.setValues(override);&lt;br /&gt;
&lt;br /&gt;
    popdown(tipArgSelf);&lt;br /&gt;
    fgcommand(&amp;quot;dialog-new&amp;quot;, tmpl);&lt;br /&gt;
    fgcommand(&amp;quot;dialog-show&amp;quot;, tipArgSelf);&lt;br /&gt;
&lt;br /&gt;
    currTimerSelf += 1;&lt;br /&gt;
    var thisTimerSelf = currTimerSelf;&lt;br /&gt;
&lt;br /&gt;
    # Final argument 1 is a flag to use &amp;quot;real&amp;quot; time, not simulated time&lt;br /&gt;
    settimer(func { if(currTimerSelf == thisTimerSelf) { popdown(tipArgSelf) } }, delay, 1);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Nasal scripting language#settimer loops|More information about using the settimer function to create loops.]]&lt;br /&gt;
&lt;br /&gt;
=== maketimer() ===&lt;br /&gt;
{{FG ver|2.12+}}&lt;br /&gt;
&lt;br /&gt;
Since FlightGear v2.12, there is a new API for making a timer that allows more control over what happens in a timer, as opposed to setting one and forgetting about it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var timer = maketimer(&amp;lt;interval&amp;gt;, &amp;lt;function&amp;gt;);&lt;br /&gt;
var timer = maketimer(&amp;lt;interval&amp;gt;, &amp;lt;self&amp;gt;, &amp;lt;function&amp;gt;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
timer.start();&lt;br /&gt;
timer.stop();&lt;br /&gt;
timer.restart(&amp;lt;interval&amp;gt;);&lt;br /&gt;
timer.singleShot [read/write]&lt;br /&gt;
timer.isRunning [read-only]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
# create timer with 1 second interval&lt;br /&gt;
var timer = maketimer(1, func(){ &lt;br /&gt;
    print('timer called'); &lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
# start the timer (with 1 second inverval)&lt;br /&gt;
timer.start();&lt;br /&gt;
&lt;br /&gt;
# restart timer with 4 second interval&lt;br /&gt;
timer.restart(4);&lt;br /&gt;
&lt;br /&gt;
# fire one single time in 6 seconds&lt;br /&gt;
timer.singleShot = 1;&lt;br /&gt;
timer.restart(6);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var Tooltip = {&lt;br /&gt;
    new: func(){&lt;br /&gt;
        var m = { parents: [Tooltip] };&lt;br /&gt;
&lt;br /&gt;
        m._hideTimer = maketimer(1.0, m, Tooltip._hideTimeout);&lt;br /&gt;
        m._hideTimer.singleShot = 1;&lt;br /&gt;
&lt;br /&gt;
        return m;&lt;br /&gt;
    },&lt;br /&gt;
&lt;br /&gt;
    run: func(){&lt;br /&gt;
        if(!me._hideTimer.isRunning) me._hideTimer.start();&lt;br /&gt;
    },&lt;br /&gt;
&lt;br /&gt;
    _hideTimeout: func(){&lt;br /&gt;
        print(&amp;quot;_hideTimeout&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var t = Tooltip.new();&lt;br /&gt;
t.run();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== history() (3.1+) ===&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 legth&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;
=== systime() ===&lt;br /&gt;
Returns epoch time (time since 1970/01/01 00:00) in seconds as a floating point number with high resolution. This is useful for benchmarking purposes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
#benchmarking example:&lt;br /&gt;
var start = systime();&lt;br /&gt;
how_fast_am_I(123);&lt;br /&gt;
var end = systime();&lt;br /&gt;
print(&amp;quot;took &amp;quot;, end - start, &amp;quot; seconds&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== parsexml() ===&lt;br /&gt;
&lt;br /&gt;
This function is an interface to the built-in [http://expat.sourceforge.net/ Expat XML parser]. It takes up to five arguments. The first is a mandatory absolute path to an XML file, the remaining four are optional callback functions, each of which can be nil (which is also the default value).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var ret = parsexml(&amp;lt;path&amp;gt; [, &amp;lt;start-elem&amp;gt; [, &amp;lt;end-elem&amp;gt; [, &amp;lt;data&amp;gt; [, &amp;lt;pi&amp;gt; ]]]]);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;start-elem&amp;gt;  ... called for every starting tag with two arguments: the tag name, and an attribute hash&lt;br /&gt;
&amp;lt;end-elem&amp;gt;    ... called for every ending tag with one argument: the tag name&lt;br /&gt;
&amp;lt;data&amp;gt;        ... called for every piece of data with one argument: the data string&lt;br /&gt;
&amp;lt;pi&amp;gt;          ... called for every &amp;quot;processing information&amp;quot; with two args: target and data string&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ret&amp;gt;         ... the return value is nil on error, and the &amp;lt;path&amp;gt; otherwise&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var start = func(name, attr) {&lt;br /&gt;
    print(&amp;quot;starting tag &amp;quot;, name);&lt;br /&gt;
    foreach (var a; keys(attr))&lt;br /&gt;
        print(&amp;quot;\twith attribute &amp;quot;, a, &amp;quot;=&amp;quot;, attr[a]);&lt;br /&gt;
}&lt;br /&gt;
var end = func(name) { print(&amp;quot;ending tag &amp;quot;, name) }&lt;br /&gt;
var data = func(data) { print(&amp;quot;data=&amp;quot;, data) }&lt;br /&gt;
var pi = func(target, data) { print(&amp;quot;processing instruction: target=&amp;quot;, target, &amp;quot; data=&amp;quot;, data) }&lt;br /&gt;
parsexml(&amp;quot;/tmp/foo.xml&amp;quot;, start, end, data, pi);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== resolvepath() ===&lt;br /&gt;
&lt;br /&gt;
SimGear features its own [[Resolving Paths|path resolving framework]] that takes a relative path and returns an absolute path, checking from base directories such as [[$FG_ROOT]], [[$FG_HOME]], [[$FG_AIRCRAFT]], and the current aircraft directory (&amp;lt;tt&amp;gt;/sim/aircraft-dir&amp;lt;/tt&amp;gt;). This function in Nasal takes a path string and returns the absolute path or an empty string if the path couldn't be resolved.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var guess_path = func(path...) {&lt;br /&gt;
    var path_concat = string.join(path, &amp;quot;/&amp;quot;);&lt;br /&gt;
    var file_path = resolvepath(path_concat);&lt;br /&gt;
    if (file_path == &amp;quot;&amp;quot;) die(&amp;quot;Path not found: &amp;quot;~path_concat);&lt;br /&gt;
    return file_path;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== HTTP module (2.99+) ===&lt;br /&gt;
&lt;br /&gt;
Get remote data using the HTTP.&lt;br /&gt;
&lt;br /&gt;
==== http.load() ====&lt;br /&gt;
&lt;br /&gt;
Load resource identified by its URL into memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var request = http.load(&amp;lt;url&amp;gt;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
http.load(&amp;quot;http://example.com/test.txt&amp;quot;)&lt;br /&gt;
    .done(func(r) print(&amp;quot;Got response: &amp;quot; ~ r.response));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== http.save() ====&lt;br /&gt;
&lt;br /&gt;
Save resource to a local file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var request = http.save(&amp;lt;url&amp;gt;, &amp;lt;file_path&amp;gt;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
http.save(&amp;quot;http://example.com/test.png&amp;quot;, getprop('/sim/fg-home') ~ '/cache/test.png')&lt;br /&gt;
    .fail(func print(&amp;quot;Download failed!&amp;quot;))&lt;br /&gt;
    .done(func(r) print(&amp;quot;Finished request with status: &amp;quot; ~ r.status ~ &amp;quot; &amp;quot; ~ r.reason))&lt;br /&gt;
    .always(func print(&amp;quot;Request complete (fail or success)&amp;quot;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== rand() ===&lt;br /&gt;
&lt;br /&gt;
Return a random number as generated by &amp;lt;tt&amp;gt;sg_random&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== srand() ===&lt;br /&gt;
&lt;br /&gt;
Seed the random number generator based upon the current time. Returns 0.&lt;br /&gt;
&lt;br /&gt;
=== md5() (3.1+) ===&lt;br /&gt;
&lt;br /&gt;
Get the md5 hash of a string.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var hash = md5(&amp;lt;str&amp;gt;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Appendix}}&lt;/div&gt;</summary>
		<author><name>Chris-barry</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_library_functions&amp;diff=92154</id>
		<title>Nasal library functions</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_library_functions&amp;diff=92154"/>
		<updated>2016-02-01T03:24:00Z</updated>

		<summary type="html">&lt;p&gt;Chris-barry: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Nasal Navigation}}&lt;br /&gt;
&lt;br /&gt;
Please first see: http://plausible.org/nasal/lib.html&lt;br /&gt;
&lt;br /&gt;
A better and more complete description of these functions can also be found at http://wiki.flightgear.org/Nasal_library&lt;br /&gt;
&lt;br /&gt;
== size() ==&lt;br /&gt;
'''Usage:'''&lt;br /&gt;
&lt;br /&gt;
 size(''object'');&lt;br /&gt;
&lt;br /&gt;
where ''object'' may be a ''string'', a ''vector'' or a ''hash''.&lt;br /&gt;
&lt;br /&gt;
'''Return value'''&lt;br /&gt;
&lt;br /&gt;
An intger equal to the number of characters in a ''string'' argument or the number of elements in a ''vector'' or ''hash''.&lt;br /&gt;
&lt;br /&gt;
If the argument is a non-string scalar then the error '''object has no size()''' will be generated.&lt;br /&gt;
&lt;br /&gt;
== keys() ==&lt;br /&gt;
&lt;br /&gt;
== append() ==&lt;br /&gt;
&lt;br /&gt;
== pop() ==&lt;br /&gt;
&lt;br /&gt;
== setsize() ==&lt;br /&gt;
'''Usage:'''&lt;br /&gt;
&lt;br /&gt;
 setsize(vect, new_size)&lt;br /&gt;
&lt;br /&gt;
where ''vect'' is an expression which evaluates to a vector and ''new_size'' is an expression that evaluates to a non-negative number.&lt;br /&gt;
&lt;br /&gt;
'''Action:'''&lt;br /&gt;
&lt;br /&gt;
Changes the number of elements in the vetor ''v'' to the value of s.&lt;br /&gt;
&lt;br /&gt;
'''Return value:'''&lt;br /&gt;
&lt;br /&gt;
The resized vector.&lt;br /&gt;
&lt;br /&gt;
'''Notes'''&lt;br /&gt;
&lt;br /&gt;
Elements that exist in both the original and the resized vector retain their values. When the vector is enlarged newly created elements are set to ''nil''. When the size is reduced the values of all elements beyond the new size are permanently lost.&lt;br /&gt;
&lt;br /&gt;
The ''new_size'' argument may be any non-negative number. Non-integer values are rounded down.&lt;br /&gt;
&lt;br /&gt;
The ''vect'' argument need not be a named variable. The expression:&lt;br /&gt;
&lt;br /&gt;
 var v1 = setsize([], n);&lt;br /&gt;
&lt;br /&gt;
Is a convenient way to allocate an empty vector of a specific size.&lt;br /&gt;
&lt;br /&gt;
== subvec() ==&lt;br /&gt;
&lt;br /&gt;
Create a new vector comprising elements from a contiguous range of elements of an existing vector.&lt;br /&gt;
&lt;br /&gt;
'''Usage:'''&lt;br /&gt;
&lt;br /&gt;
 subvec([''vect'', [''start'', [''count'']]])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&lt;br /&gt;
&amp;lt;dt&amp;gt;''vect''&amp;lt;/dt&amp;gt;&lt;br /&gt;
&amp;lt;dd&amp;gt;The original vector&amp;lt;/dd&amp;gt;&lt;br /&gt;
&amp;lt;dt&amp;gt;''start''&amp;lt;/dt&amp;gt;&lt;br /&gt;
&amp;lt;dd&amp;gt;The zero-based index in the original vector of the first element to be copied.&amp;lt;/dd&amp;gt;&lt;br /&gt;
&amp;lt;dt&amp;gt;''count''&amp;lt;/dt&amp;gt;&lt;br /&gt;
&amp;lt;dd&amp;gt;The number of elements to copy. If this argument is omitted then ''size(vect) - start'' is assumed.&amp;lt;/dd&amp;gt;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Return value'''&lt;br /&gt;
&lt;br /&gt;
A new vector containing the specified range from the original vector, or ''nil''.&lt;br /&gt;
&lt;br /&gt;
'''Notes:'''&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Omitting the ''vect'' and ''start'' arguments is not an error (possibly it should be) but the return value is ''nil''.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
A negative ''start'' argument ''is'' an error. This seems wrong. Perhaps the language designer could comment.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
A value of ''start'' greater than ''size(vect)'' causes an error. A value equal to ''size(vect)'' returns an empty vector.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
If the value of ''count'' is greater than ''size(vect) - start'' then it is ignored. That is, all elements from ''start'' to the end of ''vect'' are returned. If ''count'' is zero then an empty vector is returned. A negative value of ''count'' causes an error.&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = directory(FGRoot ~ filename);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;.&amp;quot; , &amp;quot;..&amp;quot; , &amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
With subvec():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = subvec(directory(FGRoot ~ filename),2);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = subvec(directory(FGRoot ~ filename),3);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
== delete() ==&lt;br /&gt;
Remove an element from a hash.&lt;br /&gt;
&lt;br /&gt;
'''Usage'''&lt;br /&gt;
&lt;br /&gt;
 delete(''hash'', ''key'')&lt;br /&gt;
&lt;br /&gt;
Remove the element with key ''key'' from the hash ''hash''. If the key is not present then the hash is unaltered.&lt;br /&gt;
&lt;br /&gt;
== int() ==&lt;br /&gt;
&lt;br /&gt;
== num(str) ==&lt;br /&gt;
Convert string to number.&lt;br /&gt;
Returns nil if str is nil, empty string, string with no number.&lt;br /&gt;
&lt;br /&gt;
== streq() ==&lt;br /&gt;
&lt;br /&gt;
== cmp() ==&lt;br /&gt;
&lt;br /&gt;
== substr() ==&lt;br /&gt;
&lt;br /&gt;
== chr() ==&lt;br /&gt;
&lt;br /&gt;
== contains() ==&lt;br /&gt;
&lt;br /&gt;
== typeof() ==&lt;br /&gt;
&lt;br /&gt;
== ghosttype(ghost) ==&lt;br /&gt;
Returns a string containing either a descriptive name as passed to ''naNewGhost'' or ''naNewGhost2'' in C/C++ while creating the ghost or a unique id (aka the pointer to the C/C++ naGhostType instance) if no name has been set.&lt;br /&gt;
&lt;br /&gt;
== compile() ==&lt;br /&gt;
&lt;br /&gt;
== call() ==&lt;br /&gt;
&lt;br /&gt;
== die() ==&lt;br /&gt;
&lt;br /&gt;
== sprintf() ==&lt;br /&gt;
&lt;br /&gt;
== caller() ==&lt;br /&gt;
&lt;br /&gt;
== closure() ==&lt;br /&gt;
&lt;br /&gt;
== find() ==&lt;br /&gt;
&lt;br /&gt;
== split() ==&lt;br /&gt;
&lt;br /&gt;
== rand() ==&lt;br /&gt;
&lt;br /&gt;
== bind() ==&lt;br /&gt;
&lt;br /&gt;
== sort() ==&lt;br /&gt;
&lt;br /&gt;
== id() ==&lt;br /&gt;
&lt;br /&gt;
= math =&lt;br /&gt;
== Trigonometric_functions ==&lt;br /&gt;
'''Caution''': All trigonometric functions works with [https://en.wikipedia.org/wiki/Radian Radian]-values - not with Degree!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;To convert this&amp;lt;/u&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
radians = degree * math.pi / 180&amp;lt;br&amp;gt;&lt;br /&gt;
degree  = radians * 180 / math.pi&lt;br /&gt;
=== sin() ===&lt;br /&gt;
=== cos() ===&lt;br /&gt;
=== tan() ===&lt;br /&gt;
=== asin() ===&lt;br /&gt;
=== acos() ===&lt;br /&gt;
=== atan2() ===&lt;br /&gt;
== exp() ==&lt;br /&gt;
== ln() ==&lt;br /&gt;
== pow() ==&lt;br /&gt;
== sqrt() ==&lt;br /&gt;
== floor() ==&lt;br /&gt;
Returns the value rounded downward&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
math.floor(1.2); # returns 1&lt;br /&gt;
math.floor(1.6); # returns 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ceil() ==&lt;br /&gt;
Returns the value rounded upward&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
math.ceil(1.2); # returns 2&lt;br /&gt;
math.ceil(1.6); # returns 2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== fmod() ==&lt;br /&gt;
A '''modulo'''-operator. The [https://en.wikipedia.org/wiki/Modulo_operation modulo]-operation finds the remainder of division of one number by another (sometimes called modulus).&lt;br /&gt;
&lt;br /&gt;
fmod(x , y) may be negative if x &amp;lt; 0, whereas mod() seems to guarantee that 0 ≤ mod(x,y) &amp;lt; y, according to tests made with x and y integers, y &amp;gt; 0, x positive or negative.&lt;br /&gt;
&lt;br /&gt;
== clamp() ==&lt;br /&gt;
== periodic() ==&lt;br /&gt;
== round() ==&lt;br /&gt;
== pi ==&lt;br /&gt;
== e ==&lt;br /&gt;
&lt;br /&gt;
= io =&lt;br /&gt;
&lt;br /&gt;
* SEEK_SET&lt;br /&gt;
* SEEK_CUR&lt;br /&gt;
* SEEK_END&lt;br /&gt;
* stdin&lt;br /&gt;
* stdout&lt;br /&gt;
* stderr&lt;br /&gt;
&lt;br /&gt;
== stat() ==&lt;br /&gt;
== directory() ==&lt;br /&gt;
returns the files in a given directory&lt;br /&gt;
&lt;br /&gt;
e.g. chatter_list = directory( chatter_dir );&lt;br /&gt;
&lt;br /&gt;
Example : &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = directory(FGRoot ~ filename);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns :   &lt;br /&gt;
'''&amp;quot;.&amp;quot; , &amp;quot;..&amp;quot; , &amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
To delete the &amp;quot;.&amp;quot; and &amp;quot;..&amp;quot; see the subvec() function.&lt;br /&gt;
&lt;br /&gt;
== open() ==&lt;br /&gt;
== read() ==&lt;br /&gt;
== readln() ==&lt;br /&gt;
== seek() ==&lt;br /&gt;
== tell() ==&lt;br /&gt;
== write() ==&lt;br /&gt;
== flush() ==&lt;br /&gt;
== close() ==&lt;br /&gt;
&lt;br /&gt;
= utf8 =&lt;br /&gt;
== chstr() ==&lt;br /&gt;
== strc() ==&lt;br /&gt;
== substr() ==&lt;br /&gt;
== size() ==&lt;br /&gt;
== validate() ==&lt;/div&gt;</summary>
		<author><name>Chris-barry</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_library_functions&amp;diff=92153</id>
		<title>Nasal library functions</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_library_functions&amp;diff=92153"/>
		<updated>2016-02-01T03:17:55Z</updated>

		<summary type="html">&lt;p&gt;Chris-barry: /* delete() */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Nasal Navigation}}&lt;br /&gt;
&lt;br /&gt;
Please first see: http://plausible.org/nasal/lib.html&lt;br /&gt;
&lt;br /&gt;
== size() ==&lt;br /&gt;
'''Usage:'''&lt;br /&gt;
&lt;br /&gt;
 size(''object'');&lt;br /&gt;
&lt;br /&gt;
where ''object'' may be a ''string'', a ''vector'' or a ''hash''.&lt;br /&gt;
&lt;br /&gt;
'''Return value'''&lt;br /&gt;
&lt;br /&gt;
An intger equal to the number of characters in a ''string'' argument or the number of elements in a ''vector'' or ''hash''.&lt;br /&gt;
&lt;br /&gt;
If the argument is a non-string scalar then the error '''object has no size()''' will be generated.&lt;br /&gt;
&lt;br /&gt;
== keys() ==&lt;br /&gt;
&lt;br /&gt;
== append() ==&lt;br /&gt;
&lt;br /&gt;
== pop() ==&lt;br /&gt;
&lt;br /&gt;
== setsize() ==&lt;br /&gt;
'''Usage:'''&lt;br /&gt;
&lt;br /&gt;
 setsize(vect, new_size)&lt;br /&gt;
&lt;br /&gt;
where ''vect'' is an expression which evaluates to a vector and ''new_size'' is an expression that evaluates to a non-negative number.&lt;br /&gt;
&lt;br /&gt;
'''Action:'''&lt;br /&gt;
&lt;br /&gt;
Changes the number of elements in the vetor ''v'' to the value of s.&lt;br /&gt;
&lt;br /&gt;
'''Return value:'''&lt;br /&gt;
&lt;br /&gt;
The resized vector.&lt;br /&gt;
&lt;br /&gt;
'''Notes'''&lt;br /&gt;
&lt;br /&gt;
Elements that exist in both the original and the resized vector retain their values. When the vector is enlarged newly created elements are set to ''nil''. When the size is reduced the values of all elements beyond the new size are permanently lost.&lt;br /&gt;
&lt;br /&gt;
The ''new_size'' argument may be any non-negative number. Non-integer values are rounded down.&lt;br /&gt;
&lt;br /&gt;
The ''vect'' argument need not be a named variable. The expression:&lt;br /&gt;
&lt;br /&gt;
 var v1 = setsize([], n);&lt;br /&gt;
&lt;br /&gt;
Is a convenient way to allocate an empty vector of a specific size.&lt;br /&gt;
&lt;br /&gt;
== subvec() ==&lt;br /&gt;
&lt;br /&gt;
Create a new vector comprising elements from a contiguous range of elements of an existing vector.&lt;br /&gt;
&lt;br /&gt;
'''Usage:'''&lt;br /&gt;
&lt;br /&gt;
 subvec([''vect'', [''start'', [''count'']]])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&lt;br /&gt;
&amp;lt;dt&amp;gt;''vect''&amp;lt;/dt&amp;gt;&lt;br /&gt;
&amp;lt;dd&amp;gt;The original vector&amp;lt;/dd&amp;gt;&lt;br /&gt;
&amp;lt;dt&amp;gt;''start''&amp;lt;/dt&amp;gt;&lt;br /&gt;
&amp;lt;dd&amp;gt;The zero-based index in the original vector of the first element to be copied.&amp;lt;/dd&amp;gt;&lt;br /&gt;
&amp;lt;dt&amp;gt;''count''&amp;lt;/dt&amp;gt;&lt;br /&gt;
&amp;lt;dd&amp;gt;The number of elements to copy. If this argument is omitted then ''size(vect) - start'' is assumed.&amp;lt;/dd&amp;gt;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Return value'''&lt;br /&gt;
&lt;br /&gt;
A new vector containing the specified range from the original vector, or ''nil''.&lt;br /&gt;
&lt;br /&gt;
'''Notes:'''&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Omitting the ''vect'' and ''start'' arguments is not an error (possibly it should be) but the return value is ''nil''.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
A negative ''start'' argument ''is'' an error. This seems wrong. Perhaps the language designer could comment.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
A value of ''start'' greater than ''size(vect)'' causes an error. A value equal to ''size(vect)'' returns an empty vector.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
If the value of ''count'' is greater than ''size(vect) - start'' then it is ignored. That is, all elements from ''start'' to the end of ''vect'' are returned. If ''count'' is zero then an empty vector is returned. A negative value of ''count'' causes an error.&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = directory(FGRoot ~ filename);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;.&amp;quot; , &amp;quot;..&amp;quot; , &amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
With subvec():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = subvec(directory(FGRoot ~ filename),2);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = subvec(directory(FGRoot ~ filename),3);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
== delete() ==&lt;br /&gt;
Remove an element from a hash.&lt;br /&gt;
&lt;br /&gt;
'''Usage'''&lt;br /&gt;
&lt;br /&gt;
 delete(''hash'', ''key'')&lt;br /&gt;
&lt;br /&gt;
Remove the element with key ''key'' from the hash ''hash''. If the key is not present then the hash is unaltered.&lt;br /&gt;
&lt;br /&gt;
== int() ==&lt;br /&gt;
&lt;br /&gt;
== num(str) ==&lt;br /&gt;
Convert string to number.&lt;br /&gt;
Returns nil if str is nil, empty string, string with no number.&lt;br /&gt;
&lt;br /&gt;
== streq() ==&lt;br /&gt;
&lt;br /&gt;
== cmp() ==&lt;br /&gt;
&lt;br /&gt;
== substr() ==&lt;br /&gt;
&lt;br /&gt;
== chr() ==&lt;br /&gt;
&lt;br /&gt;
== contains() ==&lt;br /&gt;
&lt;br /&gt;
== typeof() ==&lt;br /&gt;
&lt;br /&gt;
== ghosttype(ghost) ==&lt;br /&gt;
Returns a string containing either a descriptive name as passed to ''naNewGhost'' or ''naNewGhost2'' in C/C++ while creating the ghost or a unique id (aka the pointer to the C/C++ naGhostType instance) if no name has been set.&lt;br /&gt;
&lt;br /&gt;
== compile() ==&lt;br /&gt;
&lt;br /&gt;
== call() ==&lt;br /&gt;
&lt;br /&gt;
== die() ==&lt;br /&gt;
&lt;br /&gt;
== sprintf() ==&lt;br /&gt;
&lt;br /&gt;
== caller() ==&lt;br /&gt;
&lt;br /&gt;
== closure() ==&lt;br /&gt;
&lt;br /&gt;
== find() ==&lt;br /&gt;
&lt;br /&gt;
== split() ==&lt;br /&gt;
&lt;br /&gt;
== rand() ==&lt;br /&gt;
&lt;br /&gt;
== bind() ==&lt;br /&gt;
&lt;br /&gt;
== sort() ==&lt;br /&gt;
&lt;br /&gt;
== id() ==&lt;br /&gt;
&lt;br /&gt;
= math =&lt;br /&gt;
== Trigonometric_functions ==&lt;br /&gt;
'''Caution''': All trigonometric functions works with [https://en.wikipedia.org/wiki/Radian Radian]-values - not with Degree!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;To convert this&amp;lt;/u&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
radians = degree * math.pi / 180&amp;lt;br&amp;gt;&lt;br /&gt;
degree  = radians * 180 / math.pi&lt;br /&gt;
=== sin() ===&lt;br /&gt;
=== cos() ===&lt;br /&gt;
=== tan() ===&lt;br /&gt;
=== asin() ===&lt;br /&gt;
=== acos() ===&lt;br /&gt;
=== atan2() ===&lt;br /&gt;
== exp() ==&lt;br /&gt;
== ln() ==&lt;br /&gt;
== pow() ==&lt;br /&gt;
== sqrt() ==&lt;br /&gt;
== floor() ==&lt;br /&gt;
Returns the value rounded downward&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
math.floor(1.2); # returns 1&lt;br /&gt;
math.floor(1.6); # returns 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ceil() ==&lt;br /&gt;
Returns the value rounded upward&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
math.ceil(1.2); # returns 2&lt;br /&gt;
math.ceil(1.6); # returns 2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== fmod() ==&lt;br /&gt;
A '''modulo'''-operator. The [https://en.wikipedia.org/wiki/Modulo_operation modulo]-operation finds the remainder of division of one number by another (sometimes called modulus).&lt;br /&gt;
&lt;br /&gt;
fmod(x , y) may be negative if x &amp;lt; 0, whereas mod() seems to guarantee that 0 ≤ mod(x,y) &amp;lt; y, according to tests made with x and y integers, y &amp;gt; 0, x positive or negative.&lt;br /&gt;
&lt;br /&gt;
== clamp() ==&lt;br /&gt;
== periodic() ==&lt;br /&gt;
== round() ==&lt;br /&gt;
== pi ==&lt;br /&gt;
== e ==&lt;br /&gt;
&lt;br /&gt;
= io =&lt;br /&gt;
&lt;br /&gt;
* SEEK_SET&lt;br /&gt;
* SEEK_CUR&lt;br /&gt;
* SEEK_END&lt;br /&gt;
* stdin&lt;br /&gt;
* stdout&lt;br /&gt;
* stderr&lt;br /&gt;
&lt;br /&gt;
== stat() ==&lt;br /&gt;
== directory() ==&lt;br /&gt;
returns the files in a given directory&lt;br /&gt;
&lt;br /&gt;
e.g. chatter_list = directory( chatter_dir );&lt;br /&gt;
&lt;br /&gt;
Example : &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = directory(FGRoot ~ filename);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns :   &lt;br /&gt;
'''&amp;quot;.&amp;quot; , &amp;quot;..&amp;quot; , &amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
To delete the &amp;quot;.&amp;quot; and &amp;quot;..&amp;quot; see the subvec() function.&lt;br /&gt;
&lt;br /&gt;
== open() ==&lt;br /&gt;
== read() ==&lt;br /&gt;
== readln() ==&lt;br /&gt;
== seek() ==&lt;br /&gt;
== tell() ==&lt;br /&gt;
== write() ==&lt;br /&gt;
== flush() ==&lt;br /&gt;
== close() ==&lt;br /&gt;
&lt;br /&gt;
= utf8 =&lt;br /&gt;
== chstr() ==&lt;br /&gt;
== strc() ==&lt;br /&gt;
== substr() ==&lt;br /&gt;
== size() ==&lt;br /&gt;
== validate() ==&lt;/div&gt;</summary>
		<author><name>Chris-barry</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_library_functions&amp;diff=92152</id>
		<title>Nasal library functions</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_library_functions&amp;diff=92152"/>
		<updated>2016-02-01T02:50:47Z</updated>

		<summary type="html">&lt;p&gt;Chris-barry: /* subvec() */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Nasal Navigation}}&lt;br /&gt;
&lt;br /&gt;
Please first see: http://plausible.org/nasal/lib.html&lt;br /&gt;
&lt;br /&gt;
== size() ==&lt;br /&gt;
'''Usage:'''&lt;br /&gt;
&lt;br /&gt;
 size(''object'');&lt;br /&gt;
&lt;br /&gt;
where ''object'' may be a ''string'', a ''vector'' or a ''hash''.&lt;br /&gt;
&lt;br /&gt;
'''Return value'''&lt;br /&gt;
&lt;br /&gt;
An intger equal to the number of characters in a ''string'' argument or the number of elements in a ''vector'' or ''hash''.&lt;br /&gt;
&lt;br /&gt;
If the argument is a non-string scalar then the error '''object has no size()''' will be generated.&lt;br /&gt;
&lt;br /&gt;
== keys() ==&lt;br /&gt;
&lt;br /&gt;
== append() ==&lt;br /&gt;
&lt;br /&gt;
== pop() ==&lt;br /&gt;
&lt;br /&gt;
== setsize() ==&lt;br /&gt;
'''Usage:'''&lt;br /&gt;
&lt;br /&gt;
 setsize(vect, new_size)&lt;br /&gt;
&lt;br /&gt;
where ''vect'' is an expression which evaluates to a vector and ''new_size'' is an expression that evaluates to a non-negative number.&lt;br /&gt;
&lt;br /&gt;
'''Action:'''&lt;br /&gt;
&lt;br /&gt;
Changes the number of elements in the vetor ''v'' to the value of s.&lt;br /&gt;
&lt;br /&gt;
'''Return value:'''&lt;br /&gt;
&lt;br /&gt;
The resized vector.&lt;br /&gt;
&lt;br /&gt;
'''Notes'''&lt;br /&gt;
&lt;br /&gt;
Elements that exist in both the original and the resized vector retain their values. When the vector is enlarged newly created elements are set to ''nil''. When the size is reduced the values of all elements beyond the new size are permanently lost.&lt;br /&gt;
&lt;br /&gt;
The ''new_size'' argument may be any non-negative number. Non-integer values are rounded down.&lt;br /&gt;
&lt;br /&gt;
The ''vect'' argument need not be a named variable. The expression:&lt;br /&gt;
&lt;br /&gt;
 var v1 = setsize([], n);&lt;br /&gt;
&lt;br /&gt;
Is a convenient way to allocate an empty vector of a specific size.&lt;br /&gt;
&lt;br /&gt;
== subvec() ==&lt;br /&gt;
&lt;br /&gt;
Create a new vector comprising elements from a contiguous range of elements of an existing vector.&lt;br /&gt;
&lt;br /&gt;
'''Usage:'''&lt;br /&gt;
&lt;br /&gt;
 subvec([''vect'', [''start'', [''count'']]])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&lt;br /&gt;
&amp;lt;dt&amp;gt;''vect''&amp;lt;/dt&amp;gt;&lt;br /&gt;
&amp;lt;dd&amp;gt;The original vector&amp;lt;/dd&amp;gt;&lt;br /&gt;
&amp;lt;dt&amp;gt;''start''&amp;lt;/dt&amp;gt;&lt;br /&gt;
&amp;lt;dd&amp;gt;The zero-based index in the original vector of the first element to be copied.&amp;lt;/dd&amp;gt;&lt;br /&gt;
&amp;lt;dt&amp;gt;''count''&amp;lt;/dt&amp;gt;&lt;br /&gt;
&amp;lt;dd&amp;gt;The number of elements to copy. If this argument is omitted then ''size(vect) - start'' is assumed.&amp;lt;/dd&amp;gt;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Return value'''&lt;br /&gt;
&lt;br /&gt;
A new vector containing the specified range from the original vector, or ''nil''.&lt;br /&gt;
&lt;br /&gt;
'''Notes:'''&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Omitting the ''vect'' and ''start'' arguments is not an error (possibly it should be) but the return value is ''nil''.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
A negative ''start'' argument ''is'' an error. This seems wrong. Perhaps the language designer could comment.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
A value of ''start'' greater than ''size(vect)'' causes an error. A value equal to ''size(vect)'' returns an empty vector.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
If the value of ''count'' is greater than ''size(vect) - start'' then it is ignored. That is, all elements from ''start'' to the end of ''vect'' are returned. If ''count'' is zero then an empty vector is returned. A negative value of ''count'' causes an error.&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = directory(FGRoot ~ filename);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;.&amp;quot; , &amp;quot;..&amp;quot; , &amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
With subvec():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = subvec(directory(FGRoot ~ filename),2);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = subvec(directory(FGRoot ~ filename),3);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
== delete() ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== int() ==&lt;br /&gt;
&lt;br /&gt;
== num(str) ==&lt;br /&gt;
Convert string to number.&lt;br /&gt;
Returns nil if str is nil, empty string, string with no number.&lt;br /&gt;
&lt;br /&gt;
== streq() ==&lt;br /&gt;
&lt;br /&gt;
== cmp() ==&lt;br /&gt;
&lt;br /&gt;
== substr() ==&lt;br /&gt;
&lt;br /&gt;
== chr() ==&lt;br /&gt;
&lt;br /&gt;
== contains() ==&lt;br /&gt;
&lt;br /&gt;
== typeof() ==&lt;br /&gt;
&lt;br /&gt;
== ghosttype(ghost) ==&lt;br /&gt;
Returns a string containing either a descriptive name as passed to ''naNewGhost'' or ''naNewGhost2'' in C/C++ while creating the ghost or a unique id (aka the pointer to the C/C++ naGhostType instance) if no name has been set.&lt;br /&gt;
&lt;br /&gt;
== compile() ==&lt;br /&gt;
&lt;br /&gt;
== call() ==&lt;br /&gt;
&lt;br /&gt;
== die() ==&lt;br /&gt;
&lt;br /&gt;
== sprintf() ==&lt;br /&gt;
&lt;br /&gt;
== caller() ==&lt;br /&gt;
&lt;br /&gt;
== closure() ==&lt;br /&gt;
&lt;br /&gt;
== find() ==&lt;br /&gt;
&lt;br /&gt;
== split() ==&lt;br /&gt;
&lt;br /&gt;
== rand() ==&lt;br /&gt;
&lt;br /&gt;
== bind() ==&lt;br /&gt;
&lt;br /&gt;
== sort() ==&lt;br /&gt;
&lt;br /&gt;
== id() ==&lt;br /&gt;
&lt;br /&gt;
= math =&lt;br /&gt;
== Trigonometric_functions ==&lt;br /&gt;
'''Caution''': All trigonometric functions works with [https://en.wikipedia.org/wiki/Radian Radian]-values - not with Degree!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;To convert this&amp;lt;/u&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
radians = degree * math.pi / 180&amp;lt;br&amp;gt;&lt;br /&gt;
degree  = radians * 180 / math.pi&lt;br /&gt;
=== sin() ===&lt;br /&gt;
=== cos() ===&lt;br /&gt;
=== tan() ===&lt;br /&gt;
=== asin() ===&lt;br /&gt;
=== acos() ===&lt;br /&gt;
=== atan2() ===&lt;br /&gt;
== exp() ==&lt;br /&gt;
== ln() ==&lt;br /&gt;
== pow() ==&lt;br /&gt;
== sqrt() ==&lt;br /&gt;
== floor() ==&lt;br /&gt;
Returns the value rounded downward&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
math.floor(1.2); # returns 1&lt;br /&gt;
math.floor(1.6); # returns 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ceil() ==&lt;br /&gt;
Returns the value rounded upward&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
math.ceil(1.2); # returns 2&lt;br /&gt;
math.ceil(1.6); # returns 2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== fmod() ==&lt;br /&gt;
A '''modulo'''-operator. The [https://en.wikipedia.org/wiki/Modulo_operation modulo]-operation finds the remainder of division of one number by another (sometimes called modulus).&lt;br /&gt;
&lt;br /&gt;
fmod(x , y) may be negative if x &amp;lt; 0, whereas mod() seems to guarantee that 0 ≤ mod(x,y) &amp;lt; y, according to tests made with x and y integers, y &amp;gt; 0, x positive or negative.&lt;br /&gt;
&lt;br /&gt;
== clamp() ==&lt;br /&gt;
== periodic() ==&lt;br /&gt;
== round() ==&lt;br /&gt;
== pi ==&lt;br /&gt;
== e ==&lt;br /&gt;
&lt;br /&gt;
= io =&lt;br /&gt;
&lt;br /&gt;
* SEEK_SET&lt;br /&gt;
* SEEK_CUR&lt;br /&gt;
* SEEK_END&lt;br /&gt;
* stdin&lt;br /&gt;
* stdout&lt;br /&gt;
* stderr&lt;br /&gt;
&lt;br /&gt;
== stat() ==&lt;br /&gt;
== directory() ==&lt;br /&gt;
returns the files in a given directory&lt;br /&gt;
&lt;br /&gt;
e.g. chatter_list = directory( chatter_dir );&lt;br /&gt;
&lt;br /&gt;
Example : &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = directory(FGRoot ~ filename);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns :   &lt;br /&gt;
'''&amp;quot;.&amp;quot; , &amp;quot;..&amp;quot; , &amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
To delete the &amp;quot;.&amp;quot; and &amp;quot;..&amp;quot; see the subvec() function.&lt;br /&gt;
&lt;br /&gt;
== open() ==&lt;br /&gt;
== read() ==&lt;br /&gt;
== readln() ==&lt;br /&gt;
== seek() ==&lt;br /&gt;
== tell() ==&lt;br /&gt;
== write() ==&lt;br /&gt;
== flush() ==&lt;br /&gt;
== close() ==&lt;br /&gt;
&lt;br /&gt;
= utf8 =&lt;br /&gt;
== chstr() ==&lt;br /&gt;
== strc() ==&lt;br /&gt;
== substr() ==&lt;br /&gt;
== size() ==&lt;br /&gt;
== validate() ==&lt;/div&gt;</summary>
		<author><name>Chris-barry</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_library_functions&amp;diff=92151</id>
		<title>Nasal library functions</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_library_functions&amp;diff=92151"/>
		<updated>2016-02-01T02:49:03Z</updated>

		<summary type="html">&lt;p&gt;Chris-barry: /* subvec() */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Nasal Navigation}}&lt;br /&gt;
&lt;br /&gt;
Please first see: http://plausible.org/nasal/lib.html&lt;br /&gt;
&lt;br /&gt;
== size() ==&lt;br /&gt;
'''Usage:'''&lt;br /&gt;
&lt;br /&gt;
 size(''object'');&lt;br /&gt;
&lt;br /&gt;
where ''object'' may be a ''string'', a ''vector'' or a ''hash''.&lt;br /&gt;
&lt;br /&gt;
'''Return value'''&lt;br /&gt;
&lt;br /&gt;
An intger equal to the number of characters in a ''string'' argument or the number of elements in a ''vector'' or ''hash''.&lt;br /&gt;
&lt;br /&gt;
If the argument is a non-string scalar then the error '''object has no size()''' will be generated.&lt;br /&gt;
&lt;br /&gt;
== keys() ==&lt;br /&gt;
&lt;br /&gt;
== append() ==&lt;br /&gt;
&lt;br /&gt;
== pop() ==&lt;br /&gt;
&lt;br /&gt;
== setsize() ==&lt;br /&gt;
'''Usage:'''&lt;br /&gt;
&lt;br /&gt;
 setsize(vect, new_size)&lt;br /&gt;
&lt;br /&gt;
where ''vect'' is an expression which evaluates to a vector and ''new_size'' is an expression that evaluates to a non-negative number.&lt;br /&gt;
&lt;br /&gt;
'''Action:'''&lt;br /&gt;
&lt;br /&gt;
Changes the number of elements in the vetor ''v'' to the value of s.&lt;br /&gt;
&lt;br /&gt;
'''Return value:'''&lt;br /&gt;
&lt;br /&gt;
The resized vector.&lt;br /&gt;
&lt;br /&gt;
'''Notes'''&lt;br /&gt;
&lt;br /&gt;
Elements that exist in both the original and the resized vector retain their values. When the vector is enlarged newly created elements are set to ''nil''. When the size is reduced the values of all elements beyond the new size are permanently lost.&lt;br /&gt;
&lt;br /&gt;
The ''new_size'' argument may be any non-negative number. Non-integer values are rounded down.&lt;br /&gt;
&lt;br /&gt;
The ''vect'' argument need not be a named variable. The expression:&lt;br /&gt;
&lt;br /&gt;
 var v1 = setsize([], n);&lt;br /&gt;
&lt;br /&gt;
Is a convenient way to allocate an empty vector of a specific size.&lt;br /&gt;
&lt;br /&gt;
== subvec() ==&lt;br /&gt;
&lt;br /&gt;
Create a new vector comprising elements from a contiguous range of elements of an existing vector.&lt;br /&gt;
&lt;br /&gt;
'''Usage:'''&lt;br /&gt;
&lt;br /&gt;
 subvec([''vect'', [''start'', [''count'']]])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&lt;br /&gt;
&amp;lt;dt&amp;gt;''vect''&amp;lt;/dt&amp;gt;&lt;br /&gt;
&amp;lt;dd&amp;gt;The original vector&amp;lt;/dd&amp;gt;&lt;br /&gt;
&amp;lt;dt&amp;gt;''start''&amp;lt;/dt&amp;gt;&lt;br /&gt;
&amp;lt;dd&amp;gt;The zero-based index in the original vector of the first element to be copied.&amp;lt;/dd&amp;gt;&lt;br /&gt;
&amp;lt;dt&amp;gt;''count''&amp;lt;/dt&amp;gt;&lt;br /&gt;
&amp;lt;dd&amp;gt;The number of elements to copy. If this argument is omitted then ''size(vect) - start'' is assumed.&amp;lt;/dd&amp;gt;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Return value'''&lt;br /&gt;
&lt;br /&gt;
A new vector containing the specified range from the original vector, or ''nil''.&lt;br /&gt;
&lt;br /&gt;
'''Notes:'''&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Omitting the ''vect'' and ''start'' arguments is not an error (possibly it should be) but the return value is ''nil''.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
A negative ''start'' argument ''is'' an error. This seems wrong. Perhaps the language designer could comment.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
A value of ''start'' greater than ''size(vect)'' causes an error. A value equal to ''size(vect)'' returns an empty vector.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
If the value of ''count'' is greater than ''size(vect) - start'' then it is ignored. That is, all elements from ''start'' to the end of ''vect'' are returned. A negative value of ''count'' causes an error.&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = directory(FGRoot ~ filename);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;.&amp;quot; , &amp;quot;..&amp;quot; , &amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
With subvec():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = subvec(directory(FGRoot ~ filename),2);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = subvec(directory(FGRoot ~ filename),3);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
== delete() ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== int() ==&lt;br /&gt;
&lt;br /&gt;
== num(str) ==&lt;br /&gt;
Convert string to number.&lt;br /&gt;
Returns nil if str is nil, empty string, string with no number.&lt;br /&gt;
&lt;br /&gt;
== streq() ==&lt;br /&gt;
&lt;br /&gt;
== cmp() ==&lt;br /&gt;
&lt;br /&gt;
== substr() ==&lt;br /&gt;
&lt;br /&gt;
== chr() ==&lt;br /&gt;
&lt;br /&gt;
== contains() ==&lt;br /&gt;
&lt;br /&gt;
== typeof() ==&lt;br /&gt;
&lt;br /&gt;
== ghosttype(ghost) ==&lt;br /&gt;
Returns a string containing either a descriptive name as passed to ''naNewGhost'' or ''naNewGhost2'' in C/C++ while creating the ghost or a unique id (aka the pointer to the C/C++ naGhostType instance) if no name has been set.&lt;br /&gt;
&lt;br /&gt;
== compile() ==&lt;br /&gt;
&lt;br /&gt;
== call() ==&lt;br /&gt;
&lt;br /&gt;
== die() ==&lt;br /&gt;
&lt;br /&gt;
== sprintf() ==&lt;br /&gt;
&lt;br /&gt;
== caller() ==&lt;br /&gt;
&lt;br /&gt;
== closure() ==&lt;br /&gt;
&lt;br /&gt;
== find() ==&lt;br /&gt;
&lt;br /&gt;
== split() ==&lt;br /&gt;
&lt;br /&gt;
== rand() ==&lt;br /&gt;
&lt;br /&gt;
== bind() ==&lt;br /&gt;
&lt;br /&gt;
== sort() ==&lt;br /&gt;
&lt;br /&gt;
== id() ==&lt;br /&gt;
&lt;br /&gt;
= math =&lt;br /&gt;
== Trigonometric_functions ==&lt;br /&gt;
'''Caution''': All trigonometric functions works with [https://en.wikipedia.org/wiki/Radian Radian]-values - not with Degree!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;To convert this&amp;lt;/u&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
radians = degree * math.pi / 180&amp;lt;br&amp;gt;&lt;br /&gt;
degree  = radians * 180 / math.pi&lt;br /&gt;
=== sin() ===&lt;br /&gt;
=== cos() ===&lt;br /&gt;
=== tan() ===&lt;br /&gt;
=== asin() ===&lt;br /&gt;
=== acos() ===&lt;br /&gt;
=== atan2() ===&lt;br /&gt;
== exp() ==&lt;br /&gt;
== ln() ==&lt;br /&gt;
== pow() ==&lt;br /&gt;
== sqrt() ==&lt;br /&gt;
== floor() ==&lt;br /&gt;
Returns the value rounded downward&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
math.floor(1.2); # returns 1&lt;br /&gt;
math.floor(1.6); # returns 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ceil() ==&lt;br /&gt;
Returns the value rounded upward&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
math.ceil(1.2); # returns 2&lt;br /&gt;
math.ceil(1.6); # returns 2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== fmod() ==&lt;br /&gt;
A '''modulo'''-operator. The [https://en.wikipedia.org/wiki/Modulo_operation modulo]-operation finds the remainder of division of one number by another (sometimes called modulus).&lt;br /&gt;
&lt;br /&gt;
fmod(x , y) may be negative if x &amp;lt; 0, whereas mod() seems to guarantee that 0 ≤ mod(x,y) &amp;lt; y, according to tests made with x and y integers, y &amp;gt; 0, x positive or negative.&lt;br /&gt;
&lt;br /&gt;
== clamp() ==&lt;br /&gt;
== periodic() ==&lt;br /&gt;
== round() ==&lt;br /&gt;
== pi ==&lt;br /&gt;
== e ==&lt;br /&gt;
&lt;br /&gt;
= io =&lt;br /&gt;
&lt;br /&gt;
* SEEK_SET&lt;br /&gt;
* SEEK_CUR&lt;br /&gt;
* SEEK_END&lt;br /&gt;
* stdin&lt;br /&gt;
* stdout&lt;br /&gt;
* stderr&lt;br /&gt;
&lt;br /&gt;
== stat() ==&lt;br /&gt;
== directory() ==&lt;br /&gt;
returns the files in a given directory&lt;br /&gt;
&lt;br /&gt;
e.g. chatter_list = directory( chatter_dir );&lt;br /&gt;
&lt;br /&gt;
Example : &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = directory(FGRoot ~ filename);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns :   &lt;br /&gt;
'''&amp;quot;.&amp;quot; , &amp;quot;..&amp;quot; , &amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
To delete the &amp;quot;.&amp;quot; and &amp;quot;..&amp;quot; see the subvec() function.&lt;br /&gt;
&lt;br /&gt;
== open() ==&lt;br /&gt;
== read() ==&lt;br /&gt;
== readln() ==&lt;br /&gt;
== seek() ==&lt;br /&gt;
== tell() ==&lt;br /&gt;
== write() ==&lt;br /&gt;
== flush() ==&lt;br /&gt;
== close() ==&lt;br /&gt;
&lt;br /&gt;
= utf8 =&lt;br /&gt;
== chstr() ==&lt;br /&gt;
== strc() ==&lt;br /&gt;
== substr() ==&lt;br /&gt;
== size() ==&lt;br /&gt;
== validate() ==&lt;/div&gt;</summary>
		<author><name>Chris-barry</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_library_functions&amp;diff=92150</id>
		<title>Nasal library functions</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_library_functions&amp;diff=92150"/>
		<updated>2016-02-01T02:48:04Z</updated>

		<summary type="html">&lt;p&gt;Chris-barry: /* subvec() */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Nasal Navigation}}&lt;br /&gt;
&lt;br /&gt;
Please first see: http://plausible.org/nasal/lib.html&lt;br /&gt;
&lt;br /&gt;
== size() ==&lt;br /&gt;
'''Usage:'''&lt;br /&gt;
&lt;br /&gt;
 size(''object'');&lt;br /&gt;
&lt;br /&gt;
where ''object'' may be a ''string'', a ''vector'' or a ''hash''.&lt;br /&gt;
&lt;br /&gt;
'''Return value'''&lt;br /&gt;
&lt;br /&gt;
An intger equal to the number of characters in a ''string'' argument or the number of elements in a ''vector'' or ''hash''.&lt;br /&gt;
&lt;br /&gt;
If the argument is a non-string scalar then the error '''object has no size()''' will be generated.&lt;br /&gt;
&lt;br /&gt;
== keys() ==&lt;br /&gt;
&lt;br /&gt;
== append() ==&lt;br /&gt;
&lt;br /&gt;
== pop() ==&lt;br /&gt;
&lt;br /&gt;
== setsize() ==&lt;br /&gt;
'''Usage:'''&lt;br /&gt;
&lt;br /&gt;
 setsize(vect, new_size)&lt;br /&gt;
&lt;br /&gt;
where ''vect'' is an expression which evaluates to a vector and ''new_size'' is an expression that evaluates to a non-negative number.&lt;br /&gt;
&lt;br /&gt;
'''Action:'''&lt;br /&gt;
&lt;br /&gt;
Changes the number of elements in the vetor ''v'' to the value of s.&lt;br /&gt;
&lt;br /&gt;
'''Return value:'''&lt;br /&gt;
&lt;br /&gt;
The resized vector.&lt;br /&gt;
&lt;br /&gt;
'''Notes'''&lt;br /&gt;
&lt;br /&gt;
Elements that exist in both the original and the resized vector retain their values. When the vector is enlarged newly created elements are set to ''nil''. When the size is reduced the values of all elements beyond the new size are permanently lost.&lt;br /&gt;
&lt;br /&gt;
The ''new_size'' argument may be any non-negative number. Non-integer values are rounded down.&lt;br /&gt;
&lt;br /&gt;
The ''vect'' argument need not be a named variable. The expression:&lt;br /&gt;
&lt;br /&gt;
 var v1 = setsize([], n);&lt;br /&gt;
&lt;br /&gt;
Is a convenient way to allocate an empty vector of a specific size.&lt;br /&gt;
&lt;br /&gt;
== subvec() ==&lt;br /&gt;
&lt;br /&gt;
Create a new vector comprising elements from a contiguous range of elements of an existing vector.&lt;br /&gt;
&lt;br /&gt;
'''Usage:'''&lt;br /&gt;
&lt;br /&gt;
 subvec([''vect'', [''start'', [''count'']]])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&lt;br /&gt;
&amp;lt;dt&amp;gt;''vect''&amp;lt;/dt&amp;gt;&lt;br /&gt;
&amp;lt;dd&amp;gt;The original vector&amp;lt;/dd&amp;gt;&lt;br /&gt;
&amp;lt;dt&amp;gt;''start''&amp;lt;/dt&amp;gt;&lt;br /&gt;
&amp;lt;dd&amp;gt;The zero-based index in the original vector of the first element to be copied.&amp;lt;/dd&amp;gt;&lt;br /&gt;
&amp;lt;dt&amp;gt;''count''&amp;lt;/dt&amp;gt;&lt;br /&gt;
&amp;lt;dd&amp;gt;The number of elements to copy. If this argument is omitted then ''size(vect) - start'' is assumed.&amp;lt;/dd&amp;gt;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Return value'''&lt;br /&gt;
&lt;br /&gt;
A new vector containing the specified range from the original vector, or ''nil''.&lt;br /&gt;
&lt;br /&gt;
'''Notes:'''&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Omitting the ''vect'' and ''start'' arguments is not an error (possibly it should be) but the return value is ''nil''.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
A negative ''start'' argument '''is'' an error. This seems wrong. Perhaps the language designer could comment.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
A value of ''start'' greater than ''size(vect)'' causes an error. A value equal to ''size(vect)'' returns an empty vector.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
If the value of ''count'' is greater than ''size(vect) - start'' then it is ignored. That is, all elements from ''start'' to the end of ''vect'' are returned. A negative value of ''count'' causes an error.&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = directory(FGRoot ~ filename);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;.&amp;quot; , &amp;quot;..&amp;quot; , &amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
With subvec():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = subvec(directory(FGRoot ~ filename),2);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = subvec(directory(FGRoot ~ filename),3);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
== delete() ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== int() ==&lt;br /&gt;
&lt;br /&gt;
== num(str) ==&lt;br /&gt;
Convert string to number.&lt;br /&gt;
Returns nil if str is nil, empty string, string with no number.&lt;br /&gt;
&lt;br /&gt;
== streq() ==&lt;br /&gt;
&lt;br /&gt;
== cmp() ==&lt;br /&gt;
&lt;br /&gt;
== substr() ==&lt;br /&gt;
&lt;br /&gt;
== chr() ==&lt;br /&gt;
&lt;br /&gt;
== contains() ==&lt;br /&gt;
&lt;br /&gt;
== typeof() ==&lt;br /&gt;
&lt;br /&gt;
== ghosttype(ghost) ==&lt;br /&gt;
Returns a string containing either a descriptive name as passed to ''naNewGhost'' or ''naNewGhost2'' in C/C++ while creating the ghost or a unique id (aka the pointer to the C/C++ naGhostType instance) if no name has been set.&lt;br /&gt;
&lt;br /&gt;
== compile() ==&lt;br /&gt;
&lt;br /&gt;
== call() ==&lt;br /&gt;
&lt;br /&gt;
== die() ==&lt;br /&gt;
&lt;br /&gt;
== sprintf() ==&lt;br /&gt;
&lt;br /&gt;
== caller() ==&lt;br /&gt;
&lt;br /&gt;
== closure() ==&lt;br /&gt;
&lt;br /&gt;
== find() ==&lt;br /&gt;
&lt;br /&gt;
== split() ==&lt;br /&gt;
&lt;br /&gt;
== rand() ==&lt;br /&gt;
&lt;br /&gt;
== bind() ==&lt;br /&gt;
&lt;br /&gt;
== sort() ==&lt;br /&gt;
&lt;br /&gt;
== id() ==&lt;br /&gt;
&lt;br /&gt;
= math =&lt;br /&gt;
== Trigonometric_functions ==&lt;br /&gt;
'''Caution''': All trigonometric functions works with [https://en.wikipedia.org/wiki/Radian Radian]-values - not with Degree!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;To convert this&amp;lt;/u&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
radians = degree * math.pi / 180&amp;lt;br&amp;gt;&lt;br /&gt;
degree  = radians * 180 / math.pi&lt;br /&gt;
=== sin() ===&lt;br /&gt;
=== cos() ===&lt;br /&gt;
=== tan() ===&lt;br /&gt;
=== asin() ===&lt;br /&gt;
=== acos() ===&lt;br /&gt;
=== atan2() ===&lt;br /&gt;
== exp() ==&lt;br /&gt;
== ln() ==&lt;br /&gt;
== pow() ==&lt;br /&gt;
== sqrt() ==&lt;br /&gt;
== floor() ==&lt;br /&gt;
Returns the value rounded downward&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
math.floor(1.2); # returns 1&lt;br /&gt;
math.floor(1.6); # returns 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ceil() ==&lt;br /&gt;
Returns the value rounded upward&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
math.ceil(1.2); # returns 2&lt;br /&gt;
math.ceil(1.6); # returns 2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== fmod() ==&lt;br /&gt;
A '''modulo'''-operator. The [https://en.wikipedia.org/wiki/Modulo_operation modulo]-operation finds the remainder of division of one number by another (sometimes called modulus).&lt;br /&gt;
&lt;br /&gt;
fmod(x , y) may be negative if x &amp;lt; 0, whereas mod() seems to guarantee that 0 ≤ mod(x,y) &amp;lt; y, according to tests made with x and y integers, y &amp;gt; 0, x positive or negative.&lt;br /&gt;
&lt;br /&gt;
== clamp() ==&lt;br /&gt;
== periodic() ==&lt;br /&gt;
== round() ==&lt;br /&gt;
== pi ==&lt;br /&gt;
== e ==&lt;br /&gt;
&lt;br /&gt;
= io =&lt;br /&gt;
&lt;br /&gt;
* SEEK_SET&lt;br /&gt;
* SEEK_CUR&lt;br /&gt;
* SEEK_END&lt;br /&gt;
* stdin&lt;br /&gt;
* stdout&lt;br /&gt;
* stderr&lt;br /&gt;
&lt;br /&gt;
== stat() ==&lt;br /&gt;
== directory() ==&lt;br /&gt;
returns the files in a given directory&lt;br /&gt;
&lt;br /&gt;
e.g. chatter_list = directory( chatter_dir );&lt;br /&gt;
&lt;br /&gt;
Example : &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = directory(FGRoot ~ filename);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns :   &lt;br /&gt;
'''&amp;quot;.&amp;quot; , &amp;quot;..&amp;quot; , &amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
To delete the &amp;quot;.&amp;quot; and &amp;quot;..&amp;quot; see the subvec() function.&lt;br /&gt;
&lt;br /&gt;
== open() ==&lt;br /&gt;
== read() ==&lt;br /&gt;
== readln() ==&lt;br /&gt;
== seek() ==&lt;br /&gt;
== tell() ==&lt;br /&gt;
== write() ==&lt;br /&gt;
== flush() ==&lt;br /&gt;
== close() ==&lt;br /&gt;
&lt;br /&gt;
= utf8 =&lt;br /&gt;
== chstr() ==&lt;br /&gt;
== strc() ==&lt;br /&gt;
== substr() ==&lt;br /&gt;
== size() ==&lt;br /&gt;
== validate() ==&lt;/div&gt;</summary>
		<author><name>Chris-barry</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_library_functions&amp;diff=92149</id>
		<title>Nasal library functions</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_library_functions&amp;diff=92149"/>
		<updated>2016-02-01T02:47:13Z</updated>

		<summary type="html">&lt;p&gt;Chris-barry: /* subvec() */ The previous description began with a statement that was incorrect and then gave no further description. The examples are trivial but that probably does not justify removing them.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Nasal Navigation}}&lt;br /&gt;
&lt;br /&gt;
Please first see: http://plausible.org/nasal/lib.html&lt;br /&gt;
&lt;br /&gt;
== size() ==&lt;br /&gt;
'''Usage:'''&lt;br /&gt;
&lt;br /&gt;
 size(''object'');&lt;br /&gt;
&lt;br /&gt;
where ''object'' may be a ''string'', a ''vector'' or a ''hash''.&lt;br /&gt;
&lt;br /&gt;
'''Return value'''&lt;br /&gt;
&lt;br /&gt;
An intger equal to the number of characters in a ''string'' argument or the number of elements in a ''vector'' or ''hash''.&lt;br /&gt;
&lt;br /&gt;
If the argument is a non-string scalar then the error '''object has no size()''' will be generated.&lt;br /&gt;
&lt;br /&gt;
== keys() ==&lt;br /&gt;
&lt;br /&gt;
== append() ==&lt;br /&gt;
&lt;br /&gt;
== pop() ==&lt;br /&gt;
&lt;br /&gt;
== setsize() ==&lt;br /&gt;
'''Usage:'''&lt;br /&gt;
&lt;br /&gt;
 setsize(vect, new_size)&lt;br /&gt;
&lt;br /&gt;
where ''vect'' is an expression which evaluates to a vector and ''new_size'' is an expression that evaluates to a non-negative number.&lt;br /&gt;
&lt;br /&gt;
'''Action:'''&lt;br /&gt;
&lt;br /&gt;
Changes the number of elements in the vetor ''v'' to the value of s.&lt;br /&gt;
&lt;br /&gt;
'''Return value:'''&lt;br /&gt;
&lt;br /&gt;
The resized vector.&lt;br /&gt;
&lt;br /&gt;
'''Notes'''&lt;br /&gt;
&lt;br /&gt;
Elements that exist in both the original and the resized vector retain their values. When the vector is enlarged newly created elements are set to ''nil''. When the size is reduced the values of all elements beyond the new size are permanently lost.&lt;br /&gt;
&lt;br /&gt;
The ''new_size'' argument may be any non-negative number. Non-integer values are rounded down.&lt;br /&gt;
&lt;br /&gt;
The ''vect'' argument need not be a named variable. The expression:&lt;br /&gt;
&lt;br /&gt;
 var v1 = setsize([], n);&lt;br /&gt;
&lt;br /&gt;
Is a convenient way to allocate an empty vector of a specific size.&lt;br /&gt;
&lt;br /&gt;
== subvec() ==&lt;br /&gt;
&lt;br /&gt;
Create a new vector comprising elements from a contiguous range of elements of an existing vector.&lt;br /&gt;
'''Usage:'''&lt;br /&gt;
&lt;br /&gt;
 subvec([''vect'', [''start'', [''count'']]])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&lt;br /&gt;
&amp;lt;dt&amp;gt;''vect''&amp;lt;/dt&amp;gt;&lt;br /&gt;
&amp;lt;dd&amp;gt;The original vector&amp;lt;/dd&amp;gt;&lt;br /&gt;
&amp;lt;dt&amp;gt;''start''&amp;lt;/dt&amp;gt;&lt;br /&gt;
&amp;lt;dd&amp;gt;The zero-based index in the original vector of the first element to be copied.&amp;lt;/dd&amp;gt;&lt;br /&gt;
&amp;lt;dt&amp;gt;''count''&amp;lt;/dt&amp;gt;&lt;br /&gt;
&amp;lt;dd&amp;gt;The number of elements to copy. If this argument is omitted then ''size(vect) - start'' is assumed.&amp;lt;/dd&amp;gt;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Return value'''&lt;br /&gt;
&lt;br /&gt;
A new vector containing the specified range from the original vector, or ''nil''.&lt;br /&gt;
&lt;br /&gt;
'''Notes:'''&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Omitting the ''vect'' and ''start'' arguments is not an error (possibly it should be) but the return value is ''nil''.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
A negative ''start'' argument '''is'' an error. This seems wrong. Perhaps the language designer could comment.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
A value of ''start'' greater than ''size(vect)'' causes an error. A value equal to ''size(vect)'' returns an empty vector.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
If the value of ''count'' is greater than ''size(vect) - start'' then it is ignored. That is, all elements from ''start'' to the end of ''vect'' are returned. A negative value of ''count'' causes an error.&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = directory(FGRoot ~ filename);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;.&amp;quot; , &amp;quot;..&amp;quot; , &amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
With subvec():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = subvec(directory(FGRoot ~ filename),2);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = subvec(directory(FGRoot ~ filename),3);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
== delete() ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== int() ==&lt;br /&gt;
&lt;br /&gt;
== num(str) ==&lt;br /&gt;
Convert string to number.&lt;br /&gt;
Returns nil if str is nil, empty string, string with no number.&lt;br /&gt;
&lt;br /&gt;
== streq() ==&lt;br /&gt;
&lt;br /&gt;
== cmp() ==&lt;br /&gt;
&lt;br /&gt;
== substr() ==&lt;br /&gt;
&lt;br /&gt;
== chr() ==&lt;br /&gt;
&lt;br /&gt;
== contains() ==&lt;br /&gt;
&lt;br /&gt;
== typeof() ==&lt;br /&gt;
&lt;br /&gt;
== ghosttype(ghost) ==&lt;br /&gt;
Returns a string containing either a descriptive name as passed to ''naNewGhost'' or ''naNewGhost2'' in C/C++ while creating the ghost or a unique id (aka the pointer to the C/C++ naGhostType instance) if no name has been set.&lt;br /&gt;
&lt;br /&gt;
== compile() ==&lt;br /&gt;
&lt;br /&gt;
== call() ==&lt;br /&gt;
&lt;br /&gt;
== die() ==&lt;br /&gt;
&lt;br /&gt;
== sprintf() ==&lt;br /&gt;
&lt;br /&gt;
== caller() ==&lt;br /&gt;
&lt;br /&gt;
== closure() ==&lt;br /&gt;
&lt;br /&gt;
== find() ==&lt;br /&gt;
&lt;br /&gt;
== split() ==&lt;br /&gt;
&lt;br /&gt;
== rand() ==&lt;br /&gt;
&lt;br /&gt;
== bind() ==&lt;br /&gt;
&lt;br /&gt;
== sort() ==&lt;br /&gt;
&lt;br /&gt;
== id() ==&lt;br /&gt;
&lt;br /&gt;
= math =&lt;br /&gt;
== Trigonometric_functions ==&lt;br /&gt;
'''Caution''': All trigonometric functions works with [https://en.wikipedia.org/wiki/Radian Radian]-values - not with Degree!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;To convert this&amp;lt;/u&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
radians = degree * math.pi / 180&amp;lt;br&amp;gt;&lt;br /&gt;
degree  = radians * 180 / math.pi&lt;br /&gt;
=== sin() ===&lt;br /&gt;
=== cos() ===&lt;br /&gt;
=== tan() ===&lt;br /&gt;
=== asin() ===&lt;br /&gt;
=== acos() ===&lt;br /&gt;
=== atan2() ===&lt;br /&gt;
== exp() ==&lt;br /&gt;
== ln() ==&lt;br /&gt;
== pow() ==&lt;br /&gt;
== sqrt() ==&lt;br /&gt;
== floor() ==&lt;br /&gt;
Returns the value rounded downward&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
math.floor(1.2); # returns 1&lt;br /&gt;
math.floor(1.6); # returns 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ceil() ==&lt;br /&gt;
Returns the value rounded upward&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
math.ceil(1.2); # returns 2&lt;br /&gt;
math.ceil(1.6); # returns 2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== fmod() ==&lt;br /&gt;
A '''modulo'''-operator. The [https://en.wikipedia.org/wiki/Modulo_operation modulo]-operation finds the remainder of division of one number by another (sometimes called modulus).&lt;br /&gt;
&lt;br /&gt;
fmod(x , y) may be negative if x &amp;lt; 0, whereas mod() seems to guarantee that 0 ≤ mod(x,y) &amp;lt; y, according to tests made with x and y integers, y &amp;gt; 0, x positive or negative.&lt;br /&gt;
&lt;br /&gt;
== clamp() ==&lt;br /&gt;
== periodic() ==&lt;br /&gt;
== round() ==&lt;br /&gt;
== pi ==&lt;br /&gt;
== e ==&lt;br /&gt;
&lt;br /&gt;
= io =&lt;br /&gt;
&lt;br /&gt;
* SEEK_SET&lt;br /&gt;
* SEEK_CUR&lt;br /&gt;
* SEEK_END&lt;br /&gt;
* stdin&lt;br /&gt;
* stdout&lt;br /&gt;
* stderr&lt;br /&gt;
&lt;br /&gt;
== stat() ==&lt;br /&gt;
== directory() ==&lt;br /&gt;
returns the files in a given directory&lt;br /&gt;
&lt;br /&gt;
e.g. chatter_list = directory( chatter_dir );&lt;br /&gt;
&lt;br /&gt;
Example : &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = directory(FGRoot ~ filename);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns :   &lt;br /&gt;
'''&amp;quot;.&amp;quot; , &amp;quot;..&amp;quot; , &amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
To delete the &amp;quot;.&amp;quot; and &amp;quot;..&amp;quot; see the subvec() function.&lt;br /&gt;
&lt;br /&gt;
== open() ==&lt;br /&gt;
== read() ==&lt;br /&gt;
== readln() ==&lt;br /&gt;
== seek() ==&lt;br /&gt;
== tell() ==&lt;br /&gt;
== write() ==&lt;br /&gt;
== flush() ==&lt;br /&gt;
== close() ==&lt;br /&gt;
&lt;br /&gt;
= utf8 =&lt;br /&gt;
== chstr() ==&lt;br /&gt;
== strc() ==&lt;br /&gt;
== substr() ==&lt;br /&gt;
== size() ==&lt;br /&gt;
== validate() ==&lt;/div&gt;</summary>
		<author><name>Chris-barry</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Howto:Set_up_a_multiplayer_server&amp;diff=92138</id>
		<title>Howto:Set up a multiplayer server</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Howto:Set_up_a_multiplayer_server&amp;diff=92138"/>
		<updated>2016-01-31T20:33:51Z</updated>

		<summary type="html">&lt;p&gt;Chris-barry: One would not refer to a beautiful view about a sunset, or an unobstructed view about the sewage farm. The same applies to &amp;quot;overview&amp;quot;.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page is dedicated to providing a short overview of installing the [[FlightGear Multiplayer Server]] ('fgms'). The reader is assumed to be reasonably familiar with working in a Unix/Linux shell environment.&lt;br /&gt;
&lt;br /&gt;
== Pre-Requisites ==&lt;br /&gt;
* A computer running a variant of *nix to compile and host the server. Speed of the machine isn't of great consequence as the protocol is a multiplexer which doesn't require much processing grunt.&lt;br /&gt;
** For specific documentation for setting up on FreeBSD see [[Howto:Set up a multiplayer server on FreeBSD]].&lt;br /&gt;
* direct/physical or remote access to the server (i.e. SSH/telnet, a conventional web hosting package will usually '''not''' be sufficient!)-suitable hosting packages are: dedicated root servers, virtual private servers, shell servers - for a collection of '''free''' shell account providers that may be suitable for fgms, see [[Free Shell Providers]] (you may want to check this out if you are interested in running fgms but don't have hosting yet)&lt;br /&gt;
* if the server is meant to be a public internet server: an internet connection, featuring sufficient upstream/downstream capabilities (see below for details concerning bandwidth requirements). &lt;br /&gt;
* firewall policies will need to be set up to allow for incoming and outgoing UDP traffic for the corresponding ports, the same applies to the administration port (TCP)&lt;br /&gt;
* permission to run unattended background processes (this may only be an issue with certain limited hosting packages)&lt;br /&gt;
* a working GNU toolchain including gcc/g++ (compiler), make &amp;amp;  cmake&lt;br /&gt;
* fgms source code, currently version 0.10.23&lt;br /&gt;
* about 5-10 MB of hard disk space (mainly required for building the binary)&lt;br /&gt;
&lt;br /&gt;
== Traffic &amp;amp; Bandwidth Considerations ==&lt;br /&gt;
&lt;br /&gt;
Note: Currently (May 2008), the server code basically boils down to a packet multiplexer (i.e. most data is -unconditionally- transmitted to all 'active' clients), which may thus create considerable amounts of traffic; this ought to be taken into consideration due to bandwidth limitations in most hosting packages (i.e. '''fgms may create considerable amounts of traffic!'''). For basic calculations: inbound traffic is 25 Kilobit per second while outbound is 25 Kbits per second for each plane/client that can 'see' another. &lt;br /&gt;
&lt;br /&gt;
By default, assuming a 10hz update interval, each active fgfs client will currently cause I/O traffic of approximately 5 kbytes/sec (one update consuming ~500 bytes) [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg16016.html].&lt;br /&gt;
&lt;br /&gt;
As client updates have to be propagated to all other active clients by the server, this number has to be multiplied by the number of active clients -1 (i.e. clients within a configurable range, minus the originating client). &lt;br /&gt;
In addition, the fgms system allows for traffic updates to be sort of 'mirrored' on (relayed to) other configurable multiplayer/relay servers. &lt;br /&gt;
&lt;br /&gt;
This feature makes it possible for users/clients to use an arbitrary server (with acceptable latency), but still see clients/vehicles connected to different servers. Thus, such relay servers may additionally increase inbound/outbound traffic considerably as all traffic is mirrored/propagated to such relays.&lt;br /&gt;
&lt;br /&gt;
Having more servers should actually decrease the load on each server in high load situations, i.e. when most of the clients are within range of each other. See this&lt;br /&gt;
[http://www.gidenstam.org/FlightGear/fgms/fgms_bandwidth_estimates.txt brief note on the theoretical bandwidth behaviour of fgms.]&lt;br /&gt;
&lt;br /&gt;
=== Facts ===&lt;br /&gt;
In March 2008, the main fgms multiplayer server (pigeond.net) was reported to consume approximately 15 gb of bandwidth per '''day''', with an average throughput of 200 kB/sec and peak loads of up to ~ 650 kB/sec [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg16016.html].&lt;br /&gt;
&lt;br /&gt;
During the same month (the much less used but interconnected) mpserver06.flightgear.org had on average 742 MB incoming and 688 MB outgoing traffic per day (i.e. 72 kbit/sec respective 66 kbit/sec on average).&lt;br /&gt;
&lt;br /&gt;
In September 2009, mpserver 05 had a massive peak bandwidth of 1.0 MB/sec. Average bandwidth consumed was about 9 GB of bandwidth per day. The average bandwidth usage per day is climbing due to more users moving from 02 to 05.&lt;br /&gt;
&lt;br /&gt;
In July 2013, mpserver01 load was reported averaging at 10 MBit/sec&lt;br /&gt;
&lt;br /&gt;
=== Reducing bandwidth requirements ===&lt;br /&gt;
Total network traffic is mainly determined by the number of active clients that 'see eachother' and configured mirrors. &lt;br /&gt;
If traffic considerations are relevant, the following options exist to reduce overall server/network load:&lt;br /&gt;
&lt;br /&gt;
* configure a relatively low &amp;quot;server.out_of_reach&amp;quot; value, so that clients outside a certain range are not provided with updates (usually about 100 nm on the main server network)&lt;br /&gt;
* for virtual gatherings (i.e. fly-ins), have clients use airports and places that do not have lots of other traffic (i.e. in other words, avoid places like standard airports such as KSFO)&lt;br /&gt;
* avoid the use of unnecessary relay servers&lt;br /&gt;
* if you are not interested in your server being publicly available, only share its address with your friends privately&lt;br /&gt;
* for local testing/development purposes, you may want to run only a private fgms session, that may be specific to your LAN or even computer.&lt;br /&gt;
&lt;br /&gt;
== Getting &amp;amp; Building fgms ==&lt;br /&gt;
* You will need the build tools cmake and make, and also g++ to compile the fgms application. These can usually be found in the package manager for most the common Linux distributions. You will also need the git client to fetch the source code from the repository, if you plan to download it from the command line interface (see below).&lt;br /&gt;
* Once the build tools are installed on your machine, create a directory to hold the source code. This could be named anything, such as fgms. Create it in your user home directory. Note that this WILL NOT be the directory where the program will be compiled.&lt;br /&gt;
* Now 'cd' into the directory you just made, where you will run the command to fetch the source code from the git repository (see below). &lt;br /&gt;
* To download the latest stable version via HTTP, you can use direct your browse to the URL https://gitlab.com/fgms/fgms-0-x. Download and unzip the source code, and place it in the directory you created above.&lt;br /&gt;
* To download a file directly to your server from an ssh session, you can use git tools with the following command:&lt;br /&gt;
:&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;git clone https://gitlab.com/fgms/fgms-0-x.git&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compiling FGMS ==&lt;br /&gt;
&lt;br /&gt;
For FreeBSD-specific instructions, please see [[Howto:Set up a multiplayer server on FreeBSD]]&lt;br /&gt;
&lt;br /&gt;
NOTE: In general, on any current machine this process should not take longer than about 60 seconds.&lt;br /&gt;
&lt;br /&gt;
* Once you have the source code, 'cd' into the ~/fgms/fgms-0-x/ directory and note the presence of the CMakeLists.txt file and the README.cmake file. Open the README.cmake file and take a minute to read it over. Also, note the path to the CMakeLists.txt file, as you will need this in the following steps.&lt;br /&gt;
&lt;br /&gt;
* Now create a build-fgms directory in your home directory, and 'cd' into it. From inside the ~/build-fgms/ directory, run the cmake command using the path to the CMakeLists.txt as an argument. For example: cmake /home/&amp;lt;user_name&amp;gt;/fgms/fgms-0-x/&lt;br /&gt;
&lt;br /&gt;
* Once the build finishes, you can either run the &amp;quot;cmake --build ...&amp;quot; command as shown in the README.cmake file, or you can simply use &amp;quot;make&amp;quot; to build the program.&lt;br /&gt;
&lt;br /&gt;
* Once the compilation process finishes, you need to install the program using &amp;quot;make install&amp;quot; (as user), or you can also install as root.&lt;br /&gt;
&lt;br /&gt;
* Once the program has been installed, you need to copy the fgms_example.conf file from the /fgms/fgms-0-x/src/server directory, into the build-fgms directory. To do this from inside the /fgms/fgms-0-x/src/server directory, you can use this command: cp ./fgms_example.conf ~/build-fgms/&lt;br /&gt;
&lt;br /&gt;
* Now 'cd' into the build-fgms directory, and rename the file you just copied as &amp;quot;fgms.conf&amp;quot; so that fgms can find the proper configuration.&lt;br /&gt;
&lt;br /&gt;
== Setting up the config file ==&lt;br /&gt;
&lt;br /&gt;
At this point you should have a working 'fgms' binary in the build-fgms directory. If the server will be offline or for private use (i.e. LAN-only, please comment out the relay servers section. This will save bandwidth from the server being consumed.&lt;br /&gt;
&lt;br /&gt;
* Edit the fgms.conf file according to the instructions found elsewhere on this page, then save and close the file.&lt;br /&gt;
&lt;br /&gt;
{{cquote|As long as you are not absolutly sure what you are doing you should:&lt;br /&gt;
- disable tracking&lt;br /&gt;
- disable HUB setting&amp;lt;ref&amp;gt;{{cite web |url=http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg40454.html|title=&amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] New FlightGear Multiplayer Server&amp;lt;/nowiki&amp;gt;|author=Oliver Schröder|date=Wed, 10 Jul 2013 13:53:55 -0700}}&amp;lt;/ref&amp;gt;|Oliver Schröder}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{cquote|fgms will ignore traffic comming from unknown relays and since the multiplayer network is a star topology you should list only mpserver01&lt;br /&gt;
as your only relay. Currently mpserver01 is the only HUB, Although multiple HUBs should work I have not tested a multi HUB environment yet.&lt;br /&gt;
And for those interrested: Current traffic load on mpserver01 is around 10 MBit/s&amp;lt;ref&amp;gt;{{cite web |url=http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg40454.html|title=&amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] New FlightGear Multiplayer Server&amp;lt;/nowiki&amp;gt;|author=Oliver Schröder|date=Wed, 10 Jul 2013 13:53:55 -0700}}&amp;lt;/ref&amp;gt;|Oliver Schröder}}&lt;br /&gt;
&lt;br /&gt;
{{cquote|your fgms.conf should look like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# basic setting&lt;br /&gt;
server.name = mpserver02&lt;br /&gt;
server.port = 5000&lt;br /&gt;
&lt;br /&gt;
# you can telnet to this port with this username/password&lt;br /&gt;
# and see statistics (nice cisco like CLI)&lt;br /&gt;
server.admin_port = 6002&lt;br /&gt;
server.admin_user = fred&lt;br /&gt;
server.admin_pass = fred&lt;br /&gt;
&lt;br /&gt;
server.admin_enable = fred&lt;br /&gt;
&lt;br /&gt;
# mpserver01 does this&lt;br /&gt;
server.tracked = false&lt;br /&gt;
&lt;br /&gt;
# mpserver01 is hub&lt;br /&gt;
server.is_hub = false&amp;lt;/pre&amp;gt;&amp;lt;ref&amp;gt;{{cite web |url=http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg40454.html|title=&amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] New FlightGear Multiplayer Server&amp;lt;/nowiki&amp;gt;|author=Oliver Schröder|date=Wed, 10 Jul 2013 13:53:55 -0700}}&amp;lt;/ref&amp;gt;|Oliver Schröder}}&lt;br /&gt;
&lt;br /&gt;
{{cquote|&amp;lt;pre&amp;gt;# don't set this too high&lt;br /&gt;
server.out_of_reach = 100&lt;br /&gt;
&lt;br /&gt;
# your only relay should be mpserver01&lt;br /&gt;
relay.host = mpserver01.flightgear.org&lt;br /&gt;
relay.port = 5000&lt;br /&gt;
&lt;br /&gt;
# you don't need a crossfeed, it's only interresting for fgms-developers&lt;br /&gt;
# crossfeed.host = foo.example.com&lt;br /&gt;
# crossfeed.port = 5002&lt;br /&gt;
&lt;br /&gt;
# you can add static entries of IPs which get blocked,&lt;br /&gt;
# but it's generally not needed and you can add them via&lt;br /&gt;
# the admin CLI&lt;br /&gt;
# blacklist = 123.123.123.123&amp;lt;/pre&amp;gt;&amp;lt;ref&amp;gt;{{cite web |url=http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg40454.html|title=&amp;lt;nowiki&amp;gt;Re: [Flightgear-devel] New FlightGear Multiplayer Server&amp;lt;/nowiki&amp;gt;|author=Oliver Schröder|date=Wed, 10 Jul 2013 13:53:55 -0700}}&amp;lt;/ref&amp;gt;|Oliver Schröder}}&lt;br /&gt;
&lt;br /&gt;
== Running FGMS for the first time ==&lt;br /&gt;
&lt;br /&gt;
In addition to its configuration file, FGMS supports a number of configuration parameters that can be passed at startup (and that will by default override any configuration file settings), to get a summary of supported parameters, you may want to run:&lt;br /&gt;
 $ ./fgms --help&lt;br /&gt;
&lt;br /&gt;
Which should present you with the following output:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
options are:&lt;br /&gt;
-h            print this help screen&lt;br /&gt;
-a PORT       listen to PORT for telnet&lt;br /&gt;
-c config     read 'config' as configuration file&lt;br /&gt;
-p PORT       listen to PORT&lt;br /&gt;
-t TTL        Time a client is active while not sending packets&lt;br /&gt;
-o OOR        nautical miles two players must be apart to be out of reach&lt;br /&gt;
-l LOGFILE    Log to LOGFILE&lt;br /&gt;
-v LEVEL      verbosity (loglevel) in range 1 (few) and 5 (much)&lt;br /&gt;
-d            do _not_ run as a daemon (stay in foreground)&lt;br /&gt;
-D            do run as a daemon&lt;br /&gt;
&lt;br /&gt;
the default is to run as a daemon, which can be overridden in the&lt;br /&gt;
config file.&lt;br /&gt;
commandline parameters always override config file options&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After having finished the fgms configuration, you can try running fgms and start up fgfs to use the new server.&lt;br /&gt;
=== Public Server ===&lt;br /&gt;
If you'd like to make it a public server, you can simply use your external (public) IP address to set up the multiplayer in fgfs.&lt;br /&gt;
&lt;br /&gt;
For others to know about your public server you should notify the developers of the existence of your server by posting a message to the [[Mailing list|developers mailing list]].&lt;br /&gt;
&lt;br /&gt;
Add your server to this list: http://wiki.flightgear.org/Howto:Multiplayer#Servers&lt;br /&gt;
&lt;br /&gt;
== Related content ==&lt;br /&gt;
* [http://fgms.freeflightsim.org/ Website: fgms.freeflightsim.org]&lt;br /&gt;
* [[Howto: Multiplayer|Multiplayer howto]]&lt;br /&gt;
* [[MPmap]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Howto]]&lt;br /&gt;
[[Category:Multiplayer]]&lt;br /&gt;
&lt;br /&gt;
[[fr:Installer un serveur multijoueur]]&lt;/div&gt;</summary>
		<author><name>Chris-barry</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_Conditionals&amp;diff=91978</id>
		<title>Nasal Conditionals</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_Conditionals&amp;diff=91978"/>
		<updated>2016-01-28T15:36:36Z</updated>

		<summary type="html">&lt;p&gt;Chris-barry: /* Conditionals */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:Nasal Navigation}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Sometimes you may only want to execute certain portions of your code, depending on conditions. This can be accomplished in several ways. One of the most straightforward ways  being an '''if''' expression, which  has the form:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var condition=1; # this evaluates to boolean true&lt;br /&gt;
if (condition) {&lt;br /&gt;
    # true block, will  be executed if condition is true&lt;br /&gt;
} else {&lt;br /&gt;
    # false block, will be executed if condition is false&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To negate the whole thing, use the '''!''' operator:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var condition=1; # boolean true&lt;br /&gt;
if (!condition) {&lt;br /&gt;
    # false block, will  be executed if condition is true&lt;br /&gt;
} else {&lt;br /&gt;
    # true block, will be executed if condition is false&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In both examples, the '''condition''' variable is just a placeholder, it could be a variable named '''condition''', but it could also be a more complex expression, such as a '''getprop''' call for example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var condition = getprop(&amp;quot;/sim/signals/freeze&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
if (condition) {&lt;br /&gt;
    # true block, will  be executed if condition is true&lt;br /&gt;
} else {&lt;br /&gt;
    # false block, will be executed if condition is false&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The same thing could be accomplished by using a call to getprop() as part of the condition:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
if (var condition = getprop(&amp;quot;/sim/signals/freeze&amp;quot;)) {&lt;br /&gt;
    # true block, will  be executed if condition is true&lt;br /&gt;
} else {&lt;br /&gt;
    # false block, will be executed if condition is false&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that you are never using the condition variable here, so you could also omit the whole declaration and directly use the getprop call:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
if (getprop(&amp;quot;/sim/signals/freeze&amp;quot;)) {&lt;br /&gt;
    # true block, will  be executed if condition is true&lt;br /&gt;
} else {&lt;br /&gt;
    # false block, will be executed if condition is false&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The condition can also be arbitrarily complex, in that it can be made up of other conditions, that may be nested using these  boolean operators:&lt;br /&gt;
* '''!''' (not)&lt;br /&gt;
* '''and'''&lt;br /&gt;
* '''or'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var condition = (1==1 and 2==2 and 3==3) or (4!=5 and !0);&lt;br /&gt;
if (condition) {&lt;br /&gt;
    # true block, will  be executed if condition is true&lt;br /&gt;
} else {&lt;br /&gt;
    # false block, will be executed if condition is false&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Conditionals ==&lt;br /&gt;
&lt;br /&gt;
Nasal has no &amp;quot;statements&amp;quot;, which means that any expression can appear in any context. This means that you can use an if/else clause to do what the ?: (ternary operator) does in C. &lt;br /&gt;
The last semicolon in a code block is optional, to make this prettier. First, a completely conventional implementation of the '''abs''' function:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var abs = func(n) { &lt;br /&gt;
    if(n&amp;lt;0) &lt;br /&gt;
    { return -n }&lt;br /&gt;
    else &lt;br /&gt;
    { return n }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This form would work as it is in &amp;quot;C&amp;quot; and, with minor adjustments for syntax, in many other languages. However, the following form would not work in &amp;quot;C&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var abs = func(n) { &lt;br /&gt;
    return if (n&amp;lt;0) &lt;br /&gt;
    { -n }&lt;br /&gt;
    else &lt;br /&gt;
    { n }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this form the '''if''' clause is clearly an expression that yields a value. That value is the result of the last expression executed within the '''if''' clause.&lt;br /&gt;
&lt;br /&gt;
And for those who don't like typing, the ternary operator works like you expect:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var abs = func(n) { n &amp;lt; 0 ? -n : n }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This also illustrates that a function will return a value even when there is no '''return''' clause. The value returned is the value of the last expression evaluated within the function.&lt;br /&gt;
&lt;br /&gt;
In addition, Nasal supports braceless blocks, like they're known from C/C++ and other languages. Basically, the block ends with a semicolon, instead of being encapsulated inside a &amp;lt;tt&amp;gt;{&amp;lt;/tt&amp;gt;/&amp;lt;tt&amp;gt;}&amp;lt;/tt&amp;gt; pair. This means basically that the first statement (expression) after a conditional is evaluated if the condition is true, otherwise it will be ignored:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var foo=1;&lt;br /&gt;
if (foo)&lt;br /&gt;
    print(&amp;quot;1\n&amp;quot;);&lt;br /&gt;
else&lt;br /&gt;
    print(&amp;quot;0\n&amp;quot;);&lt;br /&gt;
print(&amp;quot;this is printed regardless\n&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Instead of a switch statement one can use&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
if (1==2) {&lt;br /&gt;
    print(&amp;quot;wrong&amp;quot;);&lt;br /&gt;
} else if (1==3) { # NOTE the space between else and if&lt;br /&gt;
    print(&amp;quot;wronger&amp;quot;);&lt;br /&gt;
} else {&lt;br /&gt;
    print(&amp;quot;don't know&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which produces the expected output of &amp;lt;code&amp;gt;don't know&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Instead of &amp;quot;else if&amp;quot;, you can also use the shorter equivalent form &amp;quot;elsif&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
if (1==2) {&lt;br /&gt;
    print(&amp;quot;wrong&amp;quot;);&lt;br /&gt;
} elsif (1==3) { &lt;br /&gt;
    print(&amp;quot;wronger&amp;quot;);&lt;br /&gt;
} else {&lt;br /&gt;
   print(&amp;quot;don't know&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;nil&amp;lt;/tt&amp;gt; logic is actually quite logical, let's just restate the obvious:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
if (nil) {&lt;br /&gt;
    print(&amp;quot;This should never be printed&amp;quot;);&lt;br /&gt;
} else {&lt;br /&gt;
    print(&amp;quot;This will be printed, because nil is always false&amp;quot;);		&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nasal's binary boolean operators are &amp;quot;and&amp;quot; and &amp;quot;or&amp;quot;, unlike C. Unary not is still &amp;quot;!&amp;quot; however. They short-circuit like you expect:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var toggle = 0;&lt;br /&gt;
var a = nil;&lt;br /&gt;
if (a != nil and a.field == 42) {&lt;br /&gt;
    toggle = !toggle; # doesn't crash when a is nil&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that you should always surround multiple conditions within outer parentheses:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
if (1) do_something();&lt;br /&gt;
if (1 and 1) do_something();&lt;br /&gt;
if ( (1) and (1) ) do_something();&lt;br /&gt;
if ( (1) or (0) ) do_something();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nasal's binary boolean operators can also be used to default expressions to certain values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var altitude = getprop(&amp;quot;/position/altitude-ft&amp;quot;) or 0.00;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Basically this will first execute the getprop() call and if it doesn't return &amp;quot;true&amp;quot; (i.e. if it isn't zero or nil), it will instead use 0.00 as the value for the altitude variable.&lt;br /&gt;
&lt;br /&gt;
Regarding boolean operators like and/or: This is working because they &amp;quot;short circuit&amp;quot;, i.e. in an OR comparison, the remaining checks are NEVER done IF any single of the previous checks is true (1), because that'll suffice to satisfy the OR expression (i.e. knowing that a single check evaluates to true).&lt;br /&gt;
&lt;br /&gt;
Similarly, an &amp;quot;and&amp;quot; expression will inevitably need to do ALL &amp;quot;and&amp;quot; checks in order to evaluate the whole expression.&lt;br /&gt;
&lt;br /&gt;
At first, this may seem pretty complex and counter-intuitive - but it's important to keep this technique in mind, especially for variables that are later on used in calcuations:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var x = getprop(&amp;quot;/velocities/airspeed-kts&amp;quot;) or 0.00; # to ensure that x is always valid number&lt;br /&gt;
var foo = 10*3.1*x; # ... for this computation&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So this is to ensure that invalid property tree state does not mess up the calculations done in Nasal by defaulting x to 0.00, i.e. a valid numeric value.&lt;br /&gt;
&lt;br /&gt;
Bottom line being, using &amp;quot;or&amp;quot; to default a variable to a given value is a short and succinct way to avoid otherwise elaborate checks, e.g. compare:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var altitude_ft = getprop(&amp;quot;/position/altitude-ft&amp;quot;);&lt;br /&gt;
if (altitude_ft == nil) {&lt;br /&gt;
    altitude_ft = 0.0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
versus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var altitude_ft = getprop(&amp;quot;/position/altitude-ft&amp;quot;) or 0.00;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Basically: whenever you read important state from the property tree that you'll use in calculations, it's a good practice to default the value to some sane value.&lt;br /&gt;
&lt;br /&gt;
But this technique isn't really specific to getprop (or any other library call).&lt;br /&gt;
&lt;br /&gt;
Nasal is a language that has no statements, it's all about EXPRESSIONS. So you can put things in pretty much arbitrary places.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var do_something = func return 0;&lt;br /&gt;
if (a==1) {&lt;br /&gt;
    do_something() or print(&amp;quot;failed&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var do_something = func return 0;&lt;br /&gt;
( (a==1) and do_something() ) or print(&amp;quot;failed&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In a boolean comparison, 1 always means &amp;quot;true&amp;quot; while 0 always means &amp;quot;false&amp;quot;. For instance, ANY comparison with if x ==1 can be abbreviated to if (x), because the ==1 check is implictly done:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var do_something = func return 0;&lt;br /&gt;
( a and do_something() ) or print(&amp;quot;failed&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Using Hashs to map keys to functions ==&lt;br /&gt;
&lt;br /&gt;
You can easily reduce the complexity of huge conditional (IF) statements, such as this one:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
if (a==1) function_a();&lt;br /&gt;
else&lt;br /&gt;
if (a==2) function_b();&lt;br /&gt;
else&lt;br /&gt;
if (a==3) function_c();&lt;br /&gt;
else&lt;br /&gt;
if (a==4) function_d();&lt;br /&gt;
else&lt;br /&gt;
if (a==5) function_e();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
.. just by using the variable as a key (index) into a hash, so that you can directly call the corresponding function:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var mapping = {1:function_a, 2:function_b, 3:function_c, 4:function_d,5:function_e};&lt;br /&gt;
mapping[a] ();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This initializes first a hash map of values and maps a function &amp;quot;pointer&amp;quot; to each value, so that accessing mapping[x] will return the function pointer for the key &amp;quot;x&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Next, you can actually call the function by appending a list of function arguments (empty parentheses for no args) to the hash lookup.&lt;br /&gt;
&lt;br /&gt;
Using this technique, you can reduce the complexity of huge conditional blocks. For example, consider this extract from weather_tile_management.nas:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
if (code == &amp;quot;altocumulus_sky&amp;quot;){weather_tiles.set_altocumulus_tile();}&lt;br /&gt;
else if (code == &amp;quot;broken_layers&amp;quot;) {weather_tiles.set_broken_layers_tile();}&lt;br /&gt;
else if (code == &amp;quot;stratus&amp;quot;) {weather_tiles.set_overcast_stratus_tile();}&lt;br /&gt;
else if (code == &amp;quot;cumulus_sky&amp;quot;) {weather_tiles.set_fair_weather_tile();}&lt;br /&gt;
else if (code == &amp;quot;gliders_sky&amp;quot;) {weather_tiles.set_gliders_sky_tile();}&lt;br /&gt;
else if (code == &amp;quot;blue_thermals&amp;quot;) {weather_tiles.set_blue_thermals_tile();}&lt;br /&gt;
else if (code == &amp;quot;summer_rain&amp;quot;) {weather_tiles.set_summer_rain_tile();}&lt;br /&gt;
else if (code == &amp;quot;high_pressure_core&amp;quot;) {weather_tiles.set_high_pressure_core_tile();}&lt;br /&gt;
else if (code == &amp;quot;high_pressure&amp;quot;) {weather_tiles.set_high_pressure_tile();}&lt;br /&gt;
else if (code == &amp;quot;high_pressure_border&amp;quot;) {weather_tiles.set_high_pressure_border_tile();}&lt;br /&gt;
else if (code == &amp;quot;low_pressure_border&amp;quot;) {weather_tiles.set_low_pressure_border_tile();}&lt;br /&gt;
else if (code == &amp;quot;low_pressure&amp;quot;) {weather_tiles.set_low_pressure_tile();}&lt;br /&gt;
else if (code == &amp;quot;low_pressure_core&amp;quot;) {weather_tiles.set_low_pressure_core_tile();}&lt;br /&gt;
else if (code == &amp;quot;cold_sector&amp;quot;) {weather_tiles.set_cold_sector_tile();}&lt;br /&gt;
else if (code == &amp;quot;warm_sector&amp;quot;) {weather_tiles.set_warm_sector_tile();}&lt;br /&gt;
else if (code == &amp;quot;tropical_weather&amp;quot;) {weather_tiles.set_tropical_weather_tile();}&lt;br /&gt;
else if (code == &amp;quot;test&amp;quot;) {weather_tiles.set_4_8_stratus_tile();}&lt;br /&gt;
else ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
While this is not a very complex or huge block of code, it is an excellent example for very good naming conventions used already, because the consistency of naming variables and functions can pay off easily here, with just some very small changes, you can already reduce the whole thing to a hash lookup like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
weather_tiles[&amp;quot;set_&amp;quot;~code~&amp;quot;_tile&amp;quot;]();  # naming convention&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This would dynamically concatenate a key consisting of &amp;quot;set_&amp;quot; + code + &amp;quot;_title&amp;quot; into the hash named weather_tiles, and then call the function that is returned from the hash lookup.&lt;br /&gt;
&lt;br /&gt;
So for this to work you only need to enforce consistency when naming your functions (i.e. this would of course CURRENTLY fail when the variable code contains &amp;quot;test&amp;quot; because there is no such hash member (it's &amp;quot;4_8_stratus&amp;quot; instead).&lt;br /&gt;
&lt;br /&gt;
The same applies to cumulus sky (fair weather), stratus/overcast stratus.&lt;br /&gt;
&lt;br /&gt;
But these are very simple changes to do (just renaming these functions to match the existing conventions). When you do that, you can easily replace such huge IF statements and replace them with a single hash lookup and function call:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
hash[key] (arguments...);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, consider:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var makeFuncString = func(c) return tolower(&amp;quot;set_&amp;quot;~c~&amp;quot;_tile&amp;quot;);&lt;br /&gt;
var isFunc = func(f) typeof(f)=='func';&lt;br /&gt;
var hasMethod = func(h,m) contains(h,m) and isFunc;&lt;br /&gt;
var callIfAvailable = func(hash, method, unavailable=func{} ) {&lt;br /&gt;
    var c=hasMethod(hash,makeFuncString(m) ) or unavailable();&lt;br /&gt;
    hash[makeFuncString(m)] ();&lt;br /&gt;
}&lt;br /&gt;
callIfAvailable( weather_tiles,code, func {die(&amp;quot;key not found in hash or not a func&amp;quot;);} );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Chris-barry</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_Conditionals&amp;diff=91927</id>
		<title>Nasal Conditionals</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_Conditionals&amp;diff=91927"/>
		<updated>2016-01-27T20:24:09Z</updated>

		<summary type="html">&lt;p&gt;Chris-barry: If I have undestood correctly then the example given did not illustrate the feature it was intended to, that is that the 'if' clause is an expression that reurns a value.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:Nasal Navigation}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Sometimes you may only want to execute certain portions of your code, depending on conditions. This can be accomplished in several ways. One of the most straightforward ways  being an '''if''' expression, which  has the form:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var condition=1; # this evaluates to boolean true&lt;br /&gt;
if (condition) {&lt;br /&gt;
    # true block, will  be executed if condition is true&lt;br /&gt;
} else {&lt;br /&gt;
    # false block, will be executed if condition is false&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To negate the whole thing, use the '''!''' operator:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var condition=1; # boolean true&lt;br /&gt;
if (!condition) {&lt;br /&gt;
    # false block, will  be executed if condition is true&lt;br /&gt;
} else {&lt;br /&gt;
    # true block, will be executed if condition is false&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In both examples, the '''condition''' variable is just a placeholder, it could be a variable named '''condition''', but it could also be a more complex expression, such as a '''getprop''' call for example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var condition = getprop(&amp;quot;/sim/signals/freeze&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
if (condition) {&lt;br /&gt;
    # true block, will  be executed if condition is true&lt;br /&gt;
} else {&lt;br /&gt;
    # false block, will be executed if condition is false&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The same thing could be accomplished by using a call to getprop() as part of the condition:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
if (var condition = getprop(&amp;quot;/sim/signals/freeze&amp;quot;)) {&lt;br /&gt;
    # true block, will  be executed if condition is true&lt;br /&gt;
} else {&lt;br /&gt;
    # false block, will be executed if condition is false&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that you are never using the condition variable here, so you could also omit the whole declaration and directly use the getprop call:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
if (getprop(&amp;quot;/sim/signals/freeze&amp;quot;)) {&lt;br /&gt;
    # true block, will  be executed if condition is true&lt;br /&gt;
} else {&lt;br /&gt;
    # false block, will be executed if condition is false&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The condition can also be arbitrarily complex, in that it can be made up of other conditions, that may be nested using these  boolean operators:&lt;br /&gt;
* '''!''' (not)&lt;br /&gt;
* '''and'''&lt;br /&gt;
* '''or'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var condition = (1==1 and 2==2 and 3==3) or (4!=5 and !0);&lt;br /&gt;
if (condition) {&lt;br /&gt;
    # true block, will  be executed if condition is true&lt;br /&gt;
} else {&lt;br /&gt;
    # false block, will be executed if condition is false&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Conditionals ==&lt;br /&gt;
&lt;br /&gt;
Nasal has no &amp;quot;statements&amp;quot;, which means that any expression can appear in any context. This means that you can use an if/else clause to do what the ?: (ternary operator) does in C. &lt;br /&gt;
The last semicolon in a code block is optional, to make this prettier. First, a completely conventional implementation of the '''abs''' function:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var abs = func(n) { &lt;br /&gt;
    if(n&amp;lt;0) &lt;br /&gt;
    { return -n }&lt;br /&gt;
    else &lt;br /&gt;
    { return n }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This form would work as it is in &amp;quot;C&amp;quot; and, with minor adjustments for syntax, in many other languages. However, te following form would not work in &amp;quot;C&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var abs = func(n) { &lt;br /&gt;
    return if (n&amp;lt;0) &lt;br /&gt;
    { -n }&lt;br /&gt;
    else &lt;br /&gt;
    { n }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this form the '''if''' clause is clearly an expression that yields a value. That value is the result of the last expression executed within the '''if''' clause.&lt;br /&gt;
&lt;br /&gt;
And for those who don't like typing, the ternary operator works like you expect:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var abs = func(n) { n &amp;lt; 0 ? -n : n }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This also illustrates that a function will return a value even when there is no '''return''' clause. The value returned is the value of the last expression evaluated within the function.&lt;br /&gt;
&lt;br /&gt;
In addition, Nasal supports braceless blocks, like they're known from C/C++ and other languages. Basically, the block ends with a semicolon, instead of being encapsulated inside a &amp;lt;tt&amp;gt;{&amp;lt;/tt&amp;gt;/&amp;lt;tt&amp;gt;}&amp;lt;/tt&amp;gt; pair. This means basically that the first statement (expression) after a conditional is evaluated if the condition is true, otherwise it will be ignored:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var foo=1;&lt;br /&gt;
if (foo)&lt;br /&gt;
    print(&amp;quot;1\n&amp;quot;);&lt;br /&gt;
else&lt;br /&gt;
    print(&amp;quot;0\n&amp;quot;);&lt;br /&gt;
print(&amp;quot;this is printed regardless\n&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Instead of a switch statement one can use&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
if (1==2) {&lt;br /&gt;
    print(&amp;quot;wrong&amp;quot;);&lt;br /&gt;
} else if (1==3) { # NOTE the space between else and if&lt;br /&gt;
    print(&amp;quot;wronger&amp;quot;);&lt;br /&gt;
} else {&lt;br /&gt;
    print(&amp;quot;don't know&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which produces the expected output of &amp;lt;code&amp;gt;don't know&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Instead of &amp;quot;else if&amp;quot;, you can also use the shorter equivalent form &amp;quot;elsif&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
if (1==2) {&lt;br /&gt;
    print(&amp;quot;wrong&amp;quot;);&lt;br /&gt;
} elsif (1==3) { &lt;br /&gt;
    print(&amp;quot;wronger&amp;quot;);&lt;br /&gt;
} else {&lt;br /&gt;
   print(&amp;quot;don't know&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;nil&amp;lt;/tt&amp;gt; logic is actually quite logical, let's just restate the obvious:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
if (nil) {&lt;br /&gt;
    print(&amp;quot;This should never be printed&amp;quot;);&lt;br /&gt;
} else {&lt;br /&gt;
    print(&amp;quot;This will be printed, because nil is always false&amp;quot;);		&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nasal's binary boolean operators are &amp;quot;and&amp;quot; and &amp;quot;or&amp;quot;, unlike C. Unary not is still &amp;quot;!&amp;quot; however. They short-circuit like you expect:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var toggle = 0;&lt;br /&gt;
var a = nil;&lt;br /&gt;
if (a != nil and a.field == 42) {&lt;br /&gt;
    toggle = !toggle; # doesn't crash when a is nil&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that you should always surround multiple conditions within outer parentheses:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
if (1) do_something();&lt;br /&gt;
if (1 and 1) do_something();&lt;br /&gt;
if ( (1) and (1) ) do_something();&lt;br /&gt;
if ( (1) or (0) ) do_something();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nasal's binary boolean operators can also be used to default expressions to certain values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var altitude = getprop(&amp;quot;/position/altitude-ft&amp;quot;) or 0.00;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Basically this will first execute the getprop() call and if it doesn't return &amp;quot;true&amp;quot; (i.e. if it isn't zero or nil), it will instead use 0.00 as the value for the altitude variable.&lt;br /&gt;
&lt;br /&gt;
Regarding boolean operators like and/or: This is working because they &amp;quot;short circuit&amp;quot;, i.e. in an OR comparison, the remaining checks are NEVER done IF any single of the previous checks is true (1), because that'll suffice to satisfy the OR expression (i.e. knowing that a single check evaluates to true).&lt;br /&gt;
&lt;br /&gt;
Similarly, an &amp;quot;and&amp;quot; expression will inevitably need to do ALL &amp;quot;and&amp;quot; checks in order to evaluate the whole expression.&lt;br /&gt;
&lt;br /&gt;
At first, this may seem pretty complex and counter-intuitive - but it's important to keep this technique in mind, especially for variables that are later on used in calcuations:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var x = getprop(&amp;quot;/velocities/airspeed-kts&amp;quot;) or 0.00; # to ensure that x is always valid number&lt;br /&gt;
var foo = 10*3.1*x; # ... for this computation&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So this is to ensure that invalid property tree state does not mess up the calculations done in Nasal by defaulting x to 0.00, i.e. a valid numeric value.&lt;br /&gt;
&lt;br /&gt;
Bottom line being, using &amp;quot;or&amp;quot; to default a variable to a given value is a short and succinct way to avoid otherwise elaborate checks, e.g. compare:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var altitude_ft = getprop(&amp;quot;/position/altitude-ft&amp;quot;);&lt;br /&gt;
if (altitude_ft == nil) {&lt;br /&gt;
    altitude_ft = 0.0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
versus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var altitude_ft = getprop(&amp;quot;/position/altitude-ft&amp;quot;) or 0.00;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Basically: whenever you read important state from the property tree that you'll use in calculations, it's a good practice to default the value to some sane value.&lt;br /&gt;
&lt;br /&gt;
But this technique isn't really specific to getprop (or any other library call).&lt;br /&gt;
&lt;br /&gt;
Nasal is a language that has no statements, it's all about EXPRESSIONS. So you can put things in pretty much arbitrary places.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var do_something = func return 0;&lt;br /&gt;
if (a==1) {&lt;br /&gt;
    do_something() or print(&amp;quot;failed&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var do_something = func return 0;&lt;br /&gt;
( (a==1) and do_something() ) or print(&amp;quot;failed&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In a boolean comparison, 1 always means &amp;quot;true&amp;quot; while 0 always means &amp;quot;false&amp;quot;. For instance, ANY comparison with if x ==1 can be abbreviated to if (x), because the ==1 check is implictly done:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var do_something = func return 0;&lt;br /&gt;
( a and do_something() ) or print(&amp;quot;failed&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Using Hashs to map keys to functions ==&lt;br /&gt;
&lt;br /&gt;
You can easily reduce the complexity of huge conditional (IF) statements, such as this one:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
if (a==1) function_a();&lt;br /&gt;
else&lt;br /&gt;
if (a==2) function_b();&lt;br /&gt;
else&lt;br /&gt;
if (a==3) function_c();&lt;br /&gt;
else&lt;br /&gt;
if (a==4) function_d();&lt;br /&gt;
else&lt;br /&gt;
if (a==5) function_e();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
.. just by using the variable as a key (index) into a hash, so that you can directly call the corresponding function:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var mapping = {1:function_a, 2:function_b, 3:function_c, 4:function_d,5:function_e};&lt;br /&gt;
mapping[a] ();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This initializes first a hash map of values and maps a function &amp;quot;pointer&amp;quot; to each value, so that accessing mapping[x] will return the function pointer for the key &amp;quot;x&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Next, you can actually call the function by appending a list of function arguments (empty parentheses for no args) to the hash lookup.&lt;br /&gt;
&lt;br /&gt;
Using this technique, you can reduce the complexity of huge conditional blocks. For example, consider this extract from weather_tile_management.nas:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
if (code == &amp;quot;altocumulus_sky&amp;quot;){weather_tiles.set_altocumulus_tile();}&lt;br /&gt;
else if (code == &amp;quot;broken_layers&amp;quot;) {weather_tiles.set_broken_layers_tile();}&lt;br /&gt;
else if (code == &amp;quot;stratus&amp;quot;) {weather_tiles.set_overcast_stratus_tile();}&lt;br /&gt;
else if (code == &amp;quot;cumulus_sky&amp;quot;) {weather_tiles.set_fair_weather_tile();}&lt;br /&gt;
else if (code == &amp;quot;gliders_sky&amp;quot;) {weather_tiles.set_gliders_sky_tile();}&lt;br /&gt;
else if (code == &amp;quot;blue_thermals&amp;quot;) {weather_tiles.set_blue_thermals_tile();}&lt;br /&gt;
else if (code == &amp;quot;summer_rain&amp;quot;) {weather_tiles.set_summer_rain_tile();}&lt;br /&gt;
else if (code == &amp;quot;high_pressure_core&amp;quot;) {weather_tiles.set_high_pressure_core_tile();}&lt;br /&gt;
else if (code == &amp;quot;high_pressure&amp;quot;) {weather_tiles.set_high_pressure_tile();}&lt;br /&gt;
else if (code == &amp;quot;high_pressure_border&amp;quot;) {weather_tiles.set_high_pressure_border_tile();}&lt;br /&gt;
else if (code == &amp;quot;low_pressure_border&amp;quot;) {weather_tiles.set_low_pressure_border_tile();}&lt;br /&gt;
else if (code == &amp;quot;low_pressure&amp;quot;) {weather_tiles.set_low_pressure_tile();}&lt;br /&gt;
else if (code == &amp;quot;low_pressure_core&amp;quot;) {weather_tiles.set_low_pressure_core_tile();}&lt;br /&gt;
else if (code == &amp;quot;cold_sector&amp;quot;) {weather_tiles.set_cold_sector_tile();}&lt;br /&gt;
else if (code == &amp;quot;warm_sector&amp;quot;) {weather_tiles.set_warm_sector_tile();}&lt;br /&gt;
else if (code == &amp;quot;tropical_weather&amp;quot;) {weather_tiles.set_tropical_weather_tile();}&lt;br /&gt;
else if (code == &amp;quot;test&amp;quot;) {weather_tiles.set_4_8_stratus_tile();}&lt;br /&gt;
else ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
While this is not a very complex or huge block of code, it is an excellent example for very good naming conventions used already, because the consistency of naming variables and functions can pay off easily here, with just some very small changes, you can already reduce the whole thing to a hash lookup like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
weather_tiles[&amp;quot;set_&amp;quot;~code~&amp;quot;_tile&amp;quot;]();  # naming convention&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This would dynamically concatenate a key consisting of &amp;quot;set_&amp;quot; + code + &amp;quot;_title&amp;quot; into the hash named weather_tiles, and then call the function that is returned from the hash lookup.&lt;br /&gt;
&lt;br /&gt;
So for this to work you only need to enforce consistency when naming your functions (i.e. this would of course CURRENTLY fail when the variable code contains &amp;quot;test&amp;quot; because there is no such hash member (it's &amp;quot;4_8_stratus&amp;quot; instead).&lt;br /&gt;
&lt;br /&gt;
The same applies to cumulus sky (fair weather), stratus/overcast stratus.&lt;br /&gt;
&lt;br /&gt;
But these are very simple changes to do (just renaming these functions to match the existing conventions). When you do that, you can easily replace such huge IF statements and replace them with a single hash lookup and function call:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
hash[key] (arguments...);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, consider:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot;&amp;gt;&lt;br /&gt;
var makeFuncString = func(c) return tolower(&amp;quot;set_&amp;quot;~c~&amp;quot;_tile&amp;quot;);&lt;br /&gt;
var isFunc = func(f) typeof(f)=='func';&lt;br /&gt;
var hasMethod = func(h,m) contains(h,m) and isFunc;&lt;br /&gt;
var callIfAvailable = func(hash, method, unavailable=func{} ) {&lt;br /&gt;
    var c=hasMethod(hash,makeFuncString(m) ) or unavailable();&lt;br /&gt;
    hash[makeFuncString(m)] ();&lt;br /&gt;
}&lt;br /&gt;
callIfAvailable( weather_tiles,code, func {die(&amp;quot;key not found in hash or not a func&amp;quot;);} );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Chris-barry</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_library_functions&amp;diff=91909</id>
		<title>Nasal library functions</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_library_functions&amp;diff=91909"/>
		<updated>2016-01-27T18:18:49Z</updated>

		<summary type="html">&lt;p&gt;Chris-barry: /* size() */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Nasal Navigation}}&lt;br /&gt;
&lt;br /&gt;
Please first see: http://plausible.org/nasal/lib.html&lt;br /&gt;
&lt;br /&gt;
== size() ==&lt;br /&gt;
'''Usage:'''&lt;br /&gt;
&lt;br /&gt;
 size(''object'');&lt;br /&gt;
&lt;br /&gt;
where ''object'' may be a ''string'', a ''vector'' or a ''hash''.&lt;br /&gt;
&lt;br /&gt;
'''Return value'''&lt;br /&gt;
&lt;br /&gt;
An intger equal to the number of characters in a ''string'' argument or the number of elements in a ''vector'' or ''hash''.&lt;br /&gt;
&lt;br /&gt;
If the argument is a non-string scalar then the error '''object has no size()''' will be generated.&lt;br /&gt;
&lt;br /&gt;
== keys() ==&lt;br /&gt;
&lt;br /&gt;
== append() ==&lt;br /&gt;
&lt;br /&gt;
== pop() ==&lt;br /&gt;
&lt;br /&gt;
== setsize() ==&lt;br /&gt;
'''Usage:'''&lt;br /&gt;
&lt;br /&gt;
 setsize(vect, new_size)&lt;br /&gt;
&lt;br /&gt;
where ''vect'' is an expression which evaluates to a vector and ''new_size'' is an expression that evaluates to a non-negative number.&lt;br /&gt;
&lt;br /&gt;
'''Action:'''&lt;br /&gt;
&lt;br /&gt;
Changes the number of elements in the vetor ''v'' to the value of s.&lt;br /&gt;
&lt;br /&gt;
'''Return value:'''&lt;br /&gt;
&lt;br /&gt;
The resized vector.&lt;br /&gt;
&lt;br /&gt;
'''Notes'''&lt;br /&gt;
&lt;br /&gt;
Elements that exist in both the original and the resized vector retain their values. When the vector is enlarged newly created elements are set to ''nil''. When the size is reduced the values of all elements beyond the new size are permanently lost.&lt;br /&gt;
&lt;br /&gt;
The ''new_size'' argument may be any non-negative number. Non-integer values are rounded down.&lt;br /&gt;
&lt;br /&gt;
The ''vect'' argument need not be a named variable. The expression:&lt;br /&gt;
&lt;br /&gt;
 var v1 = setsize([], n);&lt;br /&gt;
&lt;br /&gt;
Is a convenient way to allocate an empty vector of a specific size.&lt;br /&gt;
&lt;br /&gt;
== subvec() ==&lt;br /&gt;
Extract items of a vector - equivalent to the left() function for a string&lt;br /&gt;
&lt;br /&gt;
Example :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = directory(FGRoot ~ filename);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;.&amp;quot; , &amp;quot;..&amp;quot; , &amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
With subvec():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = subvec(directory(FGRoot ~ filename),2);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = subvec(directory(FGRoot ~ filename),3);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
== delete() ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== int() ==&lt;br /&gt;
&lt;br /&gt;
== num(str) ==&lt;br /&gt;
Convert string to number.&lt;br /&gt;
Returns nil if str is nil, empty string, string with no number.&lt;br /&gt;
&lt;br /&gt;
== streq() ==&lt;br /&gt;
&lt;br /&gt;
== cmp() ==&lt;br /&gt;
&lt;br /&gt;
== substr() ==&lt;br /&gt;
&lt;br /&gt;
== chr() ==&lt;br /&gt;
&lt;br /&gt;
== contains() ==&lt;br /&gt;
&lt;br /&gt;
== typeof() ==&lt;br /&gt;
&lt;br /&gt;
== ghosttype(ghost) ==&lt;br /&gt;
Returns a string containing either a descriptive name as passed to ''naNewGhost'' or ''naNewGhost2'' in C/C++ while creating the ghost or a unique id (aka the pointer to the C/C++ naGhostType instance) if no name has been set.&lt;br /&gt;
&lt;br /&gt;
== compile() ==&lt;br /&gt;
&lt;br /&gt;
== call() ==&lt;br /&gt;
&lt;br /&gt;
== die() ==&lt;br /&gt;
&lt;br /&gt;
== sprintf() ==&lt;br /&gt;
&lt;br /&gt;
== caller() ==&lt;br /&gt;
&lt;br /&gt;
== closure() ==&lt;br /&gt;
&lt;br /&gt;
== find() ==&lt;br /&gt;
&lt;br /&gt;
== split() ==&lt;br /&gt;
&lt;br /&gt;
== rand() ==&lt;br /&gt;
&lt;br /&gt;
== bind() ==&lt;br /&gt;
&lt;br /&gt;
== sort() ==&lt;br /&gt;
&lt;br /&gt;
== id() ==&lt;br /&gt;
&lt;br /&gt;
= math =&lt;br /&gt;
== Trigonometric_functions ==&lt;br /&gt;
'''Caution''': All trigonometric functions works with [https://en.wikipedia.org/wiki/Radian Radian]-values - not with Degree!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;To convert this&amp;lt;/u&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
radians = degree * math.pi / 180&amp;lt;br&amp;gt;&lt;br /&gt;
degree  = radians * 180 / math.pi&lt;br /&gt;
=== sin() ===&lt;br /&gt;
=== cos() ===&lt;br /&gt;
=== tan() ===&lt;br /&gt;
=== asin() ===&lt;br /&gt;
=== acos() ===&lt;br /&gt;
=== atan2() ===&lt;br /&gt;
== exp() ==&lt;br /&gt;
== ln() ==&lt;br /&gt;
== pow() ==&lt;br /&gt;
== sqrt() ==&lt;br /&gt;
== floor() ==&lt;br /&gt;
Returns the value rounded downward&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
math.floor(1.2); # returns 1&lt;br /&gt;
math.floor(1.6); # returns 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ceil() ==&lt;br /&gt;
Returns the value rounded upward&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
math.ceil(1.2); # returns 2&lt;br /&gt;
math.ceil(1.6); # returns 2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== fmod() ==&lt;br /&gt;
A '''modulo'''-operator. The [https://en.wikipedia.org/wiki/Modulo_operation modulo]-operation finds the remainder of division of one number by another (sometimes called modulus).&lt;br /&gt;
&lt;br /&gt;
fmod(x , y) may be negative if x &amp;lt; 0, whereas mod() seems to guarantee that 0 ≤ mod(x,y) &amp;lt; y, according to tests made with x and y integers, y &amp;gt; 0, x positive or negative.&lt;br /&gt;
&lt;br /&gt;
== clamp() ==&lt;br /&gt;
== periodic() ==&lt;br /&gt;
== round() ==&lt;br /&gt;
== pi ==&lt;br /&gt;
== e ==&lt;br /&gt;
&lt;br /&gt;
= io =&lt;br /&gt;
&lt;br /&gt;
* SEEK_SET&lt;br /&gt;
* SEEK_CUR&lt;br /&gt;
* SEEK_END&lt;br /&gt;
* stdin&lt;br /&gt;
* stdout&lt;br /&gt;
* stderr&lt;br /&gt;
&lt;br /&gt;
== stat() ==&lt;br /&gt;
== directory() ==&lt;br /&gt;
returns the files in a given directory&lt;br /&gt;
&lt;br /&gt;
e.g. chatter_list = directory( chatter_dir );&lt;br /&gt;
&lt;br /&gt;
Example : &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = directory(FGRoot ~ filename);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns :   &lt;br /&gt;
'''&amp;quot;.&amp;quot; , &amp;quot;..&amp;quot; , &amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
To delete the &amp;quot;.&amp;quot; and &amp;quot;..&amp;quot; see the subvec() function.&lt;br /&gt;
&lt;br /&gt;
== open() ==&lt;br /&gt;
== read() ==&lt;br /&gt;
== readln() ==&lt;br /&gt;
== seek() ==&lt;br /&gt;
== tell() ==&lt;br /&gt;
== write() ==&lt;br /&gt;
== flush() ==&lt;br /&gt;
== close() ==&lt;br /&gt;
&lt;br /&gt;
= utf8 =&lt;br /&gt;
== chstr() ==&lt;br /&gt;
== strc() ==&lt;br /&gt;
== substr() ==&lt;br /&gt;
== size() ==&lt;br /&gt;
== validate() ==&lt;/div&gt;</summary>
		<author><name>Chris-barry</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_library_functions&amp;diff=91908</id>
		<title>Nasal library functions</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_library_functions&amp;diff=91908"/>
		<updated>2016-01-27T18:13:30Z</updated>

		<summary type="html">&lt;p&gt;Chris-barry: /* setsize() */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Nasal Navigation}}&lt;br /&gt;
&lt;br /&gt;
Please first see: http://plausible.org/nasal/lib.html&lt;br /&gt;
&lt;br /&gt;
== size() ==&lt;br /&gt;
Usage:&lt;br /&gt;
size(''object'');&lt;br /&gt;
&lt;br /&gt;
where ''object'' may be a ''string'', a ''vector'' or a ''hash''.&lt;br /&gt;
&lt;br /&gt;
Returns an intger equal to the number of characters in a ''string'' argument or the number of elements in a ''vector'' or ''hash''.&lt;br /&gt;
&lt;br /&gt;
If the argument is a non-string scalar then the error '''object has no size()''' will be generated.&lt;br /&gt;
&lt;br /&gt;
== keys() ==&lt;br /&gt;
&lt;br /&gt;
== append() ==&lt;br /&gt;
&lt;br /&gt;
== pop() ==&lt;br /&gt;
&lt;br /&gt;
== setsize() ==&lt;br /&gt;
'''Usage:'''&lt;br /&gt;
&lt;br /&gt;
 setsize(vect, new_size)&lt;br /&gt;
&lt;br /&gt;
where ''vect'' is an expression which evaluates to a vector and ''new_size'' is an expression that evaluates to a non-negative number.&lt;br /&gt;
&lt;br /&gt;
'''Action:'''&lt;br /&gt;
&lt;br /&gt;
Changes the number of elements in the vetor ''v'' to the value of s.&lt;br /&gt;
&lt;br /&gt;
'''Return value:'''&lt;br /&gt;
&lt;br /&gt;
The resized vector.&lt;br /&gt;
&lt;br /&gt;
'''Notes'''&lt;br /&gt;
&lt;br /&gt;
Elements that exist in both the original and the resized vector retain their values. When the vector is enlarged newly created elements are set to ''nil''. When the size is reduced the values of all elements beyond the new size are permanently lost.&lt;br /&gt;
&lt;br /&gt;
The ''new_size'' argument may be any non-negative number. Non-integer values are rounded down.&lt;br /&gt;
&lt;br /&gt;
The ''vect'' argument need not be a named variable. The expression:&lt;br /&gt;
&lt;br /&gt;
 var v1 = setsize([], n);&lt;br /&gt;
&lt;br /&gt;
Is a convenient way to allocate an empty vector of a specific size.&lt;br /&gt;
&lt;br /&gt;
== subvec() ==&lt;br /&gt;
Extract items of a vector - equivalent to the left() function for a string&lt;br /&gt;
&lt;br /&gt;
Example :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = directory(FGRoot ~ filename);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;.&amp;quot; , &amp;quot;..&amp;quot; , &amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
With subvec():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = subvec(directory(FGRoot ~ filename),2);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = subvec(directory(FGRoot ~ filename),3);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
== delete() ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== int() ==&lt;br /&gt;
&lt;br /&gt;
== num(str) ==&lt;br /&gt;
Convert string to number.&lt;br /&gt;
Returns nil if str is nil, empty string, string with no number.&lt;br /&gt;
&lt;br /&gt;
== streq() ==&lt;br /&gt;
&lt;br /&gt;
== cmp() ==&lt;br /&gt;
&lt;br /&gt;
== substr() ==&lt;br /&gt;
&lt;br /&gt;
== chr() ==&lt;br /&gt;
&lt;br /&gt;
== contains() ==&lt;br /&gt;
&lt;br /&gt;
== typeof() ==&lt;br /&gt;
&lt;br /&gt;
== ghosttype(ghost) ==&lt;br /&gt;
Returns a string containing either a descriptive name as passed to ''naNewGhost'' or ''naNewGhost2'' in C/C++ while creating the ghost or a unique id (aka the pointer to the C/C++ naGhostType instance) if no name has been set.&lt;br /&gt;
&lt;br /&gt;
== compile() ==&lt;br /&gt;
&lt;br /&gt;
== call() ==&lt;br /&gt;
&lt;br /&gt;
== die() ==&lt;br /&gt;
&lt;br /&gt;
== sprintf() ==&lt;br /&gt;
&lt;br /&gt;
== caller() ==&lt;br /&gt;
&lt;br /&gt;
== closure() ==&lt;br /&gt;
&lt;br /&gt;
== find() ==&lt;br /&gt;
&lt;br /&gt;
== split() ==&lt;br /&gt;
&lt;br /&gt;
== rand() ==&lt;br /&gt;
&lt;br /&gt;
== bind() ==&lt;br /&gt;
&lt;br /&gt;
== sort() ==&lt;br /&gt;
&lt;br /&gt;
== id() ==&lt;br /&gt;
&lt;br /&gt;
= math =&lt;br /&gt;
== Trigonometric_functions ==&lt;br /&gt;
'''Caution''': All trigonometric functions works with [https://en.wikipedia.org/wiki/Radian Radian]-values - not with Degree!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;To convert this&amp;lt;/u&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
radians = degree * math.pi / 180&amp;lt;br&amp;gt;&lt;br /&gt;
degree  = radians * 180 / math.pi&lt;br /&gt;
=== sin() ===&lt;br /&gt;
=== cos() ===&lt;br /&gt;
=== tan() ===&lt;br /&gt;
=== asin() ===&lt;br /&gt;
=== acos() ===&lt;br /&gt;
=== atan2() ===&lt;br /&gt;
== exp() ==&lt;br /&gt;
== ln() ==&lt;br /&gt;
== pow() ==&lt;br /&gt;
== sqrt() ==&lt;br /&gt;
== floor() ==&lt;br /&gt;
Returns the value rounded downward&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
math.floor(1.2); # returns 1&lt;br /&gt;
math.floor(1.6); # returns 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ceil() ==&lt;br /&gt;
Returns the value rounded upward&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
math.ceil(1.2); # returns 2&lt;br /&gt;
math.ceil(1.6); # returns 2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== fmod() ==&lt;br /&gt;
A '''modulo'''-operator. The [https://en.wikipedia.org/wiki/Modulo_operation modulo]-operation finds the remainder of division of one number by another (sometimes called modulus).&lt;br /&gt;
&lt;br /&gt;
fmod(x , y) may be negative if x &amp;lt; 0, whereas mod() seems to guarantee that 0 ≤ mod(x,y) &amp;lt; y, according to tests made with x and y integers, y &amp;gt; 0, x positive or negative.&lt;br /&gt;
&lt;br /&gt;
== clamp() ==&lt;br /&gt;
== periodic() ==&lt;br /&gt;
== round() ==&lt;br /&gt;
== pi ==&lt;br /&gt;
== e ==&lt;br /&gt;
&lt;br /&gt;
= io =&lt;br /&gt;
&lt;br /&gt;
* SEEK_SET&lt;br /&gt;
* SEEK_CUR&lt;br /&gt;
* SEEK_END&lt;br /&gt;
* stdin&lt;br /&gt;
* stdout&lt;br /&gt;
* stderr&lt;br /&gt;
&lt;br /&gt;
== stat() ==&lt;br /&gt;
== directory() ==&lt;br /&gt;
returns the files in a given directory&lt;br /&gt;
&lt;br /&gt;
e.g. chatter_list = directory( chatter_dir );&lt;br /&gt;
&lt;br /&gt;
Example : &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = directory(FGRoot ~ filename);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns :   &lt;br /&gt;
'''&amp;quot;.&amp;quot; , &amp;quot;..&amp;quot; , &amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
To delete the &amp;quot;.&amp;quot; and &amp;quot;..&amp;quot; see the subvec() function.&lt;br /&gt;
&lt;br /&gt;
== open() ==&lt;br /&gt;
== read() ==&lt;br /&gt;
== readln() ==&lt;br /&gt;
== seek() ==&lt;br /&gt;
== tell() ==&lt;br /&gt;
== write() ==&lt;br /&gt;
== flush() ==&lt;br /&gt;
== close() ==&lt;br /&gt;
&lt;br /&gt;
= utf8 =&lt;br /&gt;
== chstr() ==&lt;br /&gt;
== strc() ==&lt;br /&gt;
== substr() ==&lt;br /&gt;
== size() ==&lt;br /&gt;
== validate() ==&lt;/div&gt;</summary>
		<author><name>Chris-barry</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_library_functions&amp;diff=91906</id>
		<title>Nasal library functions</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_library_functions&amp;diff=91906"/>
		<updated>2016-01-27T17:34:30Z</updated>

		<summary type="html">&lt;p&gt;Chris-barry: /* size() */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Nasal Navigation}}&lt;br /&gt;
&lt;br /&gt;
Please first see: http://plausible.org/nasal/lib.html&lt;br /&gt;
&lt;br /&gt;
== size() ==&lt;br /&gt;
Usage:&lt;br /&gt;
size(''object'');&lt;br /&gt;
&lt;br /&gt;
where ''object'' may be a ''string'', a ''vector'' or a ''hash''.&lt;br /&gt;
&lt;br /&gt;
Returns an intger equal to the number of characters in a ''string'' argument or the number of elements in a ''vector'' or ''hash''.&lt;br /&gt;
&lt;br /&gt;
If the argument is a non-string scalar then the error '''object has no size()''' will be generated.&lt;br /&gt;
&lt;br /&gt;
== keys() ==&lt;br /&gt;
&lt;br /&gt;
== append() ==&lt;br /&gt;
&lt;br /&gt;
== pop() ==&lt;br /&gt;
&lt;br /&gt;
== setsize() ==&lt;br /&gt;
&lt;br /&gt;
== subvec() ==&lt;br /&gt;
Extract items of a vector - equivalent to the left() function for a string&lt;br /&gt;
&lt;br /&gt;
Example :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = directory(FGRoot ~ filename);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;.&amp;quot; , &amp;quot;..&amp;quot; , &amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
With subvec():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = subvec(directory(FGRoot ~ filename),2);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = subvec(directory(FGRoot ~ filename),3);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
== delete() ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== int() ==&lt;br /&gt;
&lt;br /&gt;
== num(str) ==&lt;br /&gt;
Convert string to number.&lt;br /&gt;
Returns nil if str is nil, empty string, string with no number.&lt;br /&gt;
&lt;br /&gt;
== streq() ==&lt;br /&gt;
&lt;br /&gt;
== cmp() ==&lt;br /&gt;
&lt;br /&gt;
== substr() ==&lt;br /&gt;
&lt;br /&gt;
== chr() ==&lt;br /&gt;
&lt;br /&gt;
== contains() ==&lt;br /&gt;
&lt;br /&gt;
== typeof() ==&lt;br /&gt;
&lt;br /&gt;
== ghosttype(ghost) ==&lt;br /&gt;
Returns a string containing either a descriptive name as passed to ''naNewGhost'' or ''naNewGhost2'' in C/C++ while creating the ghost or a unique id (aka the pointer to the C/C++ naGhostType instance) if no name has been set.&lt;br /&gt;
&lt;br /&gt;
== compile() ==&lt;br /&gt;
&lt;br /&gt;
== call() ==&lt;br /&gt;
&lt;br /&gt;
== die() ==&lt;br /&gt;
&lt;br /&gt;
== sprintf() ==&lt;br /&gt;
&lt;br /&gt;
== caller() ==&lt;br /&gt;
&lt;br /&gt;
== closure() ==&lt;br /&gt;
&lt;br /&gt;
== find() ==&lt;br /&gt;
&lt;br /&gt;
== split() ==&lt;br /&gt;
&lt;br /&gt;
== rand() ==&lt;br /&gt;
&lt;br /&gt;
== bind() ==&lt;br /&gt;
&lt;br /&gt;
== sort() ==&lt;br /&gt;
&lt;br /&gt;
== id() ==&lt;br /&gt;
&lt;br /&gt;
= math =&lt;br /&gt;
== Trigonometric_functions ==&lt;br /&gt;
'''Caution''': All trigonometric functions works with [https://en.wikipedia.org/wiki/Radian Radian]-values - not with Degree!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;To convert this&amp;lt;/u&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
radians = degree * math.pi / 180&amp;lt;br&amp;gt;&lt;br /&gt;
degree  = radians * 180 / math.pi&lt;br /&gt;
=== sin() ===&lt;br /&gt;
=== cos() ===&lt;br /&gt;
=== tan() ===&lt;br /&gt;
=== asin() ===&lt;br /&gt;
=== acos() ===&lt;br /&gt;
=== atan2() ===&lt;br /&gt;
== exp() ==&lt;br /&gt;
== ln() ==&lt;br /&gt;
== pow() ==&lt;br /&gt;
== sqrt() ==&lt;br /&gt;
== floor() ==&lt;br /&gt;
Returns the value rounded downward&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
math.floor(1.2); # returns 1&lt;br /&gt;
math.floor(1.6); # returns 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ceil() ==&lt;br /&gt;
Returns the value rounded upward&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
math.ceil(1.2); # returns 2&lt;br /&gt;
math.ceil(1.6); # returns 2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== fmod() ==&lt;br /&gt;
A '''modulo'''-operator. The [https://en.wikipedia.org/wiki/Modulo_operation modulo]-operation finds the remainder of division of one number by another (sometimes called modulus).&lt;br /&gt;
&lt;br /&gt;
fmod(x , y) may be negative if x &amp;lt; 0, whereas mod() seems to guarantee that 0 ≤ mod(x,y) &amp;lt; y, according to tests made with x and y integers, y &amp;gt; 0, x positive or negative.&lt;br /&gt;
&lt;br /&gt;
== clamp() ==&lt;br /&gt;
== periodic() ==&lt;br /&gt;
== round() ==&lt;br /&gt;
== pi ==&lt;br /&gt;
== e ==&lt;br /&gt;
&lt;br /&gt;
= io =&lt;br /&gt;
&lt;br /&gt;
* SEEK_SET&lt;br /&gt;
* SEEK_CUR&lt;br /&gt;
* SEEK_END&lt;br /&gt;
* stdin&lt;br /&gt;
* stdout&lt;br /&gt;
* stderr&lt;br /&gt;
&lt;br /&gt;
== stat() ==&lt;br /&gt;
== directory() ==&lt;br /&gt;
returns the files in a given directory&lt;br /&gt;
&lt;br /&gt;
e.g. chatter_list = directory( chatter_dir );&lt;br /&gt;
&lt;br /&gt;
Example : &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = directory(FGRoot ~ filename);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns :   &lt;br /&gt;
'''&amp;quot;.&amp;quot; , &amp;quot;..&amp;quot; , &amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
To delete the &amp;quot;.&amp;quot; and &amp;quot;..&amp;quot; see the subvec() function.&lt;br /&gt;
&lt;br /&gt;
== open() ==&lt;br /&gt;
== read() ==&lt;br /&gt;
== readln() ==&lt;br /&gt;
== seek() ==&lt;br /&gt;
== tell() ==&lt;br /&gt;
== write() ==&lt;br /&gt;
== flush() ==&lt;br /&gt;
== close() ==&lt;br /&gt;
&lt;br /&gt;
= utf8 =&lt;br /&gt;
== chstr() ==&lt;br /&gt;
== strc() ==&lt;br /&gt;
== substr() ==&lt;br /&gt;
== size() ==&lt;br /&gt;
== validate() ==&lt;/div&gt;</summary>
		<author><name>Chris-barry</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_library_functions&amp;diff=91905</id>
		<title>Nasal library functions</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_library_functions&amp;diff=91905"/>
		<updated>2016-01-27T17:33:39Z</updated>

		<summary type="html">&lt;p&gt;Chris-barry: /* size() */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Nasal Navigation}}&lt;br /&gt;
&lt;br /&gt;
Please first see: http://plausible.org/nasal/lib.html&lt;br /&gt;
&lt;br /&gt;
== size() ==&lt;br /&gt;
Usage:&lt;br /&gt;
size(''object'');&lt;br /&gt;
where ''object'' may be a ''string'', a ''vector'' or a ''hash''.&lt;br /&gt;
Returns an intger equal to the number of characters in a ''string'' argument or the number of elements in a ''vector'' or ''hash''.&lt;br /&gt;
If the argument is a non-string scalar then the error '''object has no size()''' will be generated.&lt;br /&gt;
&lt;br /&gt;
== keys() ==&lt;br /&gt;
&lt;br /&gt;
== append() ==&lt;br /&gt;
&lt;br /&gt;
== pop() ==&lt;br /&gt;
&lt;br /&gt;
== setsize() ==&lt;br /&gt;
&lt;br /&gt;
== subvec() ==&lt;br /&gt;
Extract items of a vector - equivalent to the left() function for a string&lt;br /&gt;
&lt;br /&gt;
Example :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = directory(FGRoot ~ filename);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;.&amp;quot; , &amp;quot;..&amp;quot; , &amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
With subvec():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = subvec(directory(FGRoot ~ filename),2);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = subvec(directory(FGRoot ~ filename),3);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns : '''&amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
== delete() ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== int() ==&lt;br /&gt;
&lt;br /&gt;
== num(str) ==&lt;br /&gt;
Convert string to number.&lt;br /&gt;
Returns nil if str is nil, empty string, string with no number.&lt;br /&gt;
&lt;br /&gt;
== streq() ==&lt;br /&gt;
&lt;br /&gt;
== cmp() ==&lt;br /&gt;
&lt;br /&gt;
== substr() ==&lt;br /&gt;
&lt;br /&gt;
== chr() ==&lt;br /&gt;
&lt;br /&gt;
== contains() ==&lt;br /&gt;
&lt;br /&gt;
== typeof() ==&lt;br /&gt;
&lt;br /&gt;
== ghosttype(ghost) ==&lt;br /&gt;
Returns a string containing either a descriptive name as passed to ''naNewGhost'' or ''naNewGhost2'' in C/C++ while creating the ghost or a unique id (aka the pointer to the C/C++ naGhostType instance) if no name has been set.&lt;br /&gt;
&lt;br /&gt;
== compile() ==&lt;br /&gt;
&lt;br /&gt;
== call() ==&lt;br /&gt;
&lt;br /&gt;
== die() ==&lt;br /&gt;
&lt;br /&gt;
== sprintf() ==&lt;br /&gt;
&lt;br /&gt;
== caller() ==&lt;br /&gt;
&lt;br /&gt;
== closure() ==&lt;br /&gt;
&lt;br /&gt;
== find() ==&lt;br /&gt;
&lt;br /&gt;
== split() ==&lt;br /&gt;
&lt;br /&gt;
== rand() ==&lt;br /&gt;
&lt;br /&gt;
== bind() ==&lt;br /&gt;
&lt;br /&gt;
== sort() ==&lt;br /&gt;
&lt;br /&gt;
== id() ==&lt;br /&gt;
&lt;br /&gt;
= math =&lt;br /&gt;
== Trigonometric_functions ==&lt;br /&gt;
'''Caution''': All trigonometric functions works with [https://en.wikipedia.org/wiki/Radian Radian]-values - not with Degree!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;To convert this&amp;lt;/u&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
radians = degree * math.pi / 180&amp;lt;br&amp;gt;&lt;br /&gt;
degree  = radians * 180 / math.pi&lt;br /&gt;
=== sin() ===&lt;br /&gt;
=== cos() ===&lt;br /&gt;
=== tan() ===&lt;br /&gt;
=== asin() ===&lt;br /&gt;
=== acos() ===&lt;br /&gt;
=== atan2() ===&lt;br /&gt;
== exp() ==&lt;br /&gt;
== ln() ==&lt;br /&gt;
== pow() ==&lt;br /&gt;
== sqrt() ==&lt;br /&gt;
== floor() ==&lt;br /&gt;
Returns the value rounded downward&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
math.floor(1.2); # returns 1&lt;br /&gt;
math.floor(1.6); # returns 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ceil() ==&lt;br /&gt;
Returns the value rounded upward&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
math.ceil(1.2); # returns 2&lt;br /&gt;
math.ceil(1.6); # returns 2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== fmod() ==&lt;br /&gt;
A '''modulo'''-operator. The [https://en.wikipedia.org/wiki/Modulo_operation modulo]-operation finds the remainder of division of one number by another (sometimes called modulus).&lt;br /&gt;
&lt;br /&gt;
fmod(x , y) may be negative if x &amp;lt; 0, whereas mod() seems to guarantee that 0 ≤ mod(x,y) &amp;lt; y, according to tests made with x and y integers, y &amp;gt; 0, x positive or negative.&lt;br /&gt;
&lt;br /&gt;
== clamp() ==&lt;br /&gt;
== periodic() ==&lt;br /&gt;
== round() ==&lt;br /&gt;
== pi ==&lt;br /&gt;
== e ==&lt;br /&gt;
&lt;br /&gt;
= io =&lt;br /&gt;
&lt;br /&gt;
* SEEK_SET&lt;br /&gt;
* SEEK_CUR&lt;br /&gt;
* SEEK_END&lt;br /&gt;
* stdin&lt;br /&gt;
* stdout&lt;br /&gt;
* stderr&lt;br /&gt;
&lt;br /&gt;
== stat() ==&lt;br /&gt;
== directory() ==&lt;br /&gt;
returns the files in a given directory&lt;br /&gt;
&lt;br /&gt;
e.g. chatter_list = directory( chatter_dir );&lt;br /&gt;
&lt;br /&gt;
Example : &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nasal&amp;quot; enclose=&amp;quot;div&amp;quot;&amp;gt;&lt;br /&gt;
var FGRoot = getprop(&amp;quot;/sim/fg-root&amp;quot;);&lt;br /&gt;
var filename = &amp;quot;/Aircraft&amp;quot;;&lt;br /&gt;
var path_files = directory(FGRoot ~ filename);&lt;br /&gt;
&lt;br /&gt;
foreach(var key; path_files) {&lt;br /&gt;
print(key);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
returns :   &lt;br /&gt;
'''&amp;quot;.&amp;quot; , &amp;quot;..&amp;quot; , &amp;quot;Generic&amp;quot;, &amp;quot;Instruments&amp;quot;, &amp;quot;Instruments-3d&amp;quot;, &amp;quot;c172p&amp;quot;, &amp;quot;ufo&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
To delete the &amp;quot;.&amp;quot; and &amp;quot;..&amp;quot; see the subvec() function.&lt;br /&gt;
&lt;br /&gt;
== open() ==&lt;br /&gt;
== read() ==&lt;br /&gt;
== readln() ==&lt;br /&gt;
== seek() ==&lt;br /&gt;
== tell() ==&lt;br /&gt;
== write() ==&lt;br /&gt;
== flush() ==&lt;br /&gt;
== close() ==&lt;br /&gt;
&lt;br /&gt;
= utf8 =&lt;br /&gt;
== chstr() ==&lt;br /&gt;
== strc() ==&lt;br /&gt;
== substr() ==&lt;br /&gt;
== size() ==&lt;br /&gt;
== validate() ==&lt;/div&gt;</summary>
		<author><name>Chris-barry</name></author>
	</entry>
</feed>